detached 3493a07

test(keys): cover alt utf8 state cleanup

commit
3493a0737767bdde4e0139bec649f52b326a08f3
author
brice · · 2026-07-03 21:35 UTC
parent
de4decf
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
1 file · +28 -0
M internal/usecase/keys/router_test.go +28 -0
@@ -89,6 +89,11 @@ func TestRouterInterceptsAltAZERTYUTF8SplitAcrossReads(t *testing.T) {
8989 r.Route([]byte{0xa9})
9090 require.Equal(t, []Action{ActionSwitchTab2}, h.actions)
9191 require.Empty(t, h.forwards)
92+ assertRouterPendingCleared(t, r)
93+
94+ r.Route([]byte{ESC, ' '})
95+ require.Equal(t, []Action{ActionSwitchTab2, ActionOpenPalette}, h.actions)
96+ require.Empty(t, h.forwards)
9297 }
9398
9499 func TestRouterInterceptsRetainedAltAZERTYUTF8SplitAcrossReads(t *testing.T) {
@@ -105,6 +110,11 @@ func TestRouterInterceptsRetainedAltAZERTYUTF8SplitAcrossReads(t *testing.T) {
105110 r.Route([]byte{0xa9})
106111 require.Equal(t, []Action{ActionSwitchTab2}, h.actions)
107112 require.Empty(t, h.forwards)
113+ assertRouterPendingCleared(t, r)
114+
115+ r.Route([]byte{ESC, ' '})
116+ require.Equal(t, []Action{ActionSwitchTab2, ActionOpenPalette}, h.actions)
117+ require.Empty(t, h.forwards)
108118 }
109119
110120 func TestRouterForwardsUnboundAltUTF8SplitAcrossReads(t *testing.T) {
@@ -117,6 +127,11 @@ func TestRouterForwardsUnboundAltUTF8SplitAcrossReads(t *testing.T) {
117127
118128 require.Empty(t, h.actions)
119129 require.Equal(t, [][]byte{{ESC, 0xc3, 0xb1}}, h.forwards)
130+ assertRouterPendingCleared(t, r)
131+
132+ r.Route([]byte("Z"))
133+ require.Empty(t, h.actions)
134+ require.Equal(t, [][]byte{{ESC, 0xc3, 0xb1}, []byte("Z")}, h.forwards)
120135 }
121136
122137 func TestRouterForwardsInvalidSplitAltUTF8WithoutDroppingBytes(t *testing.T) {
@@ -129,6 +144,19 @@ func TestRouterForwardsInvalidSplitAltUTF8WithoutDroppingBytes(t *testing.T) {
129144
130145 require.Empty(t, h.actions)
131146 require.Equal(t, [][]byte{{ESC, 0xc3}, []byte("X")}, h.forwards)
147+ assertRouterPendingCleared(t, r)
148+
149+ r.Route([]byte{ESC, ' '})
150+ require.Equal(t, []Action{ActionOpenPalette}, h.actions)
151+ require.Equal(t, [][]byte{{ESC, 0xc3}, []byte("X")}, h.forwards)
152+}
153+
154+func assertRouterPendingCleared(t *testing.T, r *Router) {
155+ t.Helper()
156+ require.False(t, r.pending)
157+ require.Nil(t, r.pendingAlt)
158+ require.Nil(t, r.timer)
159+ require.Nil(t, r.pendingDone)
132160 }
133161
134162 func TestTopRowDigitIndexAcceptsQWERTYAndAZERTYVariants(t *testing.T) {
@@ -89,6 +89,11 @@ func TestRouterInterceptsAltAZERTYUTF8SplitAcrossReads(t *testing.T) {
89 r.Route([]byte{0xa9})89 r.Route([]byte{0xa9})
90 require.Equal(t, []Action{ActionSwitchTab2}, h.actions)90 require.Equal(t, []Action{ActionSwitchTab2}, h.actions)
91 require.Empty(t, h.forwards)91 require.Empty(t, h.forwards)
92+ assertRouterPendingCleared(t, r)
93+
94+ r.Route([]byte{ESC, ' '})
95+ require.Equal(t, []Action{ActionSwitchTab2, ActionOpenPalette}, h.actions)
96+ require.Empty(t, h.forwards)
92 }97 }
93 98
94 func TestRouterInterceptsRetainedAltAZERTYUTF8SplitAcrossReads(t *testing.T) {99 func TestRouterInterceptsRetainedAltAZERTYUTF8SplitAcrossReads(t *testing.T) {
@@ -105,6 +110,11 @@ func TestRouterInterceptsRetainedAltAZERTYUTF8SplitAcrossReads(t *testing.T) {
105 r.Route([]byte{0xa9})110 r.Route([]byte{0xa9})
106 require.Equal(t, []Action{ActionSwitchTab2}, h.actions)111 require.Equal(t, []Action{ActionSwitchTab2}, h.actions)
107 require.Empty(t, h.forwards)112 require.Empty(t, h.forwards)
113+ assertRouterPendingCleared(t, r)
114+
115+ r.Route([]byte{ESC, ' '})
116+ require.Equal(t, []Action{ActionSwitchTab2, ActionOpenPalette}, h.actions)
117+ require.Empty(t, h.forwards)
108 }118 }
109 119
110 func TestRouterForwardsUnboundAltUTF8SplitAcrossReads(t *testing.T) {120 func TestRouterForwardsUnboundAltUTF8SplitAcrossReads(t *testing.T) {
@@ -117,6 +127,11 @@ func TestRouterForwardsUnboundAltUTF8SplitAcrossReads(t *testing.T) {
117 127
118 require.Empty(t, h.actions)128 require.Empty(t, h.actions)
119 require.Equal(t, [][]byte{{ESC, 0xc3, 0xb1}}, h.forwards)129 require.Equal(t, [][]byte{{ESC, 0xc3, 0xb1}}, h.forwards)
130+ assertRouterPendingCleared(t, r)
131+
132+ r.Route([]byte("Z"))
133+ require.Empty(t, h.actions)
134+ require.Equal(t, [][]byte{{ESC, 0xc3, 0xb1}, []byte("Z")}, h.forwards)
120 }135 }
121 136
122 func TestRouterForwardsInvalidSplitAltUTF8WithoutDroppingBytes(t *testing.T) {137 func TestRouterForwardsInvalidSplitAltUTF8WithoutDroppingBytes(t *testing.T) {
@@ -129,6 +144,19 @@ func TestRouterForwardsInvalidSplitAltUTF8WithoutDroppingBytes(t *testing.T) {
129 144
130 require.Empty(t, h.actions)145 require.Empty(t, h.actions)
131 require.Equal(t, [][]byte{{ESC, 0xc3}, []byte("X")}, h.forwards)146 require.Equal(t, [][]byte{{ESC, 0xc3}, []byte("X")}, h.forwards)
147+ assertRouterPendingCleared(t, r)
148+
149+ r.Route([]byte{ESC, ' '})
150+ require.Equal(t, []Action{ActionOpenPalette}, h.actions)
151+ require.Equal(t, [][]byte{{ESC, 0xc3}, []byte("X")}, h.forwards)
152+}
153+
154+func assertRouterPendingCleared(t *testing.T, r *Router) {
155+ t.Helper()
156+ require.False(t, r.pending)
157+ require.Nil(t, r.pendingAlt)
158+ require.Nil(t, r.timer)
159+ require.Nil(t, r.pendingDone)
132 }160 }
133 161
134 func TestTopRowDigitIndexAcceptsQWERTYAndAZERTYVariants(t *testing.T) {162 func TestTopRowDigitIndexAcceptsQWERTYAndAZERTYVariants(t *testing.T) {

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