vis

a vi-like editor based on Plan 9's structural regular expressions

git clone https://9o.is/git/vis.git

commit 9a9c2b4b6f9fe61ecdbd740670135d76e1c2f341
parent 462da935f35319c28101e0c3c73a7729d5fecd93
Author: Marc André Tanner <mat@brain-dump.org>
Date:   Sun, 25 Sep 2016 10:57:01 +0200

vis: move file name and word completion logic to a shell script

The shell script should be reviewed for quoting issues, currently
it allows command injections as in:

 $ vis-complete "'; rm -f some-file; echo "

However it is intended for interactive usage and from within vis
it is only ever called with a valid completion prefix.

The file name completion logic now supports nested directories.

Close #347

Diffstat:
MMakefile | 2++
Mmain.c | 6++----
Avis-complete | 35+++++++++++++++++++++++++++++++++++
Mvis.h | 3+++
4 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/Makefile b/Makefile @@ -87,6 +87,8 @@ install: vis vis-menu @chmod 755 ${DESTDIR}${PREFIX}/bin/vis-open @cp -f vis-clipboard ${DESTDIR}${PREFIX}/bin @chmod 755 ${DESTDIR}${PREFIX}/bin/vis-clipboard + @cp -f vis-complete ${DESTDIR}${PREFIX}/bin + @chmod 755 ${DESTDIR}${PREFIX}/bin/vis-complete @test ${CONFIG_LUA} -eq 0 || { \ echo installing support files to ${DESTDIR}${SHAREPREFIX}/vis; \ mkdir -p ${DESTDIR}${SHAREPREFIX}/vis; \ diff --git a/main.c b/main.c @@ -2131,8 +2131,7 @@ static const char *complete_word(Vis *vis, const char *keys, const Arg *arg) { Buffer cmd; buffer_init(&cmd); char *prefix = get_completion_prefix(vis); - if (prefix && buffer_printf(&cmd, "tr -cs '[:alnum:]_' '\n' | grep '^%s.' | sort -u | " - VIS_MENU " -b | sed 's/^%s//' | tr -d '\n'", prefix, prefix)) { + if (prefix && buffer_printf(&cmd, VIS_COMPLETE " --word '%s'", prefix)) { Filerange all = text_range_new(0, text_size(txt)); insert_dialog_selection(vis, &all, (const char*[]){ buffer_content0(&cmd), NULL }); } @@ -2145,8 +2144,7 @@ static const char *complete_filename(Vis *vis, const char *keys, const Arg *arg) Buffer cmd; buffer_init(&cmd); char *prefix = get_completion_prefix(vis); - if (prefix && buffer_printf(&cmd, "ls -1 | grep '^%s.' | sort | " - VIS_MENU " -b | sed 's/^%s//' | tr -d '\n'", prefix, prefix)) { + if (prefix && buffer_printf(&cmd, VIS_COMPLETE " --file '%s'", prefix)) { Filerange empty = text_range_new(0, 0); insert_dialog_selection(vis, &empty, (const char*[]){ buffer_content0(&cmd), NULL }); } diff --git a/vis-complete b/vis-complete @@ -0,0 +1,35 @@ +#!/bin/sh +set -e + +PATTERN="" +COMPLETE_WORD=0 + +while [ $# -gt 0 ]; do + case "$1" in + -h|--help) + echo "usage: $(basename "$0") [-h] [--file|--word] [pattern]" + exit 0; + ;; + --file) + shift + ;; + --word) + COMPLETE_WORD=1 + shift + ;; + *) + PATTERN="$1" + break + ;; + esac +done + +if [ $COMPLETE_WORD = 1 ]; then + CMD=$(printf "tr -cs '[:alnum:]_' '\n' | grep '^%s.' | sort -u" "$PATTERN") +else + CMD=$(printf "find . ! -path '*/\.*' -a -path './%s*' | cut -b 3- | sort" "$PATTERN") +fi + +CMD=$(printf "$CMD | vis-menu -b | sed 's/^%s//' | tr -d '\n'" "$PATTERN") + +exec /bin/sh -c "$CMD" diff --git a/vis.h b/vis.h @@ -23,6 +23,9 @@ typedef struct Win Win; #ifndef VIS_CLIPBOARD #define VIS_CLIPBOARD "vis-clipboard" #endif +#ifndef VIS_COMPLETE +#define VIS_COMPLETE "vis-complete" +#endif typedef struct { void (*vis_init)(Vis*);