summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:03:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:03:58 +0000
commitd460debc6f2747699a54b7ea0e25f4ec69bf1b3d (patch)
treeca88441f05ddeb5857757e4fbba5f266119e0439
parentAdding upstream version 1:2.12.0. (diff)
downloadbash-completion-d460debc6f2747699a54b7ea0e25f4ec69bf1b3d.tar.xz
bash-completion-d460debc6f2747699a54b7ea0e25f4ec69bf1b3d.zip
Adding upstream version 1:2.13.0.upstream/1%2.13.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--.github/release-please-manifest.json2
-rw-r--r--.github/workflows/ci.yaml14
-rw-r--r--.gitignore4
-rw-r--r--.pre-commit-config.yaml8
-rw-r--r--.typos.toml18
-rw-r--r--CHANGELOG.md31
-rw-r--r--bash_completion4
-rw-r--r--completions/Makefile.am1
-rw-r--r--completions/_rg8
-rw-r--r--completions/curl5
-rw-r--r--completions/ip189
-rw-r--r--completions/tar2
-rw-r--r--completions/xmllint2
-rw-r--r--completions/xmlwf2
-rw-r--r--configure.ac2
-rw-r--r--doc/Makefile.am1
-rw-r--r--doc/api-and-naming.md14
-rw-r--r--pyproject.toml8
-rwxr-xr-xtest/docker/entrypoint.sh1
l---------test/fallback/completions/rg1
l---------test/fixtures/_comp_load/bin/cmd11
l---------test/fixtures/_comp_load/bin/cmd21
-rw-r--r--test/requirements-dev.txt2
-rw-r--r--test/t/conftest.py12
-rw-r--r--test/t/test_curl.py4
-rw-r--r--test/t/test_ip.py34
-rw-r--r--test/t/test_java.py2
-rw-r--r--test/t/test_perldoc.py6
-rw-r--r--test/t/unit/Makefile.am3
-rw-r--r--test/t/unit/test_unit_compgen.py5
-rw-r--r--test/t/unit/test_unit_compgen_available_interfaces.py25
-rw-r--r--test/t/unit/test_unit_load.py130
-rw-r--r--test/t/unit/test_unit_load_completion.py94
-rw-r--r--version.txt2
34 files changed, 471 insertions, 167 deletions
diff --git a/.github/release-please-manifest.json b/.github/release-please-manifest.json
index 95b1793..6f6cd64 100644
--- a/.github/release-please-manifest.json
+++ b/.github/release-please-manifest.json
@@ -1 +1 @@
-{".":"2.12.0"}
+{".":"2.13.0"}
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 27480fa..60f9adb 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -82,13 +82,17 @@ jobs:
env:
DIST: ${{matrix.dist}}
NETWORK: ${{matrix.network}}
+ - uses: actions/upload-artifact@v4
+ with:
+ path: |
+ bash-completion-*.tar.xz
+ sha256sums.txt
+ if: matrix.dist == 'alpine'
- name: Upload release assets
run: |
set -x
gh release upload ${{steps.release.outputs.tag_name}} \
- bash-completion-$(cat version.txt).tar.xz
+ bash-completion-$(cat version.txt).tar.xz sha256sums.txt
+ env:
+ GH_TOKEN: ${{github.token}}
if: steps.release.outputs.release_created
- - uses: actions/upload-artifact@v4
- with:
- path: bash-completion-*.tar.xz
- if: matrix.dist == 'alpine'
diff --git a/.gitignore b/.gitignore
index ab43e5e..c6b4b43 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,10 @@ pytestdebug.log
/bash-completion-config.cmake
/bash-completion.pc
/bash_completion.sh
+/.mise.local.toml
+/.mise.*.local.toml
+/sha256sums.txt
+/venv/
# Files generated by autotools
Makefile
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 6ba2382..52eea9b 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -17,7 +17,7 @@ repos:
exclude: ^completions/(\.gitignore|Makefile.*)$
- repo: https://github.com/shellcheck-py/shellcheck-py
- rev: v0.9.0.6
+ rev: v0.10.0.1
hooks:
- id: shellcheck
args: [-f, gcc]
@@ -43,7 +43,7 @@ repos:
pass_filenames: false
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.2.2
+ rev: v0.3.5
hooks:
- id: ruff
types: [text]
@@ -83,7 +83,7 @@ repos:
files: ^(helpers/perl|.+\.p[ml])$
- repo: https://github.com/jackdewinter/pymarkdown
- rev: v0.9.17
+ rev: v0.9.18
hooks:
- id: pymarkdown
entry: pymarkdown
@@ -98,7 +98,7 @@ repos:
- id: check-case-conflict
- repo: https://github.com/crate-ci/typos
- rev: v1.18.2
+ rev: v1.20.3
hooks:
- id: typos
exclude: ^(CHANGELOG\.md|test/(test-cmd-list\.txt|fixtures/.+))$
diff --git a/.typos.toml b/.typos.toml
index 327d012..c789e40 100644
--- a/.typos.toml
+++ b/.typos.toml
@@ -18,8 +18,14 @@ clea = "clea"
clien = "clien"
# completions/openssl
ede = "ede"
+# completions/patch
+fior = "fior"
# completions/make
fo = "fo"
+# completions/.gitignore, completions/Makefile.am, completions/_hexdump,
+# completions/gnome-screenshot, completions/mii-diag, completions/mii-tool,
+# completions/qemu,
+hd = "hd"
# test/t/test_ccache.py
hel = "hel"
# completions/bts
@@ -30,16 +36,28 @@ iif = "iif"
inout = "inout"
# test/t/unit/test_unit_expand_glob.py
ket = "ket"
+# completions/hcitool, completions/ip
+lst = "lst"
# completions/tshark, test/t/test_screen.py
nd = "nd"
+# bash_completion
+odf = "odf"
+# completions/ip
+oif = "oif"
# completions/mplayer
oly = "oly"
# test/t/unit/test_unit_find_unique_completion_pair.py
ot = "ot"
# completions/modinfo
parm = "parm"
+# bash_completion, completions/eog, completions/gnome-screenshot,
+# test/t/test_nmap.py
+pn = "pn"
# completions/wget
referer = "referer"
+# completions/_mount.linux, completions/tune2fs, test/t/test_curl.py,
+# test/t/unit/test_unit_find_unique_completion_pair.py
+ro = "ro"
# completions/ps
ser = "ser"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 933aec8..711ab85 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -299,6 +299,37 @@
* pre-commit: anchor exclude patterns ([cc697a6](https://www.github.com/scop/bash-completion/commit/cc697a646c1bd1100890abd367bb8d0274a42275))
* extra/make-changelog: check and output usage message ([cf90b29](https://www.github.com/scop/bash-completion/commit/cf90b297696cee57650f4fb6c29cebe872f773a7))
+## [2.13.0](https://github.com/scop/bash-completion/compare/2.12.0...2.13.0) (2024-04-03)
+
+
+### Features
+
+* **curl:** Complete protocols for --proto-default ([7051379](https://github.com/scop/bash-completion/commit/7051379e448147407c3fe43c89872dafb76ebb27))
+* **ip:** Add completion for netconf subcommand ([03a10ff](https://github.com/scop/bash-completion/commit/03a10ff63226782e61dae4407138c3240ff0c7c2))
+* **ip:** Complete commands for netns exec ([1f03796](https://github.com/scop/bash-completion/commit/1f03796cd930ddad6207d46814da820674f16edc))
+* **ip:** Complete help for unknown subcommands ([21f7e32](https://github.com/scop/bash-completion/commit/21f7e32f9009c2064d1659668425b6b6ccb537bd))
+* **ip:** Complete ip link property ([efa663c](https://github.com/scop/bash-completion/commit/efa663cd0dd63d54fd2d2987ee66fb954ccf4a86))
+* **ip:** Complete link types for address show ([ca5ea03](https://github.com/scop/bash-completion/commit/ca5ea037e2ec1b0b5ec4d31295df88125d51b43e))
+* **ip:** Complete neigh show and flush ([c7c3c03](https://github.com/scop/bash-completion/commit/c7c3c039bf5a462ea577e8fcc92ebd94d6afad49))
+* **ip:** Complete stats subcommand ([cd73e8c](https://github.com/scop/bash-completion/commit/cd73e8c1689e3e014c4a75d5101ee3d932013120))
+* **ip:** Create function to get link types ([8e60245](https://github.com/scop/bash-completion/commit/8e60245c7531e1615dc96b032035bb4f59972f4a))
+* **rg:** add fallback 3rd party completion loader ([7e4cc2f](https://github.com/scop/bash-completion/commit/7e4cc2fb199f1c88bd9a358a157fe06327fc2b28))
+* **xmllint,xmlwf:** also suggest *.rss files ([a89cde2](https://github.com/scop/bash-completion/commit/a89cde2216b1634521b4a264b2dbc5cda7522061))
+
+
+### Bug Fixes
+
+* **available_interfaces:** fix regression of unwanted trailing colons ([c2f83e0](https://github.com/scop/bash-completion/commit/c2f83e0436208ef2bfa9c762bc28ff6374ba0c73))
+* **ip:** Complete addrlabel add/del properties ([ea07616](https://github.com/scop/bash-completion/commit/ea076166e9a5cce9d22a27e63f95bbf00be9b894))
+* **ip:** Complete ip delete with type correctly ([f3a9be3](https://github.com/scop/bash-completion/commit/f3a9be3e2f6eaf0d94bb66220fd02cf0e3c76481))
+* **ip:** Complete more variations of subcommands ([c8920c5](https://github.com/scop/bash-completion/commit/c8920c57f83199a14230485cc44b426f028acafb))
+* **ip:** Complete netns attach subcommand ([bfb1de6](https://github.com/scop/bash-completion/commit/bfb1de64a53d1eba749c9921cea3809460cd2319))
+* **ip:** Complete only relevant addrlabel subcmds ([05147f1](https://github.com/scop/bash-completion/commit/05147f19d3d04040fa8dacbd9e1705bfc1432073))
+* **ip:** Keep completing after -netns name ([1a5df4f](https://github.com/scop/bash-completion/commit/1a5df4fe22eb374424b18e7db27b8446e919f4b2))
+* **ip:** Quote all instantiation of ip as "$1" ([ef25163](https://github.com/scop/bash-completion/commit/ef25163e6bd9095e528b57d44cb31d32f0321bb9))
+* **ip:** Quote network namespace names ([216734b](https://github.com/scop/bash-completion/commit/216734bed7ba02655128bf1dbc2f184420ad69ef))
+* **Makefile:** include api-and-naming.md in dist ([fdd8048](https://github.com/scop/bash-completion/commit/fdd80487ba6944e639baf32ba991f8665840728d))
+
## [2.12.0](https://github.com/scop/bash-completion/compare/v2.11.0...2.12.0) (2024-02-21)
diff --git a/bash_completion b/bash_completion
index e245cc5..42a5dca 100644
--- a/bash_completion
+++ b/bash_completion
@@ -25,7 +25,7 @@
BASH_COMPLETION_VERSINFO=(
2 # x-release-please-major
- 12 # x-release-please-minor
+ 13 # x-release-please-minor
0 # x-release-please-patch
)
@@ -1737,7 +1737,7 @@ _comp_compgen_available_interfaces()
fi
} 2>/dev/null | _comp_awk \
'/^[^ \t]/ { if ($1 ~ /^[0-9]+:/) { print $2 } else { print $1 } }')" &&
- _comp_compgen -U generated set "${generated[@]}"
+ _comp_compgen -U generated set "${generated[@]%%[[:punct:]]*}"
}
# Echo number of CPUs, falling back to 1 on failure.
diff --git a/completions/Makefile.am b/completions/Makefile.am
index 8f11291..ed1f215 100644
--- a/completions/Makefile.am
+++ b/completions/Makefile.am
@@ -377,6 +377,7 @@ bashcomp_DATA = 2to3 \
_reptyr \
resolvconf \
_rfkill \
+ _rg \
ri \
rmlist \
rmmod \
diff --git a/completions/_rg b/completions/_rg
new file mode 100644
index 0000000..4129371
--- /dev/null
+++ b/completions/_rg
@@ -0,0 +1,8 @@
+# 3rd party completion loader for commands emitting -*- shell-script -*-
+# their completion using "$cmd --generate complete-bash".
+#
+# This serves as a fallback in case the completion is not installed otherwise.
+
+eval -- "$("$1" --generate complete-bash 2>/dev/null)"
+
+# ex: filetype=sh
diff --git a/completions/curl b/completions/curl
index 6cbbca4..55865c0 100644
--- a/completions/curl
+++ b/completions/curl
@@ -22,7 +22,7 @@ _comp_cmd_curl()
--happy-eyeballs-timeout-ms | --hostpubmd5 | --keepalive-time | \
--limit-rate | --local-port | --login-options | --mail-auth | \
--mail-from | --mail-rcpt | --max-filesize | --max-redirs | \
- --max-time | --pass | --proto | --proto-default | --proto-redir | \
+ --max-time | --pass | --proto | --proto-redir | \
--proxy-ciphers | --proxy-pass | --proxy-service-name | \
--proxy-tls13-ciphers | --proxy-tlspassword | --proxy-tlsuser | \
--proxy-user | --proxy1.0 | --quote | --range | --referer | \
@@ -127,6 +127,9 @@ _comp_cmd_curl()
_comp_compgen_known_hosts -- "$cur"
return
;;
+ --proto-default)
+ _comp_compgen_split "$("$1" --version 2>/dev/null | command sed -e '/Protocols/!d' -e 's/Protocols://')"
+ ;;
--pubkey)
_comp_compgen -x ssh identityfile pub
return
diff --git a/completions/ip b/completions/ip
index 511f206..09bec5b 100644
--- a/completions/ip
+++ b/completions/ip
@@ -8,10 +8,45 @@ _comp_cmd_ip__iproute2_etc()
_comp_cmd_ip__netns()
{
- _comp_compgen_split -- "$(
+ local unquoted
+ _comp_split -l unquoted "$(
{
${1-ip} -c=never netns list 2>/dev/null || ${1-ip} netns list
- } | _comp_awk '{print $1}'
+ } | command sed -e 's/ (.*//'
+ )"
+ # namespace names can have spaces, so we quote all of them if needed
+ local ns quoted=()
+ for ns in "${unquoted[@]}"; do
+ local namespace
+ printf -v namespace '%q' "$ns"
+ quoted+=("$namespace")
+ done
+ ((${#quoted[@]})) && _comp_compgen -- -W '"${quoted[@]}"'
+}
+
+_comp_cmd_ip__link_types()
+{
+ _comp_compgen_split -- "$(
+ {
+ ${1-ip} -c=never link help || ${1-ip} link help
+ } 2>&1 | command sed -e \
+ '/TYPE := /,/}/!d' -e \
+ 's/.*{//' -e \
+ 's/}.*//' -e \
+ 's/|/ /g'
+ )"
+}
+
+_comp_cmd_ip__neigh_states()
+{
+ _comp_compgen_split -- "$(
+ {
+ ${1-ip} -c=never neigh help || ${1-ip} neigh help
+ } 2>&1 | command sed -e \
+ '/STATE := /,/}/!d' -e \
+ 's/.*{//' -e \
+ 's/}.*//' -e \
+ 's/|/ /g'
)"
}
@@ -47,7 +82,7 @@ _comp_cmd_ip()
[[ ${words[subcword]} == -b?(atch) ]] && return
[[ $has_cmd ]] && subcmd=${words[subcword]} && break
[[ ${words[subcword]} != -* &&
- ${words[subcword - 1]} != -@(f?(amily)|rc?(vbuf)) ]] &&
+ ${words[subcword - 1]} != -@(f?(amily)|rc?(vbuf)|n?(etns)) ]] &&
cmd=${words[subcword]} has_cmd=set
done
@@ -66,7 +101,7 @@ _comp_cmd_ip()
*)
_comp_compgen_split -- "help $(
{
- $1 -c=never help || $1 help
+ "$1" -c=never help || "$1" help
} 2>&1 | command sed -e \
'/OBJECT := /,/}/!d' -e \
's/.*{//' -e \
@@ -87,19 +122,12 @@ _comp_cmd_ip()
# TODO
;;
delete)
- case $((cword - subcword)) in
- 1)
- _comp_compgen_available_interfaces
- ;;
- 2)
- _comp_compgen -- -W 'type'
- ;;
- 3)
- [[ $prev == type ]] &&
- _comp_compgen -- -W 'vlan veth vcan dummy ifb
- macvlan can'
- ;;
- esac
+ if [[ $prev == type ]]; then
+ _comp_cmd_ip__link_types "$1"
+ else
+ _comp_compgen_available_interfaces
+ _comp_compgen -a -- -W 'type'
+ fi
;;
set)
if ((cword - subcword == 1)); then
@@ -132,9 +160,20 @@ _comp_cmd_ip()
_comp_cmd_ip__iproute2_etc group
fi
;;
+ property)
+ if ((cword - 1 == subcword)); then
+ _comp_compgen -- -W 'add del'
+ elif [[ $prev == dev ]]; then
+ _comp_compgen_available_interfaces
+ elif [[ $prev == altname ]]; then
+ return
+ else
+ _comp_compgen -- -W 'dev altname'
+ fi
+ ;;
*)
((cword == subcword)) &&
- _comp_compgen -- -W 'help add delete set show'
+ _comp_compgen -- -W 'help add delete set show property'
;;
esac
;;
@@ -164,11 +203,13 @@ _comp_cmd_ip()
_comp_compgen_available_interfaces
_comp_compgen -a -- -W 'dev scope to label dynamic
permanent tentative deprecated dadfailed temporary
- primary secondary up'
+ primary secondary up type'
elif [[ $prev == dev ]]; then
_comp_compgen_available_interfaces
elif [[ $prev == scope ]]; then
_comp_cmd_ip__iproute2_etc rt_scopes
+ elif [[ $prev == type ]]; then
+ _comp_cmd_ip__link_types "$1"
fi
;;
*)
@@ -181,13 +222,16 @@ _comp_cmd_ip()
addrlabel)
case $subcmd in
- list | add | del | flush)
+ add | del)
if [[ $prev == dev ]]; then
_comp_compgen_available_interfaces
+ elif [[ $prev == prefix || $prev == label ]]; then
+ : # TODO - Is there a way to complete these?
else
- : # TODO
+ _comp_compgen -- -W 'dev prefix label'
fi
;;
+ list | flush | help) ;;
*)
((cword == subcword)) &&
_comp_compgen -- -W 'help list add del flush'
@@ -211,14 +255,14 @@ _comp_cmd_ip()
if [[ $prev == via ]]; then
_comp_compgen_split -- "$(
{
- $1 -c=never r 2>/dev/null || $1 r
+ "$1" -c=never r 2>/dev/null || "$1" r
} | command sed -ne \
's/.*via \([0-9.]*\).*/\1/p'
)"
elif [[ $prev == "$subcmd" ]]; then
_comp_compgen_split -- "table default $(
{
- $1 -c=never r 2>/dev/null || $1 r
+ "$1" -c=never r 2>/dev/null || "$1" r
} | cut -d ' ' -f 1
)"
elif [[ $prev == dev ]]; then
@@ -274,14 +318,62 @@ _comp_cmd_ip()
;;
esac
;;
+ stats)
+ case "$subcmd" in
+ show)
+ if [[ $prev == dev ]]; then
+ _comp_compgen_available_interfaces
+ elif [[ $prev == group ]]; then
+ _comp_compgen -- -W "$(
+ # stats command was added after color, should always have it
+ "$1" -c=never stats help 2>&1 |
+ command sed -e \
+ '/^GROUP := /,/}/!d' -e \
+ 's/^GROUP := //g' -e \
+ '/:=/d' -e \
+ 's/[{}|]//g'
+ )"
+ elif [[ $prev == subgroup || $prev == suite ]]; then
+ : # TODO: complete subgroup and suite
+ else
+ _comp_compgen -- -W 'dev group subgroup suite'
+ fi
+ ;;
+ set)
+ if [[ $prev == dev ]]; then
+ _comp_compgen_available_interfaces
+ elif [[ $prev == l3_stats ]]; then
+ _comp_compgen -- -W 'on off'
+ else
+ _comp_compgen -- -W 'dev l3_stats'
+ fi
+ ;;
+ *)
+ _comp_compgen -- -W 'show set help'
+ ;;
+ esac
+ ;;
- neigh)
+ n | neigh | neighbor | neighbour)
case $subcmd in
add | del | change | replace)
# TODO
;;
show | flush)
- # TODO
+ case "$prev" in
+ nud)
+ _comp_cmd_ip__neigh_states "$1"
+ ;;
+ dev)
+ _comp_compgen_available_interfaces
+ ;;
+ nomaster | proxy | to | vrf) # TODO - Maybe we can complete vrf here?
+ :
+ ;;
+ *)
+ _comp_compgen -- -W 'proxy to nud vrf dev nomaster'
+ ;;
+ esac
;;
*)
((cword == subcword)) &&
@@ -306,7 +398,7 @@ _comp_cmd_ip()
esac
;;
- tunnel)
+ tun | tunnel)
case $subcmd in
show) ;;
@@ -369,24 +461,57 @@ _comp_cmd_ip()
esac
;;
- netns)
+ net | netns)
case $subcmd in
list | monitor) ;;
add | identify | list-id)
# TODO
;;
- delete | exec | pids | set)
+ delete | pids | set)
[[ $prev == "$subcmd" ]] && _comp_cmd_ip__netns "$1"
;;
+ exec)
+ local all_offset=0 i
+ for ((i = 1; i <= cword; i++)); do
+ case ${words[i]} in
+ -a | -all)
+ all_offset=1
+ break
+ ;;
+ esac
+ done
+ if [[ $prev == "$subcmd" && $all_offset != 1 ]]; then
+ _comp_cmd_ip__netns "$1"
+ else
+ local offset
+ offset="$((subcword + 2 - all_offset))"
+ _comp_command_offset "$offset"
+ fi
+ ;;
*)
((cword == subcword)) &&
- _comp_compgen -- -W 'help add delete exec identify list
+ _comp_compgen -- -W 'help add attach delete exec identify list
list-id monitor pids set'
;;
esac
;;
+ netconf)
+ case $subcmd in
+ show)
+ if ((cword == subcword + 1)); then
+ _comp_compgen -- -W 'dev'
+ elif [[ $prev == dev ]]; then
+ _comp_compgen_available_interfaces
+ fi
+ ;;
+ *)
+ ((cword == subcword)) && _comp_compgen -- -W 'help show'
+ ;;
+ esac
+ ;;
+
xfrm)
case $subcmd in
state | policy | monitor)
@@ -394,10 +519,14 @@ _comp_cmd_ip()
;;
*)
((cword == subcword)) &&
- _comp_compgen -- -W 'state policy monitor'
+ _comp_compgen -- -W 'help state policy monitor'
;;
esac
;;
+ help) ;;
+ *)
+ _comp_compgen -- -W 'help'
+ ;;
esac
} &&
complete -F _comp_cmd_ip ip
diff --git a/completions/tar b/completions/tar
index 83a4073..b11bd9b 100644
--- a/completions/tar
+++ b/completions/tar
@@ -31,7 +31,7 @@
# FIXME: timeout on tarball listing
# FIXME: cache 'tar --help' parsing results into global variables
# FIXME: at least 'tar -<tab>' should show some helping text (apart from just
-# pure option advices)
+# pure option advice)
# FIXME: short option completion should be more intuitive
# - verbose mode option should be advised multiple times
# - mode option should be advised only once
diff --git a/completions/xmllint b/completions/xmllint
index 57445bb..e424840 100644
--- a/completions/xmllint
+++ b/completions/xmllint
@@ -46,7 +46,7 @@ _comp_cmd_xmllint()
return
fi
- _comp_compgen_filedir '@(*ml|htm|svg?(z)|xs[dl]|rng|wsdl|jnlp|tld|dbk|docbook|page)?(.gz)'
+ _comp_compgen_filedir '@(*ml|htm|svg?(z)|xs[dl]|rng|wsdl|jnlp|tld|dbk|docbook|page|rss)?(.gz)'
} &&
complete -F _comp_cmd_xmllint xmllint
diff --git a/completions/xmlwf b/completions/xmlwf
index d047ee1..201734f 100644
--- a/completions/xmlwf
+++ b/completions/xmlwf
@@ -24,7 +24,7 @@ _comp_cmd_xmlwf()
return
fi
- _comp_compgen_filedir '@(*ml|htm|svg|xs[dl]|rng|wsdl|jnlp|tld|dbk|docbook|page)'
+ _comp_compgen_filedir '@(*ml|htm|svg|xs[dl]|rng|wsdl|jnlp|tld|dbk|docbook|page|rss)'
} &&
complete -F _comp_cmd_xmlwf xmlwf
diff --git a/configure.ac b/configure.ac
index 83a6f12..649ee3c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
AC_PREREQ([2.60])
-AC_INIT([bash-completion], [2.12.0]) dnl x-release-please-version
+AC_INIT([bash-completion], [2.13.0]) dnl x-release-please-version
dnl tar-pax for portable UTF-8 handling
AM_INIT_AUTOMAKE([
foreign dist-xz no-dist-gzip tar-pax -Wall -Wno-portability -Werror
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 8bac9e8..775ff4b 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -1,4 +1,5 @@
EXTRA_DIST = \
+ api-and-naming.md \
configuration.md \
styleguide.md \
testing.md
diff --git a/doc/api-and-naming.md b/doc/api-and-naming.md
index 59b2c36..e7f4ee6 100644
--- a/doc/api-and-naming.md
+++ b/doc/api-and-naming.md
@@ -13,8 +13,8 @@ specific names. `local`izing output variables before invoking a function that
populates them is the caller's responsibility. Note that if calling multiple
functions that assign output to the same variable during one completion
function run, each result should be copied to another variable between the
-calls to avoid it possibly being overwritten and lost on the next call. Also,
-the variables should also be ensured to be clear before each call that
+calls to avoid it possibly being overwritten and lost on the next call.
+The variables should also be ensured to be clear before each call that
references the value, variable name, or their existence, typically by `unset
-v`ing them when multiple such calls are used, to avoid them interfering with
each other.
@@ -24,8 +24,8 @@ unconventional, but this choice of the name is intended to be consistent with
the value substitutions `${| func; }`, which is originally supported by mksh
and will be supported by Bash >= 5.3. The value substitutions are replaced by
the contents of the output variable `REPLY` set by `func`. Although we cannot
-currently assume Bash 5.3 in the codebase, but we can switch to the value
-substitutions at the point Bash <= 5.2 disappear from the market.
+currently assume Bash 5.3 in the codebase, we can switch to the value
+substitutions at the point Bash <= 5.2 disappears from the market.
Everything in fallback completion files (ones starting with an underscore)
is considered private and is to be named accordingly. Fallback files are not
@@ -164,9 +164,9 @@ append the results to the target variable, use `_comp_compgen_split -- "$(cmd
A generator function should replace the existing content of the variable by
default. When the appending behavior is favored, the caller should specify it
-through `_comp_compgen -a NAME`. The generator function do not need to process
-it because internal `_comp_compgen` calls automatically reflects the option
-`-a` specified to the outer calls of `_comp_compgen`.
+through `_comp_compgen -a NAME`. The generator function does not need to
+process it because internal `_comp_compgen` calls automatically reflect the
+option `-a` specified to the outer calls of `_comp_compgen`.
The exit status is implementation-defined.
diff --git a/pyproject.toml b/pyproject.toml
index 83d0112..12d45e6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,7 +1,7 @@
[tool.ruff]
line-length = 79
target-version = "py37"
-lint.select = ["E", "F", "B"]
+lint.select = ["E", "F", "B", "I"]
lint.ignore = [
# https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
# (keep order of ignores here same as ^there for maintainability)
@@ -21,8 +21,6 @@ lint.ignore = [
"ISC002",
"E501",
]
+lint.isort.known-first-party = ["conftest"]
+lint.isort.known-third-party = ["pexpect", "pytest"]
fix = true
-
-[tool.ruff.lint.isort]
-known-first-party = ["conftest"]
-known-third-party = ["pexpect", "pytest"]
diff --git a/test/docker/entrypoint.sh b/test/docker/entrypoint.sh
index c647782..88ba5ad 100755
--- a/test/docker/entrypoint.sh
+++ b/test/docker/entrypoint.sh
@@ -20,3 +20,4 @@ make -j
xvfb-run make distcheck \
PYTESTFLAGS="${PYTESTFLAGS---verbose -p no:cacheprovider --numprocesses=auto --dist=loadfile}"
cp -p bash-completion-*.tar.* "$oldpwd/"
+sha256sum bash-completion-*.tar.* >"$oldpwd/sha256sums.txt"
diff --git a/test/fallback/completions/rg b/test/fallback/completions/rg
new file mode 120000
index 0000000..cb88b04
--- /dev/null
+++ b/test/fallback/completions/rg
@@ -0,0 +1 @@
+../../../completions/_rg \ No newline at end of file
diff --git a/test/fixtures/_comp_load/bin/cmd1 b/test/fixtures/_comp_load/bin/cmd1
deleted file mode 120000
index 5e6359b..0000000
--- a/test/fixtures/_comp_load/bin/cmd1
+++ /dev/null
@@ -1 +0,0 @@
-../prefix1/bin/cmd1 \ No newline at end of file
diff --git a/test/fixtures/_comp_load/bin/cmd2 b/test/fixtures/_comp_load/bin/cmd2
deleted file mode 120000
index 933265d..0000000
--- a/test/fixtures/_comp_load/bin/cmd2
+++ /dev/null
@@ -1 +0,0 @@
-../prefix1/sbin/cmd2 \ No newline at end of file
diff --git a/test/requirements-dev.txt b/test/requirements-dev.txt
index 7051ab7..68655c4 100644
--- a/test/requirements-dev.txt
+++ b/test/requirements-dev.txt
@@ -3,4 +3,4 @@
-r requirements.txt
mypy==1.8.0
-ruff==0.2.2
+ruff==0.3.5
diff --git a/test/t/conftest.py b/test/t/conftest.py
index 874ef1c..cb279cc 100644
--- a/test/t/conftest.py
+++ b/test/t/conftest.py
@@ -601,9 +601,9 @@ class bash_env_saved:
def _unprotect_variable(self, varname: str):
if varname not in self.saved_variables:
- self.saved_variables[
- varname
- ] = bash_env_saved.saved_state.ChangesDetected
+ self.saved_variables[varname] = (
+ bash_env_saved.saved_state.ChangesDetected
+ )
self._copy_variable(
varname, "%s_OLDVAR_%s" % (self.prefix, varname)
)
@@ -695,9 +695,9 @@ class bash_env_saved:
def save_variable(self, varname: str):
self._unprotect_variable(varname)
- self.saved_variables[
- varname
- ] = bash_env_saved.saved_state.ChangesIgnored
+ self.saved_variables[varname] = (
+ bash_env_saved.saved_state.ChangesIgnored
+ )
# TODO: We may restore the "export" attribute as well though it is
# not currently tested in "diff_env"
diff --git a/test/t/test_curl.py b/test/t/test_curl.py
index 07050e9..2b86997 100644
--- a/test/t/test_curl.py
+++ b/test/t/test_curl.py
@@ -27,6 +27,10 @@ class TestCurl:
assert completion == "d/"
assert not completion.endswith(" ")
+ @pytest.mark.complete("curl --proto-default ", require_cmd=True)
+ def test_proto_default(self, completion):
+ assert completion
+
@pytest.mark.complete("curl --dont-fail-in-unset-mode")
def test_unknown_option(self, completion):
# Just see that it does not error out
diff --git a/test/t/test_ip.py b/test/t/test_ip.py
index 0be088c..552015d 100644
--- a/test/t/test_ip.py
+++ b/test/t/test_ip.py
@@ -15,6 +15,23 @@ class TestIp:
assert completion
@pytest.mark.complete(
+ "ip stats show group ",
+ require_cmd=True,
+ skipif="ip stats help 2>/dev/null; (( $? != 255 ))",
+ )
+ def test_stats(self, completion):
+ # "link" was one of the first groups added, should always be there
+ assert "link" in completion
+
+ @pytest.mark.complete(
+ "ip neigh show nud ",
+ require_cmd=True,
+ skipif="ip neigh help 2>&1 | grep 'STATE :=' > /dev/null; (( $? != 0 ))",
+ )
+ def test_neigh_state(self, completion):
+ assert "stale" in completion
+
+ @pytest.mark.complete(
"ip monitor ",
require_cmd=True,
skipif="ip monitor help 2>/dev/null; (( $? != 255 ))",
@@ -23,6 +40,23 @@ class TestIp:
assert "neigh" in completion
assert "all" in completion
+ @pytest.mark.complete("ip netconf ")
+ def test_netconf(self, completion):
+ assert "show" in completion
+
+ @pytest.mark.complete("ip link property add ")
+ def test_link_property(self, completion):
+ assert "altname" in completion
+ assert "dev" in completion
+
+ @pytest.mark.complete(
+ "ip addr show type ",
+ require_cmd=True,
+ skipif="ip link help 2>/dev/null; (( $? != 255 ))",
+ )
+ def test_addr_type(self, completion):
+ assert "bridge" in completion
+
@pytest.mark.complete("ip -", require_cmd=True)
def test_options(self, completion):
assert "-family" in completion
diff --git a/test/t/test_java.py b/test/t/test_java.py
index 03f1520..407438b 100644
--- a/test/t/test_java.py
+++ b/test/t/test_java.py
@@ -1,6 +1,6 @@
import pytest
-from conftest import is_bash_type, assert_bash_exec, bash_env_saved
+from conftest import assert_bash_exec, bash_env_saved, is_bash_type
@pytest.mark.bashcomp(
diff --git a/test/t/test_perldoc.py b/test/t/test_perldoc.py
index 282f824..a5b36d7 100644
--- a/test/t/test_perldoc.py
+++ b/test/t/test_perldoc.py
@@ -9,7 +9,11 @@ class TestPerldoc:
assert "fixtures/" not in completion # Our fixtures/ dir
assert not [x for x in completion if "File::File::" in x]
- @pytest.mark.complete("perldoc -", require_cmd=True)
+ @pytest.mark.complete(
+ "perldoc -",
+ require_cmd=True,
+ skipif="! perldoc -V &>/dev/null",
+ )
def test_2(self, completion):
assert completion
diff --git a/test/t/unit/Makefile.am b/test/t/unit/Makefile.am
index 54722de..5a1eb47 100644
--- a/test/t/unit/Makefile.am
+++ b/test/t/unit/Makefile.am
@@ -2,7 +2,9 @@ EXTRA_DIST = \
test_unit_abspath.py \
test_unit_command_offset.py \
test_unit_compgen.py \
+ test_unit_compgen_available_interfaces.py \
test_unit_compgen_commands.py \
+ test_unit_compgen_split.py \
test_unit_count_args.py \
test_unit_delimited.py \
test_unit_deprecate_func.py \
@@ -18,6 +20,7 @@ EXTRA_DIST = \
test_unit_initialize.py \
test_unit_ip_addresses.py \
test_unit_known_hosts.py \
+ test_unit_load.py \
test_unit_longopt.py \
test_unit_looks_like_path.py \
test_unit_parse_help.py \
diff --git a/test/t/unit/test_unit_compgen.py b/test/t/unit/test_unit_compgen.py
index cfdec8e..fb04d74 100644
--- a/test/t/unit/test_unit_compgen.py
+++ b/test/t/unit/test_unit_compgen.py
@@ -1,7 +1,8 @@
-import pytest
import re
-from conftest import assert_bash_exec, bash_env_saved, assert_complete
+import pytest
+
+from conftest import assert_bash_exec, assert_complete, bash_env_saved
@pytest.mark.bashcomp(cmd=None)
diff --git a/test/t/unit/test_unit_compgen_available_interfaces.py b/test/t/unit/test_unit_compgen_available_interfaces.py
new file mode 100644
index 0000000..5e93100
--- /dev/null
+++ b/test/t/unit/test_unit_compgen_available_interfaces.py
@@ -0,0 +1,25 @@
+import pytest
+
+from conftest import assert_bash_exec
+
+
+@pytest.mark.bashcomp(cmd=None)
+class TestUtilCompgenAvailableInterfaces:
+ @pytest.fixture
+ def functions(self, bash):
+ assert_bash_exec(
+ bash,
+ "_comp__test_dump() { ((${#arr[@]})) && printf '<%s>' \"${arr[@]}\"; echo; }",
+ )
+ assert_bash_exec(
+ bash,
+ '_comp__test_compgen() { local -a arr=(00); _comp_compgen -v arr "$@"; _comp__test_dump; }',
+ )
+
+ def test_1_trailing_colons(self, bash, functions):
+ output = assert_bash_exec(
+ bash,
+ "_comp__test_compgen available_interfaces",
+ want_output=True,
+ )
+ assert ":" not in output.strip()
diff --git a/test/t/unit/test_unit_load.py b/test/t/unit/test_unit_load.py
new file mode 100644
index 0000000..3515703
--- /dev/null
+++ b/test/t/unit/test_unit_load.py
@@ -0,0 +1,130 @@
+import os
+
+import pytest
+
+from conftest import assert_bash_exec, bash_env_saved, prepare_fixture_dir
+
+
+@pytest.mark.bashcomp(cmd=None, cwd="_comp_load")
+class TestCompLoad:
+ @pytest.fixture
+ def fixture_dir(self, request, bash):
+ """Construct the fixture directory in a temporary directory.
+
+ Some of the tests use specific setups of symbolic links. However, if
+ we put the symbolic links in the static fixture directory, Automake
+ resolves them for tarballs. As a result, the tests fail when the files
+ are extracted from the tarballs. There does not seem to be any option
+ to change the behavior of Automake.
+
+ We instead manually set up all symbolic links needed for the tests
+ here. The other normal files and directories are statically included
+ in the repository as "/test/fixtures/_comp_load". We first copy the
+ statically included files and directories to a temporary directory and
+ set up symbolic links.
+ """
+
+ tmpdir, _, _ = prepare_fixture_dir(request, files=[], dirs=[])
+ assert_bash_exec(bash, "cp -R %s/* %s/" % (os.getcwd(), tmpdir))
+ assert_bash_exec(bash, "mkdir -p %s/bin" % tmpdir)
+ assert_bash_exec(
+ bash, "ln -sf ../prefix1/bin/cmd1 %s/bin/cmd1" % tmpdir
+ )
+ assert_bash_exec(
+ bash, "ln -sf ../prefix1/sbin/cmd2 %s/bin/cmd2" % tmpdir
+ )
+ return str(tmpdir)
+
+ def test_userdir_1(self, bash, fixture_dir):
+ with bash_env_saved(bash) as bash_env:
+ bash_env.chdir(fixture_dir)
+ bash_env.write_variable(
+ "BASH_COMPLETION_USER_DIR",
+ "$PWD/userdir1:$PWD/userdir2:$BASH_COMPLETION_USER_DIR",
+ quote=False,
+ )
+ bash_env.write_variable(
+ "PATH", "$PWD/prefix1/bin:$PWD/prefix1/sbin", quote=False
+ )
+ output = assert_bash_exec(
+ bash, "_comp_load cmd1", want_output=True
+ )
+ assert output.strip() == "cmd1: sourced from userdir1"
+ output = assert_bash_exec(
+ bash, "_comp_load cmd2", want_output=True
+ )
+ assert output.strip() == "cmd2: sourced from userdir2"
+
+ def test_PATH_1(self, bash, fixture_dir):
+ with bash_env_saved(bash) as bash_env:
+ bash_env.chdir(fixture_dir)
+ bash_env.write_variable(
+ "PATH", "$PWD/prefix1/bin:$PWD/prefix1/sbin", quote=False
+ )
+ output = assert_bash_exec(
+ bash, "_comp_load cmd1", want_output=True
+ )
+ assert output.strip() == "cmd1: sourced from prefix1"
+ output = assert_bash_exec(
+ bash, "_comp_load cmd2", want_output=True
+ )
+ assert output.strip() == "cmd2: sourced from prefix1"
+ output = assert_bash_exec(
+ bash, "complete -p cmd2", want_output=True
+ )
+ assert " cmd2" in output
+ output = assert_bash_exec(
+ bash, 'complete -p "$PWD/prefix1/sbin/cmd2"', want_output=True
+ )
+ assert "/prefix1/sbin/cmd2" in output
+
+ def test_cmd_path_1(self, bash, fixture_dir):
+ with bash_env_saved(bash) as bash_env:
+ bash_env.chdir(fixture_dir)
+ assert_bash_exec(bash, "complete -r cmd1 || :", want_output=None)
+ output = assert_bash_exec(
+ bash, "_comp_load prefix1/bin/cmd1", want_output=True
+ )
+ assert output.strip() == "cmd1: sourced from prefix1"
+ output = assert_bash_exec(
+ bash, 'complete -p "$PWD/prefix1/bin/cmd1"', want_output=True
+ )
+ assert "/prefix1/bin/cmd1" in output
+ assert_bash_exec(bash, "! complete -p cmd1", want_output=None)
+ output = assert_bash_exec(
+ bash, "_comp_load prefix1/sbin/cmd2", want_output=True
+ )
+ assert output.strip() == "cmd2: sourced from prefix1"
+ output = assert_bash_exec(
+ bash, "_comp_load bin/cmd1", want_output=True
+ )
+ assert output.strip() == "cmd1: sourced from prefix1"
+ output = assert_bash_exec(
+ bash, "_comp_load bin/cmd2", want_output=True
+ )
+ assert output.strip() == "cmd2: sourced from prefix1"
+
+ def test_cmd_path_2(self, bash, fixture_dir):
+ with bash_env_saved(bash) as bash_env:
+ bash_env.chdir(fixture_dir)
+ bash_env.write_variable("PATH", "$PWD/bin:$PATH", quote=False)
+ output = assert_bash_exec(
+ bash, "_comp_load cmd1", want_output=True
+ )
+ assert output.strip() == "cmd1: sourced from prefix1"
+ output = assert_bash_exec(
+ bash, "_comp_load cmd2", want_output=True
+ )
+ assert output.strip() == "cmd2: sourced from prefix1"
+
+ def test_cmd_intree_precedence(self, bash, fixture_dir):
+ """
+ Test in-tree, i.e. completions/$cmd relative to the main script
+ has precedence over location derived from PATH.
+ """
+ with bash_env_saved(bash) as bash_env:
+ bash_env.chdir(fixture_dir)
+ bash_env.write_variable("PATH", "$PWD/prefix1/bin", quote=False)
+ # The in-tree `sh` completion should be loaded here,
+ # and cause no output, unlike our `$PWD/prefix1/bin/sh` canary.
+ assert_bash_exec(bash, "_comp_load sh", want_output=False)
diff --git a/test/t/unit/test_unit_load_completion.py b/test/t/unit/test_unit_load_completion.py
deleted file mode 100644
index 6272e5b..0000000
--- a/test/t/unit/test_unit_load_completion.py
+++ /dev/null
@@ -1,94 +0,0 @@
-import pytest
-
-from conftest import assert_bash_exec, bash_env_saved
-
-
-@pytest.mark.bashcomp(cmd=None, cwd="_comp_load")
-class TestLoadCompletion:
- def test_userdir_1(self, bash):
- with bash_env_saved(bash) as bash_env:
- bash_env.write_variable(
- "BASH_COMPLETION_USER_DIR",
- "$PWD/userdir1:$PWD/userdir2:$BASH_COMPLETION_USER_DIR",
- quote=False,
- )
- bash_env.write_variable(
- "PATH", "$PWD/prefix1/bin:$PWD/prefix1/sbin", quote=False
- )
- output = assert_bash_exec(
- bash, "_comp_load cmd1", want_output=True
- )
- assert output.strip() == "cmd1: sourced from userdir1"
- output = assert_bash_exec(
- bash, "_comp_load cmd2", want_output=True
- )
- assert output.strip() == "cmd2: sourced from userdir2"
-
- def test_PATH_1(self, bash):
- with bash_env_saved(bash) as bash_env:
- bash_env.write_variable(
- "PATH", "$PWD/prefix1/bin:$PWD/prefix1/sbin", quote=False
- )
- output = assert_bash_exec(
- bash, "_comp_load cmd1", want_output=True
- )
- assert output.strip() == "cmd1: sourced from prefix1"
- output = assert_bash_exec(
- bash, "_comp_load cmd2", want_output=True
- )
- assert output.strip() == "cmd2: sourced from prefix1"
- output = assert_bash_exec(
- bash, "complete -p cmd2", want_output=True
- )
- assert " cmd2" in output
- output = assert_bash_exec(
- bash, 'complete -p "$PWD/prefix1/sbin/cmd2"', want_output=True
- )
- assert "/prefix1/sbin/cmd2" in output
-
- def test_cmd_path_1(self, bash):
- assert_bash_exec(bash, "complete -r cmd1 || :", want_output=None)
- output = assert_bash_exec(
- bash, "_comp_load prefix1/bin/cmd1", want_output=True
- )
- assert output.strip() == "cmd1: sourced from prefix1"
- output = assert_bash_exec(
- bash, 'complete -p "$PWD/prefix1/bin/cmd1"', want_output=True
- )
- assert "/prefix1/bin/cmd1" in output
- assert_bash_exec(bash, "! complete -p cmd1", want_output=None)
- output = assert_bash_exec(
- bash, "_comp_load prefix1/sbin/cmd2", want_output=True
- )
- assert output.strip() == "cmd2: sourced from prefix1"
- output = assert_bash_exec(
- bash, "_comp_load bin/cmd1", want_output=True
- )
- assert output.strip() == "cmd1: sourced from prefix1"
- output = assert_bash_exec(
- bash, "_comp_load bin/cmd2", want_output=True
- )
- assert output.strip() == "cmd2: sourced from prefix1"
-
- def test_cmd_path_2(self, bash):
- with bash_env_saved(bash) as bash_env:
- bash_env.write_variable("PATH", "$PWD/bin:$PATH", quote=False)
- output = assert_bash_exec(
- bash, "_comp_load cmd1", want_output=True
- )
- assert output.strip() == "cmd1: sourced from prefix1"
- output = assert_bash_exec(
- bash, "_comp_load cmd2", want_output=True
- )
- assert output.strip() == "cmd2: sourced from prefix1"
-
- def test_cmd_intree_precedence(self, bash):
- """
- Test in-tree, i.e. completions/$cmd relative to the main script
- has precedence over location derived from PATH.
- """
- with bash_env_saved(bash) as bash_env:
- bash_env.write_variable("PATH", "$PWD/prefix1/bin", quote=False)
- # The in-tree `sh` completion should be loaded here,
- # and cause no output, unlike our `$PWD/prefix1/bin/sh` canary.
- assert_bash_exec(bash, "_comp_load sh", want_output=False)
diff --git a/version.txt b/version.txt
index d8b6989..fb2c076 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-2.12.0
+2.13.0