detached 23fbc2c

fix(core): allow leaving stash-only overview piles

commit
23fbc2c439f31ec12908ca6a5d250a7ad9df7f85
author
brice · · 2026-10-05 20:56 UTC
parent
ad3ecff
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
refs
feat/overview-stash-navigation
4 files · +15 -5
M docs/config.md +2 -2
@@ -255,9 +255,9 @@ The drop can be on another monitor; focus follows the window. There, the middle
255255 | `return` | Show the selected front card; picking a hidden column moves the maximization to it. Other rows shown keep their focus, maximization and float order |
256256 | `escape` | Return to the original workspace; every row shown keeps its focus, maximization and float order |
257257
258-The focus binds (`focus-column-left/right`, `focus-window-up/down`, `cmd+arrows` by default) move the selection like these keys. In the overview, `focus-workspace-up/down` also traverse cards before crossing workspace rows, including named ones.
258+The focus binds (`focus-column-left/right`, `focus-window-up/down`, `cmd+arrows` by default) move the selection like these keys. In the overview, `focus-workspace-up/down` also traverse cards before crossing workspace rows, including named ones, except inside a selected stash pile.
259259
260-Each workspace's [stash](#stash), hidden or not, shows as a pile of cards on the left of its row, which stays centred unless it would overlap the pile: its selected window in front, up to three others behind it, dimmed. In the pile, `k` / `j` or up/down browse stash cards and stop at either end without changing workspace. Right (`l`) leaves the pile immediately when the workspace has a main card; left (`h`) stays in the pile. Browsing brings the selected card to the front without reordering the stash. `return` or a click on a card closes the overview with the stash shown on that window.
260+Each workspace's [stash](#stash), hidden or not, shows as a pile of cards on the left of its row, which stays centred unless it would overlap the pile: its selected window in front, up to three others behind it, dimmed. In the pile, `k` / `j` or up/down browse stash cards and stop at either end without changing workspace. Right (`l`) leaves the pile immediately; left (`h`) stays in the pile. On a stash-only workspace, right deselects the pile so up/down can change workspace. Browsing brings the selected card to the front without reordering the stash. `return` or a click on a card closes the overview with the stash shown on that window.
261261
262262 A four-finger swipe up opens the overview, or hides the [stash](#stash) when it is shown, and a swipe down closes the overview on the selection (with the overview closed, a swipe down shows or hides the stash), whatever `touchpad.natural-scroll` says. Two-finger scrolling and the mouse wheel move the selection: left and right through the columns, up and down through stack cards before crossing workspaces, following `touchpad.natural-scroll` for two-finger scrolling and `mouse.natural-scroll` for the wheel. A two-finger scroll sideways moves it to the next column after a short distance, then one column per longer distance, and stays on the columns until the fingers lift; up or down it moves one step per scroll, so a card in a stack is easy to pick. The wheel moves one step per notch. A three-finger swipe moves it one step when the fingers lift: left/right enters or leaves the stash pile, and up/down browses its cards while it is selected. Two-finger scrolling, the wheel and keyboard navigation follow the same pile boundaries.
263263
@@ -255,9 +255,9 @@ The drop can be on another monitor; focus follows the window. There, the middle
255 | `return` | Show the selected front card; picking a hidden column moves the maximization to it. Other rows shown keep their focus, maximization and float order |255 | `return` | Show the selected front card; picking a hidden column moves the maximization to it. Other rows shown keep their focus, maximization and float order |
256 | `escape` | Return to the original workspace; every row shown keeps its focus, maximization and float order |256 | `escape` | Return to the original workspace; every row shown keeps its focus, maximization and float order |
257 257
258-The focus binds (`focus-column-left/right`, `focus-window-up/down`, `cmd+arrows` by default) move the selection like these keys. In the overview, `focus-workspace-up/down` also traverse cards before crossing workspace rows, including named ones.258+The focus binds (`focus-column-left/right`, `focus-window-up/down`, `cmd+arrows` by default) move the selection like these keys. In the overview, `focus-workspace-up/down` also traverse cards before crossing workspace rows, including named ones, except inside a selected stash pile.
259 259
260-Each workspace's [stash](#stash), hidden or not, shows as a pile of cards on the left of its row, which stays centred unless it would overlap the pile: its selected window in front, up to three others behind it, dimmed. In the pile, `k` / `j` or up/down browse stash cards and stop at either end without changing workspace. Right (`l`) leaves the pile immediately when the workspace has a main card; left (`h`) stays in the pile. Browsing brings the selected card to the front without reordering the stash. `return` or a click on a card closes the overview with the stash shown on that window.260+Each workspace's [stash](#stash), hidden or not, shows as a pile of cards on the left of its row, which stays centred unless it would overlap the pile: its selected window in front, up to three others behind it, dimmed. In the pile, `k` / `j` or up/down browse stash cards and stop at either end without changing workspace. Right (`l`) leaves the pile immediately; left (`h`) stays in the pile. On a stash-only workspace, right deselects the pile so up/down can change workspace. Browsing brings the selected card to the front without reordering the stash. `return` or a click on a card closes the overview with the stash shown on that window.
261 261
262 A four-finger swipe up opens the overview, or hides the [stash](#stash) when it is shown, and a swipe down closes the overview on the selection (with the overview closed, a swipe down shows or hides the stash), whatever `touchpad.natural-scroll` says. Two-finger scrolling and the mouse wheel move the selection: left and right through the columns, up and down through stack cards before crossing workspaces, following `touchpad.natural-scroll` for two-finger scrolling and `mouse.natural-scroll` for the wheel. A two-finger scroll sideways moves it to the next column after a short distance, then one column per longer distance, and stays on the columns until the fingers lift; up or down it moves one step per scroll, so a card in a stack is easy to pick. The wheel moves one step per notch. A three-finger swipe moves it one step when the fingers lift: left/right enters or leaves the stash pile, and up/down browses its cards while it is selected. Two-finger scrolling, the wheel and keyboard navigation follow the same pile boundaries.262 A four-finger swipe up opens the overview, or hides the [stash](#stash) when it is shown, and a swipe down closes the overview on the selection (with the overview closed, a swipe down shows or hides the stash), whatever `touchpad.natural-scroll` says. Two-finger scrolling and the mouse wheel move the selection: left and right through the columns, up and down through stack cards before crossing workspaces, following `touchpad.natural-scroll` for two-finger scrolling and `mouse.natural-scroll` for the wheel. A two-finger scroll sideways moves it to the next column after a short distance, then one column per longer distance, and stays on the columns until the fingers lift; up or down it moves one step per scroll, so a card in a stack is easy to pick. The wheel moves one step per notch. A three-finger swipe moves it one step when the fingers lift: left/right enters or leaves the stash pile, and up/down browses its cards while it is selected. Two-finger scrolling, the wheel and keyboard navigation follow the same pile boundaries.
263 263
M internal/core/overview.go +4 -2
@@ -364,7 +364,8 @@ func (m *Monitor) showOverview(w *Workspace) {
364364 }
365365
366366 // OverviewMove shares navigation rules across keys, scrolls and swipes.
367-// Vertical moves stay in a selected stash pile; horizontal moves leave it.
367+// Vertical moves stay in a selected stash pile; left stays, and right
368+// deselects it, even when the row has no main card.
368369 func (m *Monitor) OverviewMove(dx, dy int) {
369370 if dy != 0 {
370371 m.overviewVertical(dy)
@@ -392,8 +393,9 @@ func (m *Monitor) overviewVertical(dy int) {
392393 func (m *Monitor) overviewHorizontal(dx int) {
393394 w := m.Current()
394395 if m.cardAt(w) >= 0 {
395- if dx > 0 && len(w.stack()) > 0 {
396+ if dx > 0 {
396397 m.ov.card, m.ov.cardOf = 0, nil
398+ m.ov.selected = 0
397399 item := m.stackFront(w)
398400 if item.kind == stackColumns {
399401 if w.overviewMaximized() {
@@ -364,7 +364,8 @@ func (m *Monitor) showOverview(w *Workspace) {
364 }364 }
365 365
366 // OverviewMove shares navigation rules across keys, scrolls and swipes.366 // OverviewMove shares navigation rules across keys, scrolls and swipes.
367-// Vertical moves stay in a selected stash pile; horizontal moves leave it.367+// Vertical moves stay in a selected stash pile; left stays, and right
368+// deselects it, even when the row has no main card.
368 func (m *Monitor) OverviewMove(dx, dy int) {369 func (m *Monitor) OverviewMove(dx, dy int) {
369 if dy != 0 {370 if dy != 0 {
370 m.overviewVertical(dy)371 m.overviewVertical(dy)
@@ -392,8 +393,9 @@ func (m *Monitor) overviewVertical(dy int) {
392 func (m *Monitor) overviewHorizontal(dx int) {393 func (m *Monitor) overviewHorizontal(dx int) {
393 w := m.Current()394 w := m.Current()
394 if m.cardAt(w) >= 0 {395 if m.cardAt(w) >= 0 {
395- if dx > 0 && len(w.stack()) > 0 {396+ if dx > 0 {
396 m.ov.card, m.ov.cardOf = 0, nil397 m.ov.card, m.ov.cardOf = 0, nil
398+ m.ov.selected = 0
397 item := m.stackFront(w)399 item := m.stackFront(w)
398 if item.kind == stackColumns {400 if item.kind == stackColumns {
399 if w.overviewMaximized() {401 if w.overviewMaximized() {
M internal/core/overview_stack_test.go +1 -1
@@ -278,7 +278,7 @@ func TestOverviewStackNoFloatVeil(t *testing.T) {
278278 }
279279 }
280280
281-// l past the last stash card returns to the front card, even with no columns.
281+// l leaves the pile for the front card, even with no columns.
282282 func TestOverviewPileRightToFloatCard(t *testing.T) {
283283 m := monitor()
284284 m.SetOutput(300, 200)
@@ -278,7 +278,7 @@ func TestOverviewStackNoFloatVeil(t *testing.T) {
278 }278 }
279 }279 }
280 280
281-// l past the last stash card returns to the front card, even with no columns.281+// l leaves the pile for the front card, even with no columns.
282 func TestOverviewPileRightToFloatCard(t *testing.T) {282 func TestOverviewPileRightToFloatCard(t *testing.T) {
283 m := monitor()283 m := monitor()
284 m.SetOutput(300, 200)284 m.SetOutput(300, 200)
M internal/core/overview_test.go +8 -0
@@ -448,6 +448,14 @@ func TestOverviewPileOnly(t *testing.T) {
448448 if m.Current() != w || m.cardAt(w) != 0 {
449449 t.Fatal("vertical navigation escaped a stash-only workspace")
450450 }
451+ m.OverviewMove(1, 0)
452+ if m.cardAt(w) >= 0 || m.ov.selected != 0 {
453+ t.Fatal("right did not deselect the stash-only pile")
454+ }
455+ m.OverviewMove(0, 1)
456+ if m.Current() == w {
457+ t.Fatal("vertical navigation after leaving the pile did not change workspace")
458+ }
451459 m.CancelOverview()
452460 m.Focus(1)
453461 m.ToggleOverview()
@@ -448,6 +448,14 @@ func TestOverviewPileOnly(t *testing.T) {
448 if m.Current() != w || m.cardAt(w) != 0 {448 if m.Current() != w || m.cardAt(w) != 0 {
449 t.Fatal("vertical navigation escaped a stash-only workspace")449 t.Fatal("vertical navigation escaped a stash-only workspace")
450 }450 }
451+ m.OverviewMove(1, 0)
452+ if m.cardAt(w) >= 0 || m.ov.selected != 0 {
453+ t.Fatal("right did not deselect the stash-only pile")
454+ }
455+ m.OverviewMove(0, 1)
456+ if m.Current() == w {
457+ t.Fatal("vertical navigation after leaving the pile did not change workspace")
458+ }
451 m.CancelOverview()459 m.CancelOverview()
452 m.Focus(1)460 m.Focus(1)
453 m.ToggleOverview()461 m.ToggleOverview()

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