// 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.package cobraimport ()const (// ShellCompRequestCmd is the name of the hidden command that is used to request // completion results from the program. It is used by the shell completion scripts.ShellCompRequestCmd = "__complete"// ShellCompNoDescRequestCmd is the name of the hidden command that is used to request // completion results without their description. It is used by the shell completion scripts.ShellCompNoDescRequestCmd = "__completeNoDesc")// Global map of flag completion functions. Make sure to use flagCompletionMutex before you try to read and write from it.var flagCompletionFunctions = map[*pflag.Flag]func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective){}// lock for reading and writing from flagCompletionFunctionsvar flagCompletionMutex = &sync.RWMutex{}// ShellCompDirective is a bit map representing the different behaviors the shell// can be instructed to have once completions have been provided.typeShellCompDirectiveinttype flagCompError struct { subCommand string flagName string}func ( *flagCompError) () string {return"Subcommand '" + .subCommand + "' does not support flag '" + .flagName + "'"}const (// ShellCompDirectiveError indicates an error occurred and completions should be ignored.ShellCompDirectiveErrorShellCompDirective = 1 << iota// ShellCompDirectiveNoSpace indicates that the shell should not add a space // after the completion even if there is a single completion provided.ShellCompDirectiveNoSpace// ShellCompDirectiveNoFileComp indicates that the shell should not provide // file completion even when no completion is provided.ShellCompDirectiveNoFileComp// ShellCompDirectiveFilterFileExt indicates that the provided completions // should be used as file extension filters. // For flags, using Command.MarkFlagFilename() and Command.MarkPersistentFlagFilename() // is a shortcut to using this directive explicitly. The BashCompFilenameExt // annotation can also be used to obtain the same behavior for flags.ShellCompDirectiveFilterFileExt// ShellCompDirectiveFilterDirs indicates that only directory names should // be provided in file completion. To request directory names within another // directory, the returned completions should specify the directory within // which to search. The BashCompSubdirsInDir annotation can be used to // obtain the same behavior but only for flags.ShellCompDirectiveFilterDirs// ShellCompDirectiveKeepOrder indicates that the shell should preserve the order // in which the completions are providedShellCompDirectiveKeepOrder// ===========================================================================// All directives using iota should be above this one. // For internal use. shellCompDirectiveMaxValue// ShellCompDirectiveDefault indicates to let the shell perform its default // behavior after completions have been provided. // This one must be last to avoid messing up the iota count.ShellCompDirectiveDefaultShellCompDirective = 0)const (// Constants for the completion command compCmdName = "completion" compCmdNoDescFlagName = "no-descriptions" compCmdNoDescFlagDesc = "disable completion descriptions" compCmdNoDescFlagDefault = false)// CompletionOptions are the options to control shell completiontypeCompletionOptionsstruct {// DisableDefaultCmd prevents Cobra from creating a default 'completion' command DisableDefaultCmd bool// DisableNoDescFlag prevents Cobra from creating the '--no-descriptions' flag // for shells that support completion descriptions DisableNoDescFlag bool// DisableDescriptions turns off all completion descriptions for shells // that support them DisableDescriptions bool// HiddenDefaultCmd makes the default 'completion' command hidden HiddenDefaultCmd bool}// NoFileCompletions can be used to disable file completion for commands that should// not trigger file completions.func ( *Command, []string, string) ([]string, ShellCompDirective) {returnnil, ShellCompDirectiveNoFileComp}// FixedCompletions can be used to create a completion function which always// returns the same results.func ( []string, ShellCompDirective) func( *Command, []string, string) ([]string, ShellCompDirective) {returnfunc( *Command, []string, string) ([]string, ShellCompDirective) {return , }}// RegisterFlagCompletionFunc should be called to register a function to provide completion for a flag.func ( *Command) ( string, func( *Command, []string, string) ([]string, ShellCompDirective)) error { := .Flag()if == nil {returnfmt.Errorf("RegisterFlagCompletionFunc: flag '%s' does not exist", ) }flagCompletionMutex.Lock()deferflagCompletionMutex.Unlock()if , := flagCompletionFunctions[]; {returnfmt.Errorf("RegisterFlagCompletionFunc: flag '%s' already registered", ) }flagCompletionFunctions[] = returnnil}// GetFlagCompletionFunc returns the completion function for the given flag of the command, if available.func ( *Command) ( string) (func(*Command, []string, string) ([]string, ShellCompDirective), bool) { := .Flag()if == nil {returnnil, false }flagCompletionMutex.RLock()deferflagCompletionMutex.RUnlock() , := flagCompletionFunctions[]return , }// Returns a string listing the different directive enabled in the specified parameterfunc ( ShellCompDirective) () string {var []stringif &ShellCompDirectiveError != 0 { = append(, "ShellCompDirectiveError") }if &ShellCompDirectiveNoSpace != 0 { = append(, "ShellCompDirectiveNoSpace") }if &ShellCompDirectiveNoFileComp != 0 { = append(, "ShellCompDirectiveNoFileComp") }if &ShellCompDirectiveFilterFileExt != 0 { = append(, "ShellCompDirectiveFilterFileExt") }if &ShellCompDirectiveFilterDirs != 0 { = append(, "ShellCompDirectiveFilterDirs") }if &ShellCompDirectiveKeepOrder != 0 { = append(, "ShellCompDirectiveKeepOrder") }iflen() == 0 { = append(, "ShellCompDirectiveDefault") }if >= shellCompDirectiveMaxValue {returnfmt.Sprintf("ERROR: unexpected ShellCompDirective value: %d", ) }returnstrings.Join(, ", ")}// initCompleteCmd adds a special hidden command that can be used to request custom completions.func ( *Command) ( []string) { := &Command{Use: fmt.Sprintf("%s [command-line]", ShellCompRequestCmd),Aliases: []string{ShellCompNoDescRequestCmd},DisableFlagsInUseLine: true,Hidden: true,DisableFlagParsing: true,Args: MinimumNArgs(1),Short: "Request shell completion choices for the specified command-line",Long: fmt.Sprintf("%[2]s is a special command that is used by the shell completion logic\n%[1]s","to request completion choices for the specified command-line.", ShellCompRequestCmd),Run: func( *Command, []string) { , , , := .getCompletions()if != nil {CompErrorln(.Error())// Keep going for multiple reasons: // 1- There could be some valid completions even though there was an error // 2- Even without completions, we need to print the directive } := .CalledAs() == ShellCompNoDescRequestCmdif ! {if , := strconv.ParseBool(getEnvConfig(, configEnvVarSuffixDescriptions)); == nil { = ! } } := GetActiveHelpConfig() == activeHelpGlobalDisable := .OutOrStdout()for , := range {if && strings.HasPrefix(, activeHelpMarker) {// Remove all activeHelp entries if it's disabled.continue }if {// Remove any description that may be included following a tab character. = strings.SplitN(, "\t", 2)[0] }// Make sure we only write the first line to the output. // This is needed if a description contains a linebreak. // Otherwise the shell scripts will interpret the other lines as new flags // and could therefore provide a wrong completion. = strings.SplitN(, "\n", 2)[0]// Finally trim the completion. This is especially important to get rid // of a trailing tab when there are no description following it. // For example, a sub-command without a description should not be completed // with a tab at the end (or else zsh will show a -- following it // although there is no description). = strings.TrimSpace()// Print each possible completion to the output for the completion script to consume.fmt.Fprintln(, ) }// As the last printout, print the completion directive for the completion script to parse. // The directive integer must be that last character following a single colon (:). // The completion script expects :<directive>fmt.Fprintf(, ":%d\n", )// Print some helpful info to stderr for the user to understand. // Output from stderr must be ignored by the completion script.fmt.Fprintf(.ErrOrStderr(), "Completion ended with directive: %s\n", .string()) }, } .AddCommand() , , := .Find()if != nil || .Name() != ShellCompRequestCmd {// Only create this special command if it is actually being called. // This reduces possible side-effects of creating such a command; // for example, having this command would cause problems to a // cobra program that only consists of the root command, since this // command would cause the root command to suddenly have a subcommand. .RemoveCommand() }}func ( *Command) ( []string) (*Command, []string, ShellCompDirective, error) {// The last argument, which is not completely typed by the user, // should not be part of the list of arguments := [len()-1] := [:len()-1]var *Commandvar []stringvarerror// Find the real command for which completion must be performed // check if we need to traverse here to parse local flags on parent commandsif .Root().TraverseChildren { , , = .Root().Traverse() } else {// For Root commands that don't specify any value for their Args fields, when we call // Find(), if those Root commands don't have any sub-commands, they will accept arguments. // However, because we have added the __complete sub-command in the current code path, the // call to Find() -> legacyArgs() will return an error if there are any arguments. // To avoid this, we first remove the __complete command to get back to having no sub-commands. := .Root()iflen(.Commands()) == 1 { .RemoveCommand() } , , = .Find() }if != nil {// Unable to find the real command. E.g., <program> someInvalidCmd <TAB>return , []string{}, ShellCompDirectiveDefault, fmt.Errorf("unable to find a command for arguments: %v", ) } .ctx = .ctx// These flags are normally added when `execute()` is called on `finalCmd`, // however, when doing completion, we don't call `finalCmd.execute()`. // Let's add the --help and --version flag ourselves but only if the finalCmd // has not disabled flag parsing; if flag parsing is disabled, it is up to the // finalCmd itself to handle the completion of *all* flags.if !.DisableFlagParsing { .InitDefaultHelpFlag() .InitDefaultVersionFlag() }// Check if we are doing flag value completion before parsing the flags. // This is important because if we are completing a flag value, we need to also // remove the flag name argument from the list of finalArgs or else the parsing // could fail due to an invalid value (incomplete) for the flag. , , , := checkIfFlagCompletion(, , )// Check if interspersed is false or -- was set on a previous arg. // This works by counting the arguments. Normally -- is not counted as arg but // if -- was already set or interspersed is false and there is already one arg then // the extra added -- is counted as arg. := true _ = .ParseFlags(append(, "--")) := .Flags().NArg()// Parse the flags early so we can check if required flags are setif = .ParseFlags(); != nil {return , []string{}, ShellCompDirectiveDefault, fmt.Errorf("Error while parsing flags from args %v: %s", , .Error()) } := .Flags().NArg()if > {// don't do flag completion (see above) = false }// Error while attempting to parse flagsif != nil {// If error type is flagCompError and we don't want flagCompletion we should ignore the errorif , := .(*flagCompError); !( && !) {return , []string{}, ShellCompDirectiveDefault, } }// Look for the --help or --version flags. If they are present, // there should be no further completions.ifhelpOrVersionFlagPresent() {return , []string{}, ShellCompDirectiveNoFileComp, nil }// We only remove the flags from the arguments if DisableFlagParsing is not set. // This is important for commands which have requested to do their own flag completion.if !.DisableFlagParsing { = .Flags().Args() }if != nil && {// Check if we are completing a flag value subject to annotationsif , := .Annotations[BashCompFilenameExt]; {iflen() != 0 {// File completion filtered by extensionsreturn , , ShellCompDirectiveFilterFileExt, nil }// The annotation requests simple file completion. There is no reason to do // that since it is the default behavior anyway. Let's ignore this annotation // in case the program also registered a completion function for this flag. // Even though it is a mistake on the program's side, let's be nice when we can. }if , := .Annotations[BashCompSubdirsInDir]; {iflen() == 1 {// Directory completion from within a directoryreturn , , ShellCompDirectiveFilterDirs, nil }// Directory completionreturn , []string{}, ShellCompDirectiveFilterDirs, nil } }var []stringvarShellCompDirective// Enforce flag groups before doing flag completions .enforceFlagGroupsForCompletion()// Note that we want to perform flagname completion even if finalCmd.DisableFlagParsing==true; // doing this allows for completion of persistent flag names even for commands that disable flag parsing. // // When doing completion of a flag name, as soon as an argument starts with // a '-' we know it is a flag. We cannot use isFlagArg() here as it requires // the flag name to be completeif == nil && len() > 0 && [0] == '-' && !strings.Contains(, "=") && {// First check for required flags = completeRequireFlags(, )// If we have not found any required flags, only then can we show regular flagsiflen() == 0 { := func( *pflag.Flag) {if !.Changed ||strings.Contains(.Value.Type(), "Slice") ||strings.Contains(.Value.Type(), "Array") {// If the flag is not already present, or if it can be specified multiple times (Array or Slice) // we suggest it as a completion = append(, getFlagNameCompletions(, )...) } }// We cannot use finalCmd.Flags() because we may not have called ParsedFlags() for commands // that have set DisableFlagParsing; it is ParseFlags() that merges the inherited and // non-inherited flags. .InheritedFlags().VisitAll(func( *pflag.Flag) { () })// Try to complete non-inherited flags even if DisableFlagParsing==true. // This allows programs to tell Cobra about flags for completion even // if the actual parsing of flags is not done by Cobra. // For instance, Helm uses this to provide flag name completion for // some of its plugins. .NonInheritedFlags().VisitAll(func( *pflag.Flag) { () }) } = ShellCompDirectiveNoFileCompiflen() == 1 && strings.HasSuffix([0], "=") {// If there is a single completion, the shell usually adds a space // after the completion. We don't want that if the flag ends with an = = ShellCompDirectiveNoSpace }if !.DisableFlagParsing {// If DisableFlagParsing==false, we have completed the flags as known by Cobra; // we can return what we found. // If DisableFlagParsing==true, Cobra may not be aware of all flags, so we // let the logic continue to see if ValidArgsFunction needs to be called.return , , , nil } } else { = ShellCompDirectiveDefaultif == nil { := false// If TraverseChildren is true on the root command we don't check for // local flags because we can use a local flag on a parent commandif !.Root().TraverseChildren {// Check if there are any local, non-persistent flags on the command-line := .LocalNonPersistentFlags() .NonInheritedFlags().VisitAll(func( *pflag.Flag) {if .Lookup(.Name) != nil && .Changed { = true } }) }// Complete subcommand names, including the help commandiflen() == 0 && ! {// We only complete sub-commands if: // - there are no arguments on the command-line and // - there are no local, non-persistent flags on the command-line or TraverseChildren is truefor , := range .Commands() {if .IsAvailableCommand() || == .helpCommand {ifstrings.HasPrefix(.Name(), ) { = append(, fmt.Sprintf("%s\t%s", .Name(), .Short)) } = ShellCompDirectiveNoFileComp } } }// Complete required flags even without the '-' prefix = append(, completeRequireFlags(, )...)// Always complete ValidArgs, even if we are completing a subcommand name. // This is for commands that have both subcommands and ValidArgs.iflen(.ValidArgs) > 0 {iflen() == 0 {// ValidArgs are only for the first argumentfor , := range .ValidArgs {ifstrings.HasPrefix(, ) { = append(, ) } } = ShellCompDirectiveNoFileComp// If no completions were found within commands or ValidArgs, // see if there are any ArgAliases that should be completed.iflen() == 0 {for , := range .ArgAliases {ifstrings.HasPrefix(, ) { = append(, ) } } } }// If there are ValidArgs specified (even if they don't match), we stop completion. // Only one of ValidArgs or ValidArgsFunction can be used for a single command.return , , , nil }// Let the logic continue so as to add any ValidArgsFunction completions, // even if we already found sub-commands. // This is for commands that have subcommands but also specify a ValidArgsFunction. } }// Find the completion function for the flag or commandvarfunc( *Command, []string, string) ([]string, ShellCompDirective)if != nil && {flagCompletionMutex.RLock() = flagCompletionFunctions[]flagCompletionMutex.RUnlock() } else { = .ValidArgsFunction }if != nil {// Go custom completion defined for this flag or command. // Call the registered completion function to get the completions.var []string , = (, , ) = append(, ...) }return , , , nil}func helpOrVersionFlagPresent( *Command) bool {if := .Flags().Lookup("version"); != nil &&len(.Annotations[FlagSetByCobraAnnotation]) > 0 && .Changed {returntrue }if := .Flags().Lookup("help"); != nil &&len(.Annotations[FlagSetByCobraAnnotation]) > 0 && .Changed {returntrue }returnfalse}func getFlagNameCompletions( *pflag.Flag, string) []string {ifnonCompletableFlag() {return []string{} }var []string := "--" + .Nameifstrings.HasPrefix(, ) {// Flag without the = = append(, fmt.Sprintf("%s\t%s", , .Usage))// Why suggest both long forms: --flag and --flag= ? // This forces the user to *always* have to type either an = or a space after the flag name. // Let's be nice and avoid making users have to do that. // Since boolean flags and shortname flags don't show the = form, let's go that route and never show it. // The = form will still work, we just won't suggest it. // This also makes the list of suggested flags shorter as we avoid all the = forms. // // if len(flag.NoOptDefVal) == 0 { // // Flag requires a value, so it can be suffixed with = // flagName += "=" // completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage)) // } } = "-" + .Shorthandiflen(.Shorthand) > 0 && strings.HasPrefix(, ) { = append(, fmt.Sprintf("%s\t%s", , .Usage)) }return}func completeRequireFlags( *Command, string) []string {var []string := func( *pflag.Flag) {if , := .Annotations[BashCompOneRequiredFlag]; {if !.Changed {// If the flag is not already present, we suggest it as a completion = append(, getFlagNameCompletions(, )...) } } }// We cannot use finalCmd.Flags() because we may not have called ParsedFlags() for commands // that have set DisableFlagParsing; it is ParseFlags() that merges the inherited and // non-inherited flags. .InheritedFlags().VisitAll(func( *pflag.Flag) { () }) .NonInheritedFlags().VisitAll(func( *pflag.Flag) { () })return}func checkIfFlagCompletion( *Command, []string, string) (*pflag.Flag, []string, string, error) {if .DisableFlagParsing {// We only do flag completion if we are allowed to parse flags // This is important for commands which have requested to do their own flag completion.returnnil, , , nil }varstring := := false := // When doing completion of a flag name, as soon as an argument starts with // a '-' we know it is a flag. We cannot use isFlagArg() here as that function // requires the flag name to be completeiflen() > 0 && [0] == '-' {if := strings.Index(, "="); >= 0 {// Flag with an =ifstrings.HasPrefix([:], "--") {// Flag has full name = [2:] } else {// Flag is shorthand // We have to get the last shorthand flag name // e.g. `-asd` => d to provide the correct completion // https://github.com/spf13/cobra/issues/1257 = [-1 : ] } = [+1:] = true } else {// Normal flag completionreturnnil, , , nil } }iflen() == 0 {iflen() > 0 { := [len()-1]ifisFlagArg() {// Only consider the case where the flag does not contain an =. // If the flag contains an = it means it has already been fully processed, // so we don't need to deal with it here.if := strings.Index(, "="); < 0 {ifstrings.HasPrefix(, "--") {// Flag has full name = [2:] } else {// Flag is shorthand // We have to get the last shorthand flag name // e.g. `-asd` => d to provide the correct completion // https://github.com/spf13/cobra/issues/1257 = [len()-1:] }// Remove the uncompleted flag or else there could be an error created // for an invalid value for that flag = [:len()-1] } } } }iflen() == 0 {// Not doing flag completionreturnnil, , , nil } := findFlag(, )if == nil {// Flag not supported by this command, the interspersed option might be set so return the original argsreturnnil, , , &flagCompError{subCommand: .Name(), flagName: } }if ! {iflen(.NoOptDefVal) != 0 {// We had assumed dealing with a two-word flag but the flag is a boolean flag. // In that case, there is no value following it, so we are not really doing flag completion. // Reset everything to do noun completion. = = nil } }return , , , nil}// InitDefaultCompletionCmd adds a default 'completion' command to c.// This function will do nothing if any of the following is true:// 1- the feature has been explicitly disabled by the program,// 2- c has no subcommands (to avoid creating one),// 3- c already has a 'completion' command provided by the program.func ( *Command) () {if .CompletionOptions.DisableDefaultCmd || !.HasSubCommands() {return }for , := range .commands {if .Name() == compCmdName || .HasAlias(compCmdName) {// A completion command is already availablereturn } } := !.CompletionOptions.DisableNoDescFlag && !.CompletionOptions.DisableDescriptions := &Command{Use: compCmdName,Short: "Generate the autocompletion script for the specified shell",Long: fmt.Sprintf(`Generate the autocompletion script for %[1]s for the specified shell.See each sub-command's help for details on how to use the generated script.`, .Root().Name()),Args: NoArgs,ValidArgsFunction: NoFileCompletions,Hidden: .CompletionOptions.HiddenDefaultCmd,GroupID: .completionCommandGroupID, } .AddCommand() := .OutOrStdout() := .CompletionOptions.DisableDescriptions := "Generate the autocompletion script for %s" := &Command{Use: "bash",Short: fmt.Sprintf(, "bash"),Long: fmt.Sprintf(`Generate the autocompletion script for the bash shell.This script depends on the 'bash-completion' package.If it is not installed already, you can install it via your OS's package manager.To load completions in your current shell session: source <(%[1]s completion bash)To load completions for every new session, execute once:#### Linux: %[1]s completion bash > /etc/bash_completion.d/%[1]s#### macOS: %[1]s completion bash > $(brew --prefix)/etc/bash_completion.d/%[1]sYou will need to start a new shell for this setup to take effect.`, .Root().Name()),Args: NoArgs,DisableFlagsInUseLine: true,ValidArgsFunction: NoFileCompletions,RunE: func( *Command, []string) error {return .Root().GenBashCompletionV2(, !) }, }if { .Flags().BoolVar(&, compCmdNoDescFlagName, compCmdNoDescFlagDefault, compCmdNoDescFlagDesc) } := &Command{Use: "zsh",Short: fmt.Sprintf(, "zsh"),Long: fmt.Sprintf(`Generate the autocompletion script for the zsh shell.If shell completion is not already enabled in your environment you will needto enable it. You can execute the following once: echo "autoload -U compinit; compinit" >> ~/.zshrcTo load completions in your current shell session: source <(%[1]s completion zsh)To load completions for every new session, execute once:#### Linux: %[1]s completion zsh > "${fpath[1]}/_%[1]s"#### macOS: %[1]s completion zsh > $(brew --prefix)/share/zsh/site-functions/_%[1]sYou will need to start a new shell for this setup to take effect.`, .Root().Name()),Args: NoArgs,ValidArgsFunction: NoFileCompletions,RunE: func( *Command, []string) error {if {return .Root().GenZshCompletionNoDesc() }return .Root().GenZshCompletion() }, }if { .Flags().BoolVar(&, compCmdNoDescFlagName, compCmdNoDescFlagDefault, compCmdNoDescFlagDesc) } := &Command{Use: "fish",Short: fmt.Sprintf(, "fish"),Long: fmt.Sprintf(`Generate the autocompletion script for the fish shell.To load completions in your current shell session: %[1]s completion fish | sourceTo load completions for every new session, execute once: %[1]s completion fish > ~/.config/fish/completions/%[1]s.fishYou will need to start a new shell for this setup to take effect.`, .Root().Name()),Args: NoArgs,ValidArgsFunction: NoFileCompletions,RunE: func( *Command, []string) error {return .Root().GenFishCompletion(, !) }, }if { .Flags().BoolVar(&, compCmdNoDescFlagName, compCmdNoDescFlagDefault, compCmdNoDescFlagDesc) } := &Command{Use: "powershell",Short: fmt.Sprintf(, "powershell"),Long: fmt.Sprintf(`Generate the autocompletion script for powershell.To load completions in your current shell session: %[1]s completion powershell | Out-String | Invoke-ExpressionTo load completions for every new session, add the output of the above commandto your powershell profile.`, .Root().Name()),Args: NoArgs,ValidArgsFunction: NoFileCompletions,RunE: func( *Command, []string) error {if {return .Root().GenPowerShellCompletion() }return .Root().GenPowerShellCompletionWithDesc() }, }if { .Flags().BoolVar(&, compCmdNoDescFlagName, compCmdNoDescFlagDefault, compCmdNoDescFlagDesc) } .AddCommand(, , , )}func findFlag( *Command, string) *pflag.Flag { := .Flags()iflen() == 1 {// First convert the short flag into a long flag // as the cmd.Flag() search only accepts long flagsif := .ShorthandLookup(); != nil { = .Name } else { := .InheritedFlags()if = .ShorthandLookup(); != nil { = .Name } else {returnnil } } }return .Flag()}// CompDebug prints the specified string to the same file as where the// completion script prints its logs.// Note that completion printouts should never be on stdout as they would// be wrongly interpreted as actual completion choices by the completion script.func ( string, bool) { = fmt.Sprintf("[Debug] %s", )// Such logs are only printed when the user has set the environment // variable BASH_COMP_DEBUG_FILE to the path of some file to be used.if := os.Getenv("BASH_COMP_DEBUG_FILE"); != "" { , := os.OpenFile(,os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)if == nil {defer .Close()WriteStringAndCheck(, ) } }if {// Must print to stderr for this not to be read by the completion script.fmt.Fprint(os.Stderr, ) }}// CompDebugln prints the specified string with a newline at the end// to the same file as where the completion script prints its logs.// Such logs are only printed when the user has set the environment// variable BASH_COMP_DEBUG_FILE to the path of some file to be used.func ( string, bool) {CompDebug(fmt.Sprintf("%s\n", ), )}// CompError prints the specified completion message to stderr.func ( string) { = fmt.Sprintf("[Error] %s", )CompDebug(, true)}// CompErrorln prints the specified completion message to stderr with a newline at the end.func ( string) {CompError(fmt.Sprintf("%s\n", ))}// These values should not be changed: users will be using them explicitly.const ( configEnvVarGlobalPrefix = "COBRA" configEnvVarSuffixDescriptions = "COMPLETION_DESCRIPTIONS")var configEnvVarPrefixSubstRegexp = regexp.MustCompile(`[^A-Z0-9_]`)// configEnvVar returns the name of the program-specific configuration environment// variable. It has the format <PROGRAM>_<SUFFIX> where <PROGRAM> is the name of the// root command in upper case, with all non-ASCII-alphanumeric characters replaced by `_`.func configEnvVar(, string) string {// This format should not be changed: users will be using it explicitly. := strings.ToUpper(fmt.Sprintf("%s_%s", , )) = configEnvVarPrefixSubstRegexp.ReplaceAllString(, "_")return}// getEnvConfig returns the value of the configuration environment variable// <PROGRAM>_<SUFFIX> where <PROGRAM> is the name of the root command in upper// case, with all non-ASCII-alphanumeric characters replaced by `_`.// If the value is empty or not set, the value of the environment variable// COBRA_<SUFFIX> is returned instead.func getEnvConfig( *Command, string) string { := os.Getenv(configEnvVar(.Root().Name(), ))if == "" { = os.Getenv(configEnvVar(configEnvVarGlobalPrefix, )) }return}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.