@@ -441,6 +441,7 @@ _comp_split()
441441# @var[in] $?
442442# @var[in] _var
443443# @var[in] _append
444+ # @var[in] _upvars
444445# @return original $?
445446_comp_compgen__error_fallback ()
446447{
@@ -451,35 +452,46 @@ _comp_compgen__error_fallback()
451452 else
452453 eval -- " $_var =()"
453454 fi
455+ if (( ${# _upvars[@]} )) ; then
456+ _comp_unlocal " ${_upvars[@]} "
457+ _upvars=()
458+ fi
454459 return " $_status "
455460}
456461
457462# Provide a common interface to generate completion candidates in COMPREPLY or
458463# in a specified array.
459464# OPTIONS
460- # -a Append to the array
461- # -v arr Store the results to the array ARR. The default is `COMPREPLY`.
462- # The array name should not start with an underscores "_", which is
463- # internally used. The array name should not be any of "cur", "IFS"
464- # or "OPT{IND,ARG,ERR}".
465- # -U var Unlocalize VAR before performing the assignments. This option can
466- # be specified multiple times to register multiple variables. This
467- # option is supposed to be used in implementing a generator (G1) when
468- # G1 defines a local variable name that does not start with `_`. In
469- # such a case, when the target variable specified to G1 by `-v VAR1`
470- # conflicts with the local variable, the assignment to the target
471- # variable fails to propagate outside G1. To avoid such a situation,
472- # G1 can call `_comp_compgen` with `-U VAR` to unlocalize `VAR`
473- # before accessing the target variable. For a builtin compgen call
474- # (i.e., _comp_compgen [options] -- options), VAR is unlocalized
475- # after calling the builtin `compgen` but before assigning results to
476- # the target array. For a generator call (i.e., _comp_compgen
477- # [options] G2 ...), VAR is unlocalized before calling the child
478- # generator function `_comp_compgen_G2`.
479- # -c cur Set a word used as a prefix to filter the completions. The default
480- # is ${cur-}.
481- # -R The same as -c ''. Use raw outputs without filtering.
482- # -C dir Evaluate compgen/generator in the specified directory.
465+ # -a Append to the array
466+ # -v arr Store the results to the array ARR. The default is `COMPREPLY`.
467+ # The array name should not start with an underscores "_", which is
468+ # internally used. The array name should not be any of "cur",
469+ # "IFS" or "OPT{IND,ARG,ERR}".
470+ # -U var Unlocalize VAR before performing the assignments. This option
471+ # can be specified multiple times to register multiple variables.
472+ # This option is supposed to be used in implementing a generator
473+ # (G1) when G1 defines a local variable name that does not start
474+ # with `_`. In such a case, when the target variable specified to
475+ # G1 by `-v VAR1` conflicts with the local variable, the assignment
476+ # to the target variable fails to propagate outside G1. To avoid
477+ # such a situation, G1 can call `_comp_compgen` with `-U VAR` to
478+ # unlocalize `VAR` before accessing the target variable. For a
479+ # builtin compgen call (i.e., _comp_compgen [options] -- options),
480+ # VAR is unlocalized after calling the builtin `compgen` but before
481+ # assigning results to the target array. For a generator call
482+ # (i.e., _comp_compgen [options] G2 ...), VAR is unlocalized before
483+ # calling the child generator function `_comp_compgen_G2`.
484+ # -c cur Set a word used as a prefix to filter the completions. The
485+ # default is ${cur-}.
486+ # -R The same as -c ''. Use raw outputs without filtering.
487+ # -C dir Evaluate compgen/generator in the specified directory.
488+ # -P prefix Prepend the prefix to the generated completions. Unlike `compgen
489+ # -P prefix`, this prefix is subject to filtering by `cur`. When a
490+ # non-empty prefix is specified, first `cur` is tested whether it
491+ # is consistent with the prefix. Then, `cur` is reduced for the
492+ # part excluding the prefix, and the normal completion generation
493+ # is performed. Finally, the prefix is prepended to generated
494+ # completions.
483495# @var[in,opt] cur Used as the default value of a prefix to filter the
484496# completions.
485497#
@@ -564,6 +576,7 @@ _comp_compgen()
564576 local _var=
565577 local _cur=${_comp_compgen__cur-${cur-} }
566578 local _dir=" "
579+ local _prefix=" "
567580 local _ifs=$' \t\n ' _has_ifs=" "
568581 local _icmd=" " _xcmd=" "
569582 local -a _upvars=()
@@ -574,7 +587,7 @@ _comp_compgen()
574587 shopt -u nocasematch
575588 fi
576589 local OPTIND=1 OPTARG=" " OPTERR=0 _opt
577- while getopts ' :av:U:Rc:C:lF:i:x:' _opt " $@ " ; do
590+ while getopts ' :av:U:Rc:C:P: lF:i:x:' _opt " $@ " ; do
578591 case $_opt in
579592 a) _append=set ;;
580593 v)
@@ -603,6 +616,7 @@ _comp_compgen()
603616 fi
604617 _dir=$OPTARG
605618 ;;
619+ P) _prefix=$OPTARG ;;
606620 l) _has_ifs=set _ifs=$' \n ' ;;
607621 F) _has_ifs=set _ifs=$OPTARG ;;
608622 [ix])
@@ -638,6 +652,19 @@ _comp_compgen()
638652 [[ $_append ]] || _append=${_comp_compgen__append-}
639653 fi
640654
655+ local _prefix_fail=" "
656+ if [[ $_prefix ]]; then
657+ if [[ $_cur == " $_prefix " * ]]; then
658+ _cur=${_cur# " $_prefix " }
659+ elif [[ $_prefix == " $_cur " * ]]; then
660+ _cur=" "
661+ else
662+ # No completions are generated because the current word does not match
663+ # the prefix.
664+ _prefix_fail=set
665+ fi
666+ fi
667+
641668 if [[ $1 != -* ]]; then
642669 # usage: _comp_compgen [options] NAME args
643670 if [[ $_has_ifs ]]; then
@@ -659,6 +686,11 @@ _comp_compgen()
659686 fi
660687 shift
661688
689+ if [[ $_prefix_fail ]]; then
690+ _comp_compgen__error_fallback
691+ return 1
692+ fi
693+
662694 _comp_compgen__call_generator " $@ "
663695 else
664696 # usage: _comp_compgen [options] -- [compgen_options]
@@ -682,6 +714,11 @@ _comp_compgen()
682714 return 2
683715 fi
684716
717+ if [[ $_prefix_fail ]]; then
718+ _comp_compgen__error_fallback
719+ return 1
720+ fi
721+
685722 _comp_compgen__call_builtin " $@ "
686723 fi
687724}
@@ -696,8 +733,6 @@ _comp_compgen()
696733# @var[in] _var
697734_comp_compgen__call_generator ()
698735{
699- (( ${# _upvars[@]} )) && _comp_unlocal " ${_upvars[@]} "
700-
701736 if [[ $_dir ]]; then
702737 local _original_pwd=$PWD
703738 local PWD=${PWD-} OLDPWD=${OLDPWD-}
@@ -710,14 +745,28 @@ _comp_compgen__call_generator()
710745 }
711746 fi
712747
748+ (( ${# _upvars[@]} )) && _comp_unlocal " ${_upvars[@]} "
749+
713750 local _comp_compgen__append=$_append
714751 local _comp_compgen__var=$_var
715752 local _comp_compgen__cur=$_cur cur=$_cur
753+ if [[ $_prefix ]]; then
754+ local -a tmp=()
755+ local _comp_compgen__var=tmp
756+ local _comp_compgen__append=" "
757+ fi
716758 # Note: we use $1 as a part of a function name, and we use $2... as
717759 # arguments to the function if any.
718760 # shellcheck disable=SC2145
719761 " ${_generator[@]} " " $@ "
720762 local _status=$?
763+ if [[ $_prefix ]]; then
764+ local _i
765+ for _i in " ${! tmp[@]} " ; do
766+ tmp[_i]=$_prefix ${tmp[_i]}
767+ done
768+ _comp_compgen -RU tmp ${_append: +-a} -v " $_var " -- -W ' "${tmp[@]}"'
769+ fi
721770
722771 # Go back to the original directory.
723772 # Note: Failure of this line results in the change of the current
@@ -772,6 +821,13 @@ if ((BASH_VERSINFO[0] > 5 || BASH_VERSINFO[0] == 5 && BASH_VERSINFO[1] >= 3)); t
772821
773822 (( ${# _upvars[@]} )) && _comp_unlocal " ${_upvars[@]} "
774823 (( ${# _result[@]} )) || return
824+
825+ if [[ $_prefix ]]; then
826+ local _i
827+ for _i in " ${! _result[@]} " ; do
828+ _result[_i]=$_prefix ${_result[_i]}
829+ done
830+ fi
775831 if [[ $_append ]]; then
776832 eval -- " $_var +=(\"\$ {_result[@]}\" )"
777833 else
@@ -796,7 +852,13 @@ else
796852 }
797853
798854 (( ${# _upvars[@]} )) && _comp_unlocal " ${_upvars[@]} "
799- _comp_split -l ${_append: +-a} " $_var " " $_result "
855+
856+ if [[ $_prefix ]]; then
857+ _comp_split -l ${_append: +-a} " $_var " \
858+ " $( IFS=$' \n ' compgen -W ' $_result' -P " $_prefix " ) "
859+ else
860+ _comp_split -l ${_append: +-a} " $_var " " $_result "
861+ fi
800862 }
801863fi
802864
@@ -1854,7 +1916,7 @@ _comp_compgen_tilde()
18541916{
18551917 if [[ ${cur-} == \~ * && $cur != * /* ]]; then
18561918 # Try generate ~username completions
1857- if _comp_compgen -c " ${cur # \~ } " -- - P ' ~' -u; then
1919+ if _comp_compgen -P ' ~' -- -u; then
18581920 # 2>/dev/null for direct invocation, e.g. in the
18591921 # _comp_compgen_tilde unit test
18601922 compopt -o filenames 2> /dev/null
0 commit comments