client_toast_test.go RawHistoryFolder

1package client
2
3import (
4	"bytes"
5	"regexp"
6	"testing"
7
8	"github.com/stretchr/testify/require"
9
10	renderer "github.com/bnema/vev-vt"
11	"github.com/bnema/vev/internal/domain"
12	"github.com/bnema/vev/internal/usecase/ui"
13)
14
15func TestDrawClientToastPlacement(t *testing.T) {
16	size := domain.Size{Cols: 100, Rows: 30}
17	tests := []struct {
18		name   string
19		anchor domain.Anchor
20		check  func(t *testing.T, bounds domain.Rect)
21	}{
22		{name: "notice sits top-right", anchor: domain.AnchorTopRight, check: func(t *testing.T, bounds domain.Rect) {
23			require.Less(t, bounds.Y, 3)
24			require.Greater(t, bounds.X+bounds.Width, size.Cols-3)
25		}},
26		{name: "transition stays centered", anchor: domain.AnchorCenter, check: func(t *testing.T, bounds domain.Rect) {
27			require.Equal(t, (size.Rows-bounds.Height)/2, bounds.Y)
28			require.Equal(t, (size.Cols-bounds.Width)/2, bounds.X)
29		}},
30	}
31	for _, tt := range tests {
32		t.Run(tt.name, func(t *testing.T) {
33			var out bytes.Buffer
34			bounds, err := drawClientToast(&out, size, "SSH authentication failed", tt.anchor, domain.NoticeInfo)
35			require.NoError(t, err)
36			require.NotZero(t, out.Len())
37			tt.check(t, bounds)
38		})
39	}
40}
41
42func TestClientToastLinesKeepExactWidth(t *testing.T) {
43	sgr := regexp.MustCompile("\x1b\\[[0-9;]*m")
44	tests := []struct {
45		name    string
46		message string
47		border  string
48	}{
49		{name: "ascii", message: "host down"},
50		{name: "wide rune", message: "hôte 東京 down"},
51		{name: "colored border", message: "hôte 東京 down", border: toastBorderSGR(domain.NoticeError)},
52	}
53	for _, tt := range tests {
54		t.Run(tt.name, func(t *testing.T) {
55			bounds := ui.ToastBounds(domain.Size{Cols: 100, Rows: 30}, ui.Toast{Message: tt.message, Anchor: domain.AnchorTopRight})
56			for i, line := range clientToastLines(bounds, tt.message, tt.border) {
57				width := 0
58				for _, r := range sgr.ReplaceAllString(line, "") {
59					width += renderer.RuneWidth(r)
60				}
61				require.Equal(t, bounds.Width, width, "row %d width", i)
62			}
63		})
64	}
65}
66
67func TestDrawClientToastSeverityBorder(t *testing.T) {
68	size := domain.Size{Cols: 100, Rows: 30}
69	tests := []struct {
70		name     string
71		severity domain.NoticeSeverity
72		want     string
73	}{
74		{name: "error border is red", severity: domain.NoticeError, want: "\x1b[38;5;167m"},
75		{name: "warn border is yellow", severity: domain.NoticeWarn, want: "\x1b[38;5;179m"},
76		{name: "info keeps the default color", severity: domain.NoticeInfo},
77	}
78	for _, tt := range tests {
79		t.Run(tt.name, func(t *testing.T) {
80			var out bytes.Buffer
81			_, err := drawClientToast(&out, size, "host down", domain.AnchorTopRight, tt.severity)
82			require.NoError(t, err)
83			if tt.want == "" {
84				require.NotContains(t, out.String(), "\x1b[38;5;")
85				return
86			}
87			require.Contains(t, out.String(), tt.want)
88			require.Contains(t, out.String(), "host down")
89		})
90	}
91}

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