v0.2.0 13c6a90

float_order_test.go RawHistoryFolder

1package core
2
3import (
4	"slices"
5	"testing"
6)
7
8func order(w *Workspace) []WindowID {
9	ids := []WindowID{}
10	for _, p := range w.Layout() {
11		if !p.Hidden {
12			ids = append(ids, p.ID)
13		}
14	}
15	return ids
16}
17
18func wantOrder(t *testing.T, w *Workspace, want ...WindowID) {
19	t.Helper()
20	if got := order(w); !slices.Equal(got, want) {
21		t.Fatalf("order %v, want %v", got, want)
22	}
23}
24
25func TestCoveringFloatOrder(t *testing.T) {
26	for _, overflow := range []Overflow{OverflowScroll, OverflowFixed} {
27		t.Run(string(overflow), func(t *testing.T) {
28			w := workspace()
29			w.Overflow = overflow
30			w.border = 2
31			w.AddWindow(1)
32			w.AddWindow(2)
33			w.AddFloating(3, 98, 79) // placed rect fills the 100x81 usable area
34			wantOrder(t, w, 1, 2, 3)
35			w.FocusID(2)
36			wantOrder(t, w, 3, 1, 2)
37			if id, _ := w.Focused(); id != 2 {
38				t.Fatalf("focus %d", id)
39			}
40			w.RemoveWindow(2)
41			wantOrder(t, w, 3, 1)
42			if id, _ := w.Focused(); id != 1 {
43				t.Fatalf("after close focus %d", id)
44			}
45			w.AddFloating(4, 20, 20) // new dialogs map on top
46			wantOrder(t, w, 3, 1, 4)
47			w.FocusID(3)
48			wantOrder(t, w, 1, 3, 4) // user-selected float rises only within its allowed group
49			w.FocusID(1)
50			wantOrder(t, w, 3, 1, 4)
51			w.ResizeFloating(3, 99, 80)
52			wantOrder(t, w, 3, 1, 4)
53			w.SetOutput(102, 83)
54			w.SetUsable(Rect{W: 102, H: 83})
55			wantOrder(t, w, 3, 1, 4)
56			w.ResizeFloating(3, 20, 20)
57			wantOrder(t, w, 1, 4, 3)
58		})
59	}
60}
61
62func TestCoveringFloatGeometryAndGroup(t *testing.T) {
63	w := workspace()
64	w.border = 2
65	w.AddWindow(1)
66	w.AddFloating(2, 94, 75) // two border widths plus two pixels on each axis
67	if !w.coversFloat(w.Floats[0]) {
68		t.Fatal("rounding tolerance")
69	}
70	w.FocusID(1)
71	wantOrder(t, w, 2, 1)
72	w.SetUsable(Rect{X: 5, Y: 4, W: 90, H: 73})
73	wantOrder(t, w, 2, 1)
74	w.SetUsable(Rect{W: 100, H: 81})
75	wantOrder(t, w, 2, 1)
76	w.border = 0
77	w.reconcileFloats()
78	wantOrder(t, w, 1, 2)
79}
80
81func TestDemotedFloatFullscreenRoundTrip(t *testing.T) {
82	m := monitor()
83	m.SetBorder(2)
84	for _, overflow := range []Overflow{OverflowScroll, OverflowFixed} {
85		m = monitor()
86		m.SetBorder(2)
87		m.Current().Overflow = overflow
88		m.AddWindow(1)
89		m.AddFloating(2, 100, 80)
90		w := m.Current()
91		w.FocusID(1)
92		wantOrder(t, w, 2, 1)
93		m.SetFullscreen(2, true)
94		// Fixed overflow refuses an unfocused window's fullscreen (ADR 011).
95		if p := placement(w, 2); p.Fullscreen != (overflow == OverflowScroll) {
96			t.Fatalf("%v: fullscreen %+v", overflow, p)
97		}
98		m.SetFullscreen(2, false)
99		wantOrder(t, w, 2, 1)
100		if id, _ := w.Focused(); id != 1 {
101			t.Fatalf("focus %d", id)
102		}
103	}
104}
105
106func TestDemotedFloatMoveAndAdopt(t *testing.T) {
107	m := monitor()
108	m.SetBorder(2)
109	m.AddWindow(1)
110	m.AddFloating(2, 100, 80)
111	w := m.Current()
112	w.FocusID(1)
113	other := monitor()
114	other.SetOutput(102, 82)
115	other.SetBorder(2)
116	m.take(w)
117	other.adopt(w, false, 0)
118	if !w.Floats[0].below {
119		t.Fatal("adopt raised float")
120	}
121	wantOrder(t, w, 2, 1)
122	// A user moving the selected float to a workspace raises it there.
123	other.show(w)
124	w.FocusID(2)
125	other.MoveToWorkspace(1, false)
126	if w.has(2) || !other.Workspaces[1].has(2) {
127		t.Fatal("move lost float")
128	}
129}
130
131// Up from the top of a column raises the last demoted covering float;
132// down leaves it for the columns again without changing workspaces.
133func TestFocusWindowReturnsToDemotedCoveringFloat(t *testing.T) {
134	for _, overflow := range []Overflow{OverflowScroll, OverflowFixed} {
135		t.Run(string(overflow), func(t *testing.T) {
136			m := monitor()
137			m.SetOverflow(overflow)
138			m.SetBorder(2)
139			m.AddWindow(1)            // kitty
140			m.AddFloating(2, 100, 80) // covering game
141			m.AddFloating(3, 100, 80) // last demoted float is on top
142			w := m.Current()
143			w.FocusID(1)
144			wantOrder(t, w, 2, 3, 1)
145			m.Apply(ActionFocusWindowUp)
146			if id, _ := w.Focused(); id != 3 || m.Active != 0 || w.Floats[len(w.Floats)-1].below {
147				t.Fatalf("up focused %d on workspace %d, floats %+v", id, m.Active, w.Floats)
148			}
149			wantOrder(t, w, 2, 1, 3)
150			m.Apply(ActionFocusWindowDown)
151			if id, _ := w.Focused(); id != 1 || m.Active != 0 {
152				t.Fatalf("down focused %d on workspace %d", id, m.Active)
153			}
154			wantOrder(t, w, 2, 3, 1)
155		})
156	}
157}
158
159func TestFocusWindowDemotedFloatAfterColumnAndScreenNeighbors(t *testing.T) {
160	m := monitor()
161	m.SetOverflow(OverflowFixed)
162	m.SetBorder(2)
163	m.AddWindow(1)
164	m.AddWindow(2)
165	w := m.Current()
166	w.ConsumeOrExpel(-1) // two windows in the same column
167	w.AddFloating(9, 100, 80)
168	w.FocusID(1) // top of the column
169	w.FocusID(2) // bottom of the column
170	if !w.FocusWindow(-1) {
171		t.Fatal("up inside column failed")
172	}
173	if id, _ := w.Focused(); id != 1 || !w.Floats[0].below {
174		t.Fatalf("up inside column focused %d, float %+v", id, w.Floats[0])
175	}
176	if !w.FocusWindow(-1) {
177		t.Fatal("up to float failed")
178	}
179	if id, _ := w.Focused(); id != 9 {
180		t.Fatalf("up to float focused %d", id)
181	}
182
183	m = monitor()
184	m.SetOverflow(OverflowFixed)
185	m.SetMaxColumns(2)
186	for id := WindowID(1); id <= 4; id++ {
187		m.AddWindow(id)
188	}
189	w = m.Current()
190	w.AddFloating(9, 100, 80)
191	w.FocusID(4)
192	if !w.FocusWindow(-1) {
193		t.Fatal("up to on-screen column failed")
194	}
195	if id, _ := w.Focused(); id != 2 || !w.Floats[0].below {
196		t.Fatalf("up focused %d, float %+v", id, w.Floats[0])
197	}
198}
199
200func TestFocusWindowWithoutDemotedFloatChangesWorkspace(t *testing.T) {
201	m := monitor()
202	m.AddWindow(1)
203	m.Focus(1)
204	m.AddWindow(2)
205	m.Apply(ActionFocusWindowUp)
206	if m.Active != 0 {
207		t.Fatalf("up on workspace %d", m.Active)
208	}
209}
210
211// Up from a shown stash stays in the stash, even with a demoted covering
212// float; from a fullscreen float it leaves fullscreen for the tile below.
213func TestFocusWindowUpStashAndPinned(t *testing.T) {
214	m := monitor()
215	m.SetBorder(2)
216	m.AddWindow(1)
217	m.AddWindow(2)
218	w := m.Current()
219	w.AddFloating(9, 100, 80)
220	w.FocusID(2)
221	w.ToggleWindowStash() // 2 to the shown stash, focused
222	if !w.Floats[0].below {
223		t.Fatalf("float not below: %+v", w.Floats[0])
224	}
225	m.Apply(ActionFocusWindowUp)
226	if id, _ := w.Focused(); id != 2 || !w.Floats[0].below || m.Active != 0 {
227		t.Fatalf("stash up focused %d on %d, float %+v", id, m.Active, w.Floats[0])
228	}
229
230	m = monitor()
231	m.SetOverflow(OverflowFixed)
232	m.AddWindow(1)
233	m.AddFloating(2, 50, 40)
234	m.SetFullscreen(2, true)
235	if m.Active != 0 || !m.Current().pinned() {
236		t.Fatalf("setup: active %d", m.Active)
237	}
238	m.Apply(ActionFocusWindowUp)
239	if id, _ := m.Current().Focused(); id != 1 || m.Active != 0 || m.Current().fullscreen != 0 {
240		t.Fatalf("pinned up focused %d on %d", id, m.Active)
241	}
242}
243
244// Directional focus on a covering float with nothing under it keeps the
245// float focused.
246func TestCoveringFloatAloneKeepsFocus(t *testing.T) {
247	w := workspace()
248	w.border = 2
249	w.AddFloating(3, 98, 79)
250	w.FocusColumn(-1)
251	w.FocusWindow(1)
252	if id, ok := w.Focused(); !ok || id != 3 {
253		t.Fatalf("focus %d %v", id, ok)
254	}
255	wantOrder(t, w, 3)
256}
257
258// A tile leaving fullscreen with the focus comes back in front of a
259// covering float mapped meanwhile.
260func TestFullscreenReturnRaisesColumns(t *testing.T) {
261	for _, stacked := range []bool{false, true} {
262		m := monitor()
263		m.SetBorder(2)
264		m.SetOverflow(OverflowFixed)
265		m.AddWindow(1)
266		m.AddWindow(2)
267		if stacked {
268			m.Current().ConsumeOrExpel(-1)
269		}
270		w := m.Current()
271		w.FocusID(2)
272		m.ToggleFullscreen()
273		w.AddFloating(3, 100, 80)
274		m.ToggleFullscreen() // back, focused
275		if id, _ := w.Focused(); id != 2 {
276			t.Fatalf("stacked %v: focus %d", stacked, id)
277		}
278		if got := order(w); got[0] != 3 {
279			t.Fatalf("stacked %v: order %v, covering float not below", stacked, got)
280		}
281	}
282}

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