aboutsummaryrefslogtreecommitdiff
path: root/bash/bash_completion.d/sd.bash
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2018-12-06 11:26:14 +1300
committerTom Ryder <tom@sanctum.geek.nz>2018-12-06 11:30:10 +1300
commit5e75e4044f7f5a70d743af6b47009354ab518c4e (patch)
tree826babc065540c39dcb22fded402a0a96ced3e9c /bash/bash_completion.d/sd.bash
parentMerge branch 'hotfix/v3.0.1' into develop (diff)
downloaddotfiles-5e75e4044f7f5a70d743af6b47009354ab518c4e.tar.gz
dotfiles-5e75e4044f7f5a70d743af6b47009354ab518c4e.zip
Refactor bd()/sd() completion a lot
Avoid very many forks; and work around Bash 3.0 bugs with array behaviour: bash-3.0$ nodes=(a b c) bash-3.0$ printf '%s\n' "${nodes[@]:1}" b c bash-3.0$ nodes=(a b) bash-3.0$ printf '%s\n' "${nodes[@]:1}" bash-3.0 Compare: bash-5.0$ nodes=(a b c) bash-5.0$ printf '%s\n' "${nodes[@]:1}" b c bash-5.0$ nodes=(a b) bash-5.0$ printf '%s\n' "${nodes[@]:1}" b bash-5.0$
Diffstat (limited to 'bash/bash_completion.d/sd.bash')
-rw-r--r--bash/bash_completion.d/sd.bash47
1 files changed, 34 insertions, 13 deletions
diff --git a/bash/bash_completion.d/sd.bash b/bash/bash_completion.d/sd.bash
index 4dc72f31..8adc9810 100644
--- a/bash/bash_completion.d/sd.bash
+++ b/bash/bash_completion.d/sd.bash
@@ -14,25 +14,46 @@ _sd() {
# Make globs expand appropriately
shopt -s dotglob nullglob
+
+ # Get list of siblings; use trailing slashes to limit to directories
+ # There should always be at least one (self)
+ siblings=(../*/)
+
+ # Strip leading dot-dot-slash and trailing slash
+ siblings=("${siblings[@]#../}")
+ siblings=("${siblings[@]%/}")
+
+ # Add quoted siblings to new array; for large directories, this is
+ # faster than forking a subshell for `printf %q` on each item
+ while read -d / -r sibling ; do
+ siblings_quoted[sqi++]=$sibling
+ done < <(printf '%q/' "${siblings[@]}")
+
+ # Make matching work appropriately
if _completion_ignore_case ; then
shopt -s nocasematch 2>/dev/null
fi
- # Print matching sibling dirs that are not the current dir
- for sib in ../*/ ; do
- # Strip leading ../
- sib=${sib#../}
- # Strip trailing slash
- sib=${sib%/}
- # Skip self
- [[ $sib != "${PWD##*/}" ]] || continue
- # Check the quoted and unquoted word for matching
- for match in "$sib" "$(printf '%q' "$sib")" ; do
- # Print any match, slash-terminated
+ # Get current dir
+ self=${PWD##*/}
+
+ # Iterate through keys of the siblings array
+ for si in "${!siblings[@]}" ; do
+
+ # Get sibling and associated quoted sibling
+ sibling=${siblings[si]}
+ sibling_quoted=${siblings_quoted[si]}
+
+ # Skip if this sibling looks like the current dir
+ [[ $sibling != "$self" ]] || continue
+
+ # If either the unquoted or quoted sibling matches, print the
+ # unquoted one as a completion reply
+ for match in "$sibling" "$sibling_quoted" ; do
case $match in
("$2"*)
- printf '%s/' "$sib"
- continue
+ printf '%s/' "$sibling"
+ break
;;
esac
done