From 9a387d159503e992baf5516ca201ab850d8f1335 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Thu, 22 Dec 2022 08:31:38 +0200 Subject: [PATCH 1/3] refactor: ground work for shipping depreated things in a separate file https://github.com/scop/bash-completion/discussions/537#discussioncomment-3613857 --- Makefile.am | 5 +- bash_completion | 132 ------------------- bash_completion.d/000_bash_completion_compat | 132 +++++++++++++++++++ test/config/bashrc | 5 +- 4 files changed, 137 insertions(+), 137 deletions(-) create mode 100644 bash_completion.d/000_bash_completion_compat diff --git a/Makefile.am b/Makefile.am index 55000feb73b..cf7a743f0e9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,7 +4,7 @@ pkgdata_DATA = bash_completion # Empty, but here just to get the compat dir created with install compatdir = $(sysconfdir)/bash_completion.d -compat_DATA = +compat_DATA = bash_completion.d/000_bash_completion_compat profiledir = $(sysconfdir)/profile.d profile_DATA = bash_completion.sh @@ -31,7 +31,8 @@ CLEANFILES = bash_completion.sh bash-completion.pc \ EXTRA_DIST = CHANGELOG.md $(pkgdata_DATA) bash_completion.sh.in .dir-locals.el \ .editorconfig README.md CONTRIBUTING.md pyproject.toml .perltidyrc \ .shellcheckrc bash-completion.pc.in bash-completion-config.cmake.in \ - bash-completion-config-version.cmake.in setup-symlinks.sh + bash-completion-config-version.cmake.in setup-symlinks.sh \ + $(compat_DATA) install-data-hook: tmpfile=`mktemp $${TMPDIR:-/tmp}/bash_completion.XXXXXX` && \ diff --git a/bash_completion b/bash_completion index 594e429e110..9884737e539 100644 --- a/bash_completion +++ b/bash_completion @@ -98,8 +98,6 @@ _comp_userland() [[ $userland == "$1" ]] } -_comp_deprecate_func _userland _comp_userland - # This function sets correct SysV init directories # _comp_sysvdirs() @@ -112,8 +110,6 @@ _comp_sysvdirs() return 0 } -_comp_deprecate_func _sysvdirs _comp_sysvdirs - # This function checks whether we have a given program on the system. # _comp_have_command() @@ -123,18 +119,6 @@ _comp_have_command() PATH=$PATH:/usr/sbin:/sbin:/usr/local/sbin type "$1" &>/dev/null } -_comp_deprecate_func _have _comp_have_command - -# Backwards compatibility for compat completions that use have(). -# @deprecated should no longer be used; generally not needed with dynamically -# loaded completions, and _comp_have_command is suitable for runtime use. -# shellcheck disable=SC2317 # available at load time only -have() -{ - unset -v have - _comp_have_command "$1" && have=yes -} - # This function checks whether a given readline variable # is `on'. # @@ -143,8 +127,6 @@ _comp_readline_variable_on() [[ $(bind -v) == *$1+([[:space:]])on* ]] } -_comp_deprecate_func _rl_enabled _comp_readline_variable_on - # This function shell-quotes the argument # @param $1 String to be quoted # @var[out] ret Resulting string @@ -153,15 +135,6 @@ _comp_quote() ret=\'${1//\'/\'\\\'\'}\' } -# This function shell-quotes the argument -# @deprecated Use `_comp_quote` instead. Note that `_comp_quote` stores -# the results in the variable `ret` instead of writing them to stdout. -quote() -{ - local quoted=${1//\'/\'\\\'\'} - printf "'%s'" "$quoted" -} - # @see _quote_readline_by_ref() quote_readline() { @@ -231,18 +204,6 @@ _comp_dequote() eval "ret=($1)" 2>/dev/null # may produce failglob } -# This function shell-dequotes the argument -# @deprecated Use `_comp_dequote' instead. Note that `_comp_dequote` stores -# the results in the array `ret` instead of writing them to stdout. -dequote() -{ - local ret - _comp_dequote "$1" - local rc=$? - printf %s "$ret" - return $rc -} - # Unset the given variables across a scope boundary. Useful for unshadowing # global scoped variables. Note that simply calling unset on a local variable # will not unshadow the global variable. Rather, the result will be a local @@ -260,29 +221,6 @@ _comp_unlocal() fi } -# Assign variable one scope above the caller -# Usage: local "$1" && _upvar $1 "value(s)" -# @param $1 Variable name to assign value to -# @param $* Value(s) to assign. If multiple values, an array is -# assigned, otherwise a single value is assigned. -# NOTE: For assigning multiple variables, use '_upvars'. Do NOT -# use multiple '_upvar' calls, since one '_upvar' call might -# reassign a variable to be used by another '_upvar' call. -# @see https://fvue.nl/wiki/Bash:_Passing_variables_by_reference -_upvar() -{ - echo "bash_completion: $FUNCNAME: deprecated function," \ - "use _upvars instead" >&2 - if unset -v "$1"; then # Unset & validate varname - # shellcheck disable=SC2140 # TODO - if (($# == 2)); then - eval "$1"=\"\$2\" # Return single value - else - eval "$1"=\(\"\$"{@:2}"\"\) # Return array - fi - fi -} - # Assign variables one scope above the caller # Usage: local varname [varname ...] && # _upvars [-v varname value] | [-aN varname [value ...]] ... @@ -648,66 +586,6 @@ _get_comp_words_by_ref() ((${#upvars[@]})) && local "${upvars[@]}" && _upvars "${upargs[@]}" } -# Get the word to complete. -# This is nicer than ${COMP_WORDS[COMP_CWORD]}, since it handles cases -# where the user is completing in the middle of a word. -# (For example, if the line is "ls foobar", -# and the cursor is here --------> ^ -# @param $1 string Characters out of $COMP_WORDBREAKS which should NOT be -# considered word breaks. This is useful for things like scp where -# we want to return host:path and not only path, so we would pass the -# colon (:) as $1 in this case. -# @param $2 integer Index number of word to return, negatively offset to the -# current word (default is 0, previous is 1), respecting the exclusions -# given at $1. For example, `_get_cword "=:" 1' returns the word left of -# the current word, respecting the exclusions "=:". -# @deprecated Use `_get_comp_words_by_ref cur' instead -# @see _get_comp_words_by_ref() -_get_cword() -{ - local LC_CTYPE=C - local cword words - __reassemble_comp_words_by_ref "${1-}" words cword - - # return previous word offset by $2 - if [[ ${2-} && ${2//[^0-9]/} ]]; then - printf "%s" "${words[cword - $2]}" - elif ((${#words[cword]} == 0 && COMP_POINT == ${#COMP_LINE})); then - : # nothing - else - local i - local cur=$COMP_LINE - local index=$COMP_POINT - for ((i = 0; i <= cword; ++i)); do - # Current word fits in $cur, and $cur doesn't match cword? - while [[ ${#cur} -ge ${#words[i]} && - ${cur:0:${#words[i]}} != "${words[i]}" ]]; do - # Strip first character - cur=${cur:1} - # Decrease cursor position, staying >= 0 - ((index > 0)) && ((index--)) - done - - # Does found word match cword? - if ((i < cword)); then - # No, cword lies further; - local old_size=${#cur} - cur=${cur#"${words[i]}"} - local new_size=${#cur} - ((index -= old_size - new_size)) - fi - done - - if [[ ${words[cword]:0:${#cur}} != "$cur" ]]; then - # We messed up! At least return the whole word so things - # keep working - printf "%s" "${words[cword]}" - else - printf "%s" "${cur:0:index}" - fi - fi -} # _get_cword() - # Get word previous to the current word. # This is a good alternative to `prev=${COMP_WORDS[COMP_CWORD-1]}' because bash4 # will properly return the previous word with respect to any given exclusions to @@ -1127,7 +1005,6 @@ _comp_initialize() return 0 } -_comp_deprecate_func _init_completion _comp_initialize # Helper function for _parse_help and _parse_usage. # @return True (0) if an option was found, False (> 0) otherwise @@ -1582,10 +1459,6 @@ _gids() # _comp_backup_glob='@(#*#|*@(~|.@(bak|orig|rej|swp|dpkg*|rpm@(orig|new|save))))' -# @deprecated Use the variable `_comp_backup_glob` instead. This is the -# backward-compatibility name. -_backup_glob=$_comp_backup_glob - # Complete on xinetd services # _xinetd_services() @@ -2387,7 +2260,6 @@ _comp_command_offset() done fi } -_comp_deprecate_func _command_offset _comp_command_offset # A _comp_command_offset wrapper function for use when the offset is unknown. # Only intended to be used as a completion function directly associated @@ -2407,7 +2279,6 @@ _comp_command() done _comp_command_offset $offset } -_comp_deprecate_func _command _comp_command complete -F _comp_command aoss command "do" else eval exec ltrace nice nohup padsp \ "then" time tsocks vsound xargs @@ -2417,7 +2288,6 @@ _comp_root_command() local root_command=$1 _comp_command } -_comp_deprecate_func _root_command _comp_root_command complete -F _comp_root_command fakeroot gksu gksudo kdesudo really # Return true if the completion should be treated as running as root @@ -2739,8 +2609,6 @@ _comp_xfunc() "$xfunc_name" "${@:3}" } -_comp_deprecate_func _xfunc _comp_xfunc - # source compat completion directory definitions _comp__init_compat_dir=${BASH_COMPLETION_COMPAT_DIR:-/etc/bash_completion.d} if [[ -d $_comp__init_compat_dir && -r $_comp__init_compat_dir && -x $_comp__init_compat_dir ]]; then diff --git a/bash_completion.d/000_bash_completion_compat b/bash_completion.d/000_bash_completion_compat new file mode 100644 index 00000000000..4ee534ff509 --- /dev/null +++ b/bash_completion.d/000_bash_completion_compat @@ -0,0 +1,132 @@ +# Deprecated bash_completion functions and variables -*- shell-script -*- + +_comp_deprecate_func _userland _comp_userland +_comp_deprecate_func _sysvdirs _comp_sysvdirs +_comp_deprecate_func _have _comp_have_command +_comp_deprecate_func _rl_enabled _comp_readline_variable_on +_comp_deprecate_func _init_completion _comp_initialize +_comp_deprecate_func _command_offset _comp_command_offset +_comp_deprecate_func _command _comp_command +_comp_deprecate_func _root_command _comp_root_command +_comp_deprecate_func _xfunc _comp_xfunc + +# Backwards compatibility for compat completions that use have(). +# @deprecated should no longer be used; generally not needed with dynamically +# loaded completions, and _comp_have_command is suitable for +# runtime use. +# shellcheck disable=SC2317 # available at load time only +have() +{ + unset -v have + _comp_have_command "$1" && have=yes +} + +# This function shell-quotes the argument +# @deprecated Use `_comp_quote` instead. Note that `_comp_quote` stores +# the results in the variable `ret` instead of writing them to stdout. +quote() +{ + local quoted=${1//\'/\'\\\'\'} + printf "'%s'" "$quoted" +} + +# This function shell-dequotes the argument +# @deprecated Use `_comp_dequote' instead. Note that `_comp_dequote` stores +# the results in the array `ret` instead of writing them to stdout. +dequote() +{ + local ret + _comp_dequote "$1" + local rc=$? + printf %s "$ret" + return $rc +} + +# Assign variable one scope above the caller +# Usage: local "$1" && _upvar $1 "value(s)" +# @param $1 Variable name to assign value to +# @param $* Value(s) to assign. If multiple values, an array is +# assigned, otherwise a single value is assigned. +# NOTE: For assigning multiple variables, use '_upvars'. Do NOT +# use multiple '_upvar' calls, since one '_upvar' call might +# reassign a variable to be used by another '_upvar' call. +# @see https://fvue.nl/wiki/Bash:_Passing_variables_by_reference +_upvar() +{ + echo "bash_completion: $FUNCNAME: deprecated function," \ + "use _upvars instead" >&2 + if unset -v "$1"; then # Unset & validate varname + # shellcheck disable=SC2140 # TODO + if (($# == 2)); then + eval "$1"=\"\$2\" # Return single value + else + eval "$1"=\(\"\$"{@:2}"\"\) # Return array + fi + fi +} + +# Get the word to complete. +# This is nicer than ${COMP_WORDS[COMP_CWORD]}, since it handles cases +# where the user is completing in the middle of a word. +# (For example, if the line is "ls foobar", +# and the cursor is here --------> ^ +# @param $1 string Characters out of $COMP_WORDBREAKS which should NOT be +# considered word breaks. This is useful for things like scp where +# we want to return host:path and not only path, so we would pass the +# colon (:) as $1 in this case. +# @param $2 integer Index number of word to return, negatively offset to the +# current word (default is 0, previous is 1), respecting the exclusions +# given at $1. For example, `_get_cword "=:" 1' returns the word left of +# the current word, respecting the exclusions "=:". +# @deprecated Use `_get_comp_words_by_ref cur' instead +# @see _get_comp_words_by_ref() +_get_cword() +{ + local LC_CTYPE=C + local cword words + __reassemble_comp_words_by_ref "${1-}" words cword + + # return previous word offset by $2 + if [[ ${2-} && ${2//[^0-9]/} ]]; then + printf "%s" "${words[cword - $2]}" + elif ((${#words[cword]} == 0 && COMP_POINT == ${#COMP_LINE})); then + : # nothing + else + local i + local cur=$COMP_LINE + local index=$COMP_POINT + for ((i = 0; i <= cword; ++i)); do + # Current word fits in $cur, and $cur doesn't match cword? + while [[ ${#cur} -ge ${#words[i]} && + ${cur:0:${#words[i]}} != "${words[i]}" ]]; do + # Strip first character + cur=${cur:1} + # Decrease cursor position, staying >= 0 + ((index > 0)) && ((index--)) + done + + # Does found word match cword? + if ((i < cword)); then + # No, cword lies further; + local old_size=${#cur} + cur=${cur#"${words[i]}"} + local new_size=${#cur} + ((index -= old_size - new_size)) + fi + done + + if [[ ${words[cword]:0:${#cur}} != "$cur" ]]; then + # We messed up! At least return the whole word so things + # keep working + printf "%s" "${words[cword]}" + else + printf "%s" "${cur:0:index}" + fi + fi +} # _get_cword() + +# @deprecated Use the variable `_comp_backup_glob` instead. This is the +# backward-compatibility name. +_backup_glob=$_comp_backup_glob + +# ex: filetype=sh diff --git a/test/config/bashrc b/test/config/bashrc index 9b3774d5b10..b6296f7c873 100644 --- a/test/config/bashrc +++ b/test/config/bashrc @@ -37,9 +37,7 @@ export BASH_COMPLETION_USER_FILE=/dev/null # dir with which we cause loading of our in-tree deprecated completions # instead of possibly (system-)installed upstream ones. export BASH_COMPLETION_USER_DIR="$SRCDIRABS/deprecated" -# /var/empty isn't necessarily actually always empty :P -export BASH_COMPLETION_COMPAT_DIR=/var/empty/bash_completion.d -export BASH_COMPLETION_COMPAT_IGNORE='*' +export BASH_COMPLETION_COMPAT_DIR="$SRCDIRABS/../bash_completion.d" export XDG_DATA_DIRS=/var/empty # Make sure default settings are in effect @@ -48,6 +46,7 @@ unset -v \ BASH_COMPLETION_CMD_CVS_REMOTE \ BASH_COMPLETION_CMD_IWCONFIG_SCAN \ BASH_COMPLETION_CMD_TAR_INTERNAL_PATHS \ + BASH_COMPLETION_COMPAT_IGNORE \ BASH_COMPLETION_FILEDIR_FALLBACK \ BASH_COMPLETION_KNOWN_HOSTS_WITH_HOSTFILE \ COMP_CONFIGURE_HINTS \ From cdd8a157abdbb4ce2e74df3fd8131a2b199152e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Wed, 22 Feb 2023 22:14:58 +0200 Subject: [PATCH 2/3] feat(bash_completion.d): load from one relative to the main script Primarily for run-in-place-from-git-clone setups. --- bash_completion | 25 +++++++++++++++++++++---- doc/configuration.md | 9 +++++---- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/bash_completion b/bash_completion index 9884737e539..dec128eda78 100644 --- a/bash_completion +++ b/bash_completion @@ -2610,14 +2610,31 @@ _comp_xfunc() } # source compat completion directory definitions -_comp__init_compat_dir=${BASH_COMPLETION_COMPAT_DIR:-/etc/bash_completion.d} -if [[ -d $_comp__init_compat_dir && -r $_comp__init_compat_dir && -x $_comp__init_compat_dir ]]; then +_comp__init_compat_dirs=() +if [[ -n $BASH_COMPLETION_COMPAT_DIR ]]; then + _comp__init_compat_dirs+=("$BASH_COMPLETION_COMPAT_DIR") +else + _comp__init_compat_dirs+=(/etc/bash_completion.d) + # Similarly as for the "completions" dir, look up from relative to + # bash_completion, primarily for run-in-place-from-git-clone setups. + # Notably we do it after the system location here, in order to + # prefer in-tree variables and functions. + if [[ $BASH_SOURCE == */* ]]; then + _comp__init_compat_dir="${BASH_SOURCE%/*}/bash_completion.d" + [[ ${_comp__init_compat_dirs[0]} == "$_comp__init_compat_dir" ]] || + _comp__init_compat_dirs+=("$_comp__init_compat_dir") + else + _comp__init_compat_dirs+=(./bash_completion.d) + fi +fi +for _comp__init_compat_dir in "${_comp__init_compat_dirs[@]}"; do + [[ -d $_comp__init_compat_dir && -r $_comp__init_compat_dir && -x $_comp__init_compat_dir ]] || continue for _comp__init_file in "$_comp__init_compat_dir"/*; do [[ ${_comp__init_file##*/} != @($_comp_backup_glob|Makefile*|${BASH_COMPLETION_COMPAT_IGNORE-}) && -f $_comp__init_file && -r $_comp__init_file ]] && . "$_comp__init_file" done -fi -unset -v _comp__init_compat_dir _comp__init_file +done +unset -v _comp__init_compat_dirs _comp__init_compat_dir _comp__init_file # source user completion file # diff --git a/doc/configuration.md b/doc/configuration.md index f8d4b7f80fe..6036b3a8190 100644 --- a/doc/configuration.md +++ b/doc/configuration.md @@ -20,10 +20,11 @@ used instead of it. ### `BASH_COMPLETION_COMPAT_DIR` -Directory for pre-dynamic loading era (pre-2.0) backwards compatibility -completion files that are loaded eagerly from `bash_completion` when it is -loaded. If unset or null, the default compatibility directory to use is -`/etc/bash_completion.d`. +Directory for pre-dynamic loading era (pre-2.0) and other backwards +compatibility completion files that are loaded eagerly from `bash_completion` +when it is loaded. If unset or null, the default compatibility directories to +use are `/etc/bash_completion.d`, and `bash_completion.d` relative to +`bash_completion` location. ### `BASH_COMPLETION_FILEDIR_FALLBACK` From b9db024fe6a93a831e8e1785d9057ea2223d2676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Sat, 25 Feb 2023 23:20:30 +0200 Subject: [PATCH 3/3] fix(compat): checking non-empty `$BASH_COMPLETION_COMPAT_DIR` Co-authored-by: Koichi Murase --- bash_completion | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bash_completion b/bash_completion index dec128eda78..11588d6cf3d 100644 --- a/bash_completion +++ b/bash_completion @@ -2611,7 +2611,7 @@ _comp_xfunc() # source compat completion directory definitions _comp__init_compat_dirs=() -if [[ -n $BASH_COMPLETION_COMPAT_DIR ]]; then +if [[ ${BASH_COMPLETION_COMPAT_DIR-} ]]; then _comp__init_compat_dirs+=("$BASH_COMPLETION_COMPAT_DIR") else _comp__init_compat_dirs+=(/etc/bash_completion.d)