git-bug

  1#compdef git-bug
  2compdef _git-bug git-bug
  3
  4# zsh completion for git-bug                              -*- shell-script -*-
  5
  6__git-bug_debug()
  7{
  8    local file="$BASH_COMP_DEBUG_FILE"
  9    if [[ -n ${file} ]]; then
 10        echo "$*" >> "${file}"
 11    fi
 12}
 13
 14_git-bug()
 15{
 16    local shellCompDirectiveError=1
 17    local shellCompDirectiveNoSpace=2
 18    local shellCompDirectiveNoFileComp=4
 19    local shellCompDirectiveFilterFileExt=8
 20    local shellCompDirectiveFilterDirs=16
 21    local shellCompDirectiveKeepOrder=32
 22
 23    local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace keepOrder
 24    local -a completions
 25
 26    __git-bug_debug "\n========= starting completion logic =========="
 27    __git-bug_debug "CURRENT: ${CURRENT}, words[*]: ${words[*]}"
 28
 29    # The user could have moved the cursor backwards on the command-line.
 30    # We need to trigger completion from the $CURRENT location, so we need
 31    # to truncate the command-line ($words) up to the $CURRENT location.
 32    # (We cannot use $CURSOR as its value does not work when a command is an alias.)
 33    words=("${=words[1,CURRENT]}")
 34    __git-bug_debug "Truncated words[*]: ${words[*]},"
 35
 36    lastParam=${words[-1]}
 37    lastChar=${lastParam[-1]}
 38    __git-bug_debug "lastParam: ${lastParam}, lastChar: ${lastChar}"
 39
 40    # For zsh, when completing a flag with an = (e.g., git-bug -n=<TAB>)
 41    # completions must be prefixed with the flag
 42    setopt local_options BASH_REMATCH
 43    if [[ "${lastParam}" =~ '-.*=' ]]; then
 44        # We are dealing with a flag with an =
 45        flagPrefix="-P ${BASH_REMATCH}"
 46    fi
 47
 48    # Prepare the command to obtain completions
 49    requestComp="${words[1]} __complete ${words[2,-1]}"
 50    if [ "${lastChar}" = "" ]; then
 51        # If the last parameter is complete (there is a space following it)
 52        # We add an extra empty parameter so we can indicate this to the go completion code.
 53        __git-bug_debug "Adding extra empty parameter"
 54        requestComp="${requestComp} \"\""
 55    fi
 56
 57    __git-bug_debug "About to call: eval ${requestComp}"
 58
 59    # Use eval to handle any environment variables and such
 60    out=$(eval ${requestComp} 2>/dev/null)
 61    __git-bug_debug "completion output: ${out}"
 62
 63    # Extract the directive integer following a : from the last line
 64    local lastLine
 65    while IFS='\n' read -r line; do
 66        lastLine=${line}
 67    done < <(printf "%s\n" "${out[@]}")
 68    __git-bug_debug "last line: ${lastLine}"
 69
 70    if [ "${lastLine[1]}" = : ]; then
 71        directive=${lastLine[2,-1]}
 72        # Remove the directive including the : and the newline
 73        local suffix
 74        (( suffix=${#lastLine}+2))
 75        out=${out[1,-$suffix]}
 76    else
 77        # There is no directive specified.  Leave $out as is.
 78        __git-bug_debug "No directive found.  Setting do default"
 79        directive=0
 80    fi
 81
 82    __git-bug_debug "directive: ${directive}"
 83    __git-bug_debug "completions: ${out}"
 84    __git-bug_debug "flagPrefix: ${flagPrefix}"
 85
 86    if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then
 87        __git-bug_debug "Completion received error. Ignoring completions."
 88        return
 89    fi
 90
 91    local activeHelpMarker="_activeHelp_ "
 92    local endIndex=${#activeHelpMarker}
 93    local startIndex=$((${#activeHelpMarker}+1))
 94    local hasActiveHelp=0
 95    while IFS='\n' read -r comp; do
 96        # Check if this is an activeHelp statement (i.e., prefixed with $activeHelpMarker)
 97        if [ "${comp[1,$endIndex]}" = "$activeHelpMarker" ];then
 98            __git-bug_debug "ActiveHelp found: $comp"
 99            comp="${comp[$startIndex,-1]}"
100            if [ -n "$comp" ]; then
101                compadd -x "${comp}"
102                __git-bug_debug "ActiveHelp will need delimiter"
103                hasActiveHelp=1
104            fi
105
106            continue
107        fi
108
109        if [ -n "$comp" ]; then
110            # If requested, completions are returned with a description.
111            # The description is preceded by a TAB character.
112            # For zsh's _describe, we need to use a : instead of a TAB.
113            # We first need to escape any : as part of the completion itself.
114            comp=${comp//:/\\:}
115
116            local tab="$(printf '\t')"
117            comp=${comp//$tab/:}
118
119            __git-bug_debug "Adding completion: ${comp}"
120            completions+=${comp}
121            lastComp=$comp
122        fi
123    done < <(printf "%s\n" "${out[@]}")
124
125    # Add a delimiter after the activeHelp statements, but only if:
126    # - there are completions following the activeHelp statements, or
127    # - file completion will be performed (so there will be choices after the activeHelp)
128    if [ $hasActiveHelp -eq 1 ]; then
129        if [ ${#completions} -ne 0 ] || [ $((directive & shellCompDirectiveNoFileComp)) -eq 0 ]; then
130            __git-bug_debug "Adding activeHelp delimiter"
131            compadd -x "--"
132            hasActiveHelp=0
133        fi
134    fi
135
136    if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then
137        __git-bug_debug "Activating nospace."
138        noSpace="-S ''"
139    fi
140
141    if [ $((directive & shellCompDirectiveKeepOrder)) -ne 0 ]; then
142        __git-bug_debug "Activating keep order."
143        keepOrder="-V"
144    fi
145
146    if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then
147        # File extension filtering
148        local filteringCmd
149        filteringCmd='_files'
150        for filter in ${completions[@]}; do
151            if [ ${filter[1]} != '*' ]; then
152                # zsh requires a glob pattern to do file filtering
153                filter="\*.$filter"
154            fi
155            filteringCmd+=" -g $filter"
156        done
157        filteringCmd+=" ${flagPrefix}"
158
159        __git-bug_debug "File filtering command: $filteringCmd"
160        _arguments '*:filename:'"$filteringCmd"
161    elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then
162        # File completion for directories only
163        local subdir
164        subdir="${completions[1]}"
165        if [ -n "$subdir" ]; then
166            __git-bug_debug "Listing directories in $subdir"
167            pushd "${subdir}" >/dev/null 2>&1
168        else
169            __git-bug_debug "Listing directories in ."
170        fi
171
172        local result
173        _arguments '*:dirname:_files -/'" ${flagPrefix}"
174        result=$?
175        if [ -n "$subdir" ]; then
176            popd >/dev/null 2>&1
177        fi
178        return $result
179    else
180        __git-bug_debug "Calling _describe"
181        if eval _describe $keepOrder "completions" completions $flagPrefix $noSpace; then
182            __git-bug_debug "_describe found some completions"
183
184            # Return the success of having called _describe
185            return 0
186        else
187            __git-bug_debug "_describe did not find completions."
188            __git-bug_debug "Checking if we should do file completion."
189            if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then
190                __git-bug_debug "deactivating file completion"
191
192                # We must return an error code here to let zsh know that there were no
193                # completions found by _describe; this is what will trigger other
194                # matching algorithms to attempt to find completions.
195                # For example zsh can match letters in the middle of words.
196                return 1
197            else
198                # Perform file completion
199                __git-bug_debug "Activating file completion"
200
201                # We must return the result of this command, so it must be the
202                # last command, or else we must store its result to return it.
203                _arguments '*:filename:_files'" ${flagPrefix}"
204            fi
205        fi
206    fi
207}
208
209# don't run the completion function when being source-ed or eval-ed
210if [ "$funcstack[1]" = "_git-bug" ]; then
211    _git-bug
212fi