aboutsummaryrefslogtreecommitdiffstats
path: root/zellij-server/src/tab/mod.rs
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-11 14:38:16 +0200
committeruser <user@clank>2026-08-11 14:38:16 +0200
commit844617b4ee27c2529fa16d1b53c40c62fe04fa70 (patch)
tree822144798626c4a4451da5a56e5a6b36dd9994e8 /zellij-server/src/tab/mod.rs
parentsl0p: cap how many rows the stacked-pane picker takes (diff)
downloadsl0ppij-844617b4ee27c2529fa16d1b53c40c62fe04fa70.tar.gz
sl0ppij-844617b4ee27c2529fa16d1b53c40c62fe04fa70.tar.xz
sl0ppij-844617b4ee27c2529fa16d1b53c40c62fe04fa70.zip
sl0p: fix clicking a scrolled stack entry selecting the wrong pane
Regression from the picker row cap. The row -> member mapping lives in TWO places: the renderer, and the hit-test that resolves mouse events to a pane. Capping made the renderer draw a WINDOW of the members, so screen row 0 is members[window_start], but the hit-test still resolved row N to members[N]. Any click or hover on a capped stack whose window had scrolled therefore landed on the wrong pane -- with 8 members focused on the last, clicking the top row selected member 0 instead of member 5. Both sites now go through stack_list_window(). Clicks on the "+N more" indicator resolve to no member rather than to a bogus one. Caught by asking how a user reaches the panes past the cutoff, not by the tests: the previous commit tested the window arithmetic and the rendering, but nothing covered this second consumer of the same mapping.
Diffstat (limited to 'zellij-server/src/tab/mod.rs')
-rw-r--r--zellij-server/src/tab/mod.rs17
1 files changed, 15 insertions, 2 deletions
diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs
index 2c75c425..7f132465 100644
--- a/zellij-server/src/tab/mod.rs
+++ b/zellij-server/src/tab/mod.rs
@@ -1170,8 +1170,21 @@ impl Tab {
if point.line() < geom.y as isize {
return pane_id;
}
- let rank = (point.line() - geom.y as isize) as usize;
- list.members.get(rank).copied().unwrap_or(pane_id)
+ // Screen row, NOT the member's rank: the picker draws a window of the
+ // members (see stack_list_window), so row 0 is members[window_start]
+ // once the list has scrolled. Resolving this against the raw rank picks
+ // the wrong pane for every capped, scrolled stack.
+ let row = (point.line() - geom.y as isize) as usize;
+ let visible_rank = list.rank_of(&list.visible).unwrap_or(0);
+ let (window_start, shown_count) = self.stack_list_window(list.members.len(), visible_rank);
+ if row >= shown_count {
+ // the "+N more" indicator row, which is not a member
+ return pane_id;
+ }
+ list.members
+ .get(window_start + row)
+ .copied()
+ .unwrap_or(pane_id)
}
pub fn suppressed_stack_list_members(&self) -> impl Iterator<Item = (&PaneId, &Box<dyn Pane>)> {
self.suppressed_panes