|
1 // Copyright 2013-2022 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 |
1 package cobra |
15 package cobra |
2 |
16 |
3 import ( |
17 import ( |
4 "fmt" |
18 "fmt" |
5 "os" |
19 "os" |
258 // Unable to find the real command. E.g., <program> someInvalidCmd <TAB> |
272 // Unable to find the real command. E.g., <program> someInvalidCmd <TAB> |
259 return c, []string{}, ShellCompDirectiveDefault, fmt.Errorf("Unable to find a command for arguments: %v", trimmedArgs) |
273 return c, []string{}, ShellCompDirectiveDefault, fmt.Errorf("Unable to find a command for arguments: %v", trimmedArgs) |
260 } |
274 } |
261 finalCmd.ctx = c.ctx |
275 finalCmd.ctx = c.ctx |
262 |
276 |
|
277 // These flags are normally added when `execute()` is called on `finalCmd`, |
|
278 // however, when doing completion, we don't call `finalCmd.execute()`. |
|
279 // Let's add the --help and --version flag ourselves. |
|
280 finalCmd.InitDefaultHelpFlag() |
|
281 finalCmd.InitDefaultVersionFlag() |
|
282 |
263 // Check if we are doing flag value completion before parsing the flags. |
283 // Check if we are doing flag value completion before parsing the flags. |
264 // This is important because if we are completing a flag value, we need to also |
284 // This is important because if we are completing a flag value, we need to also |
265 // remove the flag name argument from the list of finalArgs or else the parsing |
285 // remove the flag name argument from the list of finalArgs or else the parsing |
266 // could fail due to an invalid value (incomplete) for the flag. |
286 // could fail due to an invalid value (incomplete) for the flag. |
267 flag, finalArgs, toComplete, flagErr := checkIfFlagCompletion(finalCmd, finalArgs, toComplete) |
287 flag, finalArgs, toComplete, flagErr := checkIfFlagCompletion(finalCmd, finalArgs, toComplete) |
288 if flagErr != nil { |
308 if flagErr != nil { |
289 // If error type is flagCompError and we don't want flagCompletion we should ignore the error |
309 // If error type is flagCompError and we don't want flagCompletion we should ignore the error |
290 if _, ok := flagErr.(*flagCompError); !(ok && !flagCompletion) { |
310 if _, ok := flagErr.(*flagCompError); !(ok && !flagCompletion) { |
291 return finalCmd, []string{}, ShellCompDirectiveDefault, flagErr |
311 return finalCmd, []string{}, ShellCompDirectiveDefault, flagErr |
292 } |
312 } |
|
313 } |
|
314 |
|
315 // Look for the --help or --version flags. If they are present, |
|
316 // there should be no further completions. |
|
317 if helpOrVersionFlagPresent(finalCmd) { |
|
318 return finalCmd, []string{}, ShellCompDirectiveNoFileComp, nil |
293 } |
319 } |
294 |
320 |
295 // We only remove the flags from the arguments if DisableFlagParsing is not set. |
321 // We only remove the flags from the arguments if DisableFlagParsing is not set. |
296 // This is important for commands which have requested to do their own flag completion. |
322 // This is important for commands which have requested to do their own flag completion. |
297 if !finalCmd.DisableFlagParsing { |
323 if !finalCmd.DisableFlagParsing { |
459 comps, directive = completionFn(finalCmd, finalArgs, toComplete) |
485 comps, directive = completionFn(finalCmd, finalArgs, toComplete) |
460 completions = append(completions, comps...) |
486 completions = append(completions, comps...) |
461 } |
487 } |
462 |
488 |
463 return finalCmd, completions, directive, nil |
489 return finalCmd, completions, directive, nil |
|
490 } |
|
491 |
|
492 func helpOrVersionFlagPresent(cmd *Command) bool { |
|
493 if versionFlag := cmd.Flags().Lookup("version"); versionFlag != nil && |
|
494 len(versionFlag.Annotations[FlagSetByCobraAnnotation]) > 0 && versionFlag.Changed { |
|
495 return true |
|
496 } |
|
497 if helpFlag := cmd.Flags().Lookup("help"); helpFlag != nil && |
|
498 len(helpFlag.Annotations[FlagSetByCobraAnnotation]) > 0 && helpFlag.Changed { |
|
499 return true |
|
500 } |
|
501 return false |
464 } |
502 } |
465 |
503 |
466 func getFlagNameCompletions(flag *pflag.Flag, toComplete string) []string { |
504 func getFlagNameCompletions(flag *pflag.Flag, toComplete string) []string { |
467 if nonCompletableFlag(flag) { |
505 if nonCompletableFlag(flag) { |
468 return []string{} |
506 return []string{} |
605 } |
643 } |
606 |
644 |
607 return flag, trimmedArgs, lastArg, nil |
645 return flag, trimmedArgs, lastArg, nil |
608 } |
646 } |
609 |
647 |
610 // initDefaultCompletionCmd adds a default 'completion' command to c. |
648 // InitDefaultCompletionCmd adds a default 'completion' command to c. |
611 // This function will do nothing if any of the following is true: |
649 // This function will do nothing if any of the following is true: |
612 // 1- the feature has been explicitly disabled by the program, |
650 // 1- the feature has been explicitly disabled by the program, |
613 // 2- c has no subcommands (to avoid creating one), |
651 // 2- c has no subcommands (to avoid creating one), |
614 // 3- c already has a 'completion' command provided by the program. |
652 // 3- c already has a 'completion' command provided by the program. |
615 func (c *Command) initDefaultCompletionCmd() { |
653 func (c *Command) InitDefaultCompletionCmd() { |
616 if c.CompletionOptions.DisableDefaultCmd || !c.HasSubCommands() { |
654 if c.CompletionOptions.DisableDefaultCmd || !c.HasSubCommands() { |
617 return |
655 return |
618 } |
656 } |
619 |
657 |
620 for _, cmd := range c.commands { |
658 for _, cmd := range c.commands { |
633 See each sub-command's help for details on how to use the generated script. |
671 See each sub-command's help for details on how to use the generated script. |
634 `, c.Root().Name()), |
672 `, c.Root().Name()), |
635 Args: NoArgs, |
673 Args: NoArgs, |
636 ValidArgsFunction: NoFileCompletions, |
674 ValidArgsFunction: NoFileCompletions, |
637 Hidden: c.CompletionOptions.HiddenDefaultCmd, |
675 Hidden: c.CompletionOptions.HiddenDefaultCmd, |
|
676 GroupID: c.completionCommandGroupID, |
638 } |
677 } |
639 c.AddCommand(completionCmd) |
678 c.AddCommand(completionCmd) |
640 |
679 |
641 out := c.OutOrStdout() |
680 out := c.OutOrStdout() |
642 noDesc := c.CompletionOptions.DisableDescriptions |
681 noDesc := c.CompletionOptions.DisableDescriptions |