v0.2.85 6b4f716

partialjson_test.go RawHistoryFolder

1package tui
2
3import "testing"
4
5func TestExtractLastNewText(t *testing.T) {
6	cases := []struct {
7		name      string
8		raw       string
9		wantValue string
10		wantOK    bool
11		wantDone  bool
12		wantIdx   int
13	}{
14		{
15			name:      "no newText yet",
16			raw:       `{"path":"/x","edits":[{"oldText":"a"}`,
17			wantValue: "",
18			wantOK:    false,
19			wantDone:  false,
20			wantIdx:   0,
21		},
22		{
23			name:      "single newText partial",
24			raw:       `{"edits":[{"oldText":"a","newText":"b`,
25			wantValue: "b",
26			wantOK:    true,
27			wantDone:  false,
28			wantIdx:   1,
29		},
30		{
31			name:      "single newText complete",
32			raw:       `{"edits":[{"oldText":"a","newText":"b"}]`,
33			wantValue: "b",
34			wantOK:    true,
35			wantDone:  true,
36			wantIdx:   1,
37		},
38		{
39			name:      "two edits, second still streaming",
40			raw:       `{"edits":[{"oldText":"x","newText":"y"},{"oldText":"a","newText":"hello wor`,
41			wantValue: "hello wor",
42			wantOK:    true,
43			wantDone:  false,
44			wantIdx:   2,
45		},
46	}
47	for _, c := range cases {
48		t.Run(c.name, func(t *testing.T) {
49			v, ok, done, idx := ExtractLastNewText(c.raw)
50			if v != c.wantValue || ok != c.wantOK || done != c.wantDone || idx != c.wantIdx {
51				t.Errorf("want (v=%q ok=%v done=%v idx=%d), got (v=%q ok=%v done=%v idx=%d)",
52					c.wantValue, c.wantOK, c.wantDone, c.wantIdx, v, ok, done, idx)
53			}
54		})
55	}
56}
57
58func TestExtractPartialStringField(t *testing.T) {
59	cases := []struct {
60		name      string
61		raw       string
62		field     string
63		wantValue string
64		wantOK    bool
65		wantDone  bool
66	}{
67		{
68			name:      "empty buffer",
69			raw:       "",
70			field:     "content",
71			wantValue: "",
72			wantOK:    false,
73			wantDone:  false,
74		},
75		{
76			name:      "no such field",
77			raw:       `{"path":"/x","foo":"bar"}`,
78			field:     "content",
79			wantValue: "",
80			wantOK:    false,
81			wantDone:  false,
82		},
83		{
84			name:      "complete",
85			raw:       `{"path":"/x","content":"hello"}`,
86			field:     "content",
87			wantValue: "hello",
88			wantOK:    true,
89			wantDone:  true,
90		},
91		{
92			name:      "partial mid-word",
93			raw:       `{"path":"/x","content":"hel`,
94			field:     "content",
95			wantValue: "hel",
96			wantOK:    true,
97			wantDone:  false,
98		},
99		{
100			name:      "escaped quote",
101			raw:       `{"content":"say \"hi\""}`,
102			field:     "content",
103			wantValue: `say "hi"`,
104			wantOK:    true,
105			wantDone:  true,
106		},
107		{
108			name:      "escaped newline inside string",
109			raw:       `{"content":"line1\nline2"}`,
110			field:     "content",
111			wantValue: "line1\nline2",
112			wantOK:    true,
113			wantDone:  true,
114		},
115		{
116			name:      "trailing backslash (unfinished escape)",
117			raw:       `{"content":"line1\`,
118			field:     "content",
119			wantValue: "line1",
120			wantOK:    true,
121			wantDone:  false,
122		},
123		{
124			name:      "incomplete unicode escape",
125			raw:       `{"content":"before\u00`,
126			field:     "content",
127			wantValue: "before",
128			wantOK:    true,
129			wantDone:  false,
130		},
131		{
132			name:      "key before value",
133			raw:       `{"content":`,
134			field:     "content",
135			wantValue: "",
136			wantOK:    false,
137			wantDone:  false,
138		},
139	}
140
141	for _, c := range cases {
142		t.Run(c.name, func(t *testing.T) {
143			v, ok, done := ExtractPartialStringField(c.raw, c.field)
144			if v != c.wantValue {
145				t.Errorf("value: want %q, got %q", c.wantValue, v)
146			}
147			if ok != c.wantOK {
148				t.Errorf("ok: want %v, got %v", c.wantOK, ok)
149			}
150			if done != c.wantDone {
151				t.Errorf("done: want %v, got %v", c.wantDone, done)
152			}
153		})
154	}
155}

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 1

Tags 476

↑↓ moveenter openesc close