mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 10:03:42 +08:00 
			
		
		
		
	- release notes: https://github.com/spf13/cobra/releases/tag/v1.8.0 - full diff: https://github.com/spf13/cobra/compare/v1.7.0...v1.8.0 Release notes highlights: Features - Support usage as plugin for tools like kubectl - this means that programs that utilize a "plugin-like" structure have much better support and usage (like for completions, command paths, etc.) - Move documentation sources to site/content - Add 'one required flag' group - this includes a new MarkFlagsOneRequired API for flags which can be used to mark a flag group as required and cause command failure if at least one is not used when invoked. - Customizable error message prefix - This adds the SetErrPrefix and ErrPrefix APIs on the Command struct to allow for setting a custom prefix for errors - feat: add getters for flag completions - Feature: allow running persistent run hooks of all parents - Improve API to get flag completion function Bug fixes - Fix typo in fish completions - Fix grammar: 'allows to' - powershell: escape variable with curly brackets - Don't complete --help flag when flag parsing disabled - Replace all non-alphanumerics in active help env var program prefix Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
		
			
				
	
	
		
			326 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			326 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2013-2023 The Cobra Authors
 | 
						|
//
 | 
						|
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
// you may not use this file except in compliance with the License.
 | 
						|
// You may obtain a copy of the License at
 | 
						|
//
 | 
						|
//      http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
//
 | 
						|
// Unless required by applicable law or agreed to in writing, software
 | 
						|
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
// See the License for the specific language governing permissions and
 | 
						|
// limitations under the License.
 | 
						|
 | 
						|
// 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"
 | 
						|
)
 | 
						|
 | 
						|
