So far, terminals that fail to parse OSC sequences are the only reason
for wanting to turn off OSC 133. Let's allow to work around it by
adding a feature flag (which is implied to be temporary).
To use it, run this once, and restart fish:
set -Ua fish_features no-mark-prompt
Tested with
fish -i | string escape | grep 133 &&
! fish_features=no-mark-prompt fish -i | string escape | grep 133
See #11749
Also #11609
This is standard on macOS and in chrome/firefox.
On master, this was sneakily added in
2bb5cbc959 (Default bindings for token movements v2, 2025-03-04)
and before that in
6af96a81a8 (Default bindings for token movement commands, 2024-10-05)
Ref: https://lobste.rs/s/ndlwoh/wizard_his_shell#c_qvhnvd
Cherry-picked from
- 941701da3d (Restore some async-signal discipline to SIGTERM, 2025-06-15)
- 81d45caa76e (Restore terminal state on SIGTERM again, 2025-06-21)
Also, be more careful in terminal_protocols_disable_ifn about accessing
reader_current_data(), as pointed out in 65a4cb5245 (Revert "Restore terminal
state on SIGTERM again", 2025-07-19).
See #11597
Historically, fish has treated input bytes [0x1b, 'b'] as alt-b (rather than
"escape,b") if the second byte arrives within 30ms of the first.
Since we made builtin bind match key events instead of raw byte sequences,
we have another place where we do similar disambiguation: when we read keys
such as alt-left ("\e[1;3D"), we only consider bytes to be part of this
sequence if stdin is immediately readable (actually "readable after a 1ms
timeout" since e1be842 (Work around torn byte sequences in qemu kbd input
with 1ms timeout, 2025-03-04)).
This is technically wrong but has worked in practice (for Kakoune etc.).
Issue #11668 reports two issues on some Windows terminals feeding a remote
fish shell:
- the "bracketed paste finished" sequence may be split into multiple packets,
which causes a delay of > 1ms between individual bytes being readable.
- AutoHotKey scripts simulating seven "left" keys result in sequence tearing
as well.
Try to fix the paste case by increasing the timeout when parsing escape
sequences.
Also increase the timeout for terminals that support the kitty keyboard
protocol. The user should only notice this new delay after pressing one of
escape,O, escape,P, escape,[, or escape,] **while the kitty keyboard protocol
is disabled** (e.g. while an external command is running). In this case,
the fish_escape_delay_ms is also virtually increased; hopefully this edge
case is not ever relevant.
Part of #11668
(cherry picked from commit 30ff3710a0)
readb() has only one caller that passes blocking=false: try_readb().
This function is used while decoding keys; anything but a successful read
is treated as "end of input sequence".
This means that key input sequences such as \e[1;3D
can be torn apart by
- signals (EINTR) which is more likely since e1be842 (Work around torn byte
sequences in qemu kbd input with 1ms timeout, 2025-03-04).
- universal variable notifications (from other fish processes)
Fix this by blocking signals and not listening on the uvar fd. We do something
similar when matching key sequences against bindings, so extract a function
and use it for key decoding too.
Ref: https://github.com/fish-shell/fish-shell/issues/11668#issuecomment-3101341081
(cherry picked from commit da96172739)
try_readch() was added to help a fuzzing harness, specifically to avoid a
call to `unreachable!()` in the NothingToRead case. I don't know much about
that but it seems like we should find a better way to tell the fuzzer that
this can't happen.
Fortunately the next commit will get rid of readb()'s "blocking" argument,
along the NothingToRead enum variant. So we'll no longer need this.
This reverts commit b92830cb17.
(cherry picked from commit fb7ee0db74)
Historically, ctrl-i sends the same code as tab, ctrl-h sends backspace and
ctrl-j and ctrl-m behave like enter.
Even for terminals that send unambiguous encodings (via the kitty keyboard
protocol), we have kept bindings like ctrl-h, to support existing habits.
We forgot that pressing alt-ctrl-h would behave like alt-backspace (and can
be easier to reach) so maybe we should add that as well.
Don't add ctrl-shift-i because at least on Linux, that's usually intercepted
by the terminal emulator.
Technically there are some more such as "ctrl-2" (which used to do the same as
"ctrl-space") but I don't think anyone uses that over "ctrl-space".
Closes #https://github.com/fish-shell/fish-shell/discussions/11548
(cherry picked from commit 4d67ca7c58)
From commit ba00d721f4 (Correct statvfs call to statfs, 2025-06-19):
> This was missed in the Rust port
To elaborate:
- ec176dc07e (Port path.h, 2023-04-09) didn't change this (as before,
`statvfs` used `ST_LOCAL` and `statfs` used `MNT_LOCAL`)
- 6877773fdd (Fix build on NetBSD (#10270), 2024-01-28) changed the `statvfs`
call to `statfs`, presumably due to the libc-wrapper for
`statvfs` being missing on NetBSD. This change happens
to work fine on NetBSD because they do [`#define ST_LOCAL
MNT_LOCAL`](https://github.com/fish-shell/fish-shell/pull/11486#discussion_r2092408952)
But it was wrong on others like macOS and FreeBSD, which was fixed by
ba00d721f4 (but that broke the build on NetBSD).
- 7228cb15bf (Include sys/statvfs.h for the definition of ST_LOCAL (Rust
port regression), 2025-05-16)
fixed a code clone left behind by the above commit (incorrectly assuming
that the clone had always existed.)
Fix the NetBSD build specifically by using statfs on that platform.
Note that this still doesn't make the behavior equivalent to commit LastC++11.
That one used ST_LOCAL if defined, and otherwise MNT_LOCAL if defined.
If we want perfect equivalence, we could detect both flags in `src/build.rs`.
Then we would also build on operating systems that define neither. Not sure.
Closes#11596
(cherry picked from commit 6644cc9b0e)
Commit 97581ed20f (Do send bracketed paste inside midnight commander,
2024-10-12) accidentally started sending CSI commands such as "CSI >5;0m",
which we intentionally didn't do for some old versions of Midnight Commander,
which fail to parse them. Fix that.
Fixes#11617
Systems like NixOS might not have "git-receive-pack" or any other "git-*"
executable in in $PATH -- instead they patch git to use absolute paths.
This is weird. But no reason for us to fail. Silence the error.
Fixes#11590
(cherry picked from commit 4f46d369c4)
Commit cd3da62d24 (fix(completion): unescape strings for __fish_complete_list,
2024-09-17) bravely addressed an issue that exists in a lot of completions.
It did so only for __fish_complete_list. Fair enough.
Unfortunately it unescaped more than just "$(commandline -t)".
This causes the problem described at
https://github.com/fish-shell/fish-shell/issues/11508#issuecomment-2889088934
where completion descriptions containing a backslash followed by "n" are
interpreted as newlines, breaking the completion parser. Fix that.
(cherry picked from commit 60881f1195)
Given a command line like
foo --foo=bar=baz=qux\=argument
(the behavior is the same if '=' is substituted with ':').
fish completes arguments starting from the last unescaped separator, i.e.
foo --foo=bar=baz=qux\=argument
^
__fish_complete_list provides completions like
printf %s\n (commandline -t)(printf %s\n choice1 choice2 ...)
This means that completions include the "--foo=bar=baz=" prefix.
This is wrong. This wasn't a problem until commit f9febba (Fix replacing
completions with a -foo prefix, 2024-12-14), because prior to that, replacing
completions would replace the entire token.
This made it too hard to writ ecompletions like
complete -c foo -s s -l long -xa "hello-world goodbye-friend"
that would work with "foo --long fri" as well as "foo --long=frie".
Replacing the entire token would only work if the completion included that
prefix, but the above command is supposed to just work.
So f9febba made us replace only the part after the separator.
Unfortunately that caused the earlier problem. Work around this. The change
is not pretty, but it's a compromise until we have a better way of telling
which character fish considers to be the separator.
Fixes#11508
(cherry picked from commit 320ebb6859)
This was missed in the Rust port - C++ had statfs for MNT_LOCAL and not statvfs.
The effect of this is that fish never thought its filesystem was local on macOS
or BSDs (Linux was OK). This caused history race tests to fail, and also could
in rare cases result in history items being dropped with multiple concurrent
sessions.
This fixes the history race tests under macOS and FreeBSD - we weren't locking
because we thought the history was a remote file.
Cherry-picked from ba00d721f4
As explained in c3740b85be (config_paths: fix compiled-in locale dir,
2025-06-12), fish is "relocatable", i.e. "mv /usr/ /usr2/" will leave
"/usr2/bin/fish" fully functional.
There is one exception: for LOCALEDIR we always use the path determined at
compile time.
This seems wrong; let's use the same relocatable-logic as for other paths.
Inspired by bf65b9e3a7 (Change `gettext` paths to be relocatable (#11195),
2025-03-30).
On terminals that do not implement the kitty keyboard protocol "ctrl-ц" on
a Russian keyboard layout generally sends the same byte as "ctrl-w". This
is because historically there was no standard way to encode "ctrl-ц",
and the "ц" letter happens to be in the same position as "w" on the PC-101
keyboard layout.
Users have gotten used to this, probably because many of them are switching
between a Russian (or Greek etc.) and an English layout.
Vim/Emacs allow opting in to this behavior by setting the "input method"
(which probably means "keyboard layout").
Match key events that have the base layout key set against bindings for
that key.
Closes#11520
---
Alternatively, we could add the relevant preset bindings (for "ctrl-ц" etc.)
but
1. this will be wrong if there is a disagreement on the placement of "ц" between two layouts
2. there are a lot of them
3. it won't work for user bindings (for better or worse)
(cherry picked from commit 7a79728df3)
As explained in the parent commit, "alt-+" is usually preferred over
"alt-shift-=" but both have their moments. We communicate this via a comment
saying "# recommended notation". This is not always true and not super helpful,
especially as we add a third variant for #11520 (physical key), which is
the recommended one for users who switch between English and Cyrillic layouts.
Only explain what each variant does. Based on this the user may figure out
which one to use.
(cherry picked from commit 4cbd1b83f1)
This was copied from C++ code but we have overflow checks, which
forces us to actually handle errors.
While at it, add some basic error logging.
Fixes#11092
(cherry picked from commit 4c28a7771e)
When "self.paste_is_buffering()" is true, "parse_escape_sequence()" explicitly
returns "None" instead of "Some(Escape)". This is irrelevant because this
return value is never read, as long as "self.paste_is_buffering()" remains
true until "parse_escape_sequence()" returns, because the caller will return
early in that case. Paste buffering only ends if we actually read a complete
escape sequence (for ending bracketed paste).
Remove this extra branch.
(cherry picked from commit e5fdd77b09)
The new key notation canonicalizes aggressively, e.g. these two bindings
clash:
bind ctrl-shift-a something
bind shift-ctrl-a something else
This means that key events generally match at most one active binding that
uses the new syntax.
The exception -- two coexisting new-syntax binds that match the same key
event -- was added by commit 50a6e486a5 (Allow explicit shift modifier for
non-ASCII letters, fix capslock behavior, 2025-03-30):
bind ctrl-A 'echo A'
bind ctrl-shift-a 'echo shift-a'
The precedence was determined by definition order.
This doesn't seem very useful.
A following patch wants to resolve#11520 by matching "ctrl-ц" events against
"ctrl-w" bindings. It would be surprising if a "ctrl-w" binding shadowed a
"ctrl-ц" one based on something as subtle as definition order. Additionally,
definition order semantics (which is an unintended cause of the implementation)
is not really obvious. Reverse definition order would make more sense.
Remove the ambiguity by always giving precedence to bindings that use
explicit shift.
Unrelated to this, as established in 50a6e486a5, explicit shift is still
recommended for bicameral letters but not typically for others -- e.g. alt-+
is typically preferred over alt-shift-= because the former also works on a
German keyboard.
See #11520
(cherry picked from commit 08c8afcb12)
We canonicalize "ctrl-shift-i" to "ctrl-I".
Both when deciphering this notation (as given to builtin bind),
and when receiving it as a key event ("\e[105;73;6u")
This has problems:
A. Our bind notation canonicalization only works for 26 English letters.
For example, "ctrl-shift-ä" is not supported -- only "ctrl-Ä" is.
We could try to fix that but this depends on the keyboard layout.
For example "bind alt-shift-=" and "bind alt-+" are equivalent on a "us"
layout but not on a "de" layout.
B. While capslock is on, the key event won't include a shifted key ("73" here).
This is due a quirk in the kitty keyboard protocol[^1]. This means that
fish_key_reader's canonicalization doesn't work (unless we call toupper()
ourselves).
I think we want to support both notations.
It's recommended to match all of these (in this order) when pressing
"ctrl-shift-i".
1. bind ctrl-shift-i do-something
2. bind ctrl-shift-I do-something
3. bind ctrl-I do-something
4. bind ctrl-i do-something
Support 1 and 3 for now, allowing both bindings to coexist. No priorities
for now. This solves problem A, and -- if we take care to use the explicit
shift notation -- problem B.
For keys that are not affected by capslock, problem B does not apply. In this
case, recommend the shifted notation ("alt-+" instead of "alt-shift-=")
since that seems more intuitive.
Though if we prioritized "alt-shift-=" over "alt-+" as per the recommendation,
that's an argument against the shifted key.
Example output for some key events:
$ fish_key_reader -cV
# decoded from: \e\[61:43\;4u
bind alt-+ 'do something' # recommended notation
bind alt-shift-= 'do something'
# decoded from: \e\[61:43\;68u
bind alt-+ 'do something' # recommended notation
bind alt-shift-= 'do something'
# decoded from: \e\[105:73\;6u
bind ctrl-I 'do something'
bind ctrl-shift-i 'do something' # recommended notation
# decoded from: \e\[105\;70u
bind ctrl-shift-i 'do something'
Due to the capslock quirk, the last one has only one matching representation
since there is no shifted key. We could decide to match ctrl-shift-i events
(that don't have a shifted key) to ctrl-I bindings (for ASCII letters), as
before this patch. But that case is very rare, it should only happen when
capslock is on, so it's probably not even a breaking change.
The other way round is supported -- we do match ctrl-I events (typically
with shifted key) to ctrl-shift-i bindings (but only for ASCII letters).
This is mainly for backwards compatibility.
Also note that, bindings without other modifiers currently need to use the
shifted key (like "Ä", not "shift-ä"), since we still get a legacy encoding,
until we request "Report all keys as escape codes".
[^1]: <https://github.com/kovidgoyal/kitty/issues/8493>
(cherry picked from commit 50a6e486a5)
This notation doesn't make sense, use either A or shift-a. We accept it
for ASCII letters only -- things like "bind shift-!" or "bind shift-Ä"
do not work as of today, we don't tolerate extra shift modifiers yet.
So let's remove it for consistency.
Note that the next commit will allow the shift-A notation again, but it will
not match shift-a events.
(cherry picked from commit 7f25d865a9)
Switch to fish_wcstoul because we want the constant to be unsigned.
It's u32 because most callers of function_key() want that.
(cherry picked from commit e9d1cdfe87)
Commit 109ef88831 (Add menu and printscreen keys, 2025-01-01)
accidentally broke an assumption by inverting f1..f12. Fix that.
Fixes#11098
(cherry picked from commit d2b2c5286a)
These aren't typically used in the terminal but they are present on
many keyboards.
Also reorganize the named key constants a bit. Between F500 and
ENCODE_DIRECT_BASE (F600) we have space for 256 named keys.
(cherry picked from commit 109ef88831)
We parse "\e\e[x" as alt-modified "Invalid" key. Due to this extra
modifier, we accidentally add it to the input queue, instead of
dropping this invalid key.
We don't really want to try to extract some valid keys from this
invalid sequence, see also the parent commit.
This allows us to remove misplaced validation that was added by
e8e91c97a6 (fish_key_reader: ignore sentinel key, 2024-04-02) but
later obsoleted by 66c6e89f98 (Don't add collateral sentinel key to
input queue, 2024-04-03).
(cherry picked from commit 84f19a931d)
This situation can be triggered in practice inside a terminal like tmux
3.5 by running
tmux new-session fish -C 'sleep 2' -d reader -o log-file
and typing "alt-escape x"
The log shows that we drop treat this as alt-[ and drop the x on the floor.
reader: Read char alt-\[ -- Key { modifiers: Modifiers { ctrl: false,
alt: true, shift: false }, codepoint: '[' } -- [27, 91, 120]
This input ("\e[x") is ambiguous.
It looks like it could mean "alt-[,x". However that conflicts with a
potential future CSI code, so it makes no sense to try to support this.
Returning "None" from parse_csi() causes this weird behavior of
returning "alt-[" and dropping the rest of the parsed sequence.
This is too easy; it has even crept into a bunch of places
where the input sequence is actually valid like "VT200 button released"
but where we definitely don't want to report any key.
Fix the default: report no key for all unknown sequences and
intentionally-suppressed sequences. Treat it at "alt-[" only when
there is no input byte available, which is more or less unambiguous,
hence a strong enough signal that this is a actually "alt-[".
(cherry picked from commit 3201cb9f01)