v0.3.0 99dc266

bindings.go RawHistoryFolder

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}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close