aboutsummaryrefslogtreecommitdiff
path: root/src/app/input/terminal.rs
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-07-24 02:09:22 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-07-24 02:10:47 +0300
commit58e812b238844fa05233eadc537081a1f0d06f36 (patch)
tree61d071cf4a6c33b58cf8a35f56aa8174fe084252 /src/app/input/terminal.rs
parent36de78dd4fa4e2c203ee955f18caf82a6bca7e80 (diff)
fix: consume handled url click gestures
refs #1761
Diffstat (limited to 'src/app/input/terminal.rs')
-rw-r--r--src/app/input/terminal.rs50
1 files changed, 50 insertions, 0 deletions
diff --git a/src/app/input/terminal.rs b/src/app/input/terminal.rs
index 61c6bbb3..371803da 100644
--- a/src/app/input/terminal.rs
+++ b/src/app/input/terminal.rs
@@ -328,6 +328,7 @@ impl App {
}
pub(crate) fn release_input_source_headless(&mut self, source_id: crate::app::InputSourceId) {
+ self.pending_url_click_sources.remove(&source_id);
for pressed in self.take_pressed_keys_for_source(source_id) {
let release = pressed
.key
@@ -337,6 +338,7 @@ impl App {
}
pub(crate) async fn release_input_source(&mut self, source_id: crate::app::InputSourceId) {
+ self.pending_url_click_sources.remove(&source_id);
for pressed in self.take_pressed_keys_for_source(source_id) {
let release = pressed
.key
@@ -846,6 +848,54 @@ mod tests {
#[cfg(unix)]
#[tokio::test]
+ async fn ctrl_click_url_does_not_forward_release_to_mouse_reporting_pane() {
+ let line = "see https://github.com/ogulcancelik/herdr/issues/1761";
+ let col = line.find("github").expect("url host") as u16;
+ let (mut app, info) = app_with_screen_bytes(b"");
+ let pane_id = app.state.workspaces[0].tabs[0].root_pane;
+ let screen = format!("\x1b[?1049h\x1b[?1000h\x1b[?1006h{line}");
+ let (runtime, mut input_rx) =
+ crate::terminal::TerminalRuntime::test_with_channel_and_scrollback_bytes(
+ info.inner_rect.width,
+ info.inner_rect.height,
+ 0,
+ screen.as_bytes(),
+ 4,
+ );
+ app.state.insert_test_runtime(pane_id, runtime);
+ install_test_link_handler(&mut app);
+ let mut send_mouse = |source_id, kind, column, modifiers| {
+ app.handle_mouse_from_input_source(
+ source_id,
+ modified_mouse(kind, column, info.inner_rect.y, modifiers),
+ );
+ };
+ let down = MouseEventKind::Down(MouseButton::Left);
+ let up = MouseEventKind::Up(MouseButton::Left);
+ let url_x = info.inner_rect.x + col;
+
+ send_mouse(41, down, url_x, KeyModifiers::CONTROL);
+ send_mouse(42, down, info.inner_rect.x, KeyModifiers::empty());
+ send_mouse(42, up, info.inner_rect.x, KeyModifiers::empty());
+ send_mouse(41, up, url_x, KeyModifiers::empty());
+
+ assert_eq!(app.state.plugin_command_logs.len(), 1);
+ assert_eq!(
+ input_rx.try_recv().expect("other source mouse down"),
+ Bytes::from_static(b"\x1b[<0;1;1M")
+ );
+ assert_eq!(
+ input_rx.try_recv().expect("other source mouse up"),
+ Bytes::from_static(b"\x1b[<0;1;1m")
+ );
+ assert!(
+ input_rx.try_recv().is_err(),
+ "handled URL click must not leave an unmatched release for the pane"
+ );
+ }
+
+ #[cfg(unix)]
+ #[tokio::test]
async fn ctrl_click_url_invokes_plugin_link_handler_but_super_click_does_not() {
let line = "see https://github.com/ogulcancelik/herdr/issues/398";
let col = line.find("github").expect("url host") as u16;