100 lines
3.2 KiB
Go
100 lines
3.2 KiB
Go
// PowerShell completions are based on the amazing work from clap:
|
|
// https://github.com/clap-rs/clap/blob/3294d18efe5f264d12c9035f404c7d189d4824e1/src/completions/powershell.rs
|
|
//
|
|
// The generated scripts require PowerShell v5.0+ (which comes Windows 10, but
|
|
// can be downloaded separately for windows 7 or 8.1).
|
|
|
|
package cobra
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/spf13/pflag"
|
|
)
|
|
|
|
var powerShellCompletionTemplate = `using namespace System.Management.Automation
|
|
using namespace System.Management.Automation.Language
|
|
Register-ArgumentCompleter -Native -CommandName '%s' -ScriptBlock {
|
|
param($wordToComplete, $commandAst, $cursorPosition)
|
|
$commandElements = $commandAst.CommandElements
|
|
$command = @(
|
|
'%s'
|
|
for ($i = 1; $i -lt $commandElements.Count; $i++) {
|
|
$element = $commandElements[$i]
|
|
if ($element -isnot [StringConstantExpressionAst] -or
|
|
$element.StringConstantType -ne [StringConstantType]::BareWord -or
|
|
$element.Value.StartsWith('-')) {
|
|
break
|
|
}
|
|
$element.Value
|
|
}
|
|
) -join ';'
|
|
$completions = @(switch ($command) {%s
|
|
})
|
|
$completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
|
|
Sort-Object -Property ListItemText
|
|
}`
|
|
|
|
func generatePowerShellSubcommandCases(out io.Writer, cmd *Command, previousCommandName string) {
|
|
var cmdName string
|
|
if previousCommandName == "" {
|
|
cmdName = cmd.Name()
|
|
} else {
|
|
cmdName = fmt.Sprintf("%s;%s", previousCommandName, cmd.Name())
|
|
}
|
|
|
|
fmt.Fprintf(out, "\n '%s' {", cmdName)
|
|
|
|
cmd.Flags().VisitAll(func(flag *pflag.Flag) {
|
|
if nonCompletableFlag(flag) {
|
|
return
|
|
}
|
|
usage := escapeStringForPowerShell(flag.Usage)
|
|
if len(flag.Shorthand) > 0 {
|
|
fmt.Fprintf(out, "\n [CompletionResult]::new('-%s', '%s', [CompletionResultType]::ParameterName, '%s')", flag.Shorthand, flag.Shorthand, usage)
|
|
}
|
|
fmt.Fprintf(out, "\n [CompletionResult]::new('--%s', '%s', [CompletionResultType]::ParameterName, '%s')", flag.Name, flag.Name, usage)
|
|
})
|
|
|
|
for _, subCmd := range cmd.Commands() {
|
|
usage := escapeStringForPowerShell(subCmd.Short)
|
|
fmt.Fprintf(out, "\n [CompletionResult]::new('%s', '%s', [CompletionResultType]::ParameterValue, '%s')", subCmd.Name(), subCmd.Name(), usage)
|
|
}
|
|
|
|
fmt.Fprint(out, "\n break\n }")
|
|
|
|
for _, subCmd := range cmd.Commands() {
|
|
generatePowerShellSubcommandCases(out, subCmd, cmdName)
|
|
}
|
|
}
|
|
|
|
func escapeStringForPowerShell(s string) string {
|
|
return strings.Replace(s, "'", "''", -1)
|
|
}
|
|
|
|
// GenPowerShellCompletion generates PowerShell completion file and writes to the passed writer.
|
|
func (c *Command) GenPowerShellCompletion(w io.Writer) error {
|
|
buf := new(bytes.Buffer)
|
|
|
|
var subCommandCases bytes.Buffer
|
|
generatePowerShellSubcommandCases(&subCommandCases, c, "")
|
|
fmt.Fprintf(buf, powerShellCompletionTemplate, c.Name(), c.Name(), subCommandCases.String())
|
|
|
|
_, err := buf.WriteTo(w)
|
|
return err
|
|
}
|
|
|
|
// GenPowerShellCompletionFile generates PowerShell completion file.
|
|
func (c *Command) GenPowerShellCompletionFile(filename string) error {
|
|
outFile, err := os.Create(filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer outFile.Close()
|
|
|
|
return c.GenPowerShellCompletion(outFile)
|
|
}
|