aboutsummaryrefslogtreecommitdiff
path: root/bash/bash_completion.d/bd.bash
blob: f6ca3a6b1616edeee04b0398c071a0329e826df8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# Load _completion_ignore_case helper function
if ! declare -F _completion_ignore_case >/dev/null ; then
    source "$HOME"/.bash_completion.d/_completion_ignore_case.bash
fi

# Completion setup for bd()
_bd() {

    # Iterate through completions produced by subshell
    local ci comp
    while IFS= read -d / -r comp ; do
        COMPREPLY[ci++]=$comp
    done < <(

        # Build an array of path ancestors
        path=$PWD
        while [[ -n $path ]] ; do

            # Peel off the leaf of the path
            ancestor=${path##*/}
            path=${path%/*}

            # Skip if this is a null string; root, trailing/double slash...
            [[ -n $ancestor ]] || continue

            # Skip the first non-null element (current dir)
            ((generation++)) || continue

            # Push node onto ancestry list
            ancestors[ai++]=$ancestor
        done

        # Continue if we have at least one non-root ancestor
        ((ai)) || return

        # Add quoted ancestors to new array; for long paths, this is faster than
        # forking a subshell for `printf %q` on each item
        while read -d / -r ancestor ; do
            ancestors_quoted[aqi++]=$ancestor
        done < <(printf '%q/' "${ancestors[@]}")

        # Make matching behave appropriately
        if _completion_ignore_case ; then
            shopt -s nocasematch 2>/dev/null
        fi

        # Iterate through keys of the ancestors array
        for ai in "${!ancestors[@]}" ; do

            # Get ancestor and associated quoted ancestor
            ancestor=${ancestors[ai]}
            ancestor_quoted=${ancestors_quoted[ai]}

            # If either the unquoted or quoted ancestor matches, print the
            # unquoted one as a completion reply
            for match in "$ancestor" "$ancestor_quoted" ; do
                case $match in
                    ("$2"*)
                        printf '%s/' "$ancestor"
                        break
                        ;;
                esac
            done
        done
    )
}
complete -F _bd -o filenames bd