Skip to content

[waiting for #1359] feat(_comp_compgen): support -P prefix with adjusted cur #1360

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Draft
82 changes: 73 additions & 9 deletions bash_completion
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ _comp_split()
# @var[in] $?
# @var[in] _var
# @var[in] _append
# @var[in] _upvars
# @return original $?
_comp_compgen__error_fallback()
{
Expand All @@ -449,6 +450,10 @@ _comp_compgen__error_fallback()
else
eval -- "$_var=()"
fi
if ((${#_upvars[@]})); then
_comp_unlocal "${_upvars[@]}"
_upvars=()
fi
return "$_status"
}

Expand Down Expand Up @@ -478,6 +483,13 @@ _comp_compgen__error_fallback()
# is ${cur-}.
# -R The same as -c ''. Use raw outputs without filtering.
# -C dir Evaluate compgen/generator in the specified directory.
# -P pref Prepend the prefix to the generated completions. Unlike `compgen
# -P prefix`, this prefix is subject to filtering by `cur`. When a
# non-empty prefix is specified, first `cur` is tested whether it is
# consistent with the prefix. Then, `cur` is reduced for the part
# excluding the prefix, and the normal completion generation is
# performed. Finally, the prefix is prepended to generated
# completions.
# @var[in,opt] cur Used as the default value of a prefix to filter the
# completions.
#
Expand Down Expand Up @@ -562,6 +574,7 @@ _comp_compgen()
local _var=
local _cur=${_comp_compgen__cur-${cur-}}
local _dir=""
local _prefix=""
local _ifs=$' \t\n' _has_ifs=""
local _icmd="" _xcmd=""
local -a _upvars=()
Expand All @@ -572,7 +585,7 @@ _comp_compgen()
shopt -u nocasematch
fi
local OPTIND=1 OPTARG="" OPTERR=0 _opt
while getopts ':av:U:Rc:C:lF:i:x:' _opt "$@"; do
while getopts ':av:U:Rc:C:P:lF:i:x:' _opt "$@"; do
case $_opt in
a) _append=set ;;
v)
Expand Down Expand Up @@ -601,6 +614,7 @@ _comp_compgen()
fi
_dir=$OPTARG
;;
P) _prefix=$OPTARG ;;
l) _has_ifs=set _ifs=$'\n' ;;
F) _has_ifs=set _ifs=$OPTARG ;;
[ix])
Expand Down Expand Up @@ -636,6 +650,19 @@ _comp_compgen()
[[ $_append ]] || _append=${_comp_compgen__append-}
fi

