The main changes are:
- disabling some checks related to POSIX file permissions when a filesystem is
mounted with "noacl" (default on MSYS2)
- disabling some checks related to symlinks when using fake ones (file copy)
Windows with acl hasn't been tested because 1) Cygwin itself does not have any
Rust package yet to compile fish, and 2) MSYS2 defaults to `noacl`
Part of #12171
- Use the different strings for different checks to more easily narrow down
where a failure happens
- Move CHECK comments outside a `if...else...end` to avoid giving the impression
that the check only runs in the `if` case.
Part of #12171
Previously, SIGTERM immediately re-raised with SIG_DFL, killing
fish without saving history. SIGHUP deferred via a flag but never
re-raised, so the parent saw a normal exit instead of signal death.
Unify both signals: the handler stores the signal number in a single
AtomicI32, the reader loop exits normally, throwing_main() saves
history and re-raises with SIG_DFL so the parent sees WIFSIGNALED.
Fixes#10300Closes#12615
Move the functions for escaping and unescaping strings from
`src/common.rs` into `fish_common`. It might make sense to move them
into a dedicated crate at some point, but for now just move them to the
preexisting crate to unblock other extraction.
Closes#12625
This time, move char constants from `src/expand.rs` to
`fish_widestring`, which resolves a dependency cycle between
`src/expand.rs` and `src/common.rs`.
Part of #12625
The decoding functions for our widestrings are already in the
`fish_widestring` crate, so by symmetry, it makes sense to put the
encoding functions there as well. This also makes it easier to depend on
these functions, giving more options when it comes to further code
extraction.
Part of #12625
Use `fish_widestring` as the place where char definitions live. This has
the advantage that all our code can depend on `fish_widestring` without
introducing dependency cycles. Having a common place for character
definitions also makes it easier to see which chars have a special
meaning assigned to them.
This change also unblocks some follow-up refactoring by removing a
dependency cycle between `src/common.rs` and `src/wildcard.rs`.
Part of #12625
These functions don't depend on `wcstringutil` functionality, so there
is no need for them to be there. The advantage of putting them into our
`widestring` crate is that quite a lot of code depends on it, and
extracting some of that code would result in crate dependency cycles if
the functions stayed in the `wcstringutil` crate. Our `widestring` crate
does not depend on any of our other crates, so there won't be any cyclic
dependency issues with code in it.
Part of #12625
It makes a lot more sense to have this function in the same module as
the other escaping functions. There was no usage of this function in
`parse_util` except for the test, so it makes little sense to keep the
function there. Moving it also eliminates a pointless cyclic dependency
between `common` and `parse_util`.
Part of #12625
Exporting it as both `safe_write_loop` and `write_loop` is redundant and
causes inconsistencies. Remove the `pub use` and use `write_loop` for
the function name. It is shorter, and in Rust the default assumption is
that code is safe unless otherwise indicated, so there is no need to be
explicit about it.
Part of #12625
Not reexporting means that imports have to change to directly import
from `fish_common`. This makes it easier to see which dependencies on
`src/common.rs` actually remain, which helps with identifying candidates
for extraction.
While at it, group some imports.
Part of #12625
Removing this dependency allows extracting the `fish_reserved_codepoint`
function, and other code depending on it in subsequent commits.
Part of #12625
Reduce verbosity of const definitions. Define a dedicated const for the
base of the special key encoding range. This range is 256 bytes wide, so
by defining consts via an u8 offset from the base, we can guarantee that
the consts fall into the allocated range. Ideally, we would also check
for collisions, but Rust's const capabilities don't allow for that as
far as I'm aware.
Having `SPECIAL_KEY_ENCODE_BASE` in the `rust-widestring` crate allows
getting rid of the dependency on `key::Backspace` in the
`fish_reserved_codepoint` function, which unblocks code extraction.
Part of #12625
While the function is only used to decode single codepoints, nothing in
its implementation limits it to single codepoints, so the name
`decode_one_codepoint_utf8` is misleading. Change it to the simpler and
more accurate `decode_utf8`. Add a doc comment to describe the
function's behavior.
Part of #12625
To homogenize error reporting format, use a new Error struct. Currently this
is used for builtins and ensuring a common cmd/subcmd prefix.
Part of #12556
Repro:
$ abbr -h | less
fish: Job 1, 'abbr --help | less' has stopped
Bisects to 5ece9bec6c (__fish_print_help: use man as-is, 2025-08-29).
Root cause is similar to
https://github.com/fish-shell/fish-shell/issues/8699#issuecomment-1030762748
except it's specific to how __fish_print_help is invoked, since
"__fish_print_help abbr | less" works fine.
Fix this by letting __fish_print_help access the terminal.
Fixes#12612
Solved by Claude in a single prompt:
---
▐▛███▜▌ Claude Code v2.1.92
▝▜█████▛▘ Sonnet 4.6
▘▘ ▝▝ ~/git/fish-shell
❯ "abbr -h | less" gets a signal, resulting in the message "fish: Job 1, 'abbr -h | less' has stopped"
whereas "__fish_print_help abbr | less" works just fine, even though "abbr -h" should run exactly that.
Why this difference?
[...]
● Now I can give you a clear answer.
---
The difference comes down to job group inheritance when man is
spawned.
The deferred execution order
In abbr -h | less, fish uses the "deferred process" optimization:
since abbr is a non-external process piping into an external one,
fish launches less first,
transfers the terminal to less's process group, then runs the
deferred abbr builtin. By the time abbr's help function spawns man,
the terminal already
belongs to less's pgroup.
Same thing happens with __fish_print_help abbr | less — the outer
less is launched first and gets the terminal.
Where the paths diverge
Function case (__fish_print_help abbr | less):
get_performer_for_function (exec.rs:1050) captures job.group.clone()
and passes it to eval_node. So when command man runs inside the
function, it's given the outer pipeline's job group — the same
one that owns the terminal. man's inner less pager joins that group
and can read from the terminal freely. ✓
Builtin case (abbr -h | less): builtin_print_help calls
parser.eval(&cmd, streams.io_chain) (shared.rs:652). parser.eval
is defined as:
pub fn eval(&self, cmd: &wstr, io: &IoChain) -> EvalRes {
self.eval_with(cmd, io, None, BlockType::top, false)
// ^^^^ job_group = None
}
job_group = None means man creates a brand-new job group with no
terminal access. When man spawns its less pager, the pager tries
to read keyboard input from
the terminal, but the terminal belongs to the outer less's process
group. The pager receives SIGTTIN → stops → the whole job is
reported as stopped.
The fix
builtin_print_help should pass streams.job_group to the eval call
(which is already populated at exec.rs:1192). Changing line 652 from:
let res = parser.eval(&cmd, streams.io_chain);
to:
let res = parser.eval_with(&cmd, streams.io_chain, streams.job_group.as_ref(), BlockType::top, false);
would give man the outer job's job group, letting its pager access
the terminal just like the function case.
✻ Sautéed for 13m 0s
Another step in splitting up the main library crate.
Note that this change requires removing the `#[cfg(test)]` annotations
around the `LOCAL_OVERRIDE_STACK` code, because otherwise the code would
be removed in test builds for other packages, making the `#[cfg(test)]`
functions unusable from other packages, and functions with such feature
gates in their body would have the code guarded by these gates removed
in test builds for tests in other packages.
Closes#12494
Having a public function named `test` is quite unspecific. Exporting it
both as `test` and `feature_test` results in inconsistent usage. Fix
this by renaming the function to `feature_test` and removing the alias.
Part of #12494
Several features of fish can be toggled at runtime (in practice at
startup). To keep track of the active features, `FEATURES`, an array of
`AtomicBool` is used. This can safely be shared across threads without
requiring locks.
Some of our tests override certain features to test behavior with a
specific value of the feature. Prior to this commit, they did this by
using thread-local versions of `FEATURES` instead of the process-wide
version used in non-test builds. This approach has two downsides:
- It does not allow nested overrides.
- It prevents using the code across package boundaries.
The former is a fairly minor issue, since I don't think we need nested
overrides. The latter prevents splitting up our large library crate,
since `#[cfg(test)]`-guarded code can only be used within a single
package.
To resolve these issues, a new approach to feature overrides in
tests is introduced in this commit: Instead of having a thread-local
version of `FEATURES`, all code, whether test or not, uses the
process-wide `FEATURES`. For non-test code, there is no change. For test
code, `FEATURES` is now also used. To override features in tests, a new
`with_overridden_feature` function is added, which replaces
`scoped_test` and `set`. It works by maintaining a thread-local stack of
feature overrides (`LOCAL_OVERRIDE_STACK`). The overridden `FeatureFlag`
and its new value are pushed to the stack, then the code for which the
override should be active is run, and finally the stack is popped again.
Feature tests now have to scan the stack for the first appearance of the
`FeatureFlag`, or use the value in `FEATURES` if the stack does not
contain the `FeatureFlag`. In most cases, the stack will be empty or
contain very few elements, so scanning it should not take long. For now,
it's only active in test code, so non-test code is unaffected. The plan
is to change this when the feature flag code is extracted from the main
library crate. This would slightly slow down feature tests in non-test
code, but there the stack will always be empty, since we only override
features in tests.
Part of #12494
To homogenize error reporting format, use a new Error struct. Currently this
is used for builtins and ensuring a common cmd/subcmd prefix.
Part of #12556
With a few exceptions, only one test is added for a given message, even
when there are multiple ways to trigger the same message (e.g. different
invalid option combinations, or triggered in shared functions such as
`builtin_unknown_option`)
Includes a few very minor fixes, such as missing a newline, or using the
wrong var name.
Closes#12603
- fix wrong pattern used in `string replace` error message
- replace unreachable error with `unreachable!` in `string`
- fix cmd being used in place of subcmd
Part of #12603
Previously executing `set -a` or `set -p` would just list all the
variables, which does not make sense since the user specifically ask
for an action (append/prepend).
Update the help page synopsis
Part of #12603
If all of
$PREFIX/bin/fish
$PREFIX/share/fish
$PREFIX/etc/fish
exist, then fish assumes it's in a relocatable directory tree.
This is used by homebrew (PREFIX=/usr/local) and maybe also nix(?).
Other Linux distros prefer to use /etc/fish instead of $PREFIX/etc/fish
[1]. To do so, they need to pass -DCMAKE_INSTALL_SYSCONFDIR=/etc.
The relocatable tree logic assumes default data and sysconf dirs
(relative to a potentially relocatable prefix). If the user changes
any of those, and the relocatable tree logic happens to kick in,
that'd overrule user preference, which is surprising.
So a non-default data or sysconf path is a strong enough signal that
we want to disable the relocatable tree logic. Do that.
Closes#10748
[1]: ff2f69cd56/PKGBUILD (L43)
test_history_path_detection calls add_pending_with_file_detection(),
which spawns a thread pool task via ThreadPool::perform(). This
requires threads::init() to have been called, otherwise
assert_is_background_thread() panics.
Add the missing test_init() call, matching other tests that use
subsystems requiring initialization.
Closes#12604
- Remove unreachable error message in `handle_env_return()`
While we could have put an empty block in `handle_env_return()` and
removed the condition on `NotFound` in `erase()`, we prefered to use
`unreachable!` in case `handle_env_return()` gets called in new scenarios
in the future
- Make reachable the error message when asking to show a slice
Part of #12603
With empty argument, `realpath` skips all processing, so the error
message, based on `errno`, was unrelated and changed depending on what
failed before. E.g:
```
$ builtin realpath "" /tmp "" /no-exist ""
builtin realpath: : Resource temporarily unavailable
/tmp
builtin realpath: : Invalid argument
/dont-exist
builtin realpath: : No such file or directory
```
Part of #12603
`to_stdout` is set to `true` if and only if `argv` is not empty.
- `argv` length and `to_stdout` are redundant, so we can remove `to_stdout`
- some tests in `validate_read_args` are necessarily false
Part of #12603
We support multiple "man" implementations; at least man-db's and
mandoc's.
So we can relax the mandoc dependency to a dependency on the virtual
package providing "man". Note that as of today, "mandoc" fails to
have a "Provides: man".
However since Debian policy says in
https://www.debian.org/doc/debian-policy/ch-relationships.html
> To specify which of a set of real packages should be the default
> to satisfy a particular dependency on a virtual package, list the
> real package as an alternative before the virtual one.
we want to list possible real packages anyway, so do that.
Closes#12596
The previous handling was unnecessarily complex and had a bug introduced
by porting from C++ to Rust: The substrings `\0x0B` and `\0x0C` in Rust
mean `\0` (the NUL character) followed by the regular characters `0B`
and `0C`, respectively, so feature names starting or ending with these
characters would have these characters stripped away.
Replace this handling by built-in functionality, and simplify some
syntax. We now trim all whitespace, instead of just certain ASCII
characters, but I think there is no reason to limit trimming to ASCII.
Closes#12592
help2man 1.50 added \X'tty: link URL' hyperlink escapes to generated
man pages. coreutils 9.10 is the first widely-deployed package to ship
these, and it broke completion generation for most of its commands
(only 17/106 man pages parsed successfully).
The escape wraps option text like this:
\X'tty: link https://example.com/a'\fB\-a, \-\-all\fP\X'tty: link'
Two places needed fixing:
- remove_groff_formatting() didn't strip \X'...', so Type1-4 parsers
extracted garbage option names like "--all\X'tty"
- Deroffer.esc_char_backslash() didn't recognize \X, falling through
to the generic single-char escape which stripped only the \, leaving
"X'tty: link ...'" as literal text. Option lines then started with
X instead of -, so TypeDeroffManParser's is_option() check failed.
Also handle \Z'...' (zero-width string) which has identical syntax.
Closes#12578
Return None rather than -1 for nonprintables. We probably still
differ from wcwidth which is bad (given we use the same name), but
hopefully not in a way that matters.
Fixes 146384abc6 (Stop using wcwidth entirely, 2026-03-15).
This reverts commit 23ce9de1c3.
The compilation failure on Rust nightly was fixed in rust-shellexpand
commit b6173f0 (Rename WstrExt and WstrRefExt methods, 2026-02-23).
wcwidth isn't a great idea - it returns "-1" for anything it doesn't
know and non-printables, which can easily break text.
It is also unclear that it would be accurate to the system console,
and that's a minority use-case over using ssh to access older systems.
Additionally, it means we use one less function from libc and
simplifies the code.
Closes#12562
"Emoji width" refers to the width of emoji codepoints. Since Unicode
9, they're classified as "wide" according to
TR11 (https://www.unicode.org/reports/tr11/).
Unicode 9 was released in 2016, and this slowly percolated into C
libraries and terminals. Glibc updated its default in 2.26, released
in August 2017.
Until now, we'd guess support for unicode 9 by checking the system
wcwidth function for an emoji - if it returned 2, we'd set our emoji
width to 2 as well.
However, that's a problem in the common case of using ssh to connect
to an old server - modern desktop OS, old server LTS OS, boom.
So now we instead just figure you've got a system that's *displaying*
the emoji that has been updated in the last 9 years.
In effect we're putting the burden on those who run old RHEL et al as
their client OS. They need to set $fish_emoji_width to 1.
Fixes#12500
Part of #12562
When cargo is installed via rustup, running cargo actually goes through
a proxy managed by rustup. This proxy determines the actual toolchain
to use, depending on environment variables, directory overrides etc. In
some cases, the proxy may automatically install the selected toolchain
if it's not yet installed, for example when first working on a project
that pins its rust toolchain via a `rust-toolchain.toml` file. In that
case, running cargo in the completion script can block the prompt for
a very long time. To avoid this, we instruct the rustup proxy not to
auto-install any toolchain with an environment variable.
Closes#12575
Commit 7ef4e7dfe7 (Time out terminal queries after a while,
2025-09-21) though that "2 seconds ought to be enough for anyone".
But that's not true in practice: when rebooting a macOS system, it
can take longer. Let's see if 10 seconds is enough. It should be fine
to have such a high timeout since this shouldn't happen in other cases.
Closes#12571
Add support for the SHELL_PROMPT_PREFIX, SHELL_PROMPT_SUFFIX, and
SHELL_WELCOME environment variables as standardized by systemd v257.
SHELL_PROMPT_PREFIX and SHELL_PROMPT_SUFFIX are automatically prepended
and appended to the left prompt at the shell level, so all prompts
(default, custom, and sample) pick them up without modification.
SHELL_WELCOME is displayed after the greeting when an interactive shell
starts.
These variables provide a standard interface for tools like systemd's
run0 to communicate session context to the shell.
Fixes https://github.com/fish-shell/fish-shell/issues/10924Closes#12570
The `forward-word` readline command on "a-a-a" is wrong (jumps to
"a"); on "aa-aa-aa" it's right (jumps to "-"); that's a regression
from bbb2f0de8d (feat(vi-mode): make word movements vi-compliant,
2026-01-10).
The is_word_end check for ForwardWordEmacs only tests for blank
(whitespace) after the current char. In the Punctuation style, words
also end before punctuation.
Fix this.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
See https://github.com/fish-shell/fish-shell/issues/12543#issuecomment-4125223455
`set_color normal` is too ambiguous and easily misinterpreted since
it actually reset all colors and modes instead of resetting just
the foreground color as one without prior knowledge might expect.
Closes#12548
Use portageq to retrieve system paths instead of hardcoding them in.
This helps especially in Gentoo Prefix, where the installation is not
in / but rather offset inside a subdirectory (usually a users home
directory).
This only affects the "slow" path. When eix is installed it will be used
instead. It already accounts for Prefix installations.
Closes#12552
Repro (with default prompt):
$ HOME=$PWD target/debug/fish -C '
function sleep_func; sleep 1; false; end
commandline "sleep 2 | sleep 3 | sleep 4 | sleep_func"
'
Welcome to fish, the friendly interactive shell
Type help for instructions on how to use fish
johannes@e15 ~> sleep 2 | sleep 3 | sleep 4 | sleep_func
^Zfish: Job 1, 'sleep 2 | sleep 3 | sleep 4 | s…' has stopped
johannes@e15 ~ [0|SIGTSTP|SIGTSTP|1]>
I'm not sure why the first sleep is not reported as stopped.
Co-authored-by: Lieuwe Rooijakkers <lieuwerooijakkers@gmail.com>
Fixes issue #12301Closes#12550
/bin/ls and /bin/echo do not necessarily exist on all systems, e.g.
nixos.
/bin/sh should at least exist on more systems than /bin/ls and /bin/echo
Part of #12544
/bin/cat doesn't exist on e.g. nixos, which only has /bin/sh and
/usr/bin/env.
/usr/bin/env should at least exist on more systems than /bin/cat
Part of #12544
These binaries are not guaranteed to exist at /bin/X on all systems,
e.g. nixos does not place binaries there, but as long as they are in the
PATH we can find them with command.
Part of #12544
This is done partly for consistency `underline` where we still need
`off` but where true/false doesn't make sense, and partly to simplify
user choices and the code.
See #12507Closes#12541
In WSL, if Docker is not started, the `docker` command is a script
that prints an error message to stdout instead of a valid script.
`docker.exe` is available and can return the completion script. However
any completion will end up calling that `docker` script anyway,
resulting further errors due to the unexpected output.
Closes#12538
The value shown is in KiB (2^{10} bytes), according to
`man 2 getrusage`, not kb (10^3 bits), so reflect this in the variable
name and output.
Closes#12529
`--foreground` has two purposes:
- allow resetting the foreground color to its default, without also
resetting the other colors and modes
- improve readibility and unify the `set_color` arguments
`--reset` also has two purposes:
- provide a more intuitive way to reset the text formatting
- allow setting the colors and modes from a clean state without
requiring two calls to `set_color`
Part 3/3 of #12495Closes#12507
Add an optional `on`/`off`` value to italics/reverse/striketrough
to allow turning of the attribute without having to use the `normal`
color, i.e. reset the whole style
Part 1/3 of #12495
Part of #12507
The notion of default is context dependent: there is the default for
the state (default color, non-bold, no underline, ...) and the default
for a change (no color change, no underline change, ...).
Currently, using a single default works because either the style
attributes cannot be turned off individually (the user is expected
to reset to default then re-set necessary attributes), or the code
has special handling for specific scenarios (e.g. highlighting).
So in preparation for later commits, where attribute can be turned off
individually, make the two defaults explicit.
Part of #12507
When trying to complete a command starting with `-`, and more
specifically when trying to get the description of possible commands,
the dash was interpreted as an option for `__fish_describe_command`,
resulting in an "unknown option" most of the time.
This is a regression introduced when adding option parsing to
`__fish_describe_command`
Fixes 7fc27e9e5 (cygwin: improve handling of `.exe` file extension, 2025-11-22)
Fixes#12510Closes#12522
This fixes, or should make it less likely, spurious CI failures because
of:
`child_info_fork::abort: address space needed by <DLL> is already occupied`
The issue is that Unix `fork()`, given how it works, preserves
libraries' addresses. Windows does not have such a function, so Cygwin
needs emulate it by moving the libraries in a child process to match
the addresses in its parent. This leads to conflicts if Windows already
loaded something there.
As a workaround, Cygwin has a `rebase` application to assign specific
addresses to each DLL and forcing Windows to use those. This generally
fixes the issue (until a DLL is updated that is, but that's not
a concern for CI since everything is rebuilt from scratch every time).
In the case of #12515 though, the failing DLL is a temporary one built
during the compilation. So a rebase of MSYS2 packages will not quite
fix the problem. However, by moving other DLLs at specific locations,
it reduce the risk of collision to only be between the temporary ones.
Fixes#12515Closes#12521
This partially reverts 324223ddff.
The offending commit broke the ability to set color mode via option
completely in interactive sessions.
Closes#12511
Change the behavior when `getrusage` fails. Previously, failure was
masked by using 0 values for everything. This is misleading. Instead, we
now panic on such failures, because they should never occur with our
usage of the function.
Closes#12502
Similar to `perror_io`, we don't need to make a libc call for `nix`
results, since the error variant contains the errno, from which a static
mapping to an error message exists. Avoid using `perror` and instead use
`perror_io` or `perror_nix` as appropriate where possible.
The `perror_io` and `perror_nix` functions could be combined by
implementing `fish_printf::ToArg` for `nix::errno::Errno`, but such a
function would violate type safety, as it would allow passing any
formattable argument, not necessarily limited to functions with a `%s`
formatting.
Part of #12502
Change some files which have lines whose indentation is not a multiple
of the 4 spaces specified in the editorconfig file.
Some of these changes are fixes or clear improvements (e.g. in Rust
macros which rustfmt can't format properly). Other changes don't clearly
improve the code style, and in some cases it might actually get worse.
The goal is to eventually be able to use our editorconfig for automated
style checks, but there are a lot of cases where conforming to the
limited editorconfig style spec does not make sense, so I'm not sure how
useful such automated checks can be.
Closes#12408
Previously, we chose the ellipsis character/string based on the locale.
We now assume a UTF-8 locale, and accordingly always use the Unicode
HORIZONTAL ELLIPSIS U+2026 `…`. When this was changed, some of the logic
for handling different ellipsis values was left behind. It no longer
serves a purpose, so remove it.
The functions returning constants are replaced by constants. Since the
ellipsis as a `wstr` is only used in a single file, make it a local
const there and define it via the `ELLIPSIS_CHAR` const.
Put the `ELLIPSIS_CHAR` definition into `fish-widestring`, removing the
dependency of `fish-wcstringutil` on `fish-common`, helping future
extraction efforts.
One localized message contains an ellipsis, which was inserted via a
placeholder, preventing translators from localizing it. Since the
ellipsis is a constant, put it directly into the localized string.
Closes#12493
In shallow, dirty git repo, the version identifier will look something
like `fish, version 4.5.0-g971e0b7-dirty`, with no commit counter
indicating the commits since the last version. Our regex did not handle
this case.
Make the commit counter optional, which also allows removing the second
alternative in the regex, since it's now subsumed by the first.
Fixes#12497Closes#12498
This time, functions for decoding `wstr` into various types and the
`ToCString` trait are extracted.
Part of the wider goal of slimming down the main library to improve
incremental build performance and reduce dependency cycles.
Part of #12492
The `msguniq` call for deduplicating the msgids originating from Rust
previously did not get a header entry (empty msgid with msgstr
containing metadata). This works fine as long as all msgids are
ASCII-only. But when a non-ASCII character appears in a msgid, `msguniq`
errors out without a header specifying the encoding. To resolve this,
add the header to the input of this `msguniq` invocation and then remove
the header again using sed to prevent duplicating it for the outer
msguniq call at the end of the file.
Closes#12491
Panicking suggests that an assumption of our code was violated.
The current use of panics in xtasks is for expected failures, so it's
better to avoid panicking and instead just print the error message to
stderr and exit 1.
Closes#12482
Lint table order is unspecified, leading to spurious "unknown
lint" errors which ought to have been suppressed, see
https://github.com/rust-lang/cargo/issues/16518
From https://rust-lang.github.io/rfcs/3389-manifest-lint.html
> lower (particularly negative) numbers ... show up first on the
> command-line to tools like rustc
So we can use the priority property to make sure that unknown lints
are suppressed before rustc processes the other lint specifications.
Part of #12334
For now, only add it in a single place. There are more instances where
width calculation could be improved, but this one has already been
converted to use the `unicode-width` crate before, so conversion is easy
and a strict improvement.
Closes#12457
Accurately computing the width of arbitrary strings is a non-trivial
problem. We outsource the logic for it to the `unicode-width` crate. But
directly passing our PUA-encoded strings to the crate would give
incorrect results whenever a PUA codepoint is encoded in our string,
since one input PUA codepoint is converted into 3 consecutive codepoints
in our encoding. Therefore, we need to decode before performing width
calculations. Our regular decoding decodes to raw bytes, which is
incompatible with the `unicode-width` crate, since it expects `char`s,
and the decoded bytes could be invalid UTF-8, making their width
undefined. We tackle this problem by building a custom iterator which
does on-the-fly decoding. Encoded PUA codepoints are turned back into
the original codepoints, and any other PUA-encoded bytes are replaced by
one replacement character (U+FFFD) per byte. The latter is not necessary
since PUA codepoints have a defined width of 1, so we could also forward
the PUA-encoded bytes which encode invalid UTF-8 input instead of
inserting the replacement character. The choice to use the replacement
character is made to avoid producing a char sequence where some PUA
codepoints represent themselves, whereas others still encode non-UTF-8
bytes. Such a mix of semantics would be confusing if the char sequence
is ever used for anything else. Replacement characters make it clear
that there are no remaining encoded semantics. Note that using the char
sequences produced in this way for any purpose other than width
computation is not intended. For output, our pre-existing decoding to
bytes should be used, which allows preserving non-UTF-8 bytes.
The implementation of the iterator is not entirely straightforward,
since we need to read up to 3 chars to be able to decide whether we have
an encoded PUA character. Therefore, we need to cache some chars across
invocations of the iterator's `next` and `next_back` invocations. This
is done via a custom buffer struct, which does not require dynamic
allocations.
The tests for the new functionality are only in the main crate because
the encoding function is not available in the `fish-widestring` crate.
Once that is resolved, the tests should be moved.
Part of #12457
`protontricks -l` will launch a graphical prompt to choose Steam
installation if multiple installations are found. `-L/--list-all`
is a new flag introduced in 1.14.0 that retrieves all games without user
interaction.
Also silence stderr, since it can cause warning messages to be printed.
Part of #12477
Commit 7ac9ce7ffb (Reduce the number of escape sequences for text
styles, 2026-02-06) includes a bad merge conflict resolution of
a conflict with 38513de954 (Remove duplicated code introduced in
commit 289057f, 2026-02-07). Fix that.
Fixes#12476
Replace the `build_tools/style.fish` script by an xtask. This eliminates
the need for a fish binary for performing the formatting/checking. The
`fish_indent` binary is still needed. Eventually, this should be made
available as a library function, so the xtask can use that instead of
requiring a `fish_indent` binary in the `$PATH`.
The new xtask is called `format` rather than `style`, because that's a
more fitting description of what it does (and what the script it
replaces did).
The old script's behavior is not replicated exactly:
- Specifying `--all` and explicit paths is supported within a single
invocation.
- Explicit arguments no longer have to be files. If a directory is
specified, all files within it will be considered.
- The git check for un-staged changes is no longer filtered by file
names, mainly to simplify the implementation.
- A warning is now printed if neither the `--all` flag nor a path are
provided as arguments. The reason for this is that one might assume
that omitting these arguments would default to formatting everything
in the current directory, but instead no formatting will happen in
this case.
- The wording of some messages is different.
The design of the new code tries to make it easy to add formatters for
additional languages, or change the ones we already have. This is
achieved by separating the code into one function per language, which
can be modified without touching the code for the other languages.
Adding support for a new formatter/language only requires adding a
function which builds the formatter command line based on the arguments
to the xtask, and calling that function from the main `format` function.
Closes#12467
The cursor position calculation did not correctly account for the width
of Unicode text, resulting in the cursor being placed to far left in
scenarios with characters taking up 2 cells, such as in Chinese text.
Fix this by combining the entire line into a string and computing the
length of the resulting string using the `unicode-width` crate.
This is the first code in the main crate making use of `unicode-width`.
Eventually, we'll probably want to use it in more places, to get better
and consistent results.
Fixes#12444Closes#12446
Rust idiomatic naming is "take" for "move", also Rust might actually
move the object to a different memory adress, which is fine because
all Rust objects are trivially relocatable.
When setting graphics attributes (SGR), combine them into a single
escape sequence to reduce the length of the string and make it slightly
easier to read by people when needed.
Some terminal/parser[^1] may have a cap on the number of parameters, so
we limit the number to 16.
[^1]: https://vt100.net/emu/dec_ansi_parser: "There is no limit to the
number of characters in a parameter string, although a maximum of 16
parameters need be stored. If more than 16 parameters arrive, all
the extra parameters are silently ignored.""
Closes#12429
This Dockerfile has been broken for quite a while now, at least since
Rust is required for building fish. No one seems to have complained
about it being broken, so there is no point in keeping it around. The
`docker` directory contains several Dockerfiles which could be used
instead.
https://github.com/fish-shell/fish-shell/pull/12408#discussion_r2770432433Closes#12435
github actions runners have python 3.12, so the upgrade to debian
stable's 3.13 broke things:
+ env UV_PYTHON=python uv --no-managed-python lock --check --exclude-newer=2026-02-01T13:00:00Z
Using CPython 3.12.3 interpreter at: /usr/bin/python
error: The requested interpreter resolved to Python 3.12.3, which is incompatible with the project's Python requirement: `>=3.13` (from `project.requires-python`)
Error: Process completed with exit code 2.
Steps:
1. edit pyproject.toml and
2. uv lock --upgrade --exclude-newer="$(awk -F'"' <uv.lock '/^exclude-newer[[:space:]]*=/ {print $2}')"
In future we should maybe use managed python?
These commands are meant to be used in Vi mode when the cursor is on
a valid character, so there's not much reason to try to make them do
something when the cursor is past-end. Do nothing, like we already
do for the empty commandline.
Reported in #12430
update __fish_git_stash_not_using_subcommand check for actual subcommands
instead of treating any word after 'stash' as a subcommand.
stay dry by adding__fish_git_stash_is_push helper that matches both implicit and explicit push.
fixes#11307Closes#12421
sphinx==9.1.0 depends on Python>=3.12,
so change our pinning policy to fit.
Note we still support Python 3.9 in user-facing code.
Steps:
1. edit updatecli.d/python.yml
2. remove bad "uv lock" from build_tools/update-dependencies.sh
(didn't respect exclude-newer)
3. updatecli apply --config updatecli.d/python.yml
4. uv lock --upgrade --exclude-newer="$(date --date='7 days ago' --iso-8601)"
LLM-generated contributions tend to produce too many redundant
comments. Fix that. This doesn't work OOTB for Claude, but it's easy
to tell it to respect AGENTS.md..
This fails intermittently in CI. Disable it. We disable a lot of
other tests as well which is why we run tests on developer machines
before pushing to master.
See #12351
Currently history files are written to the "data directory"
(XDG_DATA_HOME). This is awkward in testing since we have to put files
into this directory.
Allow histories to have their own directory, so that they don't
interfere with other files. This will help simplify some tests.
Adopt this in some (but not all) history tests.
Commit 38e633d49b (fish_vi_key_bindings: add support for count,
2025-12-16) introduced an operator mode which kind of makes a lot of
sense for today's fish. If we end up needing more flexibility and
tighter integration, we might want to move some of this into core.
Unfortunately the change is at odds with our cursed forward-jump
implementation. The forward-jump special input function works by
magically reading the next key from stdin, which causes problems when
we are executing a script:
commandline -f begin-selection
commandline -f forward-jump
commandline -f end-selection
here end-selection will be executed immediately
and forward-jump fails to wait for a keystroke.
We should get rid of forward-jump implementation.
For now, replace only the broken thing with a dedicated bind mode
for each of f/F/t/T.
Fixes#12417
Commit 46d1334f95 (Silence bind errors in default key bindings,
2017-10-03) worked around errors arising from "bind -k".
We no longer use that, so remove that.
Commit bbb2f0de8d added a ctrl-right binding to override the shared
binding with forward-word-vi for vi-compliance. However, it incorrectly
passed $argv which caused the error:
"bind: cannot parse key 'default'"
when calling fish_vi_key_bindings with a mode argument like:
fish_vi_key_bindings "default"
Fix that.
Co-Authored-By: Johannes Altmanninger <aclopte@gmail.com>
Closes#12413
Some languages have different conventions regarding colons. In order to
handle this better in cases with non-constant strings, as is the case in
`describe_with_prefix`, use localization to figure out how colons should
be localized.
This approach fixes the extra whitespace inserted after Chinese colons.
See #12405.
Closes#12414
Now that we have trimmed our msgids, add an assertion to ensure that
they stay trimmed. Note that we don't check msgstrs. We could do so when
building the maps which get put into the executable, but there we also
include messages originating from fish scripts, and there we don't
enforce trimmed messages, so limiting the checks to only messages
originating from the Rust code there would not be trivial.
Closes#12405
This allows the strings to be simpler, and keeps
localization-independent formatting out of localizable strings.
Tab-based formatting is brittle, and should probably be reworked.
This is also the final piece to have no more leading or trailing
whitespace in our localizable strings in the Rust code.
Part of #12405
Now, non of the localizable strings in Rust have any more leading or
trailing spaces, making it easier to use them with Fluent. Again, there
are some slight issues with Chinese translations, which now have
additional whitespace.
Part of #12405
Another step towards trimming the localizable strings. Fix
inconsistencies in some of the translations. Translations for zh_CN are
not entirely consistent between using ASCII colons and `:`. If the
latter is used, which also happens for zh_TW, no trailing space is
present in the translation even if it is present in the msgid. This
means that the new code will show excessive whitespace after these
colons, since a regular space is inserted outside of the localization
code. While this might not be pretty, I don't think it really breaks
anything, and not having to deal with trailing whitespace simplifies
working with Fluent.
Part of #12405
This simplifies our table formatting. Since none of our translations
modify the string `PID`, it seems reasonable to assume that the term
does not benefit from localization.
Part of #12405
Complete the work started in
e78e3f16e (gettext: remove trailing newlines, 2026-01-30)
Now, there are no remaining trailing newlines in the localizable strings
in our Rust sources. A bit more work is still needed to get rid of a few
leading and trailing spaces, the goal being that for all localizable
strings `s` in our Rust sources, `s == s.trim()`.
Includes a bit of drive-by refactoring.
Part of #12405
The problem introduced by 081c469f6f (tarball: include
.cargo/config.toml again, 2026-01-13) seems solved by 09d8570922
(debian packaging: generate patches automatically, 2026-02-01),
so the argument to make_tarball.sh is no longer needed.
The vendor tarball drops a new version of .cargo/config into place,
which the Debian toolchain does not like (as it is an unexpected
modification of the original tarball). Tell dpkg-source to generate a
patch automatically, as trying to do it in fish's packaging scripts is
brittle.
Commit 92dae88f62 (tarball: remove redundant "version" file,
2026-01-12) committed to using Cargo.toml as single source of truth
for our version string.
This works fine for tarballs built from a tag, but those built from
an arbitrary Git commit will show a misleading version ("4.3.3"
instead of something like "4.3.3-190-g460081725b5-dirty").
Fix this by copying the Git version to the tarball's Cargo.{toml,lock}.
It's not clear if we really need this (it's only for nightly builds)
so we might end up reverting this.
Ref: https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$BdRagDGCV-8yVjBs0i3QyWUdBK820vTmjuSBqgpsuJY
Note that OBS builds are probably still broken from 081c469f6f
(tarball: include .cargo/config.toml again, 2026-01-13); see
https://github.com/fish-shell/fish-shell/pull/12292#discussion_r2694000477
Remove trailing newlines from msgids. Newlines do not need to be
localized, so translators should not have to care about them.
In addition to simplifying the jobs of translators using gettext, not
having trailing newlines also makes it easier to port localizations to
Fluent.
Closes#12399
This makes them more general than the previous versions which expected
`&wstr`. It comes at the cost of additional eager calls to `chars()`.
To implement `appendln` without having to call `append` twice, implement
`IntoCharIter` for chained iterators whose elements are both the kind of
iterator specified by `IntoCharIter`.
Because `IntoCharIter` is not implemented for owned types to avoid
allocations, some call sites which used to pass `WString` need to be
updated to pass references instead, which constitutes the bulk of the
changes in this commit.
Part of #12396
Prior to this commit, the line number of each block (say, begin, or
function call, etc) was computed eagerly and stored in the block. However
this line number is only used in rare cases, when printing backtraces.
Instead of storing the line number, store the node in the abstract syntax
tree along with the (shared) source text, and only compute the line numbers
when a backtrace is required.
This is about a ~4% improvement on seq_echo benchmark.
Apologies about the unsolicited PR. I hope this helps.
Adding Catppuccin themes from: https://github.com/catppuccin/fish
They note:
Q: Where's the Latte theme?
A: All three themes contain Latte as the light variant. Install any of
them, and then set your system or terminal theme to light mode.
Not sure about Fish Shell policy to keep them up to date here, I hope
this is not a nuissance.
Closes#12299
I took the verbiage mostly from `man git-rev-parse` (slightly shortened
since space is at a premium for completions):
--is-inside-git-dir
When the current working directory is below the repository directory print "true", otherwise "false".
--is-inside-work-tree
When the current working directory is inside the work tree of the repository print "true", otherwise "false".
Closes#12382
- fixed argument order for `-Sg`, `-Sl`, `-Qg`, `-Qp` and `-Qo`
- removed completions for `-Dk`
- added "Package Group" completions for `-Q` and `-R`
- remove package completions for `-F `
Part of #12347
Add lists with most known archictures for Arch Linux Ports and
all possible options for PKGEXT. Also simplified option list
for `--color` and improved completions for `--config`.
Part of #12347
test_complete and test_history_races both have the #[serial]
annotations. Still, "cargo test" sometimes fails with
thread 'complete::tests::test_complete' (370134) panicked at │
src/complete.rs:2814:13: │
assertion `left == right` failed │
left: [("TTestWithColon", false), ("history-races-test-balloon", │
true), ("test/", true)] │
right: [("TTestWithColon", false), ("test/", true)] │
I don't understand why this happens (filesystem race condition?)
but let's fix it by having "test_complete" ignore files from other
tests.
Fixes#12184
Unlimited concurrency frequently makes system tests fail when when run
as "tests/test_driver.py" or "cargo xtask check". Add a workaround
until we fix them.
Use $(nproc), which is already the default for RUST_TEST_THREADS
and CARGO_BUILD_JOBS, and it works pretty reliably on my laptop.
It's possible that we can increase it a bit to make it faster,
but until the tests are improved, we can't increase it much without
risking failures.
Ref: https://github.com/fish-shell/fish-shell/pull/12292#discussion_r2713370474
Tracking issue: #11815
Use the `nix::sys::wait::waitpid` function instead of libc's `waitpid`
for reaping disowned PIDs.
Note that this commit changes behavior. Previously, any updates received
for the PID were interpreted as the process having exited. However,
`waitpid` also indicates that processes were stopped or continued, or,
on Linux, that a ptrace event occurred. If the process has not exited,
it cannot be reaped, so I think it should be kept in the list of
disowned PIDs.
Part of #12380
The nix crate offers thin wrappers around these functions which allow us
to get rid of our own libc wrappers, reducing the amount of code marked
`unsafe`.
Part of #12380
We want to discourage direct conversion from regular Rust strings to
`WString`, since our `WString`s are assumed to use the PUA encoding
scheme. If the input string contains certain PUA codepoints and the
resulting `WString` is decoded, it would not result in the same bytes as
the UTF-8 encoding of the input string. To avoid this, use
`str2wcstring`.
There are two remaining usages of `WString::from_str` which have been
annotated to indicate why they are there.
- Don't use `WString::from_str` for `str`s which are available at
compile-time. Use `L!(input).to_owned()` instead. The reason for this
is that `WString::from_str` can cause problems if the input contains
PUA bytes which we use for our custom encoding scheme. In such cases,
`bytes2wcstring` should be used, to avoid problems when decoding the
`WString`. Removing harmless usages of `WString::from_str` allows us
to focus on the potentially dangerous ones which don't convert
`str`'s that are compiled into the binary.
- Make `cstr2wcstring` actually take `CStr` as its input. The former
version was only used in one place, and the conversion to `CStr`
should happen there, where it can be checked that the conversion makes
sense and is safe. The new version is used in
`src/env/environmant.rs`, to avoid `to_bytes()` calls cluttering the
code there.
- Add `osstr2wcstring` function. This function also works for `Path`.
Now, these types can be converted to widestrings with much less
syntactic clutter.
This function mutates the autosuggestion's search_string_range without
updating the number of matched codepoints accordingly, fix that.
Fixes 78f4541116 (reader: fix try_apply_edit_to_autosuggestion false
positive, 2026-01-22).
Fixes#12377
Add tab completion support for claude CLI tool, including:
- Top-level commands (doctor, install, mcp, plugin, setup-token, update)
- Global options for model, agent, system prompt configuration
- Tool and permission management options
- MCP server configuration
- IDE and Chrome integration settings
- Output format and session management options
- Sub-command specific help
Closes#12361
Given command line ": i" and suggestion ": İnstall" whose lowercase
mapping is ": i\u{307}nstall", most of our code assumes that typing
"n" invalidates the autosuggestion.
This doesn't happen because try_apply_edit_to_autosuggestion thinks
that "i" has fully matched the suggestion's "İ".
Fix this inconsistency by recording the exact number of lowercase
characters already matched in the suggestion; then we only need to
compare the rest.
This allows us to restore an important invariant; this reverts
1d2a5997cc (Remove broken assert, 2026-01-21).
The special exit handling when running with address sanitization no
longer seems necessary. Our tests all pass without it.
Similarly, the leak sanitizer suppression is no longer needed, since we
don't get any warnings when running our checks without it.
Because our Rust code no longer has any ASAN-specific behavior, we don't
need the `asan` feature anymore.
Closes#12366
See #12326. Turns out there wasn't just one assert, it was three.
These can be triggered by entering (interactively) "flatpak in"
after having "flatpak İnstall" in your history so it's autosuggested.
Removing the asserts it generally *works* okay, and there's absolutely
no good reason for turning this into a crash.
Our test driver (`tests/test_driver.py`) already builds this
unconditionally on each run, so there is no point in having CMake build
the binary as well. If we want to reduce the effort of rebuilding the
test helper on each invocation of the test driver, we could consider
some other caching approach, but it should work for non-CMake builds as
well. I consider this a low priority, since building the executable only
takes a few 10s of milliseconds on relatively modern hardware.
Closes#12364
This task is a bit annoying to implement because `sphinx-build` depends
on `fish_indent`, so that needs to be built, and the binary location
added to `PATH`.
Building `fish_indent` can be avoided by setting the `--fish-indent`
argument to the path to an existing `fish_indent` executable.
Use the new xtask in CMake builds. To do so without having to add
configuration options about where to put the docs, or having to copy
them from the default location to `build/user_doc`, we instead get rid of
the `user_doc` directory and change the code which accesses the docs to
read them from the non-configurable default output location in Cargo's
target directory.
Part of #12292
This is an initial implementation of the cargo xtask approach
https://github.com/matklad/cargo-xtask
For now, the only xtask is "check", which can be triggered by running
`cargo xtask check`. It is a thin wrapper around `build_tools/check.sh`.
Part of #12292
The `cargo` directory in the CMake build directory is only used to store
Cargo's build output, as would be done by `target` when building without
CMake. But instead of putting the build output directly into the `cargo`
directory, a nested `build` directory was used. There is no point in
this nesting, so remove it.
Closes#12352
`FISH_CMAKE_BINARY_DIR` is the top-level CMake output directory, not its
subdirectory used as the target directory by Cargo. So far, this has not
caused issues because CMake builds explicitly call `sphinx-build` to
build the man pages, instead of using the Rust crate for embedding them.
Closes#12354
This can't work because __fish_cached calls out to /bin/sh for fairly dubious reasons,
and it tries to get it to run a function.
So just run the *command* that the function runs and do the added filtering outside.
See #12326
I have been able to trigger this pretty reliably, and the simplest fix is
to... just not assert out when we would return anyway.
It doesn't reproduce with `commandline` because it needs the
suggestion to exist, it'll happen when you enter the "n" of "install"
if the suggestion is "İnstall" (i.e. uppercase turkish dotted i)
In general asserts in the reader make for a terrible experience.
We could technically extract this into a function, but it's a trivial
one-liner.
This allows rustup completions to be independently overridden.
Fixes#12357
Using `assert_eq!` instead of `assert!` has the advantage that when the
assertion fails, the debug representation of both sides will be shown,
which can provide more information about the failure than only seeing
that the assertion failed.
Part of #12336
Prepare for having HTML docs in the build output as well as man pages.
To avoid cluttering the top-level build dir, introduce a new `fish-docs`
directory, and put directories for the different types of docs in it.
The doctrees (cache files for sphinx) will be put parallel to the output
directories, to have a clear separation between desired output and cache
files. Note that we use separate cache directories for the different
builders, since sphinx does not handle shared caches well.
Part of #12292
Now, the `fish_wchar` crate does not have any local dependencies, making
it easy to depend on it in other crates without worrying about cyclic
dependencies.
Additionally, remove the (non-fish) `widestring` crate as a direct
dependency of the main crate.
Now, only the `fish_wchar` and `fish_printf` crates directly depend on
`widestring`. `fish_printf` could also depend on `fish_wchar`, but I
left that as is since `fish_printf` was published, so depending on a
crate which is not published to crates.io does not seem like a good
idea.
Part of #12313
The problem worked around by commit e4674cd7b5 (.cargo/config.toml:
exclude from tarball, 2025-01-12) is as follows:
our OBS packages are built by doing something like
tar xf $tarball && tar xf $vendor_tarball
except that the tool apparently break when a file is present in
both tarballs.
Our workaround is to not include .cargo/config.toml in the tarball.
The workaround seems too broad. It need not affect all tarballs
but only the ones used by OBS. We want to add xtask aliases to
.cargo/config.toml. They will be used by CMake targets (sphinx-doc),
so they should be available to tarball consumers.
Restrict the scope of the workaround: add back .cargo/config.toml
to the export, and allow opting in to this behavioer by passing a
negative pathspec
build_tools/make_tarball.sh :/!.cargo/config.toml
Fixes bbb2f0de8d (feat(vi-mode): make word movements vi-compliant,
2026-01-10).
When setting cursor pos, we need to make sure to call update_buff_pos,
which knows whether the one-past-last character ought to be selectable.
get_version() in build.rs duplicates some logic in
build_tools/git_version_gen.sh. There are some differences
1. When computing the Git hash, get_version() falls back to reading
.git/HEAD directly if "git describe" fails
1.1. Git is not installed
Not sure if this is a good strong reason. If you don't have
Git installed, how would you have created ".git"? If the exact
Git SHA is important, maybe we should use something like gitoxide
for this rather than implementing our own.
1.2. there is a permission problem
The case mentiond in 0083192fcb (Read git SHA ourselves if it
is unavailable, 2024-12-09) doesn't seem to happen with current
versions of Git: "sudo git describe" works fine. Something like
"sudo -u postgres git describe" doesn't. We could support that
but let's wait until we know of a use case.
1.3 there are no tags
(when doing "cargo install --git", as mentioned in 0dfc490721
(build.rs: Use Cargo_PKG_VERSION if no version could be found,
2024-06-10)).
Missing tags are no longer a problem because we read the version
from Cargo.toml now. Tweak the script to make sure that the
version is 4.3.3-g${git_sha} instead of just ${git_sha}.
2. get_version() falls back to jj too.
That was added for jj workspaces that don't have a Git worktree;
but those should be one their way out; when using jj's Git backend,
all workspaces will get an associated worktre.
Use the version in Cargo.toml instead.
Print a warning if the Cargo.toml version is not a prefix of the Git
version. This can happen legit scenarios, see 0dfc490721 (build.rs:
Use Cargo_PKG_VERSION if no version could be found, 2024-06-10)
but the next commit will fix that.
Also remove stale comments in git_version_gen.sh.
The `git_version_gen.sh` script is no longer used to write any files, so
remove the logic for it.
This code included handling for permission problems when running `git
describe`. It was introduced by
15f1b5f368, but unfortunately without
mentioning which CVE caused the change in git. I found CVE-2022-24765,
which was published not long before the commit was made, and its
description looks like it's fitting. On a recent version of git
(2.52.0), I had no problems running `make && sudo make install`, so it
seems like this issue might no longer be relevant. One suboptimal thing
to note is that `sudo make install` currently builds `fish_indent` even
if it was built via `make` before, which is not great, but unrelated to
these changes.
Part of #12307
This version file handling is no longer in use. Version strings are
generated on-demand using either `build_tools/git_version_gen.sh` or the
Rust implementation in `build.rs`. This makes the CMake code for version
handling obsolete.
Note that the current handling for version strings in Rust builds is
imperfect. If none of the build inputs change, the Rust code will not be
rebuilt, meaning the version strings in the executables are not updated.
This has been the case for a while and is not caused by this patch
series. This trade-off has been deemed worthwhile, because it simplifies
the implementation and eliminates the need for rebuilds when only the
version string changed. Because any changes to the actual input files
will trigger rebuilds, the version string will reference a commit which
is close enough to the actual version that it should not cause problems.
Part of #12307
The `build_tools/git_version_gen.sh` script can be used to determine the
appropriate version string. With this change, the convoluted version
file generation logic in CMake is no longer used and can subsequently be
removed.
Part of #12307
The `FISH_BUILD_VERSION_FILE` variable was only read in
`doc_src/conf.py`. There, it can be replaced by the
`build_tools/git_version_gen.sh` script, which takes the version from a
file called `version` at the workspace root if one exists, and otherwise
from git. This should cover all cases where the docs are built, so there
is no need to keep using the `FISH_BUILD_VERSION_FILE` variable.
Part of #12307
On macOS, pressing ctrl-o (VDISCARD) before starting fish will discard
all terminal output, from shell or its child processes. This breaks
querying and seems like something we don't want to support, so maybe
disable it?
Not sure if term_fix_external_modes needs it too, add it I guess.
Fixes#12304
This extracts the remaining code from `src/common.rs` which does not
depend on other parts of the main library crate. No functional changes.
Closes#12310
There was only a single usage of `EMPTY_STRING`, and there it was
immediately dereferenced, so use an empty static `&wstr` instead and
remove the `WString` constant.
Closes#12309
The `conf.py` file that was copied is not used for building. It seems
that it was used as a mechanism for triggering rebuilds on changes to
the original file, but in the current setup, `sphinx-build` is called
unconditionally when the relevant targets are built, so there is no
point in keeping on copying the `conf.py` file.
Closes#12303
Ensure `bind` builtin lists binds for all modes if `--mode` is not
given.
- The `get` function in `src/input.rs` now takes an optional bind
mode and returns a list of input mappings (binds).
- The `list_one` function in `src/builtins/bind.rs` lists binds in
the results returned by `get`.
- Creating the output string for a bind has been extracted to its
own function: `BuiltinBind::generate_output_string`.
- The `bind_mode_given` option has been removed.
Fixes#12214Closes#12285
- The behavior of `{,d}{w,W}`, `{,d}{,g}{e,E}` bindings in vi-mode is
now more compatible with vim, except that the underscore is not a
keyword (which can be achieved by setting `set iskeyword-=_` in vim).
- Add commands `{forward,kill}-{word,bigword}-vi`,
`{forward,backward,kill,backward-kill}-{word,bigword}-end` and
`kill-{a,inner}-{word,bigword}` corresponding to above-mentioned
bindings.
- Closes#10393.
Closes#12269
Co-authored-by: Johannes Altmanninger <aclopte@gmail.com>
Add `use Direction::*` and `use MoveWordStyle::*` in tests to reduce
verbosity. Reformat tests to one-line style and reorder by test type.
No behavior change.
Part of #12269
Highlighting the entire record caused custom prefixes to be
parsed as command syntax. For example, using:
`history --show-time="[%Y-%m-%d %H:%M:%S] "`
resulted in the timestamp being colorized as shell code.
Move highlighting inside format_history_record to process the
command string before the timestamp is prepended.
Closes#12300
https://codeberg.org/gpanders/ijqhttps://github.com/gpanders/ijq
For comparison purposes, here's the output of `ijq --help`
as of ijq 1.2.0:
```
ijq - interactive jq
Usage: ijq [-cnsrRMSV] [-f file] [filter] [files ...]
Options:
-C force colorized JSON, even if writing to a pipe or file
-H string
set path to history file. Set to '' to disable history. (default "/Users/ilyagr/Library/Application Support/ijq/history")
-M monochrome (don't colorize JSON)
-R read raw strings, not JSON texts
-S sort keys of objects on output
-V print version and exit
-c compact instead of pretty-printed output
-f filename
read initial filter from filename
-hide-input-pane
hide input (left) viewing pane
-jqbin string
name of or path to jq binary to use (default "jq")
-n use `null` as the single input value
-r output raw strings, not JSON texts
-s read (slurp) all inputs into an array; apply filter to it
```
Closes#12297
As mentioned in commit 289057f981 (reset_abandoning_line: actually
clear line on first prompt, 2025-11-11), we want to eventually allow
builtin read with a starting cursor with x>0. Until then, add a hack
to restore historical behavior in the case that users observed.
See #12296
To reduce the likelihood of false positive line-wise history
autosuggestions, we only them when the cursor's line starts a new
process ("parse_util_process_extent").
There are still false positives. Given
$ true &&
somecommand
$ echo "
someothercommand
"
typing "some" suggests "someothercommand" from history even though
that was not actually used as command.
Fix this by using similar rules for suggestion candidates.
Might help #12290
If my history has
git clean -dxf &&
./autogen.sh &&
./configure --prefix=...
then autosuggestions for "./conf" will show the third line, even if
./configure does not exist.
This is because even for line-wise autosuggestions, we only check
validity of the first command ("git"). Fix that by checking
the command from the line that's actually suggested.
The next commit will fix the issue that line-wise autosuggestions
may not actually be commands.
See also #12290
Multiple PRs fail with
pkg: Repository FreeBSD-ports cannot be opened. 'pkg update' required
Updating database digests format: . done
pkg: No packages available to install matching 'cmake-core' have been found in the repositories
Rust 1.70 stabilized `std::sync::OnceLock`, which replaces
`once_cell::sync::OnceCell`.
With this, we only have a single remaining direct dependency on
`once_cell`: `VAR_DISPATCH_TABLE` in `src/env_dispatch.rs`, where we use
`Lazy::get`. This can be replaced with `LazyLock::get` once our MSRV
reaches 1.94, where the function is stabilized.
At the moment, `serial_test` depends on `once_cell`, so even if we
eliminate it as a direct dependency, it will remain a transitive
dependency.
Closes#12289
Rust 1.80 stabilized `std::sync::LazyLock`, which replaces
`once_cell::sync::Lazy`. There is one exception in
`src/env_dispatch.rs`, which still uses the `once_cell` variant, since
the code there relies on `Lazy::get`, which also exists for `LazyLock`,
but will only be stabilized in Rust 1.94, so we can't use it yet.
Part of #12289
This is useful for running the checks with a toolchain which is
different from the default toolchain, for example to check if everything
works with our MSRV, or on beta/nightly toolchains. Additionally,
providing a way to run using the nightly toolchain allows writing
wrappers around `check.sh` which make use of nightly-only features.
The toolchain could be changed using `rustup toolchain default`, but if
the toolchain should only be used for a specific run, this is
inconvenient, and it does not allow for concurrent builds using
different toolchains.
Closes#12281
Webconfig persists themes to ~/.config/fish/conf.d/fish_frozen_theme.fish
(the name is due to historical reasons).
That file's color variables have no "--theme=foo" annotations, which
means that fish_config can't distinguish them from other "user-set"
values. We can change this in future, but that doesn't affect the
following fix.
A "fish_config theme choose foo" command is supposed to
overwrite all variables that are defined in "foo.theme".
If the theme is color-theme-aware *and* this command runs before
$fish_terminal_color_theme is initialized, we delay loading of the
theme until that initialization happens. But the --on-variable
invocation won't have the override bit set, thus it will not touch
variables that don't have "--theme=*" value. Fix this by clearing
immediately the variables mentioned in the theme.
Fixes#12278
While at it, tweak the error message for this command because it's
not an internal error:
fish -c 'echo yes | fish_config theme save tomorrow'
This replaces `initialize_gettext`. It is only defined when the
`localize-messages` feature is enabled, to avoid giving the impression
that it does anything useful when the feature is disabled.
With this change, Fluent will be initialized as well once it is added,
without requiring any additional code for initialization.
Closes#12190
Extract the language selection code from the gettext crate, and to a
lesser extent from `src/localization/mod.rs` and put it into
`src/localization/settings.rs`. No functional changes are intended.
Aside from better separation of concerns, this refactoring makes it
feasible to reuse the language selection logic for Fluent later on.
Part of #12190
The __fish_migrate.fish function spawns a "sh -c 'sleep 7' &" child
process that inherits stdin/stdout/stderr file descriptors fish.
This means that if the app running "fish
tests/checks/__fish_migrate.fish" actually waits for fish to close its
standard file descriptors, it will appear to hang for 7 seconds. Fix
that by closing the file descriptors in the background job when
creating it.
Closes#12271
The backward compat hack canonicalization caused us to always treat
"tomorrow" light theme.
Restrict this hack to the legacy name (Tomorrow); don't do it when
the new canonical name (tomorrow) is used. The same issue does not
affect other themes because their legacy names always have a "light"
or 'dark' suffix, which means that the canonical name is different,
so the legacy hacks don't affect the canonical name.
Fixes#12266
This logic exists to not break user configurations as we renamed
themes. But user-sourced themes haven't been renamed.
(It's also questionable whether we should really have these compat
hacks; they might cause confusion in the long run).
- Add missing options and completions for fetch, show-branch, am,
checkout, archive, grep, pull, push, revert, rm, config, clean, and
other commands
- Replace TODO comments with actual option completions for improved
usability
- Ensure all new options have appropriate descriptions and argument
handling for fish shell completion
Closes#12263
Due to the way tmux implements it, color theme reporting
causes issues when typing commands really quickly (such as
when synthesizing keys). We're working on fixing this, see
https://github.com/tmux/tmux/issues/4787#issuecomment-3707866550
Disable it for now. AFAIK other terminals are not affected.
Closes#12261
- Fix the background color of .function-body in dark mode to improve readability.
- Switch to Tomorrow Night Bright color theme for better contrast and readability in dark mode.
- Format all stylesheets of fish_config.
Closes#12257
Something like
PATH=mypath builtin fish_indent --help
runs "fish -c '__fish_print_help fish_indent'" internally. Since we
don't call setenv(), the PATH update doesn't reach the child shell.
Fix this by using what other builtins use if we are one (i.e. if we
have a Parser in context).
Fixes#12229
Maybe also #12085
We sometimes use explicit reclaim() and sometimes rely on the drop
implementation. This adds an unnecesary step to reading all uses of
this code. Make this consistent. Use drop everywhere though we could
use explicit reclaim too.
Prior to f417cbc981 (Show soft-wrapped portions in autosuggestions,
2025-12-11), we'd truncate autosuggestions before the right prompt.
We no longer do that for autosuggestions that soft-wrap, which means
we try to draw both right prompt and suggestion in the same space.
Make suggestion paint over right prompt for now, since this seems to
be a simple and robust solution. We can revisit this later.
Fixes#12255
If "will_replace_token" is set, we generally only consider
appending completions. This changed in commit 656b39a0b3 (Also show
case-insensitive prefix matches in completion pager, 2025-11-23) which
also allowed icase completions as long as they are also prefix matches.
Such replacing completions might cause the common prefix to be empty,
which breaks the appending completions.
Fix this by not considering these replacing completions for the
common-prefix computation. The pager already doesn't show the prefix
for these completions specifically.
Fixes#12249
We skip completions where "will_replace_token != c.replaces_token()".
This means that
- if will_replace_token, we filter out non-replacing completions.
But those do not exist because, by definition, will_replace_token
is true iff there are no non-replacing completions.
- if !will_replace_token, we filter out replacing completions.
From the definition of will_replace_token follows that there is
some non-replacing completion, which must be a prefix or exact match.
Since we've filtered by rank, any replacing ones must have the same rank.
So the replacement bit must be due to smartcase. Smartcase
completions are already passed through explicitly here since
656b39a0b3 (Also show case-insensitive prefix matches in completion
pager, 2025-11-23).
So the cases where we 'continue' here can never happen.
Remove this redundant check.
The tuple (will_replace_token, all_matches_exact_or_prefix) can never
be (false, false).
Proof by contraction:
1. Goal: show unsatisfiability of: !will_replace_token && !all_matches_exact_or_prefix
2. Substitute defintions: !all(replaces) && !all(is_exact_or_prefix)
3. wlog, !replaces(c1) && !is_exact_or_prefix(c2)
4. since c1 and c2 have same rank we know that !is_exact_or_prefix(c1)
5. !is_exact_or_prefix() implies requires_full_replacement()
6. all callers that create a Completion from StringFuzzyMatch::try_create(),
set CompleteFlags::REPLACE_TOKEN if requires_full_replacement(),
so requires_full_replacement() implies replaces()
7. From 4-6 follows: !is_exact_or_prefix(c1) implies replaces(c1), which is a contradiction
A recent change attempted this:
let result: std::io::Result<()> = { code()? }
However this doesn't initialize the Result on error - instead it
returns from the function, meaning that the error would be silently
dropped.
Fix that by reporting the error at the call site instead.
Commit fbad0ab50a (reset_abandoning_line: remove redundant
allocations, 2025-11-13) uses byte count of ⏎ (3) instead of char
count (1), thus overestimating the number of spaces this symbol takes.
Fixes#12246
Rust has this annoying design where all of the syscall conveniences on
File assume that it owns its fd; in particular this means that we can't
easily construct File from stdin, a raw file descriptor, etc.
The usual workarounds are to construct a File and then mem::forget it
(this is apparently idiomatic Rust!). But this has problems of its own:
for example it can't easily be used in Drop.
Introduce BorrowedFdFile which wraps File with ManuallyDrop and then
never drops the file (i.e. it's always forgotten). Replace some raw FDs
with BorrowedFdFile.
Prior to this commit, this code:
fish_indent <&-
would panic as we would construct a File with a negative fd.
Check for a closed fd as other builtins do.
Since fish_indent became a builtin, it cannot be canceled with control-C,
because Rust's `read_to_end` retries on EINTR. Add our own function which
propagates EINTR and use it.
Fixes#12238
Commit 7996637db5 (Make fish immediately show color changes again,
2025-12-01) repaints unnecessarily when a local unexported color
variable changes. Also, it repaints when the change comes from
fish_prompt, causing an easy infinite loop. Same when changing TERM,
COLORTERM and others.
This feature is relevant when using a color-theme aware theme, so
try to keep it. Repaint only on global/universal changes.
Also ignore changes if already repainting fish prompt.
This change may be at odds with concurrent execution (parser should
not care about whether we are repainting) but that's intentional
because of 1. time constraints and 2. I'm not sure what the solution
will look like; we could use the event infrastructure. But a lot of
existing variable listeners don't use that.
Extract a context object we pass whenever we mutate the environment; While
at it, use it to pass EnvMode::USER, to reduce EnvMode responsibilities.
Fixes#12233
We set "global_modified" to true if the global exist, or if the
default scope is global but not if EnvMode::GLOBAL.
This is an accident from 77aeb6a2a8 (Port execution, 2023-10-08).
Restore it. Tested in a following commit.
We have pretty weird behavior:
$ set --path somepath 1 2 3
set --erase --unpath somepath[2]
[1]$ set --path somepath 1 2 3
set --erase --unpath somepath
$
The first command fails to erase from the variable, because the
--path/--unpath mismatch prevents us from accessing the variable.
The second succeeds at erasing because we ignore --path/--unpath.
We should probably fix this; for now only simplify the unrelated
change added by fed64999bc (Allow erasing in multiple scopes in one
go, 2022-10-15):
we implement "set --erase --global --path" as
try_erase(scope="--global")
try_erase(scope="--path")
Do this instead, which is closer to historical behavior.
try_erase(scope="--global --path")
This also allows us to express more obviously the behavior if no scope
(out of -lfgU) was specified.
Just following basic shellscript optimization:
- Remove a useless use of cat (`status get-file` takes microseconds,
`status get-file | cat` is on the order of a millisecond - slower with
bigger $PATH)
- Pipe, don't run in a loop
- Filter early
This reduces the time taken from 12ms to 6ms on one of my systems, and
6.5ms to 4.5ms on another.
This is paid on every single shell startup, including
non-interactively, so it's worth it.
There's more to investigate, but this is a good first pass.
Commit 7b4802091a installs fish_indent and fish_key_reader as
hardlinks to fish. When we create our fat binary for macOS, we add
3 of these X86 binaries to the fattened one,
resulting in a corrupted Mach-O binary. Fix that.
Fixes#12224
Commit 135fc73191 (Remove man/HTML docs from tarball, require Sphinx
instead, 2025-11-20) broke cross compilation of tarballs.
Add an option to allow users to pick any fish_indent (such as
"target/debug/fish_indent" as created by "cargo build"), to allow
cross compilation.
In future, we should remove this option in favor of doing all of this
transparently at build type (in build.rs).
Ref: https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$psPcu-ogWK5q9IkgvfdvBGTdJ2XGhNq5z_Ug0iTCx2Q
When I ssh to a macOS system, typing ctrl-p ctrl-j in quick succession
sometimes causes ^[[I (focus in) to be echoed. Looks like we fail to
disable terminal-echo in time. Possible race condition? Revert until
we find out more.
This reverts commit 7dd2004da7.
Closes#12232
The __fish_data_with_file wrapper was born out of a desire to simplify
handling of file paths that may or may not be embedded into the
fish binary.
Since 95aeb16ca2 (Remove embed-data feature flag, 2025-11-20) this is
no longer needed since almost everything is embedded unconditionally.
The exception is man pages (see a1baf97f54 (Do not embed man pages
in CMake builds, 2025-11-20)), but they use __fish_data_with_directory.
Man pages used to be built by "build.rs" but now are built by a
dependent "crates/build-man-pages/build.rs". This means that changing
the environment of build.rs is ineffective.
In future, "fn get_version" should probably be a part of
"crates/build-helper/", so Cargo builds only need to compute the
version once.
Lack of this dependency means that "build-man-pages" does not
pass FISH_BUILD_VERSION, which means that Sphinx will fall back to
build_tools/git_version_gen.sh. This acceptable for now given that
"build-man-pages" is not used in CMake builds.
Commit 2343a6b1f1 passed the FISH_BUILD_VERSION_FILE to
sphinx-manpages to remove the fish_indent dependency.
For sphinx-docs this has been solved in another way in e895f96f8a
(Do not rely on `fish_indent` for version in Sphinx, 2025-08-19).
This is a needless inconsistency.
Remove it. Use FISH_BUILD_VERSION_FILE whenever possible, since that
means that a full build process only needs to call git_version_gen.sh
once.
Keep the fallback to git_version_gen.sh, in case someone calls
sphinx-build directly.
Prior to commit 135fc73191 (Remove man/HTML docs from tarball, require
Sphinx instead, 2025-11-20), HTML docs were built from a Git worktree.
Now they are built in the tarball. We call
build_tools/git_version_gen.sh from doc_src so it fails to find the
version file. Fix that.
Fixes#12228
Not being able to delete these for good (if unused) seems to be
a nuisance. Let's go back to storing universal __fish_initialized
also on fresh installations, which I guess is a small price to to
avoid recreating these files.
Closes#12230
Commit 30942e16dc (Fix prefix/suffix icase comparisons, 2025-12-27)
incorrectly treated "gs " as prefix of "gs" which causes a crash
immediately after expanding that abbreviation iff "gs" is our
autosuggestion (i.e. there's no history autosuggestion taking
precedence).
Fixes#12223
Now that the default theme no longer contains light/dark sections,
we don't need to wait for $fish_terminal_color_theme to be initialized
before setting it.
Let's set it before loading user config to allow users to do things
like "set -e fish_color_command" in their config.
Fixes#12209
If we're overriding the theme with --color-theme=, we don't need to
register the hook because $fish_terminal_color_theme will be ignored.
Also if the theme is not color-theme aware, there is no need to
register the hook.
The readability concern in ed881bcdd8 (Make default theme use named
colors only, 2023-07-25) was no longer relevant, but people might
prefer we use terminal colors by default, because other apps do too,
and because it's a well-known way to make colors look good across
both dark and light mode.
If we revert this, we should make sure fish_default_mode_prompt.fish
and prompt_login.fish also use RGB colors
As reported on Gitter, running "echo İ" makes history autosuggestion
for "echo i" crash. This is because history search correctly
returns the former, but string_prefixes_string_case_insensitive("i",
"İ") incorrectly returns false. This is because the prefix check
is implemented by trimming the rhs to the length of the prefix and
checking if the result is equal to the prefix. This is wrong because
the prefix computation should operate on the canonical lowercase
version, because that's what history search uses.
The theme marker is set by "fish_config theme choose" to allow
us to react to terminal color theme changes, and to tell future
"fish_config theme choose" invocations which variables it should erase
-- it should not erase color variables not set in the theme file,
like Git prompt colors.
I'm not sure if either really makes sense for "fish_config theme save".
Reacting to terminal color theme changes is weird for universals.
I'm not sure if "fish_config theme save" should erase universal
variables that are not defined in the theme. Historically, it did
so for a hardcoded list of colors, which is hacky. For now let's
err on the side of leaving around color variables.
The "save" subcommand is deprecated; it's possible that this changes
in future (and we add support for "--theme" to it) but I'm not sure
if we have enough need for that.
Users who run the default theme are silently migrated to global
variables. Universal color variables are deleted, leaving existing
sessions uncolored. Tell the user to restart them, and make some
other improvements; now it looks like:
fish: upgraded to version 4.3:
* Color variables are no longer set in universal scope.
To restore syntax highlighting in other fish sessions, please restart them.
* The fish_key_bindings variable is no longer set in universal scope by default.
Migrated it to a global variable set in ~/.config/fish/conf.d/fish_frozen_key_bindings.fish
Same for users who do not use the default theme (who already got a
message before this change). For them, the first bullet point looks
like this:
[...]
* Color variables are no longer set in universal scope by default.
Migrated them to global variables set in ~/.config/fish/conf.d/fish_frozen_theme.fish
To restore syntax highlighting in other fish sessions, please restart them.
[...]
Closes#12161
These fall back to param/command roles, so there's no need to
duplicate the value.
Make sure the "set fish_color_o<TAB>" still works if they're not
defined.
Leave it as a comment in theme files I guess, since users copy-pasting
a theme might reasonably want to set it.
Closes#12209
Change the input of some functions to take `impl IntoCharIter`, allowing
them to accept more input. Implementing this efficiently means that no
owned types should be passed into these functions, because their
`IntoCharIter` implementation would require unnecessary allocations.
Instead, convert the uses which previously passed `WString` by prefixing
an `&`, so the borrowed `&WString` is passed instead.
To allow for wider use of the modified functions, `IntoCharIter`
implementations are added for `&String`, `&Cow<str>`, and `&Cow<wstr>`.
Closes#12207
Removed in 9edd0cf8ee (Remove some now unused CMake bits, 2024-07-07).
The replacements are not documented in prose but in the GitHub
release workflow.
This command
echo $(/bin/echo -n 1; echo -n 2)
sometimes outputs "21" because we implement this as
let bufferfill = IoBufferfill::create_opts(...);
...
let eval_res = parser.eval_with(...);
let buffer = IoBufferfill::finish(bufferfill);
i.e. /bin/echo and builtin echo both output to the same buffer; the
builtin does inside parser.eval_with(), and the external process may
or may not output before that, depending on when the FD monitor thread
gets scheduled (to run item_callback).
(Unrelated to that we make sure to consume all available input in
"IoBufferfill::finish(bufferfill)" but that doesn't help with
ordering.)
Fix this by reading all available data from stdout after the child
process has exited.
This means we need to pass the BufferFill down to
process_mark_finished_children().
We don't need to do this for builtins like "fg" or "wait",
because commands that buffer output do not get job control, see
2ca66cff53 (Disable job control inside command substitutions,
2021-07-26).
We also don't need to do it when reaping from reader because there
should be no buffering(?).
fish still deviates from other shells in that it doesn't wait for
it's child's stdout to be closed, meaning that this will behave
non-deterministically.
fish -c '
echo -n $(
sh -c " ( for i in \$(seq 10000); do printf .; done ) & "
)
' | wc -c
We should fix that later.
Closes#12018
The existing functionality of converting a `&wstr` to bytes (unescaping
PUA codepoints) and writing these to a file descriptor can be reused for
Rust's built-in strings by making the input type generic. This is
simple, because the only functionality we need is converting the input
into a `char` iterator, which is available for both types.
While at it, rename the functions to have more accurate and informative
names.
Closes#12206
When the output is redirected, Python buffer its whole output, unlike
a TTY output where only lines are buffered.
In GitHub actions in particular, it means that we can't see any progress
after each test. And if a test blocks forever, there is no output at all.
So flush the output after printing each result to see the progress
being made
Run fish_indent on test scripts that will be modified in a later
commit
Not running it on all the files because a quarter of them need fixing,
some of which are badly formatted on purpose
This is done in preparation for Fluent's FTL files, which will be placed
in `localization/fluent/`. Having a shared parent reduces top-level
clutter in the repo and makes it easier to find the localization files
for translators, including realizing that both PO and FTL files exist.
We keep PO and FTL files in separate directories because we need to
rebuild on any changes in the PO directory (technically only when there
are changes to `*.po` files, but due to technical limitations we can't
reliably trigger rebuilds only if those changes but not other files in
the same directory.) Changes to FTL files do not require rebuilds for
dev builds, since for these `rust-embed` does not actually embed them
into the binary but rather loads them from the file system at runtime.
Closes#12193
The upstream completions have not been updated for some time, but the
docker binary can generate completions. These include dynamic
completions for image names and so on.
Closes#12197.
Localization deserves its own module. As a first step, this module is
created here. This will be followed up by significant refactoring in
preparation for supporting Fluent alongside gettext.
`localization/mod.rs` is used instead of `localization.rs` because it is
planned to split this module into submodules.
Part of #12190
The needless_return lint was disabled almost two years ago, alongside
several other lints. It might have been helpful for porting from C++.
Now, I think we can enable that lint again, since omitting the returns
results in equivalent, more concise code, which should not be harder to
read.
The only manual changes in this commit are removing the lint exception
from `Cargo.toml` and removing the unnecessary returns inside `cfg_if!`
macro invocations (in `src/fd_monitor.rs` and `src/proc.rs`).
All other changes were generated by
`cargo clippy --workspace --all-targets --fix && cargo fmt`
Closes#12189
Having the prelude in wchar is not great. The wchar module was empty
except for the prelude, and its prelude included things from wutil.
Having a top-level prelude module in the main crate resolves this. It
allows us to completely remove the wchar module, and a top-level prelude
module makes more sense conceptually. Putting non-wchar things into the
prelude also becomes more sensible, if we ever want to do that.
Closes#12182
After I run a child process like "fish -C 'cd /tmp'", the terminal
will have a stale working directory.
Let's send the OSC 7 notification also once for every fresh prompt
(which is less frequent than the calls to fish_prompt).
This is not fully correct, since it will not work for cases like bind
ctrl-g 'fish -C "cd /tmp"' which allow running external commands
without creating a fresh prompt. We can fix those later, using the
code paths for bracketed paste and friends.
A minor argument for not fixing this just yet is that some people
override "__fish_update_cwd_osc" to work around bugs in their terminal.
Closes#12191Closes#11778Closes#11777
When I run "read" and press enter on the foot terminal, I see a "^[[I"
echoed in the TTY. This is because
1. builtin read creates a TtyHandoff and runs enable_tty_protocols()
2. it runs Reader::readline(), which creates another TtyHandoff.
3. before Reader::readline() returns, it unsets shell modes
(turning ECHO back on). It also drops its TtyHandoff,
which enables TTY protocols again.
4. Enabling focus reporting causes this terminal to send
focus-in event immediately.
This is our fault; we should not have TTY protocols enabled while
ECHO is on.
Fix this by removing the first TtyHandoff (which seems redundant),
meaning that the second one will not try to re-enable protocols.
Breaks the build on OpenBSD.
This is another case of a nix feature being unavailable on some platforms,
so start documenting them.
This reverts commit d6108e5bc0.
Fixes#12192
Our error marking code:
```
function foobar
^~~~~~~^
```
runs fish_wcswidth to figure out how wide the squiggly line should be.
That function returns -1 when it runs into a codepoint that wcwidth
returns -1 for, so the marking would stop at a single `^`.
In some cases, this happens because the error range includes a
newline.
Since we already find the end of the line, and can only mark one line,
we clamp the squiggles at the end of that line.
This improves some markings.
See discussion in #12171
A subsequent commit will need to test for cygwin in a new crate. On
current stable Rust (1.92) this works via `#[cfg(target_os = "cygwin)]`,
but our MSRV (1.85) does not support this. To avoid code duplication,
the OS detection logic is extracted into the build helper crate. For
now, only `detect_cygwin` is needed, but it would be inconsistent to
extract that but not the same functions for other operating systems.
Part of #12183
Another reduction in size of the main crate. Also allows other crates to
depend on the new wchar crate.
The original `src/wchar.rs` file is kept around for now to keep the
prelude imports working.
Part of #12182
Dependencies between crates must form a DAG. This means that breaking up
the large library crate requires breaking dependency cycles. The goal of
this commit is creating a crate which contains some of the main crate's
functionality, without depending on the main crate.
To start off, we only move things required for extracting `src/wchar.rs`
and `src/wchar_ext.rs`, which will happen in a subsequent commit.
Part of #12182
This should help with improving incremental build speed. Extracting this
code is easy, since it does not have dependencies. It also unblocks
further extraction of code which depends on widecharwidth.
Closes#12181
We have logic to prevent "commandline --cursor 123" inside "complete
-C" from setting the transient commandline's cursor.
But reading this cursor ("commandline --cursor")
is fine and expected to work by completion scripts.
I don't expect there is a use case for setting the cursor while
computing completions, so let's make that an error for now.
Could revisit that.
Closes#11993
This test removes $PWD which would cause an error if it were to start
a new process. Normaly we would "cd -" before the removal but later
assertions expect an empty $PWD, so stay there, but don't remove it
to prevent possible surprise.
stage_wildcards has no need for INTERNAL_SEPARATOR. Remove it already
at this stage, to avoid the need to have the workaround in the generic
decoding routine.
Unfortunately we still can't add assert!(!fish_reserved_codepoint(c));
to wcs2bytes_callback, since builtin printf still passes arbitrary
characters. We should fix that later.
Test that printf now behaves correctly for INTERNAL_SEPARATOR.
Also add a regression test for 0c9b73e317.
For some reason r-a shows this diagnostic even though we suppress it
in Cargo.toml (I still need to create a bug report).
Making these upper case would be noisy at the call sites, and it
probably doesn't help since we don't think of these identifiers
as global variables (we never access their fields directly).
Silence the r-a warning for now.
See #12156
This is part of the larger effort of splitting up fish's huge main crate
to improve incremental build speed.
We could extract more logic from `src/wutil/gettext.rs` into the new
crate, but this would require putting wide-string handling into that
crate, which I'm not sure we want. Doing so would have the advantage
that crates which don't depend on fish's main crate (i.e. all crates
other than fish's main crate itself and the binary crates built on top
of it) could then localize messages as well. This will be less relevant
if we replace gettext with Fluent for messages originating from the Rust
sources.
Closes#12108
Based on the discussion in
https://github.com/fish-shell/fish-shell/pull/11967
Introduce a `status language` builtin, which has subcommands for
controlling and inspecting fish's message localization status.
The motivation for this is that using only the established environment
variables `LANGUAGE`, `LC_ALL`, `LC_MESSAGES`, and `LANG` can cause
problems when fish interprets them differently from GNU gettext.
In addition, these are not well-suited for users who want to override
their normal localization settings only for fish, since fish would
propagate the values of these variables to its child processes.
Configuration via these variables still works as before, but now there
is the `status language set` command, which allows overriding the
localization configuration.
If `status language set` is used, the language precedence list will be
taken from its remaining arguments.
Warnings will be shown for invalid arguments.
Once this command was used, the localization related environment
variables are ignored.
To go back to taking the configuration from the environment variables
after `status language set` was executed, users can run `status language
unset`.
Running `status language` without arguments shows information about the
current message localization status, allowing users to better understand
how their settings are interpreted by fish.
The `status language list-available` command shows which languages are
available to choose from, which is used for completions.
This commit eliminates dependencies from the `gettext_impl` module to
code in fish's main crate, allowing for extraction of this module into
its own crate in a future commit.
Closes#12106
We delete the tmpdir unconditionally once all tests are completed, so
there is no point in printing a path which will no longer exist when
analyzing test failures. The paths don't contain any useful information,
so let's delete them to avoid confusion and useless output.
Before this, our test driver printed littlecheck's output before the
test result (test name, duration, PASSED/FAILED/SKIPPED).
This makes it harder to read the output and is inconsistent with the way
pexpect test failures are shown.
Starting with this commit, the result is printed first for both test
types, followed by details about failures, if any.
This reverts commit 52ea511768 ("cleanup: remove useless `INTERNAL_SEPARATOR` handling").
I don't know how to test this given that we don't know what users exist (maybe "root"?).
Fixes#12175
`alias` is terrible, but the main downside of this is that it shows up
in the output of `alias`, which it shouldn't because the user didn't
define these.
This appends "-g" to RUSTFLAGS if the cmake build type is debug or
RelWithDebInfo.
However, these are already mapped to cargo profiles that enable these
things, see https://doc.rust-lang.org/cargo/reference/profiles.html:
> The debug setting controls the -C debuginfo flag which controls the
amount of debug information included in the compiled binary.
(`rustc -g` is equivalent to `debuginfo=2`)
By setting $RUSTFLAGS in cmake, we bake it into the generated
makefile (/ninja thing), which is surprising.
See #12165
Path component movement is not aware of fish syntax -- and we should
be careful as we teach it some fish syntax, because it is expected
to be used on command lines that have unclosed quotes etc.
Tab completion typically uses backslashes to escape paths with spaces.
Using ctrl-w on such path components doesn't work well because it
stops at the escaped space.
Add a quick hack to change it to skip over backslashed spaces. Note that
this isn't fully correct because it will treat backslashes inside
quotes the same way. Not sure what we should do here. We could have
ctrl-w erase all of this
"this is"'only\ one 'path component
But that might be surprising.
Regardless of what we end up with, skipping over backslashed whitespace
seems totally fine, so add that now
Closes#2016
From each logical line in the autosuggestion, we show all or nothing.
This means that we may truncate too early -- specifically 1 + the
number of soft-wrappings in this line. Fix that.
See also #12153
Implicitly-universal variables have some downsides:
- It's surprising that "set fish_color_normal ..."
and "set fish_key_bindings fish_vi_key_bindings" propagate to other
shells and persist, especially since all other variables (and other
shells) would use the global scope.
- they don't play well with tracking configuration in Git.
- we don't know how to roll out updates to the default theme (which is
problematic since can look bad depending on terminal background
color scheme).
It's sort of possible to use only globals and unset universal variables
(because fish only sets them at first startup), but that requires
knowledge of fish internals; I don't think many people do that.
So:
- Set all color variables that are not already set as globals.
- To enable this do the following, once, after upgrading:
copy any existing universal color variables to globals, and:
- if existing universal color variables exactly match
the previous default theme, and pretend they didn't exist.
- else migrate the universals to ~/.config/fish/conf.d/fish_frozen_theme.fish,
which is a less surprising way of persisting this.
- either way, delete all universals to do the right thing for most users.
- Make sure that webconfig's "Set Theme" continues to:
- instantly update all running shells
- This is achieved by a new universal variable (but only for
notifying shells, so this doesn't actually need to be persisted).
In future, we could use any other IPC mechanism such as "kill -SIGUSR1"
or if we go for a new feature, "varsave" or "set --broadcast", see
https://github.com/fish-shell/fish-shell/issues/7317#issuecomment-701165897https://github.com/fish-shell/fish-shell/pull/8455#discussion_r757837137.
- persist the theme updates, completely overriding any previous theme.
Use the same "fish_frozen_theme.fish" snippet as for migration (see above).
It's not meant to be edited directly. If people want flexibility
the should delete it.
It could be a universal variable instead of a conf snippet file;
but I figured that the separate file looks nicer
(we can have better comments etc.)
- Ask the terminal whether it's using dark or light mode, and use an
optimized default. Add dark/light variants to themes,
and the "unknown" variant for the default theme.
Other themes don't need the "unknown" variant;
webconfig already has a background color in context,
and CLI can require the user to specify variant explicitly if
terminal doesn't advertise colors.
- Every variable that is set as part of fish's default behavior
gets a "--label=default" tacked onto it.
This is to allow our fish_terminal_color_theme event handler to
know which variables it is allowed to update. It's also necessary
until we revert 7e3fac561d (Query terminal only just before reading
from it, 2025-09-25) because since commit, we need to wait until
the first reader_push() to get query results. By this time, the
user's config.fish may already have set variables.
If the user sets variables via either webconfig, "fish_config theme
{choose,save}", or directly via "set fish_color_...", they'd almost
always remove this label.
- For consistency, make default fish_key_bindings global
(note that, for better or worse, fish_add_path still remains as
one place that implicitly sets universal variables, but it's not
something we inject by default)
- Have "fish_config theme choose" and webconfig equivalents reset
all color variables. This makes much more sense than keeping a
hardcoded subset of "known colors"; and now that we don't really
expect to be deleting universals this way, it's actually possible
to make this change without much fear.
Should have split this into two commits (the changelog entries are
intertwined though).
Closes#11580Closes#11435Closes#7317
Ref: https://github.com/fish-shell/fish-shell/issues/12096#issuecomment-3632065704
This is incomplete, and we'll solve the problem differently. For now,
leave colors that are not mentioned in the theme. This causes problems
for sparse themes, but a following commit will fix that by making
"fish_config theme choose" erase all variables set by a previous
invocation (but not erase variables set by the user). Only webconfig
won't do that since it (historically) uses copy semantics, but we
could change that too if needed.
This also breaks the guarantee mentioned by this comment in webconfig:
> Ensure that we have all the color names we know about, so that if the
> user deletes one he can still set it again via the web interface
which should be fine because:
1. a following commit will always set all globals at interactive init,
so colors should only be missing in edge cases ("fish -c fish_config").
2. it's easy to recover from by setting a default theme.
For better or worse, "set -L" prints all of $history, which makes
"fish_config theme show" very slow. Fix this by only printing the
relevant variables. While at, make the escaping function use the
shared subset of fish and POSIX shell quoting syntax, to allow a
following commit to use shlex.split().
A following commit wants to add some more logic and call some of
fish_config's private APIs from webconfig. We could keep it all in
one file but I'm not sure we should so try the splitting we usually do.
Historically, fish tried to re-exec the prompt and repaint immediately
when a color variable changed.
Commit f5c6306bde (Do not repaint prompt on universal variable events,
but add event handler for fish_color_cwd, 2006-05-11) restricted this
to only variables used in the prompt like "fish_color_cwd".
Commit 0c9a1a56c2 (Lots of work on web config Change to make fish
immediately show color changes, 2012-03-25) added repainting back
for all colors (except for pager colors).
Commit ff62d172e5 (Stop repainting in C++, 2020-12-11) undid that.
Finally, 69c71052ef (Remove __fish_repaint, 2021-03-04) removed the
--on-variable repaint handlers added by the first commit.
So if color changes via either
1. webconfig
2. an event handler reacting to the terminal switching between light/dark mode
3. a binding etc.
then we fail to redraw. Affects both colors used in prompts and those
not used in prompts.
Fix that by adding back the hack from the second commit. This is
particularly important for case 2, to be added by a following commit.
In future we can remove this hack by making "--on-variable" take
a wildcard.
I can no longer reproduce the issue described in bdd478bbd0 (Disable
focus reporting on non-tmux again for now, 2024-04-18). Maybe the
TTY handoff changes fixed this. Let's remove this workaround and
enable focus reporting everywhere.
Start by converting the "default" theme's colors to RGB, using
XTerm colors since they are simple, see
https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit.
Then make the following changes:
for both default-light and default-dark:
- Reinstate fish_color_command/fish_color_keyword as blue since one
of the reasons in 81ff6db62d (default color scheme: Make commands
"normal" color, 2024-10-02) doesn't hold anymore.
- bravely replace "fish_pager_color_selected_background -r" with
something that hopefully matches better.
Note we can't trivially use the fallback to
"fish_color_search_match", since for unknown reasons,
"fish_pager_color_selected_background" is only for background and
the others are for foreground.
for default-light:
- brgreen (00ff00) looks bad on light background, so replace it with green (00cd00).
This means that we no longer use two different shades of green in the default theme
(which helps address the "fruit salad" mentioned 81ff6db62d).
- yellow (cdcd00) looks bad on light background, make it darker (a0a000)
- fish_pager_color_progress's --background=cyan (00cdcd) seems a bit too bright, make it darker
- same for other uses of cyan (also for consistency)
- this means fish_color_operator / fish_color_escape can use 00cdcd I guess.
for default-dark:
- use bright green (00ff00) for all greens
- use bright blue (5c5cff) instead of regular blue for command/keyword
- make autosuggestions a bit lighter (9f9f9f instead of 7f7f7f)
- etc.. I think I made the two themes mostly symmetrical.
Part of #11580
The "fish-" prefix is not needed here and it would add more noise to
a following commit which adds default-{dark,light} variants that use
24 bit RGB colors.
Don't set fish_pager_color_completion,
it already falls back to fish_color_normal.
Also remove a comment, it's obvious and maybe no longer
true, since 8 bit colors are widely available now, see
https://github.com/fish-shell/fish-shell/issues/11344#issuecomment-3568265178
Though we prefer 24 bit colors wherever we can.
For historical reasons (namely the webconfig origin), our theme
names contain spaces and uppercase letters which can be inconvenient
when using the "fish_config theme choose" shell command. Use more
conventional file names.
Web config still uses the pretty names, using the ubiquitous "# name:"
property.
This function returns a heterogeneous list (containing dicts/lists)
by accident. Fix that and reduce code duplication. Fixes c018bfdb4d
(Initial work to add support for angularjs, 2013-08-17).
Note that we don't need to set the mtime anymore -- it was added in
5b5b53872c (tarball generation: include config.h.in, set mode and
ownership, 2013-09-09) for autotools' multi-stage builds.
Advantages of prebuilt docs:
- convenient for users who compile the tarball
- convenient for packagers who don't have sphinx-build packaged
(but packaging/installing that should be easy nowadays?
see https://github.com/fish-shell/fish-shell/issues/12052#issuecomment-3520336984)
Disadvantages:
- Extra build stage / code path
- Users who switch from building from tarball to building from source
might be surprised to lose docs.
- People put the [tarballs into Git repositories](https://salsa.debian.org/debian/fish), which seems weird.
Remove the tarball.
Let's hope this is not too annoying to users who build on outdated
distros that don't have sphinx -- but those users can probably use
our static builds, skipping all compilation.
To avoid breaking packagers who use `-DBUILD_DOCS=OFF` (which still
installs prebuilt docs), rename the option.
Closes#12088
The logic added by 2dbaf10c36 (Also refresh TTY timestamps
after external commands from bindings, 2024-10-21) is obsoleted
by TtyHandoff. That module is also responsible for calling
reader_save_screen_state after it writes to the TTY, so we don't
actually need to check if it wrote anything.
We silence erros from the key binding function since 2c5151bb78 (Fix
bug in key binding code causing unneeded error messages, 2007-10-31).
Reasons are
1. fish_key_bindings is not a valid function
2. fish_key_bindings runs "bind -k" for things that are not supported (#1155)
Both reasons are obsolete:
1. we already check that earlier
2. "-k" is gone. (Also, we could have silenced "bind -k" invocations instead).
- Prefer the command name without `.exe` since the extension is optional
when launching application on Windows...
- ... but if the user started to type the extension, then use it.
- If there is no description and/or completion for `foo.exe` then
use those for `foo`
Closes#12100
Discussion with terminal authors indicates a slight preference for
removing the prefix. We don't need it at this point, since we only
use it to detect macOS clients.
Two issues:
1. "complete -e foo" doesn't erase wrap definitions
2. "complete -e foo --wraps" erases things other than the wrap definitions
Fix them.
There's another issue, the second erase command leaves around an
extra complete entry. Let's leave that for later.
Fixes#12150
These tests are unreliable in CI when running with address sanitiation
enabled, resulting in intermittent CI failures.
Disable them to get rid of the many false positives to reduce annoyance
and to avoid desensitization regarding failures of the asan CI job.
Suggested in
https://github.com/fish-shell/fish-shell/pull/12132#issuecomment-3605639954Closes#12142Closes#12132Closes#12126
This lint is intended to make it harder to unintentionally cast a
function to an int. We do want to store function pointers in a usize
here, so add the intermediate cast suggested by the lint.
Closes#12131
Buggy programs parsing "fish_indent --ansi" output break because
we wemit SGR0 after the final newline. I suppose this is weird,
and there's no need to wait until after the \n to emit SGR0 so let's
move it before that.
Closes#12096
We should isolate conditionally-compiled code as much as possible,
to allow the compiler to do more work, and to simplify code.
Do that for the embedding definition for __fish_build_paths, like we
already do for "Docs". Duplicate the workaround we use to set the
embedded struct to a "virtually empty" directory. Don't set it to
"$FISH_RESOLVED_BUILD_DIR", because that directory can contain >50k
files, and in debug mode listing files (even if all are excluded)
would take a second.
Ref: https://github.com/fish-shell/fish-shell/pull/12103#issuecomment-3592280477
This should also fix#12120.
Multiple gettext-extraction proc macro instances can run at the same
time due to Rust's compilation model. In the previous implementation,
where every instance appended to the same file, this has resulted in
corruption of the file. This was reported and discussed in
https://github.com/fish-shell/fish-shell/pull/11928#discussion_r2488047964
for the equivalent macro for Fluent message ID extraction. The
underlying problem is the same.
The best way we have found to avoid such race condition is to write each
entry to a new file, and concatenate them together before using them.
It's not a beautiful approach, but it should be fairly robust and
portable.
Closes#12125
This eliminates the proc-macro panic occasionally observed in CI,
instead ignoring paths which cannot be canonicalized.
See #12120.
While this does not address the underlying issue of why the proc-macro
fail happens, it should result in builds no longer failing, and since
they failed in the case where no embedding is desired, there should be
no issue with ignoring failed path canonicalization, since we do not
want to embed anything in these cases.
The old approach does not properly protect from concurrent tests
accessing the same tempdir. Fix this by moving to the new tempfile
functionality. This also eliminates the need to explicitly create and
delete the directory. There is also no longer a reason to specify names
for the temporary directories, since name collisions are avoided using
more robust means, and there is little benefit to having the names in
the directory name.
Closes#12030
The `mkstemp` function opens files without setting `O_CLOEXEC`. We could
manually set this using `fnctl` once the file is opened, but that has
the issue of introducing race conditions. If fish `exec`s in another
thread before the `fnctl` call completes, the file would be left open.
One way of mitigating this is `mkostemp`, but that function is not
available on all systems fish supports, so we can't rely on it.
Instead, build our own tempfile creation logic which uses the `rand`
crate for getting entropy and relies on Rust's stdlib for the rest.
The stdlib functions we use set `O_CLOEXEC` by default.
For directory creation we keep using `mkdtemp`, since there we don't
open anything. We could replace this by extending our custom logic a
bit, which would allow us to drop the `nix` dependency for our
`tempfile` crate, but since the code is simpler as it is now and we need
nix in fish's main crate, there is no need to modify the directory
creation code.
Part of #12030
`SmallRng` was chosen in part due to limitation of old macOS versions.
This is no longer relevant, since the affected versions are not
supported by Rust anymore.
Switch everything which does not need fixed sequences based on a seed to
`ThreadRng`, which has better cryptographic properties and is
occasionally reseeded. Performance differences should not matter much,
since initialization of `ThreadRng` is not that expensive and it's
generation speed is easily fast enough for our purposes.
In some cases, like tests and the `random` builtin, we want a PRNG which
consistently produces the same sequence of values for a given seed.
`ThreadRng` does not do this, since it is occasionally reseeded
automatically. In these cases, we keep using `SmallRng`.
Part of #12030
Function names containing `gen` have been deprecated to avoid conflicts
with the Rust 2024 keyword, so this commit also switches to the new
names.
Part of #12030
Since we changed our MSRV to 1.85, macOS < 10.12 is no longer supported,
so the comment removed here is no longer relevant.
The workaround for old macOS was introduced in
9337c20c2 (Stop using the getrandom feature of the rand crate, 2024-10-07)
We might want to reconsider which RNGs and other features of the `rand`
crate we use, but there is no immediate need to do so, since the current
approach seems to have worked well enough.
Part of #12030
As discussed in #12112, this is a false friend (the libc logb()
does something else), and without keyword arguments or at least
function overloading, this is hard to read.
Better use "/ log(base)" trick.
The old handling of Unicode escape sequences seems partially obsolete
and unnecessarily complicated. For our purposes, Rust's u32 to char
parsing should be exactly what we want.
Due to fish treating certain code points specially, we need to check
if the provided character is among the special chars, and if so we need
to encode it using our PUA scheme. This was not done in the old code,
but is now.
Add tests for this.
Fixes#12081
Rework the error message for invalid code points.
The old message about invalid code points not yet being supported seems
odd. I don't think we should support this, so stop implying that we
might do so in the future.
In the new code, indicating that a Unicode character is
out of range is also not ideal, since the range is not contiguous.
E.g. `\uD800` is invalid, but \U0010FFFF is valid.
Refrain from referring to a "range" and instead just state that the
character is invalid.
Move formatting of the escape sequence into Rust's `format!` to simplify
porting to Fluent.
Closes#12118
While it's not necessary to rebuild the proc macro for extraction when
the env var controlling the output location changes, this way everything
using the macro will automatically be rebuilt when this env var changes,
making it impossible to forget adding this to other `build.rs` files.
For now, keeping the rebuild instructions in fish's main crate's
`build.rs` would be fine as well, but if we start breaking this crate
into smaller parts, it would become annoying to add the rebuild command
in every crate depending on gettext extraction.
Closes#12107
There was a mismatch between the extraction done from
`build_tools/check.sh` and the one done in
`build_tools/fish_xgettext.fish`, resulting in messages guarded by
default features being extracted by the former but not the latter.
This brings them in sync.
Ideally, we would enable all features for extraction, but compiling with
`--all-features` is broken and manually keeping the features lists
updated is tedious and error prone, so we'll settle on only using
default features for now.
Closes#12103
Improve separation of concerns by handling catalog lookup in the
`gettext_impl` module, while taking care of string interning and string
type conversion in the outer `gettext` function as before.
This improves isolation, meaning we no longer have to expose the
catalogs from `gettext_impl` to its parent module.
It also helps with readability.
Part of #12102
Modify the `str_enum!` macro to be able to handle multiple strings per
enum variant. This means that no separate step is required for defining
the enum. Instead definition of the enum and implementation of the
string conversion functions is now combined into a single macro
invocation, eliminating code duplication, as well as making it easier to
add and identify aliases for an enum variant.
Closes#12101
This seems to be a left-over detail from the C++ version. Setting the
first element to 0 does not have any effect, since that's the default,
and setting it to 1 seems to serve no purpose in the current code.
Part of #12101
There is no difference in how these two variants are treated. Keeping
the old command name around for compatibility is nice, but it does not
need to have its own enum variant.
Part of #12101
The -n flag adds warnings about preexisting problems because we don't
check it in CI, so let's not recommend that.
Not everyone uses cmake but it's still the source of truth for docs,
so mention the cmake incantation. Though it seems like the direct
sphinx-build invocation works just fine, so keep it first.
Commit 0893134543 (Added .editorconfig file (#3332) (#3313),
2016-08-25) trimmed trailing whitespace for Markdown file (which do
have significant trailing whitespace) but ReStructuredText does not,
and none of our Markdown files cares about this, so let's clean up
whitespace always.
This message is no longer used since we unconditionally embed files now.
The `#[allow(dead_code)]` annotation was needed to avoid warnings while
ensuring that message extraction was not broken.
Closes#12099
Completions for "foo bar=baz" are sourced from
1. file paths (and custom completions) where "bar=baz" is a subsequence.
2. file paths where "baz" is a subsequence.
I'm not sure if there is ever a case where 1 is non-empty and we
still want to show 2.
Bravely include this property in our completion ranking, and only
show the best ones.
This enables us to get rid of the hack added by b6c249be0c (Back out
"Escape : and = in file completions", 2025-01-10).
Closes#5363
This is another case where we can don't need to use complicated
formatting specifiers. There is also no need to use `wgettext_fmt` for
messages which don't contain any localizable parts.
The instances using `sprintf` could be kept as is, but I think it's
better to keep the width computation at the place where it can sensibly
be done, even though it is not done correctly at the moment because it
does not use grapheme widths.
Removing complicated conversion specifiers from localized messages helps
with the transition to Fluent.
Closes#12119
We already compute the length of the substring we want to print in Rust.
Passing that length as the precision to let printf formatting limit the
length is brittle, as it requires that the same semantics for "length"
are used.
Simplifying conversion specifiers also makes the transition to Fluent
easier.
Part of #12119
The newly added `cargo deny check licenses` command complains about the
licenses added in this commit not being explicitly allowed, so add them
to the config here. There is no intended change in semantics.
Closes#12097
As mentioned in https://github.com/fish-shell/fish-shell/issues/12055#issuecomment-3554869126
> instances of `/bin/sh` as freestanding commands within `.fish`
> files are most likely not automatically handled by `termux-exec`
and
> This topic is complicated by the fact that some Android ROMs _do_
> contain real `/bin/sh` files
Core uses /system/bin/sh on Android. Let's do the same from script
(even if /bin/sh exists), for consistency.
For paths embedded via `rust-embed`, we only need to rebuild on path
changes if the files are actually embedded.
To avoid having to remember and duplicate this logic for all embedded
paths, extract it into the build helper.
Closes#12083
Commit 0709e4be8b (Use standalone code paths by default, 2025-10-26)
mainly wanted to embed internal functions to unbreak upgrade scenarios.
Embedding man pages in CMake has small-ish disadvantages:
1. extra space usage
2. less discoverability
3. a "cyclic" dependency:
1. "sphinx-docs" depends on "fish_indent"
2. "fish_indent" via "crates/build-man-pages" depends on "doc_src/".
So every "touch doc_src/foo.rst && ninja -Cbuild sphinx-docs"
re-builds fish, just to re-run sphinx-build.
The significant one is number 3. It can be worked around by running
sphinx-build with stale "fish_indent" but I don't think we want to
do that.
Let's backtrack a little by stopping embedding man pages in CMake
builds; use the on-disk man pages (which we still install).
The remaining "regression" from 0709e4be8b is that "ninja -Cbuild
fish" needs to rebuild whenever anything in "share/" changes. I don't
know if that's also annoying?
Since man pages for "build/fish" are not in share/, expose the exact
path as $__fish_man_dir.
When $RELOCATED_PREFIX/bin/fish detects that
$RELOCATED_PREFIX/share/fish and $RELOCATED_PREFIX/etc/fish exist,
it uses paths from $RELOCATED_PREFIX (which is determined at runtime,
based on $argv), and not the prefix determined at compile time.
Except we do use DOCDIR (= ${CMAKE_INSTALL_FULL_DOCDIR}). This
seems like a weird side effect of commit b758c0c335 (Relax the
requirement that we find a working 'doc' directory in order for fish
to be relocatable. 2014-01-17) which enabled relocatable logic in
scenarios where $PREFIX/share/doc/fish was not installed.
This is weird; fish's "help" command should not take docs from a
different prefix.
Always use the matching docdir. This shouldn't make any practical
difference because since commit b5aea3fd8b (Revert "[cmake] Fix
installing docs", 2018-03-13), $PREFIX/share/doc/fish/CHANGELOG.rst
is always installed.
The help_sections.rs file was added to the tarball only as a quick hack.
There is a cyclic dependency between docs and fish:
"fish_indent" via "crates/build-man-pages" depends on "doc_src/".
So every "touch doc_src/foo.rst && ninja -Cbuild sphinx-docs"
re-builds fish.
In future "fish_indent" should not depend on "crates/build-man-pages".
Until then, a following commit wants to break this cyclic dependency
in a different way: we won't embed man pages (matching historical
behavior), which means that CMake builds won't need to run
sphinx-build.
But sphinx-build is also used for extracting help sections.
Also, the fix for #12082 will use help sections elsewhere in the code.
Prepare to remove the dependency on doc_src by committing the help
sections (we already do elsewhere).
This mode still has some problems (see the next commit) but having
it behind a feature flag doesn't serve us. Let's commit to the parts
we want to keep and drop anything that we don't want.
To reduce diff noise, use "if false" in the code paths used by man
pages; a following commit will use them.
macOS has en_US.UTF-8 but not C.UTF-8, which leads to a glitch when
typing "🐟". Fix that by trying the user's locale first, restoring
historical behavior.
Fixes 71a962653d (Be explicit about setlocale() scope, 2025-10-24).
Reported-by: Ilya Grigoriev <ilyagr@users.noreply.github.com>
When running fish inside SSH and local and remote OS differ, fish
uses key bindings for the remote OS, which is weird. Fix that by
asking the terminal for the OS name.
This should be available on foot and kitty soon, see
https://codeberg.org/dnkl/foot/pulls/2217#issuecomment-8249741
Ref: #11107
iTerm2 displays commands in other UI widgets such as in Command History
(View → Toolbelt → Command History). This needs prompt end marker
so the terminal can distinguish prompt from the command line.
Closes#11837
Historically, "fish_color_*" variables used a hand-written option
parser that would try to recover from invalid options.
Commit 037c1896d4 (Reuse wgetopt parsing for set_color for internal
colors, 2025-04-13) tried to preserve this recovering, but that
breaks WGetopter invariants.
I don't think this type of fallback is important, because
there's no reason we can't parse color variables (except maybe
forward-compatibility in future). Let's turn errors into the default
style; this should tell the user that their color is unsupported.
Fixes#12078
For historical reasons, fish does not implement the VT state
machine but uses a relatively low timeout when reading
escape sequences. This might be causing issues like
https://github.com/fish-shell/fish-shell/issues/11841#issuecomment-3544505235
so let's cautiously increase the timeout.
Make it opt-in and print a noisy error when we time out, so we can
find affected terminals.
We've removed several terminal-specific workarounds but also added
some recently. Most of the non-Apple issues have been reported
upstream. Many of our workarounds were only meant to be temporary.
Some workarounds are unreliable and some can cause introduce other
problems.
Add a feature flag we can use later to let users turn off workarounds.
This doesn't disable anything yet, mostly because because despite being
off-by-default, this might surprise people who use "fish_features=all".
The fix would be "fish_features=all,no-omit-term-workarounds".
So we'd want a high degree of confidence.
For now we'll use this only with the next commit.
Closes#11819
Commit 3f2e4b71bc (functions/__fish_print_help: bravely remove
fallback to mandoc/groff, 2025-11-09) savagely made commands like
"abbr -h" require man, or else it prints a noisy stack trace.
Some packages have not yet replaced "nroff/mandoc" with "man"
as dependency, and, independent of that, man is still an optional
dependency.
Make missing "man" a proper error, which is easier to read tan the
stack trace.
Use \e\\ as sequence terminator for the first OSC 133 prompt start
marker. The intention is to find out if a terminal fails to parse
this. If needed, the user can turn it off by adding "no-mark-prompt"
to their feature flags; but the shell is still usable without this.
Part of #12032
For now, we mostly use "/bin/sh" for background tasks; but sometimes
we call it as "sh". The former does not work on android, but I'm not
yet sure how we should fix that.
Let's make things consistent first, so they are easier to change
(we might remove some background tasks, or reimplement them in fish
script).
We always use python3 but don't use, say python3.999 until we update
our hardcoded list. This is inconsistent (we're careful about the
latter but not the former). Fix this by always picking the highest
minor version (>= 3.5+) there is. This also reduces maintenance work.
Note that NetBSD is the only OS we know about that doesn't provide
the python3 symlink OOTB. In future, the NetBSD package should
add a patch to replace "python3" in __fish_anypython.fish
with the correct path. Downstream discussion is at
https://mail-index.netbsd.org/pkgsrc-users/2025/11/17/msg042205.html
As mentioned in
https://github.com/fish-shell/fish-shell/issues/11921#issuecomment-3540587001,
binaries duplicate a lot of information unnecessarily.
$ cargo b --release
$ du -h target/release/fish{,_indent,_key_reader}
15M target/release/fish
15M target/release/fish_indent
4.1M target/release/fish_key_reader
34M total
Remove the duplication in CMake-installed builds by creating hard
links. I'm not sure how to do that for Cargo binaries yet (can we
write a portable wrapper script)?
This is still a bit weird because hardlinks are rarely used like
this; but symlinks may cause issues on MSYS2. Maybe we should write
a /bin/sh wrapper script instead.
This might help cross-compilation; even if it doesn't matter in
practice, this is more correct. While at it, get rid of $TARGET in
favor of the more accurate $CARGO_CFG_TARGET_OS.
Not yet sure how to do it for "has_small_stack".
Frequently when I launch a new shell and type away, my input is
echoed in the terminal before fish gets a chance to set shell modes
(turn off ECHO and put the terminal into non-canonical mode).
This means that fish assumption about the cursor x=0 is wrong, which
causes the prompt (here '$ ') to be draw at the wrong place, making
it look like this:
ececho hello
This seems to have been introduced in 4.1.0 in a0e687965e (Fix
unsaved screen modification, 2025-01-14). Not sure how it wasn't a
problem before.
Fix this by clearing to the beginning of the line after turning off
ECHO but before we draw anything to the screen.
This turns this comment in the patch context into a true statement:
> This means that `printf %s foo; fish` will overwrite the `foo`
Note that this currently applies per-reader, so builtin "read" will
also clear the line before doing anything.
We could potentially change this in future, if we both
1. query the cursor x before we output anything
2. refactor the screen module to properly deal with x>0 states.
But even if we did that, it wouldn't change the fact that we want
to force x=0 if the cursor has only been moved due to ECHO, so I'm
not sure.
Adds [`Vermin`](https://github.com/netromdk/vermin) to make sure our
user facing Python scripts conform to the proper minimum Python version
requirements.
The tool parses Python code into an AST and checks it against a database
of rules covering Python 2.0-3.13.
Testing Python version compatibility is tricky because most issues only
show up at runtime. Type annotations like `str | None` (Python 3.10+)
compile just fine (under pyc) and they don't throw an exception until
you actually call the relevant function.
This makes it hard to catch compatibility bugs without running the code
(through all possible execution paths) on every Python version.
Signed-off-by: seg6 <hi@seg6.space>
Closes#12044
Issue #11933 stems from Cygwin's flock implementation not being thread
safe. Previous code fixed the worst behavior (deadlock), at least in
some circumstance but still failed the history tests.
This new workaround correctly make flock usage thread safe by surrounding
it with a mutex lock.
The failing test can now pass and is much faster (5s instead of 15 on
my machine)
Upstream bug report: https://cygwin.com/pipermail/cygwin/2025-November/258963.htmlCloses#12068Closes#11933
As discovered in #12062, man-db as installed from brew is not affected
by the "read-only-filesystem" problem what makewhatis suffers from
(though users do need to run "gmandb" once).
Restrict the workaround to the path to macOS's apropos; hopefully
that's stable.
This breaks people who define an alias for apropos; I guess for those
we could check "command -v" instead, but that's weird because the thing
found by type is the actual thing we're gonna execute. So I'd first
rather want to find out why anyone would override this obscure command.
In POSIX sh, ";" is not a valid statement, leading to errors when the
__fish_cached callback argument has a trailing newline (5c2073135e
(Fix syntax error in __fish_print_port_packages.fish, 2025-11-14)).
Use a newline instead of ";", to avoid this error.
While at it, replace rogue tab characters.
`grep -Fx` will match fixed strings over the entire line.
`status list-files foo` will match anything that starts with "foo".
Since we always pass a suffix here, that's the same thing.
If we really cared, we could do `string match "*.$suffix"` or similar.
Fixes#12060
- History is no longer corrupted with NUL bytes when fish receives SIGTERM or SIGHUP (:issue:`10300`).
-``fish_update_completions`` now handles groff ``\X'...'`` device control escapes, fixing completion generation for man pages produced by help2man 1.50 and later (such as coreutils 9.10).
For distributors and developers
-------------------------------
- When the default global config directory (``$PREFIX/etc/fish``) exists but has been overridden with ``-DCMAKE_INSTALL_SYSCONFDIR``, fish will now respect that override (:issue:`10748`).
Regression fixes:
-----------------
fish 4.6.0 (released March 28, 2026)
====================================
Notable improvements and fixes
------------------------------
- New Spanish translations (:issue:`12489`).
- New Japanese translations (:issue:`12499`).
Deprecations and removed features
---------------------------------
- The default width for emoji is switched from 1 to 2, improving the experience for users connecting to old systems from modern desktops. Users of old desktops who notice that lines containing emoji are misaligned can set ``$fish_emoji_width`` back to 1 (:issue:`12562`).
Interactive improvements
------------------------
- The tab completion pager now left-justifies the description of each column (:issue:`12546`).
- fish now supports the ``SHELL_PROMPT_PREFIX``, ``SHELL_PROMPT_SUFFIX``, and ``SHELL_WELCOME`` environment variables. The prefix and suffix are automatically prepended and appended to the left prompt, and the welcome message is displayed on startup after the greeting.
These variables are set by systemd's ``run0`` for example (:issue:`10924`).
Improved terminal support
-------------------------
-``set_color`` is able to turn off italics, reverse mode, strikethrough and underline individually (e.g. ``--italics=off``).
-``set_color`` learned the foreground (``--foreground`` or ``-f``) and reset (``--reset``) options.
- An error caused by slow terminal responses at macOS startup has been addressed (:issue:`12571`).
Other improvements
------------------
- Signals like ``SIGWINCH`` (as sent on terminal resize) no longer interrupt builtin output (:issue:`12496`).
- For compatibility with Bash, fish now accepts ``|&`` as alternate spelling of ``&|``, for piping both standard output and standard error (:issue:`11516`).
-``fish_indent`` now preserves comments and newlines immediately preceding a brace block (``{ }``) (:issue:`12505`).
- A crash when suspending certain pipelines with :kbd:`ctrl-z` has been fixed (:issue:`12301`).
For distributors and developers
-------------------------------
-``cargo xtask`` subcommands no longer panic on test failures.
Regression fixes:
-----------------
- (from 4.5.0) Intermediate ``⏎`` artifact when redrawing prompt (:issue:`12476`).
- (from 4.4.0) ``history`` honors explicitly specified ``--color=`` again (:issue:`12512`).
- (from 4.4.0) Vi mode ``dl`` and ``dh`` (:issue:`12461`).
- (from 4.3.0) Error completing of commands starting with ``-`` (:issue:`12522`).
fish 4.5.0 (released February 17, 2026)
=======================================
This is mostly a patch release for Vi mode regressions in 4.4.0 but other minor behavior changes are included as well.
Interactive improvements
------------------------
-:kbd:`ctrl-l` no longer cancels history search (:issue:`12436`).
- History search cursor positioning now works correctly with characters of arbitrary width.
Deprecations and removed features
---------------------------------
- fish no longer reads the terminfo database to alter behaviour based on the :envvar:`TERM` environment variable, and does not depend on ncurses or terminfo. The ``ignore-terminfo`` feature flag, introduced and enabled by default in fish 4.1, is now permanently enabled. fish may no longer work correctly on Data General Dasher D220 and Wyse WY-350 terminals, but should continue to work on all known terminal emulators released in the 21st century.
Regression fixes:
-----------------
- (from 4.4.0) Vi mode ``d,f`` key binding did not work (:issue:`12417`).
- (from 4.4.0) Vi mode crash on ``c,i,w`` after accepting autosuggestion (:issue:`12430`).
- (from 4.4.0) ``fish_vi_key_bindings`` called with a mode argument produced an error (:issue:`12413`).
- (from 4.0.0) Build on Illumos (:issue:`12410`).
fish 4.4.0 (released February 03, 2026)
=======================================
Deprecations and removed features
---------------------------------
- The default fossil prompt has been disabled (:issue:`12342`).
Interactive improvements
------------------------
- The ``bind`` builtin lists mappings from all modes if ``--mode`` is not provided (:issue:`12214`).
- Line-wise autosuggestions that don't start a command are no longer shown (739b82c34db, 58e7a50de8a).
- Builtin ``history`` now assumes that :envvar:`PAGER` supports ANSI color sequences.
- fish now clears the terminal's ``FLUSHO`` flag when acquiring control of the terminal, to fix an issue caused by pressing :kbd:`ctrl-o` on macOS (:issue:`12304`).
New or improved bindings
------------------------
- Vi mode word movements (``w``, ``W``, ``e``, and ``E``) are now largely in line with Vim. The only exception is that underscores are treated as word separators (:issue:`12269`).
- New special input functions to support these movements: ``forward-word-vi``, ``kill-word-vi``, ``forward-bigword-vi``, ``kill-bigword-vi``, ``forward-word-end``, ``backward-word-end``, ``forward-bigword-end``, ``backward-bigword-end``, ``kill-a-word``, ``kill-inner-word``, ``kill-a-bigword``, and ``kill-inner-bigword``.
- Vi mode key bindings now support counts for movement and deletion commands (e.g. `d3w` or `3l`), via a new operator mode (:issue:`2192`).
- New ``catppuccin-*`` color themes.
Improved terminal support
-------------------------
-``set_color`` learned the strikethrough (``--strikethrough`` or ``-s``) modifier.
For distributors and developers
-------------------------------
- The CMake option ``WITH_GETTEXT`` has been renamed to ``WITH_MESSAGE_LOCALIZATION``, to reflect that it toggles localization independently of the backend used in the implementation.
- New ``cargo xtask`` commands can replace some CMake workflows.
Regression fixes:
-----------------
- (from 4.1.0) Crash when autosuggesting Unicode characters with nontrivial lowercase mapping (:issue:`12326`, 78f4541116e).
- (from 4.3.0) Glitch on ``read --prompt-str ""`` (:issue:`12296`).
fish 4.3.3 (released January 07, 2026)
======================================
This release fixes the following problems identified in fish 4.3.0:
- Selecting a completion could insert only part of the token (:issue:`12249`).
- Glitch with soft-wrapped autosuggestions and :doc:`fish_right_prompt <cmds/fish_right_prompt>` (:issue:`12255`).
- Spurious echo in tmux when typing a command really fast (:issue:`12261`).
-``tomorrow`` theme always using the light variant (:issue:`12266`).
-``fish_config theme choose`` sometimes not shadowing themes set by e.g. webconfig (:issue:`12278`).
- The sample prompts and themes are correctly installed (:issue:`12241`).
- Last line of command output could be hidden when missing newline (:issue:`12246`).
Other improvements include:
- The ``abbr``, ``bind``, ``complete``, ``functions``, ``history`` and ``type`` commands now support a ``--color`` option to control syntax highlighting in their output. Valid values are ``auto`` (default), ``always``, or ``never``.
- Existing file paths in redirection targets such as ``> file.txt`` are now highlighted using :envvar:`fish_color_valid_path`, indicating that ``file.txt`` will be clobbered (:issue:`12260`).
fish 4.3.2 (released December 30, 2025)
=======================================
This release fixes the following problems identified in 4.3.0:
- Pre-built macOS packages failed to start due to a ``Malformed Mach-O file`` error (:issue:`12224`).
-``extra_functionsdir`` (usually ``vendor_functions.d``) and friends were not used (:issue:`12226`).
- Sample config file ``~/.config/fish/config.fish/`` and config directories ``~/.config/fish/conf.d/``, ``~/.config/fish/completions/`` and ``~/.config/fish/functions/`` were recreated on every startup instead of only the first time fish runs on a system (:issue:`12230`).
- Spurious echo of ``^[[I`` in some scenarios (:issue:`12232`).
- Infinite prompt redraw loop on some prompts (:issue:`12233`).
- The removal of pre-built HTML docs from tarballs revealed that cross compilation is broken because we use ``${CMAKE_BINARY_DIR}/fish_indent`` for building HTML docs.
As a workaround, the new CMake build option ``FISH_INDENT_FOR_BUILDING_DOCS`` can be set to the path of a runnable ``fish_indent`` binary.
fish 4.3.1 (released December 28, 2025)
=======================================
This release fixes the following problem identified in 4.3.0:
- Possible crash after expanding an abbreviation (:issue:`12223`).
fish 4.3.0 (released December 28, 2025)
=======================================
Deprecations and removed features
---------------------------------
- fish no longer sets user-facing :ref:`universal variables <variables-universal>` by default, making the configuration easier to understand.
Specifically, the ``fish_color_*``, ``fish_pager_color_*`` and ``fish_key_bindings`` variables are now set in the global scope by default.
After upgrading to 4.3.0, fish will (once and never again) migrate these universals to globals set at startup in the
``~/.config/fish/conf.d/fish_frozen_theme.fish`` and
We suggest that you delete those files and :ref:`set your theme <syntax-highlighting>` in ``~/.config/fish/config.fish``.
- You can still configure fish to propagate theme changes instantly; see :ref:`here <syntax-highlighting-instant-update>` for an example.
- You can still opt into storing color variables in the universal scope
via ``fish_config theme save`` though unlike ``fish_config theme choose``,
it does not support dynamic theme switching based on the terminal's color theme (see below).
- In addition to setting the variables which are explicitly defined in the given theme,
``fish_config theme choose`` now clears only color variables that were set by earlier invocations of a ``fish_config theme choose`` command
(which is how fish's default theme is set).
Scripting improvements
----------------------
- New :ref:`status language <status-language>` command allows showing and modifying language settings for fish messages without having to modify environment variables.
- When using a noninteractive fish instance to compute completions, ``commandline --cursor`` works as expected instead of throwing an error (:issue:`11993`).
-:envvar:`fish_trace` can now be set to ``all`` to also trace execution of key bindings, event handlers as well as prompt and title functions.
Interactive improvements
------------------------
- When typing immediately after starting fish, the first prompt is now rendered correctly.
- Completion accuracy was improved for file paths containing ``=`` or ``:`` (:issue:`5363`).
- Prefix-matching completions are now shown even if they don't match the case typed by the user (:issue:`7944`).
- On Cygwin/MSYS, command name completion will favor the non-exe name (``foo``) unless the user started typing the extension.
- When using the exe name (``foo.exe``), fish will use the description and completions for ``foo`` if there are none for ``foo.exe``.
- Autosuggestions now also show soft-wrapped portions (:issue:`12045`).
New or improved bindings
------------------------
-:kbd:`ctrl-w` (``backward-kill-path-component``) also deletes escaped spaces (:issue:`2016`).
- New special input functions ``backward-path-component``, ``forward-path-component`` and ``kill-path-component`` (:issue:`12127`).
Improved terminal support
-------------------------
- Themes can now be made color-theme-aware by including both ``[light]`` and ``[dark]`` sections in the :ref:`theme file <fish-config-theme-files>`.
Some default themes have been made color-theme-aware, meaning they dynamically adjust as your terminal's background color switches between light and dark colors (:issue:`11580`).
- The working directory is now reported on every fresh prompt (via OSC 7), fixing scenarios where a child process (like ``ssh``) left behind a stale working directory (:issue:`12191`).
- OSC 133 prompt markers now also mark the prompt end, which improves shell integration with terminals like iTerm2 (:issue:`11837`).
- Operating-system-specific key bindings are now decided based on the :ref:`terminal's host OS <status-terminal-os>`.
- New :ref:`feature flag <featureflags>```omit-term-workarounds`` can be turned on to prevent fish from trying to work around some incompatible terminals.
For distributors and developers
-------------------------------
- Tarballs no longer contain prebuilt documentation,
so building and installing documentation requires Sphinx.
To avoid users accidentally losing docs, the ``BUILD_DOCS`` and ``INSTALL_DOCS`` configuration options have been replaced with a new ``WITH_DOCS`` option.
-``fish_key_reader`` and ``fish_indent`` are now installed as hardlinks to ``fish``, to save some space.
Regression fixes:
-----------------
- (from 4.1.0) Crash on incorrectly-set color variables (:issue:`12078`).
- (from 4.1.0) Crash when autosuggesting Unicode characters with nontrivial lowercase mapping.
- (from 4.2.0) Incorrect emoji width computation on macOS.
- (from 4.2.0) Mouse clicks and :kbd:`ctrl-l` edge cases in multiline command lines (:issue:`12121`).
- (from 4.2.0) Completions for Git remote names on some non-glibc systems.
- (from 4.2.0) Expansion of ``~$USER``.
fish 4.2.1 (released November 13, 2025)
=======================================
@@ -102,15 +331,13 @@ This release fixes the following regressions identified in 4.1.0:
This will not affect fish's child processes unless ``LC_MESSAGES`` was already exported.
- Some :doc:`fish_config <cmds/fish_config>` subcommands for showing prompts and themes had been broken in standalone Linux builds (those using the ``embed-data`` cargo feature), which has been fixed (:issue:`11832`).
- On Windows Terminal, we observed an issue where fish would fail to read the terminal's response to our new startup queries, causing noticeable lags and a misleading error message. A workaround has been added (:issue:`11841`).
- On Windows Terminal, we observed an issue where fish would fail to read the terminal's response to our new startup queries, causing noticeable lags and a misleading error message. A workaround has been added (:issue:`11841`).
- A WezTerm `issue breaking shifted key input <https://github.com/wezterm/wezterm/issues/6087>`__ has resurfaced on some versions of WezTerm; our workaround has been extended to cover all versions for now (:issue:`11204`).
- Fixed a crash in :doc:`the web-based configuration tool <cmds/fish_config>` when using the new underline styles (:issue:`11840`).
- using the `installer from fishshell.com <https://fishshell.com/>`__
- as a `standalone app from fishshell.com <https://fishshell.com/>`__
Note: The minimum supported macOS version is 10.10 "Yosemite".
Note: The minimum supported macOS version is 10.12.
Packages for Linux
~~~~~~~~~~~~~~~~~~
@@ -117,7 +117,7 @@ Dependencies
Compiling fish requires:
- Rust (version 1.85 or later)
- Rust (version 1.85 or later), including cargo
- CMake (version 3.15 or later)
- a C compiler (for system feature detection and the test helper binary)
- PCRE2 (headers and libraries) - optional, this will be downloaded if missing
@@ -157,11 +157,14 @@ In addition to the normal CMake build options (like ``CMAKE_INSTALL_PREFIX``), f
- Rust_COMPILER=path - the path to rustc. If not set, cmake will check $PATH and ~/.cargo/bin
- Rust_CARGO=path - the path to cargo. If not set, cmake will check $PATH and ~/.cargo/bin
- Rust_CARGO_TARGET=target - the target to pass to cargo. Set this for cross-compilation.
-BUILD_DOCS=ON|OFF - whether to build the documentation. This is automatically set to OFF when Sphinx isn't installed.
-INSTALL_DOCS=ON|OFF - whether to install the docs. This is automatically set to on when BUILD_DOCS is or prebuilt documentation is available (like when building in-tree from a tarball).
-WITH_DOCS=ON|OFF - whether to build the documentation. By default, this is ON when Sphinx is installed.
-FISH_INDENT_FOR_BUILDING_DOCS - useful for cross-compilation.
Set this to the path to the ``fish_indent`` executable to use for building HTML docs.
By default, ``${CMAKE_BINARY_DIR}/fish_indent`` will be used.
If that's not runnable on the compile host,
you can build a native one with ``cargo build --bin fish_indent`` and set this to ``$PWD/target/debug/fish_indent``.
- FISH_USE_SYSTEM_PCRE2=ON|OFF - whether to use an installed pcre2. This is normally autodetected.
-MAC_CODESIGN_ID=String|OFF - the codesign ID to use on Mac, or "OFF" to disable codesigning.
- WITH_GETTEXT=ON|OFF - whether to include translations.
-WITH_MESSAGE_LOCALIZATION=ON|OFF - whether to include translations.
- extra_functionsdir, extra_completionsdir and extra_confdir - to compile in an additional directory to be searched for functions, completions and configuration snippets
Building fish with Cargo
@@ -185,13 +188,14 @@ You can also install Sphinx another way and drop the ``uv run --no-managed-pytho
This will place standalone binaries in ``~/.cargo/bin/``, but you can move them wherever you want.
To disable translations, disable the ``localize-messages`` feature by passing ``--no-default-features --features=embed-data`` to cargo.
To disable translations, disable the ``localize-messages`` feature by passing ``--no-default-features --features=embed-manpages`` to cargo.
You can also link this build statically (but not against glibc) and move it to other computers.
Here are the remaining advantages of a full installation, as currently done by CMake:
- Man pages like ``fish(1)`` installed in standard locations, easily accessible from outside fish.
- Separate files for builtins (e.g. ``$PREFIX/share/fish/man/man1/abbr.1``).
- A local copy of the HTML documentation, typically accessed via the ``help`` fish function.
In Cargo builds, ``help`` will redirect to `<https://fishshell.com/docs/current/>`__
- Ability to use our CMake options extra_functionsdir, extra_completionsdir and extra_confdir,
/// This must be configurable because the value changed between Unicode 8 and Unicode 9, `wcwidth()`
/// is emoji-unaware, and terminal emulators do different things.
///
/// See issues like [#4539](https://github.com/fish-shell/fish-shell/issues/4539) and <https://github.com/neovim/neovim/issues/4976> for how painful this is.
///
/// Valid values are 1, and 2. 1 is the typical emoji width used in Unicode 8 while some newer
/// terminals use a width of 2 since Unicode 9.
// For some reason, this is declared here and exposed here, but is set in `env_dispatch`.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.