detached bfb04cb

fix(layout): place joined windows after the stack's current column

commit
bfb04cb29ea2b331a58f68f4c5cb4c42d452d346
author
brice · · 2026-09-25 20:23 UTC
parent
3bc98da
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +15 -1
M internal/core/monitor.go +2 -1
@@ -367,7 +367,8 @@ func (m *Monitor) leaveFullscreen(fs *Workspace, focus bool) {
367367 origin, back, id := fs.origin, fs.back, fs.back.id
368368 fs.origin, fs.back = nil, origPlace{}
369369 fs.RemoveWindow(id)
370- defer m.foldInto(fs, origin, back.col+1, focus, back.tiled)
370+ // A closure: back.col is where the window lands, known after the switch.
371+ defer func() { m.foldInto(fs, origin, back.col+1, focus, back.tiled) }()
371372 switch prev := origin.Focus; {
372373 case back.float != nil && focus:
373374 origin.AddFloating(id, back.float.W, back.float.H)
@@ -367,7 +367,8 @@ func (m *Monitor) leaveFullscreen(fs *Workspace, focus bool) {
367 origin, back, id := fs.origin, fs.back, fs.back.id367 origin, back, id := fs.origin, fs.back, fs.back.id
368 fs.origin, fs.back = nil, origPlace{}368 fs.origin, fs.back = nil, origPlace{}
369 fs.RemoveWindow(id)369 fs.RemoveWindow(id)
370- defer m.foldInto(fs, origin, back.col+1, focus, back.tiled)370+ // A closure: back.col is where the window lands, known after the switch.
371+ defer func() { m.foldInto(fs, origin, back.col+1, focus, back.tiled) }()
371 switch prev := origin.Focus; {372 switch prev := origin.Focus; {
372 case back.float != nil && focus:373 case back.float != nil && focus:
373 origin.AddFloating(id, back.float.W, back.float.H)374 origin.AddFloating(id, back.float.W, back.float.H)
M internal/core/monitor_test.go +13 -0
@@ -500,6 +500,19 @@ func TestMonitorFixedFullscreenEdges(t *testing.T) {
500500 t.Fatal(got, m.Active)
501501 }
502502 })
503+ t.Run("a joined window lands after its stack when columns shifted", func(t *testing.T) {
504+ m := fixed()
505+ w := m.Current()
506+ w.Columns = []Column{{Windows: []WindowID{1}}, {Windows: []WindowID{5}}, {Windows: []WindowID{2, 3}}, {Windows: []WindowID{6}}}
507+ w.FocusID(3)
508+ m.ToggleFullscreen()
509+ m.AddWindow(7)
510+ m.RemoveWindow(1)
511+ m.ToggleFullscreen()
512+ if got := windows(m); !reflect.DeepEqual(got, [][]WindowID{{5, 2, 3, 7, 6}, {}}) {
513+ t.Fatal(got)
514+ }
515+ })
503516 t.Run("the bind from a dialog returns the fullscreen window", func(t *testing.T) {
504517 m := fixed()
505518 m.Current().FocusID(2)
@@ -500,6 +500,19 @@ func TestMonitorFixedFullscreenEdges(t *testing.T) {
500 t.Fatal(got, m.Active)500 t.Fatal(got, m.Active)
501 }501 }
502 })502 })
503+ t.Run("a joined window lands after its stack when columns shifted", func(t *testing.T) {
504+ m := fixed()
505+ w := m.Current()
506+ w.Columns = []Column{{Windows: []WindowID{1}}, {Windows: []WindowID{5}}, {Windows: []WindowID{2, 3}}, {Windows: []WindowID{6}}}
507+ w.FocusID(3)
508+ m.ToggleFullscreen()
509+ m.AddWindow(7)
510+ m.RemoveWindow(1)
511+ m.ToggleFullscreen()
512+ if got := windows(m); !reflect.DeepEqual(got, [][]WindowID{{5, 2, 3, 7, 6}, {}}) {
513+ t.Fatal(got)
514+ }
515+ })
503 t.Run("the bind from a dialog returns the fullscreen window", func(t *testing.T) {516 t.Run("the bind from a dialog returns the fullscreen window", func(t *testing.T) {
504 m := fixed()517 m := fixed()
505 m.Current().FocusID(2)518 m.Current().FocusID(2)

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 26

Tags 10

↑↓ moveenter openesc close