fish’s core code has been ported from C++ to Rust (#9512). This means a large change in dependencies and how to build fish. However, there should be no direct impact on users. Packagers should see the For Distributors section at the end.
Notable backwards-incompatible changes
-
As part of a larger binding rework,
bind
gained a new key notation.
In most cases the old notation should keep working, but in rare cases you may have to change abind
invocation to use the new notation.
See below for details. -
ctrl-c
now calls a new bind function calledclear-commandline
. The old behavior, which leaves a “^C” marker, is available ascancel-commandline
(#10935) -
random
will produce different values from previous versions of fish when used with the same seed, and will work more sensibly with small seed numbers.
The seed was never guaranteed to give the same result across systems,
so we do not expect this to have a large impact (#9593). -
Variables in command position that expand to a subcommand keyword are now forbidden to fix a likely user error.
For example,set editor command emacs; $editor
is no longer allowed (#10249). -
functions --handlers
will now list handlers in a different order.
Now it is definition order, first to last, where before it was last to first.
This was never specifically defined, and we recommend not relying on a specific order (#9944). -
The
qmark-noglob
feature, introduced in fish 3.0, is enabled by default. That means?
will no longer act as a single-character glob.
You can, for the time being, turn it back on by addingno-qmark-noglob
tofish_features
and restarting fish:set -Ua fish_features no-qmark-noglob
The flag will eventually be made read-only, making it impossible to turn off.
-
Terminals that fail to ignore unrecognized OSC or CSI sequences may display garbage. We know cool-retro-term and emacs’ ansi-term are affected, but most mainstream terminals are not.
-
fish no longer searches directories from the Windows system/user
$PATH
environment variable for Linux executables. To execute Linux binaries by name (i.e. not with a relative or absolute path) from a Windows folder, make sure the/mnt/c/...
path is explicitly added to$fish_user_paths
and not just automatically appended to$PATH
bywsl.exe
(#10506). -
Under Microsoft Windows Subsystem for Linux 1 (not WSL 2), backgrounded jobs that have not been disowned and do not terminate on their own after a
SIGHUP
+SIGCONT
sequence will be explicitly killed by fish on exit (after the usual prompt to close or disown them) to work around a WSL 1 deficiency that sees backgrounded processes that run intoSIGTTOU
remain in a suspended state indefinitely (#5263). The workaround is to explicitlydisown
processes you wish to outlive the shell session.
Notable improvements and fixes
-
fish now requests XTerm’s
modifyOtherKeys
keyboard encoding and kitty keyboard protocol’s progressive enhancements (#10359).
Depending on terminal support, this allows to binding more key combinations, including arbitrary combinations of modifiersctrl
,alt
andshift
, and distinguishing (for example)ctrl-i
fromtab
.Additionally,
bind
now supports a human-readable syntax in addition to byte sequences.
This includes modifier names, and names for keys likeenter
andbackspace
.
For examplebind up 'do something'
binds the up-arrow key instead of a two-key sequence (“u” and then “p”)bind ctrl-x,alt-c 'do something'
binds a sequence of two keys.
Any key argument that starts with an ASCII control character (like
e
orcX
) or is up to 3 characters long, not a named key, and does not contain,
or-
will be interpreted in the old syntax to keep compatibility for the majority of bindings.Keyboard protocols can be turned off by disabling the “keyboard-protocols” feature flag:
set -Ua fish_features no-keyboard-protocols
This is a temporary measure to work around buggy terminals (#11056), which appear to be relatively rare.
Use this if something like “=0” or “=5u” appears in your commandline mysteriously. -
fish can now be built as a self-installing binary (#10367). That means it can be easily built on one system and copied to another, where it can extract supporting files.
To do this, run:cargo install --path . # in a clone of the fish repository # or `cargo build --release` and copy target/release/fish{,_indent,_key_reader} wherever you want
The first time it runs interactively, it will extract all the data files to
~/.local/share/fish/install/
. A specific path can be used for the data files withfish --install=PATH
To uninstall, remove the fish binaries and that directory.This build system is experimental; the main build system, using
cmake
, remains the recommended approach for packaging and installation to a prefix. -
A new function
fish_should_add_to_history
can be overridden to decide whether a command should be added to the history (#10302). -
Bindings can now mix special input functions and shell commands, so
bind ctrl-g expand-abbr "commandline -i n"
works as expected (#8186). -
Special input functions run from bindings via
commandline -f
are now applied immediately, instead of after the currently executing binding (#3031, #10126).
For example,commandline -i foo; commandline | grep foo
succeeds now. -
Undo history is no longer truncated after every command, but kept for the lifetime of the shell process.
-
The
ctrl-r
history search now uses glob syntax (#10131). -
The
ctrl-r
history search now operates only on the line or command substitution at cursor, making it easier to combine commands from history (#9751). -
Abbreviations can now be restricted to specific commands. For instance:
abbr --add --command git back 'reset --hard HEAD^'
will expand “back” to
reset --hard HEAD^
, but only when the command isgit
(#9411).
Deprecations and removed features
-
commandline --tokenize
(short option-o
) has been deprecated in favor ofcommandline --tokens-expanded
(short option-x
) which expands variables and other shell syntax, removing the need to use eval in completion scripts (#10212). -
Two new feature flags:
remove-percent-self
(seestatus features
) disables PID expansion of%self
, which has been supplanted by$fish_pid
(#10262).test-require-arg
disablestest
’s one-argument mode. That meanstest -n
without an additional argument will return false,test -z
will keep returning true. Any other option without an argument, anything that is not an option and no argument will be an error. This also goes for[
, test’s alternate name.
This is a frequent source of confusion and so we are breaking with POSIX explicitly in this regard.
In addition to the feature flag, there is a debug category “deprecated-test”. Running fish withfish -d deprecated-test
will show warnings whenever atest
invocation that would change is used. (#10365).
These can be enabled with:
set -Ua fish_features remove-percent-self test-require-arg
We intend to enable them by default in future, and after that eventually make them read-only.
-
Specifying key names as terminfo names (using the
bind -k
syntax) is deprecated and may be removed in a future version. -
When a terminal pastes text into fish using bracketed paste, fish used to switch to a special
paste
bind mode.
This bind mode has been removed. The behavior on paste is no longer configurable. -
When an interactive fish is stopped or terminated by a signal that cannot be caught (SIGSTOP or SIGKILL), it may leave the terminal in a state where keypresses with modifiers are sent as CSI u sequences, instead of traditional control characters or escape sequences that are recognized by Readline and compatible programs, such as bash and python.
If this happens, you can use thereset
command fromncurses
to restore the terminal state. -
fish_key_reader --verbose
no longer shows timing information. -
Terminal information is no longer read from hashed terminfo databases, or termcap databases (#10269). The vast majority of systems use a non-hashed terminfo database, which is still supported.
-
source
returns an error if used without a filename or pipe/redirection (#10774).
5 Comments
abound
The most interesting thing about Fish 4.0.0 for most people will be that it is now written in Rust, which they talk about here [1]. Looking forward to testing it out and seeing if there are any noticeable differences.
[1] https://github.com/fish-shell/fish-shell/pull/9512
nindalf
Fish 4.0: The Fish Of Theseus (https://fishshell.com/blog/rustport/) is the full story of their rewrite from C++ to Rust.
Discussed on HN here – https://news.ycombinator.com/item?id=42535217 (906 points, 198 comments).
Highlights of the rewrite
– 1155 files changed, 110247 insertions(+), 88941 deletions(-) (excluding translations)
– 2604 commits by over 200 authors
– 498 issues
– Almost 2 years of work
– 57K Lines of C++ to 75K Lines of Rust 5 (plus 400 lines of C 6)
– C++–
oersted
I've used Fish for many years, but frankly only for the great autocompletion. The streamlined theme/prompt system and oh-my-fish plugin management are quite nice too, but minor.
The rest of Fish features that are not bash-compatible are rather a pain, particularly environment variable management. In principle these features have a better design than in bash, but not that much better, and their use is infrequent enough to have to re-learn them every time. Unfortunately, they just end up being a minor inconvenience when you try to copy-paste setup instructions from docs, and I don't interact with these features otherwise.
guytv
Can someone from the team share how the dev coordination for the Rust migration was handled? I only see a single PR (#9512)—how was the work organized?
albertzeyer
> However, there should be no direct impact on users.
I find this quite impressive, that they rewrote the whole Fish core, but everything keeps working exactly in the same way (except very few minor things which change in only minor ways, which they list).