From 199475b6cab7ba483a4062ed8efa6c6534a40854 Mon Sep 17 00:00:00 2001 From: ken <39673849+SuperKenVery@users.noreply.github.com> Date: Thu, 6 Nov 2025 18:19:54 +0800 Subject: [PATCH] Stop disabling mouse tracking Commit eecc223 (Recognize and disable mouse-tracking CSI events, 2021-02-06) made fish disable mouse reporting whenever we receive a mouse event. This was because at the time we didn't have a parser for mouse inputs. We do now, so let's allow users to toggle mouse support with printf '\e[?1000h' printf '\e[?1000l' Currently the only mouse even we support is left click (to move cursor in commandline, select pager items). Part of #4918 See #12026 [ja: tweak patch and commit message] --- CHANGELOG.rst | 3 +++ doc_src/terminal-compatibility.rst | 4 ---- src/input_common.rs | 18 +++--------------- src/reader/reader.rs | 14 ++++---------- src/terminal.rs | 2 -- tests/pexpects/disable_mouse.py | 10 +++++----- 6 files changed, 15 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4c8c7059a..d9c65fd89 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -20,6 +20,9 @@ Interactive improvements - Fish now hides the portion of a multiline prompt that is scrolled out of view due to a huge command line. This prevents duplicate lines after repainting with partially visible prompt (:issue:`11911`). - On macOS, fish sets :envvar:`MANPATH` correctly also when that variable was already present in the environment (:issue:`10684`). - Added a workaround for MSYS2 to prevent Konsole and WezTerm from opening new tabs in the wrong working directory (:issue:`11981`). +- fish no longer disables mouse tracking sequences (DECSET/DECRST 1000), + so you can use those to toggle mouse reporting, + which allows to move the cursor or select completions items with the mouse (:issue:`4918`). Scripting improvements ---------------------- diff --git a/doc_src/terminal-compatibility.rst b/doc_src/terminal-compatibility.rst index 34d1d1f01..72b44ae8d 100644 --- a/doc_src/terminal-compatibility.rst +++ b/doc_src/terminal-compatibility.rst @@ -239,10 +239,6 @@ Optional Commands - cvvis - Enable cursor visibility (DECTCEM). - VT220 - * - ``\e[?1000l`` - - n/a - - Disable mouse reporting. - - XTerm * - ``\e[?1004h`` - n/a - Enable focus reporting. diff --git a/src/input_common.rs b/src/input_common.rs index 9a499f802..1d59e2091 100644 --- a/src/input_common.rs +++ b/src/input_common.rs @@ -324,8 +324,6 @@ pub enum ImplicitEvent { FocusIn, /// Our terminal window lost focus. FocusOut, - /// Request to disable mouse tracking. - DisableMouseTracking, /// Mouse left click. MouseLeft(ViewportPosition), } @@ -1049,7 +1047,7 @@ fn parse_csi(&mut self, buffer: &mut Vec) -> Option { b'F' => masked_key(key::End), // PC/xterm style b'H' => masked_key(key::Home), // PC/xterm style b'M' | b'm' => { - self.disable_mouse_tracking(); + FLOG!(reader, "mouse event"); // Generic X10 or modified VT200 sequence, or extended (SGR/1006) mouse // reporting mode, with semicolon-separated parameters for button code, Px, // and Py, ending with 'M' for button press or 'm' for button release. @@ -1089,14 +1087,14 @@ fn parse_csi(&mut self, buffer: &mut Vec) -> Option { return None; } b't' => { - self.disable_mouse_tracking(); + FLOG!(reader, "mouse event"); // VT200 button released in mouse highlighting mode at valid text location. 5 chars. let _ = next_char(self); let _ = next_char(self); return None; } b'T' => { - self.disable_mouse_tracking(); + FLOG!(reader, "mouse event"); // VT200 button released in mouse highlighting mode past end-of-line. 9 characters. for _ in 0..6 { let _ = next_char(self); @@ -1249,16 +1247,6 @@ fn parse_csi(&mut self, buffer: &mut Vec) -> Option { Some(key) } - fn disable_mouse_tracking(&mut self) { - // fish recognizes but does not actually support mouse reporting. We never turn it on, and - // it's only ever enabled if a program we spawned enabled it and crashed or forgot to turn - // it off before exiting. We turn it off here to avoid wasting resources. - FLOG!(reader, "Disabling mouse tracking"); - - // We shouldn't directly manipulate stdout from here, so we ask the reader to do it. - self.push_front(CharEvent::Implicit(ImplicitEvent::DisableMouseTracking)); - } - fn parse_ss3(&mut self, buffer: &mut Vec) -> Option { let mut raw_mask = 0; let Some(mut code) = self.try_readb(buffer) else { diff --git a/src/reader/reader.rs b/src/reader/reader.rs index 5acb07b64..edc30f3ad 100644 --- a/src/reader/reader.rs +++ b/src/reader/reader.rs @@ -127,10 +127,10 @@ use crate::terminal::Output; use crate::terminal::Outputter; use crate::terminal::TerminalCommand::{ - ClearScreen, DecrstAlternateScreenBuffer, DecrstMouseTracking, DecsetAlternateScreenBuffer, - DecsetShowCursor, Osc0WindowTitle, Osc133CommandFinished, Osc133CommandStart, - QueryCursorPosition, QueryKittyKeyboardProgressiveEnhancements, QueryPrimaryDeviceAttribute, - QueryXtgettcap, QueryXtversion, + ClearScreen, DecrstAlternateScreenBuffer, DecsetAlternateScreenBuffer, DecsetShowCursor, + Osc0WindowTitle, Osc133CommandFinished, Osc133CommandStart, QueryCursorPosition, + QueryKittyKeyboardProgressiveEnhancements, QueryPrimaryDeviceAttribute, QueryXtgettcap, + QueryXtversion, }; use crate::termsize::{termsize_invalidate_tty, termsize_last, termsize_update}; use crate::text_face::TextFace; @@ -2623,12 +2623,6 @@ fn handle_char_event(&mut self, injected_event: Option) -> ControlFlo event::fire_generic(self.parser, L!("fish_focus_out").to_owned(), vec![]); self.save_screen_state(); } - ImplicitEvent::DisableMouseTracking => { - Outputter::stdoutput() - .borrow_mut() - .write_command(DecrstMouseTracking); - self.save_screen_state(); - } ImplicitEvent::MouseLeft(position) => { FLOG!(reader, "Mouse left click", position); self.request_cursor_position( diff --git a/src/terminal.rs b/src/terminal.rs index 358fd1bd3..24026afe5 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -111,7 +111,6 @@ pub(crate) enum TerminalCommand<'a> { ScrollContentUp(usize), DecsetShowCursor, - DecrstMouseTracking, DecsetFocusReporting, DecrstFocusReporting, DecsetBracketedPaste, @@ -183,7 +182,6 @@ fn write(out: &mut impl Output, sequence: &'static [u8]) -> bool { QueryCursorPosition => write(self, b"\x1b[6n"), ScrollContentUp(lines) => scroll_content_up(self, lines), DecsetShowCursor => write(self, b"\x1b[?25h"), - DecrstMouseTracking => write(self, b"\x1b[?1000l"), DecsetFocusReporting => write(self, b"\x1b[?1004h"), DecrstFocusReporting => write(self, b"\x1b[?1004l"), DecsetBracketedPaste => write(self, b"\x1b[?2004h"), diff --git a/tests/pexpects/disable_mouse.py b/tests/pexpects/disable_mouse.py index 0c5c13db7..0112fd5f7 100644 --- a/tests/pexpects/disable_mouse.py +++ b/tests/pexpects/disable_mouse.py @@ -8,25 +8,25 @@ sp.expect_prompt() # Five char sequence. sp.send("\x1b[tDE") -sp.expect_str("reader: Disabling mouse tracking") +sp.expect_str("reader: mouse event") # Six char sequence. sp.send("\x1b[MABC") -sp.expect_str("reader: Disabling mouse tracking") +sp.expect_str("reader: mouse event") # Nine char sequences. sp.send("\x1b[TABCDEF") -sp.expect_str("reader: Disabling mouse tracking") +sp.expect_str("reader: mouse event") # sleep to catch up under ASAN sp.sleep(0.5) # Extended SGR sequences. sp.send("\x1b[<1;2;3M") -sp.expect_str("reader: Disabling mouse tracking") +sp.expect_str("reader: mouse event") sp.send("\x1b[<1;2;3m") -sp.expect_str("reader: Disabling mouse tracking") +sp.expect_str("reader: mouse event") sp.sendline("echo done") sp.expect_prompt("done")