perf(bash-v2): standard completion optimizations (#1683)

Refactor to remove two loops over the entire list of candidates.

Format descriptions only for completions that are actually going to be
displayed, instead of for all candidates.

Format descriptions inline in completions array, removing need for a
command substitution/subshell and a printf escape per displayed
completion.
This commit is contained in:
Ville Skyttä 2022-05-03 04:00:51 +03:00 committed by GitHub
parent 4f0facbcee
commit 09d6ba690f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 45 additions and 53 deletions

View File

@ -177,40 +177,28 @@ __%[1]s_handle_standard_completion_case() {
local tab=$'\t' comp local tab=$'\t' comp
local longest=0 local longest=0
local compline
# Look for the longest completion so that we can format things nicely # Look for the longest completion so that we can format things nicely
while IFS='' read -r comp; do while IFS='' read -r compline; do
# Strip any description before checking the length # Strip any description before checking the length
comp=${comp%%%%$tab*} comp=${compline%%%%$tab*}
# Only consider the completions that match # Only consider the completions that match
comp=$(compgen -W "$comp" -- "$cur") comp=$(compgen -W "$comp" -- "$cur")
[[ -z $comp ]] && continue
COMPREPLY+=("$compline")
if ((${#comp}>longest)); then if ((${#comp}>longest)); then
longest=${#comp} longest=${#comp}
fi fi
done < <(printf "%%s\n" "${out}") done < <(printf "%%s\n" "${out}")
local completions=()
while IFS='' read -r comp; do
if [ -z "$comp" ]; then
continue
fi
__%[1]s_debug "Original comp: $comp"
comp="$(__%[1]s_format_comp_descriptions "$comp" "$longest")"
__%[1]s_debug "Final comp: $comp"
completions+=("$comp")
done < <(printf "%%s\n" "${out}")
while IFS='' read -r comp; do
COMPREPLY+=("$comp")
done < <(compgen -W "${completions[*]}" -- "$cur")
# If there is a single completion left, remove the description text # If there is a single completion left, remove the description text
if [ ${#COMPREPLY[*]} -eq 1 ]; then if [ ${#COMPREPLY[*]} -eq 1 ]; then
__%[1]s_debug "COMPREPLY[0]: ${COMPREPLY[0]}" __%[1]s_debug "COMPREPLY[0]: ${COMPREPLY[0]}"
comp="${COMPREPLY[0]%%%% *}" comp="${COMPREPLY[0]%%%%$tab*}"
__%[1]s_debug "Removed description from single completion, which is now: ${comp}" __%[1]s_debug "Removed description from single completion, which is now: ${comp}"
COMPREPLY=() COMPREPLY[0]=$comp
COMPREPLY+=("$comp") else # Format the descriptions
__%[1]s_format_comp_descriptions $longest
fi fi
} }
@ -230,11 +218,15 @@ __%[1]s_handle_special_char()
__%[1]s_format_comp_descriptions() __%[1]s_format_comp_descriptions()
{ {
local tab=$'\t' local tab=$'\t'
local comp="$1" local comp desc maxdesclength
local longest=$2 local longest=$1
local i ci
for ci in ${!COMPREPLY[*]}; do
comp=${COMPREPLY[ci]}
# Properly format the description string which follows a tab character if there is one # Properly format the description string which follows a tab character if there is one
if [[ "$comp" == *$tab* ]]; then if [[ "$comp" == *$tab* ]]; then
__%[1]s_debug "Original comp: $comp"
desc=${comp#*$tab} desc=${comp#*$tab}
comp=${comp%%%%$tab*} comp=${comp%%%%$tab*}
@ -263,10 +255,10 @@ __%[1]s_format_comp_descriptions()
fi fi
comp+=" ($desc)" comp+=" ($desc)"
fi fi
COMPREPLY[ci]=$comp
__%[1]s_debug "Final comp: $comp"
fi fi
done
# Must use printf to escape all special characters
printf "%%q" "${comp}"
} }
__start_%[1]s() __start_%[1]s()