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