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}