Since the predominant use case for compgen is generating output that then gets split back up into an array, it seems like it would be nice to have an option that avoids the extra steps (and their associated pitfalls)
From e75306bd43d4ed233a7fedddb060a6bdd9305fdc Mon Sep 17 00:00:00 2001 From: Grisha Levit <grishale...@gmail.com> Date: Thu, 13 Apr 2023 04:14:18 -0400 Subject: [PATCH] compgen -V option
--- builtins/complete.def | 72 ++++++++++++++++++++++++++++-------- externs.h | 1 + lib/readline/doc/rluser.texi | 11 ++++-- 3 files changed, 64 insertions(+), 20 deletions(-) diff --git a/builtins/complete.def b/builtins/complete.def index 881c4711..0c68aec1 100644 --- a/builtins/complete.def +++ b/builtins/complete.def @@ -87,7 +87,7 @@ struct _optflags { static int find_compact (char *); static int find_compopt (char *); -static int build_actions (WORD_LIST *, struct _optflags *, unsigned long *, unsigned long *); +static int build_actions (WORD_LIST *, struct _optflags *, unsigned long *, unsigned long *, char **); static int remove_cmd_completions (WORD_LIST *); @@ -177,9 +177,10 @@ find_compopt (char *name) /* Build the actions and compspec options from the options specified in LIST. ACTP is a pointer to an unsigned long in which to place the bitmap of actions. OPTP is a pointer to an unsigned long in which to place the - bitmap of compspec options (arguments to `-o'). PP, if non-null, gets 1 - if -p is supplied; RP, if non-null, gets 1 if -r is supplied. - If either is null, the corresponding option generates an error. + bitmap of compspec options (arguments to `-o'). FLAGP is a pointer to a + struct that stores non-action binary options. VNAMEP is a pointer to a + string to store the name of the output variable. + If any of the above is null, the corresponding option generates an error. This also sets variables corresponding to options that take arguments as a side effect; the caller should ensure that those variables are set to NULL before calling build_actions. Return value: @@ -189,7 +190,7 @@ find_compopt (char *name) */ static int -build_actions (WORD_LIST *list, struct _optflags *flagp, unsigned long *actp, unsigned long *optp) +build_actions (WORD_LIST *list, struct _optflags *flagp, unsigned long *actp, unsigned long *optp, char **vnamep) { int opt, ind, opt_given; unsigned long acts, copts; @@ -199,7 +200,7 @@ build_actions (WORD_LIST *list, struct _optflags *flagp, unsigned long *actp, un opt_given = 0; reset_internal_getopt (); - while ((opt = internal_getopt (list, "abcdefgjko:prsuvA:G:W:P:S:X:F:C:DEI")) != -1) + while ((opt = internal_getopt (list, "abcdefgjko:prsuvA:G:W:P:S:X:F:C:V:DEI")) != -1) { opt_given = 1; switch (opt) @@ -341,6 +342,25 @@ build_actions (WORD_LIST *list, struct _optflags *flagp, unsigned long *actp, un case 'S': Sarg = list_optarg; break; + case 'V': +#if defined (ARRAY_VARS) + if (vnamep) + { + *vnamep = list_optarg; + if (legal_identifier (*vnamep) == 0) + { + sh_invalidid (*vnamep); + return (EX_USAGE); + } + } + else +#endif + { + sh_invalidopt ("-V"); + builtin_usage (); + return (EX_USAGE); + } + break; case 'W': Warg = list_optarg; break; @@ -385,7 +405,7 @@ complete_builtin (WORD_LIST *list) /* Build the actions from the arguments. Also sets the [A-Z]arg variables as a side effect if they are supplied as options. */ - rval = build_actions (list, &oflags, &acts, &copts); + rval = build_actions (list, &oflags, &acts, &copts, (char **)NULL); if (rval == EX_USAGE) return (rval); opt_given = rval != EXECUTION_FAILURE; @@ -630,12 +650,13 @@ print_cmd_completions (WORD_LIST *list) $BUILTIN compgen $DEPENDS_ON PROGRAMMABLE_COMPLETION $FUNCTION compgen_builtin -$SHORT_DOC compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word] +$SHORT_DOC compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [-V var] [word] Display possible completions depending on the options. Intended to be used from within a shell function generating possible completions. If the optional WORD argument is supplied, matches against -WORD are generated. +WORD are generated. With the -V option, completions are stored in the +indexed array VAR. Exit Status: Returns success unless an invalid option is supplied or an error occurs. @@ -651,17 +672,21 @@ compgen_builtin (WORD_LIST *list) char *word, **matches; char *old_line; int old_ind, old_completion, old_quoting, old_suppress; + char *varname; + SHELL_VAR *var; + WORD_LIST *alist; if (list == 0) return (EXECUTION_SUCCESS); acts = copts = (unsigned long)0L; Garg = Warg = Parg = Sarg = Xarg = Farg = Carg = (char *)NULL; + varname = (char *)NULL; cs = (COMPSPEC *)NULL; /* Build the actions from the arguments. Also sets the [A-Z]arg variables as a side effect if they are supplied as options. */ - rval = build_actions (list, (struct _optflags *)NULL, &acts, &copts); + rval = build_actions (list, (struct _optflags *)NULL, &acts, &copts, &varname); if (rval == EX_USAGE) return (rval); if (rval == EXECUTION_FAILURE) @@ -728,15 +753,30 @@ compgen_builtin (WORD_LIST *list) rl_filename_quoting_desired = old_quoting; rl_completion_suppress_append = old_suppress; - if (sl) +#if defined (ARRAY_VARS) + if (varname) { - if (sl->list && sl->list_len) - { + var = builtin_find_indexed_array (varname, 1); + if (var && sl && sl->list && sl->list_len) + { + alist = strlist_to_word_list (sl, 0, 0); + assign_array_var_from_word_list (var, alist, 0); + free (sl); + sl = (STRINGLIST *)NULL; + dispose_words (alist); rval = EXECUTION_SUCCESS; - strlist_print (sl, (char *)NULL); - } - strlist_dispose (sl); + } } + else +#endif + if (sl && sl->list && sl->list_len) + { + strlist_print (sl, (char *)NULL); + rval = EXECUTION_SUCCESS; + } + + if (sl) + strlist_dispose (sl); compspec_dispose (cs); return (rval); diff --git a/externs.h b/externs.h index 7c70da92..49f33f20 100644 --- a/externs.h +++ b/externs.h @@ -408,6 +408,7 @@ extern STRINGLIST *strlist_prefix_suffix (STRINGLIST *, const char *, const char extern void strlist_print (STRINGLIST *, const char *); extern void strlist_walk (STRINGLIST *, sh_strlist_map_func_t *); extern void strlist_sort (STRINGLIST *); +extern WORD_LIST *strlist_to_word_list (STRINGLIST *, int, int); /* declarations for functions defined in lib/sh/stringvec.c */ diff --git a/lib/readline/doc/rluser.texi b/lib/readline/doc/rluser.texi index bb1a24f5..d9efb499 100644 --- a/lib/readline/doc/rluser.texi +++ b/lib/readline/doc/rluser.texi @@ -2106,7 +2106,7 @@ be completed, and two to modify the completion as it is happening. @item compgen @btindex compgen @example -@code{compgen [@var{option}] [@var{word}]} +@code{compgen [@var{option}] [-V @var{var}] [@var{word}]} @end example Generate possible completion matches for @var{word} according to @@ -2124,15 +2124,18 @@ with the same flags. If @var{word} is specified, only those completions matching @var{word} will be displayed. +If the @option{-V} option is supplied, completions will be stored in the +indexed array variable @var{var} instead of being written to stdout. + The return value is true unless an invalid option is supplied, or no matches were generated. @item complete @btindex complete @example -@code{complete [-abcdefgjksuv] [-o @var{comp-option}] [-DEI] [-A @var{action}] [-G @var{globpat}] -[-W @var{wordlist}] [-F @var{function}] [-C @var{command}] [-X @var{filterpat}] -[-P @var{prefix}] [-S @var{suffix}] @var{name} [@var{name} @dots{}]} +@code{complete [-abcdefgjksuv] [-o @var{comp-option}] [-DEI] [-A @var{action}] + [-G @var{globpat}] [-W @var{wordlist}] [-F @var{function}] [-C @var{command}] + [-X @var{filterpat}] [-P @var{prefix}] [-S @var{suffix}] @var{name} [@var{name} @dots{}]} @code{complete -pr [-DEI] [@var{name} @dots{}]} @end example -- 2.40.0