Skip to content

Commit 47186ae

Browse files
committed
refactor: update the locations of completions and helpers
* refactor: move "completions{/_ => -fallback/}<cmd>" * refcator: move "completions{ => -core}/<cmd>" * refcator: move "helpers{ => -core}/*" * fix(_comp_load): completion files in "<bash-completion>/completions-core" and "<bash-completion>/completions-fallback" are searched finally.
1 parent b4dda6d commit 47186ae

27 files changed

+2076
-1995
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ repos:
3939
name: update-test-fallback-links
4040
language: script
4141
entry: test/fallback/update-fallback-links
42-
files: ^completions-core/_
42+
files: ^completions-fallback/
4343
pass_filenames: false
4444

4545
- repo: https://github.com/astral-sh/ruff-pre-commit

.typos.toml

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,66 +3,66 @@
33
BRE = "BRE"
44

55
[default.extend-words]
6-
# completions/abook
6+
# completions-core/abook
77
informat = "informat"
8-
# completions/ri
8+
# completions-core/ri
99
ane = "ane"
10-
# completions/reportbug
10+
# completions-core/reportbug
1111
buildd = "buildd"
12-
# completions/tar
12+
# completions-core/tar
1313
caf = "caf"
14-
# completions/chage, test/t/Makefile.am, test/t/test_chage.py,
14+
# completions-core/chage, test/t/Makefile.am, test/t/test_chage.py,
1515
# test/test-cmd-list.txt
1616
chage = "chage"
1717
# test/t/test_ccache.py
1818
clea = "clea"
1919
# test/t/test_pylint_3.py
2020
clien = "clien"
21-
# completions/openssl
21+
# completions-core/openssl
2222
ede = "ede"
23-
# completions/patch
23+
# completions-core/patch
2424
fior = "fior"
25-
# completions/make
25+
# completions-core/make
2626
fo = "fo"
27-
# completions/.gitignore, completions/Makefile.am, completions/_hexdump,
28-
# completions/gnome-screenshot, completions/mii-diag, completions/mii-tool,
29-
# completions/qemu,
27+
# completions-fallback/.gitignore, completions-fallback/Makefile.am,
28+
# completions-fallback/_hexdump, completions-core/gnome-screenshot,
29+
# completions-core/mii-diag, completions-core/mii-tool, completions-core/qemu,
3030
hd = "hd"
3131
# test/t/test_ccache.py
3232
hel = "hel"
33-
# completions/bts
33+
# completions-core/bts
3434
helo = "helo"
35-
# completions/ip
35+
# completions-core/ip
3636
iif = "iif"
37-
# completions/tcpdump
37+
# completions-core/tcpdump
3838
inout = "inout"
3939
# test/t/unit/test_unit_expand_glob.py
4040
ket = "ket"
41-
# completions/isql
41+
# completions-core/isql
4242
Lins = "Lins"
43-
# completions/hcitool, completions/ip
43+
# completions-core/hcitool, completions-core/ip
4444
lst = "lst"
45-
# completions/tshark, test/t/test_screen.py
45+
# completions-core/tshark, test/t/test_screen.py
4646
nd = "nd"
4747
# bash_completion
4848
odf = "odf"
49-
# completions/ip
49+
# completions-core/ip
5050
oif = "oif"
51-
# completions/mplayer
51+
# completions-core/mplayer
5252
oly = "oly"
5353
# test/t/unit/test_unit_find_unique_completion_pair.py
5454
ot = "ot"
55-
# completions/modinfo
55+
# completions-core/modinfo
5656
parm = "parm"
57-
# bash_completion, completions/eog, completions/gnome-screenshot,
57+
# bash_completion, completions-core/eog, completions-core/gnome-screenshot,
5858
# test/t/test_nmap.py
5959
pn = "pn"
60-
# completions/wget
60+
# completions-core/wget
6161
referer = "referer"
62-
# completions/_mount.linux, completions/tune2fs, test/t/test_curl.py,
62+
# completions-core/_mount.linux, completions-core/tune2fs, test/t/test_curl.py,
6363
# test/t/unit/test_unit_find_unique_completion_pair.py
6464
ro = "ro"
65-
# completions/ps
65+
# completions-core/ps
6666
ser = "ser"
6767

6868
[files]

Makefile.am

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
SUBDIRS = completions doc helpers test
1+
SUBDIRS = doc completions-core completions-fallback helpers-core \
2+
test completions helpers
23

34
pkgdata_DATA = bash_completion
45

README.md

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -370,24 +370,26 @@ A. Absolutely not. zsh has an extremely sophisticated completion system
370370
**Q. What is the search order for the completion file of each target command?**
371371

