From 1f240a6437685caef9806b489383b48dd2587b0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Mon, 21 Nov 2022 23:46:53 +0200 Subject: [PATCH 1/3] feat(_filedir): add tests with `_comp_compgen -C` Co-authored-by: Koichi Murase --- test/t/unit/test_unit_compgen_filedir.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/t/unit/test_unit_compgen_filedir.py b/test/t/unit/test_unit_compgen_filedir.py index aa18868c76d..6e4f3ce34ab 100644 --- a/test/t/unit/test_unit_compgen_filedir.py +++ b/test/t/unit/test_unit_compgen_filedir.py @@ -24,11 +24,22 @@ def functions(self, request, bash): "_g() { local cur;_comp_get_words cur; unset -v COMPREPLY; _comp_compgen_filedir e1; }; " "complete -F _g g", ) + assert_bash_exec( + bash, + "_fc() { local cur=$(_get_cword); unset -v COMPREPLY; _comp_compgen -C _filedir filedir; }; " + "complete -F _fc fc; " + "complete -F _fc -o filenames fc2", + ) assert_bash_exec( bash, "_fd() { local cur;_comp_get_words cur; unset -v COMPREPLY; _comp_compgen_filedir -d; };" "complete -F _fd fd", ) + assert_bash_exec( + bash, + "_fcd() { local cur=$(_get_cword); unset -v COMPREPLY; _comp_compgen -C _filedir filedir -d; };" + "complete -F _fcd fcd", + ) @pytest.fixture(scope="class") def non_windows_testdir(self, request, bash): @@ -68,6 +79,11 @@ def test_2(self, bash, functions, funcname): completion = assert_complete(bash, "%s ab/" % funcname, cwd="_filedir") assert completion == "e" + @pytest.mark.parametrize("funcname", "fc fc2".split()) + def test_2C(self, bash, functions, funcname): + completion = assert_complete(bash, "%s _filedir ab/" % funcname) + assert completion == "e" + @pytest.mark.parametrize("funcname", "f f2".split()) def test_3(self, bash, functions, funcname): completion = assert_complete( @@ -156,6 +172,10 @@ def test_14(self, bash, functions, funcname): def test_15(self, functions, completion): assert completion == "b/" + @pytest.mark.complete(r"fcd a\ ") + def test_15d(self, functions, completion): + assert completion == "b/" + @pytest.mark.complete("g ", cwd="_filedir/ext") def test_16(self, functions, completion): assert completion == sorted("ee.e1 foo/ gg.e1 ii.E1".split()) From ed7d46ec53f1e85bec9bd2327e047c03a6efa6cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Thu, 24 Nov 2022 00:12:15 +0200 Subject: [PATCH 2/3] fix(_filedir): apply trailing slashes with `-f` If we are completing entries somewhere else besides the current dir, `compopt -o filenames` won't do its usual thing; append slashes ourselves. Co-authored-by: Koichi Murase --- bash_completion | 43 +++++++++++++++++++++++++++++++++------- completions/_mount.linux | 4 ++-- completions/_slackpkg | 6 +++--- completions/removepkg | 2 +- completions/sbopkg | 2 +- completions/slapt-get | 2 +- 6 files changed, 44 insertions(+), 15 deletions(-) diff --git a/bash_completion b/bash_completion index 2f47a59d212..386bbfa7f2b 100644 --- a/bash_completion +++ b/bash_completion @@ -1166,9 +1166,15 @@ _comp_quote_compgen() # This function performs file and directory completion. It's better than # simply using 'compgen -f', because it honours spaces in filenames. -# @param $1 If `-d', complete only on directories. Otherwise filter/pick only -# completions with `.$1' and the uppercase version of it as file -# extension. +# @param $1 Complete filenames matching `.$1' and the uppercase version of it. +# Ignored with `-d`. +# OPTIONS +# -d Complete only on directories +# -f Perform `compopt -f 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. # @return 0 if at least one completion is generated, or 1 otherwise. # # @since 2.12 @@ -1177,9 +1183,22 @@ _comp_compgen_filedir() _comp_compgen_tilde && return local -a toks + local _dir="" _filenames="" + local OPTIND=1 OPTARG="" OPTERR=0 _opt + while getopts ":df" _opt "$@"; do + case $_opt in + d) _dir=set ;; + f) _filenames=set ;; + *) + printf "bash_completion: %s: usage error\n" "$FUNCNAME" >&2 + return 2 + ;; + esac + done + shift "$((OPTIND - 1))" local _arg=${1-} - if [[ $_arg == -d ]]; then + if [[ $_dir ]]; then _comp_compgen -v toks -- -d else local REPLY @@ -1223,9 +1242,19 @@ _comp_compgen_filedir() fi if ((${#toks[@]} != 0)); then - # 2>/dev/null for direct invocation, e.g. in the _comp_compgen_filedir - # unit test - compopt -o filenames 2>/dev/null + # compopt 2>/dev/null for direct invocation, e.g. in + # _comp_compgen_filedir unit test + if [[ $_filenames ]]; then + local i + for i in "${!toks[@]}"; do + if [[ -d ${toks[i]} ]]; then + toks[i]+=/ + compopt -o nospace 2>/dev/null + fi + done + else + compopt -o filenames 2>/dev/null + fi fi # Note: bash < 4.4 has a bug that all the elements are connected with diff --git a/completions/_mount.linux b/completions/_mount.linux index 3d4c30794b4..86643dfb623 100644 --- a/completions/_mount.linux +++ b/completions/_mount.linux @@ -38,11 +38,11 @@ _comp_cmd_mount() return ;; -L) - _comp_compgen -C "/dev/disk/by-label/" -- -f + _comp_compgen -C "/dev/disk/by-label/" filedir -f return ;; -U) - _comp_compgen -C "/dev/disk/by-uuid/" -- -f + _comp_compgen -C "/dev/disk/by-uuid/" filedir -f return ;; -O | --test-opts) diff --git a/completions/_slackpkg b/completions/_slackpkg index f8f7810d1a7..830976eaf51 100644 --- a/completions/_slackpkg +++ b/completions/_slackpkg @@ -65,8 +65,8 @@ _comp_cmd_slackpkg() ;; install-template | remove-template) if [[ -e $confdir/templates ]]; then - _comp_compgen -C "$confdir/templates" -- -f -X \ - "!?*.template" && COMPREPLY=("${COMPREPLY[@]%.template}") + _comp_compgen -C "$confdir/templates" filedir -f 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 -- -f + _comp_compgen -aC /var/log/packages filedir -f return ;; install | reinstall | upgrade | blacklist | download) diff --git a/completions/removepkg b/completions/removepkg index 73b632bc8b9..9bb1abe7e90 100644 --- a/completions/removepkg +++ b/completions/removepkg @@ -15,7 +15,7 @@ _comp_cmd_removepkg() fi local root=${ROOT:-/} - _comp_compgen -C "$root/var/log/packages" -- -f + _comp_compgen -C "$root/var/log/packages" filedir -f } && complete -F _comp_cmd_removepkg removepkg diff --git a/completions/sbopkg b/completions/sbopkg index a2fc5a680ff..d2d9d138e20 100644 --- a/completions/sbopkg +++ b/completions/sbopkg @@ -63,7 +63,7 @@ _comp_cmd_sbopkg() _comp_compgen_split -l -- "$(command sed -ne "s/^SLACKBUILD NAME: //p" \ "$file")" - _comp_compgen -aC "$QUEUEDIR" -- -f -X "!*.sqf" + _comp_compgen -aC "$QUEUEDIR" filedir -f sqf } && complete -F _comp_cmd_sbopkg sbopkg diff --git a/completions/slapt-get b/completions/slapt-get index 1dc09e06608..e961e5fbfa7 100644 --- a/completions/slapt-get +++ b/completions/slapt-get @@ -74,7 +74,7 @@ _comp_cmd_slapt_get() return ;; ins) # --remove|--filelist - _comp_compgen -C /var/log/packages -- -f + _comp_compgen -C /var/log/packages filedir -f return ;; set) # --install-set From a880535000b313efdee59a187675b529eaedef89 Mon Sep 17 00:00:00 2001 From: Koichi Murase Date: Sun, 24 Sep 2023 19:03:18 +0900 Subject: [PATCH 3/3] fix(_filedir): always set compopt -o filenames to quote special chars This fixes test_15d in test/t/unit/test_unit_filedir.py. --- bash_completion | 3 +-- test/t/unit/test_unit_compgen_filedir.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/bash_completion b/bash_completion index 386bbfa7f2b..de3e4fb1585 100644 --- a/bash_completion +++ b/bash_completion @@ -1252,9 +1252,8 @@ _comp_compgen_filedir() compopt -o nospace 2>/dev/null fi done - else - compopt -o filenames 2>/dev/null fi + compopt -o filenames 2>/dev/null fi # Note: bash < 4.4 has a bug that all the elements are connected with diff --git a/test/t/unit/test_unit_compgen_filedir.py b/test/t/unit/test_unit_compgen_filedir.py index 6e4f3ce34ab..b584f12e5e3 100644 --- a/test/t/unit/test_unit_compgen_filedir.py +++ b/test/t/unit/test_unit_compgen_filedir.py @@ -37,7 +37,7 @@ def functions(self, request, bash): ) assert_bash_exec( bash, - "_fcd() { local cur=$(_get_cword); unset -v COMPREPLY; _comp_compgen -C _filedir filedir -d; };" + "_fcd() { local cur=$(_get_cword); unset -v COMPREPLY; _comp_compgen -C _filedir filedir -df; };" "complete -F _fcd fcd", )