Skip to content

Commit cfb3103

Browse files
committed
fix: completion load precedence more
1 parent 84aa00f commit cfb3103

File tree

1 file changed

+88
-36
lines changed

1 file changed

+88
-36
lines changed

bash_completion

Lines changed: 88 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3451,8 +3451,7 @@ _comp_load()
34513451
done
34523452
shift "$((OPTIND - 1))"
34533453
3454-
local cmd=$1 cmdname=${1##*/} dir compfile
3455-
local -a paths
3454+
local cmd=$1 cmdname=${1##*/}
34563455
[[ $cmdname ]] || return 1
34573456
34583457
local backslash=
@@ -3470,56 +3469,109 @@ _comp_load()
34703469
cmd=$REPLY
34713470
fi
34723471
3473-
local -a dirs=()
3472+
# Begin lookup
3473+
3474+
shift # cmd
3475+
local -a source_args=("$@")
3476+
local -a dirs
3477+
local dir
3478+
3479+
# There are two kinds of completion subdirs, main and fallback.
3480+
# Main subdirs are first looked up from all supported base locations,
3481+
# followed by fallback subdir lookups in certain locations.
3482+
3483+
# Typically, there is only one main completion subdir, "completions",
3484+
# and one fallback completion subdir, "completions-fallback".
3485+
3486+
# The location of the main bash_completion script, i.e. the "home" location
3487+
# of the bash-completion setup in use, is special a few respects.
3488+
# It is primarily for run-in-place-from-git-clone setups or ones unpacked
3489+
# from tarballs, typically user setups where we want to prefer in-tree
3490+
# completions over ones possibly coming with a system installed
3491+
# bash-completion.
3492+
#
3493+
# It supports an additional "completions-core" main subdir to look up from.
3494+
# This subdir contains completion snippets that come with that
3495+
# bash-completion version, and snippets in it are looked up after the usual
3496+
# "completions" dir. The "completions" dir in this location is for other
3497+
# completion snippets, such as ones installed by packages shipping
3498+
# completions of their own.
3499+
#
3500+
# Completions in the "completions-core" subdir may make use of
3501+
# bash-completion's internal API that is highly version specific.
3502+
# Therefore we do not look up from any other "completions-core" subdir
3503+
# besides this one.
3504+
#
3505+
# This location is also the only one from which we look up fallback
3506+
# completions from. These may also make use of bash-completion's internal
3507+
# API, and as it is assumed there's little if any need for a fallback
3508+
# hierarchy, we don't do it "just in case" to avoid some lookups.
3509+
3510+
# Filenames we look up from in usual main subdirs have the name of the
3511+
# command we are looking up a completion for, with .bash suffix appended
3512+
# (recommended) or no suffix. From others (i.e. ones containing files
3513+
# that are part of the bash-completion version in use), only the one with
3514+
# .bash appended is considered.
3515+
3516+
# 1) From user locations
34743517
3475-
# Lookup order:
3476-
# 1) From BASH_COMPLETION_USER_DIR (e.g. ~/.local/share/bash-completion):
3477-
# User installed completions.
34783518
if [[ ${BASH_COMPLETION_USER_DIR-} ]]; then
3479-
_comp_split -F : dirs "$BASH_COMPLETION_USER_DIR" &&
3480-
dirs+=("${paths[@]/%*(\/)//completions}")
3519+
_comp_split -F : dirs "$BASH_COMPLETION_USER_DIR"
34813520
else
3482-
dirs=("${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion/completions")
3521+
dirs=("${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion")
34833522
fi
3523+
for dir in "${dirs[@]}"; do
3524+
_comp_load__visit_file "$dir/completions/$cmdname.bash" && return 0
3525+
_comp_load__visit_file "$dir/completions/$cmdname" && return 0
3526+
done
3527+
3528+
# 2) From the bash-completion "home" location
34843529
3485-
# 2) From the location of bash_completion: Completions relative to the main
3486-
# script. This is primarily for run-in-place-from-git-clone setups, where
3487-
# we want to prefer in-tree completions over ones possibly coming with a
3488-
# system installed bash-completion. (Due to usual install layouts, this
3489-
# often hits the correct completions in system installations, too.)
3490-
dirs+=("$_comp__base_directory"/completions{,-core,-fallback})
3530+
_comp_load__visit_file \
3531+
"$_comp__base_directory/completions/$cmdname.bash" && return 0
3532+
_comp_load__visit_file \
3533+
"$_comp__base_directory/completions/$cmdname" && return 0
3534+
_comp_load__visit_file \
3535+
"$_comp__base_directory/completions-core/$cmdname.bash" && return 0
34913536
3492-
# 3) From bin directories extracted from the specified path to the command,
3537+
# 3) From bin directories extracted from a specified path to the command,
34933538
# the real path to the command, and $PATH
3494-
paths=()
3495-
[[ $cmd == /* ]] && paths+=("${cmd%/*}")
3496-
_comp_realcommand "$cmd" && paths+=("${REPLY%/*}")
3497-
_comp_split -aF : paths "$PATH"
3498-
for dir in "${paths[@]%/}"; do
3499-
[[ $dir == ?*/@(bin|sbin) ]] &&
3500-
dirs+=("${dir%/*}/share/bash-completion"/completions)
3501-
done
35023539
3503-
# 4) From XDG_DATA_DIRS or system dirs (e.g. /usr/share, /usr/local/share):
3504-
# Completions in the system data dirs.
3505-
_comp_split -F : paths "${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" &&
3506-
dirs+=("${paths[@]/%//bash-completion}"/completions)
3540+
dirs=()
3541+
[[ $cmd == /* ]] && dirs+=("${cmd%/*}")
3542+
_comp_realcommand "$cmd" && dirs+=("${REPLY%/*}")
3543+
_comp_split -aF : dirs "$PATH"
3544+
for dir in "${dirs[@]%/}"; do
3545+
if [[ $dir == ?*/@(bin|sbin) ]]; then
3546+
_comp_load__visit_file "${dir%/*}/share/bash-completion/completions/$cmdname.bash" && return 0
3547+
_comp_load__visit_file "${dir%/*}/share/bash-completion/completions/$cmdname" && return 0
3548+
fi
3549+
done
35073550
3508-
# Look up and source
3509-
shift
3510-
local -a source_args=("$@")
3551+
# 4) From bash-completion subdir in XDG_DATA_DIRS or system dirs
3552+
# (e.g. /usr/share, /usr/local/share) -- typically meaning a system
3553+
# installed one if the one in use is not that, see 2) above
35113554
3555+
_comp_split -F : dirs "${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
35123556
for dir in "${dirs[@]}"; do
3513-
[[ -d $dir ]] || continue
3514-
for compfile in "$cmdname.bash" "$cmdname"; do
3515-
_comp_load__visit_file "$dir/$compfile" && return 0
3516-
done
3557+
_comp_load__visit_file \
3558+
"$dir/bash-completion/completions/$cmdname.bash" && return 0
3559+
_comp_load__visit_file \
3560+
"$dir/bash-completion/completions/$cmdname" && return 0
35173561
done
35183562
3519-
# Look up simple "xspec" completions
3563+
# 5) From the fallback completion dir
3564+
3565+
_comp_load__visit_file \
3566+
"$_comp__base_directory/completions-fallback/$cmdname.bash" && return 0
3567+
3568+
# 6) Simple "xspec" completions
3569+
35203570
[[ -v _comp_xspecs[$cmdname] || -v _xspecs[$cmdname] ]] &&
35213571
complete -F _comp_complete_filedir_xspec "$cmdname" "$backslash$cmdname" && return 0
35223572
3573+
# Last) fallback to minimal if applicable
3574+
35233575
if [[ $flag_fallback_default ]]; then
35243576
complete -F _comp_complete_minimal -- "$origcmd" && return 0
35253577
fi

0 commit comments

Comments
 (0)