372372
A. The completion files of commands are looked up by the shell function
373-
`__load_completion`. Here, the search order in bash-completion >= 2.12 is
374-
explained.
375-
376-
1. `BASH_COMPLETION_USER_DIR`. The subdirectory `completions` of each paths
377-
in `BASH_COMPLETION_USER_DIR` separated by colons is considered for a
378-
completion directory.
379-
2. The location of the main `bash_completion` file. The subdirectory
380-
`completions` in the same directory as `bash_completion` is considered.
373+
`__load_completion`. Here, the search order in bash-completion >= 2.18 is
374+
explained. We first list up the bash-completion directories:
375+
376+
1. `BASH_COMPLETION_USER_DIR`. Each paths in `BASH_COMPLETION_USER_DIR`
377+
separated by colons is considered for a completion directory.
378+
2. The location of the main `bash_completion` file. The directory
379+
containing `bash_completion` is considered.
381380
3. The location of the target command. When the real location of the command
382381
is in the directory `<prefix>/bin` or `<prefix>/sbin`, the directory
383-
`<prefix>/share/bash-completion/completions` is considered.
382+
`<prefix>/share/bash-completion` is considered.
384383
4. `XDG_DATA_DIRS` (or the system directories `/usr/local/share:/usr/share`
385-
if empty). The subdirectory `bash-completion/completions` of each paths
384+
if empty). The subdirectory `bash-completion` of each paths
386385
in `XDG_DATA_DIRS` separated by colons is considered.
387386

388-
The completion files of the name `<cmd>` or `<cmd>.bash`, where `<cmd>` is
389-
the name of the target command, are searched in the above completion
390-
directories in order. The file that is found first is used. When no
391-
completion file is found in any completion directories in this process, the
392-
completion files of the name `_<cmd>` is next searched in the completion
393-
directories in order.
387+
The completion files of the name `<cmd>.bash` or `<cmd>`, where `<cmd>` is
388+
the name of the target command, are searched in the subdirectory
389+
`completions` in the above bash-completion directories in order. The file
390+
that is found first is used. When no completion file is found in this step,
391+
the completion files of the name `_<cmd>` is next searched in the
392+
`completions` subdirectories in order. When no completion file has not yet
393+
been found in any `completions` directories, the completion files in the
394+
subdirectory `completions-core` and `completions-fallback` at the location of
395+
the main `bash_completion` file are searched in order.

bash_completion

