// License: GPLv3 Copyright: 2022, Kovid Goyal, package cli import ( "fmt" "os" "strings" ) var _ = fmt.Print var _ = os.Getenv func (self *Completions) add_group(group *MatchGroup) { if len(group.Matches) > 0 { self.Groups = append(self.Groups, group) } } func (self *Completions) add_options_group(options []*Option, word string) { group := self.AddMatchGroup("Options") if strings.HasPrefix(word, "--") { if word == "--" { group.Matches = append(group.Matches, &Match{Word: "--", Description: "End of options"}) } for _, opt := range options { for _, q := range opt.Aliases { if strings.HasPrefix(q.String(), word) { group.Matches = append(group.Matches, &Match{Word: q.String(), Description: opt.Help}) break } } } } else { if word == "-" { group.Matches = append(group.Matches, &Match{Word: "--", Description: "End of options"}) for _, opt := range options { has_single_letter_alias := false for _, q := range opt.Aliases { if q.IsShort { group.AddMatch("-"+q.NameWithoutHyphens, opt.Help) has_single_letter_alias = true break } } if !has_single_letter_alias { for _, q := range opt.Aliases { if !q.IsShort { group.AddMatch(q.String(), opt.Help) break } } } } } else { runes := []rune(word) last_letter := string(runes[len(runes)-1]) for _, opt := range options { for _, q := range opt.Aliases { if q.IsShort && q.NameWithoutHyphens == last_letter { group.AddMatch(word, opt.Help) return } } } } } } func (self *Command) sub_command_allowed_at(completions *Completions, arg_num int) bool { if self.SubCommandMustBeFirst { return arg_num == 1 && completions.CurrentWordIdxInParent == 1 } return arg_num == 1 } func complete_word(word string, completions *Completions, only_args_allowed bool, expecting_arg_for *Option, arg_num int) { cmd := completions.CurrentCmd if expecting_arg_for != nil { if expecting_arg_for.Completer != nil { expecting_arg_for.Completer(completions, word, arg_num) } return } if !only_args_allowed && strings.HasPrefix(word, "-") { if strings.HasPrefix(word, "--") && strings.Contains(word, "=") { idx := strings.Index(word, "=") option := cmd.FindOption(word[:idx]) if option != nil { if option.Completer != nil { option.Completer(completions, word[idx+1:], arg_num) completions.AddPrefixToAllMatches(word[:idx+1]) } } } else { completions.add_options_group(cmd.AllOptions(), word) } return } if cmd.HasVisibleSubCommands() && cmd.sub_command_allowed_at(completions, arg_num) { for _, cg := range cmd.SubCommandGroups { group := completions.AddMatchGroup(cg.Title) if group.Title == "" { group.Title = "Sub-commands" } for _, sc := range cg.SubCommands { if strings.HasPrefix(sc.Name, word) { t := sc.ShortDescription if t == "" { t = sc.HelpText } group.AddMatch(sc.Name, t) } } } if cmd.SubCommandIsOptional && cmd.ArgCompleter != nil { cmd.ArgCompleter(completions, word, arg_num) } return } if cmd.ArgCompleter != nil { cmd.ArgCompleter(completions, word, arg_num) } return } func completion_parse_args(cmd *Command, words []string, completions *Completions) { completions.CurrentCmd = cmd if len(words) == 0 { complete_word("", completions, false, nil, 0) return } completions.AllWords = words var expecting_arg_for *Option only_args_allowed := false arg_num := 0 for i, word := range words { cmd = completions.CurrentCmd completions.CurrentWordIdx = i completions.CurrentWordIdxInParent++ is_last_word := i == len(words)-1 is_option_equal := completions.split_on_equals && word == "=" && expecting_arg_for != nil if only_args_allowed || (expecting_arg_for == nil && !strings.HasPrefix(word, "-")) { if !is_option_equal { arg_num++ } if arg_num == 1 { cmd.IndexOfFirstArg = completions.CurrentWordIdx } } if is_last_word { if is_option_equal { word = "" } complete_word(word, completions, only_args_allowed, expecting_arg_for, arg_num) } else { if expecting_arg_for != nil { if is_option_equal { continue } expecting_arg_for = nil continue } if word == "--" { only_args_allowed = true continue } if !only_args_allowed && strings.HasPrefix(word, "-") { if !strings.Contains(word, "=") { option := cmd.FindOption(word) if option != nil && option.needs_argument() { expecting_arg_for = option } } continue } if cmd.HasVisibleSubCommands() && cmd.sub_command_allowed_at(completions, arg_num) { sc := cmd.FindSubCommand(word) if sc == nil { only_args_allowed = true continue } completions.CurrentCmd = sc cmd = sc arg_num = 0 completions.CurrentWordIdxInParent = 0 only_args_allowed = false if cmd.ParseArgsForCompletion != nil { cmd.ParseArgsForCompletion(cmd, words[i+1:], completions) return } } else if cmd.StopCompletingAtArg > 0 && arg_num >= cmd.StopCompletingAtArg { return } else { only_args_allowed = true continue } } } }