aboutsummaryrefslogtreecommitdiffstats
path: root/commands/commands.go
diff options
context:
space:
mode:
authorRobin Jarry <robin@jarry.cc>2023-10-22 23:23:18 +0200
committerRobin Jarry <robin@jarry.cc>2023-10-28 19:25:10 +0200
commitabe228b14d97d8d47e8ff4406de387fac45cfe68 (patch)
tree56117403d1ae32d7253f86bab01a944a3cf225b9 /commands/commands.go
parent30851656591293ed2e19340ab78c937855a11143 (diff)
downloadaerc-abe228b14d97d8d47e8ff4406de387fac45cfe68.tar.gz
commands: use completion from go-opt
Implement command completion with complete struct field tags from the get-opt library introduced earlier. Changelog-changed: Improved command completion. Signed-off-by: Robin Jarry <robin@jarry.cc> Reviewed-by: Koni Marti <koni.marti@gmail.com> Tested-by: Moritz Poldrack <moritz@poldrack.dev> Tested-by: Inwit <inwit@sindominio.net>
Diffstat (limited to 'commands/commands.go')
-rw-r--r--commands/commands.go164
1 files changed, 42 insertions, 122 deletions
diff --git a/commands/commands.go b/commands/commands.go
index d76194af..9c193018 100644
--- a/commands/commands.go
+++ b/commands/commands.go
@@ -3,12 +3,13 @@ package commands
import (
"bytes"
"errors"
+ "path"
"reflect"
+ "sort"
"strings"
"unicode"
"git.sr.ht/~rjarry/go-opt"
- "github.com/google/shlex"
"git.sr.ht/~rjarry/aerc/app"
"git.sr.ht/~rjarry/aerc/config"
@@ -21,17 +22,6 @@ import (
type Command interface {
Aliases() []string
Execute([]string) error
- Complete([]string) []string
-}
-
-type OptionsProvider interface {
- Command
- Options() string
-}
-
-type OptionCompleter interface {
- OptionsProvider
- CompleteOption(rune, string) []string
}
type Commands map[string]Command
@@ -174,6 +164,7 @@ func GetTemplateCompletion(
templates.Terms(),
strings.TrimSpace(search),
"",
+ "",
app.SelectedAccountUiConfig().FuzzyComplete,
)
return options, prefix + padding, true
@@ -194,117 +185,62 @@ func GetTemplateCompletion(
func GetCompletions(
cmd Command, args *opt.Args,
) (options []string, prefix string) {
- // complete options
- var spec string
- if provider, ok := cmd.(OptionsProvider); ok {
- spec = provider.Options()
- }
-
- parser, err := newParser(args.String(), spec, strings.HasSuffix(args.String(), " "))
- if err != nil {
- log.Debugf("completion parser failed: %v", err)
- return
- }
-
- switch parser.kind {
- case SHORT_OPTION:
- for _, r := range strings.ReplaceAll(spec, ":", "") {
- if strings.ContainsRune(parser.flag, r) {
- continue
- }
- option := string(r)
- if strings.Contains(spec, option+":") {
- option += " "
- }
- options = append(options, option)
- }
- prefix = args.String()
- case OPTION_ARGUMENT:
- cmpl, ok := cmd.(OptionCompleter)
- if !ok {
- return
- }
- stem := args.String()
- if parser.arg != "" {
- stem = strings.TrimSuffix(stem, parser.arg)
- }
- pad := ""
- if !strings.HasSuffix(stem, " ") {
- pad += " "
- }
- s := parser.flag
- r := rune(s[len(s)-1])
- for _, option := range cmpl.CompleteOption(r, parser.arg) {
- options = append(options, pad+escape(option)+" ")
- }
- prefix = stem
- case OPERAND:
- 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 = clone.String()
- }
-
- return
+ // copy zeroed struct
+ tmp := reflect.New(reflect.TypeOf(cmd)).Interface().(Command)
+ spec := opt.NewCmdSpec(args.Arg(0), tmp)
+ return spec.GetCompletions(args)
}
-func GetFolders(args []string) []string {
+func GetFolders(arg string) []string {
acct := app.SelectedAccount()
if acct == nil {
return make([]string, 0)
}
- if len(args) == 0 {
- return acct.Directories().List()
- }
- return FilterList(acct.Directories().List(), args[0], "", acct.UiConfig().FuzzyComplete)
+ return CompletionFromList(acct.Directories().List(), arg)
}
-// CompletionFromList provides a convenience wrapper for commands to use in the
-// Complete function. It simply matches the items provided in valid
-func CompletionFromList(valid []string, args []string) []string {
- if len(args) == 0 {
- return valid
+func GetTemplates(arg string) []string {
+ templates := make(map[string]bool)
+ for _, dir := range config.Templates.TemplateDirs {
+ for _, f := range listDir(dir, false) {
+ if !isDir(path.Join(dir, f)) {
+ templates[f] = true
+ }
+ }
+ }
+ names := make([]string, len(templates))
+ for n := range templates {
+ names = append(names, n)
}
- return FilterList(valid, args[0], "", app.SelectedAccountUiConfig().FuzzyComplete)
+ sort.Strings(names)
+ return CompletionFromList(names, arg)
}
-func GetLabels(args []string) []string {
+// CompletionFromList provides a convenience wrapper for commands to use in a
+// complete callback. It simply matches the items provided in valid
+func CompletionFromList(valid []string, arg string) []string {
+ return FilterList(valid, arg, "", "", app.SelectedAccountUiConfig().FuzzyComplete)
+}
+
+func GetLabels(arg string) []string {
acct := app.SelectedAccount()
if acct == nil {
return make([]string, 0)
}
- if len(args) == 0 {
- return acct.Labels()
- }
-
- // + and - are used to denote tag addition / removal and need to be striped
- // only the last tag should be completed, so that multiple labels can be
- // selected
- last := args[len(args)-1]
- others := strings.Join(args[:len(args)-1], " ")
var prefix string
- switch last[0] {
- case '+':
- prefix = "+"
- case '-':
- prefix = "-"
- default:
- prefix = ""
- }
- trimmed := strings.TrimLeft(last, "+-")
-
- var prev string
- if len(others) > 0 {
- prev = others + " "
+ if arg != "" {
+ // + and - are used to denote tag addition / removal and need to
+ // be striped only the last tag should be completed, so that
+ // multiple labels can be selected
+ switch arg[0] {
+ case '+':
+ prefix = "+"
+ case '-':
+ prefix = "-"
+ }
+ arg = strings.TrimLeft(arg, "+-")
}
- out := FilterList(acct.Labels(), trimmed, prev+prefix, acct.UiConfig().FuzzyComplete)
- return out
+ return FilterList(acct.Labels(), arg, prefix, " ", acct.UiConfig().FuzzyComplete)
}
// hasCaseSmartPrefix checks whether s starts with prefix, using a case
@@ -324,19 +260,3 @@ func hasUpper(s string) bool {
}
return false
}
-
-// splitCmd splits the command into arguments
-func splitCmd(cmd string) ([]string, error) {
- args, err := shlex.Split(cmd)
- if err != nil {
- return nil, err
- }
- return args, nil
-}
-
-func escape(s string) string {
- if strings.Contains(s, " ") {
- return strings.ReplaceAll(s, " ", "\\ ")
- }
- return s
-}