aboutsummaryrefslogtreecommitdiff
path: root/src/app/input.rs
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-04-09 22:41:15 +0300
committerGitHub <noreply@github.com>2026-04-09 22:41:15 +0300
commitb024c273e36d3aeb4baddac47ac94ae24cf33b45 (patch)
tree405856b750b29cf6e8f039b1ba24c1bb4eba5f9a /src/app/input.rs
parent2c50690877da28187b7cce7e17a4f6053302accb (diff)
parent42fa2648ee4b98775eee5df3ccf8ecdcbec88fb3 (diff)
Merge pull request #25 from othavioquiliao/fix/pane-click-focus-mouse-reporting
fix: click focus on panes running TUIs with mouse reporting
Diffstat (limited to 'src/app/input.rs')
-rw-r--r--src/app/input.rs157
1 files changed, 145 insertions, 12 deletions
diff --git a/src/app/input.rs b/src/app/input.rs
index cf9c9de9..b2412046 100644
--- a/src/app/input.rs
+++ b/src/app/input.rs
@@ -2155,6 +2155,11 @@ impl AppState {
return None;
}
} else if let Some(info) = self.pane_at(mouse.column, mouse.row).cloned() {
+ self.focus_pane(info.id);
+ if self.mode != Mode::Terminal {
+ self.mode = Mode::Terminal;
+ }
+
if self.forward_pane_mouse_button(&info, mouse) {
self.selection = None;
return None;
@@ -2170,11 +2175,6 @@ impl AppState {
col,
self.pane_scroll_metrics(info.id),
));
-
- self.focus_pane(info.id);
- if self.mode != Mode::Terminal {
- self.mode = Mode::Terminal;
- }
} else if let Some(info) = self.view.pane_infos.iter().find(|p| {
mouse.column >= p.rect.x
&& mouse.column < p.rect.x + p.rect.width
@@ -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,
@@ -4573,4 +4568,142 @@ mod tests {
assert_eq!(wheel_routing(input_state), WheelRouting::HostScroll);
}
+
+ #[tokio::test]
+ async fn clicking_unfocused_pane_with_mouse_reporting_focuses_it_via_left_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::Left),
+ second_info.inner_rect.x + 2,
+ second_info.inner_rect.y + 2,
+ ));
+
+ assert_eq!(
+ app.state.workspaces[0].tabs[0].layout.focused(),
+ second_pane,
+ "left-clicking a pane with mouse reporting should move focus to it"
+ );
+ 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"
+ );
+ }
}