diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-07-11 02:46:41 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-07-11 02:46:58 +0300 |
| commit | 46174563489273199a17c982356c6e4674ef00d4 (patch) | |
| tree | e87a16bdb34e45b66124732c3458eed1e64d91a0 /src/app/input | |
| parent | 3b8aeee166d1594e1f8e41631a51748104d76834 (diff) | |
feat: add copy-on-select setting
Diffstat (limited to 'src/app/input')
| -rw-r--r-- | src/app/input/mod.rs | 5 | ||||
| -rw-r--r-- | src/app/input/mouse.rs | 14 | ||||
| -rw-r--r-- | src/app/input/terminal.rs | 81 |
3 files changed, 89 insertions, 11 deletions
diff --git a/src/app/input/mod.rs b/src/app/input/mod.rs index bcd5da98..421b3738 100644 --- a/src/app/input/mod.rs +++ b/src/app/input/mod.rs @@ -408,6 +408,11 @@ impl App { } fn handle_pane_double_click(&mut self, mouse: MouseEvent) -> bool { + if !self.state.copy_on_select { + self.last_pane_click = None; + return false; + } + // A pane press stops being a double-click candidate once it becomes // a drag or completes as a real text selection. match mouse.kind { diff --git a/src/app/input/mouse.rs b/src/app/input/mouse.rs index 495bcd53..911e27c0 100644 --- a/src/app/input/mouse.rs +++ b/src/app/input/mouse.rs @@ -640,12 +640,14 @@ impl AppState { mouse.row - info.inner_rect.y, mouse.column - info.inner_rect.x, ); - self.selection = Some(Selection::anchor( - info.id, - row, - col, - self.pane_scroll_metrics(terminal_runtimes, info.id), - )); + if self.copy_on_select { + self.selection = Some(Selection::anchor( + info.id, + row, + col, + self.pane_scroll_metrics(terminal_runtimes, info.id), + )); + } if let Some(ws_idx) = self.active { return Some(MouseAction::FocusPane { ws_idx, diff --git a/src/app/input/terminal.rs b/src/app/input/terminal.rs index 0fc35bd3..dd1e811f 100644 --- a/src/app/input/terminal.rs +++ b/src/app/input/terminal.rs @@ -459,6 +459,34 @@ mod tests { } #[tokio::test] + async fn copy_on_select_disabled_ignores_drag_and_double_click_selection() { + let (mut app, info) = app_with_screen_bytes(b"alpha beta"); + app.state.copy_on_select = false; + let row = info.inner_rect.y; + let start_col = info.inner_rect.x; + let end_col = info.inner_rect.x + 4; + + app.handle_mouse(mouse( + MouseEventKind::Down(MouseButton::Left), + start_col, + row, + )); + app.handle_mouse(mouse(MouseEventKind::Drag(MouseButton::Left), end_col, row)); + app.handle_mouse(mouse(MouseEventKind::Up(MouseButton::Left), end_col, row)); + + assert!(app.state.selection.is_none()); + assert!(app.state.selection_autoscroll.is_none()); + assert!(app.event_rx.try_recv().is_err()); + + double_click(&mut app, start_col, row); + + assert!(app.state.selection.is_none()); + assert!(app.last_pane_click.is_none()); + assert!(app.selection_highlight_clear_deadline.is_none()); + assert!(app.event_rx.try_recv().is_err()); + } + + #[tokio::test] async fn double_click_uses_display_columns_for_wide_chars() { let (mut app, info) = app_with_screen_bytes("echo 你好-world done".as_bytes()); let col = info.inner_rect.x + 8; @@ -730,15 +758,58 @@ mod tests { } #[tokio::test] - async fn double_click_is_forwarded_when_mouse_reporting_is_enabled() { - let (mut app, info) = app_with_screen_bytes(b"\x1b[?1002halpha beta"); - let col = info.inner_rect.x + 8; - let row = info.inner_rect.y; - double_click(&mut app, col, row); + async fn copy_on_select_disabled_still_forwards_mouse_reporting_gestures() { + let mut app = app_for_mouse_test(); + let mut ws = Workspace::test_new("test"); + let pane_id = ws.tabs[0].root_pane; + let pane_infos = ws.tabs[0].layout.panes(Rect::new(26, 2, 80, 18)); + let info = pane_infos[0].clone(); + let (runtime, mut input_rx) = + crate::terminal::TerminalRuntime::test_with_channel_and_scrollback_bytes( + info.inner_rect.width, + info.inner_rect.height, + 0, + b"\x1b[?1002h\x1b[?1006h", + 4, + ); + ws.insert_test_runtime(pane_id, runtime); + 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; + app.state.copy_on_select = false; + + let col = info.inner_rect.x + 2; + let row = info.inner_rect.y + 3; + app.handle_mouse(mouse(MouseEventKind::Down(MouseButton::Left), col, row)); + app.handle_mouse(mouse( + MouseEventKind::Drag(MouseButton::Left), + col + 1, + row + 1, + )); + app.handle_mouse(mouse( + MouseEventKind::Up(MouseButton::Left), + col + 1, + row + 1, + )); assert!(app.event_rx.try_recv().is_err()); assert!(app.state.selection.is_none()); assert!(app.selection_highlight_clear_deadline.is_none()); + assert_eq!( + input_rx.try_recv().expect("forwarded left mouse down"), + Bytes::from_static(b"\x1b[<0;3;4M") + ); + assert_eq!( + input_rx.try_recv().expect("forwarded left mouse drag"), + Bytes::from_static(b"\x1b[<32;4;5M") + ); + assert_eq!( + input_rx.try_recv().expect("forwarded left mouse up"), + Bytes::from_static(b"\x1b[<0;4;5m") + ); + assert!(input_rx.try_recv().is_err()); } #[tokio::test] |
