aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Jarry <robin@jarry.cc>2022-11-14 11:54:31 +0100
committerRobin Jarry <robin@jarry.cc>2022-11-16 16:11:54 +0100
commit46e027bde57204a2383193bd35cabcd0a5dfaaf8 (patch)
treeea608855629cf941ac72154e23018d16e7225773
parent5402bfef76ed6d0cb9a89fc9d0ea6bda72dcc288 (diff)
downloadaerc-46e027bde57204a2383193bd35cabcd0a5dfaaf8.tar.gz
config: move binds.conf parsing in binds.go
The config.go file is getting too big. Move all binds.conf parsing logic into binds.go where it belongs. No functional change. Signed-off-by: Robin Jarry <robin@jarry.cc> Acked-by: Moritz Poldrack <moritz@poldrack.dev>
-rw-r--r--config/binds.go205
-rw-r--r--config/config.go193
2 files changed, 207 insertions, 191 deletions
diff --git a/config/binds.go b/config/binds.go
index 7816296a..63fc335a 100644
--- a/config/binds.go
+++ b/config/binds.go
@@ -5,11 +5,35 @@ import (
"errors"
"fmt"
"io"
+ "os"
+ "path"
+ "regexp"
"strings"
+ "git.sr.ht/~rjarry/aerc/logging"
"github.com/gdamore/tcell/v2"
+ "github.com/go-ini/ini"
)
+type BindingConfig struct {
+ Global *KeyBindings
+ AccountWizard *KeyBindings
+ Compose *KeyBindings
+ ComposeEditor *KeyBindings
+ ComposeReview *KeyBindings
+ MessageList *KeyBindings
+ MessageView *KeyBindings
+ MessageViewPassthrough *KeyBindings
+ Terminal *KeyBindings
+}
+
+type BindingConfigContext struct {
+ ContextType ContextType
+ Regex *regexp.Regexp
+ Bindings *KeyBindings
+ BindContext string
+}
+
type KeyStroke struct {
Modifiers tcell.ModMask
Key tcell.Key
@@ -38,6 +62,187 @@ const (
type BindingSearchResult int
+func (config *AercConfig) parseBinds(root string) error {
+ // These bindings are not configurable
+ config.Bindings.AccountWizard.ExKey = KeyStroke{
+ Key: tcell.KeyCtrlE,
+ }
+ quit, _ := ParseBinding("<C-q>", ":quit<Enter>")
+ config.Bindings.AccountWizard.Add(quit)
+
+ filename := path.Join(root, "binds.conf")
+ if _, err := os.Stat(filename); errors.Is(err, os.ErrNotExist) {
+ logging.Debugf("%s not found, installing the system default", filename)
+ if err := installTemplate(root, "binds.conf"); err != nil {
+ return err
+ }
+ }
+ logging.Infof("Parsing key bindings configuration from %s", filename)
+ binds, err := ini.Load(filename)
+ if err != nil {
+ return err
+ }
+
+ baseGroups := map[string]**KeyBindings{
+ "default": &config.Bindings.Global,
+ "compose": &config.Bindings.Compose,
+ "messages": &config.Bindings.MessageList,
+ "terminal": &config.Bindings.Terminal,
+ "view": &config.Bindings.MessageView,
+ "view::passthrough": &config.Bindings.MessageViewPassthrough,
+ "compose::editor": &config.Bindings.ComposeEditor,
+ "compose::review": &config.Bindings.ComposeReview,
+ }
+
+ // Base Bindings
+ for _, sectionName := range binds.SectionStrings() {
+ // Handle :: delimeter
+ baseSectionName := strings.ReplaceAll(sectionName, "::", "////")
+ sections := strings.Split(baseSectionName, ":")
+ baseOnly := len(sections) == 1
+ baseSectionName = strings.ReplaceAll(sections[0], "////", "::")
+
+ group, ok := baseGroups[strings.ToLower(baseSectionName)]
+ if !ok {
+ return errors.New("Unknown keybinding group " + sectionName)
+ }
+
+ if baseOnly {
+ err = config.LoadBinds(binds, baseSectionName, group)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ config.Bindings.Global.Globals = false
+ for _, contextBind := range config.ContextualBinds {
+ if contextBind.BindContext == "default" {
+ contextBind.Bindings.Globals = false
+ }
+ }
+
+ logging.Debugf("binds.conf: %#v", config.Bindings)
+ return nil
+}
+
+func LoadBindingSection(sec *ini.Section) (*KeyBindings, error) {
+ bindings := NewKeyBindings()
+ for key, value := range sec.KeysHash() {
+ if key == "$ex" {
+ strokes, err := ParseKeyStrokes(value)
+ if err != nil {
+ return nil, err
+ }
+ if len(strokes) != 1 {
+ return nil, errors.New("Invalid binding")
+ }
+ bindings.ExKey = strokes[0]
+ continue
+ }
+ if key == "$noinherit" {
+ if value == "false" {
+ continue
+ }
+ if value != "true" {
+ return nil, errors.New("Invalid binding")
+ }
+ bindings.Globals = false
+ continue
+ }
+ binding, err := ParseBinding(key, value)
+ if err != nil {
+ return nil, err
+ }
+ bindings.Add(binding)
+ }
+ return bindings, nil
+}
+
+func (config *AercConfig) LoadBinds(binds *ini.File, baseName string, baseGroup **KeyBindings) error {
+ if sec, err := binds.GetSection(baseName); err == nil {
+ binds, err := LoadBindingSection(sec)
+ if err != nil {
+ return err
+ }
+ *baseGroup = MergeBindings(binds, *baseGroup)
+ }
+
+ for _, sectionName := range binds.SectionStrings() {
+ if !strings.Contains(sectionName, baseName+":") ||
+ strings.Contains(sectionName, baseName+"::") {
+ continue
+ }
+
+ bindSection, err := binds.GetSection(sectionName)
+ if err != nil {
+ return err
+ }
+
+ binds, err := LoadBindingSection(bindSection)
+ if err != nil {
+ return err
+ }
+
+ contextualBind := BindingConfigContext{
+ Bindings: binds,
+ BindContext: baseName,
+ }
+
+ var index int
+ if strings.Contains(sectionName, "=") {
+ index = strings.Index(sectionName, "=")
+ value := string(sectionName[index+1:])
+ contextualBind.Regex, err = regexp.Compile(value)
+ if err != nil {
+ return err
+ }
+ } else {
+ return fmt.Errorf("Invalid Bind Context regex in %s", sectionName)
+ }
+
+ switch sectionName[len(baseName)+1 : index] {
+ case "account":
+ acctName := sectionName[index+1:]
+ valid := false
+ for _, acctConf := range config.Accounts {
+ matches := contextualBind.Regex.FindString(acctConf.Name)
+ if matches != "" {
+ valid = true
+ }
+ }
+ if !valid {
+ logging.Warnf("binds.conf: unexistent account: %s", acctName)
+ continue
+ }
+ contextualBind.ContextType = BIND_CONTEXT_ACCOUNT
+ case "folder":
+ // No validation needed. If the folder doesn't exist, the binds
+ // never get used
+ contextualBind.ContextType = BIND_CONTEXT_FOLDER
+ default:
+ return fmt.Errorf("Unknown Context Bind Section: %s", sectionName)
+ }
+ config.ContextualBinds = append(config.ContextualBinds, contextualBind)
+ }
+
+ return nil
+}
+
+func defaultBindsConfig() BindingConfig {
+ return BindingConfig{
+ Global: NewKeyBindings(),
+ AccountWizard: NewKeyBindings(),
+ Compose: NewKeyBindings(),
+ ComposeEditor: NewKeyBindings(),
+ ComposeReview: NewKeyBindings(),
+ MessageList: NewKeyBindings(),
+ MessageView: NewKeyBindings(),
+ MessageViewPassthrough: NewKeyBindings(),
+ Terminal: NewKeyBindings(),
+ }
+}
+
func NewKeyBindings() *KeyBindings {
return &KeyBindings{
ExKey: KeyStroke{tcell.ModNone, tcell.KeyRune, ':'},
diff --git a/config/config.go b/config/config.go
index 6a16234b..7a880b6d 100644
--- a/config/config.go
+++ b/config/config.go
@@ -102,25 +102,6 @@ const (
FILTER_HEADER
)
-type BindingConfig struct {
- Global *KeyBindings
- AccountWizard *KeyBindings
- Compose *KeyBindings
- ComposeEditor *KeyBindings
- ComposeReview *KeyBindings
- MessageList *KeyBindings
- MessageView *KeyBindings
- MessageViewPassthrough *KeyBindings
- Terminal *KeyBindings
-}
-
-type BindingConfigContext struct {
- ContextType ContextType
- Regex *regexp.Regexp
- Bindings *KeyBindings
- BindContext string
-}
-
type ComposeConfig struct {
Editor string `ini:"editor"`
HeaderLayout [][]string `ini:"-"`
@@ -557,17 +538,7 @@ func LoadConfigFromFile(root *string, accts []string) (*AercConfig, error) {
}
file.NameMapper = mapName
config := &AercConfig{
- Bindings: BindingConfig{
- Global: NewKeyBindings(),
- AccountWizard: NewKeyBindings(),
- Compose: NewKeyBindings(),
- ComposeEditor: NewKeyBindings(),
- ComposeReview: NewKeyBindings(),
- MessageList: NewKeyBindings(),
- MessageView: NewKeyBindings(),
- MessageViewPassthrough: NewKeyBindings(),
- Terminal: NewKeyBindings(),
- },
+ Bindings: defaultBindsConfig(),
ContextualBinds: []BindingConfigContext{},
@@ -656,13 +627,6 @@ func LoadConfigFromFile(root *string, accts []string) (*AercConfig, error) {
Openers: make(map[string][]string),
}
- // These bindings are not configurable
- config.Bindings.AccountWizard.ExKey = KeyStroke{
- Key: tcell.KeyCtrlE,
- }
- quit, _ := ParseBinding("<C-q>", ":quit<Enter>")
- config.Bindings.AccountWizard.Add(quit)
-
if err = config.LoadConfig(file); err != nil {
return nil, err
}
@@ -689,166 +653,13 @@ func LoadConfigFromFile(root *string, accts []string) (*AercConfig, error) {
if err := config.parseAccounts(*root, accts); err != nil {
return nil, err
}
-
- filename = path.Join(*root, "binds.conf")
- if _, err := os.Stat(filename); errors.Is(err, os.ErrNotExist) {
- logging.Debugf("%s not found, installing the system default", filename)
- if err := installTemplate(*root, "binds.conf"); err != nil {
- return nil, err
- }
- }
- logging.Infof("Parsing key bindings configuration from %s", filename)
- binds, err := ini.Load(filename)
- if err != nil {
+ if err := config.parseBinds(*root); err != nil {
return nil, err
}
- baseGroups := map[string]**KeyBindings{
- "default": &config.Bindings.Global,
- "compose": &config.Bindings.Compose,
- "messages": &config.Bindings.MessageList,
- "terminal": &config.Bindings.Terminal,
- "view": &config.Bindings.MessageView,
- "view::passthrough": &config.Bindings.MessageViewPassthrough,
- "compose::editor": &config.Bindings.ComposeEditor,
- "compose::review": &config.Bindings.ComposeReview,
- }
-
- // Base Bindings
- for _, sectionName := range binds.SectionStrings() {
- // Handle :: delimeter
- baseSectionName := strings.ReplaceAll(sectionName, "::", "////")
- sections := strings.Split(baseSectionName, ":")
- baseOnly := len(sections) == 1
- baseSectionName = strings.ReplaceAll(sections[0], "////", "::")
-
- group, ok := baseGroups[strings.ToLower(baseSectionName)]
- if !ok {
- return nil, errors.New("Unknown keybinding group " + sectionName)
- }
-
- if baseOnly {
- err = config.LoadBinds(binds, baseSectionName, group)
- if err != nil {
- return nil, err
- }
- }
- }
-
- config.Bindings.Global.Globals = false
- for _, contextBind := range config.ContextualBinds {
- if contextBind.BindContext == "default" {
- contextBind.Bindings.Globals = false
- }
- }
- logging.Debugf("binds.conf: %#v", config.Bindings)
-
return config, nil
}
-func LoadBindingSection(sec *ini.Section) (*KeyBindings, error) {
- bindings := NewKeyBindings()
- for key, value := range sec.KeysHash() {
- if key == "$ex" {
- strokes, err := ParseKeyStrokes(value)
- if err != nil {
- return nil, err
- }
- if len(strokes) != 1 {
- return nil, errors.New("Invalid binding")
- }
- bindings.ExKey = strokes[0]
- continue
- }
- if key == "$noinherit" {
- if value == "false" {
- continue
- }
- if value != "true" {
- return nil, errors.New("Invalid binding")
- }
- bindings.Globals = false
- continue
- }
- binding, err := ParseBinding(key, value)
- if err != nil {
- return nil, err
- }
- bindings.Add(binding)
- }
- return bindings, nil
-}
-
-func (config *AercConfig) LoadBinds(binds *ini.File, baseName string, baseGroup **KeyBindings) error {
- if sec, err := binds.GetSection(baseName); err == nil {
- binds, err := LoadBindingSection(sec)
- if err != nil {
- return err
- }
- *baseGroup = MergeBindings(binds, *baseGroup)
- }
-
- for _, sectionName := range binds.SectionStrings() {
- if !strings.Contains(sectionName, baseName+":") ||
- strings.Contains(sectionName, baseName+"::") {
- continue
- }
-
- bindSection, err := binds.GetSection(sectionName)
- if err != nil {
- return err
- }
-
- binds, err := LoadBindingSection(bindSection)
- if err != nil {
- return err
- }
-
- contextualBind := BindingConfigContext{
- Bindings: binds,
- BindContext: baseName,
- }
-
- var index int
- if strings.Contains(sectionName, "=") {
- index = strings.Index(sectionName, "=")
- value := string(sectionName[index+1:])
- contextualBind.Regex, err = regexp.Compile(value)
- if err != nil {
- return err
- }
- } else {
- return fmt.Errorf("Invalid Bind Context regex in %s", sectionName)
- }
-
- switch sectionName[len(baseName)+1 : index] {
- case "account":
- acctName := sectionName[index+1:]
- valid := false
- for _, acctConf := range config.Accounts {
- matches := contextualBind.Regex.FindString(acctConf.Name)
- if matches != "" {
- valid = true
- }
- }
- if !valid {
- logging.Warnf("binds.conf: unexistent account: %s", acctName)
- continue
- }
- contextualBind.ContextType = BIND_CONTEXT_ACCOUNT
- case "folder":
- // No validation needed. If the folder doesn't exist, the binds
- // never get used
- contextualBind.ContextType = BIND_CONTEXT_FOLDER
- default:
- return fmt.Errorf("Unknown Context Bind Section: %s", sectionName)
- }
- config.ContextualBinds = append(config.ContextualBinds, contextualBind)
- }
-
- return nil
-}
-
func parseLayout(layout string) [][]string {
rows := strings.Split(layout, ",")
l := make([][]string, len(rows))