Skip to content

Commit 09d6ba6

Browse files
authored
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.
1 parent 4f0facb commit 09d6ba6

File tree

1 file changed

+47
-55
lines changed

1 file changed

+47
-55
lines changed

bash_completionsV2.go

Lines changed: 47 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -177,40 +177,28 @@ __%[1]s_handle_standard_completion_case() {
177177
local tab=$'\t' comp
178178
179179
local longest=0
180+
local compline
180181
# Look for the longest completion so that we can format things nicely
181-
while IFS='' read -r comp; do
182+
while IFS='' read -r compline; do
182183
# Strip any description before checking the length
183-
comp=${comp%%%%$tab*}
184+
comp=${compline%%%%$tab*}
184185
# Only consider the completions that match
185186
comp=$(compgen -W "$comp" -- "$cur")
187+
[[ -z $comp ]] && continue
188+
COMPREPLY+=("$compline")
186189
if ((${#comp}>longest)); then
187190
longest=${#comp}
188191
fi
189192
done < <(printf "%%s\n" "${out}")
190193
191-
local completions=()
192-
while IFS='' read -r comp; do
193-
if [ -z "$comp" ]; then
194-
continue
195-
fi
196-
197-
__%[1]s_debug "Original comp: $comp"
198-
comp="$(__%[1]s_format_comp_descriptions "$comp" "$longest")"
199-
__%[1]s_debug "Final comp: $comp"
200-
completions+=("$comp")
201-
done < <(printf "%%s\n" "${out}")
202-
203-
while IFS='' read -r comp; do
204-
COMPREPLY+=("$comp")
205-
done < <(compgen -W "${completions[*]}" -- "$cur")
206-
207194
# If there is a single completion left, remove the description text
208195
if [ ${#COMPREPLY[*]} -eq 1 ]; then
209196
__%[1]s_debug "COMPREPLY[0]: ${COMPREPLY[0]}"
210-
comp="${COMPREPLY[0]%%%% *}"
197+
comp="${COMPREPLY[0]%%%%$tab*}"
211198
__%[1]s_debug "Removed description from single completion, which is now: ${comp}"
212-
COMPREPLY=()
213-
COMPREPLY+=("$comp")
199+
COMPREPLY[0]=$comp
200+
else # Format the descriptions
201+
__%[1]s_format_comp_descriptions $longest
214202
fi
215203
}
216204
@@ -230,43 +218,47 @@ __%[1]s_handle_special_char()
230218
__%[1]s_format_comp_descriptions()
231219
{
232220
local tab=$'\t'
233-
local comp="$1"
234-
local longest=$2
235-
236-
# Properly format the description string which follows a tab character if there is one
237-
if [[ "$comp" == *$tab* ]]; then
238-
desc=${comp#*$tab}
239-
comp=${comp%%%%$tab*}
240-
241-
# $COLUMNS stores the current shell width.
242-
# Remove an extra 4 because we add 2 spaces and 2 parentheses.
243-
maxdesclength=$(( COLUMNS - longest - 4 ))
244-
245-
# Make sure we can fit a description of at least 8 characters
246-
# if we are to align the descriptions.
247-
if [[ $maxdesclength -gt 8 ]]; then
248-
# Add the proper number of spaces to align the descriptions
249-
for ((i = ${#comp} ; i < longest ; i++)); do
250-
comp+=" "
251-
done
252-
else
253-
# Don't pad the descriptions so we can fit more text after the completion
254-
maxdesclength=$(( COLUMNS - ${#comp} - 4 ))
255-
fi
221+
local comp desc maxdesclength
222+
local longest=$1
223+
224+
local i ci
225+
for ci in ${!COMPREPLY[*]}; do
226+
comp=${COMPREPLY[ci]}
227+
# Properly format the description string which follows a tab character if there is one
228+
if [[ "$comp" == *$tab* ]]; then
229+
__%[1]s_debug "Original comp: $comp"
230+
desc=${comp#*$tab}
231+
comp=${comp%%%%$tab*}
256232
257-
# If there is enough space for any description text,
258-
# truncate the descriptions that are too long for the shell width
259-
if [ $maxdesclength -gt 0 ]; then
260-
if [ ${#desc} -gt $maxdesclength ]; then
261-
desc=${desc:0:$(( maxdesclength - 1 ))}
262-
desc+="…"
233+
# $COLUMNS stores the current shell width.
234+
# Remove an extra 4 because we add 2 spaces and 2 parentheses.
235+
maxdesclength=$(( COLUMNS - longest - 4 ))
236+
237+
# Make sure we can fit a description of at least 8 characters
238+
# if we are to align the descriptions.
239+
if [[ $maxdesclength -gt 8 ]]; then
240+
# Add the proper number of spaces to align the descriptions
241+
for ((i = ${#comp} ; i < longest ; i++)); do
242+
comp+=" "
243+
done
244+
else
245+
# Don't pad the descriptions so we can fit more text after the completion
246+
maxdesclength=$(( COLUMNS - ${#comp} - 4 ))
263247
fi
264-
comp+=" ($desc)"
265-
fi
266-
fi
267248
268-
# Must use printf to escape all special characters
269-
printf "%%q" "${comp}"
249+
# If there is enough space for any description text,
250+
# truncate the descriptions that are too long for the shell width
251+
if [ $maxdesclength -gt 0 ]; then
252+
if [ ${#desc} -gt $maxdesclength ]; then
253+
desc=${desc:0:$(( maxdesclength - 1 ))}
254+
desc+="…"
255+
fi
256+
comp+=" ($desc)"
257+
fi
258+
COMPREPLY[ci]=$comp
259+
__%[1]s_debug "Final comp: $comp"
260+
fi
261+
done
270262
}
271263
272264
__start_%[1]s()

0 commit comments

Comments
 (0)