Network operating systems traditionally have provided a command line interface with "operation mode" and "configuration mode", with different auto-completion behaviour - specifically, with a small set of supported commands that are printed using the auto-completion shortcut key, depending on the mode. In order to be able to implement such modes using Bash, Linux and Free Software, it's necessary to be able to optionally disable auto-completion on the first word, so that the relevant help text (depending on the mode) can be printed on the console instead. Add and document a nofirstword completion option to implement this feature.
Signed-off-by: Luca Boccassi <bl...@debian.org> --- bashline.c | 47 +++++++++++++++++++++++++++++++++++++++-------- builtins/complete.def | 4 ++++ doc/bash.1 | 4 ++++ doc/bash.html | 5 +++++ doc/bash.info | 5 +++++ doc/bashref.html | 5 +++++ doc/bashref.info | 5 +++++ pcomplete.h | 1 + 8 files changed, 68 insertions(+), 8 deletions(-) diff --git a/bashline.c b/bashline.c index ae8fe1cc..436bf8d3 100644 --- a/bashline.c +++ b/bashline.c @@ -1313,8 +1313,9 @@ static int find_cmd_start (start) int start; { - register int s, os, ns; + register int s, os, ns, last; + last = 0; os = 0; /* Flags == SD_NOJMP only because we want to skip over command substitutions in assignment statements. Have to test whether this affects `standalone' @@ -1332,7 +1333,13 @@ find_cmd_start (start) continue; } os = s+1; + last = s; } + /* If the last seperator is a pipe keep it at the beginning of the command. The + pipe character is a command seperator and a command. */ + if (rl_line_buffer[last] == '|') + os = last; + return os; } @@ -1352,13 +1359,18 @@ find_cmd_name (start, sp, ep) int *sp, *ep; { char *name; - register int s, e; + register int s, s1, e; for (s = start; whitespace (rl_line_buffer[s]); s++) ; + /* If first character is a pipe char scan from next char */ + s1 = s; + if (rl_line_buffer[s] == '|') + ++s1; + /* skip until a shell break character */ - e = skip_to_delim (rl_line_buffer, s, "()<>;&| \t\n", SD_NOJMP|SD_COMPLETE); + e = skip_to_delim (rl_line_buffer, s1, "()<>;&| \t\n", SD_NOJMP|SD_COMPLETE); name = substring (rl_line_buffer, s, e); @@ -1425,6 +1437,7 @@ attempt_shell_completion (text, start, end) int in_command_position, ti, qc, dflags; char **matches, *command_separator_chars; #if defined (PROGRAMMABLE_COMPLETION) + COMPSPEC *cs; int have_progcomps, was_assignment; #endif @@ -1484,6 +1497,11 @@ attempt_shell_completion (text, start, end) that all of the previous words on the line are variable assignments. */ } +#if defined (PROGRAMMABLE_COMPLETION) + cs = progcomp_search(DEFAULTCMD); + if (cs && cs->options & COPT_NOFIRSTWORD) + in_command_position = 0; +#endif /* PROGRAMMABLE_COMPLETION */ if (in_command_position && invalid_completion (text, ti)) { @@ -1571,12 +1589,20 @@ attempt_shell_completion (text, start, end) { /* not assignment statement, but still want to perform command completion if we are composing command word. */ - foundcs = 0; - in_command_position = s == start && STREQ (n, text); /* XXX */ + if (cs && cs->options & COPT_NOFIRSTWORD) + prog_complete_matches = programmable_completions (EMPTYCMD, text, s, e, &foundcs); + else + { + foundcs = 0; + in_command_position = s == start && STREQ (n, text); /* XXX */ + } } else if (e > s && was_assignment == 0 && have_progcomps) { - prog_complete_matches = programmable_completions (n, text, s, e, &foundcs); + if (n[0] == '|' && cs && cs->options & COPT_NOFIRSTWORD) + prog_complete_matches = programmable_completions (EMPTYCMD, text, s, e, &foundcs); + else + prog_complete_matches = programmable_completions (n, text, s, e, &foundcs); /* command completion if programmable completion fails */ in_command_position = s == start && STREQ (n, text); /* XXX */ } @@ -1584,8 +1610,13 @@ attempt_shell_completion (text, start, end) else if (s >= e && n[0] == '\0' && text[0] == '\0' && start > 0 && was_assignment == 0 && member (rl_line_buffer[start-1], COMMAND_SEPARATORS)) { - foundcs = 0; - in_command_position = 1; + if (cs && cs->options & COPT_NOFIRSTWORD) + prog_complete_matches = programmable_completions (EMPTYCMD, text, s, e, &foundcs); + else + { + foundcs = 0; /* empty command name following assignments */ + in_command_position = was_assignment; + } } else if (s >= e && n[0] == '\0' && text[0] == '\0' && start > 0) { diff --git a/builtins/complete.def b/builtins/complete.def index 3ca8c1fa..9830fb3b 100644 --- a/builtins/complete.def +++ b/builtins/complete.def @@ -137,6 +137,7 @@ static const struct _compopt { { "default", COPT_DEFAULT }, { "dirnames", COPT_DIRNAMES }, { "filenames",COPT_FILENAMES}, + { "nofirstword", COPT_NOFIRSTWORD }, { "noquote", COPT_NOQUOTE }, { "nosort", COPT_NOSORT }, { "nospace", COPT_NOSPACE }, @@ -515,6 +516,7 @@ print_one_completion (cmd, cs) PRINTCOMPOPT (COPT_DEFAULT, "default"); PRINTCOMPOPT (COPT_DIRNAMES, "dirnames"); PRINTCOMPOPT (COPT_FILENAMES, "filenames"); + PRINTCOMPOPT (COPT_NOFIRSTWORD, "nofirstword"); PRINTCOMPOPT (COPT_NOQUOTE, "noquote"); PRINTCOMPOPT (COPT_NOSORT, "nosort"); PRINTCOMPOPT (COPT_NOSPACE, "nospace"); @@ -591,6 +593,7 @@ print_compopts (cmd, cs, full) XPRINTCOMPOPT (COPT_DEFAULT, "default"); XPRINTCOMPOPT (COPT_DIRNAMES, "dirnames"); XPRINTCOMPOPT (COPT_FILENAMES, "filenames"); + XPRINTCOMPOPT (COPT_NOFIRSTWORD, "nofirstword"); XPRINTCOMPOPT (COPT_NOQUOTE, "noquote"); XPRINTCOMPOPT (COPT_NOSORT, "nosort"); XPRINTCOMPOPT (COPT_NOSPACE, "nospace"); @@ -602,6 +605,7 @@ print_compopts (cmd, cs, full) PRINTCOMPOPT (COPT_DEFAULT, "default"); PRINTCOMPOPT (COPT_DIRNAMES, "dirnames"); PRINTCOMPOPT (COPT_FILENAMES, "filenames"); + PRINTCOMPOPT (COPT_NOFIRSTWORD, "nofirstword"); PRINTCOMPOPT (COPT_NOQUOTE, "noquote"); PRINTCOMPOPT (COPT_NOSORT, "nosort"); PRINTCOMPOPT (COPT_NOSPACE, "nospace"); diff --git a/doc/bash.1 b/doc/bash.1 index f19432ff..89ac1607 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -7696,6 +7696,10 @@ filename\-specific processing (like adding a slash to directory names, quoting special characters, or suppressing trailing spaces). Intended to be used with shell functions. .TP 8 +.B nofirstword +Disable autocompletion on the first word. Useful when it is necessary to +implement a "configuration mode", for example in networking operating systems. +.TP 8 .B noquote Tell readline not to quote the completed words if they are filenames (quoting filenames is the default). diff --git a/doc/bash.html b/doc/bash.html index 574db317..acaac109 100644 --- a/doc/bash.html +++ b/doc/bash.html @@ -9806,6 +9806,11 @@ Tell readline that the compspec generates filenames, so it can perform any filename-specific processing (like adding a slash to directory names, quoting special characters, or suppressing trailing spaces). Intended to be used with shell functions. +<DT><B>nofirstword</B> + +<DD> +Disable autocompletion on the first word. Useful when it is necessary +to implement a "configuration mode", for example in networking operating systems. <DT><B>noquote</B> <DD> diff --git a/doc/bash.info b/doc/bash.info index 1cef4bfd..5e5f161d 100644 --- a/doc/bash.info +++ b/doc/bash.info @@ -8793,6 +8793,11 @@ happening. is intended to be used with shell functions specified with '-F'. + 'nofirstword' + Disable autocompletion on the first word. Useful when it + is necessary to implement a "configuration mode", for + example in networking operating systems. + 'noquote' Tell Readline not to quote the completed words if they are filenames (quoting filenames is the default). diff --git a/doc/bashref.html b/doc/bashref.html index f64fbf21..7f8e3039 100644 --- a/doc/bashref.html +++ b/doc/bashref.html @@ -12039,6 +12039,11 @@ This option is intended to be used with shell functions specified with <samp>-F</samp>. </p> </dd> +<dt><code>nofirstword</code></dt> +<dd><p>Disable autocompletion on the first word. Useful when it is necessary +to implement a "configuration mode", for example in networking operating systems. +</p> +</dd> <dt><code>noquote</code></dt> <dd><p>Tell Readline not to quote the completed words if they are filenames (quoting filenames is the default). diff --git a/doc/bashref.info b/doc/bashref.info index c2ccaa58..d5675a66 100644 --- a/doc/bashref.info +++ b/doc/bashref.info @@ -8793,6 +8793,11 @@ happening. is intended to be used with shell functions specified with '-F'. + 'nofirstword' + Disable autocompletion on the first word. Useful when it + is necessary to implement a "configuration mode", for + example in networking operating systems. + 'noquote' Tell Readline not to quote the completed words if they are filenames (quoting filenames is the default). diff --git a/pcomplete.h b/pcomplete.h index 2ae8224e..62c4e83e 100644 --- a/pcomplete.h +++ b/pcomplete.h @@ -76,6 +76,7 @@ typedef struct compspec { #define COPT_BASHDEFAULT (1<<6) #define COPT_PLUSDIRS (1<<7) #define COPT_NOSORT (1<<8) +#define COPT_NOFIRSTWORD (1<<9) #define COPT_LASTUSER COPT_NOSORT -- 2.14.2