1package keys
2
3import "unicode/utf8"
4
5// Bindings maps intercepted Alt keys to actions. A Bindings value is mutable
6// while being built, then treated as frozen once published through an atomic
7// pointer; callers must clone before using mutators.
8type Bindings struct {
9 altRunes map[rune]Action
10 altArrows map[byte]Action
11}
12
13var defaultBindings = DefaultBindings()
14
15// DefaultBindings returns vev's built-in Alt-key bindings.
16func DefaultBindings() *Bindings {
17 altRunes := map[rune]Action{
18 ' ': ActionOpenPalette,
19 'a': ActionJumpAttention,
20 'f': ActionToggleFloatingPane,
21 'h': ActionFocusPaneLeft,
22 'j': ActionFocusPaneDown,
23 'k': ActionFocusPaneUp,
24 'l': ActionFocusPaneRight,
25 }
26 for idx, aliases := range topRowDigitAliases {
27 for _, alias := range aliases {
28 altRunes[alias] = ActionSwitchTab1 + Action(idx)
29 }
30 }
31 return &Bindings{
32 altRunes: altRunes,
33 altArrows: map[byte]Action{
34 'A': ActionFocusPaneUp,
35 'B': ActionFocusPaneDown,
36 'C': ActionFocusPaneRight,
37 'D': ActionFocusPaneLeft,
38 },
39 }
40}
41
42func (b *Bindings) clone() *Bindings {
43 if b == nil {
44 return DefaultBindings()
45 }
46 clone := &Bindings{
47 altRunes: make(map[rune]Action, len(b.altRunes)),
48 altArrows: make(map[byte]Action, len(b.altArrows)),
49 }
50 for key, action := range b.altRunes {
51 clone.altRunes[key] = action
52 }
53 for key, action := range b.altArrows {
54 clone.altArrows[key] = action
55 }
56 return clone
57}
58
59func (b *Bindings) removeAction(action Action) {
60 for key, bound := range b.altRunes {
61 if bound == action {
62 delete(b.altRunes, key)
63 }
64 }
65 for key, bound := range b.altArrows {
66 if bound == action {
67 delete(b.altArrows, key)
68 }
69 }
70}
71
72func (b *Bindings) bind(action Action, spec KeySpec) {
73 for _, key := range spec.altRunes {
74 b.altRunes[key] = action
75 }
76 if spec.altArrow != 0 {
77 b.altArrows[spec.altArrow] = action
78 }
79}
80
81func (b *Bindings) restoreDefaultAction(action Action) {
82 defaults := DefaultBindings()
83 for key, bound := range defaults.altRunes {
84 if bound == action {
85 if _, occupied := b.altRunes[key]; !occupied {
86 b.altRunes[key] = action
87 }
88 }
89 }
90 for key, bound := range defaults.altArrows {
91 if bound == action {
92 if _, occupied := b.altArrows[key]; !occupied {
93 b.altArrows[key] = action
94 }
95 }
96 }
97}
98
99func (b *Bindings) conflictingAction(spec KeySpec, action Action) (Action, bool) {
100 for _, key := range spec.altRunes {
101 if bound, ok := b.altRunes[key]; ok && bound != action {
102 return bound, true
103 }
104 }
105 if spec.altArrow != 0 {
106 if bound, ok := b.altArrows[spec.altArrow]; ok && bound != action {
107 return bound, true
108 }
109 }
110 return 0, false
111}
112
113func (b *Bindings) actionForAltBytes(data []byte) (Action, int, bool) {
114 if b == nil {
115 b = defaultBindings
116 }
117 if len(data) == 0 {
118 return 0, 0, false
119 }
120 key, size := utf8.DecodeRune(data)
121 if key == utf8.RuneError && size == 1 {
122 return 0, 0, false
123 }
124 action, ok := b.altRunes[key]
125 return action, size, ok
126}
127
128func (b *Bindings) actionForAltArrow(final byte) (Action, bool) {
129 if b == nil {
130 b = defaultBindings
131 }
132 action, ok := b.altArrows[final]
133 return action, ok
134}