v0.6.0 b250c5e

screen_keyboard_test.go RawHistoryFolder

1package vt
2
3import (
4	"strings"
5	"testing"
6
7	"github.com/stretchr/testify/require"
8)
9
10func TestScreenKittyKeyboardFlags(t *testing.T) {
11	tests := []struct {
12		name  string
13		input string
14		want  int
15	}{
16		{name: "default", input: "", want: 0},
17		{name: "push", input: "\x1b[>1u", want: 1},
18		{name: "push without flags", input: "\x1b[>u", want: 0},
19		{name: "push masks unknown bits", input: "\x1b[>255u", want: 31},
20		{name: "push twice", input: "\x1b[>1u\x1b[>11u", want: 11},
21		{name: "pop default one", input: "\x1b[>1u\x1b[>11u\x1b[<u", want: 1},
22		{name: "pop n", input: "\x1b[>1u\x1b[>3u\x1b[>11u\x1b[<2u", want: 1},
23		{name: "pop past empty", input: "\x1b[>1u\x1b[<5u", want: 0},
24		{name: "pop empty", input: "\x1b[<u", want: 0},
25		{name: "set replace on empty", input: "\x1b[=5u", want: 5},
26		{name: "set replace", input: "\x1b[>1u\x1b[=8;1u", want: 8},
27		{name: "set or", input: "\x1b[>1u\x1b[=8;2u", want: 9},
28		{name: "set clear", input: "\x1b[>11u\x1b[=2;3u", want: 9},
29		{name: "set unknown mode ignored", input: "\x1b[>1u\x1b[=8;4u", want: 1},
30		{name: "set replaces top only", input: "\x1b[>1u\x1b[>2u\x1b[=4u\x1b[<u", want: 1},
31		{name: "malformed flags are zero", input: "\x1b[>xu", want: 0},
32		{name: "plain CSI u restores cursor only", input: "\x1b[>3u\x1b[u", want: 3},
33		{name: "RIS resets", input: "\x1b[>3u\x1bc", want: 0},
34		{name: "alternate screen has its own stack", input: "\x1b[>1u\x1b[?1049h", want: 0},
35		{name: "alternate screen push", input: "\x1b[>1u\x1b[?1049h\x1b[>15u", want: 15},
36		{name: "leaving alternate restores main stack", input: "\x1b[>1u\x1b[?1049h\x1b[>15u\x1b[?1049l", want: 1},
37	}
38	for _, tt := range tests {
39		t.Run(tt.name, func(t *testing.T) {
40			s := NewScreen(10, 3)
41			s.Write([]byte(tt.input))
42			require.Equal(t, tt.want, s.KittyKeyboardFlags())
43			require.Equal(t, tt.want, s.Snapshot().Modes().KittyKeyboard)
44		})
45	}
46}
47
48func TestScreenKittyKeyboardStackIsBounded(t *testing.T) {
49	s := NewScreen(10, 3)
50	s.Write([]byte("\x1b[>1u"))
51	s.Write([]byte(strings.Repeat("\x1b[>2u", maxKittyKeyboardStack)))
52	require.Len(t, s.kittyKeyboard, maxKittyKeyboardStack)
53	s.Write([]byte(strings.Repeat("\x1b[<u", maxKittyKeyboardStack-1)))
54	require.Equal(t, 2, s.KittyKeyboardFlags(), "oldest entry was evicted")
55	s.Write([]byte("\x1b[<u"))
56	require.Equal(t, 0, s.KittyKeyboardFlags())
57}
58
59func TestScreenKittyKeyboardQuery(t *testing.T) {
60	tests := []struct {
61		name  string
62		input string
63		want  []string
64	}{
65		{name: "empty", input: "\x1b[?u", want: []string{"\x1b[?0u"}},
66		{name: "after push", input: "\x1b[>11u\x1b[?u", want: []string{"\x1b[?11u"}},
67		{name: "with params is ignored", input: "\x1b[?1u", want: nil},
68		{name: "split across writes", input: "\x1b[>3u\x1b[?", want: nil},
69	}
70	for _, tt := range tests {
71		t.Run(tt.name, func(t *testing.T) {
72			s := NewScreen(10, 3)
73			var got []string
74			s.OnResponse = func(b []byte) { got = append(got, string(b)) }
75			s.Write([]byte(tt.input))
76			require.Equal(t, tt.want, got)
77		})
78	}
79}

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 2

Tags 13

↑↓ moveenter openesc close