v0.2.1 7bd1a3c

history_acceptance_test.go RawHistoryFolder

1package vt
2
3import (
4	"testing"
5
6	renderer "github.com/bnema/vev-vt/core"
7)
8
9func TestSnapshotCodecsPreserveEveryTerminalCellAcrossHistoryAndRecoveryTranscript(t *testing.T) {
10	indexed := renderer.Style{
11		Bold:              true,
12		Italic:            true,
13		Inverse:           true,
14		Attrs:             renderer.AttrDim | renderer.AttrUnderline | renderer.AttrBlink | renderer.AttrStrikethrough,
15		Foreground:        196,
16		Background:        17,
17		HasUnderlineColor: true,
18		UnderlineColor:    203,
19	}
20	rgb := renderer.Style{
21		Bold:                 true,
22		Italic:               true,
23		Inverse:              true,
24		Attrs:                renderer.AttrDim | renderer.AttrUnderline | renderer.AttrBlink | renderer.AttrStrikethrough,
25		HasForegroundRGB:     true,
26		ForegroundRGB:        renderer.RGB{R: 1, G: 2, B: 3},
27		HasBackgroundRGB:     true,
28		BackgroundRGB:        renderer.RGB{R: 4, G: 5, B: 6},
29		HasUnderlineColorRGB: true,
30		UnderlineColorRGB:    renderer.RGB{R: 7, G: 8, B: 9},
31	}
32	underlines := []renderer.UnderlineStyle{
33		renderer.UnderlineNone,
34		renderer.UnderlineSingle,
35		renderer.UnderlineDouble,
36		renderer.UnderlineCurly,
37		renderer.UnderlineDotted,
38		renderer.UnderlineDashed,
39	}
40	makeRow := func(r rune, style renderer.Style) []renderer.Cell {
41		style.UnderlineStyle = underlines[int(r)%len(underlines)]
42		return []renderer.Cell{
43			{Rune: r, Style: style},
44			{Rune: ' ', Style: renderer.DefaultStyle()},
45			{Rune: '界', Style: style},
46			{Continuation: true, Style: style},
47		}
48	}
49
50	tests := []struct {
51		name string
52		run  func(*testing.T)
53	}{
54		{
55			name: "history view retains sealed chunks and mutable tail",
56			run: func(t *testing.T) {
57				history := NewHistory(HistoryConfig{MaxRows: 8, ChunkRows: 2})
58				// A through F exercise every underline style; G remains in the
59				// mutable tail so both history ownership paths are encoded.
60				want := [][]renderer.Cell{
61					makeRow('A', indexed), makeRow('B', rgb), makeRow('C', indexed),
62					makeRow('D', rgb), makeRow('E', indexed), makeRow('F', rgb), makeRow('G', indexed),
63				}
64				for _, row := range want {
65					requireHistoryAppend(t, history, row)
66				}
67				if got, wantChunks := history.View().ChunkCount(), 4; got != wantChunks {
68					t.Fatalf("chunk count = %d, want three sealed chunks plus copied tail %d", got, wantChunks)
69				}
70				encoded, err := MarshalHistory(history.View())
71				if err != nil {
72					t.Fatalf("MarshalHistory: %v", err)
73				}
74				got, err := UnmarshalHistory(encoded)
75				if err != nil {
76					t.Fatalf("UnmarshalHistory: %v", err)
77				}
78				assertHistoryRowsEqual(t, got, want)
79			},
80		},
81		{
82			name: "recovery transcript retains blanks wide heads continuations and styles",
83			run: func(t *testing.T) {
84				screen := NewScreen(4, 2)
85				want := [][]renderer.Cell{makeRow('D', rgb), makeRow('E', indexed)}
86				for y, row := range want {
87					copy(screen.Frame.Row(y), row)
88					screen.buffer.boundaries[y] = LineBound{End: len(row)}
89				}
90
91				encoded, err := screen.RecoveryTranscriptSnapshot().Marshal()
92				if err != nil {
93					t.Fatalf("marshal recovery transcript: %v", err)
94				}
95				got, err := UnmarshalHistory(encoded)
96				if err != nil {
97					t.Fatalf("unmarshal recovery transcript: %v", err)
98				}
99				assertHistoryRowsEqual(t, got, want)
100			},
101		},
102	}
103	for _, tt := range tests {
104		t.Run(tt.name, tt.run)
105	}
106}

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