local _prefix_fail=""
if [[ $_prefix ]]; then
if [[ $_cur == "$_prefix"* ]]; then
_cur=${_cur#"$_prefix"}
elif [[ $_prefix == "$_cur"* ]]; then
_cur=""
else
# No completions are generated because the current word does not match
# the prefix.
_prefix_fail=set
fi
fi

if [[ $1 != -* ]]; then
# usage: _comp_compgen [options] NAME args
if [[ $_has_ifs ]]; then
Expand All @@ -657,6 +684,11 @@ _comp_compgen()
fi
shift

if [[ $_prefix_fail ]]; then
_comp_compgen__error_fallback
return 1
fi

_comp_compgen__call_generator "$@"
else
# usage: _comp_compgen [options] -- [compgen_options]
Expand All @@ -680,6 +712,11 @@ _comp_compgen()
return 2
fi

if [[ $_prefix_fail ]]; then
_comp_compgen__error_fallback
return 1
fi

_comp_compgen__call_builtin "$@"
fi
}
Expand All @@ -694,8 +731,6 @@ _comp_compgen()
# @var[in] _var
_comp_compgen__call_generator()
{
((${#_upvars[@]})) && _comp_unlocal "${_upvars[@]}"

if [[ $_dir ]]; then
local _original_pwd=$PWD
local PWD=${PWD-} OLDPWD=${OLDPWD-}
Expand All @@ -708,14 +743,28 @@ _comp_compgen__call_generator()
}
fi

((${#_upvars[@]})) && _comp_unlocal "${_upvars[@]}"

local _comp_compgen__append=$_append
local _comp_compgen__var=$_var
local _comp_compgen__cur=$_cur cur=$_cur
if [[ $_prefix ]]; then
local -a tmp=()
local _comp_compgen__var=tmp
local _comp_compgen__append=""
fi
# Note: we use $1 as a part of a function name, and we use $2... as
# arguments to the function if any.
# shellcheck disable=SC2145
"${_generator[@]}" "$@"
local _status=$?
if [[ $_prefix ]]; then
local _i
for _i in "${!tmp[@]}"; do
tmp[_i]=$_prefix${tmp[_i]}
done
_comp_compgen -RU tmp ${_append:+-a} -v "$_var" -- -W '"${tmp[@]}"'
fi

# Go back to the original directory.
# Note: Failure of this line results in the change of the current
Expand Down Expand Up @@ -770,6 +819,13 @@ if ((BASH_VERSINFO[0] > 5 || BASH_VERSINFO[0] == 5 && BASH_VERSINFO[1] >= 3)); t

((${#_upvars[@]})) && _comp_unlocal "${_upvars[@]}"
((${#_result[@]})) || return

if [[ $_prefix ]]; then
local _i
for _i in "${!_result[@]}"; do
_result[_i]=$_prefix${_result[_i]}
done
fi
if [[ $_append ]]; then
eval -- "$_var+=(\"\${_result[@]}\")"
else
Expand All @@ -794,7 +850,13 @@ else
}

((${#_upvars[@]})) && _comp_unlocal "${_upvars[@]}"
_comp_split -l ${_append:+-a} "$_var" "$_result"

if [[ $_prefix ]]; then
_comp_split -l ${_append:+-a} "$_var" \
"$(IFS=$'\n' compgen -W '$_result' -P "$_prefix")"
else
_comp_split -l ${_append:+-a} "$_var" "$_result"
fi
}
fi

Expand Down Expand Up @@ -1352,10 +1414,12 @@ _comp_delimited()
# `show-all-if-ambiguous` on, but even that has cases where it fails
# and the last separator including everything before it is lost.
# https://github.com/scop/bash-completion/pull/913#issuecomment-1490140309
local i
for i in "${!COMPREPLY[@]}"; do
COMPREPLY[i]="$prefix${COMPREPLY[i]}"
done
if [[ $prefix ]]; then
local i
for i in "${!COMPREPLY[@]}"; do
COMPREPLY[i]="$prefix${COMPREPLY[i]}"
done
fi

[[ $delimiter != : ]] || _comp_ltrim_colon_completions "$cur"
}
Expand Down Expand Up @@ -1850,7 +1914,7 @@ _comp_compgen_tilde()
{
if [[ ${cur-} == \~* && $cur != */* ]]; then
# Try generate ~username completions
if _comp_compgen -c "${cur#\~}" -- -P '~' -u; then
if _comp_compgen -P '~' -- -u; then
# 2>/dev/null for direct invocation, e.g. in the
# _comp_compgen_tilde unit test
compopt -o filenames 2>/dev/null
Expand Down
36 changes: 16 additions & 20 deletions completions/7z
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,17 @@ _comp_cmd_7z()

case $cur in
-ao*)
_comp_compgen -c "${cur:3}" -- -P"${cur:0:3}" -W 'a s t u'
_comp_compgen -P "-ao" -- -W 'a s t u'
return
;;
-?(a)[ix]*)
local opt
if [[ $cur == -a[ix]* ]]; then
opt=${cur:0:3} cur=${cur:3}
else
opt=${cur:0:2} cur=${cur:2}
fi
if [[ $cur != *[@\!]* ]]; then
_comp_compgen -- -P"$opt" -W '@ ! r@ r-@ r0@ r! r-! r0!'
elif [[ $cur == ?(r@(-|0|))@* ]]; then
_comp_compgen -c "${cur#*@}" -- -P"${opt}${cur%%@*}@" -f
[[ $cur =~ ^-a?[ix] ]]
local prefix=${BASH_REMATCH-}
_comp_compgen -P "$prefix" -- -W '@ ! r@ r-@ r0@ r! r-! r0!'
elif [[ $cur =~ ^-a?[ix](r|r-|r0)?@ ]]; then
local prefix=${BASH_REMATCH-}
_comp_compgen -P "$prefix" -- -f
compopt -o filenames
fi
return
Expand All @@ -43,31 +40,30 @@ _comp_cmd_7z()
;;
-o* | -w?*)
compopt -o filenames
_comp_compgen -c "${cur:2}" -- -d -P"${cur:0:2}" -S/
_comp_compgen -P "${cur:0:2}" -- -d -S/
compopt -o nospace
return
;;
-r?*)
_comp_compgen -c "${cur:2}" -- -P"${cur:0:2}" -W '- 0'
_comp_compgen -P "-r" -- -W '- 0'
return
;;
-scs*)
_comp_compgen -c "${cur:4}" -- -P"${cur:0:4}" -W 'UTF-8 WIN DOS'
_comp_compgen -P "-scs" -- -W 'UTF-8 WIN DOS'
return
;;
-ssc?*)
_comp_compgen -c "${cur:4}" -- -P"${cur:0:4}" -W '-'
_comp_compgen -P "-ssc" -- -W '-'
return
;;
-t*)
if [[ $mode == w ]]; then
_comp_compgen -c "${cur:2}" -- -P"${cur:0:2}" -W '7z bzip2 gzip
swfc tar wim xz zip'
_comp_compgen -P "-t" -- -W '7z bzip2 gzip swfc tar wim xz zip'
else
_comp_compgen -c "${cur:2}" -- -P"${cur:0:2}" -W '7z apm arj
bzip2 cab chm cpio cramfs deb dmg elf fat flv gzip hfs iso
lzh lzma lzma86 macho mbr mslz mub nsis ntfs pe ppmd rar
rpm squashfs swf swfc tar udf vhd wim xar xz z zip'
_comp_compgen -P "-t" -- -W '7z apm arj bzip2 cab chm cpio
cramfs deb dmg elf fat flv gzip hfs iso lzh lzma lzma86
macho mbr mslz mub nsis ntfs pe ppmd rar rpm squashfs swf
swfc tar udf vhd wim xar xz z zip'
fi
return
;;
Expand Down
2 changes: 1 addition & 1 deletion completions/_mount
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ _comp_cmd_mount()
host=${cur#//}
host=${host%%/*}
if [[ $host ]]; then
_comp_compgen -c "${cur#//"$host"}" split -P "//$host" -- "$(
_comp_compgen -P "//$host" split -- "$(
smbclient -d 0 -NL "$host" 2>/dev/null |
command sed -ne '/^[[:blank:]]*Sharename/,/^$/p' |
command sed -ne '3,$s|^[^A-Za-z]*\([^[:blank:]]*\).*$|/\1|p'
Expand Down
Loading