commit 8126d82956636a2525263e2d0d985d721fdb8074
parent fe79a9a5879936a7f5b16cc6a8be1d93ec1bfae7
Author: Drew DeVault <sir@cmpwn.com>
Date: Thu, 21 Mar 2019 16:30:23 -0400
Add context-specific commands
Diffstat:
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 {