aerc

Working clone of aerc-mail.org
git clone git://git.danielmoch.com/aerc.git
Log | Files | Refs | README | LICENSE

commit 8126d82956636a2525263e2d0d985d721fdb8074
parent fe79a9a5879936a7f5b16cc6a8be1d93ec1bfae7
Author: Drew DeVault <sir@cmpwn.com>
Date:   Thu, 21 Mar 2019 16:30:23 -0400

Add context-specific commands

Diffstat:
Maerc.go | 36+++++++++++++++++++++++++++++++-----
Acommands/account/account.go | 16++++++++++++++++
Acommands/account/cf.go | 38++++++++++++++++++++++++++++++++++++++
Acommands/account/delete-message.go | 25+++++++++++++++++++++++++
Acommands/account/next-folder.go | 46++++++++++++++++++++++++++++++++++++++++++++++
Acommands/account/next-message.go | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acommands/account/select-message.go | 34++++++++++++++++++++++++++++++++++
Mcommands/cd.go | 2+-
Dcommands/cf.go | 38--------------------------------------
Mcommands/commands.go | 36+++++++++++++++++++++++++-----------
Dcommands/delete-message.go | 25-------------------------
Acommands/global.go | 12++++++++++++
Dcommands/next-folder.go | 46----------------------------------------------
Dcommands/next-message.go | 55-------------------------------------------------------
Mcommands/next-tab.go | 4++--
Mcommands/quit.go | 4++--
Dcommands/select-message.go | 34----------------------------------
Mcommands/term-close.go | 2+-
Mcommands/term.go | 2+-
19 files changed, 289 insertions(+), 221 deletions(-)

