Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Enable putting cursor by mouse clicking#12026

Draft
SuperKenVery wants to merge 9 commits intofish-shell:masterfrom
SuperKenVery:feat/superkenvery/click-put-cursor
Draft

Enable putting cursor by mouse clicking#12026
SuperKenVery wants to merge 9 commits intofish-shell:masterfrom
SuperKenVery:feat/superkenvery/click-put-cursor

Conversation

@SuperKenVery
Copy link
Contributor

@SuperKenVery SuperKenVery commented Nov 6, 2025

Description

The mouse handling code was already there. What I did:

  • Enable mouse reporting when initializing terminal
  • Remove disable_mouse_tracking calls

Fixes issue #4918

TODOs:

  • Changes to fish usage are reflected in user documentation/manpages.
  • Tests have been added for regressions fixed
  • User-visible changes noted in CHANGELOG.rst

@SuperKenVery SuperKenVery marked this pull request as ready for review November 6, 2025 10:26
@krobelus krobelus added this to the fish 4.2 milestone Nov 6, 2025
@krobelus
Copy link
Contributor

krobelus commented Nov 6, 2025 via email

krobelus pushed a commit that referenced this pull request Nov 6, 2025
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]
@krobelus krobelus removed this from the fish 4.2 milestone Nov 6, 2025
@krobelus krobelus added this to the fish 4.2 milestone Nov 7, 2025
@krobelus
Copy link
Contributor

krobelus commented Nov 7, 2025 via email

@SuperKenVery
Copy link
Contributor Author

Well, the main reason is I didn't know about alt-e...

My use case is that, I'm doing some deep learning work and I have very long and multi-line commands, like this:

CUDA_VISIBLE_DEVICES=0,1 \
    accelerate launch --main_process_port 0 1_train_model.py \
      --model SPF_LUT_net \
      --scale 4 \
      --modes s \
      --expDir ../models/take-residual-out \
      --trainDir ../data/DIV2K \
      --valDir ../data/SRBenchmark \
      --sample-size 3 \
      --workerNum 8 \
      --batchSize 16

And changing a number in the middle can often be a pain in the ass.

