diff --git a/bash_completion b/bash_completion
index 31529920c7f..03646d5d381 100644
--- a/bash_completion
+++ b/bash_completion
@@ -397,6 +397,23 @@ _comp_split()
((_new_size > _old_size))
}
+# Helper function for _comp_compgen
+# @var[in] $?
+# @var[in] _var
+# @var[in] _append
+# @return original $?
+_comp_compgen__error_fallback()
+{
+ local _status=$?
+ if [[ $_append ]]; then
+ # make sure existence of variable
+ eval -- "$_var+=()"
+ else
+ eval -- "$_var=()"
+ fi
+ return "$_status"
+}
+
# Provide a common interface to generate completion candidates in COMPREPLY or
# in a specified array.
# OPTIONS
@@ -414,6 +431,7 @@ _comp_split()
# -c cur Set a word used as a prefix to filter the completions. The default
# is ${cur-}.
# -R The same as -c ''. Use raw outputs without filtering.
+# -C dir Evaluate compgen/generator in the specified directory.
# @var[in,opt] cur Used as the default value of a prefix to filter the
# completions.
#
@@ -437,10 +455,10 @@ _comp_split()
# as `-v arr` as a part of the `_comp_compgen` options.
#
# Usage #2: _comp_compgen [-alR|-v arr|-c cur] name args...
-# Call `_comp_compgen_NAME ARGS...` with the specified options. This provides
-# a common interface to call the functions `_comp_compgen_NAME`, which produce
-# completion candidates, with custom options [-alR|-v arr|-c cur]. The option
-# `-F sep` is not used with this usage.
+# Call the generator `_comp_compgen_NAME ARGS...` with the specified options.
+# This provides a common interface to call the functions `_comp_compgen_NAME`,
+# which produce completion candidates, with custom options [-alR|-v arr|-c
+# cur]. The option `-F sep` is not used with this usage.
# @param $1... name args Calls the function _comp_compgen_NAME with the
# specified ARGS (if $1 does not start with a hyphen `-`). The options
# [-alR|-v arr|-c cur] are inherited by the child calls of `_comp_compgen`
@@ -484,10 +502,15 @@ _comp_compgen()
local _append=${_comp_compgen__append-}
local _var=${_comp_compgen__var-COMPREPLY}
local _cur=${_comp_compgen__cur-${cur-}}
- local _ifs=$' \t\n'
+ local _ifs=$' \t\n' _dir=""
+ local _old_nocasematch=""
+ if shopt -q nocasematch; then
+ _old_nocasematch=set
+ shopt -u nocasematch
+ fi
local OPTIND=1 OPTARG="" OPTERR=0 _opt
- while getopts ':alF:v:Rc:' _opt "$@"; do
+ while getopts ':alF:v:Rc:C:' _opt "$@"; do
case $_opt in
a) _append=set ;;
v)
@@ -501,12 +524,20 @@ _comp_compgen()
F) _ifs=$OPTARG ;;
c) _cur=$OPTARG ;;
R) _cur="" ;;
+ C)
+ if [[ ! $OPTARG ]]; then
+ printf 'bash_completion: %s: -C: invalid directory name `%s'\''.\n' "$FUNCNAME" "$OPTARG" >&2
+ return 2
+ fi
+ _dir=$OPTARG
+ ;;
*)
printf 'bash_completion: %s: usage error\n' "$FUNCNAME" >&2
return 2
;;
esac
done
+ [[ $_old_nocasematch ]] && shopt -s nocasematch
shift "$((OPTIND - 1))"
if (($# == 0)); then
printf 'bash_completion: %s: unexpected number of arguments.\n' "$FUNCNAME" >&2
@@ -521,6 +552,18 @@ _comp_compgen()
return 2
fi
+ if [[ $_dir ]]; then
+ local _original_pwd=$PWD
+ local PWD=${PWD-} OLDPWD=${OLDPWD-}
+ # Note: We also redirect stdout because `cd` may output the target
+ # directory to stdout when CDPATH is set.
+ command cd -- "$_dir" &>/dev/null ||
+ {
+ _comp_compgen__error_fallback
+ return
+ }
+ fi
+
local _comp_compgen__append=$_append
local _comp_compgen__var=$_var
local _comp_compgen__cur=$_cur cur=$_cur
@@ -528,7 +571,16 @@ _comp_compgen()
# arguments to the function if any.
# shellcheck disable=SC2145
_comp_compgen_"$@"
- return
+ local _status=$?
+
+ # Go back to the original directory.
+ # Note: Failure of this line results in the change of the current
+ # directory visible to the user. We intentionally do not redirect
+ # stderr so that the error message appear in the terminal.
+ # shellcheck disable=SC2164
+ [[ $_dir ]] && command cd -- "$_original_pwd"
+
+ return "$_status"
fi
# usage: _comp_compgen [options] -- [compgen_options]
@@ -550,16 +602,15 @@ _comp_compgen()
local _result
_result=$(
+ if [[ $_dir ]]; then
+ # Note: We also redirect stdout because `cd` may output the target
+ # directory to stdout when CDPATH is set.
+ command cd -- "$_dir" &>/dev/null || return
+ fi
IFS=$_ifs compgen "$@" ${_cur:+-- "$_cur"}
) || {
- local _status=$?
- if [[ $_append ]]; then
- # make sure existence of variable
- eval -- "$_var+=()"
- else
- eval -- "$_var=()"
- fi
- return "$_status"
+ _comp_compgen__error_fallback
+ return
}
_comp_split -l ${_append:+-a} "$_var" "$_result"
@@ -1508,13 +1559,19 @@ _available_interfaces()
}
# Echo number of CPUs, falling back to 1 on failure.
-# TODO:API: rename per conventions, rework to use vars rather than outputting
-_ncpus()
+# @var[out] ret
+# @return 0 if it successfully obtained the number of CPUs, or otherwise 1
+# @since 2.12
+_comp_get_ncpus()
{
local var=NPROCESSORS_ONLN
[[ $OSTYPE == *@(linux|msys|cygwin)* ]] && var=_$var
- local n=$(getconf $var 2>/dev/null)
- printf %s "${n:-1}"
+ if ret=$(getconf $var 2>/dev/null) && ((ret >= 1)); then
+ return 0
+ else
+ ret=1
+ return 1
+ fi
}
# Perform tilde (~) completion
diff --git a/bash_completion.d/000_bash_completion_compat.bash b/bash_completion.d/000_bash_completion_compat.bash
index 618ead21e98..2405aff47d9 100644
--- a/bash_completion.d/000_bash_completion_compat.bash
+++ b/bash_completion.d/000_bash_completion_compat.bash
@@ -335,4 +335,12 @@ _parse_usage()
return 0
}
+# @deprecated 2.12 Use `_comp_get_ncpus`.
+_ncpus()
+{
+ local ret
+ _comp_get_ncpus
+ printf %s "$ret"
+}
+
# ex: filetype=sh
diff --git a/completions/2to3 b/completions/2to3
index c22d12dc88e..7b5d04908ab 100644
--- a/completions/2to3
+++ b/completions/2to3
@@ -15,7 +15,9 @@ _comp_cmd_2to3()
return
;;
-j | --processes)
- COMPREPLY=($(compgen -W "{1..$(_ncpus)}" -- "$cur"))
+ local ret
+ _comp_get_ncpus
+ _comp_compgen -- -W "{1..$ret}"
return
;;
-o | --output-dir)
diff --git a/completions/_modules b/completions/_modules
index c208fc27695..f549cd19f88 100644
--- a/completions/_modules
+++ b/completions/_modules
@@ -21,30 +21,26 @@
# being sourced before it and thus before the `module' alias has been defined.
[[ -f /etc/profile.d/modules.sh ]] || return 1
-# TODO:API: rename per conventions, rework to use vars rather than outputting
-_module_list()
+_comp_cmd_module__compgen_list()
{
local modules="$(command sed 's/:/ /g' <<<"$LOADEDMODULES" | sort)"
- compgen -W "$modules" -- "$1"
+ _comp_compgen -- -W "$modules"
}
-# TODO:API: rename per conventions, rework to use vars rather than outputting
-_module_path()
+_comp_cmd_module__compgen_path()
{
local modules="$(command sed 's/:/ /g' <<<"$MODULEPATH" | sort)"
- compgen -W "$modules" -- "$1"
+ _comp_compgen -- -W "$modules"
}
-# TODO:API: rename per conventions, rework to use vars rather than outputting
-_module_avail()
+_comp_cmd_module__compgen_avail()
{
local modules="$(
module avail 2>&1 |
command grep -E -v '^(-|$)' |
xargs printf '%s\n' | command sed -e 's/(default)//g' | sort
)"
-
- compgen -W "$modules" -- "$1"
+ _comp_compgen -- -W "$modules"
}
# A completion function for the module alias
@@ -65,19 +61,23 @@ _comp_cmd_module()
elif ((cword == 2)); then
case $prev in
add | display | help | load | show | whatis)
- COMPREPLY=($(_module_avail "$cur"))
+ # TODO:API: use generator call?
+ _comp_cmd_module__compgen_avail
;;
rm | switch | swap | unload | update)
- COMPREPLY=($(_module_list "$cur"))
+ # TODO:API: use generator call?
+ _comp_cmd_module__compgen_list
;;
unuse)
- COMPREPLY=($(_module_path "$cur"))
+ # TODO:API: use generator call?
+ _comp_cmd_module__compgen_path
;;
esac
elif ((cword == 3)); then
case ${words[1]} in
swap | switch)
- COMPREPLY=($(_module_avail "$cur"))
+ # TODO:API: use generator call?
+ _comp_cmd_module__compgen_avail
;;
esac
fi
diff --git a/completions/_mount.linux b/completions/_mount.linux
index 51c445ba108..89c6ec3ca64 100644
--- a/completions/_mount.linux
+++ b/completions/_mount.linux
@@ -37,17 +37,11 @@ _comp_cmd_mount()
return
;;
-L)
- COMPREPLY=($(
- command cd "/dev/disk/by-label/" 2>/dev/null || return
- compgen -f -- "$cur"
- ))
+ _comp_compgen -C "/dev/disk/by-label/" -- -f
return
;;
-U)
- COMPREPLY=($(
- command cd "/dev/disk/by-uuid/" 2>/dev/null || return
- compgen -f -- "$cur"
- ))
+ _comp_compgen -C "/dev/disk/by-uuid/" -- -f
return
;;
-O | --test-opts)
diff --git a/completions/_slackpkg b/completions/_slackpkg
index 0f5d36ca561..898c19e9459 100644
--- a/completions/_slackpkg
+++ b/completions/_slackpkg
@@ -65,11 +65,8 @@ _comp_cmd_slackpkg()
;;
install-template | remove-template)
if [[ -e $confdir/templates ]]; then
- COMPREPLY=($(
- command cd -- "$confdir/templates"
- compgen -f -X "!*.template" -- "$cur"
- ))
- COMPREPLY=(${COMPREPLY[@]%.template})
+ _comp_compgen -C "$confdir/templates" -- -f -X \
+ "!?*.template" && COMPREPLY=("${COMPREPLY[@]%.template}")
fi
return
;;
@@ -77,10 +74,7 @@ _comp_cmd_slackpkg()
_comp_compgen_filedir
_comp_compgen -a -- -W 'a ap d e f k kde kdei l n t tcl x xap xfce
y'
- COMPREPLY+=($(
- command cd /var/log/packages
- compgen -f -- "$cur"
- ))
+ _comp_compgen -aC /var/log/packages -- -f
return
;;
install | reinstall | upgrade | blacklist | download)
diff --git a/completions/_umount.linux b/completions/_umount.linux
index 257d194898d..bb259752848 100644
--- a/completions/_umount.linux
+++ b/completions/_umount.linux
@@ -81,9 +81,8 @@ _comp_cmd_umount__linux_fstab()
local i
for i in ${!COMPREPLY[*]}; do
[[ ${COMPREPLY[i]} == "$realcur"* ]] &&
- COMPREPLY+=($(command cd -- "$dircur" 2>/dev/null &&
- compgen -f -d -P "$dircur" \
- -X "!${COMPREPLY[i]##"$dirrealcur"}" -- "$basecur"))
+ _comp_compgen -aC "$dircur" -c "$basecur" -- \
+ -f -d -P "$dircur" -X "!${COMPREPLY[i]##"$dirrealcur"}"
done
fi
fi
diff --git a/completions/bts b/completions/bts
index 4272015604e..41197c341e5 100644
--- a/completions/bts
+++ b/completions/bts
@@ -1,22 +1,24 @@
# bts completion -*- shell-script -*-
-# List bug numbers from bugs cache in ~/.devscripts_cache/bts
-# TODO:API: rename per conventions, rework to use vars rather than outputting
-_cached_bugs()
+# Generate bug numbers from bugs cache in ~/.devscripts_cache/bts
+# TODO:API: generator
+_comp_cmd_bts__cached_bugs()
{
- [[ -d $HOME/.devscripts_cache/bts ]] &&
+ [[ -d $HOME/.devscripts_cache/bts ]] || return 1
+ local bugs=$(
find "$HOME/.devscripts_cache/bts" -maxdepth 1 \
-name "${cur}[0-9]*.html" \
-printf "%f\n" | cut -d'.' -f1
+ )
+ _comp_compgen -aR -- -W '$bugs'
}
-# List APT source packages prefixed with "src:"
-# TODO:API: rename per conventions, rework to use vars rather than outputting
-_src_packages_with_prefix()
+# Generate APT source packages prefixed with "src:"
+# TODO:API: generator
+_comp_cmd_bts__src_packages_with_prefix()
{
- ppn=${cur:4} # partial package name, after stripping "src:"
- compgen -P "src:" -W '$(_comp_xfunc apt-cache sources "$ppn")' \
- -- "$ppn"
+ local ppn=${cur:4} # partial package name, after stripping "src:"
+ _comp_compgen -ac "$ppn" -- -P "src:" -W '$(_comp_xfunc apt-cache sources "$ppn")'
}
_comp_cmd_bts()
@@ -26,9 +28,9 @@ _comp_cmd_bts()
case $prev in
show | bugs)
- COMPREPLY=($(compgen -W 'release-critical RC from: tag:
- usertag:' -- "$cur") $(_cached_bugs)
- $(_src_packages_with_prefix))
+ _comp_compgen -- -W 'release-critical RC from: tag: usertag:'
+ _comp_cmd_bts__cached_bugs
+ _comp_cmd_bts__src_packages_with_prefix
return
;;
select)
@@ -38,8 +40,8 @@ _comp_cmd_bts()
return
;;
status)
- COMPREPLY=($(compgen -W 'file: fields: verbose' -- "$cur")
- $(_cached_bugs))
+ _comp_compgen -- -W 'file: fields: verbose'
+ _comp_cmd_bts__cached_bugs
return
;;
block | unblock)
@@ -57,7 +59,8 @@ _comp_cmd_bts()
return
;;
clone | "done" | reopen | archive | unarchive | retitle | summary | submitter | found | notfound | fixed | notfixed | merge | forcemerge | unmerge | claim | unclaim | forwarded | notforwarded | owner | noowner | subscribe | unsubscribe | reportspam | spamreport | affects | usertag | usertags | reassign | tag | tags)
- COMPREPLY=($(_cached_bugs))
+ COMPREPLY=()
+ _comp_cmd_bts__cached_bugs
return
;;
package)
@@ -65,15 +68,15 @@ _comp_cmd_bts()
return
;;
cache)
- COMPREPLY=($(_comp_xfunc apt-cache packages)
- $(_src_packages_with_prefix)
- $(compgen -W 'from: release-critical RC' -- "$cur"))
+ COMPREPLY=($(_comp_xfunc apt-cache packages))
+ _comp_cmd_bts__src_packages_with_prefix
+ _comp_compgen -a -- -W 'from: release-critical RC'
return
;;
cleancache)
- COMPREPLY=($(_comp_xfunc apt-cache packages)
- $(_src_packages_with_prefix)
- $(compgen -W 'from: tag: usertag: ALL' -- "$cur"))
+ COMPREPLY=($(_comp_xfunc apt-cache packages))
+ _comp_cmd_bts__src_packages_with_prefix
+ _comp_compgen -a -- -W 'from: tag: usertag: ALL'
return
;;
user)
diff --git a/completions/bzip2 b/completions/bzip2
index aede765cc2e..e46f8c4ae75 100644
--- a/completions/bzip2
+++ b/completions/bzip2
@@ -12,7 +12,9 @@ _comp_cmd_bzip2()
return
;;
-${noargopts}n)
- COMPREPLY=($(compgen -W "{1..$(_ncpus)}" -- "$cur"))
+ local ret
+ _comp_get_ncpus
+ _comp_compgen -- -W "{1..$ret}"
return
;;
esac
diff --git a/completions/cppcheck b/completions/cppcheck
index e3aadef02e3..eda632d5b64 100644
--- a/completions/cppcheck
+++ b/completions/cppcheck
@@ -42,7 +42,9 @@ _comp_cmd_cppcheck()
return
;;
-j)
- COMPREPLY=($(compgen -W "{2..$(_ncpus)}" -- "$cur"))
+ local ret
+ _comp_get_ncpus
+ _comp_compgen -- -W "{1..$ret}"
return
;;
--language | -x)
diff --git a/completions/feh b/completions/feh
index ae47df0e018..5ba9751f7fd 100644
--- a/completions/feh
+++ b/completions/feh
@@ -29,16 +29,12 @@ _comp_cmd_feh()
fi
local font_path
# font_path="$(imlib2-config --prefix 2>/dev/null)/share/imlib2/data/fonts"
- # COMPREPLY=( $(command cd -- "$font_path" 2>/dev/null; compgen -f \
- # -X "!*.@([tT][tT][fF])" -S / -- "$cur") )
+ # _comp_compgen -C "$font_path" -- -f -X "!*.@([tT][tT][fF])" -S /
for ((i = ${#words[@]} - 1; i > 0; i--)); do
if [[ ${words[i]} == -@(C|-fontpath) ]]; then
font_path="${words[i + 1]}"
- COMPREPLY+=($(
- command cd -- "$font_path" 2>/dev/null
- compgen -f \
- -X "!*.@([tT][tT][fF])" -S / -- "$cur"
- ))
+ _comp_compgen -aC "$font_path" -- \
+ -f -X "!*.@([tT][tT][fF])" -S /
fi
done
compopt -o nospace
diff --git a/completions/flake8 b/completions/flake8
index 0ccb509b553..e85809b35b6 100644
--- a/completions/flake8
+++ b/completions/flake8
@@ -16,7 +16,9 @@ _comp_cmd_flake8()
return
;;
--jobs | -${noargopts}j)
- COMPREPLY=($(compgen -W "auto {1..$(_ncpus)}" -- "$cur"))
+ local ret
+ _comp_get_ncpus
+ _comp_compgen -- -W "auto {1..$ret}"
return
;;
--output-file | --append-config | --config)
diff --git a/completions/gzip b/completions/gzip
index 67857f9e281..05074ee4dc8 100644
--- a/completions/gzip
+++ b/completions/gzip
@@ -13,7 +13,9 @@ _comp_cmd_gzip()
return
;;
--processes | -${noargopts}p)
- COMPREPLY=($(compgen -W "{1..$(_ncpus)}" -- "$cur"))
+ local ret
+ _comp_get_ncpus
+ _comp_comgpen -- -W "{1..$ret}"
return
;;
esac
diff --git a/completions/isort b/completions/isort
index 6129978b2e0..2a292ba3d3d 100644
--- a/completions/isort
+++ b/completions/isort
@@ -15,7 +15,9 @@ _comp_cmd_isort()
return
;;
--jobs | -j)
- COMPREPLY=($(compgen -W "{1..$(_ncpus)}" -- "$cur"))
+ local ret
+ _comp_get_ncpus
+ _comp_comgpen -- -W "{1..$ret}"
return
;;
--multi-line | -m)
diff --git a/completions/lrzip b/completions/lrzip
index a9601b22a00..16da0b97f20 100644
--- a/completions/lrzip
+++ b/completions/lrzip
@@ -34,7 +34,9 @@ _comp_cmd_lrzip()
return
;;
--threads | -${noargopts}p)
- COMPREPLY=($(compgen -W "{1..$(_ncpus)}" -- "$cur"))
+ local ret
+ _comp_get_ncpus
+ _comp_compgen -- -W "{1..$ret}"
return
;;
esac
diff --git a/completions/lzip b/completions/lzip
index 3fc7406ab3e..31c6f37534b 100644
--- a/completions/lzip
+++ b/completions/lzip
@@ -18,7 +18,9 @@ _comp_cmd_lzip()
decompress=set
;;
--threads | -${noargopts}n)
- COMPREPLY=($(compgen -W "{1..$(_ncpus)}" -- "$cur"))
+ local ret
+ _comp_get_ncpus
+ _comp_compgen -- -W "{1..$ret}"
return
;;
--output | -${noargopts}o)
diff --git a/completions/make b/completions/make
index 11e3ae91877..8090d7699c2 100644
--- a/completions/make
+++ b/completions/make
@@ -165,7 +165,9 @@ _comp_cmd_make()
return
;;
--jobs | -${noargopts}j)
- COMPREPLY=($(compgen -W "{1..$(($(_ncpus) * 2))}" -- "$cur"))
+ local ret
+ _comp_get_ncpus
+ _comp_compgen -- -W "{1..$((ret * 2))}"
return
;;
esac
diff --git a/completions/pylint b/completions/pylint
index 2a0d1c8adb5..9e27f657a7b 100644
--- a/completions/pylint
+++ b/completions/pylint
@@ -78,7 +78,9 @@ _comp_cmd_pylint()
return
;;
--jobs | -${noargopts}j)
- COMPREPLY=($(compgen -W "{1..$(_ncpus)}" -- "$cur"))
+ local ret
+ _comp_get_ncpus
+ _comp_compgen -- -W "{1..$ret}"
return
;;
--confidence)
diff --git a/completions/pytest b/completions/pytest
index 05ad0bdc833..d8bbff83fa0 100644
--- a/completions/pytest
+++ b/completions/pytest
@@ -81,7 +81,9 @@ _comp_cmd_pytest()
return
;;
--numprocesses | -${noargopts}n)
- COMPREPLY=($(compgen -W "{1..$(_ncpus)} auto" -- "$cur"))
+ local ret
+ _comp_get_ncpus
+ _comp_compgen -- -W "{1..$ret} auto"
return
;;
--dist | --vcr-record?(-mode))
diff --git a/completions/removepkg b/completions/removepkg
index 1f780e50069..73b632bc8b9 100644
--- a/completions/removepkg
+++ b/completions/removepkg
@@ -15,10 +15,7 @@ _comp_cmd_removepkg()
fi
local root=${ROOT:-/}
- COMPREPLY=($(
- command cd -- "$root/var/log/packages" 2>/dev/null || return 1
- compgen -f -- "$cur"
- ))
+ _comp_compgen -C "$root/var/log/packages" -- -f
} &&
complete -F _comp_cmd_removepkg removepkg
diff --git a/completions/sbopkg b/completions/sbopkg
index 4f58894415a..6b1acb29080 100644
--- a/completions/sbopkg
+++ b/completions/sbopkg
@@ -64,11 +64,8 @@ _comp_cmd_sbopkg()
COMPREPLY=($(
command sed -ne "/^SLACKBUILD NAME: $cur/{s/^SLACKBUILD NAME: //;p}" \
"$REPO_ROOT/$REPO_NAME/$REPO_BRANCH/SLACKBUILDS.TXT"
- )
- $(
- command cd -- "$QUEUEDIR"
- compgen -f -X "!*.sqf" -- "$cur"
))
+ _comp_compgen -aC "$QUEUEDIR" -- -f -X "!*.sqf"
} &&
complete -F _comp_cmd_sbopkg sbopkg
diff --git a/completions/slapt-get b/completions/slapt-get
index dcd9d560771..0085ed428c9 100644
--- a/completions/slapt-get
+++ b/completions/slapt-get
@@ -69,10 +69,7 @@ _comp_cmd_slapt_get()
return
;;
ins) # --remove|--filelist
- COMPREPLY=($(
- command cd /var/log/packages
- compgen -f -- "$cur"
- ))
+ _comp_compgen -C /var/log/packages -- -f
return
;;
set) # --install-set
diff --git a/completions/xdg-mime b/completions/xdg-mime
index 0cfc1261ba2..b779454468d 100644
--- a/completions/xdg-mime
+++ b/completions/xdg-mime
@@ -5,10 +5,7 @@ _comp_cmd_xdg_mime__mimetype()
local d i
local -a arr
for d in /usr/share/mime /usr/local/share/mime; do
- arr=($(
- command cd "$d" 2>/dev/null || exit 1
- compgen -f -o plusdirs -X "!*.xml" -- "$cur"
- )) || continue
+ _comp_compgen -v arr -C "$d" -- -f -o plusdirs -X "!*.xml" || continue
for i in "${!arr[@]}"; do
case ${arr[i]} in
packages*) unset -v "arr[i]" ;; # not a MIME type dir
diff --git a/completions/xz b/completions/xz
index 52d1e01505f..c89b3afa3f0 100644
--- a/completions/xz
+++ b/completions/xz
@@ -26,7 +26,9 @@ _comp_cmd_xz()
return
;;
--threads | -${noargopts}T)
- COMPREPLY=($(compgen -W "{0..$(_ncpus)}" -- "$cur"))
+ local ret
+ _comp_get_ncpus
+ _comp_compgen -- -W "{0..$ret}"
return
;;
--memlimit | --memlimit-compress | --memlimit-decompress | --memory | \
diff --git a/test/t/unit/test_unit_compgen.py b/test/t/unit/test_unit_compgen.py
index 86d042a6058..90ef54540f0 100644
--- a/test/t/unit/test_unit_compgen.py
+++ b/test/t/unit/test_unit_compgen.py
@@ -1,6 +1,7 @@
import pytest
+import re
-from conftest import assert_bash_exec, bash_env_saved
+from conftest import assert_bash_exec, bash_env_saved, assert_complete
@pytest.mark.bashcomp(cmd=None)
@@ -13,11 +14,27 @@ def functions(self, bash):
)
assert_bash_exec(
bash,
- '_comp__test_words() { local -a arr=(00) input; input=("${@:1:$#-1}"); _comp_compgen -v arr -c "${@:$#}" -- -W \'${input[@]+"${input[@]}"}\'; _comp__test_dump; }',
+ '_comp__test_compgen() { local -a arr=(00); _comp_compgen -v arr "$@"; _comp__test_dump; }',
)
assert_bash_exec(
bash,
- '_comp__test_words_ifs() { local -a arr=(00); local input=$2; _comp_compgen -F "$1" -v arr -c "${@:$#}" -- -W \'$input\'; _comp__test_dump; }',
+ '_comp__test_words() { local -a input=("${@:1:$#-1}"); _comp__test_compgen -c "${@:$#}" -- -W \'${input[@]+"${input[@]}"}\'; }',
+ )
+ assert_bash_exec(
+ bash,
+ '_comp__test_words_ifs() { local input=$2; _comp__test_compgen -F "$1" -c "${@:$#}" -- -W \'$input\'; }',
+ )
+
+ assert_bash_exec(
+ bash,
+ '_comp_cmd_fc() { _comp_compgen -c "$(_get_cword)" -C _filedir filedir; }; '
+ "complete -F _comp_cmd_fc fc; "
+ "complete -F _comp_cmd_fc -o filenames fc2",
+ )
+ assert_bash_exec(
+ bash,
+ '_comp_cmd_fcd() { _comp_compgen -c "$(_get_cword)" -C _filedir filedir -d; }; '
+ "complete -F _comp_cmd_fcd fcd",
)
def test_1_basic(self, bash, functions):
@@ -83,3 +100,31 @@ def test_5_option_F(self, bash, functions):
want_output=True,
)
assert output.strip() == "< 1><3 4><6 >< >"
+
+ def test_6_option_C_1(self, bash, functions):
+ output = assert_bash_exec(
+ bash,
+ "_comp__test_compgen -c a -C _filedir filedir",
+ want_output=True,
+ )
+ set1 = set(re.findall(r"<[^<>]*>", output.strip()))
+ assert set1 == {"", "", "", "", "", ""}
+
+ def test_6_option_C_2(self, bash, functions):
+ output = assert_bash_exec(
+ bash,
+ "_comp__test_compgen -c b -C _filedir -- -d",
+ want_output=True,
+ )
+ assert output.strip() == ""
+
+ @pytest.mark.parametrize("funcname", "fc fc2".split())
+ def test_6_option_C_3(self, bash, functions, funcname):
+ completion = assert_complete(bash, "%s _filedir ab/" % funcname)
+ assert completion == "e"
+
+ @pytest.mark.complete(r"fcd a\ ")
+ def test_6_option_C_4(self, functions, completion):
+ # Note: we are not in the original directory that "b" exists, so Bash
+ # will not suffix a slash to the directory name.
+ assert completion == "b"