diff --git a/aerc.go b/aerc.go @@ -11,10 +11,23 @@ import ( "git.sr.ht/~sircmpwn/aerc2/config" "git.sr.ht/~sircmpwn/aerc2/commands" + "git.sr.ht/~sircmpwn/aerc2/commands/account" libui "git.sr.ht/~sircmpwn/aerc2/lib/ui" "git.sr.ht/~sircmpwn/aerc2/widgets" ) +func getCommands(selected libui.Drawable) []*commands.Commands { + switch selected.(type) { + case *widgets.AccountView: + return []*commands.Commands{ + commands.GlobalCommands, + account.AccountCommands, + } + default: + return []*commands.Commands{commands.GlobalCommands} + } +} + func main() { var ( logOut io.Writer @@ -38,12 +51,25 @@ func main() { ui *libui.UI ) aerc = widgets.NewAerc(conf, logger, func(cmd string) error { - err = commands.ExecuteCommand(aerc, cmd) - if _, ok := err.(commands.ErrorExit); ok { - ui.Exit = true - return nil + 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 = true + return nil + } else if err != nil { + return err + } else { + break + } } - return err + return nil }) ui, err = libui.Initialize(conf, aerc) diff --git a/commands/account/account.go b/commands/account/account.go @@ -0,0 +1,16 @@ +package account + +import ( + "git.sr.ht/~sircmpwn/aerc2/commands" +) + +var ( + AccountCommands *commands.Commands +) + +func register(name string, cmd commands.AercCommand) { + if AccountCommands == nil { + AccountCommands = commands.NewCommands() + } + AccountCommands.Register(name, cmd) +} diff --git a/commands/account/cf.go b/commands/account/cf.go @@ -0,0 +1,38 @@ +package account + +import ( + "errors" + + "git.sr.ht/~sircmpwn/aerc2/widgets" +) + +var ( + history map[string]string +) + +func init() { + history = make(map[string]string) + register("cf", ChangeFolder) +} + +func ChangeFolder(aerc *widgets.Aerc, args []string) error { + if len(args) != 2 { + return errors.New("Usage: cf <folder>") + } + acct := aerc.SelectedAccount() + if acct == nil { + return errors.New("No account selected") + } + previous := acct.Directories().Selected() + if args[1] == "-" { + if dir, ok := history[acct.Name()]; ok { + acct.Directories().Select(dir) + } else { + return errors.New("No previous folder to return to") + } + } else { + acct.Directories().Select(args[1]) + } + history[acct.Name()] = previous + return nil +} diff --git a/commands/account/delete-message.go b/commands/account/delete-message.go @@ -0,0 +1,25 @@ +package account + +import ( + "errors" + + "git.sr.ht/~sircmpwn/aerc2/widgets" +) + +func init() { + register("delete-message", DeleteMessage) +} + +func DeleteMessage(aerc *widgets.Aerc, args []string) error { + if len(args) != 1 { + return errors.New("Usage: :delete-message") + } + acct := aerc.SelectedAccount() + if acct == nil { + return errors.New("No account selected") + } + store := acct.Messages().Store() + msg := acct.Messages().Selected() + store.Delete([]uint32{msg.Uid}) + return nil +} diff --git a/commands/account/next-folder.go b/commands/account/next-folder.go @@ -0,0 +1,46 @@ +package account + +import ( + "errors" + "fmt" + "strconv" + + "git.sr.ht/~sircmpwn/aerc2/widgets" +) + +func init() { + register("next-folder", NextPrevFolder) + register("prev-folder", NextPrevFolder) +} + +func nextPrevFolderUsage(cmd string) error { + return errors.New(fmt.Sprintf("Usage: %s [n]", cmd)) +} + +func NextPrevFolder(aerc *widgets.Aerc, args []string) error { + if len(args) > 2 { + return nextPrevFolderUsage(args[0]) + } + var ( + n int = 1 + err error + ) + if len(args) > 1 { + n, err = strconv.Atoi(args[1]) + if err != nil { + return nextPrevFolderUsage(args[0]) + } + } + acct := aerc.SelectedAccount() + if acct == nil { + return errors.New("No account selected") + } + for ; n > 0; n-- { + if args[0] == "prev-folder" { + acct.Directories().Prev() + } else { + acct.Directories().Next() + } + } + return nil +} diff --git a/commands/account/next-message.go b/commands/account/next-message.go @@ -0,0 +1,55 @@ +package account + +import ( + "errors" + "fmt" + "strconv" + "strings" + + "git.sr.ht/~sircmpwn/aerc2/widgets" +) + +func init() { + register("next-message", NextPrevMessage) + register("prev-message", NextPrevMessage) +} + +func nextPrevMessageUsage(cmd string) error { + return errors.New(fmt.Sprintf("Usage: %s [<n>[%%]]", cmd)) +} + +func NextPrevMessage(aerc *widgets.Aerc, args []string) error { + if len(args) > 2 { + return nextPrevMessageUsage(args[0]) + } + var ( + n int = 1 + err error + pct bool + ) + if len(args) > 1 { + if strings.HasSuffix(args[1], "%") { + pct = true + args[1] = args[1][:len(args[1])-1] + } + n, err = strconv.Atoi(args[1]) + if err != nil { + return nextPrevMessageUsage(args[0]) + } + } + acct := aerc.SelectedAccount() + if acct == nil { + return errors.New("No account selected") + } + if pct { + n = int(float64(acct.Messages().Height()) * (float64(n) / 100.0)) + } + for ; n > 0; n-- { + if args[0] == "prev-message" { + acct.Messages().Prev() + } else { + acct.Messages().Next() + } + } + return nil +} diff --git a/commands/account/select-message.go b/commands/account/select-message.go @@ -0,0 +1,34 @@ +package account + +import ( + "errors" + "strconv" + + "git.sr.ht/~sircmpwn/aerc2/widgets" +) + +func init() { + register("select-message", SelectMessage) +} + +func SelectMessage(aerc *widgets.Aerc, args []string) error { + if len(args) != 2 { + return errors.New("Usage: :select-message <n>") + } + var ( + n int = 1 + err error + ) + if len(args) > 1 { + n, err = strconv.Atoi(args[1]) + if err != nil { + return errors.New("Usage: :select-message <n>") + } + } + acct := aerc.SelectedAccount() + if acct == nil { + return errors.New("No account selected") + } + acct.Messages().Select(n) + return nil +} diff --git a/commands/cd.go b/commands/cd.go @@ -13,7 +13,7 @@ var ( ) func init() { - Register("cd", ChangeDirectory) + register("cd", ChangeDirectory) } func ChangeDirectory(aerc *widgets.Aerc, args []string) error { diff --git a/commands/cf.go b/commands/cf.go @@ -1,38 +0,0 @@ -package commands - -import ( - "errors" - - "git.sr.ht/~sircmpwn/aerc2/widgets" -) - -var ( - history map[string]string -) - -func init() { - history = make(map[string]string) - Register("cf", ChangeFolder) -} - -func ChangeFolder(aerc *widgets.Aerc, args []string) error { - if len(args) != 2 { - return errors.New("Usage: cf <folder>") - } - acct := aerc.SelectedAccount() - if acct == nil { - return errors.New("No account selected") - } - previous := acct.Directories().Selected() - if args[1] == "-" { - if dir, ok := history[acct.Name()]; ok { - acct.Directories().Select(dir) - } else { - return errors.New("No previous folder to return to") - } - } else { - acct.Directories().Select(args[1]) - } - history[acct.Name()] = previous - return nil -} diff --git a/commands/commands.go b/commands/commands.go @@ -10,18 +10,32 @@ import ( type AercCommand func(aerc *widgets.Aerc, args []string) error -var ( - commands map[string]AercCommand -) +type Commands map[string]AercCommand -func Register(name string, cmd AercCommand) { - if commands == nil { - commands = make(map[string]AercCommand) - } - commands[name] = cmd +func NewCommands() *Commands { + cmds := Commands(make(map[string]AercCommand)) + return &cmds +} + +func (cmds *Commands) dict() map[string]AercCommand { + return map[string]AercCommand(*cmds) +} + +func (cmds *Commands) Register(name string, cmd AercCommand) { + cmds.dict()[name] = cmd +} + +type NoSuchCommand string + +func (err NoSuchCommand) Error() string { + return "Unknown command " + string(err) +} + +type CommandSource interface { + Commands() *Commands } -func ExecuteCommand(aerc *widgets.Aerc, cmd string) error { +func (cmds *Commands) ExecuteCommand(aerc *widgets.Aerc, cmd string) error { args, err := shlex.Split(cmd) if err != nil { return err @@ -29,8 +43,8 @@ func ExecuteCommand(aerc *widgets.Aerc, cmd string) error { if len(args) == 0 { return errors.New("Expected a command.") } - if fn, ok := commands[args[0]]; ok { + if fn, ok := cmds.dict()[args[0]]; ok { return fn(aerc, args) } - return errors.New("Unknown command " + args[0]) + return NoSuchCommand(args[0]) } diff --git a/commands/delete-message.go b/commands/delete-message.go @@ -1,25 +0,0 @@ -package commands - -import ( - "errors" - - "git.sr.ht/~sircmpwn/aerc2/widgets" -) - -func init() { - Register("delete-message", DeleteMessage) -} - -func DeleteMessage(aerc *widgets.Aerc, args []string) error { - if len(args) != 1 { - return errors.New("Usage: :delete-message") - } - acct := aerc.SelectedAccount() - if acct == nil { - return errors.New("No account selected") - } - store := acct.Messages().Store() - msg := acct.Messages().Selected() - store.Delete([]uint32{msg.Uid}) - return nil -} diff --git a/commands/global.go b/commands/global.go @@ -0,0 +1,12 @@ +package commands + +var ( + GlobalCommands *Commands +) + +func register(name string, cmd AercCommand) { + if GlobalCommands == nil { + GlobalCommands = NewCommands() + } + GlobalCommands.Register(name, cmd) +} diff --git a/commands/next-folder.go b/commands/next-folder.go @@ -1,46 +0,0 @@ -package commands - -import ( - "errors" - "fmt" - "strconv" - - "git.sr.ht/~sircmpwn/aerc2/widgets" -) - -func init() { - Register("next-folder", NextPrevFolder) - Register("prev-folder", NextPrevFolder) -} - -func nextPrevFolderUsage(cmd string) error { - return errors.New(fmt.Sprintf("Usage: %s [n]", cmd)) -} - -func NextPrevFolder(aerc *widgets.Aerc, args []string) error { - if len(args) > 2 { - return nextPrevFolderUsage(args[0]) - } - var ( - n int = 1 - err error - ) - if len(args) > 1 { - n, err = strconv.Atoi(args[1]) - if err != nil { - return nextPrevFolderUsage(args[0]) - } - } - acct := aerc.SelectedAccount() - if acct == nil { - return errors.New("No account selected") - } - for ; n > 0; n-- { - if args[0] == "prev-folder" { - acct.Directories().Prev() - } else { - acct.Directories().Next() - } - } - return nil -} diff --git a/commands/next-message.go b/commands/next-message.go @@ -1,55 +0,0 @@ -package commands - -import ( - "errors" - "fmt" - "strconv" - "strings" - - "git.sr.ht/~sircmpwn/aerc2/widgets" -) - -func init() { - Register("next-message", NextPrevMessage) - Register("prev-message", NextPrevMessage) -} - -func nextPrevMessageUsage(cmd string) error { - return errors.New(fmt.Sprintf("Usage: %s [<n>[%%]]", cmd)) -} - -func NextPrevMessage(aerc *widgets.Aerc, args []string) error { - if len(args) > 2 { - return nextPrevMessageUsage(args[0]) - } - var ( - n int = 1 - err error - pct bool - ) - if len(args) > 1 { - if strings.HasSuffix(args[1], "%") { - pct = true - args[1] = args[1][:len(args[1])-1] - } - n, err = strconv.Atoi(args[1]) - if err != nil { - return nextPrevMessageUsage(args[0]) - } - } - acct := aerc.SelectedAccount() - if acct == nil { - return errors.New("No account selected") - } - if pct { - n = int(float64(acct.Messages().Height()) * (float64(n) / 100.0)) - } - for ; n > 0; n-- { - if args[0] == "prev-message" { - acct.Messages().Prev() - } else { - acct.Messages().Next() - } - } - return nil -} diff --git a/commands/next-tab.go b/commands/next-tab.go @@ -9,8 +9,8 @@ import ( ) func init() { - Register("next-tab", NextPrevTab) - Register("prev-tab", NextPrevTab) + register("next-tab", NextPrevTab) + register("prev-tab", NextPrevTab) } func nextPrevTabUsage(cmd string) error { diff --git a/commands/quit.go b/commands/quit.go @@ -7,7 +7,7 @@ import ( ) func init() { - Register("quit", ChangeQuit) + register("quit", CommandQuit) } type ErrorExit int @@ -16,7 +16,7 @@ func (err ErrorExit) Error() string { return "exit" } -func ChangeQuit(aerc *widgets.Aerc, args []string) error { +func CommandQuit(aerc *widgets.Aerc, args []string) error { if len(args) != 1 { return errors.New("Usage: quit") } diff --git a/commands/select-message.go b/commands/select-message.go @@ -1,34 +0,0 @@ -package commands - -import ( - "errors" - "strconv" - - "git.sr.ht/~sircmpwn/aerc2/widgets" -) - -func init() { - Register("select-message", SelectMessage) -} - -func SelectMessage(aerc *widgets.Aerc, args []string) error { - if len(args) != 2 { - return errors.New("Usage: :select-message <n>") - } - var ( - n int = 1 - err error - ) - if len(args) > 1 { - n, err = strconv.Atoi(args[1]) - if err != nil { - return errors.New("Usage: :select-message <n>") - } - } - acct := aerc.SelectedAccount() - if acct == nil { - return errors.New("No account selected") - } - acct.Messages().Select(n) - return nil -} diff --git a/commands/term-close.go b/commands/term-close.go @@ -8,7 +8,7 @@ import ( func init() { // TODO: Move this command into a terminal-specific command set - Register("close", TermClose) + register("close", TermClose) } func TermClose(aerc *widgets.Aerc, args []string) error { diff --git a/commands/term.go b/commands/term.go @@ -11,7 +11,7 @@ import ( ) func init() { - Register("term", Term) + register("term", Term) } func Term(aerc *widgets.Aerc, args []string) error {