Lines changed: 66 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3372,6 +3372,58 @@ _comp__init_base_directory()
33723372
}
33733373
_comp__init_base_directory
33743374
3375+
# Attempt to load the specified file and check if the completion setting is
3376+
# successfully loaded.
3377+
#
3378+
# @param $1 compfile ... filename to check.
3379+
# @var[in] cmdname
3380+
# @var[in] cmd
3381+
# @var[in] backslash
3382+
# @var[in] origcmd
3383+
# @var[in] source_args
3384+
# @exit 0 when the file is found, and the completion setting was successfully
3385+
# loaded. Otherwise, 1.
3386+
_comp_load__visit_file()
3387+
{
3388+
local compfile=$1
3389+
shift
3390+
[[ -e $compfile ]] || return 1
3391+
3392+
# Set up default $IFS in case loaded completions depend on it, as well as
3393+
# for $compspec invocation below.
3394+
local IFS=$' \t\n' compspec
3395+
3396+
# Avoid trying to source dirs as long as we support bash < 4.3
3397+
# to avoid an fd leak; https://bugzilla.redhat.com/903540
3398+
if [[ -d $compfile ]]; then
3399+
# Do not warn with . or .. (especially the former is common)
3400+
[[ $compfile == */.?(.) ]] ||
3401+
echo "bash_completion: $compfile: is a directory" >&2
3402+
elif . "$compfile" "$cmd" ${source_args[@]+"${source_args[@]}"}; then
3403+
3404+
# At least $cmd is expected to have a completion set when we return
3405+
# successfully; see if it already does
3406+
if compspec=$(complete -p -- "$cmd" 2>/dev/null); then
3407+
# $cmd is the case in which we do backslash processing
3408+
[[ $backslash ]] && eval "$compspec \"\$backslash\$cmd\""
3409+
# If invoked without path, that one should be set, too
3410+
# ...but let's not overwrite an existing one, if any
3411+
[[ $origcmd != */* ]] &&
3412+
! complete -p -- "$origcmd" &>/dev/null &&
3413+
eval "$compspec \"\$origcmd\""
3414+
return 0
3415+
fi
3416+
# If not, see if we got one for $cmdname
3417+
if [[ $cmdname != "$cmd" ]] && compspec=$(complete -p -- "$cmdname" 2>/dev/null); then
3418+
# Use that for $cmd too, if we have a full path to it
3419+
[[ $cmd == /* ]] && eval "$compspec \"\$cmd\""
3420+
return 0
3421+
fi
3422+
# Nothing expected was set, continue lookup
3423+
fi
3424+
return 1
3425+
}
3426+
33753427
# @since 2.12
33763428
_comp_load()
33773429
{
@@ -3413,18 +3465,17 @@ _comp_load()
34133465
# 1) From BASH_COMPLETION_USER_DIR (e.g. ~/.local/share/bash-completion):
34143466
# User installed completions.
34153467
if [[ ${BASH_COMPLETION_USER_DIR-} ]]; then
3416-
_comp_split -F : paths "$BASH_COMPLETION_USER_DIR" &&
3417-
dirs+=("${paths[@]/%//completions}")
3468+
_comp_split -F : dirs "$BASH_COMPLETION_USER_DIR"
34183469
else
3419-
dirs=("${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion/completions")
3470+
dirs=("${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion")
34203471
fi
34213472
34223473
# 2) From the location of bash_completion: Completions relative to the main
34233474
# script. This is primarily for run-in-place-from-git-clone setups, where
34243475
# we want to prefer in-tree completions over ones possibly coming with a
34253476
# system installed bash-completion. (Due to usual install layouts, this
34263477
# often hits the correct completions in system installations, too.)
3427-
dirs+=("$_comp__base_directory/completions")
3478+
dirs+=("$_comp__base_directory")
34283479
34293480
# 3) From bin directories extracted from the specified path to the command,
34303481
# the real path to the command, and $PATH
@@ -3434,60 +3485,30 @@ _comp_load()
34343485
_comp_split -aF : paths "$PATH"
34353486
for dir in "${paths[@]%/}"; do
34363487
[[ $dir == ?*/@(bin|sbin) ]] &&
3437-
dirs+=("${dir%/*}/share/bash-completion/completions")
3488+
dirs+=("${dir%/*}/share/bash-completion")
34383489
done
34393490
34403491
# 4) From XDG_DATA_DIRS or system dirs (e.g. /usr/share, /usr/local/share):
34413492
# Completions in the system data dirs.
34423493
_comp_split -F : paths "${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" &&
3443-
dirs+=("${paths[@]/%//bash-completion/completions}")
3444-
3445-
# Set up default $IFS in case loaded completions depend on it,
3446-
# as well as for $compspec invocation below.
3447-
local IFS=$' \t\n'
3494+
dirs+=("${paths[@]/%//bash-completion}")
34483495
34493496
# Look up and source
34503497
shift
3451-
local i prefix compspec
3498+
local -a source_args=("$@")
3499+
3500+
local i prefix
34523501
for prefix in "" _; do # Regular from all dirs first, then fallbacks
3453-
for i in ${!dirs[*]}; do
3454-
dir=${dirs[i]}
3455-
if [[ ! -d $dir ]]; then
3456-
unset -v 'dirs[i]'
3457-
continue
3458-
fi
3502+
for i in "${!dirs[@]}"; do
3503+
dir=${dirs[i]}/completions
3504+
[[ -d $dir ]] || continue
34593505
for compfile in "$prefix$cmdname" "$prefix$cmdname.bash"; do
3460-
compfile="$dir/$compfile"
3461-
# Avoid trying to source dirs as long as we support bash < 4.3
3462-
# to avoid an fd leak; https://bugzilla.redhat.com/903540
3463-
if [[ -d $compfile ]]; then
3464-
# Do not warn with . or .. (especially the former is common)
3465-
[[ $compfile == */.?(.) ]] ||
3466-
echo "bash_completion: $compfile: is a directory" >&2
3467-
elif [[ -e $compfile ]] && . "$compfile" "$cmd" "$@"; then
3468-
# At least $cmd is expected to have a completion set when
3469-
# we return successfully; see if it already does
3470-
if compspec=$(complete -p -- "$cmd" 2>/dev/null); then
3471-
# $cmd is the case in which we do backslash processing
3472-
[[ $backslash ]] && eval "$compspec \"\$backslash\$cmd\""
3473-
# If invoked without path, that one should be set, too
3474-
# ...but let's not overwrite an existing one, if any
3475-
[[ $origcmd != */* ]] &&
3476-
! complete -p -- "$origcmd" &>/dev/null &&
3477-
eval "$compspec \"\$origcmd\""
3478-
return 0
3479-
fi
3480-
# If not, see if we got one for $cmdname
3481-
if [[ $cmdname != "$cmd" ]] && compspec=$(complete -p -- "$cmdname" 2>/dev/null); then
3482-
# Use that for $cmd too, if we have a full path to it
3483-
[[ $cmd == /* ]] && eval "$compspec \"\$cmd\""
3484-
return 0
3485-
fi
3486-
# Nothing expected was set, continue lookup
3487-
fi
3506+
_comp_load__visit_file "$dir/$compfile" && return 0
34883507
done
34893508
done
34903509
done
3510+
_comp_load__visit_file "$_comp__base_directory/completions-core/$cmdname.bash" && return 0
3511+
_comp_load__visit_file "$_comp__base_directory/completions-fallback/$cmdname.bash" && return 0
34913512
34923513
# Look up simple "xspec" completions
34933514
[[ -v _comp_xspecs[$cmdname] || -v _xspecs[$cmdname] ]] &&

0 commit comments

Comments
 (0)