Skip to content

Commit b6d4335

Browse files
authored
Merge pull request #1360 from akinomyoga/_comp_compgen-P
feat(_comp_compgen): support `-P prefix` with adjusted `cur`
2 parents f3906f4 + ec2f2fd commit b6d4335

File tree

18 files changed

+300
-220
lines changed

18 files changed

+300
-220
lines changed

bash_completion

Lines changed: 90 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}
801863
fi
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

completions/7z

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,17 @@ _comp_cmd_7z()
1515

1616
case $cur in
1717
-ao*)
18-
_comp_compgen -c "${cur:3}" -- -P"${cur:0:3}" -W 'a s t u'
18+
_comp_compgen -P "-ao" -- -W 'a s t u'
1919
return
2020
;;
2121
-?(a)[ix]*)
22-
local opt
23-
if [[ $cur == -a[ix]* ]]; then
24-
opt=${cur:0:3} cur=${cur:3}
25-
else
26-
opt=${cur:0:2} cur=${cur:2}
27-
fi
2822
if [[ $cur != *[@\!]* ]]; then
29-
_comp_compgen -- -P"$opt" -W '@ ! r@ r-@ r0@ r! r-! r0!'
30-
elif [[ $cur == ?(r@(-|0|))@* ]]; then
31-
_comp_compgen -c "${cur#*@}" -- -P"${opt}${cur%%@*}@" -f
23+
[[ $cur =~ ^-a?[ix] ]]
24+
local prefix=${BASH_REMATCH-}
25+
_comp_compgen -P "$prefix" -- -W '@ ! r@ r-@ r0@ r! r-! r0!'
26+
elif [[ $cur =~ ^-a?[ix](r|r-|r0)?@ ]]; then
27+
local prefix=${BASH_REMATCH-}
28+
_comp_compgen -P "$prefix" -- -f
3229
compopt -o filenames
3330
fi
3431
return
@@ -43,31 +40,30 @@ _comp_cmd_7z()
4340
;;
4441
-o* | -w?*)
4542
compopt -o filenames
46-
_comp_compgen -c "${cur:2}" -- -d -P"${cur:0:2}" -S/
43+
_comp_compgen -P "${cur:0:2}" -- -d -S/
4744
compopt -o nospace
4845
return
4946
;;
5047
-r?*)
51-
_comp_compgen -c "${cur:2}" -- -P"${cur:0:2}" -W '- 0'
48+
_comp_compgen -P "-r" -- -W '- 0'
5249
return
5350
;;
5451
-scs*)
55-
_comp_compgen -c "${cur:4}" -- -P"${cur:0:4}" -W 'UTF-8 WIN DOS'
52+
_comp_compgen -P "-scs" -- -W 'UTF-8 WIN DOS'
5653
return
5754
;;
5855
-ssc?*)
59-
_comp_compgen -c "${cur:4}" -- -P"${cur:0:4}" -W '-'
56+
_comp_compgen -P "-ssc" -- -W '-'
6057
return
6158
;;
6259
-t*)
6360
if [[ $mode == w ]]; then
64-
_comp_compgen -c "${cur:2}" -- -P"${cur:0:2}" -W '7z bzip2 gzip
65-
swfc tar wim xz zip'
61+
_comp_compgen -P "-t" -- -W '7z bzip2 gzip swfc tar wim xz zip'
6662
else
67-
_comp_compgen -c "${cur:2}" -- -P"${cur:0:2}" -W '7z apm arj
68-
bzip2 cab chm cpio cramfs deb dmg elf fat flv gzip hfs iso
69-
lzh lzma lzma86 macho mbr mslz mub nsis ntfs pe ppmd rar
70-
rpm squashfs swf swfc tar udf vhd wim xar xz z zip'
63+
_comp_compgen -P "-t" -- -W '7z apm arj bzip2 cab chm cpio
64+
cramfs deb dmg elf fat flv gzip hfs iso lzh lzma lzma86
65+
macho mbr mslz mub nsis ntfs pe ppmd rar rpm squashfs swf
66+
swfc tar udf vhd wim xar xz z zip'
7167
fi
7268
return
7369
;;

completions/_mount

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ _comp_cmd_mount()
4444
host=${cur#//}
4545
host=${host%%/*}
4646
if [[ $host ]]; then
47-
_comp_compgen -c "${cur#//"$host"}" split -P "//$host" -- "$(
47+
_comp_compgen -P "//$host" split -- "$(
4848
smbclient -d 0 -NL "$host" 2>/dev/null |
4949
command sed -ne '/^[[:blank:]]*Sharename/,/^$/p' |
5050
command sed -ne '3,$s|^[^A-Za-z]*\([^[:blank:]]*\).*$|/\1|p'

0 commit comments

Comments
 (0)