Commit 1977d1f1ac4491fe0625c554a4643ecf60b36466

Parents: eadaec1b3c0cc3439f54595d0748e564d4129728

From: Vitaly Ovchinnikov <v@ovch.ru>
Date: Sun Oct 22 16:17:38 2023 +0700

binds: remove duplicated and empty bindings
Add keybindings filtering, so if the context binding is defined, the
parent one is removed and is not shown in the list at all.

Also add keybinding removing, so if the context defines an empty
binding, both this and parent one are removed from the list. This way
you can disable and hide specific bindings in contexts.

Changelog-added: Disable parent context bindings by declaring them empty.
Signed-off-by: Vitaly Ovchinnikov <v@ovch.ru>
Acked-by: Robin Jarry <robin@jarry.cc>

Stats

config/binds.go +48/-0
doc/aerc-binds.5.scd +13/-0

Changeset

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
diff --git a/config/binds.go b/config/binds.go
index 1b2799f2cdb9344f49b2e3c423c9a1418bbd3d13..4552030d626cb9a54a524d6d7963b2e52e67bc1d 100644
--- a/config/binds.go
+++ b/config/binds.go
@@ -272,6 +272,53 @@ 		contextualCounts: make(map[bindsContextType]int),
 	}
 }
 
+func areBindingsInputsEqual(a, b *Binding) bool {
+	if len(a.Input) != len(b.Input) {
+		return false
+	}
+
+	for idx := range a.Input {
+		if a.Input[idx] != b.Input[idx] {
+			return false
+		}
+	}
+
+	return true
+}
+
+// this scans the bindings slice for copies and leaves just the first ones
+// it also removes empty bindings, the ones that do nothing, so you can
+// override and erase parent bindings with the context ones
+func filterAndCleanBindings(bindings []*Binding) []*Binding {
+	// 1. remove a binding if we already have one with the same input
+	res1 := []*Binding{}
+	for _, b := range bindings {
+		// do we already have one here?
+		found := false
+		for _, r := range res1 {
+			if areBindingsInputsEqual(b, r) {
+				found = true
+				break
+			}
+		}
+
+		// add it if we don't
+		if !found {
+			res1 = append(res1, b)
+		}
+	}
+
+	// 2. clean up the empty bindings
+	res2 := []*Binding{}
+	for _, b := range res1 {
+		if len(b.Output) > 0 {
+			res2 = append(res2, b)
+		}
+	}
+
+	return res2
+}
+
 func MergeBindings(bindings ...*KeyBindings) *KeyBindings {
 	merged := NewKeyBindings()
 	for _, b := range bindings {
@@ -280,6 +327,7 @@ 		if !b.Globals {
 			break
 		}
 	}
+	merged.Bindings = filterAndCleanBindings(merged.Bindings)
 	merged.ExKey = bindings[0].ExKey
 	merged.Globals = bindings[0].Globals
 	return merged
diff --git a/doc/aerc-binds.5.scd b/doc/aerc-binds.5.scd
index 8ce59cf0b59318662c1bcb7510cb9402072405d9..f3e44574da0f4f94ea1260be48672c047be5c67e 100644
--- a/doc/aerc-binds.5.scd
+++ b/doc/aerc-binds.5.scd
@@ -87,6 +87,19 @@
 You may also configure global keybindings by placing them at the beginning of
 the file, before specifying any context-specific sections.
 
+Parent keybindings can be erased in the context ones by specifying an "empty"
+binding:
+
+```
+[compose::review]
+a = :attach<space>
+d = :deatch<space>
+
+[compose::review:account=no-attachments]
+a =
+d =
+```
+
 # SPECIAL OPTIONS
 
 In addition of user defined key sequences, the following special options are