(args []string)
| 314 | } |
| 315 | |
| 316 | func (c *Command) getCompletions(args []string) (*Command, []Completion, ShellCompDirective, error) { |
| 317 | // The last argument, which is not completely typed by the user, |
| 318 | // should not be part of the list of arguments |
| 319 | toComplete := args[len(args)-1] |
| 320 | trimmedArgs := args[:len(args)-1] |
| 321 | |
| 322 | var finalCmd *Command |
| 323 | var finalArgs []string |
| 324 | var err error |
| 325 | // Find the real command for which completion must be performed |
| 326 | // check if we need to traverse here to parse local flags on parent commands |
| 327 | if c.Root().TraverseChildren { |
| 328 | finalCmd, finalArgs, err = c.Root().Traverse(trimmedArgs) |
| 329 | } else { |
| 330 | // For Root commands that don't specify any value for their Args fields, when we call |
| 331 | // Find(), if those Root commands don't have any sub-commands, they will accept arguments. |
| 332 | // However, because we have added the __complete sub-command in the current code path, the |
| 333 | // call to Find() -> legacyArgs() will return an error if there are any arguments. |
| 334 | // To avoid this, we first remove the __complete command to get back to having no sub-commands. |
| 335 | rootCmd := c.Root() |
| 336 | if len(rootCmd.Commands()) == 1 { |
| 337 | rootCmd.RemoveCommand(c) |
| 338 | } |
| 339 | |
| 340 | finalCmd, finalArgs, err = rootCmd.Find(trimmedArgs) |
| 341 | } |
| 342 | if err != nil { |
| 343 | // Unable to find the real command. E.g., <program> someInvalidCmd <TAB> |
| 344 | return c, []Completion{}, ShellCompDirectiveDefault, fmt.Errorf("unable to find a command for arguments: %v", trimmedArgs) |
| 345 | } |
| 346 | finalCmd.ctx = c.ctx |
| 347 | |
| 348 | // These flags are normally added when `execute()` is called on `finalCmd`, |
| 349 | // however, when doing completion, we don't call `finalCmd.execute()`. |
| 350 | // Let's add the --help and --version flag ourselves but only if the finalCmd |
| 351 | // has not disabled flag parsing; if flag parsing is disabled, it is up to the |
| 352 | // finalCmd itself to handle the completion of *all* flags. |
| 353 | if !finalCmd.DisableFlagParsing { |
| 354 | finalCmd.InitDefaultHelpFlag() |
| 355 | finalCmd.InitDefaultVersionFlag() |
| 356 | } |
| 357 | |
| 358 | // Check if we are doing flag value completion before parsing the flags. |
| 359 | // This is important because if we are completing a flag value, we need to also |
| 360 | // remove the flag name argument from the list of finalArgs or else the parsing |
| 361 | // could fail due to an invalid value (incomplete) for the flag. |
| 362 | flag, finalArgs, toComplete, flagErr := checkIfFlagCompletion(finalCmd, finalArgs, toComplete) |
| 363 | |
| 364 | // Check if interspersed is false or -- was set on a previous arg. |
| 365 | // This works by counting the arguments. Normally -- is not counted as arg but |
| 366 | // if -- was already set or interspersed is false and there is already one arg then |
| 367 | // the extra added -- is counted as arg. |
| 368 | flagCompletion := true |
| 369 | _ = finalCmd.ParseFlags(append(finalArgs, "--")) |
| 370 | newArgCount := finalCmd.Flags().NArg() |
| 371 | |
| 372 | // Parse the flags early so we can check if required flags are set |
| 373 | if err = finalCmd.ParseFlags(finalArgs); err != nil { |
no test coverage detected