diff options
author | Robin Jarry <robin@jarry.cc> | 2022-12-11 23:57:30 +0100 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2022-12-14 11:22:53 +0100 |
commit | 9d0297e9d913a92b2d7ae02692e83f0f4093a766 (patch) | |
tree | b34425a8a295b3cc52c4cf20904f85019b6352ab /config/binds.go | |
parent | 2937830491b5adedf79c8c218afb2c80b17c019a (diff) | |
download | aerc-9d0297e9d913a92b2d7ae02692e83f0f4093a766.tar.gz |
config: rework contextual sections implementation
The current contextual binds and ui config API is awkward and cumbersome
to use. Rework it to make it more elegant.
Store the contextual sections as private fields of the UIConfig and
KeyBindings structures. Add cache to avoid recomputation of the composed
UIConfig and KeyBindings objects every time a contextual item is
requested. Replace the cache from DirectoryList with that.
Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Tim Culverhouse <tim@timculverhouse.com>
Diffstat (limited to 'config/binds.go')
-rw-r--r-- | config/binds.go | 90 |
1 files changed, 62 insertions, 28 deletions
diff --git a/config/binds.go b/config/binds.go index 6ddeb1e1..abaff78c 100644 --- a/config/binds.go +++ b/config/binds.go @@ -27,11 +27,17 @@ type BindingConfig struct { Terminal *KeyBindings } +type bindsContextType int + +const ( + bindsContextFolder bindsContextType = iota + bindsContextAccount +) + type BindingConfigContext struct { - ContextType ContextType + ContextType bindsContextType Regex *regexp.Regexp Bindings *KeyBindings - BindContext string } type KeyStroke struct { @@ -47,11 +53,20 @@ type Binding struct { type KeyBindings struct { Bindings []*Binding - // If false, disable global keybindings in this context Globals bool // Which key opens the ex line (default is :) ExKey KeyStroke + + // private + contextualBinds []*BindingConfigContext + contextualCounts map[bindsContextType]int + contextualCache map[bindsContextKey]*KeyBindings +} + +type bindsContextKey struct { + ctxType bindsContextType + value string } const ( @@ -115,13 +130,6 @@ func (config *AercConfig) parseBinds(root string) error { } } - config.Bindings.Global.Globals = false - for _, contextBind := range config.ContextualBinds { - if contextBind.BindContext == "default" { - contextBind.Bindings.Globals = false - } - } - log.Debugf("binds.conf: %#v", config.Bindings) return nil } @@ -168,6 +176,12 @@ func (config *AercConfig) LoadBinds(binds *ini.File, baseName string, baseGroup *baseGroup = MergeBindings(binds, *baseGroup) } + b := *baseGroup + + if baseName == "default" { + b.Globals = false + } + for _, sectionName := range binds.SectionStrings() { if !strings.Contains(sectionName, baseName+":") || strings.Contains(sectionName, baseName+"::") { @@ -183,10 +197,12 @@ func (config *AercConfig) LoadBinds(binds *ini.File, baseName string, baseGroup if err != nil { return err } + if baseName == "default" { + binds.Globals = false + } contextualBind := BindingConfigContext{ - Bindings: binds, - BindContext: baseName, + Bindings: binds, } var index int @@ -215,15 +231,16 @@ func (config *AercConfig) LoadBinds(binds *ini.File, baseName string, baseGroup log.Warnf("binds.conf: unexistent account: %s", acctName) continue } - contextualBind.ContextType = BIND_CONTEXT_ACCOUNT + contextualBind.ContextType = bindsContextAccount case "folder": // No validation needed. If the folder doesn't exist, the binds // never get used - contextualBind.ContextType = BIND_CONTEXT_FOLDER + contextualBind.ContextType = bindsContextFolder default: return fmt.Errorf("Unknown Context Bind Section: %s", sectionName) } - config.ContextualBinds = append(config.ContextualBinds, contextualBind) + b.contextualBinds = append(b.contextualBinds, &contextualBind) + b.contextualCounts[contextualBind.ContextType]++ } return nil @@ -245,8 +262,10 @@ func defaultBindsConfig() BindingConfig { func NewKeyBindings() *KeyBindings { return &KeyBindings{ - ExKey: KeyStroke{tcell.ModNone, tcell.KeyRune, ':'}, - Globals: true, + ExKey: KeyStroke{tcell.ModNone, tcell.KeyRune, ':'}, + Globals: true, + contextualCache: make(map[bindsContextKey]*KeyBindings), + contextualCounts: make(map[bindsContextType]int), } } @@ -260,26 +279,41 @@ func MergeBindings(bindings ...*KeyBindings) *KeyBindings { return merged } -func (config AercConfig) MergeContextualBinds(baseBinds *KeyBindings, - contextType ContextType, reg string, bindCtx string, +func (base *KeyBindings) contextual( + contextType bindsContextType, reg string, ) *KeyBindings { - bindings := baseBinds - for _, contextualBind := range config.ContextualBinds { + if base.contextualCounts[contextType] == 0 { + // shortcut if no contextual binds for that type + return base + } + + key := bindsContextKey{ctxType: contextType, value: reg} + c, found := base.contextualCache[key] + if found { + return c + } + + c = base + for _, contextualBind := range base.contextualBinds { if contextualBind.ContextType != contextType { continue } - if !contextualBind.Regex.Match([]byte(reg)) { continue } + c = MergeBindings(contextualBind.Bindings, c) + } + base.contextualCache[key] = c - if contextualBind.BindContext != bindCtx { - continue - } + return c +} - bindings = MergeBindings(contextualBind.Bindings, bindings) - } - return bindings +func (bindings *KeyBindings) ForAccount(account string) *KeyBindings { + return bindings.contextual(bindsContextAccount, account) +} + +func (bindings *KeyBindings) ForFolder(folder string) *KeyBindings { + return bindings.contextual(bindsContextFolder, folder) } func (bindings *KeyBindings) Add(binding *Binding) { |