func genPowerShellComp(buf io.StringWriter, name string, includeDesc bool) {
 | 
						|
	// Variables should not contain a '-' or ':' character
 | 
						|
	nameForVar := name
 | 
						|
	nameForVar = strings.Replace(nameForVar, "-", "_", -1)
 | 
						|
	nameForVar = strings.Replace(nameForVar, ":", "_", -1)
 | 
						|
 | 
						|
	compCmd := ShellCompRequestCmd
 | 
						|
	if !includeDesc {
 | 
						|
		compCmd = ShellCompNoDescRequestCmd
 | 
						|
	}
 | 
						|
	WriteStringAndCheck(buf, fmt.Sprintf(`# powershell completion for %-36[1]s -*- shell-script -*-
 | 
						|
 | 
						|
function __%[1]s_debug {
 | 
						|
    if ($env:BASH_COMP_DEBUG_FILE) {
 | 
						|
        "$args" | Out-File -Append -FilePath "$env:BASH_COMP_DEBUG_FILE"
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
filter __%[1]s_escapeStringWithSpecialChars {
 | 
						|
`+"    $_ -replace '\\s|#|@|\\$|;|,|''|\\{|\\}|\\(|\\)|\"|`|\\||<|>|&','`$&'"+`
 | 
						|
}
 | 
						|
 | 
						|
[scriptblock]${__%[2]sCompleterBlock} = {
 | 
						|
    param(
 | 
						|
            $WordToComplete,
 | 
						|
            $CommandAst,
 | 
						|
            $CursorPosition
 | 
						|
        )
 | 
						|
 | 
						|
    # Get the current command line and convert into a string
 | 
						|
    $Command = $CommandAst.CommandElements
 | 
						|
    $Command = "$Command"
 | 
						|
 | 
						|
    __%[1]s_debug ""
 | 
						|
    __%[1]s_debug "========= starting completion logic =========="
 | 
						|
    __%[1]s_debug "WordToComplete: $WordToComplete Command: $Command CursorPosition: $CursorPosition"
 | 
						|
 | 
						|
    # The user could have moved the cursor backwards on the command-line.
 | 
						|
    # We need to trigger completion from the $CursorPosition location, so we need
 | 
						|
    # to truncate the command-line ($Command) up to the $CursorPosition location.
 | 
						|
    # Make sure the $Command is longer then the $CursorPosition before we truncate.
 | 
						|
    # This happens because the $Command does not include the last space.
 | 
						|
    if ($Command.Length -gt $CursorPosition) {
 | 
						|
        $Command=$Command.Substring(0,$CursorPosition)
 | 
						|
    }
 | 
						|
    __%[1]s_debug "Truncated command: $Command"
 | 
						|
 | 
						|
    $ShellCompDirectiveError=%[4]d
 | 
						|
    $ShellCompDirectiveNoSpace=%[5]d
 | 
						|
    $ShellCompDirectiveNoFileComp=%[6]d
 | 
						|
    $ShellCompDirectiveFilterFileExt=%[7]d
 | 
						|
    $ShellCompDirectiveFilterDirs=%[8]d
 | 
						|
    $ShellCompDirectiveKeepOrder=%[9]d
 | 
						|
 | 
						|
    # Prepare the command to request completions for the program.
 | 
						|
    # Split the command at the first space to separate the program and arguments.
 | 
						|
    $Program,$Arguments = $Command.Split(" ",2)
 | 
						|
 | 
						|
    $RequestComp="$Program %[3]s $Arguments"
 | 
						|
    __%[1]s_debug "RequestComp: $RequestComp"
 | 
						|
 | 
						|
    # we cannot use $WordToComplete because it
 | 
						|
    # has the wrong values if the cursor was moved
 | 
						|
    # so use the last argument
 | 
						|
    if ($WordToComplete -ne "" ) {
 | 
						|
        $WordToComplete = $Arguments.Split(" ")[-1]
 | 
						|
    }
 | 
						|
    __%[1]s_debug "New WordToComplete: $WordToComplete"
 | 
						|
 | 
						|
 | 
						|
    # Check for flag with equal sign
 | 
						|
    $IsEqualFlag = ($WordToComplete -Like "--*=*" )
 | 
						|
    if ( $IsEqualFlag ) {
 | 
						|
        __%[1]s_debug "Completing equal sign flag"
 | 
						|
        # Remove the flag part
 | 
						|
        $Flag,$WordToComplete = $WordToComplete.Split("=",2)
 | 
						|
    }
 | 
						|
 | 
						|
    if ( $WordToComplete -eq "" -And ( -Not $IsEqualFlag )) {
 | 
						|
        # If the last parameter is complete (there is a space following it)
 | 
						|
        # We add an extra empty parameter so we can indicate this to the go method.
 | 
						|
        __%[1]s_debug "Adding extra empty parameter"
 | 
						|
        # PowerShell 7.2+ changed the way how the arguments are passed to executables,
 | 
						|
        # so for pre-7.2 or when Legacy argument passing is enabled we need to use
 | 
						|
`+"        # `\"`\" to pass an empty argument, a \"\" or '' does not work!!!"+`
 | 
						|
        if ($PSVersionTable.PsVersion -lt [version]'7.2.0' -or
 | 
						|
            ($PSVersionTable.PsVersion -lt [version]'7.3.0' -and -not [ExperimentalFeature]::IsEnabled("PSNativeCommandArgumentPassing")) -or
 | 
						|
            (($PSVersionTable.PsVersion -ge [version]'7.3.0' -or [ExperimentalFeature]::IsEnabled("PSNativeCommandArgumentPassing")) -and
 | 
						|
              $PSNativeCommandArgumentPassing -eq 'Legacy')) {
 | 
						|
`+"             $RequestComp=\"$RequestComp\" + ' `\"`\"'"+`
 | 
						|
        } else {
 | 
						|
             $RequestComp="$RequestComp" + ' ""'
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    __%[1]s_debug "Calling $RequestComp"
 | 
						|
    # First disable ActiveHelp which is not supported for Powershell
 | 
						|
    ${env:%[10]s}=0
 | 
						|
 | 
						|
    #call the command store the output in $out and redirect stderr and stdout to null
 | 
						|
    # $Out is an array contains each line per element
 | 
						|
    Invoke-Expression -OutVariable out "$RequestComp" 2>&1 | Out-Null
 | 
						|
 | 
						|
    # get directive from last line
 | 
						|
    [int]$Directive = $Out[-1].TrimStart(':')
 | 
						|
    if ($Directive -eq "") {
 | 
						|
        # There is no directive specified
 | 
						|
        $Directive = 0
 | 
						|
    }
 | 
						|
    __%[1]s_debug "The completion directive is: $Directive"
 | 
						|
 | 
						|
    # remove directive (last element) from out
 | 
						|
    $Out = $Out | Where-Object { $_ -ne $Out[-1] }
 | 
						|
    __%[1]s_debug "The completions are: $Out"
 | 
						|
 | 
						|
    if (($Directive -band $ShellCompDirectiveError) -ne 0 ) {
 | 
						|
        # Error code.  No completion.
 | 
						|
        __%[1]s_debug "Received error from custom completion go code"
 | 
						|
        return
 | 
						|
    }
 | 
						|
 | 
						|
    $Longest = 0
 | 
						|
    [Array]$Values = $Out | ForEach-Object {
 | 
						|
        #Split the output in name and description
 | 
						|
`+"        $Name, $Description = $_.Split(\"`t\",2)"+`
 | 
						|
        __%[1]s_debug "Name: $Name Description: $Description"
 | 
						|
 | 
						|
        # Look for the longest completion so that we can format things nicely
 | 
						|
        if ($Longest -lt $Name.Length) {
 | 
						|
            $Longest = $Name.Length
 | 
						|
        }
 | 
						|
 | 
						|
        # Set the description to a one space string if there is none set.
 | 
						|
        # This is needed because the CompletionResult does not accept an empty string as argument
 | 
						|
        if (-Not $Description) {
 | 
						|
            $Description = " "
 | 
						|
        }
 | 
						|
        @{Name="$Name";Description="$Description"}
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    $Space = " "
 | 
						|
    if (($Directive -band $ShellCompDirectiveNoSpace) -ne 0 ) {
 | 
						|
        # remove the space here
 | 
						|
        __%[1]s_debug "ShellCompDirectiveNoSpace is called"
 | 
						|
        $Space = ""
 | 
						|
    }
 | 
						|
 | 
						|
    if ((($Directive -band $ShellCompDirectiveFilterFileExt) -ne 0 ) -or
 | 
						|
       (($Directive -band $ShellCompDirectiveFilterDirs) -ne 0 ))  {
 | 
						|
        __%[1]s_debug "ShellCompDirectiveFilterFileExt ShellCompDirectiveFilterDirs are not supported"
 | 
						|
 | 
						|
        # return here to prevent the completion of the extensions
 | 
						|
        return
 | 
						|
    }
 | 
						|
 | 
						|
    $Values = $Values | Where-Object {
 | 
						|
        # filter the result
 | 
						|
        $_.Name -like "$WordToComplete*"
 | 
						|
 | 
						|
        # Join the flag back if we have an equal sign flag
 | 
						|
        if ( $IsEqualFlag ) {
 | 
						|
            __%[1]s_debug "Join the equal sign flag back to the completion value"
 | 
						|
            $_.Name = $Flag + "=" + $_.Name
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # we sort the values in ascending order by name if keep order isn't passed
 | 
						|
    if (($Directive -band $ShellCompDirectiveKeepOrder) -eq 0 ) {
 | 
						|
        $Values = $Values | Sort-Object -Property Name
 | 
						|
    }
 | 
						|
 | 
						|
    if (($Directive -band $ShellCompDirectiveNoFileComp) -ne 0 ) {
 | 
						|
        __%[1]s_debug "ShellCompDirectiveNoFileComp is called"
 | 
						|
 | 
						|
        if ($Values.Length -eq 0) {
 | 
						|
            # Just print an empty string here so the
 | 
						|
            # shell does not start to complete paths.
 | 
						|
            # We cannot use CompletionResult here because
 | 
						|
            # it does not accept an empty string as argument.
 | 
						|
            ""
 | 
						|
            return
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # Get the current mode
 | 
						|
    $Mode = (Get-PSReadLineKeyHandler | Where-Object {$_.Key -eq "Tab" }).Function
 | 
						|
    __%[1]s_debug "Mode: $Mode"
 | 
						|
 | 
						|
    $Values | ForEach-Object {
 | 
						|
 | 
						|
        # store temporary because switch will overwrite $_
 | 
						|
        $comp = $_
 | 
						|
 | 
						|
        # PowerShell supports three different completion modes
 | 
						|
        # - TabCompleteNext (default windows style - on each key press the next option is displayed)
 | 
						|
        # - Complete (works like bash)
 | 
						|
        # - MenuComplete (works like zsh)
 | 
						|
        # You set the mode with Set-PSReadLineKeyHandler -Key Tab -Function <mode>
 | 
						|
 | 
						|
        # CompletionResult Arguments:
 | 
						|
        # 1) CompletionText text to be used as the auto completion result
 | 
						|
        # 2) ListItemText   text to be displayed in the suggestion list
 | 
						|
        # 3) ResultType     type of completion result
 | 
						|
        # 4) ToolTip        text for the tooltip with details about the object
 | 
						|
 | 
						|
        switch ($Mode) {
 | 
						|
 | 
						|
            # bash like
 | 
						|
            "Complete" {
 | 
						|
 | 
						|
                if ($Values.Length -eq 1) {
 | 
						|
                    __%[1]s_debug "Only one completion left"
 | 
						|
 | 
						|
                    # insert space after value
 | 
						|
                    [System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space, "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
 | 
						|
 | 
						|
                } else {
 | 
						|
                    # Add the proper number of spaces to align the descriptions
 | 
						|
                    while($comp.Name.Length -lt $Longest) {
 | 
						|
                        $comp.Name = $comp.Name + " "
 | 
						|
                    }
 | 
						|
 | 
						|
                    # Check for empty description and only add parentheses if needed
 | 
						|
                    if ($($comp.Description) -eq " " ) {
 | 
						|
                        $Description = ""
 | 
						|
                    } else {
 | 
						|
                        $Description = "  ($($comp.Description))"
 | 
						|
                    }
 | 
						|
 | 
						|
                    [System.Management.Automation.CompletionResult]::new("$($comp.Name)$Description", "$($comp.Name)$Description", 'ParameterValue', "$($comp.Description)")
 | 
						|
                }
 | 
						|
             }
 | 
						|
 | 
						|
            # zsh like
 | 
						|
            "MenuComplete" {
 | 
						|
                # insert space after value
 | 
						|
                # MenuComplete will automatically show the ToolTip of
 | 
						|
                # the highlighted value at the bottom of the suggestions.
 | 
						|
                [System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space, "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
 | 
						|
            }
 | 
						|
 | 
						|
            # TabCompleteNext and in case we get something unknown
 | 
						|
            Default {
 | 
						|
                # Like MenuComplete but we don't want to add a space here because
 | 
						|
                # the user need to press space anyway to get the completion.
 | 
						|
                # Description will not be shown because that's not possible with TabCompleteNext
 | 
						|
                [System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars), "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock ${__%[2]sCompleterBlock}
 | 
						|
`, name, nameForVar, compCmd,
 | 
						|
		ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
 | 
						|
		ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, ShellCompDirectiveKeepOrder, activeHelpEnvVar(name)))
 | 
						|
}
 | 
						|
 | 
						|
