---
config/config.go | 150 +++++++++++++++++++++++++++++-------------
doc/aerc-config.5.scd | 15 +++++
widgets/aerc.go | 54 ++++++++++++---
3 files changed, 165 insertions(+), 54 deletions(-)
diff --git a/config/config.go b/config/config.go
index af9c63b..528c134 100644
--- a/config/config.go
+++ b/config/config.go
@@ -90,14 +90,19 @@ type AccountConfig struct {
}
type BindingConfig struct {
- Global *KeyBindings
- AccountWizard *KeyBindings
- Compose *KeyBindings
- ComposeEditor *KeyBindings
- ComposeReview *KeyBindings
- MessageList *KeyBindings
- MessageView *KeyBindings
- Terminal *KeyBindings
+ Global *BindingGroup
+ AccountWizard *BindingGroup
+ Compose *BindingGroup
+ ComposeEditor *BindingGroup
+ ComposeReview *BindingGroup
+ MessageList *BindingGroup
+ MessageView *BindingGroup
+ Terminal *BindingGroup
+}
+
+type BindingGroup struct {
+ Base *KeyBindings
+ Account map[string]*KeyBindings
}
type ComposeConfig struct {
@@ -478,16 +483,10 @@ func LoadConfigFromFile(root *string, sharedir string) (*AercConfig, error) {
}
file.NameMapper = mapName
config := &AercConfig{
- Bindings: BindingConfig{
- Global: NewKeyBindings(),
- AccountWizard: NewKeyBindings(),
- Compose: NewKeyBindings(),
- ComposeEditor: NewKeyBindings(),
- ComposeReview: NewKeyBindings(),
- MessageList: NewKeyBindings(),
- MessageView: NewKeyBindings(),
- Terminal: NewKeyBindings(),
- },
+ Bindings: BindingConfig{
+ AccountWizard: &BindingGroup{Base: NewKeyBindings()},
+ },
+
Ini: file,
Ui: UIConfig{
@@ -542,12 +541,12 @@ func LoadConfigFromFile(root *string, sharedir string) (*AercConfig, error) {
},
}
- // These bindings are not configurable
- config.Bindings.AccountWizard.ExKey = KeyStroke{
+ // These bindings are not configurable
+ config.Bindings.AccountWizard.Base.ExKey = KeyStroke{
Key: tcell.KeyCtrlE,
}
quit, _ := ParseBinding("<C-q>", ":quit<Enter>")
- config.Bindings.AccountWizard.Add(quit)
+ config.Bindings.AccountWizard.Base.Add(quit)
if err = config.LoadConfig(file); err != nil {
return nil, err
@@ -565,6 +564,7 @@ func LoadConfigFromFile(root *string, sharedir string) (*AercConfig, error) {
} else {
config.Accounts = accounts
}
+
filename = path.Join(*root, "binds.conf")
binds, err := ini.Load(filename)
if err != nil {
@@ -575,25 +575,86 @@ func LoadConfigFromFile(root *string, sharedir string) (*AercConfig, error) {
return nil, err
}
}
- groups := map[string]**KeyBindings{
- "default": &config.Bindings.Global,
- "compose": &config.Bindings.Compose,
- "messages": &config.Bindings.MessageList,
- "terminal": &config.Bindings.Terminal,
- "view": &config.Bindings.MessageView,
- "compose::editor": &config.Bindings.ComposeEditor,
- "compose::review": &config.Bindings.ComposeReview,
- }
+ bindSectionMap := map[string][]string {
+ "default": []string{},
+ "compose": []string{},
+ "messages": []string{},
+ "terminal": []string{},
+ "view": []string{},
+ "compose::editor": []string{},
+ "compose::review": []string{},
+ }
for _, name := range binds.SectionStrings() {
- sec, err := binds.GetSection(name)
+ parts := strings.Split(name, "//")
+ base := parts[0]
+ section, ok := bindSectionMap[strings.ToLower(base)]
+ if !ok {
+ return nil, errors.New("Invalid section name " + name + ", Base was: " + base)
+ }
+ section = append(section, name)
+ bindSectionMap[strings.ToLower(base)] = section
+ }
+
+ acctNames := []string{}
+ for _, acctConf := range config.Accounts {
+ acctNames = append(acctNames, acctConf.Name)
+ }
+
+ bindingGroups := make(map[string]*BindingGroup)
+ for baseName, secNames := range bindSectionMap {
+ group, err := NewBindingGroup(binds, acctNames, secNames, baseName)
+ if err != nil {
+ return nil, err
+ }
+ bindingGroups[baseName] = group
+ }
+
+ config.Bindings.Global = bindingGroups["default"]
+ config.Bindings.Compose = bindingGroups["compose"]
+ config.Bindings.ComposeEditor = bindingGroups["compose::editor"]
+ config.Bindings.ComposeReview = bindingGroups["compose::review"]
+ config.Bindings.MessageList = bindingGroups["messages"]
+ config.Bindings.MessageView = bindingGroups["view"]
+ config.Bindings.Terminal = bindingGroups["terminal"]
+
+ fmt.Printf("%:v", config.Bindings.MessageList.Account)
+
+ // Globals can't inherit from themselves
+ config.Bindings.Global.Base.Globals = false
+ for _, acctBinds := range config.Bindings.Global.Account {
+ acctBinds.Globals = false
+ }
+ return config, nil
+}
+
+func NewBindingGroup(binds *ini.File, accountNames []string, secNames []string, baseName string) (*BindingGroup, error) {
+ group := &BindingGroup{
+ Base: NewKeyBindings(), Account: make(map[string]*KeyBindings) }
+ for _, name := range accountNames {
+ group.Account[strings.ToLower(name)] = NewKeyBindings()
+ }
+ for _, name := range secNames {
+ parts := strings.Split(name, "//")
+
+ sec, err := binds.GetSection(name)
if err != nil {
return nil, err
}
- group, ok := groups[strings.ToLower(name)]
- if !ok {
- return nil, errors.New("Unknown keybinding group " + name)
- }
+
+ subgroup := &KeyBindings{}
+ if (len(parts) == 2) {
+ sub, ok := group.Account[strings.ToLower(parts[1])]
+ if !ok {
+ return nil, errors.New("Invalid binding subgroup name " + name)
+ }
+ subgroup = sub
+ } else if (len(parts) == 1) {
+ subgroup = group.Base
+ } else {
+ return nil, errors.New("Invalid binding group name " + name)
+ }
+
bindings := NewKeyBindings()
for key, value := range sec.KeysHash() {
if key == "$ex" {
@@ -602,8 +663,7 @@ func LoadConfigFromFile(root *string, sharedir string) (*AercConfig, error) {
return nil, err
}
if len(strokes) != 1 {
- return nil, errors.New(
- "Error: only one keystroke supported for $ex")
+ return nil, errors.New("Invalid binding")
}
bindings.ExKey = strokes[0]
continue
@@ -613,8 +673,7 @@ func LoadConfigFromFile(root *string, sharedir string) (*AercConfig, error) {
continue
}
if value != "true" {
- return nil, errors.New(
- "Error: expected 'true' or 'false' for $noinherit")
+ return nil, errors.New("Invalid binding")
}
bindings.Globals = false
continue
@@ -625,11 +684,14 @@ func LoadConfigFromFile(root *string, sharedir string) (*AercConfig, error) {
}
bindings.Add(binding)
}
- *group = MergeBindings(bindings, *group)
- }
- // Globals can't inherit from themselves
- config.Bindings.Global.Globals = false
- return config, nil
+
+ if len(parts) == 1 {
+ group.Base = MergeBindings(subgroup, bindings)
+ } else {
+ group.Account[strings.ToLower(parts[1])] = MergeBindings(subgroup, bindings)
+ }
+ }
+ return group, nil
}
// checkConfigPerms checks for too open permissions
diff --git a/doc/aerc-config.5.scd b/doc/aerc-config.5.scd
index d4de883..511864c 100644
--- a/doc/aerc-config.5.scd
+++ b/doc/aerc-config.5.scd
@@ -487,6 +487,21 @@ are:
*[terminal]*
keybindings for terminal tabs
+You may also configure account specific key bindings for each context:
+
+*[context//accountname]*
+ keybindings for this context and account, where *accountname* matches
+ the name provided in *accounts.conf*
+
+Example:
+```
+[messages//mailbox]
+c = :cf path:mailbox/** and<space>
+
+[compose::editor//mailbox2]
+...
+```
+
You may also configure global keybindings by placing them at the beginning of
the file, before specifying any context-specific sections. For each *key=value*
option specified, the _key_ is the keystrokes pressed (in order) to invoke this
diff --git a/widgets/aerc.go b/widgets/aerc.go
index 6df0c95..d515536 100644
--- a/widgets/aerc.go
+++ b/widgets/aerc.go
@@ -182,26 +182,60 @@ func (aerc *Aerc) Draw(ctx *ui.Context) {
}
func (aerc *Aerc) getBindings() *config.KeyBindings {
+ selectedAccountName := ""
+ if aerc.SelectedAccount() != nil {
+ selectedAccountName = strings.ToLower(aerc.SelectedAccount().acct.Name);
+ }
switch view := aerc.SelectedTab().(type) {
case *AccountView:
- return aerc.conf.Bindings.MessageList
+ acctBinds, ok := aerc.conf.Bindings.MessageList.Account[selectedAccountName]
+ if !ok {
+ return aerc.conf.Bindings.MessageList.Base
+ } else {
+ return config.MergeBindings(aerc.conf.Bindings.MessageList.Base, acctBinds)
+ }
case *AccountWizard:
- return aerc.conf.Bindings.AccountWizard
+ return aerc.conf.Bindings.AccountWizard.Base
case *Composer:
switch view.Bindings() {
case "compose::editor":
- return aerc.conf.Bindings.ComposeEditor
+ acctBinds, ok := aerc.conf.Bindings.ComposeEditor.Account[selectedAccountName]
+ if !ok {
+ return aerc.conf.Bindings.ComposeEditor.Base
+ } else {
+ return config.MergeBindings(aerc.conf.Bindings.ComposeEditor.Base, acctBinds)
+ }
case "compose::review":
- return aerc.conf.Bindings.ComposeReview
+ acctBinds, ok := aerc.conf.Bindings.ComposeReview.Account[selectedAccountName]
+ if !ok {
+ return aerc.conf.Bindings.ComposeReview.Base
+ } else {
+ return config.MergeBindings(aerc.conf.Bindings.ComposeReview.Base, acctBinds)
+ }
default:
- return aerc.conf.Bindings.Compose
+ acctBinds, ok := aerc.conf.Bindings.Compose.Account[selectedAccountName]
+ if !ok {
+ return aerc.conf.Bindings.Compose.Base
+ } else {
+ return config.MergeBindings(aerc.conf.Bindings.Compose.Base, acctBinds)
+ }
}
case *MessageViewer:
- return aerc.conf.Bindings.MessageView
+ acctBinds, ok := aerc.conf.Bindings.MessageView.Account[selectedAccountName]
+ if !ok {
+ return aerc.conf.Bindings.MessageView.Base
+ } else {
+ return config.MergeBindings(aerc.conf.Bindings.MessageView.Base, acctBinds)
+ }
case *Terminal:
- return aerc.conf.Bindings.Terminal
+ return aerc.conf.Bindings.Terminal.Base
default:
- return aerc.conf.Bindings.Global
+ acctBinds, ok := aerc.conf.Bindings.Global.Account[selectedAccountName]
+ if !ok {
+ return aerc.conf.Bindings.Global.Base
+ } else {
+ return config.MergeBindings(aerc.conf.Bindings.Global.Base, acctBinds)
+ }
}
}
@@ -245,7 +279,7 @@ func (aerc *Aerc) Event(event tcell.Event) bool {
case config.BINDING_NOT_FOUND:
}
if bindings.Globals {
- result, strokes = aerc.conf.Bindings.Global.
+ result, strokes = aerc.conf.Bindings.Global.Base.
GetBinding(aerc.pendingKeys)
switch result {
case config.BINDING_FOUND:
@@ -261,7 +295,7 @@ func (aerc *Aerc) Event(event tcell.Event) bool {
exKey := bindings.ExKey
if aerc.simulating > 0 {
// Keybindings still use : even if you change the ex key
- exKey = aerc.conf.Bindings.Global.ExKey
+ exKey = aerc.conf.Bindings.Global.Base.ExKey
}
if event.Key() == exKey.Key && event.Rune() == exKey.Rune {
aerc.BeginExCommand("")
--
2.31.1