feat/hints a471fa4

animations_off_test.go RawHistoryFolder

1package core_test
2
3import (
4	"testing"
5	"time"
6
7	"github.com/bnema/neferwl/internal/ports"
8)
9
10func animationsOff(c *ports.Config) { c.Animations.On = false }
11
12// stillMoves sends n swipe updates of (dx, dy) and expects no scene: with
13// animations off the view does not follow the fingers.
14func (r *swipeRig) stillMoves(t *testing.T, n int, dx, dy float64) {
15	t.Helper()
16	for range n {
17		r.at += 8 * time.Millisecond
18		r.input <- ports.SwipeUpdate{DX: dx, DY: dy, Time: r.at}
19	}
20	if s, ok := r.published(); ok {
21		t.Fatalf("a swipe update published a scene (%d windows): the view follows the fingers", len(s))
22	}
23}
24
25// published reports the scene set core published for the events sent so
26// far, if any. A flip that names no output is a barrier: core handles its
27// events in order and publishes before taking the next one, so once the
28// send returns every earlier event is handled.
29func (r *swipeRig) published() ([]ports.Scene, bool) {
30	send(r.frames, ports.OutputFrame{Output: "sync"})
31	select {
32	case s := <-r.scenes:
33		return s, true
34	default:
35		return nil, false
36	}
37}
38
39func focusedID(s ports.Scene) ports.WindowID {
40	for _, w := range s.Windows {
41		if w.Focused {
42			return w.ID
43		}
44	}
45	return 0
46}
47
48func TestAnimationsOffColumnSwipeFocusesAtOnce(t *testing.T) {
49	r := startSwipe(t, animationsOff)
50	before := threeColumns(t, r)
51	r.begin()
52	r.stillMoves(t, 10, -40, 0)
53	s := r.end(t, false)
54	if got := focusedID(s); got != 2 {
55		t.Fatalf("focused %d right after the lift, want 2", got)
56	}
57	if got, _ := rectOf(before, 3); got.X == 0 {
58		t.Fatalf("bad setup: column 3 at %+v", got)
59	}
60	r.noFrameScene(t)
61}
62
63func TestAnimationsOffWorkspaceSwipeLandsAtOnce(t *testing.T) {
64	r := startSwipe(t, animationsOff)
65	r.workspaces(t)
66	r.begin()
67	r.stillMoves(t, 9, 0, 30)
68	s := r.end(t, false)
69	if _, ok := rectOf(s, 1); ok {
70		t.Fatal("old workspace still shown right after the lift")
71	}
72	if got, ok := rectOf(s, 2); !ok || got.Y != 0 {
73		t.Fatalf("workspace 2 at %+v (shown %t), want the settled rect", got, ok)
74	}
75}
76
77func TestAnimationsOffSlowSwipeStays(t *testing.T) {
78	r := startSwipe(t, animationsOff)
79	before := threeColumns(t, r)
80	r.begin()
81	r.stillMoves(t, 2, -10, 0)
82	r.input <- ports.SwipeEnd{Time: r.at + time.Second}
83	if s := scene(t, r.scenes); !s.SameAs(before) {
84		t.Fatalf("a short slow swipe changed the scene: %+v, was %+v", s.Windows, before.Windows)
85	}
86	r.noFrameScene(t)
87}
88
89func TestReloadToOffSettlesALanding(t *testing.T) {
90	r := startSwipe(t, nil)
91	threeColumns(t, r)
92	s := r.flick(t, 10, -40, 0)
93	if got, _ := rectOf(s, 1); got.X == 0 {
94		t.Fatal("no landing slide to interrupt")
95	}
96	cfg := r.cfg
97	cfg.Animations.On = false
98	r.reload <- ports.ConfigChanged{Config: cfg}
99	s = scene(t, r.scenes)
100	if got, _ := rectOf(s, 1); got.X != 0 {
101		t.Fatalf("column 1 at %d after the reload, want the settled rect", got.X)
102	}
103	r.noFrameScene(t)
104}
105
106// noFrameScene sends page flips and expects no scene: no spring runs, so
107// the flips have nothing to move and publish nothing.
108func (r *swipeRig) noFrameScene(t *testing.T, outputs ...string) {
109	t.Helper()
110	if len(outputs) == 0 {
111		outputs = []string{wide.Name}
112	}
113	for range 2 {
114		r.advance(16 * time.Millisecond)
115		for _, o := range outputs {
116			r.frames <- ports.OutputFrame{Output: o}
117		}
118	}
119	if s, ok := r.published(); ok {
120		t.Fatalf("a flip published a scene (%d windows): a spring still runs", len(s))
121	}
122}
123
124// landing flicks left and returns the rect of column 1 after each given
125// time since the lift.
126func landing(t *testing.T, slowdown float64, after ...time.Duration) []int {
127	t.Helper()
128	r := startSwipe(t, func(c *ports.Config) { c.Animations.Slowdown = slowdown })
129	threeColumns(t, r)
130	r.flick(t, 10, -40, 0)
131	var xs []int
132	var at time.Duration
133	for _, d := range after {
134		got, _ := rectOf(r.frame(t, d-at), 1)
135		xs = append(xs, got.X)
136		at = d
137	}
138	return xs
139}
140
141func TestSlowdownStretchesALanding(t *testing.T) {
142	// Critically damped at stiffness 800: settled after about 330 ms, 660 ms
143	// with slowdown 2 (the exact doubling is checked on the motion).
144	one := landing(t, 1, 100*time.Millisecond, 400*time.Millisecond)
145	two := landing(t, 2, 100*time.Millisecond, 400*time.Millisecond, 700*time.Millisecond)
146	if one[0] == 0 || two[0] == 0 {
147		t.Fatalf("landing does not move after 100 ms: %v %v", one, two)
148	}
149	if one[1] != 0 || two[1] == 0 {
150		t.Fatalf("at 400 ms: slowdown 1 at %d, want settled; slowdown 2 at %d, want moving", one[1], two[1])
151	}
152	if two[2] != 0 {
153		t.Fatalf("slowdown 2 does not settle by 700 ms: %v", two)
154	}
155}

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