hint_labels_test.go RawHistoryFolder

1package vulkan
2
3import (
4	"image"
5	"math"
6	"testing"
7
8	"github.com/stretchr/testify/require"
9
10	"github.com/bnema/neferwl/internal/ports"
11)
12
13func TestHintLabelsDrawnAfterIndicators(t *testing.T) {
14	r, err := New(256, 256)
15	if err != nil {
16		t.Skipf("Vulkan unavailable: %v", err)
17	}
18	defer r.Close()
19	for _, scale := range []int{1, 2} {
20		s := ports.Scene{Scale: float64(scale),
21			CaptureIndicators: []ports.CaptureIndicator{{Rect: ports.Rect{W: 64, H: 64}}},
22			HintLabels: []ports.HintLabel{
23				{Rect: ports.Rect{X: 80, Y: 90}, Text: "f"},
24				{Rect: ports.Rect{X: 100, Y: 110}, Text: "jk", Typed: 1},
25			}}
26		bare := s
27		bare.HintLabels = nil
28		before := len(r.draws(bare, nil, newDamage(&target{}, bare, image.Rect(0, 0, 256, 256))))
29		ds := r.draws(s, nil, newDamage(&target{}, s, image.Rect(0, 0, 256, 256)))
30		require.Len(t, ds, before+2, "one draw per label, after the indicator's")
31		for i, tl := range []image.Point{{80 * scale, 90 * scale}, {100 * scale, 110 * scale}} {
32			d := ds[before+i]
33			require.NotNil(t, d.shm)
34			lw, lh := int(d.pc.rect[2]-d.pc.rect[0]), int(d.pc.rect[3]-d.pc.rect[1])
35			inset := int(math.Round(0.25 * float64(lh)))
36			require.Equal(t, int32(tl.X-lw+inset), d.pc.rect[0])
37			require.Equal(t, int32(tl.Y-lh+inset), d.pc.rect[1])
38			require.Greater(t, d.pc.rect[2], d.pc.rect[0])
39			require.Greater(t, d.pc.rect[3], d.pc.rect[1])
40			require.Equal(t, float32(1), d.pc.color[3])
41		}
42	}
43}
44
45func TestHintLabelsAnchoredAndClampedAtTopLeft(t *testing.T) {
46	r, err := New(128, 128)
47	if err != nil {
48		t.Skipf("Vulkan unavailable: %v", err)
49	}
50	defer r.Close()
51	// A target at the origin puts the anchor off-screen: clamped to 0,0.
52	s := ports.Scene{Scale: 1, HintLabels: []ports.HintLabel{{Rect: ports.Rect{X: 0, Y: 0}, Text: "f"}, {Rect: ports.Rect{X: 60, Y: 60}, Text: "f"}}}
53	ds := r.draws(s, nil, newDamage(&target{}, s, image.Rect(0, 0, 128, 128)))
54	require.Len(t, ds, 2)
55	require.Equal(t, int32(0), ds[0].pc.rect[0])
56	require.Equal(t, int32(0), ds[0].pc.rect[1])
57	lw, lh := int(ds[1].pc.rect[2]-ds[1].pc.rect[0]), int(ds[1].pc.rect[3]-ds[1].pc.rect[1])
58	inset := int(math.Round(0.25 * float64(lh)))
59	require.Equal(t, int32(60-lw+inset), ds[1].pc.rect[0])
60	require.Equal(t, int32(60-lh+inset), ds[1].pc.rect[1])
61	require.Less(t, int(ds[1].pc.rect[2]), 60+lw, "label sits left of the target, mostly outside it")
62}
63
64func TestHintLabelsAbsentDrawNothing(t *testing.T) {
65	r := &Renderer{width: 64, height: 64}
66	s := ports.Scene{Scale: 1}
67	require.Empty(t, r.draws(s, nil, newDamage(&target{}, s, image.Rect(0, 0, 64, 64))))
68}
69
70func TestHintLabelsClampedInsideOutput(t *testing.T) {
71	r, err := New(128, 128)
72	if err != nil {
73		t.Skipf("Vulkan unavailable: %v", err)
74	}
75	defer r.Close()
76	s := ports.Scene{Scale: 1, HintStyle: ports.HintStyle{Size: 40}, HintLabels: []ports.HintLabel{{Rect: ports.Rect{X: 127, Y: 127}, Text: "ff"}}}
77	ds := r.draws(s, nil, newDamage(&target{}, s, image.Rect(0, 0, 128, 128)))
78	require.Len(t, ds, 1)
79	require.LessOrEqual(t, ds[0].pc.rect[2], int32(128))
80	require.LessOrEqual(t, ds[0].pc.rect[3], int32(128))
81}
82
83func TestHintLabelsRenderAndUploadOnce(t *testing.T) {
84	r, err := New(128, 128)
85	if err != nil {
86		t.Skipf("Vulkan unavailable: %v", err)
87	}
88	defer r.Close()
89	s := ports.Scene{Scale: 1, Seq: 1, HintLabels: []ports.HintLabel{{Rect: ports.Rect{X: 4, Y: 4}, Text: "fj"}}}
90	require.NoError(t, render(r, s, nil))
91	first := r.copied
92	require.Positive(t, first)
93	s.Seq = 2
94	require.NoError(t, render(r, s, nil))
95	require.Equal(t, first, r.copied, "an unchanged label is not uploaded again")
96	s.HintStyle.Size = 26
97	s.Seq++
98	require.NoError(t, render(r, s, nil))
99	require.Greater(t, r.copied, first, "size reload uploads a new raster")
100	sized := r.copied
101	s.HintStyle.Background = "#89b4fa"
102	s.Seq++
103	require.NoError(t, render(r, s, nil))
104	require.Greater(t, r.copied, sized, "colour reload uploads a new raster")
105}
106
107func TestHintSceneDeltaOnlyHintLabelsChange(t *testing.T) {
108	phys := func(r ports.Rect) image.Rectangle { return image.Rect(r.X, r.Y, r.X+r.W, r.Y+r.H) }
109	base := ports.Scene{Scale: 1, OutputWidth: 100, OutputHeight: 100}
110	with := base
111	with.HintLabels = []ports.HintLabel{{Rect: ports.Rect{X: 1, Y: 1}, Text: "f"}}
112	_, ok := sceneDelta(base, with, phys, 1<<30)
113	require.False(t, ok, "labels appearing redraw the output")
114	typed := with
115	typed.HintLabels = []ports.HintLabel{{Rect: ports.Rect{X: 1, Y: 1}, Text: "f", Typed: 1}}
116	_, ok = sceneDelta(with, typed, phys, 1<<30)
117	require.False(t, ok)
118	_, ok = sceneDelta(with, with, phys, 1<<30)
119	require.True(t, ok, "same labels, no damage")
120}
121
122func TestHintLabelsHeldByTarget(t *testing.T) {
123	s := ports.Scene{Seq: 1, HintLabels: []ports.HintLabel{{Text: "f"}}}
124	tg := &target{}
125	tg.hold(s, &damageRegion{drawn: map[ports.WindowID]heldWindow{}})
126	s.HintLabels[0].Text = "j"
127	require.Equal(t, "f", tg.scene.HintLabels[0].Text, "the held scene owns its labels")
128}
129
130func TestHintStyleChangesSceneDamage(t *testing.T) {
131	old := ports.Scene{Scale: 1, HintLabels: []ports.HintLabel{{Text: "f"}}}
132	changed := old
133	changed.HintStyle.Size = 24
134	require.False(t, old.SameAs(changed))
135	_, partial := sceneDelta(old, changed, func(r ports.Rect) image.Rectangle { return image.Rect(r.X, r.Y, r.X+r.W, r.Y+r.H) }, 10)
136	require.False(t, partial)
137}

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 23

Tags 10

↑↓ moveenter openesc close