git-bug

  1# powershell completion for git-bug                              -*- shell-script -*-
  2
  3function __git-bug_debug {
  4    if ($env:BASH_COMP_DEBUG_FILE) {
  5        "$args" | Out-File -Append -FilePath "$env:BASH_COMP_DEBUG_FILE"
  6    }
  7}
  8
  9filter __git-bug_escapeStringWithSpecialChars {
 10    $_ -replace '\s|#|@|\$|;|,|''|\{|\}|\(|\)|"|`|\||<|>|&','`$&'
 11}
 12
 13Register-ArgumentCompleter -CommandName 'git-bug' -ScriptBlock {
 14    param(
 15            $WordToComplete,
 16            $CommandAst,
 17            $CursorPosition
 18        )
 19
 20    # Get the current command line and convert into a string
 21    $Command = $CommandAst.CommandElements
 22    $Command = "$Command"
 23
 24    __git-bug_debug ""
 25    __git-bug_debug "========= starting completion logic =========="
 26    __git-bug_debug "WordToComplete: $WordToComplete Command: $Command CursorPosition: $CursorPosition"
 27
 28    # The user could have moved the cursor backwards on the command-line.
 29    # We need to trigger completion from the $CursorPosition location, so we need
 30    # to truncate the command-line ($Command) up to the $CursorPosition location.
 31    # Make sure the $Command is longer then the $CursorPosition before we truncate.
 32    # This happens because the $Command does not include the last space.
 33    if ($Command.Length -gt $CursorPosition) {
 34        $Command=$Command.Substring(0,$CursorPosition)
 35    }
 36    __git-bug_debug "Truncated command: $Command"
 37
 38    $ShellCompDirectiveError=1
 39    $ShellCompDirectiveNoSpace=2
 40    $ShellCompDirectiveNoFileComp=4
 41    $ShellCompDirectiveFilterFileExt=8
 42    $ShellCompDirectiveFilterDirs=16
 43
 44    # Prepare the command to request completions for the program.
 45    # Split the command at the first space to separate the program and arguments.
 46    $Program,$Arguments = $Command.Split(" ",2)
 47    $RequestComp="$Program __completeNoDesc $Arguments"
 48    __git-bug_debug "RequestComp: $RequestComp"
 49
 50    # we cannot use $WordToComplete because it
 51    # has the wrong values if the cursor was moved
 52    # so use the last argument
 53    if ($WordToComplete -ne "" ) {
 54        $WordToComplete = $Arguments.Split(" ")[-1]
 55    }
 56    __git-bug_debug "New WordToComplete: $WordToComplete"
 57
 58
 59    # Check for flag with equal sign
 60    $IsEqualFlag = ($WordToComplete -Like "--*=*" )
 61    if ( $IsEqualFlag ) {
 62        __git-bug_debug "Completing equal sign flag"
 63        # Remove the flag part
 64        $Flag,$WordToComplete = $WordToComplete.Split("=",2)
 65    }
 66
 67    if ( $WordToComplete -eq "" -And ( -Not $IsEqualFlag )) {
 68        # If the last parameter is complete (there is a space following it)
 69        # We add an extra empty parameter so we can indicate this to the go method.
 70        __git-bug_debug "Adding extra empty parameter"
 71        # We need to use `"`" to pass an empty argument a "" or '' does not work!!!
 72        $RequestComp="$RequestComp" + ' `"`"'
 73    }
 74
 75    __git-bug_debug "Calling $RequestComp"
 76    #call the command store the output in $out and redirect stderr and stdout to null
 77    # $Out is an array contains each line per element
 78    Invoke-Expression -OutVariable out "$RequestComp" 2>&1 | Out-Null
 79
 80
 81    # get directive from last line
 82    [int]$Directive = $Out[-1].TrimStart(':')
 83    if ($Directive -eq "") {
 84        # There is no directive specified
 85        $Directive = 0
 86    }
 87    __git-bug_debug "The completion directive is: $Directive"
 88
 89    # remove directive (last element) from out
 90    $Out = $Out | Where-Object { $_ -ne $Out[-1] }
 91    __git-bug_debug "The completions are: $Out"
 92
 93    if (($Directive -band $ShellCompDirectiveError) -ne 0 ) {
 94        # Error code.  No completion.
 95        __git-bug_debug "Received error from custom completion go code"
 96        return
 97    }
 98
 99    $Longest = 0
100    $Values = $Out | ForEach-Object {
101        #Split the output in name and description
102        $Name, $Description = $_.Split("`t",2)
103        __git-bug_debug "Name: $Name Description: $Description"
104
105        # Look for the longest completion so that we can format things nicely
106        if ($Longest -lt $Name.Length) {
107            $Longest = $Name.Length
108        }
109
110        # Set the description to a one space string if there is none set.
111        # This is needed because the CompletionResult does not accept an empty string as argument
112        if (-Not $Description) {
113            $Description = " "
114        }
115        @{Name="$Name";Description="$Description"}
116    }
117
118
119    $Space = " "
120    if (($Directive -band $ShellCompDirectiveNoSpace) -ne 0 ) {
121        # remove the space here
122        __git-bug_debug "ShellCompDirectiveNoSpace is called"
123        $Space = ""
124    }
125
126    if ((($Directive -band $ShellCompDirectiveFilterFileExt) -ne 0 ) -or
127       (($Directive -band $ShellCompDirectiveFilterDirs) -ne 0 ))  {
128        __git-bug_debug "ShellCompDirectiveFilterFileExt ShellCompDirectiveFilterDirs are not supported"
129
130        # return here to prevent the completion of the extensions
131        return
132    }
133
134    $Values = $Values | Where-Object {
135        # filter the result
136        $_.Name -like "$WordToComplete*"
137
138        # Join the flag back if we have an equal sign flag
139        if ( $IsEqualFlag ) {
140            __git-bug_debug "Join the equal sign flag back to the completion value"
141            $_.Name = $Flag + "=" + $_.Name
142        }
143    }
144
145    if (($Directive -band $ShellCompDirectiveNoFileComp) -ne 0 ) {
146        __git-bug_debug "ShellCompDirectiveNoFileComp is called"
147
148        if ($Values.Length -eq 0) {
149            # Just print an empty string here so the
150            # shell does not start to complete paths.
151            # We cannot use CompletionResult here because
152            # it does not accept an empty string as argument.
153            ""
154            return
155        }
156    }
157
158    # Get the current mode
159    $Mode = (Get-PSReadLineKeyHandler | Where-Object {$_.Key -eq "Tab" }).Function
160    __git-bug_debug "Mode: $Mode"
161
162    $Values | ForEach-Object {
163
164        # store temporary because switch will overwrite $_
165        $comp = $_
166
167        # PowerShell supports three different completion modes
168        # - TabCompleteNext (default windows style - on each key press the next option is displayed)
169        # - Complete (works like bash)
170        # - MenuComplete (works like zsh)
171        # You set the mode with Set-PSReadLineKeyHandler -Key Tab -Function <mode>
172
173        # CompletionResult Arguments:
174        # 1) CompletionText text to be used as the auto completion result
175        # 2) ListItemText   text to be displayed in the suggestion list
176        # 3) ResultType     type of completion result
177        # 4) ToolTip        text for the tooltip with details about the object
178
179        switch ($Mode) {
180
181            # bash like
182            "Complete" {
183
184                if ($Values.Length -eq 1) {
185                    __git-bug_debug "Only one completion left"
186
187                    # insert space after value
188                    [System.Management.Automation.CompletionResult]::new($($comp.Name | __git-bug_escapeStringWithSpecialChars) + $Space, "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
189
190                } else {
191                    # Add the proper number of spaces to align the descriptions
192                    while($comp.Name.Length -lt $Longest) {
193                        $comp.Name = $comp.Name + " "
194                    }
195
196                    # Check for empty description and only add parentheses if needed
197                    if ($($comp.Description) -eq " " ) {
198                        $Description = ""
199                    } else {
200                        $Description = "  ($($comp.Description))"
201                    }
202
203                    [System.Management.Automation.CompletionResult]::new("$($comp.Name)$Description", "$($comp.Name)$Description", 'ParameterValue', "$($comp.Description)")
204                }
205             }
206
207            # zsh like
208            "MenuComplete" {
209                # insert space after value
210                # MenuComplete will automatically show the ToolTip of
211                # the highlighted value at the bottom of the suggestions.
212                [System.Management.Automation.CompletionResult]::new($($comp.Name | __git-bug_escapeStringWithSpecialChars) + $Space, "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
213            }
214
215            # TabCompleteNext and in case we get something unknown
216            Default {
217                # Like MenuComplete but we don't want to add a space here because
218                # the user need to press space anyway to get the completion.
219                # Description will not be shown because that's not possible with TabCompleteNext
220                [System.Management.Automation.CompletionResult]::new($($comp.Name | __git-bug_escapeStringWithSpecialChars), "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
221            }
222        }
223
224    }
225}