func (c *Command) genPowerShellCompletion(w io.Writer, includeDesc bool) error {
 | 
						|
	buf := new(bytes.Buffer)
 | 
						|
	genPowerShellComp(buf, c.Name(), includeDesc)
 | 
						|
	_, err := buf.WriteTo(w)
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func (c *Command) genPowerShellCompletionFile(filename string, includeDesc bool) error {
 | 
						|
	outFile, err := os.Create(filename)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer outFile.Close()
 | 
						|
 | 
						|
	return c.genPowerShellCompletion(outFile, includeDesc)
 | 
						|
}
 | 
						|
 | 
						|
// GenPowerShellCompletionFile generates powershell completion file without descriptions.
 | 
						|
func (c *Command) GenPowerShellCompletionFile(filename string) error {
 | 
						|
	return c.genPowerShellCompletionFile(filename, false)
 | 
						|
}
 | 
						|
 | 
						|
// GenPowerShellCompletion generates powershell completion file without descriptions
 | 
						|
// and writes it to the passed writer.
 | 
						|
func (c *Command) GenPowerShellCompletion(w io.Writer) error {
 | 
						|
	return c.genPowerShellCompletion(w, false)
 | 
						|
}
 | 
						|
 | 
						|
// GenPowerShellCompletionFileWithDesc generates powershell completion file with descriptions.
 | 
						|
func (c *Command) GenPowerShellCompletionFileWithDesc(filename string) error {
 | 
						|
	return c.genPowerShellCompletionFile(filename, true)
 | 
						|
}
 | 
						|
 | 
						|
// GenPowerShellCompletionWithDesc generates powershell completion file with descriptions
 | 
						|
// and writes it to the passed writer.
 | 
						|
func (c *Command) GenPowerShellCompletionWithDesc(w io.Writer) error {
 | 
						|
	return c.genPowerShellCompletion(w, true)
 | 
						|
}
 |