Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
kardolus
GitHub Repository: kardolus/chatgpt-cli
Path: blob/main/vendor/github.com/spf13/cobra/powershell_completions.go
2875 views
1
// Copyright 2013-2023 The Cobra Authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
// The generated scripts require PowerShell v5.0+ (which comes Windows 10, but
16
// can be downloaded separately for windows 7 or 8.1).
17
18
package cobra
19
20
import (
21
"bytes"
22
"fmt"
23
"io"
24
"os"
25
"strings"
26
)
27
28
func genPowerShellComp(buf io.StringWriter, name string, includeDesc bool) {
29
// Variables should not contain a '-' or ':' character
30
nameForVar := name
31
nameForVar = strings.ReplaceAll(nameForVar, "-", "_")
32
nameForVar = strings.ReplaceAll(nameForVar, ":", "_")
33
34
compCmd := ShellCompRequestCmd
35
if !includeDesc {
36
compCmd = ShellCompNoDescRequestCmd
37
}
38
WriteStringAndCheck(buf, fmt.Sprintf(`# powershell completion for %-36[1]s -*- shell-script -*-
39
40
function __%[1]s_debug {
41
if ($env:BASH_COMP_DEBUG_FILE) {
42
"$args" | Out-File -Append -FilePath "$env:BASH_COMP_DEBUG_FILE"
43
}
44
}
45
46
filter __%[1]s_escapeStringWithSpecialChars {
47
`+" $_ -replace '\\s|#|@|\\$|;|,|''|\\{|\\}|\\(|\\)|\"|`|\\||<|>|&','`$&'"+`
48
}
49
50
[scriptblock]${__%[2]sCompleterBlock} = {
51
param(
52
$WordToComplete,
53
$CommandAst,
54
$CursorPosition
55
)
56
57
# Get the current command line and convert into a string
58
$Command = $CommandAst.CommandElements
59
$Command = "$Command"
60
61
__%[1]s_debug ""
62
__%[1]s_debug "========= starting completion logic =========="
63
__%[1]s_debug "WordToComplete: $WordToComplete Command: $Command CursorPosition: $CursorPosition"
64
65
# The user could have moved the cursor backwards on the command-line.
66
# We need to trigger completion from the $CursorPosition location, so we need
67
# to truncate the command-line ($Command) up to the $CursorPosition location.
68
# Make sure the $Command is longer then the $CursorPosition before we truncate.
69
# This happens because the $Command does not include the last space.
70
if ($Command.Length -gt $CursorPosition) {
71
$Command=$Command.Substring(0,$CursorPosition)
72
}
73
__%[1]s_debug "Truncated command: $Command"
74
75
$ShellCompDirectiveError=%[4]d
76
$ShellCompDirectiveNoSpace=%[5]d
77
$ShellCompDirectiveNoFileComp=%[6]d
78
$ShellCompDirectiveFilterFileExt=%[7]d
79
$ShellCompDirectiveFilterDirs=%[8]d
80
$ShellCompDirectiveKeepOrder=%[9]d
81
82
# Prepare the command to request completions for the program.
83
# Split the command at the first space to separate the program and arguments.
84
$Program,$Arguments = $Command.Split(" ",2)
85
86
$RequestComp="$Program %[3]s $Arguments"
87
__%[1]s_debug "RequestComp: $RequestComp"
88
89
# we cannot use $WordToComplete because it
90
# has the wrong values if the cursor was moved
91
# so use the last argument
92
if ($WordToComplete -ne "" ) {
93
$WordToComplete = $Arguments.Split(" ")[-1]
94
}
95
__%[1]s_debug "New WordToComplete: $WordToComplete"
96
97
98
# Check for flag with equal sign
99
$IsEqualFlag = ($WordToComplete -Like "--*=*" )
100
if ( $IsEqualFlag ) {
101
__%[1]s_debug "Completing equal sign flag"
102
# Remove the flag part
103
$Flag,$WordToComplete = $WordToComplete.Split("=",2)
104
}
105
106
if ( $WordToComplete -eq "" -And ( -Not $IsEqualFlag )) {
107
# If the last parameter is complete (there is a space following it)
108
# We add an extra empty parameter so we can indicate this to the go method.
109
__%[1]s_debug "Adding extra empty parameter"
110
# PowerShell 7.2+ changed the way how the arguments are passed to executables,
111
# so for pre-7.2 or when Legacy argument passing is enabled we need to use
112
`+" # `\"`\" to pass an empty argument, a \"\" or '' does not work!!!"+`
113
if ($PSVersionTable.PsVersion -lt [version]'7.2.0' -or
114
($PSVersionTable.PsVersion -lt [version]'7.3.0' -and -not [ExperimentalFeature]::IsEnabled("PSNativeCommandArgumentPassing")) -or
115
(($PSVersionTable.PsVersion -ge [version]'7.3.0' -or [ExperimentalFeature]::IsEnabled("PSNativeCommandArgumentPassing")) -and
116
$PSNativeCommandArgumentPassing -eq 'Legacy')) {
117
`+" $RequestComp=\"$RequestComp\" + ' `\"`\"'"+`
118
} else {
119
$RequestComp="$RequestComp" + ' ""'
120
}
121
}
122
123
__%[1]s_debug "Calling $RequestComp"
124
# First disable ActiveHelp which is not supported for Powershell
125
${env:%[10]s}=0
126
127
#call the command store the output in $out and redirect stderr and stdout to null
128
# $Out is an array contains each line per element
129
Invoke-Expression -OutVariable out "$RequestComp" 2>&1 | Out-Null
130
131
# get directive from last line
132
[int]$Directive = $Out[-1].TrimStart(':')
133
if ($Directive -eq "") {
134
# There is no directive specified
135
$Directive = 0
136
}
137
__%[1]s_debug "The completion directive is: $Directive"
138
139
# remove directive (last element) from out
140
$Out = $Out | Where-Object { $_ -ne $Out[-1] }
141
__%[1]s_debug "The completions are: $Out"
142
143
if (($Directive -band $ShellCompDirectiveError) -ne 0 ) {
144
# Error code. No completion.
145
__%[1]s_debug "Received error from custom completion go code"
146
return
147
}
148
149
$Longest = 0
150
[Array]$Values = $Out | ForEach-Object {
151
#Split the output in name and description
152
`+" $Name, $Description = $_.Split(\"`t\",2)"+`
153
__%[1]s_debug "Name: $Name Description: $Description"
154
155
# Look for the longest completion so that we can format things nicely
156
if ($Longest -lt $Name.Length) {
157
$Longest = $Name.Length
158
}
159
160
# Set the description to a one space string if there is none set.
161
# This is needed because the CompletionResult does not accept an empty string as argument
162
if (-Not $Description) {
163
$Description = " "
164
}
165
New-Object -TypeName PSCustomObject -Property @{
166
Name = "$Name"
167
Description = "$Description"
168
}
169
}
170
171
172
$Space = " "
173
if (($Directive -band $ShellCompDirectiveNoSpace) -ne 0 ) {
174
# remove the space here
175
__%[1]s_debug "ShellCompDirectiveNoSpace is called"
176
$Space = ""
177
}
178
179
if ((($Directive -band $ShellCompDirectiveFilterFileExt) -ne 0 ) -or
180
(($Directive -band $ShellCompDirectiveFilterDirs) -ne 0 )) {
181
__%[1]s_debug "ShellCompDirectiveFilterFileExt ShellCompDirectiveFilterDirs are not supported"
182
183
# return here to prevent the completion of the extensions
184
return
185
}
186
187
$Values = $Values | Where-Object {
188
# filter the result
189
$_.Name -like "$WordToComplete*"
190
191
# Join the flag back if we have an equal sign flag
192
if ( $IsEqualFlag ) {
193
__%[1]s_debug "Join the equal sign flag back to the completion value"
194
$_.Name = $Flag + "=" + $_.Name
195
}
196
}
197
198
# we sort the values in ascending order by name if keep order isn't passed
199
if (($Directive -band $ShellCompDirectiveKeepOrder) -eq 0 ) {
200
$Values = $Values | Sort-Object -Property Name
201
}
202
203
if (($Directive -band $ShellCompDirectiveNoFileComp) -ne 0 ) {
204
__%[1]s_debug "ShellCompDirectiveNoFileComp is called"
205
206
if ($Values.Length -eq 0) {
207
# Just print an empty string here so the
208
# shell does not start to complete paths.
209
# We cannot use CompletionResult here because
210
# it does not accept an empty string as argument.
211
""
212
return
213
}
214
}
215
216
# Get the current mode
217
$Mode = (Get-PSReadLineKeyHandler | Where-Object {$_.Key -eq "Tab" }).Function
218
__%[1]s_debug "Mode: $Mode"
219
220
$Values | ForEach-Object {
221
222
# store temporary because switch will overwrite $_
223
$comp = $_
224
225
# PowerShell supports three different completion modes
226
# - TabCompleteNext (default windows style - on each key press the next option is displayed)
227
# - Complete (works like bash)
228
# - MenuComplete (works like zsh)
229
# You set the mode with Set-PSReadLineKeyHandler -Key Tab -Function <mode>
230
231
# CompletionResult Arguments:
232
# 1) CompletionText text to be used as the auto completion result
233
# 2) ListItemText text to be displayed in the suggestion list
234
# 3) ResultType type of completion result
235
# 4) ToolTip text for the tooltip with details about the object
236
237
switch ($Mode) {
238
239
# bash like
240
"Complete" {
241
242
if ($Values.Length -eq 1) {
243
__%[1]s_debug "Only one completion left"
244
245
# insert space after value
246
$CompletionText = $($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space
247
if ($ExecutionContext.SessionState.LanguageMode -eq "FullLanguage"){
248
[System.Management.Automation.CompletionResult]::new($CompletionText, "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
249
} else {
250
$CompletionText
251
}
252
253
} else {
254
# Add the proper number of spaces to align the descriptions
255
while($comp.Name.Length -lt $Longest) {
256
$comp.Name = $comp.Name + " "
257
}
258
259
# Check for empty description and only add parentheses if needed
260
if ($($comp.Description) -eq " " ) {
261
$Description = ""
262
} else {
263
$Description = " ($($comp.Description))"
264
}
265
266
$CompletionText = "$($comp.Name)$Description"
267
if ($ExecutionContext.SessionState.LanguageMode -eq "FullLanguage"){
268
[System.Management.Automation.CompletionResult]::new($CompletionText, "$($comp.Name)$Description", 'ParameterValue', "$($comp.Description)")
269
} else {
270
$CompletionText
271
}
272
}
273
}
274
275
# zsh like
276
"MenuComplete" {
277
# insert space after value
278
# MenuComplete will automatically show the ToolTip of
279
# the highlighted value at the bottom of the suggestions.
280
281
$CompletionText = $($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space
282
if ($ExecutionContext.SessionState.LanguageMode -eq "FullLanguage"){
283
[System.Management.Automation.CompletionResult]::new($CompletionText, "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
284
} else {
285
$CompletionText
286
}
287
}
288
289
# TabCompleteNext and in case we get something unknown
290
Default {
291
# Like MenuComplete but we don't want to add a space here because
292
# the user need to press space anyway to get the completion.
293
# Description will not be shown because that's not possible with TabCompleteNext
294
295
$CompletionText = $($comp.Name | __%[1]s_escapeStringWithSpecialChars)
296
if ($ExecutionContext.SessionState.LanguageMode -eq "FullLanguage"){
297
[System.Management.Automation.CompletionResult]::new($CompletionText, "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
298
} else {
299
$CompletionText
300
}
301
}
302
}
303
304
}
305
}
306
307
Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock ${__%[2]sCompleterBlock}
308
`, name, nameForVar, compCmd,
309
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
310
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, ShellCompDirectiveKeepOrder, activeHelpEnvVar(name)))
311
}
312
313
func (c *Command) genPowerShellCompletion(w io.Writer, includeDesc bool) error {
314
buf := new(bytes.Buffer)
315
genPowerShellComp(buf, c.Name(), includeDesc)
316
_, err := buf.WriteTo(w)
317
return err
318
}
319
320
func (c *Command) genPowerShellCompletionFile(filename string, includeDesc bool) error {
321
outFile, err := os.Create(filename)
322
if err != nil {
323
return err
324
}
325
defer outFile.Close()
326
327
return c.genPowerShellCompletion(outFile, includeDesc)
328
}
329
330
// GenPowerShellCompletionFile generates powershell completion file without descriptions.
331
func (c *Command) GenPowerShellCompletionFile(filename string) error {
332
return c.genPowerShellCompletionFile(filename, false)
333
}
334
335
// GenPowerShellCompletion generates powershell completion file without descriptions
336
// and writes it to the passed writer.
337
func (c *Command) GenPowerShellCompletion(w io.Writer) error {
338
return c.genPowerShellCompletion(w, false)
339
}
340
341
// GenPowerShellCompletionFileWithDesc generates powershell completion file with descriptions.
342
func (c *Command) GenPowerShellCompletionFileWithDesc(filename string) error {
343
return c.genPowerShellCompletionFile(filename, true)
344
}
345
346
// GenPowerShellCompletionWithDesc generates powershell completion file with descriptions
347
// and writes it to the passed writer.
348
func (c *Command) GenPowerShellCompletionWithDesc(w io.Writer) error {
349
return c.genPowerShellCompletion(w, true)
350
}
351
352