v0.1.0 d9218d6

layers_test.go RawHistoryFolder

1package core
2
3import (
4	"context"
5	"testing"
6	"time"
7
8	"github.com/bnema/neferwl/internal/ports"
9)
10
11func TestArrangeLayers(t *testing.T) {
12	bar := ports.LayerSurface{ID: 1, Layer: ports.LayerTop, Anchor: ports.AnchorTop | ports.AnchorLeft | ports.AnchorRight, Width: 1920, Height: 30, ExclusiveZone: 30}
13	tests := []struct {
14		name   string
15		layers []ports.LayerSurface
16		rects  []ports.Rect
17		usable ports.Rect
18	}{
19		{"top", []ports.LayerSurface{bar}, []ports.Rect{{W: 1920, H: 30}}, ports.Rect{Y: 30, W: 1920, H: 1050}},
20		{"bottom margin", []ports.LayerSurface{{Anchor: ports.AnchorBottom, Width: 100, Height: 20, ExclusiveZone: 20, Margin: [4]int32{0, 0, 5, 0}}}, []ports.Rect{{X: 910, Y: 1055, W: 100, H: 20}}, ports.Rect{W: 1920, H: 1055}},
21		{"left dock", []ports.LayerSurface{{Anchor: ports.AnchorLeft | ports.AnchorTop | ports.AnchorBottom, Width: 40, Height: 1080, ExclusiveZone: 40}}, []ports.Rect{{W: 40, H: 1080}}, ports.Rect{X: 40, W: 1880, H: 1080}},
22		{"center", []ports.LayerSurface{{Width: 100, Height: 40, Layer: ports.LayerOverlay}}, []ports.Rect{{X: 910, Y: 520, W: 100, H: 40}}, ports.Rect{W: 1920, H: 1080}},
23		{"opposing horizontal anchors with margins", []ports.LayerSurface{{Anchor: ports.AnchorLeft | ports.AnchorRight, Width: 100, Height: 20, Margin: [4]int32{0, 30, 0, 10}}}, []ports.Rect{{X: 900, Y: 530, W: 100, H: 20}}, ports.Rect{W: 1920, H: 1080}},
24		{"top only", []ports.LayerSurface{{Anchor: ports.AnchorTop, Width: 100, Height: 20, Margin: [4]int32{7, 0, 0, 0}}}, []ports.Rect{{X: 910, Y: 7, W: 100, H: 20}}, ports.Rect{W: 1920, H: 1080}},
25		{"full span between margins", []ports.LayerSurface{{Anchor: ports.AnchorLeft | ports.AnchorRight | ports.AnchorTop, Height: 20, Margin: [4]int32{7, 30, 0, 10}}}, []ports.Rect{{X: 10, Y: 7, W: 1880, H: 20}}, ports.Rect{W: 1920, H: 1080}},
26		{"opposing vertical anchors with margins", []ports.LayerSurface{{Anchor: ports.AnchorTop | ports.AnchorBottom, Width: 100, Height: 20, Margin: [4]int32{10, 0, 30, 0}}}, []ports.Rect{{X: 910, Y: 520, W: 100, H: 20}}, ports.Rect{W: 1920, H: 1080}},
27		{"minus one", []ports.LayerSurface{bar, {Layer: ports.LayerTop, Anchor: ports.AnchorTop, Width: 100, Height: 20, ExclusiveZone: -1}}, []ports.Rect{{W: 1920, H: 30}, {X: 910, W: 100, H: 20}}, ports.Rect{Y: 30, W: 1920, H: 1050}},
28		{"stack", []ports.LayerSurface{bar, {Layer: ports.LayerTop, Anchor: bar.Anchor, Width: 1920, Height: 20, ExclusiveZone: 20}}, []ports.Rect{{W: 1920, H: 30}, {Y: 30, W: 1920, H: 20}}, ports.Rect{Y: 50, W: 1920, H: 1030}},
29	}
30	for _, tt := range tests {
31		t.Run(tt.name, func(t *testing.T) {
32			got, u := arrangeLayers(1920, 1080, tt.layers)
33			if u != tt.usable || len(got) != len(tt.rects) {
34				t.Fatalf("got %v %v", got, u)
35			}
36			for i, r := range tt.rects {
37				if got[i].Rect != r {
38					t.Fatalf("rect %d: %v want %v", i, got[i].Rect, r)
39				}
40			}
41		})
42	}
43	layers := []ports.LayerSurface{{ID: 1, Layer: ports.LayerOverlay}, {ID: 2, Layer: ports.LayerBottom}, {ID: 3, Layer: ports.LayerBackground}, {ID: 4, Layer: ports.LayerTop}, {ID: 5, Layer: ports.LayerBottom}}
44	got, _ := arrangeLayers(100, 100, layers)
45	for i, id := range []ports.WindowID{3, 2, 5, 4, 1} {
46		if got[i].ID != id {
47			t.Fatalf("order: %v", got)
48		}
49	}
50}
51
52func TestLayerChangedChannels(t *testing.T) {
53	client := make(chan ports.ClientEvent)
54	output := make(chan ports.OutputEvent)
55	commands := make(chan ports.ClientCommand, 16)
56	scenes := make(chan []ports.Scene, 1)
57	cfg := ports.Config{}
58	cfg.Keyboard.CmdKey = "super"
59	cfg.Layout.MaxColumns = 2
60	c, err := New(cfg, Channels{Client: client, Output: output, Commands: commands, Scenes: scenes})
61	if err != nil {
62		t.Fatal(err)
63	}
64	ctx, cancel := context.WithCancel(context.Background())
65	defer cancel()
66	done := make(chan struct{})
67	go func() { defer close(done); _ = c.Run(ctx) }()
68	recv := func() ports.Scene {
69		t.Helper()
70		select {
71		case s := <-scenes:
72			return s[0]
73		case <-time.After(time.Second):
74			t.Fatal("scene timeout")
75			return ports.Scene{}
76		}
77	}
78	output <- ports.OutputAdded{Info: ports.OutputInfo{Name: "OUT-1", Width: 1920, Height: 1080}}
79	recv()
80	client <- ports.WindowMapped{ID: 1}
81	before := recv()
82	for len(commands) > 0 {
83		<-commands
84	}
85	bar := ports.LayerSurface{ID: 2, Layer: ports.LayerTop, Anchor: ports.AnchorTop | ports.AnchorLeft | ports.AnchorRight, Width: 1920, Height: 30, ExclusiveZone: 30}
86	client <- ports.LayerChanged{Layers: []ports.LayerSurface{bar}}
87	scene := recv()
88	if len(scene.Layers) != 1 || scene.Layers[0].Rect != (ports.Rect{W: 1920, H: 30}) || len(scene.Windows) != 1 || scene.Windows[0].Rect.Y < 30 {
89		t.Fatalf("scene: %v", scene)
90	}
91	if scene.Windows[0].Rect.H != before.Windows[0].Rect.H-30 {
92		t.Fatalf("height: %v vs %v", scene.Windows, before.Windows)
93	}
94	select {
95	case v := <-commands:
96		cfg, ok := v.(ports.ConfigureWindow)
97		if !ok || cfg.ID != 1 || cfg.Height != scene.Windows[0].Rect.H {
98			t.Fatalf("configure: %v", v)
99		}
100	case <-time.After(time.Second):
101		t.Fatal("configure timeout")
102	}
103	scene.Layers[0].Rect.Y = 99
104	client <- ports.LayerChanged{Layers: []ports.LayerSurface{bar}}
105	if next := recv(); next.Layers[0].Rect.Y != 0 {
106		t.Fatalf("scene alias: %v", next)
107	}
108	cancel()
109	<-done
110}

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