aboutsummaryrefslogtreecommitdiff
path: root/src/app/input/mod.rs
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-05-26 18:26:12 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-05-26 18:26:12 +0300
commitaf399094f5d24f157e35aaa657ed5ad5c44e5325 (patch)
tree2f44cc902312fbe8c405a972b9a438ca6bead27c /src/app/input/mod.rs
parent3750e0bae21c54da3947d337584f180a21d0bc67 (diff)
feat: open pane links with ctrl-click
refs #307
Diffstat (limited to 'src/app/input/mod.rs')
-rw-r--r--src/app/input/mod.rs38
1 files changed, 37 insertions, 1 deletions
diff --git a/src/app/input/mod.rs b/src/app/input/mod.rs
index e145e628..8ba8e4bd 100644
--- a/src/app/input/mod.rs
+++ b/src/app/input/mod.rs
@@ -1,6 +1,6 @@
//! Input handling — translates crossterm key/mouse events into state mutations.
-use crossterm::event::{KeyCode, KeyEvent, MouseButton, MouseEvent, MouseEventKind};
+use crossterm::event::{KeyCode, KeyEvent, KeyModifiers, MouseButton, MouseEvent, MouseEventKind};
use crate::app::PaneClickState;
use crate::input::TerminalKey;
@@ -195,6 +195,10 @@ impl App {
}
}
+ if self.handle_modified_url_click(mouse) {
+ return;
+ }
+
let handled_pane_double_click = self.handle_pane_double_click(mouse);
let previous_agent_panel_scope = self.state.agent_panel_scope;
@@ -248,6 +252,33 @@ impl App {
}
}
+ fn handle_modified_url_click(&mut self, mouse: MouseEvent) -> bool {
+ if self.state.mode != Mode::Terminal
+ || !matches!(mouse.kind, MouseEventKind::Down(MouseButton::Left))
+ || !mouse.modifiers.contains(KeyModifiers::CONTROL)
+ {
+ return false;
+ }
+
+ let Some(info) = self.state.pane_at(mouse.column, mouse.row).cloned() else {
+ return false;
+ };
+ let viewport_row = mouse.row.saturating_sub(info.inner_rect.y);
+ let col = mouse.column.saturating_sub(info.inner_rect.x);
+ let Some(url) =
+ self.state
+ .url_at_pane_cell(&self.terminal_runtimes, info.id, viewport_row, col)
+ else {
+ return false;
+ };
+
+ self.last_pane_click = None;
+ if let Err(err) = crate::platform::open_url(&url) {
+ tracing::warn!(err = %err, url = %url, "failed to open pane URL");
+ }
+ true
+ }
+
fn handle_pane_double_click(&mut self, mouse: MouseEvent) -> bool {
// A pane press stops being a double-click candidate once it becomes
// a drag or completes as a real text selection.
@@ -291,6 +322,11 @@ impl App {
return None;
}
+ if !mouse.modifiers.is_empty() {
+ self.last_pane_click = None;
+ return None;
+ }
+
if self.state.mode != Mode::Terminal {
self.last_pane_click = None;
return None;