fix(core): find a pushed cascade column by its windows in order
The first remembered window still heading a column names it, so a window expelled from a pushed stack no longer comes back in its place.
- commit
- d4c54abc899c21403fa986cc620fb5e691a96be7
- author
- brice · · 2026-10-16 16:59 UTC
- parent
- efa1a9f
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +23 -4
M internal/core/cascade.go +11 -4
| @@ -350,9 +350,11 @@ func (w *Workspace) shiftBand(lo, hi, dir, at int) bool { | |||
| 350 | 350 | return true | |
| 351 | 351 | } | |
| 352 | 352 | ||
| 353 | - | // columnIDs lists the windows of each column, its identity for | |
| 354 | - | // restoreBand: a column whose first window is one of them is that column, | |
| 355 | - | // even after its first window closed or the stack changed order. | |
| 353 | + | // columnIDs lists the windows of each column, in order: its identity for | |
| 354 | + | // restoreBand. The column is the one headed by the first of them still | |
| 355 | + | // heading a column, so it is found after its first window closed or its | |
| 356 | + | // stack changed order, and a window that left it for a column of its own | |
| 357 | + | // comes after the one that stayed first. | |
| 356 | 358 | func columnIDs(cols []Column) [][]WindowID { | |
| 357 | 359 | ids := make([][]WindowID, len(cols)) | |
| 358 | 360 | for i, c := range cols { | |
| @@ -443,7 +445,12 @@ func (w *Workspace) restoreBand() bool { | |||
| 443 | 445 | if rev { | |
| 444 | 446 | e = ids[len(ids)-1-k] | |
| 445 | 447 | } | |
| 446 | - | i := slices.IndexFunc(bands[nb], func(c Column) bool { return slices.Contains(e, c.Windows[0]) }) | |
| 448 | + | i := -1 | |
| 449 | + | for _, v := range e { | |
| 450 | + | if i = slices.IndexFunc(bands[nb], func(c Column) bool { return c.Windows[0] == v }); i >= 0 { | |
| 451 | + | break | |
| 452 | + | } | |
| 453 | + | } | |
| 447 | 454 | if i < 0 { | |
| 448 | 455 | continue | |
| 449 | 456 | } | |
| @@ -350,9 +350,11 @@ func (w *Workspace) shiftBand(lo, hi, dir, at int) bool { | |||||
| 350 | return true | 350 | return true | ||
| 351 | } | 351 | } | ||
| 352 | 352 | ||||
| 353 | - | // columnIDs lists the windows of each column, its identity for | 353 | + | // columnIDs lists the windows of each column, in order: its identity for |
| 354 | - | // restoreBand: a column whose first window is one of them is that column, | 354 | + | // restoreBand. The column is the one headed by the first of them still |
| 355 | - | // even after its first window closed or the stack changed order. | 355 | + | // heading a column, so it is found after its first window closed or its |
| 356 | + | // stack changed order, and a window that left it for a column of its own | |||
| 357 | + | // comes after the one that stayed first. | |||
| 356 | func columnIDs(cols []Column) [][]WindowID { | 358 | func columnIDs(cols []Column) [][]WindowID { | ||
| 357 | ids := make([][]WindowID, len(cols)) | 359 | ids := make([][]WindowID, len(cols)) | ||
| 358 | for i, c := range cols { | 360 | for i, c := range cols { | ||
| @@ -443,7 +445,12 @@ func (w *Workspace) restoreBand() bool { | |||||
| 443 | if rev { | 445 | if rev { | ||
| 444 | e = ids[len(ids)-1-k] | 446 | e = ids[len(ids)-1-k] | ||
| 445 | } | 447 | } | ||
| 446 | - | i := slices.IndexFunc(bands[nb], func(c Column) bool { return slices.Contains(e, c.Windows[0]) }) | 448 | + | i := -1 |
| 449 | + | for _, v := range e { | |||
| 450 | + | if i = slices.IndexFunc(bands[nb], func(c Column) bool { return c.Windows[0] == v }); i >= 0 { | |||
| 451 | + | break | |||
| 452 | + | } | |||
| 453 | + | } | |||
| 447 | if i < 0 { | 454 | if i < 0 { | ||
| 448 | continue | 455 | continue | ||
| 449 | } | 456 | } | ||
M internal/core/cascade_bands_test.go +12 -0
| @@ -224,6 +224,18 @@ func TestCascadeRestoreBandMemory(t *testing.T) { | |||
| 224 | 224 | w.ToggleFullWidth() | |
| 225 | 225 | wantBands(t, w, []WindowID{1, 2, 3}, []WindowID{5}) | |
| 226 | 226 | }) | |
| 227 | + | t.Run("a window expelled from the pushed column stays", func(t *testing.T) { | |
| 228 | + | _, w := cascadeMovesCore(t, 5, 4, false) // {1 2 3 4} {5} | |
| 229 | + | w.FocusID(4) | |
| 230 | + | w.ConsumeOrExpel(-1) // {1 2 3/4} {5} | |
| 231 | + | w.FocusID(2) | |
| 232 | + | w.ToggleFullWidth() // {1} {2*} {3/4 5} | |
| 233 | + | w.FocusID(4) | |
| 234 | + | w.ConsumeOrExpel(-1) // {1} {2*} {4 3 5} | |
| 235 | + | w.FocusID(2) | |
| 236 | + | w.ToggleFullWidth() | |
| 237 | + | wantBands(t, w, []WindowID{1, 2, 3}, []WindowID{4, 5}) | |
| 238 | + | }) | |
| 227 | 239 | t.Run("first window of a pushed column closed", func(t *testing.T) { | |
| 228 | 240 | _, w := cascadeMovesCore(t, 4, 3, false) // {1 2 3} {4} | |
| 229 | 241 | w.FocusID(4) | |
| @@ -224,6 +224,18 @@ func TestCascadeRestoreBandMemory(t *testing.T) { | |||||
| 224 | w.ToggleFullWidth() | 224 | w.ToggleFullWidth() | ||
| 225 | wantBands(t, w, []WindowID{1, 2, 3}, []WindowID{5}) | 225 | wantBands(t, w, []WindowID{1, 2, 3}, []WindowID{5}) | ||
| 226 | }) | 226 | }) | ||
| 227 | + | t.Run("a window expelled from the pushed column stays", func(t *testing.T) { | |||
| 228 | + | _, w := cascadeMovesCore(t, 5, 4, false) // {1 2 3 4} {5} | |||
| 229 | + | w.FocusID(4) | |||
| 230 | + | w.ConsumeOrExpel(-1) // {1 2 3/4} {5} | |||
| 231 | + | w.FocusID(2) | |||
| 232 | + | w.ToggleFullWidth() // {1} {2*} {3/4 5} | |||
| 233 | + | w.FocusID(4) | |||
| 234 | + | w.ConsumeOrExpel(-1) // {1} {2*} {4 3 5} | |||
| 235 | + | w.FocusID(2) | |||
| 236 | + | w.ToggleFullWidth() | |||
| 237 | + | wantBands(t, w, []WindowID{1, 2, 3}, []WindowID{4, 5}) | |||
| 238 | + | }) | |||
| 227 | t.Run("first window of a pushed column closed", func(t *testing.T) { | 239 | t.Run("first window of a pushed column closed", func(t *testing.T) { | ||
| 228 | _, w := cascadeMovesCore(t, 4, 3, false) // {1 2 3} {4} | 240 | _, w := cascadeMovesCore(t, 4, 3, false) // {1 2 3} {4} | ||
| 229 | w.FocusID(4) | 241 | w.FocusID(4) | ||