_gh (7604B)
1 #compdef gh 2 compdef _gh gh 3 4 # zsh completion for gh -*- shell-script -*- 5 6 __gh_debug() 7 { 8 local file="$BASH_COMP_DEBUG_FILE" 9 if [[ -n ${file} ]]; then 10 echo "$*" >> "${file}" 11 fi 12 } 13 14 _gh() 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 __gh_debug "\n========= starting completion logic ==========" 27 __gh_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 __gh_debug "Truncated words[*]: ${words[*]}," 35 36 lastParam=${words[-1]} 37 lastChar=${lastParam[-1]} 38 __gh_debug "lastParam: ${lastParam}, lastChar: ${lastChar}" 39 40 # For zsh, when completing a flag with an = (e.g., gh -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 __gh_debug "Adding extra empty parameter" 54 requestComp="${requestComp} \"\"" 55 fi 56 57 __gh_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 __gh_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 __gh_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 __gh_debug "No directive found. Setting do default" 79 directive=0 80 fi 81 82 __gh_debug "directive: ${directive}" 83 __gh_debug "completions: ${out}" 84 __gh_debug "flagPrefix: ${flagPrefix}" 85 86 if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then 87 __gh_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 __gh_debug "ActiveHelp found: $comp" 99 comp="${comp[$startIndex,-1]}" 100 if [ -n "$comp" ]; then 101 compadd -x "${comp}" 102 __gh_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 __gh_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 __gh_debug "Adding activeHelp delimiter" 131 compadd -x "--" 132 hasActiveHelp=0 133 fi 134 fi 135 136 if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then 137 __gh_debug "Activating nospace." 138 noSpace="-S ''" 139 fi 140 141 if [ $((directive & shellCompDirectiveKeepOrder)) -ne 0 ]; then 142 __gh_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 __gh_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 __gh_debug "Listing directories in $subdir" 167 pushd "${subdir}" >/dev/null 2>&1 168 else 169 __gh_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 __gh_debug "Calling _describe" 181 if eval _describe $keepOrder "completions" completions $flagPrefix $noSpace; then 182 __gh_debug "_describe found some completions" 183 184 # Return the success of having called _describe 185 return 0 186 else 187 __gh_debug "_describe did not find completions." 188 __gh_debug "Checking if we should do file completion." 189 if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then 190 __gh_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 __gh_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 210 if [ "$funcstack[1]" = "_gh" ]; then 211 _gh 212 fi