aboutsummaryrefslogtreecommitdiff
path: root/bash/bash_completion.d/sd.bash
blob: 8adc9810a1c2c67d49c8faa2a30864217abe65af (plain) (blame)
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
# 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 function for sd; any sibling directories, excluding the self
_sd() {

    # Build list of matching sibling directories
    local ci comp
    while IFS= read -d / -r comp ; do
        COMPREPLY[ci++]=$comp
    done < <(

        # 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

        # 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/' "$sibling"
                        break
                        ;;
                esac
            done
        done
    )
}
complete -F _sd -o filenames sd