- 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