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
Historically, Sphinx was required when building "standalone" builds,
else they would have no man pages.
This means that commit 0709e4be8b (Use standalone code paths by
default, 2025-10-26) broke man pages for users who build from a
tarball where non-standalone builds would use prebuilt docs.
Add a hack to use prebuilt docs again.
In future, we'll remove prebuilt docs, see #12052.
Looks like macOS packages didn't have docs??
I noticed via our Cargo warning about sphinx-build.
macOS has a variety of pythons installed:
bash-3.2$ type -a python python3
python is /Library/Frameworks/Python.framework/Versions/Current/bin/python
python3 is /opt/homebrew/bin/python3
python3 is /usr/local/bin/python3
python3 is /Library/Frameworks/Python.framework/Versions/Current/bin/python3
python3 is /usr/bin/python3
by default, "uv --no-managed-python" uses python3 (homebrew), but
"python" (and "pip") use the other one. Make uv use the same as
our scripts. Not all uv commands support "--python" today, so set
UV_PYTHON.
Use the pinned versions of Sphinx + dependencies, for reproducibility
and correctness. (Specifically, this gives us proper OSC 8
hyperlinks when /bin/sphinx-build is affected by a packaging bug,
see https://github.com/orgs/sphinx-doc/discussions/14048)
Ideally we want to credit reported-by/helped-by etc. but we'd need
to ask the GitHub API for this information.
Also we should use %(trailers) if possible.
HistoryIdentifier was an over-engineered way of annotating history items
with the paths that were found to be valid, for autosuggestion hinting.
It wasn't persisted to the file. Let's just get rid of this.
Use fstat() instead of lseek() to determine history file size.
Pass around the file_id instead of recomputing it.
This saves a few syscalls; no behavior change is expected.
Historically,
- our "man" wrapper prepends /usr/share/fish/man to $MANPATH
- "__fish_print_help" only operates on /usr/share/fish/man, to it
accesses that directly
However standalone builds -- where /usr/share/fish/man may not exist
-- have complicated things; we temporarily materialize a fake man
directory.
Reuse __fish_print_help instead of duplicating this.
Part of #12037
I don't know if anyone has installed mandoc/groff but not man.
Since 4.1 we officially require "man" as dependency (hope that works
out; we're missing some standardization, see #12037). Remove the
fallback with the old mandoc/nroff logic. This makes the next commit
slightly simpler -- which is not enough reason by itself, but we want
to do this anyway at some point.
We always try to prepend our man path to $MANPATH before calling man.
But this is not necessary when we're gonna display the output of
"status get-file man/man1/abbr.1".
Overriding man pages can cause issues like
https://github.com/fish-shell/fish-shell/issues/11472https://gitlab.com/man-db/man-db/-/merge_requests/15
which by themselves are maybe not enough reason to avoid exporting
MANPATH, but given that embedded man pages might become the only
choice in future (see #12037), we should reduce the scope of our
custom MANPATH.
These are code clones, apart from the fact that __fish_print_help
doesn't have the '{' case, because alt-h/f1 will never find that.
But adding it doesn't really hurt because it's unlikely that the user
will have a manpage for '{'. Extract a function.
These were added automatically when we used the `--strict` flag with
gettext commands. We stopped using this flag, but existing empty
comments are not automatically deleted, so it is done here manually.
Closes#12038
Also use the correct OSC number.
Note that this only works on few terminals (such as iTerm2). Not sure
if it's worth for us to have this feature but I guess multiple users
have requested it.
The section on build_tools/style.fish was stale. That tool does not
automagically format unstaged changes or the last commit's changes
anymore. Relying on such tools is bad practice anyway, people should
configure their editor to fix the style violations at the source.
Replace "before committing" with neutral phrasing.
Remove the redundant mention of "cargo fmt" and "clippy". Use of
clippy goes without saying for Rust projects. Instead, add another
mention of "build_tools/checks" which also does clippy as well as
translation update checks (which are commonly needed).
Drop the "testing with CMake" part since it's a legacy thing and
basically never needed, especially by new faces.
Use semantic line breaks in the paragraphs starting at "When in doubt".
- this is not specific to fish and only relevant to people who push
directly to master
- we don't push directly to master as often anymore
- I don't think we used it much in practice (when we should have).
- a good portion of contributions is pushed with jj which probably
does this differently
Let's remove it even though this is a nice piece of documentation.
I guess we could add it back to doc_internal/ if we have the capacity
to maintain it.
ja: the motivation for our own crate is
1. the tempfile crate is probably overkill for such a small
piece of functionality (given that we already assume Unix)
2. we want to have full control over the few temp files we
do create
Closes#12028
Since the parent commit, these tests fail repeatedly in macOS GitHub
Actions CI: complete-group-order.py, nullterm.py, scrollback.py and
set_color.py. They run fine in isolation.
We'll fix the flaky system tests soon (#11815) but until then, remove
parallelism from macOS CI.
Unlike other shells, fish tries to make it easy to work with multiline
commands. Arguably, it's often better to use a full text editor but
the shell can feel more convenient.
Spreading long commands into multiple lines can improve readability,
especially when there is some semantic grouping (loops, pipelines,
command substitutions, quoted parts). Note that in Unix shell, every
quoted string can span multiple lines, like Python's triple quotes,
so the barrier to writing a multiline command is quite low.
However these commands are not autosuggested. From
1c4e5cadf2 (commitcomment-150853293)
> the reason we don't offer multi-line autosuggestion is that they
> can cause the command line to "jump" to make room for the second
> and third lines, if you're at the bottom of your terminal.
This jumping (as done by nushell for example) might be surprising,
especially since there is no limit on the height of a command.
Let's maybe avoid this jumping by rendering only however many lines
from the autosuggestion can fit on the screen without scrolling.
The truncation is hinted at by a single ellipsis ("…") after the
last suggested character, just like when a single-line autosuggestion
is truncated. (We might want to use something else in future.)
To implement this, query for the cursor position after every command,
so we know the y-position of the shell prompt within the terminal
window (whose height we already know).
Also, after we register a terminal window resize, query for the cursor
position before doing anything else (until we od #12004, only height
changes are relevant), to prevent this scenario:
1. move prompt to bottom of terminal
2. reduce terminal height
3. increase terminal height
4. type a command that triggers a multi-line autosuggestion
5. observe that it would fail to truncate properly
As a refresher: when we fail to receive a query response, we always
wait for 2 seconds, except if the initial query had also failed,
see b907bc775a (Use a low TTY query timeout only if first query
failed, 2025-09-25).
If the terminal does not support cursor position report (which is
unlikely), show at most 1 line worth of autosuggestion. Note that
either way, we don't skip multiline commands anymore. This might make
the behavior worse on such terminals, which are probably not important
enough. Alternatively, we could use no limit for such terminals,
that's probably the better fallback behavior. The only reason I didn't
do that yet is to stay a little bit closer to historical behavior.
Storing the prompt's position simplifies scrollback-push and the mouse
click handler, which no longer need to query. Move some associated
code to the screen module.
Technically we don't need to query for cursor position if the previous
command was empty. But for now we do, trading a potential optimization
for andother simplification.
Disable this feature in pexpect tests for now, since those are still
missing some terminal emulation features.
I think the interruption event is grouped next to the check-exit one
because it used to be implemented as check exit but with a global flag
(I didn't check whether that applied to master).
Move it to the logical place.
The readline state is never finished before the very first loop
iteration. Move the check for rls.finished next to the one that
implements "read -n1" -- in future we might use the return value
for both.
For the same reason as before (upcoming multi-line autosuggestions),
reapply 1fdf37cc4a (__fish_echo: fully overwrite lines, 2025-09-17)
after it was reverted in b7fabb11ac (Make command run by __fish_echo
output to TTY for color detection, 2025-10-05)
(Make command run by __fish_echo output
to TTY for color detection, 2025-10-05). Use clear-to-end-of-screen
to allow making "ls" output directly to the terminal.
Alternatively, we could create a pseudo TTY (e.g. call something like
"unbuffer ls --color=auto").
Not sure if this will be useful but the fact that we use very
few Unicode characters, suggests that we are insecure about
this. Having some kind of central and explicit listing might help
future decision-making. Obviously, completions and translations use
more characters, but those are not as central.
Some modern terminals allow creating tabs in a single window;
this functionality has a lot of overlap with what a window manager
already provides, so I'm not sure if it's a good idea. Regardless,
a lot of people still use terminal tabs (or even multiple levels of
tabs via tmux!), so let's add a fish-native way to set the tab title
independent of the window title.
Closes#2692
Commit eecc223 (Recognize and disable mouse-tracking CSI events,
2021-02-06) made fish disable mouse reporting whenever we receive a
mouse event. This was because at the time we didn't have a parser
for mouse inputs. We do now, so let's allow users to toggle mouse
support with
printf '\e[?1000h'
printf '\e[?1000l'
Currently the only mouse even we support is left click (to move cursor
in commandline, select pager items).
Part of #4918
See #12026
[ja: tweak patch and commit message]
Since commit 7e3fac561d (Query terminal only just before reading
from it, 2025-09-25),
fish -c 'read; cat'
fails to turn ICANON back on for cat.
Even before that commit, I don't know how this ever worked. Before or
after, we'd call tcsetattr() only to set our shell modes, not the
ones for external commands (term_donate)
I also don't think there's a good reason why we set modes twice
(between term_donate () and old_modes), but I'll make a minimal (=
safer) change for now until I understand this.
The only change from 7e3fac561d was that instead of doing things in
this order:
terminal_init()
set_shell_modes
read
reader_push()
reader_readline()
save & restore old_modes
cat
we now do
read
reader_push()
terminal_init()
set_shell_modes()
reader_readline()
save & restore old_modes
cat
So we call set_shell_modes() just before saving modes,
which obviously makes us save the wrong thing.
Again, not sure how that wasn't a problem before.
Fix it by saving modes before calling terminal_init().
Fixes#12024
The new completions are like
help index#default-shell
Add a hack to use the "introduction" here.
Not sure if this is worth it but I guess we should be okay because
we at least have test for completions.
In future, we should find a better way to declare that "introduction"
is our landing page.
No need to define "cmd-foo" anchors; use :doc:`foo <cmds/foo>`
instead. If we want "cmd-foo" but it should be tested.
See also 38b24c2325 (docs: Use :doc: role when linking to commands,
2022-09-23).
functions/help and completions/help duplicate a lot of information
from doc_src. Get this information from Sphinx.
Drop short section titles such as "help globbing" in favor of the
full HTML anchor:
help language#wildcards-globbing
I think the verbosity is no big deal because we have tab completion,
we're trading in conciseness for consistency and better searchability.
In future, we can add back shorter invocations like "help globbing"
(especially given that completion descriptions often already repeated
the anchor path), but it should be checked by CI.
Also
- Remove some unused Sphinx anchors
- Remove an obsoleted script.
- Test that completions are in sync with Sphinx sources.
(note that an alternative would be to check
in the generated help_sections.rs file, see
https://internals.rust-lang.org/t/how-fail-on-cargo-warning-warnings-from-build-rs/23590/5)
Here's a list of deleted msgids. Some of them were unused, for others
there was a better message (+ translation).
$variable $variable 变量
(command) command substitution (命令) 命令替换
< and > redirections < 和 > 重定向
Autoloading functions 自动加载函数
Background jobs 后台作业
Builtin commands 内建命令
Combining different expansions 合并不同的展开
Command substitution (SUBCOMMAND) 命令替换 (子命令)
Defining aliases 定义别名
Escaping characters 转义字符
Help on how to reuse previously entered commands 关于如何重复使用先前输入的命令的帮助
How lists combine 列表如何组合
Job control 作业控制
Local, global and universal scope 局域、全局和通用作用域
Other features 其他功能
Programmable prompt 可编程提示符
Shell variable and function names Shell 变量和函数名
Some common words 一些常用词
The status variable 状况变量
Variable scope for functions 函数的变量作用域
Vi mode commands Vi 模式命令
What set -x does `set -x` 做什么
Writing your own completions 自己写补全
ifs and elses if 和 else
var[x..y] slices var[x..y] 切片
{a,b} brace expansion {a,b} 大括号展开
~ expansion ~ 展开
Closes#11796
This is useful for the next commit where tab completion produces
tokens like "foo#bar". Some cases are missing though, because we
still need to tell this function what's the previous character.
I guess next commit could also use a different sigil.
Commit 0709e4be8b (Use standalone code paths by default, 2025-10-26)
made CMake builds enable the embed-data feature. This means that
crates/build-man-pages/build.rs will run "sphinx-build" to create
man pages for embedding, now also for CMake builds.
Let's use the sphinx-build found by CMake at configuration-time.
This makes VARS_FOR_CARGO depend on cmake/Docs.cmake, so adjust the
order accordingly.
This has probably been failing intermittently in CI ever since it
was introduced. We have a reproducible test now, so let's disable
this test in CI for now to reduce noise.
See #12018
If I run
history append 'echo -X'
and type "echo -x", it renders as "echo -X".
This is not wrong but can be pretty confusing, (since the
autosuggestion is the same length as the command line).
Let's favor the case typed by the user in this specific case I guess.
Should add a full solution later.
Part of #11452
There is no need to use `'\0'`, we can use `0u8` instead.
`maxaccum` does not clearly indicate what it represents; use
`accum_capacity` instead.
To get the size of `accum`, we can use `accum.len()`, which is easier to
understand.
Use `copy_from_slice` instead of `std::ptr::copy`. This avoids the
unsafe block, at the cost of a runtime length check. If we don't want
this change for performance reasons, we might consider using
`std::ptr::copy_nonoverlapping` here (which is done by `copy_from_slice`
internally).
Part of #12008
If a language is specified using only the language code, without a
region identifier, assume that the user prefers translations from any
variant of the language over the next fallback option. For example, when
a user sets `LANGUAGE=zh:pt`, assume that the user prefers both `zh_CN` and
`zh_TW` over the next fallback option. The precedence of the different
variants of a language will be arbitrary. In this example, with the
current set of relevant available catalogs (`pt_BR`, `zh_CN`, `zh_TW`),
the effective precedence will be either `zh_CN:zh_TW:pt_BR` or
`zh_TW:zh_CN:pt_BR`.
Users who want more control over the order can
specify variants to get the results they want.
For example:
- `LANGUAGE=zh_TW:zh:pt` will result in `zh_TW:zh_CN:pt_BR`.
- `LANGUAGE=zh_CN:pt:zh` will result in `zh_CN:pt_BR:zh_TW`.
- `LANGUAGE=zh_CN:pt` will result in `zh_CN:pt_BR`.
English is always used as the last fallback.
This approach (like the previous approach) differs from GNU gettext
semantics, which map region-less language codes to on specific "default"
variant of the language, without specifying how this default is chosen.
We want to avoid making such choices and believe it is better to utilize
translations from all language variants we have available when users do
not explicitly specify their preferred variant. This way, users have an
easier time discovering localization availability, and can be more
explicit in their preferences if they don't like the defaults.
If there are conflicts with gettext semantics, users can also set locale
variables without exporting them, so fish uses different values than its
child processes.
Closes#12011
Some terminals handle invalid OSC 7 working directories by falling
back to the home directory, which is worse than if they didn't support
OSC 7. Try to work arond the common case (when $MSYSTEM is set).
local wezterm = require 'wezterm'
local config = wezterm.config_builder()
config.default_prog = {
'C:\\msys64\\msys2_shell.cmd',
'-ucrt64',
'-defterm',
'-here',
'-no-start',
'-shell', 'fish'
}
config.default_cwd = 'C:\\msys64\\home\\xxx'
return config
Upstream issues:
- https://github.com/wezterm/wezterm/discussions/7330
- https://invent.kde.org/utilities/konsole/-/merge_requests/1136Closes#11981
This was accidentally turned on because c31e769f7d (Use XTVERSION for
terminal-specific workarounds, 2025-09-21) used the wrong argument
order. Fix that.
I could reproduce both
tests/checks/tmux-empty-prompt.fish
tests/pexpects/autosuggest.py
failing in ASan CI. I didn't bisect it, since I don't think there is
a problematic code change. Bump the timeout a bit.
Closes#12016
This merges changes that make thread pools instanced. We no longer have
a single global thread pool. This results in significant simplifications
especially in the reader (no more "canary").
Enigmatic error:
1 | >>> FROM alpine:3.22 # updatecli.d/docker.yml
ERROR: failed to build: failed to solve: dockerfile parse error on line 1: FROM requires either one or three arguments
Fixes daadd81ab6 (More automation for updating dependencies, 2025-10-31).
When users update fish by replacing files, existing shells might
throw weird errors because internal functions in share/functions/
might have changed.
This is easy to remedy by restarting the shell,
but I guess it would be nice if old shells kept using old data.
This is somewhat at odds with lazy-loading.
But we can use the standalone mode. Turn that on by default.
Additionally, this could simplify packaging. Some packages incorrectly
put third party files into /usr/share/fish/completion/ when they ought
to use /usr/share/fish/vendor_completions.d/ for that. That packaging
mistake can make file conflicts randomly appearing when either fish
or foo ships a completion for foo. Once we actually stop installing
/usr/share/fish/completions, there will no longer be a conflict (for
better or worse, things will silently not work, unless packagers
notice that the directory doesn't actually exist anymore).
The only advantage of having /usr/share/fish/ on the file system is
discoverability. But getting the full source code is better anyway.
Note that we still install (redundant) $__fish_data_dir when using
CMake. This is to not unnecessarily break both
1. already running (old) shells as users upgrade to 4.2
2. plugins (as mentioned in an earlier commit),
We can stop installing $__fish_data_dir once we expect 99% of users
to upgrade from at least 4.2.
If we end up reverting this, we should try to get rid of the embed-data
knob in another way, but I'm not sure how.
Closes#11921
To-do:
- maybe make it a feature flag so users can turn it off without
recompiling with "set -Ua no-embed-data".
The next commit will make embed-data the default also for CMake builds.
Even if we revert that, from a user perspective we better call it
"Building fish with Cargo" rather than "Building fish with embedded
data".
While at it, let's list the user-facing differences when building
with Cargo as opposed to CMake.
I suppose it's not needed to mention :
> An empty ``/etc/fish/config.fish`` as well as empty directories
> ``/etc/fish/{functions,completions,conf.d}``
because that's obvious.
Since installation via Cargo is already aimed at developers, maybe
add "uv run" here to reliably install a recent version of Sphinx.
A small extra step up-front seems better than not having docs.
As mentioned in a previous commit ("Don't special-case __fish_data_dir
in standalone builds"), we want to enable embed-data by default.
To reduce the amount of breakage, we'll keep installing files,
and keep defining those variables at least for some time.
We have no use for $__fish_data_dir apart from helping plugins and
improving upgrade experience, but we still use $__fish_help_dir;
so this will allow installed "standalone" builds to use local docs
via our "help" function.
We use absence of "$__fish_data_dir[1]" as criteria to use the
"standalone" code paths that use "status list-files/get-file" instead
of $__fish_data_dir.
However, third party software seems slow to react to such breaking
changes, see https://github.com/ajeetdsouza/zoxide/issues/1045
So keep $__fish_data_dir for now to give plugins more time.
This commit makes us ignore $__fish_data_dir on standalone builds
even if defined; a following commit will actually define it again.
I guess the approach in b815fff292 (Set $__fish_data_dir to empty
for embed-data builds, 2025-04-01) made sense back when we didn't
anticipate switching to standalone builds by default yet.
Some packagers such as Homebrew use the "relocatable-tree" logic,
i.e. "fish -d config" shows paths like:
/usr/local/etc/fish
/usr/local/share/fish
Other packagers use -DSYSCONFDIR=/etc, meaning we get
/etc/fish
/usr/share/fish
which we don't treat as relocatable tree,
because "/usr/etc/fish" does **not** exists.
To get embed-data in shape for being used as a default for installed
builds, we want it to support both cases.
Today, embed-data builds only handle the "in-build-dir" logic.
Teach them also about the relocatable-tree logic. This will make
embed-data builds installed via Homebrew (i.e. CMake) use the correct
sysconfdir ("/usr/local/etc").
This means that if standalone fish is moved to ~/.local/bin/fish
and both ~/.local/share/fish as well as ~/.local/etc/fish exist,
fish will use the relocatable tree paths.
But only embedded files will be used, although a following commit will
make standalone builds define $__fish_data_dir and $__fish_help_dir
again; the latter will be used to look up help.
(This doesn't matter in practice because we always override SYSCONFDIR
in CMake builds.)
According to https://cmake.org/cmake/help/latest/command/install.html
default paths look like
Type variable default
INCLUDE ${CMAKE_INSTALL_INCLUDEDIR} include
SYSCONF ${CMAKE_INSTALL_SYSCONFDIR} etc
DATA ${CMAKE_INSTALL_DATADIR} <DATAROOT dir>
MAN ${CMAKE_INSTALL_MANDIR} <DATAROOT dir>/man
so "etc" is supposed to be a sibling of "include", not a child of DATA
(aka "share/").
This allows us to remove a hack where we needed to know the data dir
in non-standalone builds.
Today, this file is only supported in CMake builds. This is the only
place where CMake builds currently need $__fish_data_dir as opposed
to using "status get-file".
Let's embed __fish_build_paths so we can treat it like other assets.
This enables users of "embed-data" to do "rm -rf $__fish_data_dir"
(though that might break plugins).
It's always the CMake output directory, so call it
FISH_CMAKE_BINARY_DIR. It's possible to set it via some other build
system but if such builds exist, they are likely subtly broken, or
at least with the following commit which adds the assumption that
"share/__fish_build_paths.fish.in" exists in this directory.
We could even call it CMAKE_BINARY_DIR but let's namespace it to make
our use more obvious. Also, stop using the $CMAKE environment variable,
it's not in our namespace.
Google cloud CLI ships >10k man pages for subcommands, but the
completions are not useful because they don't know to replace
underscores by spaces, e.g. in:
complete -c gcloud_access-approval_requests_approve
We also ship gcloud completions, so the generated ones should not
be used.
The new automation workflow doesn't sign the Git tag or the tarball as
we used to. Since the tag is still created locally, sign it directly.
For signing the tarball; build it locally and compare the extracted
tarball with the one produced by GitHub.
Closes#11996
When building from a clean tag, set the date at the bottom of the
manpages to the tag creation date. This allows to "diff -r" the
extracted tarball to check that CI produces the same as any other
system.
Part of #11996
In future, we should ask "renovatebot" to update these version. I
don't have an opinion on whether to use "uv" or something else, but
I think we do want lockfiles, and I don't know of a natural way to
install Sphinx via Cargo.
No particular reason for this Python version.
Part of #11996
GitHub CI uses shallow clones where no Git tags available, which
breaks tests/checks/sphinx-markdown-changelog.fish.
Somehow tests/checks/sphinx-markdown-changelog.fish doesn't seem to
have run CI before the next commit (or perhaps the python3 change
from commit "tests/sphinx-markdown-changelog: workaround for mawk",
2025-10-26?).
Anway, to prevent failure, disable that part of this test in CI
for now; the point of the test is mostly to check the RST->Markdown
conversion and syntax.
- Convert update checks in check.sh to mechanical updates.
- Use https://www.updatecli.io/ for now, which is not as
full-featured as renovatebot or dependabot, but I found it easier
to plug arbitrary shell scripts into.
- Add updaters for
- ubuntu-latest-lts (which is similar to GitHub Action's "ubuntu-latest").
- FreeBSD image used in Cirrus (requires "gcloud auth login" for now,
see https://github.com/cirruslabs/cirrus-ci-docs/issues/1315)
- littlecheck and widecharwidth
- Update all dependencies except Cargo ones.
- As a reminder, our version policies are arbitrary and can be changed
as needed.
- To-do:
- Add updaters for GitHub Actions (such as "actions/checkout").
Renovatebot could do that.
Most of our docker images are for an OS release which is past EOL. Most
are not checked in CI, which leads to more staleness. It's not
obvious which docker are expected to work and which are best-effort.
I've updated all of them in the past, which would be slightly easier
if we got rid of the redundancy.
Remove most unused ones for now, to reduce confusion and maintenance
effort. Some Ubuntu images are replaced by
docker/ubuntu-latest-lts.Dockerfile
docker/ubuntu-oldest-supported.Dockerfile
Leave around the fedora:latest and opensuse/tumbleweed:latest images
for now, though I don't think there's a reason to publish them in
build_docker_images until we add CI jobs.
We can add some images back (even past-EOL versions) but preferrably
with a documentted update policy (see next commit) and CI tests
(could be a nightly/weekly/pre-release check).
If fish is invoked as
execve("/bin/fish", "fish")
on OpenBSD, "status fish-path" will output "fish". As a result,
our wrapper for fish_indent tries to execute "./fish" if it exists.
We actually no longer need to call any executable, since "fish_indent"
is available as builtin now.
Stop using the wrapper, fixing the OpenBSD issue.
As mentioned in earlier commits, "status fish-path" is either an
absolute path or "fish". At startup, we try to canonicalize this
path. This is wrong for the "fish" case -- we'll do subtly wrong
things if a file with that name happens to exist in the current
working directory.
"cargo test" captures stdout by default but not stderr.
So it's probably still useful to suppress test output like
in function 'recursive1'
in function 'recursive2'
[repeats many times]
This was done by should_suppress_stderr_for_tests() which has been
broken. Fix that, but only for the relevant cases instead of setting
a global.
On some platforms, Rust's std::env::current_exe() may use relative
paths from at least argv[0]. That function also canonicalizes the
path, so we could only detect this case by duplicating logic from
std::env::current_exe() (not sure if that's worth it).
Relative path canonicalization seems potentially surprising, especially
after fish has used "cd". Let's try to reduce surprise by saving the
value we compute at startup (before any "cd"), and use only that.
The remaining problem is that
creat("/some/directory/with/FISH");
chdir("/some/directory/with/");
execve("/bin/fish", "FISH", "-c", "status fish-path")
surprisingly prints "/some/directory/with/FISH" on some platforms.
But that requires the user actively trying to break things (passing
a relative argv[0] that doesn't match the cwd).
When "status fish-path" fails, we fall back to argv[0],
hoping that it contains an absolute path to fish, or at
least is equal to "fish" (which can happen on OpenBSD, see
https://github.com/rust-lang/rust/issues/60560#issuecomment-489425888).
I don't think it makes sense to duplicate logic that's probably
already in std::env::current_exe().
Since c8001b5023 (encoding: use UTF-8 everywhere, 2025-10-18), a
change in locale variables can no longer cause us to toggle between
"…" or "...". Have the control flow reflect this.
We use the following locale-variables via locale-aware C functions
(to look them up, grep for "libc::$function_name"):
- LC_CTYPE: wcwidth
- LC_MESSAGES: strerror, strerror
- LC_NUMERIC: localeconv/localeconv_l, snprintf (only in tests)
- LC_TIME: strftime
Additionally, we interpret LC_MESSAGES in our own code.
As of today, the PCRE2 library does not seem to use LC_MESSAGES
(their error messages are English-only); and I don't think it uses
LC_CTYPE unless we use "pcre2_maketables()".
Let's make it more obvious which locale categories are actually used
by setting those instead of LC_ALL.
This means that instead of logging the return value of «
setlocale(LC_ALL, "") » (which is an opaque binary string on Linux),
we can log the actual per-category locales that are in effect.
This means that there's no longer really a reason to hardcode a log
for the LC_MESSAGES locale. We're not logging at early startup but
we will log if any locale var had been set at startup.
Commit 046db09f90 (Try to set LC_CTYPE to something UTF-8 capable
(#8031), 2021-06-06) forced UTF-8 encoding if available.
Since c8001b5023 (encoding: use UTF-8 everywhere, 2025-10-18) we no
longer override LC_CTYPE, since we no longer use it for anything like
mbrtowc or iswalpha.
However there is one remaining use: our fallbacks to system wcwidth().
If we are started as
LC_ALL=C fish
then wcwidth('😃') will fail to return the correct value, even if
the UTF-8 locale would have been available.
Restore the previous behavior, so locale variables don't affect
emoji width.
This is consistent with the direction in c8001b5023 which stops us
from falling back to ASCII characters if our desired multibyte locale
is missing (that was not the ideal criteria).
In future we should maybe stop using wcwidth().
Commit 8dc3982408 (Always use LC_NUMERIC=C internally (#8204),
2021-10-13) made us use LC_NUMERIC=C internally, to make C library
functions behave in a predictable way.
We no longer use library functions affected by LC_NUMERIC[*]..
Since the effective value of LC_NUMERIC no longer matters, let's
simplify things by using the user locale again, like we do for the
other locale variables.
The printf crate still uses libc::snprintf() which respects LC_NUMERIC,
but it looks like "cargo test" creates a separate process per crate,
and the printf crate does not call setlocale().
* since c8001b5023 (encoding: use UTF-8 everywhere, 2025-10-18)
we always use UTF-8, which simplifies docs.
* emphasize that we (as of an earlier commit) document only the locale
variables actually used by fish. We could change this in future,
as long as the docs make it obvious whether it's about fish or
external programs.
* make things a bit more concise
* delete a stale comment - missing encoding support is no longer a problem
We may have used LC_COLLATE in the past via libc functions but I
don't think we do today. In future, we could document the variables
not used by fish, but we should make it obvious what we're documenting.
These include variables that are ignored by fish, which seems
questionable for __fish_set_locale? The the effect seems benign
because __fish_set_locale will do nothing if any of those variables
is defined. Maybe we can get rid of this function eventually.
Link to history, printf and "builtin _" which are the only(?) users
of LC_TIME, LC_NUMERIC and LC_MESSAGES respectively (besides the core
equivalent of "builtin _").
Our test driver unsets all LC_* variables as well as LANGUAGE, and
it sets LANG=C, to make errors show up as
set_color: Unknown color 'reset'
rather than
set_color: Unknown color “reset”
It also sets LC_CTYPE which is hardly necessary since c8001b5023
(encoding: use UTF-8 everywhere, 2025-10-18).
The only place where we need it seems to be the use of GNU sed as
called in tests/checks/sphinx-markdown-changelog.fish.
In future we might want to avoid these issues by setting LANG=C.UTF-8
in the test_driver again.
These are obsolete as of c8001b5023 (encoding: use UTF-8 everywhere,
2025-10-18). The only place where we still read the user's LC_CTYPE
is in libc::wcwidth(), but that's kind of a regression -- we should
always be using a UTF-8 LC_CTYPE if possible -- which will be fixed
by a following commit.
Commit c8001b5023 (encoding: use UTF-8 everywhere, 2025-10-18)
removed some places where we fallback to ASCII if no UTF-8 encoding
is available. That fallback may have been a reasonable approximator
for glyph availability in some cases but it's probably also wrong in
many cases (SSH, containers..).
There are some cases where we still have this sort of fallback.
Remove them for consistency.
Also merge them into one warning because some of these lines wrap
on a small (80 column) terminal, which looks weird. The reason they
wrap might be the long prefix ("warning: fish-build-man-pages@0.0.0:").
This fails:
tests/test_driver.py ~/.local/opt/fish/bin tests/checks/config-paths-standalone.fish
because we don't expect to run from a relocatable tree.
Their msgfmt doesn't support --output-file=- yet, so use a temporary
file if "msgfmt" doesn't support "--check-format". Else we should
have GNU gettext which supports both.
See #11982
There is no need to allocate a new box in these cases.
Flagged by nightly clippy.
There's also no need for the box at all; the comment is no longer
valid, especially because Rust const-propagates by default.
Closes#12014
Using gettext by calling it once on initialization and then reusing the
result prevents changes to the messages as when locale variables change.
A call to the gettext implementation should be made every time the
message is used to handle language changes.
Closes#12012
For historical reasons[^1], most of our Rust tests are in src/tests,
which
1. is unconventional (Rust unit tests are supposed to be either in the
same module as the implementation, or in a child module).
This makes them slightly harder to discover, navigate etc.
2. can't test private APIs (motivating some of the "exposed for
testing" comments).
Fix this by moving tests to the corresponding implementation file.
Reviewed with
git show $commit \
--color-moved=dimmed-zebra \
--color-moved-ws=allow-indentation-change
- Shared test-only code lives in
src/tests/prelude.rs,
src/builtins/string/test_helpers.rs
src/universal_notifier/test_helpers.rs
We might want to slim down the prelude in future.
- I put our two benchmarks below tests ("mod tests" followed by "mod bench").
Verified that "cargo +nightly bench --features=benchmark" still
compiles and runs.
[^1]: Separate files are idiomatic in most other languages; also
separate files makes it easy to ignore when navigating the call graph.
("rg --vimgrep | rg -v tests/"). Fortunately, rust-analyzer provides
a setting called references.excludeTests for textDocument/references,
the textDocument/prepareCallHierarchy family, and potentially
textDocument/documentHighlight (which can be used to find all
references in the current file).
Closes#11992
Commit 1fe6b28877 (rustfmt.toml: specify edition to allow 2024 syntax,
2025-10-19) mentions that "cargo fmt" has different behavior than
"rustfmt" before that commit. Probably because when .rustfmt.toml
exists, rustfmt implicitly uses a different edition (2018?) that
doesn't support c"" yet. That commit bumped the edition to 2024,
which caused yet another deviation from "cargo fmt":
Error writing files: failed to resolve mod `tests`: cannot parse /home/johannes/git/fish-shell/src/wutil/tests.rs
error: expected identifier, found reserved keyword `gen`
--> /home/johannes/git/fish-shell/src/tests/topic_monitor.rs:48:9
|
48 | for gen in &mut gens_list {
| ^^^ expected identifier, found reserved keyword
This has since been fixed by
00784248db (Update to rust 2024 edition, 2025-10-22).
Let's add a test so that such changes won't randomly break "rustfmt"
again.
Fix that by using 2021 edition, like we do in Cargo.toml.
In future, rustfmt should probably default to a current edition (or
maybe read the edition from Cargo.toml?) Not yet sure which one is the
upstream issue, maybe https://github.com/rust-lang/rustfmt/issues/5650
Prior to this commit, there was a singleton set of "debouncers" used to run
code in the background because it might perform blocking I/O - for example,
for syntax highlighting or computing autosuggestions. The complexity arose
because we might push or pop a reader. For example, a long-blocking, stale
autosuggestion thread might suddenly complete, but the reader it was for
(e.g. for `builtin_read`) is now popped. This was the basis for complex
logic like the "canary" to detect a dead Reader.
Fix this by making the Debouncers per-reader. This removes some globals and
complicated logic; it also makes this case trivial: a long-running thread
that finishes after the Reader is popped, will just produce a Result and
then go away, with nothing reading out that Result.
This also simplifies tests because there's no longer a global thread pool
to worry about. Furthermore we can remove other gross hacks like ForceSend.
This concerns threads spawned by the reader for tasks like syntax
highlighting that may need to perform I/O.
These are different from other threads typically because they need to
"report back" and have their results handled.
Create a dedicated module where this logic can live.
This also eliminates the "global" thread pool.
Sometimes we need to spawn threads to service internal processes. Make
this use a separate thread pool from the pool used for interactive tasks
(like detecting which arguments are files for syntax highlighting).
Make this pass on both macOS and Linux.
This was an obnoxious and uninteresting test to debug and so I used
claude code. It insists this is due to differences in pty handling between
macOS and Linux. Specifically it writes:
The test was failing inconsistently because macOS and Linux have different
PTY scrollback behavior after rendering prompts with right-prompts.
Root cause: After fish writes a right-prompt to the rightmost column,
different PTY drivers position the cursor differently:
- macOS PTY: Cursor wraps to next line, creating a blank line
- Linux PTY: Cursor stays on same line, no blank line
This is OS kernel-level PTY driver behavior, not terminal emulator behavior.
Fix: Instead of hardcoding platform-specific offsets, detect the actual
terminal behavior by probing the output:
1. Capture with -S -12 and check if the first line is blank
2. If blank (macOS behavior), use -S -13 to go back one more line
3. If not blank (Linux behavior), use -S -12
Also split the C-l (clear-screen) command into its own send-keys call
with tmux-sleep after it, ensuring the screen clears before new output
appears. This improves test stability on both platforms.
The solution is platform-independent and adapts to actual terminal
behavior rather than making assumptions based on OS.
This lint will be triggered by a forthcoming change, see
https://github.com/fish-shell/fish-shell/pull/11990#discussion_r2455299865
It bans the usage of
```rust
fn hello() -> impl Debug {
let useful_name = xxx;
useful_name
}
```
in favour of
```rust
fn hello() -> impl Debug {
xxx
}
```
Which is less humanly-understandable.
Part of #11990
As mentioned in 6896898769 (Add [lints] table to suppress lints
across all our crates, 2024-01-12), we can use workspace lints in
Cargo.toml now that we have MSRV >=1.74 and since we probably don't
support building without cargo.
This implies moving some lints from src/lib.rs to "workspace.lints".
While at it, address some of them insrtead.
Previously, if test setup didn't output word 'prompt' it would wait 5 second
timeout. This affected tmux-wrapping.fish and tmux-read.fish tests.
Change it so initialization function wait until any output and error out
on timeout.
Let `y=0` be the first line of the rendered commandline. Then, in final
rendering, the final value of the desired cursor was measured from
`y=scroll_amount`. This wasn't a problem because
```
if !MIDNIGHT_COMMANDER_HACK.load() {
self.r#move(0, 0);
}
```
implicitly changed the actual cursor to be measured from `y=0` to `y=scroll_amount`.
This happened because the cursor moved to `y=scroll_amount` but had its
`y` value set to 0. Since the actual and desired cursors were both measured
from the same line, the code was correct, just unintuitive.
Change this to always measure cursor position from the start of the
rendered commandline.
Reproduction:
fish -C '
function fish_prompt
echo left-prompt\n
end
function fish_right_prompt
echo right-prompt
end
'
and pressing Enter would not preserve the line with right prompt.
This occurred because Screen::cursor_is_wrapped_to_own_line assumed
the last prompt line always had index 0. However, commit 606802daa (Make
ScreenData track multiline prompt, 2025-10-15) changed this so the last
prompt line's index is now `Screen.actual.visible_prompt_lines - 1`.
Screen::cursor_is_wrapped_to_own_line also didn't account for situations
where commandline indentation was 0.
Fix Screen::cursor_is_wrapped_to_own_line and add tests for prompts with
empty last lines.
Reproduction:
fish -C '
function fish_prompt
echo left-prompt\n
end
function fish_right_prompt
echo right-prompt
end
'
This was caused by an off-by-one error in initial Screen.desired resizing
from commit 606802daa (Make ScreenData track multiline prompt, 2025-10-15).
On MSYS/Cygwin, when select/poll wait on a descriptor and `dup2` is used
to copy into that descriptor, they return the descriptor as "ready",
unlike Linux (timeout) and MacOS (EBADF error).
The test specifically checked for Linux and MaxOS behaviors, failing on
Cygwin/MSYS. So relax it to also allow that behavior.
POSIX permissions on Windows is problematic. MSYS and Cygwin have
a "acl/noacl" when mounting filesystems to specify how hard to try.
MSYS by default uses "noacl", which prevents some permissions to be set.
So disable the failing checks.
Note: Cygwin by default does use "acl", which may allow the check to
pass (unverified). But to be consereative, and because MSYS is the only
one providing a Fish-4.x package, we'll skip.
The test always fail on Cygwin (with rare exceptions) so disable it
for now.
A likely cause is issue #11933, so this change should be revisited
once that issue is fixed.
Symbolic links on Windows/Cygwin are complicated and dependent on
multiple factors (env variable, file system, ...). Limitations in the
implementation causes the tests failures and there is little that Fish
can do about it. So disable those tests on Cygwin.
Assume that UTF-8 is used everywhere. This allows for significant
simplification of encoding-related functionality. We no longer need
branching on single-byte vs. multi-byte locales, and we can get rid of
all the libc calls for encoding and decoding, replacing them with Rust's
built-in functionality, or removing them without replacement in cases
where their functionality is no longer needed.
Several tests are removed from `tests/checks/locale.fish`, since setting
the locale no longer impacts encoding behavior. We might want more
rigorous testing of UTF-8 handling instead.
Closes#11975
First, print prompt marker on repaint even if prompt is not visible.
Second, if we issue a clear at (0, 0) we need to restore marker.
This is necessary for features like Kitty's prompt navigation (`ctrl-shift-{jk}`),
which requires the prompt marker at the top of the scrolled command line
to actually jump back to the original state.
Closes#11911
Instead of pretending that prompt is always 1 line, track multiline
prompt in ScreenData.visible_prompt_lines and ScreenData.line_datas as
empty lines.
This enables:
- Trimming part of the prompt that leaves the viewport.
- Removing of the old hack needed for locating first prompt line.
- Fixing #11875.
Part of #11911
Commit 7db9553 (Fix regression causing off-by-one pager height on
truncated autosuggestion) adds line to pager if cursor located at
the start of line and previous line is softwrapped, even if line was
softwrapped normally and not by autosuggestion, giving pager too much space.
Fix that.
Part of #11911
Some string handling functions deal with `Vec<u8>` or `&[u8]`, which
have been referred to as `string` or `str` in the function names. This
is confusing, since they don't deal with Rust's `String` type. Use
`bytes` in the function names instead to reduce confusion.
Closes#11969
cargo fmt works but "rustfmt src/env_dispatch.rs" fails,
error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `"C"`
--> src/env_dispatch.rs:572:63
|
572 | let loc_ptr = unsafe { libc::setlocale(libc::LC_NUMERIC, c"C".as_ptr().cast()) };
| -^^
Fix that as suggested
Opt-in because we don't want failures not related to local changes,
see d93fc5eded (Revert "build_tools/check.sh: check that stable rust
is up-to-date", 2025-08-10).
For the same reason, it's not currently checked by CI, though we should
definitely have "renovatebot" do this in future.
Also, document the minimum supported Rust version (MSRV) policy. There's no
particular reason for this specific MSRV policy, but it's better than nothing,
since this will allow us to always update without thinking about it.
Closes#11960
Update our MSRV to Rust 1.85.
Includes fixes for lints which were previously suppressed due to them
relying on features added after Rust 1.70.
Rust 1.85 prints a warning when using `#[cfg(target_os = "cygwin")]`, so
we work around the one instance where this is a problem for now. This
workaround can be reverted when we update to Rust 1.86 or newer.
Certain old versions of macOS are no longer supported by Rust starting
with Rust 1.74, so this commit raises our macOS version requirement to
10.12.
https://blog.rust-lang.org/2023/09/25/Increasing-Apple-Version-Requirements/https://github.com/fish-shell/fish-shell/pull/11961#discussion_r2442415411Closes#11961
Also remove the check for WSL again, since that failure may be
covered by us checking for flock() success (else there's a bug in our
implementation or in WSL); we'll see if anyone runs into this again..
Closes#11963
This length modifier was reintroduced in
b7fe3190bb, which reverts
993b977c9b, a commit predating the removal
of redundant length modifiers in format strings.
Closes#11968
This commit adds `style_edition = "2024"` as a rustfmt config setting.
All other changes are automatically generated by `cargo fmt`.
The 2024 style edition fixes several bugs and changes some defaults.
https://doc.rust-lang.org/edition-guide/rust-2024/rustfmt-style-edition.html
Most of the changes made to our code result from a different sorting
method for `use` statements, improved ability to split long lines, and
contraction of short trailing expressions into single-line expressions.
While our MSRV is still 1.70, we use more recent toolchains for
development, so we can already benefit from the improvements of the new
style edition. Formatting is not require for building fish, so builds
with Rust 1.70 are not affected by this change.
More context can be found at
https://github.com/fish-shell/fish-shell/issues/11630#issuecomment-3406937077Closes#11959
These comments should be placed on top of the line they're commenting on.
Multi-line postfix comments will no longer be aligned using rustfmt's
style edition 2024, so fix this now to prevent formatting issues later.
For consistency, single-line postfix comments are also moved.
Part of #11959
Update the regex to allow remote names which are allowed in git, like
`foo-bar`, `foo.bar` or `😜`. Do not try to artificially limit the
allowed remote names through the regex.
Closes#11941
On Cygwin, fsync() on the history and uvar file fails with "permission
denied". Work around this by opening the file in read-write mode
instead of read-only mode.
Closes#11948
Today fish script can't produce this type of behavior:
$ type fish_prompt
# Defined in embedded:functions/fish_prompt.fish @ line 2
The above is only created for autoloaded functions.
On standalone builds, "fish_config prompt choose" uses the "source"
builtin, making this line say is "Defined via `source`".
In future, we might want to make things consistent (one way or
the other).
If no "fish_right_prompt" is defined, then we also don't need to
define and save an empty one. We can do nothing, which seems cleaner.
It's also what "fish_config prompt choose" does. Git blame shows no
explicit reason for for this inconsistency.
Probably the implicit reason is that when both styles where introduced
(both in 69074c1591 (fish_config: Remove right prompt in `choose` and
`save`, 2021-09-26)), that was before the "fish_config prompt choose:
make right prompt hack less weird" commit, so the "prompt choose"
code path didn't know whether the prompt existed until after checking,
hence "--erase" was more suitable.. but that inconsistency is gone.
This is important for deterministic behavior across both standalone
and installed builds in "fish_config prompt list".
I later realized that we could use "path sort" I suppose, but why
not fix the problem for everyone.
Rather than first sourcing the prompt, and then erasing the right
prompt unless the prompt file defined the right prompt, start by
erasing the right prompt. This is simpler (needs no conditional).
Now that the « chsh -s $(command -v) » approach should work both
in and outside fish, it seems like we should use that.
Non-macOS users probably shouldn't do this, but there's already a
big warning above this section.
Fixes#11931
This is mysteriously failing intermittently on GitHub Actions CI
and OBS. We get
The CHECK on line 31 wants:
{{\\x1b\\[m}}{{\\x1b\\[4m}}fish default{{\\x1b\\[m}}
which failed to match line stdout:21:
\x1b[38;2;7;114;161m/bright/vixens\x1b[m \x1b[38;2;34;94;121mjump\x1b[m \x1b[38;2;99;175;208m|\x1b[m \x1b[m\x1b[4mfish default\x1b[m
and it doesn't look like it's produced by the "grep -A1" below,
because the later output looks correct.
See https://github.com/fish-shell/fish-shell/pull/11923#discussion_r2417592216
This only builds, doesn't run tests. Use:
./build_fish_on_bsd.sh dragonflybsd_6_4 freebsd_14_0 netbsd_9_3 openbsd_7_4
To build on all of them.
Note they don't all build yet.
build_tools/check.sh would give more coverage (the translation
checks is the main difference) but it tests embed-data builds;
for now testing, traditionally installed builds is more important
(especially since I always test check.sh locally already). In future
we will probably make embedding mandatory and get rid of this schism.
Cirrus builds fail with
error: failed to get `pcre2` as a dependency of package `fish v4.1.0-snapshot (/tmp/cirrus-ci-build)`
...
Caused by:
the SSL certificate is invalid; class=Ssl (16); code=Certificate (-17)
Likely introduced by b644fdbb04 (docker: do not install recommended
packages on Ubuntu, 2025-10-06). Some Ubuntu Dockerfiles already
install ca-certificates explicitly but others do not. Fix the latter.
Re-apply commit ec27b418e after it was accidentally reverted in
5102c8b137 (Update littlecheck, 2025-10-11),
fixing a hang in e.g.
sudo docker/docker_run_tests.sh docker/jammy.Dockerfile
The rapid input can make the screen look like this:
fish: Job 1, 'sleep 0.5 &' has ended
prompt 0> echo hello world
prompt 0> sleep 3 | cat &
bg %1 <= no check matches this, previous check on line 24
Something like
tests/test_driver.py target/debug checks/foo.fish
is invalid (needs "tests/checks/foo.fish").
Let's make failure output list the right fiel name.
At least when run from the root directory.
Don't change the behavior when run from "tests/";
in that case the path was already relative.
The test driver is async now; so we can't change the process-wide
working directory without causing unpredictable behavior.
For example, given these two tests:
$ cat tests/checks/a.fish
#RUN: %fish %s
#REQUIRES: sleep 1
pwd >/tmp/pwd-of-a
$ cat tests/checks/b.fish
#RUN: %fish %s
pwd >/tmp/pwd-of-b
running them may give both fish processes the same working directory.
$ tests/test_driver.py target/debug tests/checks/a.fish tests/checks/b.fish
tests/checks/b.fish PASSED 13 ms
tests/checks/a.fish PASSED 1019 ms
2 / 2 passed (0 skipped)
$ grep . /tmp/pwd-of-a /tmp/pwd-of-b
/tmp/pwd-of-a:/tmp/fishtest-root-1q_tnyqa/fishtest-s9cyqkgz
/tmp/pwd-of-b:/tmp/fishtest-root-1q_tnyqa/fishtest-s9cyqkgz
As mentioned in #11926 our "fish_config" workaround for macOS
10.12.5 or later has been fixed in macOS 10.12.6 according to
https://andrewjaffe.net/blog/2017/05/python_bug_hunt/, I think we
can assume all users have upgraded to that patch version Remove
the workaround.
In particular
- test that it will return an error if the URL is invalid
- that the main page matches the index.html in git
- that "Enter" key will exit
Part of #11907
- Windows allows port reuse under certain conditions. In fish_config
case, this allows the signal socket to use the same port as http (e.g.
when using MINGW python). This can cause some browsers to access the
signal socket rather than the http one (e.g. when connecting using
IPv4/"127.0.0.1" instead of IPv6/"::1").
- This is also more efficient since we already know that all ports up to
and including the http one are not available
Fixes#11805
Part of #11907
"bg %1" of a pipline prints the same line twice because it tries
to background the same job twice. This doesn't make sense and
other builtins like "disown" already deduplicate, so do the same.
Unfortunately we can't use the same approach as "disown" because we
can't hold on to references to job, since we're modifying the job list.
Previously, if you called a function parameter 'argv', within the body
of the function, argv would be set to *all* the arguments to the
function, and not the one indicated by the parameter name.
The same behaviour happened if you inherited a variable named 'argv'.
Both behaviours were quite surprising, so this commit makes things more
obvious, although they could alternatively simply be made errors.
Part of #11780
This makes it so that printing a function definition will only use one
--argument-names group, instead of one for argument name.
For example, "function foo -a x y; ..." will print with "function foo
--argument-names x y" instead of "function foo --argument-names x
--argument-names y", which is very bizarre.
Moreover, the documentation no longer says that argument-names "Has to
be the last option.". This sentence appears to have been introduced in
error by pull #10524, since the ability to have options afterwards was
deliberately added by pull #6188.
Part of #11780
We want all Rust and Python files formatted, and making formatting
behavior dependent on the directory `style.fish` is called from can be
counter-intuitive, especially since `check.sh`, which also calls
`style.fish` is otherwise written in a way that allows calling it from
arbitrary working directories and getting the same results.
Closes#11925
The new names are consistently formulated as commands.
`main` is not very descriptive, so change it to `test`, which is more
informative and accurate.
`rust_checks` are replaced be the more general `lint` in preparation for
non-Rust-related checks.
These changes were suggested in
https://github.com/fish-shell/fish-shell/pull/11918#discussion_r2415957733Closes#11922
Ruff's default format is very similar to black's, so there are only a
few changes made to our Python code. They are all contained in this
commit. The primary benefit of this change is that ruff's performance is
about an order of magnitude better, reducing runtime on this repo down
to under 20ms on my machine, compared to over 150ms with black, and even
more if any changes are performed by black.
Closes#11894Closes#11918
Commit f05ad46980 (config_paths: remove vestiges of installable
builds, 2025-09-06) removed a bunch of code paths for embed-data
builds, since those builds can do without most config paths.
However they still want the sysconfig path. That commit made
embedded builds use "/etc/fish" unconditionally. Previously they
used "$workspace_root/etc". This is important when running tests,
which should not read /etc/fish.
tests/checks/invocation.fish tests this implicitly: if /etc/fish does
not exist, then
fish --profile-startup /dev/stdout
will not contain "builtin source".
Let's restore historical behavior. This might be annoying for users
who "install" with "ln -s target/debug/fish ~/bin/", but that hasn't
ever been recommended, and the historical behavior was in effect
until 4.1.0.
Fixes#11900
Some versions of `/bin/sh`, e.g. the one on FreeBSD, do not propagate
variables set on a command through shell functions. This results in
`FISH_GETTEXT_EXTRACTION_FILE` being set in the `cargo` function, but
not for the actual `cargo` process spawned from the function, which
breaks our localization scripts and tests. Exporting the variable
prevents that.
Fixes#11896Closes#11899
These were accidentally removed when semi-automatically removing length
modifiers from Rust code and shell scripts.
In C, the length modifiers are required.
Closes#11898
Fixes#11881 for me. Thanks, @krobelus, for the help with debugging
this!
The `-+X` is unrelated to the bug, strictly speaking, but makes sure the
test tests what it is intended to test.
I initially thought of also adding `LESS=` and something like
`--lesskey-content=""` to the command, but I decided against it since
`less` can also maybe be configured with `LESSOPEN` (?) and I don't know
how long the `--lesskey-content` option existed.
Closes#11891
The size was used to keep track of the number of bits of the input type
the `Arg::SInt` variant was created from. This was only relevant for
arguments defined in Rust, since the `printf` command takes all
arguments as strings.
The only thing the size was used for is for printing negative numbers
with the `x` and `X` format specifiers. In these cases, the `i64` stored
in the `SInt` variant would be cast to a `u64`, but only the number of
bits present in the original argument would be kept, so `-1i8` would be
formatted as `ff` instead of `ffffffffffffffff`.
There are no users of this feature, so let's simplify the code by
removing it. While we're at it, also remove the unused `bool` returned
by `as_wrapping_sint`.
Closes#11889
As reported in
https://github.com/fish-shell/fish-shell/issues/11836#issuecomment-3369973613,
running "fish -c read" and pasting something would result this error
from __fish_paste:
commandline: Can not set commandline in non-interactive mode
Bisects to 32c36aa5f8 (builtins commandline/complete: allow handling
commandline before reader initialization, 2025-06-13). That commit
allowed "commandline" to work only in interactive sessions, i.e. if
stdin is a TTY or if overridden with -i.
But this is not the only case where fish might read from the TTY.
The notable other case is builtin read, which also works in
noninteractive shells.
Let's allow "commandline" at least after we have initialized the TTY
for the first reader, which restores the relevant historical behavior
(which is weird, e.g. « fish -c 'read; commandline foo' »).
I think we do want to stop using CMake on Cirrus but this should
first be tested in combination with all the other changes that made
it to master concurrently (test by pushing a temporary branch to the
fish-shell repo), to avoid confusion as to what exactly broke.
This reverts commit d167ab9376.
See #11884
The root cause was that FISH_CHECK_LINT was not set. By
default, check.sh should fail if any tool is not installed, see
59b43986e9 (build_tools/style.fish: fail if formatters are not
available, 2025-07-24); like it does for rustfmt and clippy.
This reverts commit fbfd29d6d2.
See #11884
08b03a733a removed CMake from the Docker images used for the
Cirrus builds.
It might be better to use fish_run_tests.sh in the Docker image, but
that requires some context which I'm not sure is set up properly in
Cirrus.
Revamped and renamed the __fish_bind_test2 function. Now has a
more explicit name, `__fish_bind_has_keys` and allows for multiple
functions after the key-combo, doesn't offer function names after an
argument with a parameter (e.g. -M MODE).
Logic on the function is now more concise.
Closes#11864
This combination makes no sense and should be an error. (Also the
short options and --key-names were missing, so this was quite
inconsistent.)
See #11864
Previously, `set -S fish_kill<TAB>` did not list `fish_killring`. This
was because `$1` wasn't sufficiently escaped, and so instead of
referring to a regex capture group, it was always empty.
Closes#11880
As reported in
https://github.com/fish-shell/fish-shell/discussions/11868, some
terminals advertise support for the kitty keyboard protocol despite
it not necessarily being enabled.
We use this flag in 30ff3710a0 (Increase timeout when reading
escape sequences inside paste/kitty kbd, 2025-07-24), to support
the AutoHotKey scenario on terminals that support the kitty keyboard
protocols.
Let's move towards the more comprehensive fix mentioned in abd23d2a1b
(Increase escape sequence timeout while waiting for query response,
2025-09-30), i.e. only apply a low timeout when necessary to actually
distinguish legacy escape.
Let's pick 30ms for now (which has been used successfully for similar
things historically, see 30ff3710a0); a higher timeout let alone
a warning on incomplete sequence seems risky for a patch relase,
and it's also not 100% clear if this is actually a degraded state
because in theory the user might legitimately type "escape [ 1"
(while kitty keyboard protocol is turned off, e.g. before the shell
regains control).
This obsoletes and hence reverts commit 623c14aed0 (Kitty keyboard
protocol is non-functional on old versions of Zellij, 2025-10-04).
Length modifiers are useless. This simplifies the code a bit, results in
more consistency, and allows removing a few PO messages which only
differed in the use of length modifiers.
Closes#11878
Issue #3748 made stdout (the C FILE*, NOT the file descriptor) unbuffered,
due to concerns about mixing output to the stdout FILE* with output output.
We no longer write to the C FILE* and Rust libc doesn't expose stdout, which may
be a macro. This code no longer looks useful. Bravely remove it.
try_readb() uses a high timeout when the kitty keyboard protocol is
enabled, because in that case it should basically never be necessary
to interpret \e as escape key, see 30ff3710a0 (Increase timeout when
reading escape sequences inside paste/kitty kbd, 2025-07-24).
Zellij before commit 0075548a (fix(terminal): support kitty keyboard
protocol setting with "=" (#3942), 2025-01-17) fails to enable kitty
keyboard protocol, so it sends the raw escape bytes, causing us to
wait 300ms.
Closes#11868
Using a multi-line prompt with focus events on:
tmux new-session fish -C '
tmux set -g focus-events on
set -g fish_key_bindings fish_vi_key_bindings
function fish_prompt
echo (prompt_pwd)
echo -n "> "
end
tmux split
'
switching to the fish pane and typing any key sometimes leads to our
two-line-prompt being redawn one line below it's actual place.
Reportedly, it bisects to d27f5a5 which changed when we print things.
I did not verify root cause, but
1. symptoms are very similar to other
problems with TTY timestamps, see eaa837effa (Refresh TTY
timestamps again in most cases, 2025-07-24).
2. this seems fixed if we refresh timestamps after
running the focus events, which print some cursor shaping commands
to stdout. So bravely do that.
Closes#11870
As with `msgmerge`, this introduces unwanted empty comment lines above
`#, c-format`
lines. We don't need this strict formatting, so we get rid of the flag
and the associated empty comment lines.
Closes#11863
Underline is no more a boolean and should be one of the accepted style,
or None. By keeping False as default value, web_config was generating
wrong --underline=False settings
Part of #11861
The abbreviation is ambiguous, which makes the code unnecessarily hard
to read. (possible misleading expansions: direct, direction, director,
...)
Part of #11858
The `have_foo: bool` + `foo: i64` combination is more idiomatically
represented as `foo: Option<i64>`. This change is applied for
`field_width` and `precision`.
In addition, the sketchy explicit cast from `i64` to `c_int`, and the
subsequent implicit cast from `c_int` to `i32` are avoided by using
`i64` consistently.
Part of #11858
This upstream issue was fixed in 0ea77d2ec (Ticket #4597: fix CSI
parser, 2024-10-09); for old mc's we had worked around this but the
workaround was accidentally removed. Add it back for all the versions
that don't have that fix.
Fixes f0e007c439 (Relocate tty metadata and protocols and clean
it up, 2025-06-19) Turns out this was why the "Capability" enum was
added in 2d234bb676 (Only request keyboard protocols once we know
if kitty kbd is supported, 2025-01-26).
Fixes#11869
git --no-pager diff --exit-code || { echo 'There are uncommitted changes after regenerating the gettext PO files. Make sure to update them via `build_tools/update_translations.fish` after changing source files.'; exit 1; }
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 to 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>`.
- Focus reporting is enabled unconditionally, not just inside tmux.
To use it, define functions that handle the ``fish_focus_in`` or ``fish_focus_out``:ref:`events <event>`.
- 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)
=======================================
This release fixes the following problems identified in 4.2.0:
- When building from a tarball without Sphinx (that is, with ``-DBUILD_DOCS=OFF`` or when ``sphinx-build`` is not found),
builtin man pages and help files were missing, which has been fixed (:issue:`12052`).
-``fish_config``'s theme selector (the "colors" tab) was broken, which has been fixed (:issue:`12053`).
fish 4.2.0 (released November 10, 2025)
=======================================
Notable improvements and fixes
------------------------------
- History-based autosuggestions now include multi-line commands.
- A :ref:`transient prompt <transient-prompt>` containing more lines than the final prompt will now be cleared properly (:issue:`11875`).
- Taiwanese Chinese translations have been added.
- French translations have been supplemented (:issue:`11842`).
Deprecations and removed features
---------------------------------
- fish now assumes UTF-8 for character encoding even if the system does not have a UTF-8 locale.
Input bytes which are not valid UTF-8 are still round-tripped correctly.
For example, file paths using legacy encodings can still be used,
but may be rendered differently on the command line.
- On systems where no multi-byte locale is available,
fish will no longer fall back to using ASCII replacements for :ref:`Unicode characters <term-compat-unicode-codepoints>` such as "…".
Interactive improvements
------------------------
- The title of the terminal tab can now be set separately from the window title by defining the :doc:`fish_tab_title <cmds/fish_tab_title>` function (:issue:`2692`).
- fish now hides the portion of a multiline prompt that is scrolled out of view due to a huge command line. This prevents duplicate lines after repainting with partially visible prompt (:issue:`11911`).
-:doc:`fish_config prompt <cmds/fish_config>`'s ``choose`` and ``save`` subcommands have been taught to reset :doc:`fish_mode_prompt <cmds/fish_mode_prompt>` in addition to the other prompt functions (:issue:`11937`).
- fish no longer force-disables mouse capture (DECSET/DECRST 1000),
so you can use those commands
to let mouse clicks move the cursor or select completions items (:issue:`4918`).
- The :kbd:`alt-p` binding no longer adds a redundant space to the command line.
- When run as a login shell on macOS, fish now sets :envvar:`MANPATH` correctly when that variable was already present in the environment (:issue:`10684`).
- A Windows-specific case of the :doc:`web-based config <cmds/fish_config>` failing to launch has been fixed (:issue:`11805`).
- A MSYS2-specific workaround for Konsole and WezTerm has been added,
to prevent them from using the wrong working directory when opening new tabs (:issue:`11981`).
For distributors and developers
-------------------------------
- Release tags and source code tarballs are GPG-signed again (:issue:`11996`).
- Documentation in release tarballs is now built with the latest version of Sphinx,
which means that pre-built man pages include :ref:`OSC 8 hyperlinks <term-compat-osc-8>`.
- The Sphinx dependency is now specified in ``pyproject.toml``,
which allows you to use `uv <https://github.com/astral-sh/uv>`__ to provide Sphinx for building documentation (e.g. ``uv run cargo install --path .``).
- The minimum supported Rust version (MSRV) has been updated to 1.85.
- The standalone build mode has been made the default.
This means that the files in ``$CMAKE_INSTALL_PREFIX/share/fish`` will not be used anymore, except for HTML docs.
As a result, future upgrades will no longer break running shells
if one of fish's internal helper functions has been changed in the updated version.
For now, the data files are still installed redundantly,
to prevent upgrades from breaking already-running shells (:issue:`11921`).
To reverse this change (which should not be necessary),
patch out the ``embed-data`` feature from ``cmake/Rust.cmake``.
This option will be removed in future.
- OpenBSD 7.8 revealed an issue with fish's approach for displaying builtin man pages, which has been fixed.
Regression fixes:
-----------------
- (from 4.1.0) Fix the :doc:`web-based config <cmds/fish_config>` for Python 3.9 and older (:issue:`12039`).
- (from 4.1.0) Correct wrong terminal modes set by ``fish -c 'read; cat`` (:issue:`12024`).
- (from 4.1.0) On VTE-based terminals, stop redrawing the prompt on resize again, to avoid glitches.
- (from 4.1.0) On MSYS2, fix saving/loading of universal variables (:issue:`11948`).
- (from 4.1.0) Fix error using ``man`` for the commands ``!````.````:````[````{`` (:issue:`11955`).
- (from 4.1.0) Fix build issues on illumos systems (:issue:`11982`).
- (from 4.0.0) Fix build on SPARC and MIPS Linux by disabling ``SIGSTKFLT``.
- (from 4.0.0) Fix crash when passing negative PIDs to builtin :doc:`wait <cmds/wait>` (:issue:`11929`).
- (from 4.0.0) On Linux, fix :doc:`status fish-path <cmds/status>` output when fish has been reinstalled since it was started.
fish 4.1.2 (released October 7, 2025)
=====================================
This release fixes the following regressions identified in 4.1.0:
- Fixed spurious error output when completing remote file paths for ``scp`` (:issue:`11860`).
- Fixed the :kbd:`alt-l` binding not formatting ``ls`` output correctly (one entry per line, no colors) (:issue:`11888`).
- Fixed an issue where focus events (currently only enabled in ``tmux``) would cause multiline prompts to be redrawn in the wrong line (:issue:`11870`).
- Stopped printing output that would cause a glitch on old versions of Midnight Commander (:issue:`11869`).
- Added a fix for some configurations of Zellij where :kbd:`escape` key processing was delayed (:issue:`11868`).
- Fixed a case where the :doc:`web-based configuration tool <cmds/fish_config>` would generate invalid configuration (:issue:`11861`).
- Fixed a case where pasting into ``fish -c read`` would fail with a noisy error (:issue:`11836`).
- Fixed a case where upgrading fish would break old versions of fish that were still running.
In general, fish still needs to be restarted after it is upgraded,
except for `standalone builds <https://github.com/fish-shell/fish-shell/?tab=readme-ov-file#building-fish-with-embedded-data-experimental>`__.
fish 4.1.1 (released September 30, 2025)
========================================
This release fixes the following regressions identified in 4.1.0:
@@ -14,7 +176,7 @@ 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`).
@@ -844,7 +1006,7 @@ Notable improvements and fixes
which expands ``!!`` to the last history item, anywhere on the command line, mimicking other shells' history expansion.
See :ref:`the documentation <cmd-abbr>` for more.
See :doc:`the documentation <cmds/abbr>` for more.
-``path`` gained a new ``mtime`` subcommand to print the modification time stamp for files. For example, this can be used to handle cache file ages (:issue:`9057`)::
> touch foo
@@ -1269,7 +1431,7 @@ Scripting improvements
two
'blue '
-``$fish_user_paths`` is now automatically deduplicated to fix a common user error of appending to it in config.fish when it is universal (:issue:`8117`). :ref:`fish_add_path <cmd-fish_add_path>` remains the recommended way to add to $PATH.
-``$fish_user_paths`` is now automatically deduplicated to fix a common user error of appending to it in config.fish when it is universal (:issue:`8117`). :doc:`fish_add_path <cmds/fish_add_path>` remains the recommended way to add to $PATH.
-``return`` can now be used outside functions. In scripts, it does the same thing as ``exit``. In interactive mode,it sets ``$status`` without exiting (:issue:`8148`).
- An oversight prevented all syntax checks from running on commands given to ``fish -c`` (:issue:`8171`). This includes checks such as ``exec`` not being allowed in a pipeline, and ``$$`` not being a valid variable. Generally, another error was generated anyway.
-``fish_indent`` now correctly reformats tokens that end with a backslash followed by a newline (:issue:`8197`).
Use ``cargo fmt`` and ``cargo clippy``. Clippy warnings can be turned off if there's a good reason to.
We support at least the version of ``rustc`` available in Debian Stable.
Testing
=======
@@ -190,84 +199,53 @@ The source code for fish includes a large collection of tests. If you
are making any changes to fish, running these tests is a good way to make
sure the behaviour remains consistent and regressions are not
introduced. Even if you don’t run the tests on your machine, they will
still be run via Github Actions.
still be run via GitHub Actions.
You are strongly encouraged to add tests when changing the functionality
of fish, especially if you are fixing a bug to help ensure there are no
regressions in the future (i.e., we don’t reintroduce the bug).
The tests can be found in three places:
Unit tests live next to the implementation in Rust source files, in inline submodules (``mod tests {}``).
- src/tests for unit tests.
- tests/checks for script tests, run by `littlecheck <https://github.com/ridiculousfish/littlecheck>`__
- tests/pexpects for interactive tests using `pexpect <https://pexpect.readthedocs.io/en/stable/>`__
System tests live in ``tests/``:
When in doubt, the bulk of the tests should be added as a littlecheck test in tests/checks, as they are the easiest to modify and run, and much faster and more dependable than pexpect tests. The syntax is fairly self-explanatory. It's a fish script with the expected output in ``# CHECK:`` or ``# CHECKERR:`` (for stderr) comments.
If your littlecheck test has a specific dependency, use ``# REQUIRE: ...`` with a posix sh script.
-``tests/checks`` are run by `littlecheck <https://github.com/ridiculousfish/littlecheck>`__
and test noninteractive (script) behavior,
except for ``tests/checks/tmux-*`` which test interactive scenarios.
-``tests/pexpects`` tests interactive scenarios using `pexpect <https://pexpect.readthedocs.io/en/stable/>`__
The pexpects are written in python and can simulate input and output to/from a terminal, so they are needed for anything that needs actual interactivity. The runner is in tests/pexpect_helper.py, in case you need to modify something there.
When in doubt, the bulk of the tests should be added as a littlecheck test in tests/checks, as they are the easiest to modify and run, and much faster and more dependable than pexpect tests.
The syntax is fairly self-explanatory.
It's a fish script with the expected output in ``# CHECK:`` or ``# CHECKERR:`` (for stderr) comments.
If your littlecheck test has a specific dependency, use ``# REQUIRE: ...`` with a POSIX sh script.
These tests can be run via the tests/test_driver.py python script, which will set up the environment.
The pexpect tests are written in Python and can simulate input and output to/from a terminal, so they are needed for anything that needs actual interactivity.
The runner is in tests/pexpect_helper.py, in case you need to modify something there.
These tests can be run via the tests/test_driver.py Python script, which will set up the environment.
It sets up a temporary $HOME and also uses it as the current directory, so you do not need to create a temporary directory in them.
If you need a command to do something weird to test something, maybe add it to the ``fish_test_helper`` binary (in tests/fish_test_helper.c), or see if it can already do it.
If you need a command to do something weird to test something, maybe add it to the ``fish_test_helper`` binary (in ``tests/fish_test_helper.c``).
Local testing
-------------
The tests can be run on your local computer on all operating systems.
The tests can be run on your local system::
::
cmake path/to/fish-shell
make fish_run_tests
Or you can run them on a fish, without involving cmake::
cargo build
cargo test # for the unit tests
tests/test_driver.py target/debug # for the script and interactive tests
This will create a new PO file containing all messages available for translation.
If the file already exists, it will be updated.
@@ -341,9 +318,9 @@ Editing PO files
Many tools are available for editing translation files, including
command-line and graphical user interface programs. For simple use, you can use your text editor.
Open up the PO file, for example ``po/sv.po``, and you'll see something like::
Open up the PO file, for example ``localization/po/sv.po``, and you'll see something like::
msgid "%ls: No suitable job\n"
msgid "%s: No suitable job\n"
msgstr ""
The ``msgid`` here is the "name" of the string to translate, typically the English string to translate.
@@ -351,10 +328,10 @@ The second line (``msgstr``) is where your translation goes.
For example::
msgid "%ls: No suitable job\n"
msgstr "%ls: Inget passande jobb\n"
msgid "%s: No suitable job\n"
msgstr "%s: Inget passande jobb\n"
Any ``%s`` / ``%ls`` or ``%d`` are placeholders that fish will use for formatting at runtime. It is important that they match - the translated string should have the same placeholders in the same order.
Any ``%s`` or ``%d`` are placeholders that fish will use for formatting at runtime. It is important that they match - the translated string should have the same placeholders in the same order.
Also any escaped characters, like that ``\n`` newline at the end, should be kept so the translation has the same behavior.
@@ -369,7 +346,7 @@ Modifications to strings in source files
If a string changes in the sources, the old translations will no longer work.
They will be preserved in the PO files, but commented-out (starting with ``#~``).
If you add/remove/change a translatable strings in a source file,
run ``build_tools/update_translations.fish`` to propagate this to all translation files (``po/*.po``).
run ``build_tools/update_translations.fish`` to propagate this to all translation files (``localization/po/*.po``).
This is only relevant for developers modifying the source files of fish or fish scripts.
Setting Code Up For Translations
@@ -381,7 +358,7 @@ macros:
::
streams.out.append(wgettext_fmt!("%ls: There are no jobs\n", argv[0]));
streams.out.append(wgettext_fmt!("%s: There are no jobs\n", argv[0]));
All messages in fish script must be enclosed in single or double quote
characters for our message extraction script to find them.
@@ -404,6 +381,12 @@ You can use either single or double quotes to enclose the
message to be translated. You can also optionally include spaces after
the opening parentheses or before the closing parentheses.
Updating Dependencies
=====================
To update dependencies, run ``build_tools/update-dependencies.sh``.
This currently requires `updatecli <https://github.com/updatecli/updatecli>`__ and a few other tools.
``uname`` and ``sed`` at least, but the full coreutils plus ``find`` and
``awk`` is preferred)
@@ -100,6 +100,7 @@ The following optional features also have specific requirements:
messages require ``man`` for display
- automated completion generation from manual pages requires Python 3.5+
- the ``fish_config`` web configuration tool requires Python 3.5+ and a web browser
- the :ref:`alt-o <shared-binds-alt-o>` binding requires the ``file`` program.
- system clipboard integration (with the default Ctrl-V and Ctrl-X
bindings) require either the ``xsel``, ``xclip``,
``wl-copy``/``wl-paste`` or ``pbcopy``/``pbpaste`` utilities
@@ -111,14 +112,12 @@ The following optional features also have specific requirements:
Building
--------
.._dependencies-1:
Dependencies
~~~~~~~~~~~~
Compiling fish requires:
- Rust (version 1.70 or later)
- Rust (version 1.85 or later)
- 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
@@ -128,7 +127,7 @@ Compiling fish requires:
Sphinx is also optionally required to build the documentation from a
cloned git repository.
Additionally, running the full test suite requires Python 3.5+, tmux, and the pexpect package.
Additionally, running the full test suite requires diff, git, Python 3.5+, pexpect, less, tmux and wget.
Building from source with CMake
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -140,7 +139,7 @@ links above, and up-to-date `development builds of fish are available for many p
To install into ``/usr/local``, run:
..code::bash
..code::shell
mkdir build;cd build
cmake ..
@@ -158,41 +157,47 @@ 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_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.
- 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 embedded data (experimental)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Building fish with Cargo
~~~~~~~~~~~~~~~~~~~~~~~~
You can also build fish with the data files embedded.
You can also build fish with Cargo.
This example uses `uv <https://github.com/astral-sh/uv>`__ to install Sphinx (which is used for man-pages and ``--help`` options).
You can also install Sphinx another way and drop the ``uv run --no-managed-python`` prefix.
This will include all the datafiles like the included functions or web configuration tool in the main ``fish`` binary.
..code::shell
Fish will then read these right from its own binary, and print them out when needed. Some files, like the webconfig tool and the manpage completion generator, will be extracted to a temporary directory on-demand. You can list the files with ``status list-files`` and print one with ``status get-file path/to/file`` (e.g. ``status get-file functions/fish_prompt.fish`` to get the default prompt).
cargo install --path /path/to/fish # if you have a git clone
cargo install --git https://github.com/fish-shell/fish-shell --tag "$(curl -s https://api.github.com/repos/fish-shell/fish-shell/releases/latest | jq -r .tag_name)" # to build the latest release
cargo install --git https://github.com/fish-shell/fish-shell # to build the latest development snapshot
uv run --no-managed-python \
cargo install --path .
This will place the standalone binaries in ``~/.cargo/bin/``, but you can place them wherever you want.
This will place standalone binaries in ``~/.cargo/bin/``, but you can move them wherever you want.
This build won't have the HTML docs (``help`` will open the online version).
It will try to build the man pages with sphinx-build. If that is not available and you would like to include man pages, you need to install it and retrigger the build script, e.g. by setting FISH_BUILD_DOCS=1::
FISH_BUILD_DOCS=1 cargo install --path .
Setting it to "0" disables the inclusion of man pages.
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,
(also recorded in ``$PREFIX/share/pkgconfig/fish.pc``)
which are used by some package managers to house third-party completions.
Regardless of build system, fish uses ``$XDG_DATA_DIRS/{vendor_completion.d,vendor_conf.d,vendor_functions.d}``.
echo"*Download links: To download the source code for fish, we suggest the file named \"fish-$version.tar.xz\". The file downloaded from \"Source code (tar.gz)\" will not build correctly.*"
echo'Download links:'
echo'To download the source code for fish, we suggest the file named ``fish-'"$version"'.tar.xz``.'
echo'The file downloaded from ``Source code (tar.gz)`` will not build correctly.'
echo'A GPG signature using `this key <'"${FISH_GPG_PUBLIC_KEY_URL:-???}"'>`__ is available as ``fish-'"$version"'.tar.xz.asc``.'
echo
echo"*The files called fish-$version-linux-\*.tar.xz are experimental packages containing a single standalone ``fish`` binary for any Linux with the given CPU architecture.*"
echo'The files called ``fish-'"$version"'-linux-*.tar.xz`` contain'
echo'`standalone fish binaries <https://github.com/fish-shell/fish-shell/?tab=readme-ov-file#building-fish-with-cargo>`__'
echo'for any Linux with the given CPU architecture.'
@@ -31,7 +31,7 @@ The work will **proceed on master**: no long-lived branches. Tests and CI contin
The Rust code will initially resemble the replaced C++. Fidelity to existing code is more important than Rust idiomaticity, to aid review and bisecting. But don't take this to extremes - use judgement.
The port will proceed "outside in." We'll start with leaf components (e.g. builtins) and proceed towards the core. Some components will have both a Rust and C++ implementation (e.g. FLOG), in other cases we'll change the existing C++ to invoke the new Rust implementations (builtins).
The port will proceed "outside in." We'll start with leaf components (e.g. builtins) and proceed towards the core. Some components will have both a Rust and C++ implementation (e.g. flog), in other cases we'll change the existing C++ to invoke the new Rust implementations (builtins).
@@ -18,7 +18,7 @@ We use forks of the last two - see the [FFI section](#ffi) below. No special act
### Build Dependencies
fish-shell currently depends on Rust 1.70 or later. To install Rust, follow https://rustup.rs.
fish-shell currently depends on Rust 1.85 or later. To install Rust, follow https://rustup.rs.
### Build via CMake
@@ -58,7 +58,7 @@ The basic development loop for this port:
- Do this even if it results in less idiomatic Rust, but avoid being super-dogmatic either way.
- One technique is to paste the C++ into the Rust code, commented out, and go line by line.
4. Decide whether any existing C++ callers should invoke the Rust implementation, or whether we should keep the C++ one.
- Utility functions may have both a Rust and C++ implementation. An example is `FLOG` where interop is too hard.
- Utility functions may have both a Rust and C++ implementation. An example is `flog` where interop is too hard.
- Major components (e.g. builtin implementations) should _not_ be duplicated; instead the Rust should call C++ or vice-versa.
5. Remember to run `cargo fmt` and `cargo clippy` to keep the codebase somewhat clean (otherwise CI will fail). If you use rust-analyzer, you can run clippy automatically by setting `rust-analyzer.checkOnSave.command = "clippy"`.
@@ -93,7 +93,7 @@ None of the Rust string types are nul-terminated. We're taking this opportunity
One may create a `&wstr` from a string literal using the `wchar::L!` macro:
```rust
usecrate::wchar::prelude::*;
usecrate::prelude::*;
// This imports wstr, the L! macro, WString, a ToWString trait that supplies .to_wstring() along with other things
We have a prelude to make working with these string types a whole lot more ergonomic. In particular `WExt` supplies the null-terminated-compatible `.char_at(usize)`,
and a whole lot more methods that makes porting C++ code easier. It is also preferred to use char-based-methods like `.char_count()` and `.slice_{from,to}()`
and a whole lot more methods that makes porting C++ code easier. It is also preferred to use char-based-methods like `.char_count()` and `.slice_{from,to}()`
of the `WExt` trait over directly calling `.len()` and `[usize..]/[..usize]`, as that makes the code compatible with a potential future change to UTF8-strings.
```rust
@@ -144,7 +144,7 @@ These types should be confined to the FFI modules, in particular `wchar_ffi`. Th
### Format strings
Rust's builtin `std::fmt` modules do not accept runtime-provided format strings, so we mostly won't use them, except perhaps for FLOG / other non-translated text.
Rust's builtin `std::fmt` modules do not accept runtime-provided format strings, so we mostly won't use them, except perhaps for flog / other non-translated text.
Instead we'll continue to use printf-style strings, with a Rust printf implementation.
@@ -25,6 +23,8 @@ If other programs launched via fish should respect these locale variables they h
For :envvar:`LANGUAGE` you can use a list, or use colons to separate multiple languages.
If the :ref:`status language set <status-language>` command was used, its arguments specify the language precedence, and the environment variables are ignored.
@@ -147,12 +145,17 @@ The following special input functions are available:
``backward-kill-line``
move everything from the beginning of the line to the cursor to the killring
.._cmd-bind-backward-kill-path-component:
``backward-kill-path-component``
move one path component to the left of the cursor to the killring. A path component is everything likely to belong to a path component, i.e. not any of the following: `/={,}'\":@ |;<>&`, plus newlines and tabs.
``backward-kill-word``
move the word to the left of the cursor to the killring. The "word" here is everything up to punctuation or whitespace.
``backward-path-component``
move one :ref:`path component <cmd-bind-backward-kill-path-component>` to the left.
``backward-word``
move one word to the left
@@ -243,6 +246,9 @@ The following special input functions are available:
commandline, does not accept the current autosuggestion (if any). Does not change the selected item in the completion pager,
if shown.
``forward-path-component``
move one :ref:`path component <cmd-bind-backward-kill-path-component>` to the right; or if at the end of the commandline, accept a path component from the current autosuggestion.
``forward-single-char``
move one character to the right; or if at the end of the commandline, accept a single char from the current autosuggestion.
@@ -310,6 +316,9 @@ The following special input functions are available:
``kill-line``
move everything from the cursor to the end of the line to the killring
``kill-path-component``
move one :ref:`path component <cmd-bind-backward-kill-path-component>` to the killring.
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.