M aerc.go => aerc.go +40 -20
@@ 51,6 51,41 @@ func getCommands(selected libui.Drawable) []*commands.Commands {
}
}
+func execCommand(aerc *widgets.Aerc, ui *libui.UI, cmd string) error {
+ cmds := getCommands((*aerc).SelectedTab())
+ for i, set := range cmds {
+ err := set.ExecuteCommand(aerc, cmd)
+ if _, ok := err.(commands.NoSuchCommand); ok {
+ if i == len(cmds)-1 {
+ return err
+ }
+ continue
+ } else if _, ok := err.(commands.ErrorExit); ok {
+ ui.Exit()
+ return nil
+ } else if err != nil {
+ return err
+ } else {
+ break
+ }
+ }
+ return nil
+}
+
+func getCompletions(aerc *widgets.Aerc, cmd string) []string {
+ cmds := getCommands((*aerc).SelectedTab())
+ completions := make([]string, 0)
+ for _, set := range cmds {
+ opts := set.GetCompletions(aerc, cmd)
+ if len(opts) > 0 {
+ for _, opt := range opts {
+ completions = append(completions, opt)
+ }
+ }
+ }
+ return completions
+}
+
var (
Prefix string
ShareDir string
@@ 96,27 131,12 @@ func main() {
aerc *widgets.Aerc
ui *libui.UI
)
+
aerc = widgets.NewAerc(conf, logger, func(cmd string) error {
- cmds := getCommands(aerc.SelectedTab())
- for i, set := range cmds {
- err := set.ExecuteCommand(aerc, cmd)
- if _, ok := err.(commands.NoSuchCommand); ok {
- if i == len(cmds)-1 {
- return err
- } else {
- continue
- }
- } else if _, ok := err.(commands.ErrorExit); ok {
- ui.Exit()
- return nil
- } else if err != nil {
- return err
- } else {
- break
- }
- }
- return nil
- })
+ return execCommand(aerc, ui, cmd)
+ }, func(cmd string) []string {
+ return getCompletions(aerc, cmd)
+ })
ui, err = libui.Initialize(conf, aerc)
if err != nil {
M commands/account/account.go => commands/account/account.go +2 -2
@@ 8,9 8,9 @@ var (
AccountCommands *commands.Commands
)
-func register(name string, cmd commands.AercCommand) {
+func register(cmd commands.Command) {
if AccountCommands == nil {
AccountCommands = commands.NewCommands()
}
- AccountCommands.Register(name, cmd)
+ AccountCommands.Register(cmd)
}
M commands/account/cf.go => commands/account/cf.go +12 -2
@@ 10,12 10,22 @@ var (
history map[string]string
)
+type ChangeFolder struct{}
+
func init() {
history = make(map[string]string)
- register("cf", ChangeFolder)
+ register(ChangeFolder{})
+}
+
+func (_ ChangeFolder) Aliases() []string {
+ return []string{"cf"}
+}
+
+func (_ ChangeFolder) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func ChangeFolder(aerc *widgets.Aerc, args []string) error {
+func (_ ChangeFolder) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 2 {
return errors.New("Usage: cf <folder>")
}
M commands/account/compose.go => commands/account/compose.go +12 -2
@@ 6,12 6,22 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type Compose struct{}
+
func init() {
- register("compose", Compose)
+ register(Compose{})
+}
+
+func (_ Compose) Aliases() []string {
+ return []string{"compose"}
+}
+
+func (_ Compose) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
// TODO: Accept arguments for default headers, message body
-func Compose(aerc *widgets.Aerc, args []string) error {
+func (_ Compose) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 1 {
return errors.New("Usage: compose")
}
M commands/account/mkdir.go => commands/account/mkdir.go +12 -2
@@ 10,11 10,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/worker/types"
)
+type MakeDir struct{}
+
func init() {
- register("mkdir", Mkdir)
+ register(MakeDir{})
+}
+
+func (_ MakeDir) Aliases() []string {
+ return []string{"mkdir"}
+}
+
+func (_ MakeDir) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func Mkdir(aerc *widgets.Aerc, args []string) error {
+func (_ MakeDir) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 2 {
return errors.New("Usage: :mkdir <name>")
}
M commands/account/next-folder.go => commands/account/next-folder.go +14 -5
@@ 8,16 8,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type NextPrevFolder struct{}
+
func init() {
- register("next-folder", NextPrevFolder)
- register("prev-folder", NextPrevFolder)
+ register(NextPrevFolder{})
}
-func nextPrevFolderUsage(cmd string) error {
- return errors.New(fmt.Sprintf("Usage: %s [n]", cmd))
+func (_ NextPrevFolder) Aliases() []string {
+ return []string{"next-folder", "prev-folder"}
+}
+
+func (_ NextPrevFolder) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func NextPrevFolder(aerc *widgets.Aerc, args []string) error {
+func (_ NextPrevFolder) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) > 2 {
return nextPrevFolderUsage(args[0])
}
@@ 44,3 49,7 @@ func NextPrevFolder(aerc *widgets.Aerc, args []string) error {
}
return nil
}
+
+func nextPrevFolderUsage(cmd string) error {
+ return errors.New(fmt.Sprintf("Usage: %s [n]", cmd))
+}
M commands/account/next-result.go => commands/account/next-result.go +14 -5
@@ 7,16 7,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type NextPrevResult struct{}
+
func init() {
- register("next-result", NextPrevResult)
- register("prev-result", NextPrevResult)
+ register(NextPrevResult{})
}
-func nextPrevResultUsage(cmd string) error {
- return errors.New(fmt.Sprintf("Usage: %s [<n>[%%]]", cmd))
+func (_ NextPrevResult) Aliases() []string {
+ return []string{"next-result", "prev-result"}
+}
+
+func (_ NextPrevResult) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func NextPrevResult(aerc *widgets.Aerc, args []string) error {
+func (_ NextPrevResult) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) > 1 {
return nextPrevResultUsage(args[0])
}
@@ 39,3 44,7 @@ func NextPrevResult(aerc *widgets.Aerc, args []string) error {
}
return nil
}
+
+func nextPrevResultUsage(cmd string) error {
+ return errors.New(fmt.Sprintf("Usage: %s [<n>[%%]]", cmd))
+}
M commands/account/next.go => commands/account/next.go +14 -7
@@ 9,18 9,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type NextPrevMsg struct{}
+
func init() {
- register("next", NextPrevMessage)
- register("next-message", NextPrevMessage)
- register("prev", NextPrevMessage)
- register("prev-message", NextPrevMessage)
+ register(NextPrevMsg{})
}
-func nextPrevMessageUsage(cmd string) error {
- return errors.New(fmt.Sprintf("Usage: %s [<n>[%%]]", cmd))
+func (_ NextPrevMsg) Aliases() []string {
+ return []string{"next", "next-message", "prev", "prev-message"}
+}
+
+func (_ NextPrevMsg) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func NextPrevMessage(aerc *widgets.Aerc, args []string) error {
+func (_ NextPrevMsg) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) > 2 {
return nextPrevMessageUsage(args[0])
}
@@ 63,3 66,7 @@ func NextPrevMessage(aerc *widgets.Aerc, args []string) error {
}
return nil
}
+
+func nextPrevMessageUsage(cmd string) error {
+ return errors.New(fmt.Sprintf("Usage: %s [<n>[%%]]", cmd))
+}
M commands/account/pipe.go => commands/account/pipe.go +12 -2
@@ 8,11 8,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type Pipe struct{}
+
func init() {
- register("pipe", Pipe)
+ register(Pipe{})
+}
+
+func (_ Pipe) Aliases() []string {
+ return []string{"pipe"}
+}
+
+func (_ Pipe) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func Pipe(aerc *widgets.Aerc, args []string) error {
+func (_ Pipe) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) < 2 {
return errors.New("Usage: :pipe <cmd> [args...]")
}
M commands/account/search.go => commands/account/search.go +12 -3
@@ 9,12 9,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type SearchFilter struct{}
+
func init() {
- register("search", SearchFilter)
- //register("filter", SearchFilter) // TODO
+ register(SearchFilter{})
+}
+
+func (_ SearchFilter) Aliases() []string {
+ return []string{"search"}
+}
+
+func (_ SearchFilter) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func SearchFilter(aerc *widgets.Aerc, args []string) error {
+func (_ SearchFilter) Execute(aerc *widgets.Aerc, args []string) error {
var (
criteria *imap.SearchCriteria = imap.NewSearchCriteria()
)
M commands/account/select.go => commands/account/select.go +12 -3
@@ 7,12 7,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type SelectMessage struct{}
+
func init() {
- register("select", SelectMessage)
- register("select-message", SelectMessage)
+ register(SelectMessage{})
+}
+
+func (_ SelectMessage) Aliases() []string {
+ return []string{"select", "select-message"}
+}
+
+func (_ SelectMessage) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func SelectMessage(aerc *widgets.Aerc, args []string) error {
+func (_ SelectMessage) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 2 {
return errors.New("Usage: :select-message <n>")
}
M commands/account/view.go => commands/account/view.go +12 -3
@@ 6,12 6,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type ViewMessage struct{}
+
func init() {
- register("view", ViewMessage)
- register("view-message", ViewMessage)
+ register(ViewMessage{})
+}
+
+func (_ ViewMessage) Aliases() []string {
+ return []string{"view-message", "view"}
+}
+
+func (_ ViewMessage) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func ViewMessage(aerc *widgets.Aerc, args []string) error {
+func (_ ViewMessage) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 1 {
return errors.New("Usage: view-message")
}
M commands/cd.go => commands/cd.go +12 -2
@@ 12,11 12,21 @@ var (
previousDir string
)
+type ChangeDirectory struct{}
+
func init() {
- register("cd", ChangeDirectory)
+ register(ChangeDirectory{})
+}
+
+func (_ ChangeDirectory) Aliases() []string {
+ return []string{"cd"}
+}
+
+func (_ ChangeDirectory) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func ChangeDirectory(aerc *widgets.Aerc, args []string) error {
+func (_ ChangeDirectory) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) < 1 || len(args) > 2 {
return errors.New("Usage: cd [directory]")
}
M commands/commands.go => commands/commands.go +69 -9
@@ 2,27 2,47 @@ package commands
import (
"errors"
+ "strings"
"github.com/google/shlex"
"git.sr.ht/~sircmpwn/aerc/widgets"
)
-type AercCommand func(aerc *widgets.Aerc, args []string) error
+type Command interface {
+ Aliases() []string
+ Execute(*widgets.Aerc, []string) error
+ Complete(*widgets.Aerc, []string) []string
+}
-type Commands map[string]AercCommand
+type Commands map[string]Command
func NewCommands() *Commands {
- cmds := Commands(make(map[string]AercCommand))
+ cmds := Commands(make(map[string]Command))
return &cmds
}
-func (cmds *Commands) dict() map[string]AercCommand {
- return map[string]AercCommand(*cmds)
+func (cmds *Commands) dict() map[string]Command {
+ return map[string]Command(*cmds)
}
-func (cmds *Commands) Register(name string, cmd AercCommand) {
- cmds.dict()[name] = cmd
+func (cmds *Commands) Names() []string {
+ names := make([]string, 0)
+
+ for k := range cmds.dict() {
+ names = append(names, k)
+ }
+ return names
+}
+
+func (cmds *Commands) Register(cmd Command) {
+ // TODO enforce unique aliases, until then, duplicate each
+ if len(cmd.Aliases()) < 1 {
+ return
+ }
+ for _, alias := range cmd.Aliases() {
+ cmds.dict()[alias] = cmd
+ }
}
type NoSuchCommand string
@@ 43,8 63,48 @@ func (cmds *Commands) ExecuteCommand(aerc *widgets.Aerc, cmd string) error {
if len(args) == 0 {
return errors.New("Expected a command.")
}
- if fn, ok := cmds.dict()[args[0]]; ok {
- return fn(aerc, args)
+ if cmd, ok := cmds.dict()[args[0]]; ok {
+ return cmd.Execute(aerc, args)
}
return NoSuchCommand(args[0])
}
+
+func (cmds *Commands) GetCompletions(aerc *widgets.Aerc, cmd string) []string {
+ args, err := shlex.Split(cmd)
+ if err != nil {
+ return nil
+ }
+
+ if len(args) == 0 {
+ return nil
+ }
+
+ if len(args) > 1 {
+ if cmd, ok := cmds.dict()[args[0]]; ok {
+ completions := cmd.Complete(aerc, args[1:])
+ if completions != nil && len(completions) == 0 {
+ return nil
+ }
+
+ options := make([]string, 0)
+ for _, option := range completions {
+ options = append(options, args[0]+" "+option)
+ }
+ return options
+ }
+ return nil
+ }
+
+ names := cmds.Names()
+ options := make([]string, 0)
+ for _, name := range names {
+ if strings.HasPrefix(name, args[0]) {
+ options = append(options, name)
+ }
+ }
+
+ if len(options) > 0 {
+ return options
+ }
+ return nil
+}
M commands/compose/abort.go => commands/compose/abort.go +12 -2
@@ 6,11 6,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type Abort struct{}
+
func init() {
- register("abort", CommandAbort)
+ register(Abort{})
+}
+
+func (_ Abort) Aliases() []string {
+ return []string{"abort"}
+}
+
+func (_ Abort) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func CommandAbort(aerc *widgets.Aerc, args []string) error {
+func (_ Abort) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 1 {
return errors.New("Usage: abort")
}
M commands/compose/compose.go => commands/compose/compose.go +2 -2
@@ 8,9 8,9 @@ var (
ComposeCommands *commands.Commands
)
-func register(name string, cmd commands.AercCommand) {
+func register(cmd commands.Command) {
if ComposeCommands == nil {
ComposeCommands = commands.NewCommands()
}
- ComposeCommands.Register(name, cmd)
+ ComposeCommands.Register(cmd)
}
M commands/compose/edit.go => commands/compose/edit.go +12 -2
@@ 6,11 6,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type Edit struct{}
+
func init() {
- register("edit", CommandEdit)
+ register(Edit{})
+}
+
+func (_ Edit) Aliases() []string {
+ return []string{"edit"}
+}
+
+func (_ Edit) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func CommandEdit(aerc *widgets.Aerc, args []string) error {
+func (_ Edit) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 1 {
return errors.New("Usage: edit")
}
M commands/compose/next-field.go => commands/compose/next-field.go +14 -5
@@ 7,16 7,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type NextPrevField struct{}
+
func init() {
- register("next-field", NextPrevField)
- register("prev-field", NextPrevField)
+ register(NextPrevField{})
}
-func nextPrevFieldUsage(cmd string) error {
- return errors.New(fmt.Sprintf("Usage: %s", cmd))
+func (_ NextPrevField) Aliases() []string {
+ return []string{"next-field", "prev-field"}
+}
+
+func (_ NextPrevField) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func NextPrevField(aerc *widgets.Aerc, args []string) error {
+func (_ NextPrevField) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) > 2 {
return nextPrevFieldUsage(args[0])
}
@@ 28,3 33,7 @@ func NextPrevField(aerc *widgets.Aerc, args []string) error {
}
return nil
}
+
+func nextPrevFieldUsage(cmd string) error {
+ return errors.New(fmt.Sprintf("Usage: %s", cmd))
+}
M commands/compose/send.go => commands/compose/send.go +13 -3
@@ 20,13 20,23 @@ import (
"git.sr.ht/~sircmpwn/aerc/worker/types"
)
+type Send struct{}
+
func init() {
- register("send", SendMessage)
+ register(Send{})
+}
+
+func (_ Send) Aliases() []string {
+ return []string{"send"}
+}
+
+func (_ Send) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func SendMessage(aerc *widgets.Aerc, args []string) error {
+func (_ Send) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) > 1 {
- return errors.New("Usage: send-message")
+ return errors.New("Usage: send")
}
composer, _ := aerc.SelectedTab().(*widgets.Composer)
config := composer.Config()
M commands/global.go => commands/global.go +2 -2
@@ 4,9 4,9 @@ var (
GlobalCommands *Commands
)
-func register(name string, cmd AercCommand) {
+func register(cmd Command) {
if GlobalCommands == nil {
GlobalCommands = NewCommands()
}
- GlobalCommands.Register(name, cmd)
+ GlobalCommands.Register(cmd)
}
M commands/help.go => commands/help.go +13 -3
@@ 6,16 6,26 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type Help struct{}
+
func init() {
- register("help", Help)
+ register(Help{})
+}
+
+func (_ Help) Aliases() []string {
+ return []string{"help"}
+}
+
+func (_ Help) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func Help(aerc *widgets.Aerc, args []string) error {
+func (_ Help) Execute(aerc *widgets.Aerc, args []string) error {
page := "aerc"
if len(args) == 2 {
page = "aerc-" + args[1]
} else if len(args) > 2 {
return errors.New("Usage: help [topic]")
}
- return Term(aerc, []string{"term", "man", page})
+ return TermCore(aerc, []string{"term", "man", page})
}
M commands/msg/archive.go => commands/msg/archive.go +12 -2
@@ 18,11 18,21 @@ const (
ARCHIVE_MONTH = "month"
)
+type Archive struct{}
+
func init() {
- register("archive", Archive)
+ register(Archive{})
+}
+
+func (_ Archive) Aliases() []string {
+ return []string{"archive"}
+}
+
+func (_ Archive) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func Archive(aerc *widgets.Aerc, args []string) error {
+func (_ Archive) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 2 {
return errors.New("Usage: archive <flat|year|month>")
}
M commands/msg/copy.go => commands/msg/copy.go +12 -3
@@ 11,12 11,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/worker/types"
)
+type Copy struct{}
+
func init() {
- register("cp", Copy)
- register("copy", Copy)
+ register(Copy{})
+}
+
+func (_ Copy) Aliases() []string {
+ return []string{"copy"}
+}
+
+func (_ Copy) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func Copy(aerc *widgets.Aerc, args []string) error {
+func (_ Copy) Execute(aerc *widgets.Aerc, args []string) error {
opts, optind, err := getopt.Getopts(args, "p")
if err != nil {
return err
M commands/msg/delete.go => commands/msg/delete.go +12 -3
@@ 10,12 10,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/worker/types"
)
+type Delete struct{}
+
func init() {
- register("delete", DeleteMessage)
- register("delete-message", DeleteMessage)
+ register(Delete{})
+}
+
+func (_ Delete) Aliases() []string {
+ return []string{"delete", "delete-message"}
+}
+
+func (_ Delete) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func DeleteMessage(aerc *widgets.Aerc, args []string) error {
+func (_ Delete) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 1 {
return errors.New("Usage: :delete")
}
M commands/msg/move.go => commands/msg/move.go +12 -3
@@ 11,12 11,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/worker/types"
)
+type Move struct{}
+
func init() {
- register("mv", Move)
- register("move", Move)
+ register(Move{})
+}
+
+func (_ Move) Aliases() []string {
+ return []string{"mv", "move"}
+}
+
+func (_ Move) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func Move(aerc *widgets.Aerc, args []string) error {
+func (_ Move) Execute(aerc *widgets.Aerc, args []string) error {
opts, optind, err := getopt.Getopts(args, "p")
if err != nil {
return err
M commands/msg/msg.go => commands/msg/msg.go +2 -2
@@ 8,9 8,9 @@ var (
MessageCommands *commands.Commands
)
-func register(name string, cmd commands.AercCommand) {
+func register(cmd commands.Command) {
if MessageCommands == nil {
MessageCommands = commands.NewCommands()
}
- MessageCommands.Register(name, cmd)
+ MessageCommands.Register(cmd)
}
M commands/msg/read.go => commands/msg/read.go +12 -3
@@ 10,12 10,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/worker/types"
)
+type Read struct{}
+
func init() {
- register("read", Read)
- register("unread", Read)
+ register(Read{})
+}
+
+func (_ Read) Aliases() []string {
+ return []string{"read", "unread"}
+}
+
+func (_ Read) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func Read(aerc *widgets.Aerc, args []string) error {
+func (_ Read) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 1 {
return errors.New("Usage: " + args[0])
}
M commands/msg/reply.go => commands/msg/reply.go +12 -3
@@ 18,12 18,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type reply struct{}
+
func init() {
- register("reply", Reply)
- register("forward", Reply)
+ register(reply{})
+}
+
+func (_ reply) Aliases() []string {
+ return []string{"reply", "forward"}
+}
+
+func (_ reply) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func Reply(aerc *widgets.Aerc, args []string) error {
+func (_ reply) Execute(aerc *widgets.Aerc, args []string) error {
opts, optind, err := getopt.Getopts(args, "aq")
if err != nil {
return err
M commands/msgview/close.go => commands/msgview/close.go +12 -2
@@ 6,11 6,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type Close struct{}
+
func init() {
- register("close", CommandClose)
+ register(Close{})
+}
+
+func (_ Close) Aliases() []string {
+ return []string{"close"}
+}
+
+func (_ Close) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func CommandClose(aerc *widgets.Aerc, args []string) error {
+func (_ Close) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 1 {
return errors.New("Usage: close")
}
M commands/msgview/msgview.go => commands/msgview/msgview.go +2 -2
@@ 8,9 8,9 @@ var (
MessageViewCommands *commands.Commands
)
-func register(name string, cmd commands.AercCommand) {
+func register(cmd commands.Command) {
if MessageViewCommands == nil {
MessageViewCommands = commands.NewCommands()
}
- MessageViewCommands.Register(name, cmd)
+ MessageViewCommands.Register(cmd)
}
M commands/msgview/next-part.go => commands/msgview/next-part.go +14 -5
@@ 8,16 8,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type NextPrevPart struct{}
+
func init() {
- register("next-part", NextPrevPart)
- register("prev-part", NextPrevPart)
+ register(NextPrevPart{})
}
-func nextPrevPartUsage(cmd string) error {
- return errors.New(fmt.Sprintf("Usage: %s [n]", cmd))
+func (_ NextPrevPart) Aliases() []string {
+ return []string{"next-part", "prev-part"}
+}
+
+func (_ NextPrevPart) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func NextPrevPart(aerc *widgets.Aerc, args []string) error {
+func (_ NextPrevPart) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) > 2 {
return nextPrevPartUsage(args[0])
}
@@ 41,3 46,7 @@ func NextPrevPart(aerc *widgets.Aerc, args []string) error {
}
return nil
}
+
+func nextPrevPartUsage(cmd string) error {
+ return errors.New(fmt.Sprintf("Usage: %s [n]", cmd))
+}
M commands/msgview/next.go => commands/msgview/next.go +12 -5
@@ 6,14 6,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type NextPrevMsg struct{}
+
func init() {
- register("next", NextPrevMessage)
- register("next-message", NextPrevMessage)
- register("prev", NextPrevMessage)
- register("prev-message", NextPrevMessage)
+ register(NextPrevMsg{})
+}
+
+func (_ NextPrevMsg) Aliases() []string {
+ return []string{"next", "next-message", "prev", "prev-message"}
+}
+
+func (_ NextPrevMsg) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func NextPrevMessage(aerc *widgets.Aerc, args []string) error {
+func (_ NextPrevMsg) Execute(aerc *widgets.Aerc, args []string) error {
mv, _ := aerc.SelectedTab().(*widgets.MessageViewer)
acct := mv.SelectedAccount()
store := mv.Store()
M commands/msgview/open.go => commands/msgview/open.go +12 -2
@@ 14,11 14,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type Open struct{}
+
func init() {
- register("open", Open)
+ register(Open{})
+}
+
+func (_ Open) Aliases() []string {
+ return []string{"open"}
+}
+
+func (_ Open) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func Open(aerc *widgets.Aerc, args []string) error {
+func (_ Open) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 1 {
return errors.New("Usage: open")
}
M commands/msgview/pipe.go => commands/msgview/pipe.go +12 -2
@@ 12,11 12,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type Pipe struct{}
+
func init() {
- register("pipe", Pipe)
+ register(Pipe{})
+}
+
+func (_ Pipe) Aliases() []string {
+ return []string{"pipe"}
+}
+
+func (_ Pipe) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func Pipe(aerc *widgets.Aerc, args []string) error {
+func (_ Pipe) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) < 2 {
return errors.New("Usage: :pipe <cmd> [args...]")
}
M commands/msgview/save.go => commands/msgview/save.go +14 -2
@@ 16,19 16,31 @@ import (
"github.com/mitchellh/go-homedir"
)
+type Save struct{}
+
func init() {
- register("save", Save)
+ register(Save{})
+}
+
+func (_ Save) Aliases() []string {
+ return []string{"save"}
+}
+
+func (_ Save) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func Save(aerc *widgets.Aerc, args []string) error {
+func (_ Save) Execute(aerc *widgets.Aerc, args []string) error {
opts, optind, err := getopt.Getopts(args, "p")
if err != nil {
return err
}
+
var (
mkdirs bool
path string
)
+
for _, opt := range opts {
switch opt.Option {
case 'p':
M commands/msgview/toggle-headers.go => commands/msgview/toggle-headers.go +14 -4
@@ 7,15 7,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type ToggleHeaders struct{}
+
func init() {
- register("toggle-headers", ToggleHeaders)
+ register(ToggleHeaders{})
}
-func toggleHeadersUsage(cmd string) error {
- return errors.New(fmt.Sprintf("Usage: %s", cmd))
+func (_ ToggleHeaders) Aliases() []string {
+ return []string{"toggle-headers"}
+}
+
+func (_ ToggleHeaders) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func ToggleHeaders(aerc *widgets.Aerc, args []string) error {
+func (_ ToggleHeaders) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) > 1 {
return toggleHeadersUsage(args[0])
}
@@ 23,3 29,7 @@ func ToggleHeaders(aerc *widgets.Aerc, args []string) error {
mv.ToggleHeaders()
return nil
}
+
+func toggleHeadersUsage(cmd string) error {
+ return errors.New(fmt.Sprintf("Usage: %s", cmd))
+}
M commands/new-account.go => commands/new-account.go +12 -2
@@ 7,11 7,21 @@ import (
"git.sr.ht/~sircmpwn/getopt"
)
+type NewAccount struct{}
+
func init() {
- register("new-account", CommandNewAccount)
+ register(NewAccount{})
+}
+
+func (_ NewAccount) Aliases() []string {
+ return []string{"new-account"}
+}
+
+func (_ NewAccount) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func CommandNewAccount(aerc *widgets.Aerc, args []string) error {
+func (_ NewAccount) Execute(aerc *widgets.Aerc, args []string) error {
opts, _, err := getopt.Getopts(args, "t")
if err != nil {
return errors.New("Usage: new-account [-t]")
M commands/next-tab.go => commands/next-tab.go +14 -5
@@ 8,16 8,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type NextPrevTab struct{}
+
func init() {
- register("next-tab", NextPrevTab)
- register("prev-tab", NextPrevTab)
+ register(NextPrevTab{})
}
-func nextPrevTabUsage(cmd string) error {
- return errors.New(fmt.Sprintf("Usage: %s [n]", cmd))
+func (_ NextPrevTab) Aliases() []string {
+ return []string{"next-tab", "prev-tab"}
+}
+
+func (_ NextPrevTab) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func NextPrevTab(aerc *widgets.Aerc, args []string) error {
+func (_ NextPrevTab) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) > 2 {
return nextPrevTabUsage(args[0])
}
@@ 40,3 45,7 @@ func NextPrevTab(aerc *widgets.Aerc, args []string) error {
}
return nil
}
+
+func nextPrevTabUsage(cmd string) error {
+ return errors.New(fmt.Sprintf("Usage: %s [n]", cmd))
+}
M commands/pwd.go => commands/pwd.go +12 -2
@@ 8,11 8,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type PrintWorkDir struct{}
+
func init() {
- register("pwd", PrintWorkDirectory)
+ register(PrintWorkDir{})
+}
+
+func (_ PrintWorkDir) Aliases() []string {
+ return []string{"pwd"}
+}
+
+func (_ PrintWorkDir) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func PrintWorkDirectory(aerc *widgets.Aerc, args []string) error {
+func (_ PrintWorkDir) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 1 {
return errors.New("Usage: pwd")
}
M commands/quit.go => commands/quit.go +12 -2
@@ 6,8 6,18 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type Quit struct{}
+
func init() {
- register("quit", CommandQuit)
+ register(Quit{})
+}
+
+func (_ Quit) Aliases() []string {
+ return []string{"quit", "exit"}
+}
+
+func (_ Quit) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
type ErrorExit int
@@ 16,7 26,7 @@ func (err ErrorExit) Error() string {
return "exit"
}
-func CommandQuit(aerc *widgets.Aerc, args []string) error {
+func (_ Quit) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 1 {
return errors.New("Usage: quit")
}
M commands/term.go => commands/term.go +17 -2
@@ 10,11 10,22 @@ import (
"github.com/riywo/loginshell"
)
+type Term struct{}
+
func init() {
- register("term", Term)
+ register(Term{})
+}
+
+func (_ Term) Aliases() []string {
+ return []string{"terminal", "term"}
+}
+
+func (_ Term) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func Term(aerc *widgets.Aerc, args []string) error {
+// The help command is an alias for `term man` thus Term requires a simple func
+func TermCore(aerc *widgets.Aerc, args []string) error {
if len(args) == 1 {
shell, err := loginshell.Shell()
if err != nil {
@@ 43,3 54,7 @@ func Term(aerc *widgets.Aerc, args []string) error {
}
return nil
}
+
+func (_ Term) Execute(aerc *widgets.Aerc, args []string) error {
+ return TermCore(aerc, args)
+}
M commands/terminal/close.go => commands/terminal/close.go +12 -2
@@ 6,11 6,21 @@ import (
"git.sr.ht/~sircmpwn/aerc/widgets"
)
+type Close struct{}
+
func init() {
- register("close", CommandClose)
+ register(Close{})
+}
+
+func (_ Close) Aliases() []string {
+ return []string{"close"}
+}
+
+func (_ Close) Complete(aerc *widgets.Aerc, args []string) []string {
+ return nil
}
-func CommandClose(aerc *widgets.Aerc, args []string) error {
+func (_ Close) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 1 {
return errors.New("Usage: close")
}
M commands/terminal/terminal.go => commands/terminal/terminal.go +2 -2
@@ 8,9 8,9 @@ var (
TerminalCommands *commands.Commands
)
-func register(name string, cmd commands.AercCommand) {
+func register(cmd commands.Command) {
if TerminalCommands == nil {
TerminalCommands = commands.NewCommands()
}
- TerminalCommands.Register(name, cmd)
+ TerminalCommands.Register(cmd)
}
M lib/ui/textinput.go => lib/ui/textinput.go +8 -0
@@ 46,6 46,14 @@ func (ti *TextInput) String() string {
return string(ti.text)
}
+func (ti *TextInput) StringLeft() string {
+ return string(ti.text[:ti.index])
+}
+
+func (ti *TextInput) StringRight() string {
+ return string(ti.text[ti.index:])
+}
+
func (ti *TextInput) Set(value string) {
ti.text = []rune(value)
ti.index = len(ti.text)
M widgets/aerc.go => widgets/aerc.go +5 -1
@@ 14,6 14,7 @@ import (
type Aerc struct {
accounts map[string]*AccountView
cmd func(cmd string) error
+ complete func(cmd string) []string
conf *config.AercConfig
focused libui.Interactive
grid *libui.Grid
@@ 26,7 27,7 @@ type Aerc struct {
}
func NewAerc(conf *config.AercConfig, logger *log.Logger,
- cmd func(cmd string) error) *Aerc {
+ cmd func(cmd string) error, complete func(cmd string) []string) *Aerc {
tabs := libui.NewTabs()
@@ 49,6 50,7 @@ func NewAerc(conf *config.AercConfig, logger *log.Logger,
accounts: make(map[string]*AccountView),
conf: conf,
cmd: cmd,
+ complete: complete,
grid: grid,
logger: logger,
statusbar: statusbar,
@@ 289,6 291,8 @@ func (aerc *Aerc) BeginExCommand() {
}, func() {
aerc.statusbar.Pop()
aerc.focus(previous)
+ }, func(cmd string) []string {
+ return aerc.complete(cmd)
})
aerc.statusbar.Push(exline)
aerc.focus(exline)
M widgets/dirlist.go => widgets/dirlist.go +4 -0
@@ 40,6 40,10 @@ func NewDirectoryList(acctConf *config.AccountConfig, uiConf *config.UIConfig,
return dirlist
}
+func (dirlist *DirectoryList) List() []string {
+ return dirlist.dirs
+}
+
func (dirlist *DirectoryList) UpdateList(done func(dirs []string)) {
var dirs []string
dirlist.worker.PostAction(
M widgets/exline.go => widgets/exline.go +17 -7
@@ 8,17 8,21 @@ import (
type ExLine struct {
ui.Invalidatable
- cancel func()
- commit func(cmd string)
- input *ui.TextInput
+ cancel func()
+ commit func(cmd string)
+ tabcomplete func(cmd string) []string
+ input *ui.TextInput
}
-func NewExLine(commit func(cmd string), cancel func()) *ExLine {
+func NewExLine(commit func(cmd string), cancel func(),
+ tabcomplete func(cmd string) []string) *ExLine {
+
input := ui.NewTextInput("").Prompt(":")
exline := &ExLine{
- cancel: cancel,
- commit: commit,
- input: input,
+ cancel: cancel,
+ commit: commit,
+ tabcomplete: tabcomplete,
+ input: input,
}
input.OnInvalidate(func(d ui.Drawable) {
exline.Invalidate()
@@ 48,6 52,12 @@ func (ex *ExLine) Event(event tcell.Event) bool {
case tcell.KeyEsc, tcell.KeyCtrlC:
ex.input.Focus(false)
ex.cancel()
+ case tcell.KeyTab:
+ complete := ex.tabcomplete(ex.input.StringLeft())
+ if len(complete) == 1 {
+ ex.input.Set(complete[0] + " " + ex.input.StringRight())
+ }
+ ex.Invalidate()
default:
return ex.input.Event(event)
}