From 30851656591293ed2e19340ab78c937855a11143 Mon Sep 17 00:00:00 2001 From: Robin Jarry Date: Tue, 17 Oct 2023 00:14:49 +0200 Subject: commands: remove command set completion api Do not expose the completion of a command via its command set. Instead, require a single command object to be resolved in order to execute it. Extract the command names and the template terms completions in main.go. Signed-off-by: Robin Jarry Reviewed-by: Koni Marti Tested-by: Moritz Poldrack Tested-by: Inwit --- commands/commands.go | 62 +++++++++++----------------------------------------- commands/prompt.go | 2 +- main.go | 39 +++++++++++++++++++++++---------- 3 files changed, 42 insertions(+), 61 deletions(-) diff --git a/commands/commands.go b/commands/commands.go index c2137a58..d76194af 100644 --- a/commands/commands.go +++ b/commands/commands.go @@ -4,7 +4,6 @@ import ( "bytes" "errors" "reflect" - "sort" "strings" "unicode" @@ -153,11 +152,6 @@ func ExpandTemplates( func GetTemplateCompletion( cmd string, ) ([]string, string, bool) { - args, err := splitCmd(cmd) - if err != nil || len(args) == 0 { - return nil, "", false - } - countLeft := strings.Count(cmd, "{{") if countLeft == 0 { return nil, "", false @@ -197,48 +191,16 @@ func GetTemplateCompletion( } // GetCompletions returns the completion options and the command prefix -func (cmds *Commands) GetCompletions( - cmd string, +func GetCompletions( + cmd Command, args *opt.Args, ) (options []string, prefix string) { - log.Tracef("completing command: %s", cmd) - - // start completion - args, err := splitCmd(cmd) - if err != nil { - return - } - - // nothing entered, list all commands - if len(args) == 0 { - options = cmds.Names() - sort.Strings(options) - return - } - - // complete command name - spaceTerminated := cmd[len(cmd)-1] == ' ' - if len(args) == 1 && !spaceTerminated { - for _, n := range cmds.Names() { - options = append(options, n+" ") - } - options = CompletionFromList(options, args) - - return - } - - // look for command in dictionary - c, ok := cmds.dict()[args[0]] - if !ok { - return - } - // complete options var spec string - if provider, ok := c.(OptionsProvider); ok { + if provider, ok := cmd.(OptionsProvider); ok { spec = provider.Options() } - parser, err := newParser(cmd, spec, spaceTerminated) + parser, err := newParser(args.String(), spec, strings.HasSuffix(args.String(), " ")) if err != nil { log.Debugf("completion parser failed: %v", err) return @@ -256,15 +218,15 @@ func (cmds *Commands) GetCompletions( } options = append(options, option) } - prefix = cmd + prefix = args.String() case OPTION_ARGUMENT: - cmpl, ok := c.(OptionCompleter) + cmpl, ok := cmd.(OptionCompleter) if !ok { return } - stem := cmd + stem := args.String() if parser.arg != "" { - stem = strings.TrimSuffix(cmd, parser.arg) + stem = strings.TrimSuffix(stem, parser.arg) } pad := "" if !strings.HasSuffix(stem, " ") { @@ -277,14 +239,16 @@ func (cmds *Commands) GetCompletions( } prefix = stem case OPERAND: - stem := strings.Join(args[:parser.optind], " ") - for _, option := range c.Complete(args[1:]) { + clone := args.Clone() + clone.Cut(clone.Count() - parser.optind) + args.Shift(1) + for _, option := range cmd.Complete(args.Args()) { if strings.Contains(option, " ") { option = escape(option) } options = append(options, " "+option) } - prefix = stem + prefix = clone.String() } return diff --git a/commands/prompt.go b/commands/prompt.go index d42a6597..dd259c30 100644 --- a/commands/prompt.go +++ b/commands/prompt.go @@ -40,7 +40,7 @@ func (Prompt) Complete(args []string) []string { if hascommand { return nil } - cs, _ = GlobalCommands.GetCompletions(args[1]) + cs = GlobalCommands.Names() } if cs == nil { return nil diff --git a/main.go b/main.go index 43e980e9..dc7d0267 100644 --- a/main.go +++ b/main.go @@ -125,21 +125,38 @@ func execCommand( return err } -func getCompletions(cmd string) ([]string, string) { - if options, prefix, ok := commands.GetTemplateCompletion(cmd); ok { +func getCompletions(cmdline string) ([]string, string) { + cmdline = strings.TrimLeft(cmdline, ":") + + // complete template terms + if options, prefix, ok := commands.GetTemplateCompletion(cmdline); ok { + sort.Strings(options) return options, prefix } - var completions []string - var prefix string - for _, set := range getCommands(app.SelectedTabContent()) { - options, s := set.GetCompletions(cmd) - if s != "" { - prefix = s + + args := opt.LexArgs(cmdline) + cmds := getCommands(app.SelectedTabContent()) + + if args.Count() < 2 && args.TrailingSpace() == "" { + // complete command names + var completions []string + for _, set := range cmds { + for _, n := range set.Names() { + if strings.HasPrefix(n, cmdline) { + completions = append(completions, n) + } + } } - completions = append(completions, options...) + sort.Strings(completions) + return completions, "" + } + + // complete command arguments + _, cmd := expandAbbreviations(args.Arg(0), cmds) + if cmd == nil { + return nil, cmdline } - sort.Strings(completions) - return completions, prefix + return commands.GetCompletions(cmd, args) } // set at build time -- cgit v1.2.3-54-g00ecf