main f2d166b

capture_internal_test.go RawHistoryFolder

1package core
2
3import (
4	"context"
5	"reflect"
6	"slices"
7	"testing"
8
9	"github.com/bnema/neferwl/internal/ports"
10)
11
12// While an exclusion is live, the set of layers kept over a fullscreen window
13// is built once per change of the attached set and shared by every screen: a
14// publish allocates nothing for it.
15func TestExclusionKeepIsSharedAndBuiltOncePerChange(t *testing.T) {
16	c, _, _ := hiddenCaptureCommands(t)
17	c.addScreen(ports.OutputInfo{Name: "B", Width: 100, Height: 100})
18	c.captureOpen(ports.CaptureSessionOpen{ID: 1, Output: "A"})
19	c.captureExclusionBegin(ports.CaptureExclusionBegin{Session: 1})
20	c.captureExclusionLayer(ports.CaptureExclusionLayer{Session: 1, Layer: 10, Attached: true})
21	c.captureExclusionLayer(ports.CaptureExclusionLayer{Session: 1, Layer: 11, Attached: true})
22	e := c.capt.excl
23	keep := c.exclusionKeep(e)
24	if len(keep) != 2 || !keep[10] || !keep[11] {
25		t.Fatalf("keep %v", keep)
26	}
27	if n := testing.AllocsPerRun(100, func() { _ = c.exclusionKeep(e) }); n != 0 {
28		t.Fatalf("%v allocations for an unchanged exclusion", n)
29	}
30	if err := c.publish(context.Background()); err != nil {
31		t.Fatal(err)
32	}
33	for _, sc := range c.screens {
34		if reflect.ValueOf(sc.capture).Pointer() != reflect.ValueOf(keep).Pointer() {
35			t.Fatalf("screen %s has its own keep set", sc.name())
36		}
37	}
38	// A change of the attached set builds a new one, once.
39	c.captureExclusionLayer(ports.CaptureExclusionLayer{Session: 1, Layer: 11})
40	if k := c.exclusionKeep(e); len(k) != 1 || !k[10] {
41		t.Fatalf("keep after detach %v", k)
42	}
43	// An ended exclusion keeps nothing over a fullscreen window.
44	c.screens[0].layers = []ports.LayerSurface{{ID: 10}}
45	c.captureExclusionEnd(1)
46	if c.capt.excl == nil || !c.capt.excl.ended || !slices.Equal(c.capt.excl.retained, []WindowID{10}) {
47		t.Fatalf("ended exclusion %+v", c.capt.excl)
48	}
49	if k := c.exclusionKeep(c.capt.excl); k != nil {
50		t.Fatalf("keep of an ended exclusion %v", k)
51	}
52	// With no layer listed any more it is gone.
53	c.screens[0].layers = nil
54	c.pruneRetained()
55	if c.capt.excl != nil {
56		t.Fatalf("exclusion survived its last listed layer: %+v", c.capt.excl)
57	}
58}
59
60// sameCaptureState compares every field of the session state, by hand. A new
61// field must be compared there, or a change of it is never sent to wayland.
62func TestSameCaptureStateComparesEveryField(t *testing.T) {
63	const compared = 10 // ID Output Rect Workspace Hidden Active Reason Exclusion Revision Layers
64	if n := reflect.TypeFor[ports.CaptureSessionState]().NumField(); n != compared {
65		t.Fatalf("ports.CaptureSessionState has %d fields, sameCaptureState compares %d: compare the new field in sameCaptureState (capture.go), then update this count", n, compared)
66	}
67	base := ports.CaptureSessionState{}
68	for _, v := range []ports.CaptureSessionState{
69		{ID: 1}, {Output: "A"}, {Rect: Rect{W: 1}}, {Workspace: 1}, {Hidden: true}, {Active: true},
70		{Reason: ports.CaptureReasonOutputGone}, {Exclusion: true}, {Revision: 1}, {Layers: []WindowID{1}},
71	} {
72		if sameCaptureState(base, v) {
73			t.Fatalf("a change of %+v is not seen", v)
74		}
75	}
76}

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 25

Tags 10

↑↓ moveenter openesc close