diff options
| author | Othavio Quiliao <othavioaqa@gmail.com> | 2026-04-09 16:06:27 -0300 |
|---|---|---|
| committer | Othavio Quiliao <othavioaqa@gmail.com> | 2026-04-09 16:06:27 -0300 |
| commit | 42fa2648ee4b98775eee5df3ccf8ecdcbec88fb3 (patch) | |
| tree | 7375cd766497d614156667b2d00d25b36c47dc95 /src/app | |
| parent | 5e711fb7d3b6039afa7d3683d9ef0504f2de9cb2 (diff) | |
fix: always open pane context menu on right-click
The Down(Right) handler forwarded the click to the inner pane runtime
when mouse reporting was active, then early-returned before creating the
context menu state. For panes running a TUI that enables mouse reporting
(e.g. Claude Code), right-clicking focused the pane but never opened the
herdr context menu, even though right-click on plain shells or Codex
still worked.
Stop forwarding Down(Right) to the pane runtime altogether. Right-click
on a pane now always focuses it and opens the herdr context menu,
matching how terminal emulators like Ghostty, Alacritty, Kitty and iTerm2
treat right-click. This means the previous context menu actions
(close pane, split, fullscreen, etc.) now also reach the intended pane
via focus_pane before the menu is displayed.
Remove Up(Right) and Drag(Right) from the middle/right forward branch so
the inner TUI never sees an Up or Drag without a matching Down. Middle
button forwarding is preserved because it is still used for paste in
many terminal protocols.
Tighten the existing right-click regression test with assertions that
Mode::ContextMenu is entered and context_menu is populated. Without
these extra checks the earlier version of the test only verified focus
and failed to catch this exact bug.
Diffstat (limited to 'src/app')
| -rw-r--r-- | src/app/input.rs | 81 |
1 files changed, 74 insertions, 7 deletions
diff --git a/src/app/input.rs b/src/app/input.rs index 6a770d06..b2412046 100644 --- a/src/app/input.rs +++ b/src/app/input.rs @@ -2336,10 +2336,7 @@ impl AppState { } } - MouseEventKind::Up(MouseButton::Middle) - | MouseEventKind::Up(MouseButton::Right) - | MouseEventKind::Drag(MouseButton::Middle) - | MouseEventKind::Drag(MouseButton::Right) + MouseEventKind::Up(MouseButton::Middle) | MouseEventKind::Drag(MouseButton::Middle) if !in_sidebar => { if let Some(info) = self.pane_mouse_target(mouse.column, mouse.row).cloned() { @@ -2440,9 +2437,7 @@ impl AppState { MouseEventKind::Down(MouseButton::Right) if !in_sidebar => { if let Some(info) = self.pane_mouse_target(mouse.column, mouse.row).cloned() { - if self.forward_pane_mouse_button(&info, mouse) { - return None; - } + self.focus_pane(info.id); self.context_menu = Some(ContextMenuState { kind: ContextMenuKind::Pane, x: mouse.column, @@ -4639,4 +4634,76 @@ mod tests { assert_eq!(app.state.mode, Mode::Terminal); } + #[tokio::test] + async fn clicking_unfocused_pane_with_mouse_reporting_focuses_it_via_right_button() { + let mut app = app_for_mouse_test(); + let mut ws = Workspace::test_new("test"); + let first_pane = ws.tabs[0].root_pane; + let second_pane = ws.test_split(ratatui::layout::Direction::Vertical); + + let terminal_area = Rect::new(26, 2, 80, 18); + let pane_infos = ws.tabs[0].layout.panes(terminal_area); + let first_info = pane_infos + .iter() + .find(|p| p.id == first_pane) + .expect("first pane info") + .clone(); + let second_info = pane_infos + .iter() + .find(|p| p.id == second_pane) + .expect("second pane info") + .clone(); + + ws.tabs[0].runtimes.insert( + first_pane, + crate::pane::PaneRuntime::test_with_screen_bytes( + first_info.inner_rect.width.max(1), + first_info.inner_rect.height.max(1), + b"", + ), + ); + ws.tabs[0].runtimes.insert( + second_pane, + crate::pane::PaneRuntime::test_with_screen_bytes( + second_info.inner_rect.width.max(1), + second_info.inner_rect.height.max(1), + b"\x1b[?1002h", + ), + ); + + ws.tabs[0].layout.focus_pane(first_pane); + + app.state.workspaces = vec![ws]; + app.state.active = Some(0); + app.state.selected = 0; + app.state.mode = Mode::Terminal; + app.state.view.pane_infos = pane_infos; + + assert_eq!( + app.state.workspaces[0].tabs[0].layout.focused(), + first_pane, + "first pane should be focused before click" + ); + + app.handle_mouse(mouse( + MouseEventKind::Down(MouseButton::Right), + second_info.inner_rect.x + 2, + second_info.inner_rect.y + 2, + )); + + assert_eq!( + app.state.workspaces[0].tabs[0].layout.focused(), + second_pane, + "right-clicking a pane with mouse reporting should move focus to it" + ); + assert_eq!( + app.state.mode, + Mode::ContextMenu, + "right-click should enter ContextMenu mode" + ); + assert!( + app.state.context_menu.is_some(), + "right-click should populate context_menu state" + ); + } } |
