From 2f59b3c6a7931de14e837ad3c8b969327fda89ff Mon Sep 17 00:00:00 2001 From: Tom Ryder Date: Sat, 1 Dec 2018 13:06:03 +1300 Subject: Overhaul bd() completion again I forgot that the second positional parameter $2 to these completion functions is the word currently being completed. That's going to make things a bit less verbose. --- bash/bash_completion.d/bd.bash | 59 ++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 16 deletions(-) (limited to 'bash') diff --git a/bash/bash_completion.d/bd.bash b/bash/bash_completion.d/bd.bash index e67cdd09..59f4718f 100644 --- a/bash/bash_completion.d/bd.bash +++ b/bash/bash_completion.d/bd.bash @@ -1,25 +1,52 @@ # Completion setup for bd() _bd() { - # Only makes sense for the first argument + # The function accepts only one argument, so it doesn't make sense to + # complete anywhere else ((COMP_CWORD == 1)) || return - # Build a list of dirnames in $PWD - local -a dirnames - IFS=/ read -rd '' -a dirnames < <(printf '%s\0' "${PWD#/}") + # Iterate through slash-delimited matching parent path elements, as piped + # in by the subshell + local ci word + while IFS= read -rd/ word ; do + COMPREPLY[ci++]=$word + done < <( - # Remove the last element in the array (the current directory) - ((${#dirnames[@]})) || return - dirnames=("${dirnames[@]:0:${#dirnames[@]}-1}") + # Build an array of path nodes, leaf to root + path=$PWD + while [[ -n $path ]] ; do + node=${path##*/} + path=${path%/*} + [[ -n $node ]] || continue + nodes[ni++]=$node + done - # Add the matching dirnames to the reply - local dirname - for dirname in "${dirnames[@]}" ; do - case $dirname in - "${COMP_WORDS[COMP_CWORD]}"*) - COMPREPLY[${#COMPREPLY[@]}]=$(printf %q "$dirname") - ;; - esac - done + # Continue if we have at least two nodes, counting the leaf + ((${#nodes} > 1)) || return + + # Shift off the leaf, since it's not meaningful to go "back to" the + # current directory + nodes=("${nodes[@]:1}") + + # Turn on case-insensitive matching, if configured to do so + while read -r _ setting ; do + case $setting in + ('completion-ignore-case on') + shopt -s nocasematch 2>/dev/null + break + ;; + esac + done < <(bind -v) + + # Iterate through the nodes and print the ones that match the word + # being completed, with a trailing slash as terminator + for node in "${nodes[@]}" ; do + case $node in + ("$2"*) + printf '%s/' "$node" + ;; + esac + done + ) } complete -F _bd bd -- cgit v1.2.3