diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f388972..af748eb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ ## Other +- Use more robust approach to escaping in Bash completions, see #3448 (@akinomyoga) + ## Syntaxes ## Themes diff --git a/assets/completions/bat.bash.in b/assets/completions/bat.bash.in index 68c80234..66be3985 100644 --- a/assets/completions/bat.bash.in +++ b/assets/completions/bat.bash.in @@ -14,18 +14,36 @@ __bat_escape_completions() { # Do not escape if completing a quoted value. [[ $cur == [\"\']* ]] && return 0 - # printf -v to an array index is available in bash >= 4.1. - # Use it if available, as -o filenames is semantically incorrect if - # we are not actually completing filenames, and it has side effects - # (e.g. adds trailing slash to candidates matching present dirs). if (( + BASH_VERSINFO[0] > 5 || \ + BASH_VERSINFO[0] == 5 && BASH_VERSINFO[1] >= 3 + )); then + # bash >= 5.3 has "compopt -o fullquote", which exactly does + # what this function tries to do. + compopt -o fullquote + elif (( BASH_VERSINFO[0] > 4 || \ BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] > 0 )); then + # printf -v to an array index is available in bash >= 4.1. + # Use it if available, as -o filenames is semantically + # incorrect if we are not actually completing filenames, and it + # has side effects (e.g. adds trailing slash to candidates + # matching present dirs). local i for i in ${!COMPREPLY[*]}; do printf -v "COMPREPLY[i]" %q "${COMPREPLY[i]}" done + + # We can use "compopt -o noquote" available in bash >= 4.3 to + # prevent further quoting by the shell, which would be + # unexpectedly applied when a quoted result matches a filename. + if (( + BASH_VERSINFO[0] > 4 || \ + BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] >= 3 + )); then + compopt -o noquote + fi else compopt -o filenames fi @@ -66,7 +84,7 @@ _bat() { printf "%s\n" "$lang" done )" -- "$cur")) - __bat_escape_completions + __bat_escape_completions return 0 ;; -H | --highlight-line | \ @@ -130,16 +148,16 @@ _bat() { return 0 ;; --theme) - local IFS=$'\n' - COMPREPLY=($(compgen -W "auto${IFS}auto:always${IFS}auto:system${IFS}dark${IFS}light${IFS}$("$1" --list-themes)" -- "$cur")) - __bat_escape_completions - return 0 - ;; + local IFS=$'\n' + COMPREPLY=($(compgen -W "auto${IFS}auto:always${IFS}auto:system${IFS}dark${IFS}light${IFS}$("$1" --list-themes)" -- "$cur")) + __bat_escape_completions + return 0 + ;; --theme-dark | \ --theme-light) local IFS=$'\n' COMPREPLY=($(compgen -W "$("$1" --list-themes)" -- "$cur")) - __bat_escape_completions + __bat_escape_completions return 0 ;; --style) @@ -158,7 +176,7 @@ _bat() { numbers snip ) - # shellcheck disable=SC2016 + # shellcheck disable=SC2016 if declare -F _comp_delimited >/dev/null 2>&1; then # bash-completion > 2.11 _comp_delimited , -W '"${styles[@]}"'