As for the word selecting, I can just hold shift and everything would go back (and mouse events won't be reported to program in terminal), at least in wezterm.

@krobelus
Copy link
Contributor

krobelus commented Nov 8, 2025 via email

@SuperKenVery
Copy link
Contributor Author

LMK if that changes (or if you won't use it at all now that you know about alt-e)

I would probably still use this. I often just need to change some digits, and opening helix for that, then click (on the top part of the screen rather than in place), then go to insert mode, change, and escape and save, is a little bit long.

Most users probably don't know about the trick with holding shift

Well if people uses vim or helix, or anything that captures mouse, and they want to copy text to clipboard, they probably need to know this.

Also, we probably can't break habits.

Yeah, and when fish_mouse isn't set this is default to off, so I think it should be fine.

reader_set_autosuggestion_enabled(vars);
}

fn handle_fish_mouse_change(vars: &EnvStack) {
Copy link
Contributor

@krobelus krobelus Nov 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the "fish_" seems reundant,
though we could call this function handle_mouse_enabled_change or similar, not sure.
Maybe we should also rename the user-visible variable,
but tmux also calls it just "mouse" so maybe this seems fine.

}

fn handle_fish_mouse_change(vars: &EnvStack) {
let Some(data) = current_data() else {
Copy link
Contributor

@krobelus krobelus Nov 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd do something like this for docs and completions:

diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 76d1bc52fa..649fb82e26 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -22,8 +22,7 @@
 - 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,
+- It is now possible to enable mouse capture by setting :envvar:`fish_mouse`,
   which allows to move the cursor or select completions items with the mouse (:issue:`4918`).
 
 Scripting improvements
diff --git a/doc_src/language.rst b/doc_src/language.rst
index 37c3888894..6f42f29f89 100644
--- a/doc_src/language.rst
+++ b/doc_src/language.rst
@@ -1628,6 +1628,11 @@
    empty string, history is not saved to disk (but is still available within the interactive
    session).
 
+.. envvar:: fish_mouse
+
+   Set it to 1 to capture mouse input, which allows move the cursor and select pager items using the mouse.
+   Note that this will prevent the terminal from handling mouse input.
+
 .. envvar:: fish_trace
 
    if set and not empty, will cause fish to print commands before they execute, similar to ``set -x``
diff --git a/share/completions/set.fish b/share/completions/set.fish
index f5396f6dfc..82d294c295 100644
--- a/share/completions/set.fish
+++ b/share/completions/set.fish
@@ -56,6 +56,7 @@
         umask "current file creation mask" \
         fish_ambiguous_width "affects computed width of east asian chars" \
         fish_autosuggestion_enabled "set to 0 to turn autosuggestions off" \
+        fish_mouse "set to 1 to capture mouse input" \
         fish_cursor_end_mode "set to 'inclusive' to disallow moving the cursor beyond the command line end" \
         fish_cursor_selection_mode "set to 'inclusive' if selections should include the cursor" \
         fish_emoji_width "cols wide fish assumes emoji render as" \

DecsetMouseTracking
} else {
DecrstMouseTracking
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not as simple as that
because the TtyProtocolsSet is immutable.
So the variable change would be lost after the next command.

To make this work reliably, I think we should

  1. disable all protocols
  2. toggle our flag
  3. re-enable protocols, including our flag

Something like

    SetMouseTracking(enabled) => {
        FLOG!(reader, "Set mouse tracking enabled:", enabled);
        let mut tty = TtyHandoff::new(reader_save_screen_state);
        tty.disable_tty_protocols();
	// TODO now set a global atomic bool in tty_handoff.rs
	// Now let the Drop implementation of TtyHandoff re-enable
	// TTY protocols, including mouse capture if applicable.
    }

Since this involves atomics and async-signal-safe code,
it may get tricky (though it also might not),
if you prefer I can finish this when I get around to

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh. I previously tried to disable protocols, re-initialize tty protocols, then re-enable them, after fish_mouse is changed. However it didn't work as expected and I couldn't figure it out, what's more, that introduced a race condition that sometimes triggered an assertion that protocols should be off when running commands. Probably my implementation was problematic, though.

because the TtyProtocolsSet is immutable

This should explain why it didn't work...

I certainly need to dig deeper to solve this.

Also, out of curiosity, why did you handle the atomics yourself? I believe there are wrappers like OnceLock or LazyLock, which should make life easier.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, out of curiosity, why did you handle the atomics yourself? I believe there are wrappers like OnceLock or LazyLock, which should make life easier.

When you do kill -TERM $fish_pid, fish wants to disable TTY protocols.
This is currently done in a signal handler (on an arbitrary thread).

We can not use things like Mutex in signal handlers. See man signal-safety for which functions are allowed in signal handlers. For Rust APIs, we'd ideally also want a promise that the implementation won't violate signal safety in future.

Hence the mouse disposition should be accessible in a global variable by only calling async-signal-safe functions.
We try to prefix the name of every function that is used in a signal handler with safe_.

fn get_protocols(self) -> TtyProtocolsSet {
fn get_protocols(self, vars: &dyn Environment) -> TtyProtocolsSet {
let mut on_chain = vec![DecsetBracketedPaste];
let mut off_chain = vec![DecrstBracketedPaste];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with the other comment, changing the serialized commands should no longer be necessary,
but let's keep the cleanup for the tmux-specific code paths,
ideally in a separate commit

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you get the chance to work on this, can you clean up the commit history, i.e. squash most commits -- the final result should probably have two commits, one for the tmux-hack cleanup, and another one to add fish_mouse.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I will do that when I get time...

@zanchey zanchey modified the milestones: fish 4.2, fish-future Nov 12, 2025
@krobelus krobelus modified the milestones: fish-future, fish 4.3 Nov 15, 2025
@krobelus krobelus marked this pull request as draft November 15, 2025 14:24
@krobelus krobelus modified the milestones: fish 4.3, fish-future Nov 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants