From 4e383908b2c04add8a4e66efdf3464b326597d18 Mon Sep 17 00:00:00 2001 From: Koichi Murase Date: Sun, 25 Jan 2026 20:14:14 +0900 Subject: [PATCH] feat(_comp_compgen_filedir): automatically add "-f" --- bash_completion | 23 +++++++++++++++++++---- completions-core/curl.bash | 4 ---- completions-core/removepkg.bash | 2 +- completions-core/sbopkg.bash | 2 +- completions-core/slapt-get.bash | 2 +- completions-fallback/mount.linux.bash | 4 ++-- completions-fallback/slackpkg.bash | 4 ++-- test/t/unit/test_unit_compgen.py | 11 +++++++++-- test/t/unit/test_unit_compgen_filedir.py | 2 +- 9 files changed, 36 insertions(+), 18 deletions(-) diff --git a/bash_completion b/bash_completion index 9b8c2138fc0..4128da65351 100644 --- a/bash_completion +++ b/bash_completion @@ -791,6 +791,8 @@ _comp_compgen__call_generator() local _comp_compgen__append=$_append local _comp_compgen__var=$_var local _comp_compgen__cur=$_cur cur=$_cur + local _comp_compgen__dir=$_dir + local _comp_compgen__prefix=$_prefix if [[ $_prefix ]]; then local -a tmp=() local _comp_compgen__var=tmp @@ -1286,11 +1288,11 @@ _comp_quote_compgen() # Ignored with `-d`. # OPTIONS # -d Complete only on directories + # -f Perform `compopt -o filenames` modifications manually. This -# suffixes a slash to a directory name. This can be combined with -# the `-C dir` option to `_comp_compgen`, where the generated -# filenames do not exist in the current working directory and Bash -# fails to properly detect the filenames. +# suffixes a slash to a directory name. When "-C " or "-P +# " is specified to the caller "_comp_compgen", this option +# is automatically turned on. # @return 0 if at least one completion is generated, or 1 otherwise. # # @since 2.12 @@ -1300,6 +1302,19 @@ _comp_compgen_filedir() local -a toks local _dir="" _filenames="" + if [[ ${_comp_compgen__dir-} || ${_comp_compgen__prefix-} ]]; then + # When "-C " or "-P " is specified, the working directory + # does not contain the generated candidates as filenames. In the case + # of "-C ", the generated filenames are located in the directory + # "" but not in the working directory. In the case of "-P + # ", candidates have the form "". In those + # cases, Bash fails to recognize the generated candidates to be + # filenames, and Bash does not adjust these as filenames. We + # automatically detect such cases and modify the generated filenames as + # if the option "-f" is passed. + _filenames=set + fi + local OPTIND=1 OPTARG="" OPTERR=0 _opt while getopts ":df" _opt "$@"; do case $_opt in diff --git a/completions-core/curl.bash b/completions-core/curl.bash index dc61bc4ccf6..72bf1a1bf01 100644 --- a/completions-core/curl.bash +++ b/completions-core/curl.bash @@ -55,10 +55,6 @@ _comp_cmd_curl() if [[ $cur == \@* ]]; then _comp_compgen -P @ filedir _comp_compgen -aP @ -- -W '-' - if [[ ${#COMPREPLY[@]} -eq 1 && -d ${COMPREPLY[0]#@} ]]; then - COMPREPLY[0]+=/ - compopt -o nospace - fi fi return ;; diff --git a/completions-core/removepkg.bash b/completions-core/removepkg.bash index 9bb1abe7e90..80c4800ebef 100644 --- a/completions-core/removepkg.bash +++ b/completions-core/removepkg.bash @@ -15,7 +15,7 @@ _comp_cmd_removepkg() fi local root=${ROOT:-/} - _comp_compgen -C "$root/var/log/packages" filedir -f + _comp_compgen -C "$root/var/log/packages" filedir } && complete -F _comp_cmd_removepkg removepkg diff --git a/completions-core/sbopkg.bash b/completions-core/sbopkg.bash index 975d19254a5..7fe8fc2e94c 100644 --- a/completions-core/sbopkg.bash +++ b/completions-core/sbopkg.bash @@ -64,7 +64,7 @@ _comp_cmd_sbopkg() _comp_compgen_split -l -- "$(command sed -ne "s/^SLACKBUILD NAME: //p" \ "$file")" if [[ -d ${QUEUEDIR-} ]]; then - _comp_compgen -aC "$QUEUEDIR" filedir -f sqf + _comp_compgen -aC "$QUEUEDIR" filedir sqf fi } && complete -F _comp_cmd_sbopkg sbopkg diff --git a/completions-core/slapt-get.bash b/completions-core/slapt-get.bash index e961e5fbfa7..3950cce76c0 100644 --- a/completions-core/slapt-get.bash +++ b/completions-core/slapt-get.bash @@ -74,7 +74,7 @@ _comp_cmd_slapt_get() return ;; ins) # --remove|--filelist - _comp_compgen -C /var/log/packages filedir -f + _comp_compgen -C /var/log/packages filedir return ;; set) # --install-set diff --git a/completions-fallback/mount.linux.bash b/completions-fallback/mount.linux.bash index 8e384bb936b..bd34ca8e4d2 100644 --- a/completions-fallback/mount.linux.bash +++ b/completions-fallback/mount.linux.bash @@ -32,11 +32,11 @@ _comp_cmd_mount() return ;; -L) - _comp_compgen -C "/dev/disk/by-label/" filedir -f + _comp_compgen -C "/dev/disk/by-label/" filedir return ;; -U) - _comp_compgen -C "/dev/disk/by-uuid/" filedir -f + _comp_compgen -C "/dev/disk/by-uuid/" filedir return ;; -O | --test-opts) diff --git a/completions-fallback/slackpkg.bash b/completions-fallback/slackpkg.bash index 830976eaf51..5923b1b2f9c 100644 --- a/completions-fallback/slackpkg.bash +++ b/completions-fallback/slackpkg.bash @@ -65,7 +65,7 @@ _comp_cmd_slackpkg() ;; install-template | remove-template) if [[ -e $confdir/templates ]]; then - _comp_compgen -C "$confdir/templates" filedir -f template && + _comp_compgen -C "$confdir/templates" filedir template && COMPREPLY=("${COMPREPLY[@]%.template}") fi return @@ -74,7 +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' - _comp_compgen -aC /var/log/packages filedir -f + _comp_compgen -aC /var/log/packages filedir return ;; install | reinstall | upgrade | blacklist | download) diff --git a/test/t/unit/test_unit_compgen.py b/test/t/unit/test_unit_compgen.py index 101d4bbe213..2b957a43878 100644 --- a/test/t/unit/test_unit_compgen.py +++ b/test/t/unit/test_unit_compgen.py @@ -127,7 +127,14 @@ def test_6_option_C_1(self, bash, functions): want_output=True, ) set1 = set(re.findall(r"<[^<>]*>", output.strip())) - assert set1 == {"", "", "", "", "", ""} + assert set1 == { + "", + "", + "", + "", + "", + "", + } def test_6_option_C_2(self, bash, functions): output = assert_bash_exec( @@ -146,7 +153,7 @@ def test_6_option_C_3(self, bash, functions, funcname): 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" + assert completion == "b/" @pytest.mark.complete(r"fb nonexistent") def test_6_option_C_5(self, bash, functions, completion): diff --git a/test/t/unit/test_unit_compgen_filedir.py b/test/t/unit/test_unit_compgen_filedir.py index 56f9fbe0532..7705061ee4d 100644 --- a/test/t/unit/test_unit_compgen_filedir.py +++ b/test/t/unit/test_unit_compgen_filedir.py @@ -34,7 +34,7 @@ def functions(self, request, bash): ) assert_bash_exec( bash, - "_fcd() { local cur=$(_get_cword); unset -v COMPREPLY; _comp_compgen -C _filedir filedir -df; };" + "_fcd() { local cur=$(_get_cword); unset -v COMPREPLY; _comp_compgen -C _filedir filedir -d; };" "complete -F _fcd fcd", )