diff options
-rw-r--r-- | commands/commands.go | 52 | ||||
-rw-r--r-- | lib/templates/template.go | 52 | ||||
-rw-r--r-- | main.go | 3 |
3 files changed, 107 insertions, 0 deletions
diff --git a/commands/commands.go b/commands/commands.go index f50a1e8a..c6f95aaa 100644 --- a/commands/commands.go +++ b/commands/commands.go @@ -141,6 +141,58 @@ func (cmds *Commands) ExecuteCommand( return NoSuchCommand(args[0]) } +func GetTemplateCompletion( + aerc *widgets.Aerc, 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 + } + countRight := strings.Count(cmd, "}}") + + switch { + case countLeft > countRight: + // complete template terms + var i int + for i = len(cmd) - 1; i >= 0; i-- { + if strings.ContainsRune("{()| ", rune(cmd[i])) { + break + } + } + search, prefix := cmd[i+1:], cmd[:i+1] + padding := strings.Repeat(" ", + len(search)-len(strings.TrimLeft(search, " "))) + options := FilterList( + templates.Terms(), + strings.TrimSpace(search), + "", + aerc.SelectedAccountUiConfig().FuzzyComplete, + ) + return options, prefix + padding, true + case countLeft == countRight: + // expand template + data := templateData(aerc, nil, nil) + t, err := templates.ParseTemplate("", cmd) + if err != nil { + log.Warnf("template parsing failed: %v", err) + return nil, "", false + } + var sb strings.Builder + if err = templates.Render(t, &sb, data); err != nil { + log.Warnf("template rendering failed: %v", err) + return nil, "", false + } + return []string{sb.String()}, "", true + } + + return nil, "", false +} + // GetCompletions returns the completion options and the command prefix func (cmds *Commands) GetCompletions( aerc *widgets.Aerc, cmd string, diff --git a/lib/templates/template.go b/lib/templates/template.go index bf257669..6eae591a 100644 --- a/lib/templates/template.go +++ b/lib/templates/template.go @@ -6,6 +6,7 @@ import ( "io" "os" "path" + "reflect" "text/template" "git.sr.ht/~rjarry/aerc/models" @@ -56,3 +57,54 @@ func ParseTemplate(name, content string) (*template.Template, error) { func Render(t *template.Template, w io.Writer, data models.TemplateData) error { return t.Execute(w, data) } + +// builtins is a slice of keywords and functions built into the Go standard +// library for templates. Since they are not exported, they are hardcoded here. +var builtins = []string{ + // from the Go standard library: src/text/template/parse/lex.go + "block", + "break", + "continue", + "define", + "else", + "end", + "if", + "range", + "nil", + "template", + "with", + + // from the Go standard library: src/text/template/funcs.go + "and", + "call", + "html", + "index", + "slice", + "js", + "len", + "not", + "or", + "print", + "printf", + "println", + "urlquery", + "eq", + "ge", + "gt", + "le", + "lt", + "ne", +} + +func Terms() []string { + var s []string + t := reflect.TypeOf((*models.TemplateData)(nil)).Elem() + for i := 0; i < t.NumMethod(); i++ { + s = append(s, "."+t.Method(i).Name) + } + for fnStr := range templateFuncs { + s = append(s, fnStr) + } + s = append(s, builtins...) + return s +} @@ -89,6 +89,9 @@ func execCommand( } func getCompletions(aerc *widgets.Aerc, cmd string) ([]string, string) { + if options, prefix, ok := commands.GetTemplateCompletion(aerc, cmd); ok { + return options, prefix + } var completions []string var prefix string for _, set := range getCommands(aerc.SelectedTabContent()) { |