diff options
-rw-r--r-- | bin/ksh/edit.c | 83 | ||||
-rw-r--r-- | bin/ksh/ksh.1 | 23 |
2 files changed, 100 insertions, 6 deletions
diff --git a/bin/ksh/edit.c b/bin/ksh/edit.c index e66fd0ea356..1f5b69e8095 100644 --- a/bin/ksh/edit.c +++ b/bin/ksh/edit.c @@ -1,4 +1,4 @@ -/* $OpenBSD: edit.c,v 1.54 2016/08/16 15:32:07 tb Exp $ */ +/* $OpenBSD: edit.c,v 1.55 2016/09/04 17:21:44 nicm Exp $ */ /* * Command line editing - common code @@ -15,6 +15,7 @@ #include <errno.h> #include <libgen.h> #include <stdlib.h> +#include <stdio.h> #include <string.h> #include <unistd.h> @@ -578,13 +579,85 @@ x_locate_word(const char *buf, int buflen, int pos, int *startp, return end - start; } +static int +x_try_array(const char *buf, int buflen, const char *want, int wantlen, + int *nwords, char ***words) +{ + const char *cmd, *cp, *last; + int cmdlen, n; + char *name, *s; + size_t slen; + struct tbl *v, *vp; + + *nwords = 0; + *words = NULL; + + /* Walk back to find start of command. */ + if (want == buf) + return 0; + for (cmd = want; cmd > buf; cmd--) { + if (strchr(";|&()`", cmd[-1]) != NULL) + break; + } + while (cmd < want && isspace((u_char)*cmd)) + cmd++; + cmdlen = 0; + while (cmd + cmdlen < want && !isspace((u_char)cmd[cmdlen])) + cmdlen++; + + /* Take a stab at argument count from here. */ + n = 1; + for (cp = cmd + cmdlen + 1; cp < want; cp++) { + if (!isspace((u_char)cp[-1]) && isspace((u_char)*cp)) + n++; + } + + /* Try to find the array. */ + if (asprintf(&name, "complete_%.*s_%d", cmdlen, cmd, n) < 0) + internal_errorf(1, "unable to allocate memory"); + v = global(name); + free(name); + if (~v->flag & (ISSET|ARRAY)) { + if (asprintf(&name, "complete_%.*s", cmdlen, cmd) < 0) + internal_errorf(1, "unable to allocate memory"); + v = global(name); + free(name); + if (~v->flag & (ISSET|ARRAY)) + return 0; + } + + /* Walk the array and build words list. */ + for (vp = v; vp; vp = vp->u.array) { + if (~vp->flag & ISSET) + continue; + + s = str_val(vp); + slen = strlen(s); + + if (slen < wantlen) + continue; + if (slen > wantlen) + slen = wantlen; + if (slen != 0 && strncmp(s, want, slen) != 0) + continue; + + *words = areallocarray(*words, (*nwords) + 2, sizeof **words, + ATEMP); + (*words)[(*nwords)++] = str_save(s, ATEMP); + } + if (*nwords != 0) + (*words)[*nwords] = NULL; + + return *nwords != 0; +} + int x_cf_glob(int flags, const char *buf, int buflen, int pos, int *startp, int *endp, char ***wordsp, int *is_commandp) { int len; int nwords; - char **words; + char **words = NULL; int is_command; len = x_locate_word(buf, buflen, pos, startp, &is_command); @@ -597,8 +670,10 @@ x_cf_glob(int flags, const char *buf, int buflen, int pos, int *startp, if (len == 0 && is_command) return 0; - nwords = (is_command ? x_command_glob : x_file_glob)(flags, - buf + *startp, len, &words); + if (is_command) + nwords = x_command_glob(flags, buf + *startp, len, &words); + else if (!x_try_array(buf, buflen, buf + *startp, len, &nwords, &words)) + nwords = x_file_glob(flags, buf + *startp, len, &words); if (nwords == 0) { *wordsp = NULL; return 0; diff --git a/bin/ksh/ksh.1 b/bin/ksh/ksh.1 index 557b4a0eb0b..a2bdea1843a 100644 --- a/bin/ksh/ksh.1 +++ b/bin/ksh/ksh.1 @@ -1,8 +1,8 @@ -.\" $OpenBSD: ksh.1,v 1.179 2016/04/27 12:46:23 naddy Exp $ +.\" $OpenBSD: ksh.1,v 1.180 2016/09/04 17:21:44 nicm Exp $ .\" .\" Public Domain .\" -.Dd $Mdocdate: April 27 2016 $ +.Dd $Mdocdate: September 4 2016 $ .Dt KSH 1 .Os .Sh NAME @@ -4705,6 +4705,25 @@ is appended. If there is no command or file name with the current partial word as its prefix, a bell character is output (usually causing a beep to be sounded). +.Pp +Custom completions may be configured by creating an array named +.Ql complete_command , +optionally suffixed with an argument number to complete only for a single +argument. +So defining an array named +.Ql complete_kill +provides possible completions for any argument to the +.Xr kill 1 +command, but +.Ql complete_kill_1 +only completes the first argument. +For example, the following command makes +.Nm +offer a selection of signal names for the first argument to +.Xr kill 1 : +.Pp +.Dl set -A complete_kill_1 -- -9 -HUP -INFO -KILL -TERM +.Pp .It complete-command: ^X^[ Automatically completes as much as is unique of the command name having the partial word up to the cursor as its prefix, as in the |