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
Default features are not needed for message extraction, so there is no
need to spend any resources on them.
If a PO files contains a syntax error, extraction would fail if the
`localize-messages` feature is active. This is undesirable, because it
results in an unnecessary failure with worse error messages than if the
`msgmerge` invocation of the `update_translations.fish` script fails.
Closes#11849
This command is only used to determine availability of `msgfmt`. Without
these changes, the entire help output shows up if the code panics later
on, which adds useless bloat to the output, making it harder to analyze
what went wrong.
Closes#11848
Prior to this, when `msgfmt` failed, this would be detected indirectly
by the parser, which would then panic due to it input being empty.
Explicit checking allows us to properly display `msgfmt`'s error
message.
Closes#11847
I'm not sure if our peer projects do this or if it's useful to have
on top of github releases (especially as most releases are patch
releases mainly).
We could certainly use "sphinx-build -b text" in
build_tools/release-notes.sh to extract a nice plaintext changelog
and send that, but that doesn't support links. Not sure about HTML
email either.
Use msgids to mark sections. In the PO format, comments are associated
with specific messages, which does not match the semantics for section
markers.
Furthermore, comments are not preserved by `msgmerge`, which required
quite convoluted handling to copy them over from the template.
By using msgids to mark sections, this problem is avoided.
This convoluted handling was also used for header comments. Header
comments are now handled in a simpler way. There is a fixed prefix,
identifying these comments, as well as a list variable containing the
lines which should be put into the header. When a PO file is generated,
all existing lines starting with the prefix are deleted, the and the
current version of the lines is prepended to the file.
Closes#11845
These should not be comments on an actual message, since they apply
throughout the entire file, so the sensible location is as comments on
the empty msgid.
Closes#11843
Running "fish -d reader" inside SSH inside Windows terminal sometimes
results in hangs on startup (or whenever we run "scrollback-push"),
because not all of the Primary DA response is available for reading
at once:
reader: Incomplete escape sequence: \e\[?61\;4\;6\;7\;14\;21\;22\;23\;24\;28\;32
Work around this by increasing the read timeout while we're waiting
for query responses.
We should try to find a better (more comprehensive?) fix in future,
but for the patch release, this small change will do.
Fixes#11841
Integration_4.1.1 fails to generate release notes with
CHANGELOG.rst:9: WARNING: Bullet list ends without a blank
line; unexpected unindent. [docutils].
We don't care about any specific attributes but we do very much care
about the specific query and response format associated with VT100's
primary device attribute query. Use a proper noun to emphasize that
we want that one and no other.
Ref: https://github.com/fish-shell/fish-shell/pull/11833#discussion_r2385659040
Executable path is empty only in contrived circumstances.
The regex error happens only when the user explicitly turns off a
feature flag.
The orphaned process error seems very unlikely, not worth translating.
The overwhelming majority of localizable messages comes from
completions:
$ ls share/completions/ | wc -l
$ 1048
OTOH functions also contribute a small amount, mostly via their
descriptions (so usually just one per file).
$ ls share/functions/ | wc -l
$ 237
Most of these are private and almost never shown to the user, so it's
not worth bothering translators with them. So:
- Skip private (see the parent commit) and deprecated functions.
- Skip wrapper functions like grep (where the translation seems to
be provided by apropos), and even the English description is not
helpful.
- Assume that most real systems have "seq", "realpath" etc.,
so it's no use providing our own translations for our fallbacks.
- Mark fish's own functions as tier1, and some barely-used functiosn
and completions as tier3, so we can order them that way in
po/*.po. Most translators should only look at tier1 and tier2.
In future we could disable localization for tier3.
See the explanation at the bottom of
tests/checks/message-localization-tier-is-declared.fish
Part of #11833
WezTerm allows applications to enable modifyOtherKeys by default.
Its implementation has issues on non-English or non-QWERTY layouts,
see https://github.com/wezterm/wezterm/issues/6087 and #11204.
fish 4.0.1 disabled modifyOtherKeys on WezTerm specifically
(7ee6d91ba0 (Work around keyboard-layout related bugs in WezTerm's
modifyOtherKeys, 2025-03-03)), fish 4.1.0 didn't, because at that
time, WezTerm would advertise support for the kitty keyboard protocol
(even if applications are not allowed to enable it) which would make
fish skip requesting the legacy modifyOtherKeys.
WezTerm no longer advertises that if config.enable_kitty_keyboard
is false. Let's work around it in another way.
I only tested with embedded-builds; CMake tests were failing because
they use different code paths here.
fish_config could use some love. Start by extracting common
functionality between "{theme,prompt} show", fixing the behavior.
Fixes 29a35a7951 (fish_config: fix "prompt/theme show" in embed-data
builds, 2025-09-28).
Commit 2b74affaf0 (Add prompt selector, 2021-04-22)
intentionally added an unused code path that checks for
$__fish_data_dir/sample_prompts, see
https://github.com/fish-shell/fish-shell/pull/7958#discussion_r621320945
> (note: This was added in preparation of moving the sample_prompts directory out of web_config -
> because it no longer is web-exclusive)
Remove it.
Since 205d80c75a (findrust: Simplify (#11328), 2025-03-30), we need
to set Rust_COMPILER and Rust_CARGO instead of Rust_TOOLCHAIN (which
is no longer used). Adjust macOS builds accordingly.
When I set only one of the two, the error messages were pretty
unintelligible. But I guess few normal users need to override the
Rust version, and they can always look here.
While at it, enable localization. AFAIK, the only reason why we didn't
do this on macOS were problems related to the gettext shared library /
dependency. We no longer need that, and it's already tested in CI.
I'm not aware of a lot of sensible use cases where users need to access
our files directly. The one example we know about is zoxide overriding
exactly our version of "function cd", ignoring any user-provided cd.
I think this is already hacky. But I guess it's here to stay.
I think we should not recommend this for external use, or at least
ask users to tell us what they are using this for.
Given that we expect these to be used mainly/only internally,
get-file/list-files are fine as names.
The other issue is that one has to be careful to always do
status list-files 2>/dev/null
to support non-embedded builds.
Closes#11555
A lot of terminals support CSI Ps S. Currently we only allow them
to use scrollback-up if they advertise it via XTGETTCAP. This seems
surprising; it's better to make visible in fish script whether this
is supposed to be working. The canonical place is in "bind ctrl-l"
output.
The downside here is that we need to expose something that's rarely
useful. But the namespace pollution is not so bad, and this gives
users a nice paper trail instead of having to look in the source code.
Instead of adding these to the Markdown directly, add it to the
fake CHANGELOG.rst source, which makes escaping easier, and allows
generating other formats than Markdown in future.
sphinx-build fails with
sphinx.errors.SphinxError: Builder name markdown not registered or available through entry point
Apparently this issue was hidden locally by caching, and not checked
in CI because of this error causing
tests/checks/sphinx-markdown-changelog.fish to be skipped.
sphinx-build 7.2.6
runner@runnervm3ublj:~/work/fish-shell/fish-shell$ python -c 'import sphinx_markdown_builder'
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/home/runner/.local/lib/python3.12/site-packages/sphinx_markdown_builder/__init__.py", line 6, in <module>
from sphinx.util.typing import ExtensionMetadata
ImportError: cannot import name 'ExtensionMetadata' from 'sphinx.util.typing' (/usr/lib/python3/dist-packages/sphinx/util/typing.py)
This reverts commit 7b495497d7.
While at it, fail the test earlier if something went wrong, because the
remaining check will likely also fail and confuse.
GitHub-flavored Markdown translates line breaks to <br/>, which does
not match our intent. Work around that by joining lines when producing
Markdown output.
complete --subcommand was added in a8e237f0f9 (Let `complete`
show completions for one command if just given `-c`, 2020-09-09)
but never used or documented.
Some of our integration tests require a reader for code execution
and testing cancellation etc., but they never actually read from the
terminal. So they don't need to call reader_interactive_init(), and
doing so is a bit weird. Let's stop that; this allows us to assert
that reader_push() is always called with an input file descriptor
that refers to a TTY.
As mentioned in the comment, query timeouts can happen if either
1. the terminal doesn't support primary device attribute
2. there is extreme (network) latency
In the first case, we want to turn the timeout way down. In the
second case, probably not, especially because the network latency
may be transient. Let's keep the high timeout in the second case.
Fixes 7ef4e7dfe7 (Time out terminal queries after a while,
2025-09-21).
Commit 5e317497ef (Query terminal before reading config, 2025-05-17)
disabled the kitty keyboard protocol in "fish -c read". This seems
surprising, and it's not actually necessary that we query before
reading config; we only need query results before we read from
the TTY for the first time (which is about the time we call
__fish_config_interactive). Let's do that, reverting parts of
5e317497ef.
If the initial query is interrupted by ctrl-c, we leave it unset. A
later rogue "\e[?0u" reply would make us enable it, which seems
surprising. Fix that by always setting the capability if we're gonna
read from stdin.
When we receive a cursor position report, we only store the result;
we'll act on it only when we receive the primary DA reply. Make sure
we don't discard the query state until then.
Fixes 06ede39ec9 (Degrade gracefully when failing to receive cursor
position report, 2025-09-23)
As is, building man pages or HTML docs while sphinx_markdown_builder
is installed, will result in unrelated warnings. Remove those by
removing it from the extensions config. Markdown building (only used
for changelog) seems to work without this just fine.
System tests typically run outside the workspace directory, but they
still have read-only access to the workspace; fix it accordingly.
This test only works on git checkouts, not in tarballs, so skip it
if .git doesn't exist.
Currently, `__fish_git_prompt_char_upstream_diverged` can only be set to
a combination of `__fish_git_prompt_char_upstream_behind` and
`__fish_git_prompt_char_upstream_ahead`s plain-text options. Adding a
combination of the less-plain character options gives users more choice.
Closes#11817
Add a set of basic completions for udevil, which is a program that
allows unpriviledged users to mount devices.
Each command has a corresponding long-option-like syntax variant
(sometimes even multiple ones), such as "udevil monitor" -> "udevil
--monitor", which are omitted here for simplicity.
The project unfortunately seems long abandoned and as such no attempt to
submit these completions upstream has been made.
Instead of having sphinx-build only build CHANGELOG.rst, build the
entire thing, so relative references (":doc:", ":ref:") can be resolved
properly. Replace our sed-based hacks with 'markdown_http_base'.
Experience with OSC 133 and kitty keyboard protocol enabling sequences
has shown that a lot of users are still on incompatible terminals.
It's not always easy to fix those terminals straight away. There
are probably some more environments where primary device attribute
queries are not answered.
Add a feature flag (similar to keyboard-protocols and mark-prompt)
to allow users to turn this off.
When the terminal fails to respond to primary device attribute, we
already print an error pointing to "help terminal-compatibility".
Inside that document, inside the "primary device attribute" section,
point out this new feature flag.
(not sure if we should also include this in 4.1 but I guess better
safe than sorry)
So far, terminals that fail to parse OSC sequences are the only reason
for wanting to turn off OSC 133. Let's allow to work around it by
adding a feature flag (which is implied to be temporary).
To use it, run this once, and restart fish:
set -Ua fish_features no-mark-prompt
Tested with
fish -i | string escape | grep 133 &&
! fish_features=no-mark-prompt fish -i | string escape | grep 133
Closes#11749
Also #11609
(cherry picked from commit 6900b89c82)
The problem described in 829709c9c4 (Replace synchronized update
workaround, 2025-04-25) doesn't seem too bad; let's document the
workaround.
We could probably also remove our $STY-based workaround. I'm not
yet sure how many problems that one will cause.
Closes#11437
We still have terminal-specific workarounds based on TERM_PROGRAM and
others, see test/test_driver.py. In future we should get rid of them.
They are also unreliable, potentially missing inside SSH/containers,
incorrect if a terminal was started from another terminal (#11812);
also TERM can be incorrect for many reasons.
The better criterion for terminal-specific workarounds is XTVERSION,
which has none of the above disadvantages.
Since some of the workarounds (tmux, iTerm2) need to be applied before
we draw the first prompt. This also means: before we read any config
because config may call builtin "read".
Do startup queries before reading config.
Some changes implied by this:
1. Remove a call to init_input() which is already done by env_init()
2. call initialize_tty_metadata() only after queries have returned
3. Since we call initialize_tty_metadata() before the first
call to tty.enable_tty_protocols() in Reader::readline(),
we can remove the redundant call from reader_interactive_init().
When poll() or read() on stdin fails, fish's interactive reader
pretends it has received SIGHUP, and subsequently exits.
I don't know if this is the right thing to do, or how to reproduce
this in a realistic scenario.
Unlike fish, fish_key_reader seems to ignore these failures, meaning
it will retry poll()/read() immediately. This seems less correct,
so use fish's behavior for now.
We do the same thing in several places, with lots of small differences.
Extract the most reasonable behavior and use it everywhere. Note that
we had an explictly-motivated ENOTTY check; the motivating issues
doesn't seem to reproduce anymore here though I did not bisect yet.
A process like "fish -i <somefile ..." probably shouldn't query
because it's not gonna work.
In future we could enable this by sending/receiving queries to/from
/dev/tty rather than stdout/stdin.
We are more conservative with querying on startup than we are with
querying for cursor position.
Part of this is oversight (if startup querying is not done, we
basically never get into a position where we query for cursor position,
outside extreme edge cases).
Also, some specific scenarios where we query for cursor position
inside, say, Midnight Commander, are not actually broken, because that
only happens when Midnight Commander gives us control. But let's
favor consistency for now; the Midnight Commander issue should be
fixed soon anyway.
Use the same logic in both cases.
A following commit wants to run the full initialize_tty_metadata()
only after querying XTVERSION.
But MC_TMPDIR needs to be checked before querying for XTVERSION.
Remove this cyclic dependency by extracting the MC_TMPDIR check.
Commands like
fish -C 'read'
create two top-level readers one after the other. The second one is
the fish REPL.
Both run some initialization of globals and parser variables. This is
weird; it should not be necessary.
Let's call reader_interactive_init() only once.
dvtm and abduco are two terminal session managers with the same
original.
Among other issues, they fail to reply to primary device
attribute. We have added a workaround for that based on
TERM=dvtm-256color (unreliable). A patch has been submitted for dvtm
https://lists.suckless.org/hackers/2502/19264.html
I don't know of a maintained fork (the original ones have had no
commit in 5 years) and there are better alternatives available
(shpool, tmux). They have other VT100 compatibility issues as well
(accidental DECRST; something like "ls" Tab Tab Tab causes spurious
bold and underline markup).
Also, as of the parent commit, failure to respond to primary DA is
no longer catastrophic. So let's remove the workaround. This means
that fish inside dvtm/abduco will pause for 2 seconds on startup and
print a warning (unless interrupted by ctrl-c).
Add a timeout of 2 seconds queries; if any query takes longer, warn
about that and reduce the timeout so we stop blocking the UI. This 2
second delay could also happen when network latency is momentarily
really high, so we might want relax this in future.
Note that this timeout is only triggered by a single uninterrupted
poll() (and measured from the start of poll(), which should happen
shortly after sending the query). Any polls interrupted by signals
or uvars/IO port before the timeout would be hit do not matter.
We could change this in future.
Closes#11108Closes#11117
Follow up the cursor position report query with a primary device
attribute one. When that one arrives, any cursor position response
must have arrived too. This allows us to prevent a hang on terminals
that only support primary device attribute.
Instead of switching only on the response type, switch on the
combination of that and the expected response. This helps the
following commits, which add more combinations (due to following up
cursor position report with a primary DA, and adding a timeout). No
behavior change here.
- document that we currently require "cursor position report" if
either of both click_events or XTGETTCAP+indn is implemented.
One of the following patches will remove this requirement.
- document properly that scrollback-push currently only works
when XTGETTCAP+indn is implemented. There are still a few terminals
that don't support SCROLL UP, for example the Linux Console,
and there is no better way to find out if it's supported.
Users have tried to get a list of all tokens -- including operators
-- using "commandline --tokens-raw". That one has been deprecated
by cc2ca60baa (commandline.rst: deprecate --tokens-raw option,
2025-05-05). Part of the reason is that the above command is broken
for multi-line tokens.
Let's support this use case in a way that's less ambiguous.
Closes#11084
The previous version results in an immediate workflow failure due to a
syntax error in the YAML. `workflow_dispatch` should be a dictionary
key, with its value being another dictionary (whose only key is `inputs`
at the moment).
Release automation can be tested on any GitHub fork, using
build_tools/release.sh $version $repository_owner $git_remote
which should work perfectly except for macOS packages (which fail
unless provided GitHub secrets).
People might push tags to their forks, both non-release tags (which
would trigger an early failure in "is-release-tag") or replicas of
our actual release tags (which would create a draft release etc. and
only fail when building macOS packages).
Run on explicit workflow dispatch to make sure it's not triggered by
accident like that.
This means that we'll use the .github/workflows/release.yml from
the default branch (i.e. master), so try to make sure it matches the
version in the release, to prevent accidents.
Closes#11816
When connecting to MPD via a Unix socket, mpc add and insert accept
absolute paths to local files. Offer these in the completion if the
completed token starts with a slash after expansion.
Since 0fea1dae8c (__fish_print_help: Make formatting more man-like,
2024-10-03), there is barely any difference left between "man abbr"
and "abbr -h".
The main difference is that it looks almost like man but is actually
nroff/mandoc and less. This means it doesn't support environment
variables like MANWIDTH and possibly others.
Let's use full "man" for now.
This matches what "git foo --help" does so it's widely accepted.
Keep around a fallback for a while, in case users/packagers fail to
install the new "man" dependency.
In future, "abbr -h" (as opposed to "abbr --help") could show a more
concise version, not sure.
Closes#11786
__fish_print_help supports printing an error message above the
documentation.
This is currently only used by extremely rare edge cases, namely:
eval "break"
eval "continue --unknown"
fish -c 'sleep 10&; bg %1'
Let's remove this feature to enable us to use man directly (#11786).
fish -c 'sleep 1 & bg %1' is supposed to fail because the job is not
under job control.
When we try to print the failure, we accidentally still
hold a borrow of the job list. This blows up because we use
"builtin_print_help_error()" to print the failure message; that
function runs "job_reap()" which wants an exclusive borrow of the
job list. Let's drop our job list earlier.
These are not generic builtins because we check whether they're inside
a loop. There's no reason to not support "break -h" when we support
"if -h" etc.; do that.
With upcoming multi-line autosuggestions, when I run
$ function foo
true
end
and type "function", then I'll get a suggestion for the above command.
Now if press "alt-w", it will echo "function - create a function"
and rewdraw the prompt below. But the previous autosuggestion is
not cleared, so it will look weird like:
johannes@abc ~/g/fish-shell> function foo
function - create a function true
Let's erase these lines before writing them.
There's an issue remaining: the first line of the autosuggestion
(i.e. "foo") is not erased. Fortunately this is less annoying,
but it shows that __fish_echo needs more support from core.
When running a debug build, rust-embed always sources files from disk.
This is currently broken with on Cygwin.
As a temporary workaround, use the "debug-embed" feature to actually
embed the files into the binary, like we do for release builds.
We can probably fix the rust-embed issue fairly easily.
I haven't checked. For now, I think this hack is preferrable to
not having an easy way to make debug builds on Cygwin. (CMake
files would need some changes, and I also hit some problems with
installation). At least this would have helped with investigating
https://github.com/msys2/msys2-runtime/issues/308
Commit 50a6e486a5 (Allow explicit shift modifier for non-ASCII
letters, fix capslock behavior, 2025-03-30) delayed handling of kitty
keyboard protocol's shifted codepoints. It does handle shifted
codepoints when matching keys to mappings; but it fails to handle
them in the self-insert code paths where we want to insert the text
represented by CharEvent::Key.
Fix it by resolving the shifted key.
Fixes#11813
These tests require building with the `localize-messages` feature.
If certain translations are updated, this test might fail, either
because a message was changed in the source, or because a translation of
a message was changed, or because a translation was added in a language
which previously did not have a translation for a particular message,
and we rely on that in the test. If any of these happen, the tests need
to be updated accordingly.
Closes#11726
The locale path was used to tell GNU gettext where to look for MO files
at runtime. Since we now embed the message catalog data into the
executable, we no longer need a locale path.
Part of #11726
This completely removes our runtime dependency on gettext. As a
replacement, we have our own code for runtime localization in
`src/wutil/gettext.rs`. It considers the relevant locale variables to
decide which message catalogs to take localizations from. The use of
locale variables is mostly the same as in gettext, with the notable
exception that we do not support "default dialects". If `LANGUAGE=ll` is
set and we don't have a `ll` catalog but a `ll_CC` catalog, we will use
the catalog with the country code suffix. If multiple such catalogs
exist, we use an arbitrary one. (At the moment we have at most one
catalog per language, so this is not particularly relevant.)
By using an `EnvStack` to pass variables to gettext at runtime, we now
respect locale variables which are not exported.
For early output, we don't have an `EnvStack` to pass, so we add an
initialization function which constructs an `EnvStack` containing the
relevant locale variables from the corresponding Environment variables.
Treat `LANGUAGE` as path variable. This add automatic colon-splitting.
The sourcing of catalogs is completely reworked. Instead of looking for
MO files at runtime, we create catalogs as Rust maps at build time, by
converting PO files into MO data, which is not stored, but immediately
parsed to extract the mappings. From the mappings, we create Rust source
code as a build artifact, which is then macro-included in the crate's
library, i.e. `crates/gettext-maps/src/lib.rs`. The code in
`src/wutil/gettext.rs` includes the message catalogs from this library,
resulting in the message catalogs being built into the executable.
The `localize-messages` feature can now be used to control whether to
build with gettext support. By default, it is enabled. If `msgfmt` is
not available at build time, and `gettext` is enabled, a warning will be
emitted and fish is built with gettext support, but without any message
catalogs, so localization will not work then.
As a performance optimization, for each language we cache a separate
Rust source file containing its catalog as a map. This allows us to
reuse parsing results if the corresponding PO files have not changed
since we cached the parsing result.
Note that this approach does not eliminate our build-time dependency on
gettext. The process for generating PO files (which uses `msguniq` and
`msgmerge`) is unchanged, and we still need `msgfmt` to translate from
PO to MO. We could parse PO files directly, but these are significantly
more complex to parse, so we use `msgfmt` to do it for us and parse the
resulting MO data.
Advantages of the new approach:
- We have no runtime dependency on gettext anymore.
- The implementation has the same behavior everywhere.
- Our implementation is significantly simpler than GNU gettext.
- We can have localization in cargo-only builds by embedding
localizations into the code.
Previously, localization in such builds could only work reliably as
long as the binary was not moved from the build directory.
- We no longer have to take care of building and installing MO files in
build systems; everything we need for localization to work happens
automatically when building fish.
- Reduced overhead when disabling localization, both in compilation time
and binary size.
Disadvantages of this approach:
- Our own runtime implementation of gettext needs to be maintained.
- The implementation has a more limited feature set (but I don't think
it lacks any features which have been in use by fish).
Part of #11726Closes#11583Closes#11725Closes#11683
The extracted release notes trigger a sphinx warning
/tmp/tmp.V6RGP92nc2/src/index.rst:6:Document may not end with a transition.
which we don't seem to get on the full CHANGELOG.rst.
Let's work around that for now.
I'd like to move to a process where everything goes into master first,
and then flows downstream to any release branches (i.e. no merging
of Integration_* branches back into master).
The only thing we need to change for that is to add release notes for
patch releases eagerly on master. That implies that we want to use
the actual version instead of ???. (Only if something goes wrong
in the release process, we need to change this on both branches,
but that should happen too often.)
Given
bind up "echo user up, new notation"
bind \e\[A "echo user up, legacy notation"
prior to b9d9e7edc6 (Match bindings with explicit shift
first, 2025-05-24), we prioritized the legacy notation because
input_mapping_insert_sorted() makes us try longer sequences first --
and "up" is only one key compared to the three-key legacy sequence.
This prioritization was broken in b9d9e7edc6, causing plugins that
update to the "bind up" notation to break users who haven't (#11803).
Even worse, it caused preset bindings to shadow user ones:
bind --preset up "echo preset up, new notation"
bind \e\[A "echo user up, legacy notation"
Restore backwards compatibility by treating matches against legacy
notation like exact matches again.
The only install directory that's not supported is
-DCMAKE_INSTALL_PREFIX=$CARGO_MANIFEST_DIR, but that's a bad idea
anyway since share/ is Git-tracked.
On a system where _CS_PATH is not defined (tested by removing that
code path), we get:
$ cargo b && env -u PATH HOME=$PWD target/debug/fish -c 'set -S PATH'
$PATH[1]: |.local//bin|
$PATH[2]: |/usr/bin|
$PATH[3]: |/bin|
The relative $PATH[1] makes no sense; probably it's an
accident. Restore the traditional $PATH[1]=/usr/local/bin.
Commit bf65b9e3a7 (Change `gettext` paths to be relocatable (#11195),
2025-03-30) made the locale directory (/usr/local/share/locale)
relocatable as well, so that "mv /usr/local /usr/local2" would not
break translations.
But this introduces a weird circular dependency, which was probably
the reason why the locale directory hadn't been relocatable:
1. option parsing might fail and print error messages, which should
be localized, hence require detection of config paths
2. detection of config paths calls `FLOG`, which depends on options
parsing (e.g. "-d config -o /tmp/log")
Since commit bf65b9e3a7, fish initializes the config paths
lazily, as soon as needed by translations.
When initializing config paths, we produce logs. The logs are off by
default so its' fine in practical cases, but technically we should only
log things after we have handled things like FISH_DEBUG_OUTPUT.
Here's an example where the config directory initialization sneakily
injected by an error message's "wgettext_fmt!" causes logs to be
printed to the wrong file spuriously:
$ FISH_DEBUG='*' FISH_DEBUG_OUTPUT=/tmp/log build/fish --unknown-arg
config: exec_path: "./build/fish", argv[0]: "./build/fish"
config: paths.sysconf: ./etc
config: paths.bin: ./build
config: paths.data: ./share
config: paths.doc: ./user_doc/html
config: paths.locale: ./share/locale
fish: --unknown-arg: unknown option
Now we could handle "-d config", "-o", and FISH_DEBUG later, but
that would mean that in this example we don't get any logs at all,
which doesn't seem correct either.
Break the circular dependency by determining config paths earlier,
while making sure to log the config path locations only after parsing
options, because options might affect whether we want to log the
"config" category.
The global variable is only needed for locale, so use explicit argument
passing for everything else, as before.
While at it, make other binaries (fish_key_reader, fish_indent) use
the same localization logic as fish. This means that we need to tweak
the «ends_with("bin/fish")» check.
Closes#11785
This makes no sense:
$ target/debug/fish -d config
config: paths.doc: .local/share/doc/fish
so remove it.
While at it, group config paths by whether they can be embedded.
Rather than having every single config path be an Option<Path>,
clarify that we define either all or nothing.
If we want to decide this at runtime, we'd use an enum; but it's all
known at compile time, so we can give the reader even more information.
Unfortunately this means that compile errors in non-embed-data
code paths might go unnoticed for a while, and rust-analyzer often
doesn't work in those code paths. But that's a general problem with
the compile-time feature, it seems orthodox to ifdef away as much
as possible.
There are some odd data paths that don't follow the "all or nothing",
the next commits will fix this.
Note that this breaks localization for target/debug/fish built with
embed-data. But as soon as fish was moved out of the repo, that was
already broken.
Commit 3dc49d9d93 (Allow installable builds to be installed into a
specific path (#10923), 2024-12-22) added some ifdefs to use installed
config paths for installable builds that have already been installed.
The "installable" feature has been superseded by "embed-data"
which no longer uses config paths to retrieve files,
so remove those code paths. Further cleanup to follow.
Assuming every in-tree build uses CMake, the source tree must
also be a valid build directory, so we already return in the
env!("FISH_BUILD_DIR") code path above.
Commit 8b102f2571 (Stop using Cargo's OUT_DIR,
2025-06-22) accidentally removed canonicalization of
FISH_BUILD_DIR=${CMAKE_BINARY_DIR}. This means that if the path to
${CMAKE_BINARY_DIR} includes a symlink, ${CMAKE_BINARY_DIR}/fish will
wrongly use /usr/share/fish instead of ${CARGO_MANIFEST_DIR}/share.
Fix this and reintroduce the comment.
That configuration is already tested, but not clippy-checked yet.
This sometimes causes things like unused imports linger on master.
Let's at least enable clippy for stable Rust.
Also do the same build_tools/check.sh; since that script already runs
"cargo test --no-default-features", this shouldn't add much work,
though I didn't check that.
We do not need timestamps of embedded files, so setting them to 0
reduces the potential for unwanted changes to the binary, allowing for
better build reproducibility.
Also check that "cd fish-site && make && make new-release" doesn't
leave behind untracked files we're not aware of. This implies that
this script ought to refuse to run if there are untracked files,
at least in fish-site.
Things that are not currently happening in this workflow:
- No GPG-signature on the Git tag
- No *.asc signature file for the tarball (or for any other release assets)
- No GPG-signed Debian and other OBS packages
To-do:
- remove the corresponding entries from
https://github.com/fish-shell/fish-shell/wiki/Release-checklist
and link to this workflow.
- Maybe add some testing (for the Linux packages)?.
- Let's hope that this doesn't cause security issues.
Usage:
1. run "build_tools/release.sh $version"; this will create and push
a tag, which kicks off .github/workflows/release.yml
2. wait for the draft release to be created at
https://github.com/fish-shell/fish-shell/releases/tags/$version
3. publish the draft (manually, for now). This should unblock the
last part of the workflow (website updates).
Closes#10449
Incremental usage example:
version=4.0.3
repository_owner=fish-shell
remote=origin
cd ../fish-shell-secondary-worktree
git tag -d $version ||:
git push $remote :$version ||:
git reset --hard origin/Integration_$version
for d in .github build_tools; do {
rm -rf $d
cp -r ../fish-shell/$d .
git add $d
} done
git commit -m 'Backport CI/CD'
echo "See https://github.com/$repository_owner/fish-shell/actions"
echo "See the draft release at https://github.com/$repository_owner/fish-shell/releases/$version"
../fish-shell/build_tools/release.sh $version $repository_owner $remote
We use the MSRV for CI checks, and for deploying to old macOS.
But for static Linux builds , there should be no reason to use an
old Rust version. Let's track stable.
Resolves issue #3126
To match what I've been able to figure out about the existing design
philosophy, case-sensitive matches still always take priority,
but case-insensitive history suggestions precede case-insensitive
completion suggestions.
systemd 242 added two new options to halt, poweroff, and reboot:
--boot-loader-entry: Reboot to a specific boot loader entry
--boot-loader-menu: Reboot into boot loader menu with specified
timeout
Add these to the systemctl completion so that it is easy to
interactively select available entries.
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
As reported in
https://github.com/fish-shell/fish-shell/issues/11767#issuecomment-3240198608,
the new "man" function uses "rm" which is sometimes overidden to do
"rm -i".
Same as d3dd9400e3 (Make sure the rm command and not a wrapper
function that could change its behaviour is used. 2006-12-12)
While at it, make sure that all users of __fish_mktemp_relative
1. return if mktemp fails
2. actually clean up their temporary directory -- except for help.fish
which spawns an asynchronous browser window.
Not sure about whether "man fish-terminal-compatibility"; it's not
really meant for end-users, but it also doesn't hurt raise awareness
of the existence of this doc.
Either way, we should be consistent with embedded builds, where this
works since the parent commit.
"man abbr" works in embed-data builds,
but "man fish-faq" doesn't.
This is because it delegates to
__fish_print_help fish-faq
which skips all lines until the NAME section:
contains -- $name NAME; and set have_name 1
but the NAME section doesn't exist for this man pages, it only exists
for docs from doc_src/cmds/*.rst.
Let's use the "man" utility instead; this is also what the user
asked for. Unfortunately we can't use "status get-file | man -l -"
because that's not supported on BSD man. Note that man displays the
basename of the file, so make sure it looks good.
BSD mktemp doesn't support GNU mktemp's -t or --tmpdir option, so when
we want a named temporary file, we need to compute ${TMPDIR:-/tmp}
ourselves, see 5accc7c6c5 (Fix funced's tmpfile generation on OSX,
2016-05-23).
While at it, use template like "fish.XXXXXX"; seems like a good idea?
Take care to have edit_command_buffer use a pretty filename.
The --center option does exactly what you'd expect. When a
perfectly centred result is not possible, this adds extra padding to
the left. If the --right option is also given, the extra padding is
added to the right.
This new flag causes fish_opt to generrate an option spec with !
(e.g. "fish_opt -s s -rv some code" will output "s=!some code").
Such validation scripts are not particular useful (they are highly limited as
they cannot access the values for other options, and must be quoted
appropriately so they can be passed to argparse). I merely added the option to
fish_opt so that it can now generate any valid option spec.
Specifically, this commit simply makes argparse issue an error if you use the !
syntax to define a validation script on an option that does not take any
arguments. For example, "argparse foo!exit -- --foo" is now an error. This was
previously accepted, despite that fact that the code after ! would never be
executed (the ! code is only executed when an option is given a value).
Alternatively, ! validation scripts could be made to execute even when no value
was provided, but this break existing code that uses them with flags that take
optional values.
This fixes an issue noticed in the previous commit (the made the -s/--short
option optional to fish_opt): it was impossible to define a single character
long flag, unless you also provided a single-character short flag equivalent.
This commit works by allowing an option spec to start with a '/', treating the
subsequent alpha-numeric characters as a long flag name.
In detail, consider the following:
- s defines a -s short flag
- ss defines an --ss long flag
- /ss (new) also defines a --ss long flag
- s/s defines a -s short flag and an --s long flag
- s-s defines a --s long flag (if there's already an -s short flag, you'd have
to change the first s, e.g. S-s)
- /s (new) defines a --s long flag
- s/ is an error (a long flag name must follow the /)
Note that without using --strict-longopts, a long flag --s can always be
abbreviated as -s, provided that -s isn't defined as a separate short flag.
This 'issue' fixed by this commit is relatively trivial, however it does allow
simplifying the documentation for fish_opt (since it no longer needs to mention
the restriction). In particular, this commit makes the --long-only flag to
fish_opt completely unnecessary (but it is kept for backwards compatibility).
Specifically, this now makes the -s/--short option to fish_opt optional when the
-l/--long option is given. This commit does not modify argparse, as it already
supports defining long flags without a corresponding short flag, however
fish_opt would never take advantage of this feature.
Note that due to a limitation in argparse, fish_opt will give an error if you
try to define a one-character --long flag without also providing a --short
option.
For backwards compatibility, the --long-only flag is still included with
fish_opt, and when used with -s/--short, will behave as before (the short flag
is still defined, but argparse will fail if it is actually used by the parsed
arguments, moreover the _flag_ option variables will not be defined). This can
however be used to define a one character long flag.
This commit fixes#8432 by adding put =* in an option spec to indicate that the
option takes an optional value, where subsequent uses of the option accumulate
the value (so the parsing behaviour is like =?, but the _flag_ variables are
appended to like =+). If the option didn't have a value, it appends an empty
string. As an example,. long=* -- --long=1 --long will execute
set -l _flag_long 1 '' (i.e. count $_flag_long is 2), whereas with =? instead,
you'd get set -l _flag_long (i.e. count $_flag_long is 0).
As a use case, I'm aware of git clone which has a
--recurse-submodules=[<pathspec>]: if you use it without a value, it operates on
all submodules, with a value, it operates on the given submodule.
The fish_opt function will generate an =* option spec when given both the
--optional-val and --multiple-vals options (previously, doing so was an error).
fish_opt now also accepts -m as an abbreviation for --multiple-vals, to go with
the pre-existing -o and -r abbreviations for --optional-val and --required-val.
The new -U/--unknown-arguments option takes either 'optional', 'required', or
'none', indicating how many arguments unknown options are assumed to take.
The default is optional, the same behaviour as before this commit, despite
most options in practice taking not taking any arguments. Using
--unknown-arguments=required and --unknown-arguments=none (but not
--unknown-arguments=optional) can give you parse errors if, respectively,
an unknown option has no argument (because it the option is at the end of the
argument list), or is given an argument (with the `--flag=<value> syntax).
See doc_src/cmds/argparse.rst for more details (specifically, the descritpion
of the --unknown-arguments flag and the example at the end
of the examples section).
As a convenience, -U/--unknown-arguments implies -u/--move-unknown.
However you can use it the deprecated -i/--ignore-unknown if you really want to.
This just uses an ArgType and 'accumulate_args' bool in place of the old
ArgCardinality. Curently only one of the three kinds of an ArgType can
have both a true and false accumulate_args. But this will be extended to
two of three in a future commit.
This flag disables a very surprising and confusing feature I found in the code
of wgetopt.rs: the ability to abbreviate the names of long options and the
ability to parse long options with a single "-". This commit addresses #7341,
but unlike pull request #11220, it does so in a backwards compatible way: one
must use the new -S/--strict-longotps flag to disable the old legacy behaviour.
Unlike pull request #11220 however, this flag only applies to ``argparse``,
and not to any builtins used by fish.
Note that forcing the flag -S/--strict-longotps on (i.e. in src/wgetopt.rs,
replacing both uses of `self.strict_long_opts` with `true`), does not cause any
of the current test cases to fail. However, third-party fish scripts may be
depending on the current behaviour.
This fixes an issue very similar to #6483,
For example, fish --login=root used to print this:
fish: --login=root: unknown option
But `--login` is a valid option to fish.
So the above now prints:
fish: --login=root: option does not take an argument
This is done by modifying WGetOpter so that it returns a ';' if it encountered
an option with an argument, but the option was not declared as taking an option
(this is only possible with the --long=value or legacy -long=value syntax).
All uses of WGetOpter (except echo, fish_indent, and some tests) are modified to
then print an appropriate error message when ';' is returned.
echo doesn't have any long options, so it will panic if gets a ';'.
fish_indent doesn't print any error messages for invalid options anyway, and I
wasn't sure if this was intentional or not.
Moreover, WGetOpter now always returns a ':' for options that are missing an
argument. And you can no longer prefix a your option spec with a ':' to enable
this (since every use of WGetOpter was doing this anyway, except
wgetopt::test_exchange and tests::wgetopt::test_wgetopt).
This removes the functions/completions that were using the deprecated
--ignore-unknown option and replaces it with the new --move-unknown.
Although some of the code is now more verbose, it has improved the
functionality of two completions:
the iwctl completion will now skip over options when detecting
what subcommand is being used
the ninja completion wil now handle -- correctly: if the completion
internally invokes ninja, it will correctly interpret the users
arguments as being arguments if they start with a - and occur
after the --.
--move-unknown is like --ignore-unknown, but unknown options are instead moved
from $argv to $argv_opts, just like known ones. This allows unambiguously
parsing non-option arguments to other commands. For example if $argv contains
`--opt -- --file`, and we execute `argparse --move-unknown -- $argv`, we can
then call `cmd $argv_opts -- --another-file $argv`, which will correctly
interpret `--opt` as an option, but `--file` and `--some-file` as an argument.
This makes `--move-unknown` a better alternative to `--ignore-unknown`, so the
latter has been marked as deprecated, but kept for backwards compatibility.
For example, argparse --ignore-unknown h -- -ho will now set set $argv to -o and
$argv_opts to -h (i.e. -ho is split into -h and -o). Previously, it would set
$argv to -ho, and $argv_opts to empty. With this change, the "Limitations"
section of argparse's man page has been removed, and the examples merged into
the description of the -i/--ignore-unknown option. (Note: there was another
'limitation' mentioned in the 'limitations' section: that everything occuring
after an unknown option in a group was considered an argument to an option; the
documentation has been reworded to make it clear that this is intended
behaviour, as unknown options are always treated as taking optional arguments,
and modifying that behaviour would be a breaking change and not a bug fix).
The intention is that if you want to parse some of your options verbatim to
another command, but you want to modfy other options (e.g. change their value,
convert them to other options, or delete them entirely), you mark the options
you want to modify with an &, and argparse will not add them to argv_opts. You
can then call the other command with argv_opts together with any new/modified
options, ensuring that the other command doesn't set the pre-modified options.
As with other known options, & options will be removed from $argv, and have
their $_flag_ variables set.
The `&` goes at the end of the option spec, or if the option spec contains a
validation script, immediately before the `!`. There is also now a -d/--delete
flag to fish_opt that will generate such an option spec.
See the changes in doc_src/cmds/argparse.rst for more details and an example use
case.
The previous fish_opt synopsis was hard to parse, and was incorrect:
- it indicated that -s is optional
- it indicated that only one option could be provided
- it indicated that every option took a value
Specifically, every argument (other than the first --, if any) that argparse
doesn't add to $argv is now added to a new local variable $argv_opts. This
allows you to make wrapper commands that modify non-option arguments, and then
forwards all arguments to another command. See the new example at the end of
doc_src/cmds/argparse.rst for a use case for this new variable.
By wrapping the various argparse tests in begin ... end blocs, it makes it much
easier to debug test failures and add new tests. In particular, each block is
independent, and shouldn't affect any subsequent tests. There's also now a check
at the end of the test file to ensure that the tests are no longer leaking local
variables.
The .md and .rst files allready present do not hard wrap lines (the
style seems to be one line per paragraph, which could be a few hundred
characters long). So this makes those files have no line length limit,
instead of 100.
So far, terminals that fail to parse OSC sequences are the only reason
for wanting to turn off OSC 133. Let's allow to work around it by
adding a feature flag (which is implied to be temporary).
To use it, run this once, and restart fish:
set -Ua fish_features no-mark-prompt
Tested with
fish -i | string escape | grep 133 &&
! fish_features=no-mark-prompt fish -i | string escape | grep 133
See #11749
Also #11609
systemd's session_id_valid accepts [a-zA-Z0-9], so allowing only
numbers is wrong.
Fixes#11754
While at it, correct the description; instead of
showing the leader PID, show the seat, which is probably
The is inconsistent with the type annotation of `TestPass.duration_ms`.
The function is only called with `duration_ms` as an int, so there is no
need to declare it `Optional`.
Newer versions of cargo include the Cargo.toml.orig file when vendoring,
but dh_clean removes those by default. Try to disable this to fix the
package builds again.
Building man pages takes significant time due to Sphinx running for several
seconds, even when no updates are required. Previously, we added custom logic to
avoid calling `sphinx-build` if the inputs to `sphinx-build` had not changed
since a cached timestamp.
By moving this into its own crate, we can tell cargo to rebuild when the input
files changed and unrelated changes will have no effect on this crate. This
allows us to get rid of the custom code for tracking whether to recompile, while
keeping the effect of only calling `sphinx-build` when appropriate.
In order to avoid code duplication, a new `build-helper` crate is added,
which contains some functionality for use in `build.rs`.
Closes#11737
This allows building man pages without having `fish_indent` available, which is
useful because building man pages can happen during compilation of the fish
binaries, including `fish_indent`, resulting in an annoying cyclic dependency.
This change does not affect the generated man pages, at least with the current
config.
Depending on `fish_indent` when building docs is problematic because the docs
might get built before `fish_indent` is available. Furthermore, a version of
`fish_indent` which does not correspond to the current build might be used,
which would result in incorrect version information.
Use the `git_version_gen.sh` script instead to ensure up-to-date version
information without depending on build output.
This allows us to track all dependencies in a single place and
automatically avoids using different versions of the same dependency in
different crates.
Sort dependencies alphabetically.
Closes#11751
Cargo tracks normal Rust dependencies and automatically figures out if changes
to Rust source files, `Cargo.{toml,lock}`, and `build.rs` necessitate a rebuild,
and if so of what. In some cases these checks are smarter than just comparing
file modification times, so not specifying such paths explicitly can reduce the
amount of rebuilding which happens, without skipping necessary rebuilding.
ja: this reverts b2aaf1db52 (Rebuild if src changed, 2025-03-28) and
460b93a (Rebuild on changes relevant to build artifacts, 2025-03-30)
which tried to fix#11332 ("moving Git HEAD does not invalidate cargo
build results"). But that expectation is overbearing. It's better
to only rebuild if something else of relevance to the build output
has changed.
Closes#11736
With an increasing number of local dependencies, the repo root is getting
somewhat bloated. This commit moves the two current local dependencies into the
newly created `crates` directory, with the intention of using it for all future
local dependencies as well.
Some dependencies which are introduced by currently in-progress pull requests
will need modifications in order for relative paths to work correctly.
This allows having the proc macro crate as an optional dependency and speeds up
compilation in situations where `FISH_GETTEXT_EXTRACTION_FILE` changes, such as
the `build_tools/check.sh` script. Because we don't need to recompile on changes
to the environment variable when the feature is disabled, cargo can reuse
earlier compilation results instead of recompiling everything.
This speeds up the compilation work in `build_tools/check.sh` when no changes
were made which necessitate recompilation.
For such runs of `build_tools/check.sh`, these changes reduce the runtime on my
system by about 10 seconds, from 70 to 60, approximately.
The difference comes from the following two commands recompiling code without
the changes in this commit, but not with them:
- `cargo test --doc --workspace`
- `cargo doc --workspace`
There is an unlikely issue if two shells are concurrently rewriting the
history file:
- fish A runs rename("fish_history.DEADBEEF") (rewriting a history file with)
- fish B starts rewriting the history file; since "fish_history.DEADBEEF" no longer exists, it can in theory use that filename
- fish A runs wunlink("fish_history.DEADBEEF"), destroying fish B's work
Fix this by not calling wunlink() iff we successfully rename it.
[ja: add commit message and fix "!do_save" case]
Building a buffer in advance and writing it once all items are serialized into
the buffer makes for simpler code, makes it easier to ensure that
`self.first_unwritten_new_item_index` is only updated if writing succeeded, and
it actually matches the previous behavior of the code in most realistic cases,
since previously there was only more than one `write_all` call if the serialized
items took up more than `HISTORY_OUTPUT_BUFFER_SIZE` bytes (64 * 1024), which
seems unlikely to occur during normal use, where mostly just a single item will
be appended.
This should not result in behavioral changes in the code, but it eliminates some
redundant variables and is a step in refactoring the function such that early
returns via `?` become sound.
Remove the `drop` since the lock will be dropped at this point anyway, there is
no need to be explicit about it.
This restores behavior from before f438e80f9b.
The file id changes when data is written to the file, so it needs to be updated
with data obtained after the updates to the file are completed.
By default, we make every rustup user use our pinned version. This might
not be ideal at this point, for a few reasons:
1. we don't have automatic Rust updates yet (see the parent commit),
so this might unnecessarily install an old version. As a contributor,
this feels irritating (newer versions are usually strictly better).
2. it will use more bandwidth and perhaps other resources during "git-bisect"
scenarios
3. somehow rustup will download things redundantly; it will download "1.89.0"
and "stable" even if they are identical. The user will need to clean
those up at some point, even if they didn't add them explicitly.
See also
https://github.com/fish-shell/fish-shell/pull/11712#issuecomment-3165388330
Part of the motivation for rust-toolchain.toml is probably the regular
(every 6 weeks) failures due to the update check, but that failure has been
removed in the parent commit.
The other motivation ("fix the issue of local compiles running into lint
warnings from newer compilers") is a fair point but I think we should rather
fix warnings quickly.
Let's remove rust-toolchain.toml again until we have more agreement on what
we should do.
This reverts commits
* f806d35af8 (Ignore rust-toolchain.toml in CI, 2025-08-07)
* 9714b98262 (Explicitly use fully qualified rust version numbers, 2025-08-07)
* 921aaa0786 (Add rust-toolchain.toml, 2025-08-07)
Closes#11718
As reported in #11711 and #11712, the update-checks make check.sh automatically
fail every 6 weeks, so it pressures people into updating Rust, and (what's
worse), updating fish's pinned Rust version, even when that's not relevant
to their intent (which is to run `clippy -Dwarnings` and all other checks).
The update-checks were added as a "temporary" solution to make sure that
our pinned version doesn't lag too far behind stable, which gives us an
opportunity to fix new warnings before most contributors see them.
As suggested in #11584, reasonable solutions might be either of:
1. stop pinning stable Rust and rely on beta-nightlies to fix CI failures early
2. use renovatebot or similar to automate Rust updates
Until then, remove the update check to reduce friction.
I'll still run it on my machine.
This reverts commit 6d061daa91.
These changes are not intended to change any behavior. They are done to
facilitate closing the tmpfile before renaming, which is required for
correctness on some filesystems (at least btrfs). Using a `ScopeGuard` which
unlinks when the file is closed/dropped does not work in this context, so the
relevant code is wrapped in a function and the tmpfile is unlinked after the
function returns.
This ensures that, by default, developers use the toolchain that is also tested
in CI, avoiding spurious warnings from lints added in new compiler versions.
After #9542, the format for `functions -Dv` was changed for copied
functions.
```diff
-stdin
-n/a
+[path to copy location]
+[path to original definition]
[and a few more lines]
```
Some components were (and perhaps are) still expecting the old format,
however. After a search, it looks like `funced` and `fish_config` are
the only two functions using `functions -D` and `functions -Dv` in this
repo (none are using `type -p`).
As noted in issue #11614, `funced` currently edits the file which
copies the given copied function. Another option was to make `funced`
edit the file which originally defined the function. Since the copied
function would not have been updated either way, I modified `funced` so
it would pretend that the copied function was defined interactively,
like it was before.
I did not modify `fish_config`, since it was only used for preset
prompts in the web config, none of which used `functions --copy`.
(Moreover, I believe it would have behaved correctly, since the preset
would not have had to define the function, only copy it.)
Fixes issue #11614
The fish.png doc image has grey pixel artifacts in the
top-left, top-right, and bottom-right corners.
This patch takes the original image from 3a5b096
removes the artifacts, and compresses it with squoosh
to a similar file size.
This is standard on macOS and in chrome/firefox.
On master, this was sneakily added in
2bb5cbc959 (Default bindings for token movements v2, 2025-03-04)
and before that in
6af96a81a8 (Default bindings for token movement commands, 2024-10-05)
Ref: https://lobste.rs/s/ndlwoh/wizard_his_shell#c_qvhnvd
Cherry-picked from
- 941701da3d (Restore some async-signal discipline to SIGTERM, 2025-06-15)
- 81d45caa76e (Restore terminal state on SIGTERM again, 2025-06-21)
Also, be more careful in terminal_protocols_disable_ifn about accessing
reader_current_data(), as pointed out in 65a4cb5245 (Revert "Restore terminal
state on SIGTERM again", 2025-07-19).
See #11597
Historically, fish has treated input bytes [0x1b, 'b'] as alt-b (rather than
"escape,b") if the second byte arrives within 30ms of the first.
Since we made builtin bind match key events instead of raw byte sequences,
we have another place where we do similar disambiguation: when we read keys
such as alt-left ("\e[1;3D"), we only consider bytes to be part of this
sequence if stdin is immediately readable (actually "readable after a 1ms
timeout" since e1be842 (Work around torn byte sequences in qemu kbd input
with 1ms timeout, 2025-03-04)).
This is technically wrong but has worked in practice (for Kakoune etc.).
Issue #11668 reports two issues on some Windows terminals feeding a remote
fish shell:
- the "bracketed paste finished" sequence may be split into multiple packets,
which causes a delay of > 1ms between individual bytes being readable.
- AutoHotKey scripts simulating seven "left" keys result in sequence tearing
as well.
Try to fix the paste case by increasing the timeout when parsing escape
sequences.
Also increase the timeout for terminals that support the kitty keyboard
protocol. The user should only notice this new delay after pressing one of
escape,O, escape,P, escape,[, or escape,] **while the kitty keyboard protocol
is disabled** (e.g. while an external command is running). In this case,
the fish_escape_delay_ms is also virtually increased; hopefully this edge
case is not ever relevant.
Part of #11668
(cherry picked from commit 30ff3710a0)
Historically, fish has treated input bytes [0x1b, 'b'] as alt-b (rather than
"escape,b") if the second byte arrives within 30ms of the first.
Since we made builtin bind match key events instead of raw byte sequences,
we have another place where we do similar disambiguation: when we read keys
such as alt-left ("\e[1;3D"), we only consider bytes to be part of this
sequence if stdin is immediately readable (actually "readable after a 1ms
timeout" since e1be842 (Work around torn byte sequences in qemu kbd input
with 1ms timeout, 2025-03-04)).
This is technically wrong but has worked in practice (for Kakoune etc.).
Issue #11668 reports two issues on some Windows terminals feeding a remote
fish shell:
- the "bracketed paste finished" sequence may be split into multiple packets,
which causes a delay of > 1ms between individual bytes being readable.
- AutoHotKey scripts simulating seven "left" keys result in sequence tearing
as well.
Try to fix the paste case by increasing the timeout when parsing escape
sequences.
Also increase the timeout for terminals that support the kitty keyboard
protocol. The user should only notice this new delay after pressing one of
escape,O, escape,P, escape,[, or escape,] **while the kitty keyboard protocol
is disabled** (e.g. while an external command is running). In this case,
the fish_escape_delay_ms is also virtually increased; hopefully this edge
case is not ever relevant.
Part of #11668
readb() has only one caller that passes blocking=false: try_readb().
This function is used while decoding keys; anything but a successful read
is treated as "end of input sequence".
This means that key input sequences such as \e[1;3D
can be torn apart by
- signals (EINTR) which is more likely since e1be842 (Work around torn byte
sequences in qemu kbd input with 1ms timeout, 2025-03-04).
- universal variable notifications (from other fish processes)
Fix this by blocking signals and not listening on the uvar fd. We do something
similar when matching key sequences against bindings, so extract a function
and use it for key decoding too.
Ref: https://github.com/fish-shell/fish-shell/issues/11668#issuecomment-3101341081
(cherry picked from commit da96172739)
try_readch() was added to help a fuzzing harness, specifically to avoid a
call to `unreachable!()` in the NothingToRead case. I don't know much about
that but it seems like we should find a better way to tell the fuzzer that
this can't happen.
Fortunately the next commit will get rid of readb()'s "blocking" argument,
along the NothingToRead enum variant. So we'll no longer need this.
This reverts commit b92830cb17.
(cherry picked from commit fb7ee0db74)
readb() has only one caller that passes blocking=false: try_readb().
This function is used while decoding keys; anything but a successful read
is treated as "end of input sequence".
This means that key input sequences such as \e[1;3D
can be torn apart by
- signals (EINTR) which is more likely since e1be842 (Work around torn byte
sequences in qemu kbd input with 1ms timeout, 2025-03-04).
- universal variable notifications (from other fish processes)
Fix this by blocking signals and not listening on the uvar fd. We do something
similar when matching key sequences against bindings, so extract a function
and use it for key decoding too.
Ref: https://github.com/fish-shell/fish-shell/issues/11668#issuecomment-3101341081
try_readch() was added to help a fuzzing harness, specifically to avoid a
call to `unreachable!()` in the NothingToRead case. I don't know much about
that but it seems like we should find a better way to tell the fuzzer that
this can't happen.
Fortunately the next commit will get rid of readb()'s "blocking" argument,
along the NothingToRead enum variant. So we'll no longer need this.
This reverts commit b92830cb17.
See commit 081c3282b7 (Refresh TTY timestamps also in some rare cases,
2025-01-15) and others.
Fixes d27f5a5293 (Adopt TtyHandoff in remaining places, 2025-06-21)
Fixes#11671
We might
1. set TTY_PROTOCOLS_ACTIVE to false
2. receive `SIGTERM`
3. due to 1 fail to disable TTY protocols
Fix this by making sure that the disabling of protocols happens-before we
set TTY_PROTOCOLS_ACTIVE to false.
See 37c04745e6 (Avoid potential contention on SIGTERM while enabling terminal
protocols, 2024-10-08).
Fixes d27f5a5293 (Adopt TtyHandoff in remaining places, 2025-06-21)
build_tools/check.sh is supposed to fail on formatting violations. I don't
think we have a good reason for running build_tools/style.fish outside
check.sh.
black is the only formatter not versioned in CI -- but we can probably
satisfy all realistic versions.
Ref: https://github.com/fish-shell/fish-shell/pull/11608#discussion_r2173176621
Due to unnecessary quotes in the prompt command given to `read` by `funced` when
editing a function interactively (using `-i`), the name of the function to edit
would be evaluated, expanded and even executed (when using command substitution
for example), which is at least annoying when using unusual but valid and
allowed function names like '*' or 'head (cat)'. This commit delays the function
name expansion so that this should no longer happen.
Despite the caching in `sphinx-build`, it takes several seconds to run
`sphinx-build` when no rebuilding is necessary, which slows down build times
significantly.
Add custom logic to `build.rs` to avoid calling `sphinx-build` if deemed
unnecessary based on the mtime of the source files.
This is done by writing the most recent timestamp of the source files into a
dedicated file, and only calling `sphinx-build` (and updating the timestamp)
when a cached timestamp is older than the most recent source file mtime.
The sources for Sphinx documentation builds include `CHANGELOG.rst` and
`CONTRIBUTING.rst`. Use `SPHINX_DOC_SOURCES` to clarify this and avoid
repetition.
Rebuilds should happen for debug builds as well, since rebuilding is required
for updating the man files.
This adopts the tty handoff in remaining places. The idea is to rationalize
when we enable and disable tty protocols (such as CSI-U).
In particular this removes the tty protocol disabling in Parser::eval_node
- that is intended to execute pure fish script and should not be talking to
the tty.
fish-shell attempts to set up certain terminal protocols (bracketed paste,
CSI-U) while it is in control of the tty, and disable these when passing
off the tty to other processes. These terminal protocols are enabled or
disabled by emitting certain control sequences to the tty.
Today fish-shell does this in a somewhat haphazard way, tracking whether
the protocols are enabled or disabled. Functions like `Parser::exec_node`
then just toggle these, causing data to be written to the terminal in
unexpected places. In particular this is very bad for concurrent execution:
we don't want random threads talking to the tty.
Fortunately we have a controlled place where we can muck with the tty:
`TtyTransfer` which controls handoff of ownership to child processes (via
`tcsetpgrp`). Let's centralize logic around enabling and disabling terminal
protocols there. Put it in a new module and rename it to `TtyHandoff` which is a
little nicer.
This commit moves code around and does some cleanup; it doesn't actually
pull the trigger on centralizing the logic though. Next commit will do that.
This reverts commit 1d6fa258f6.
This reintroduces commit 941701da3d, which was then reverted in
941701da3d8; this commit reverts the revert to reintroduce 941701da3d.
The reason is that the existing logic in terminal_protocols_disable_ifn does a
bunch of stuff for which nobody has thought about its signal safety, such as
accessing the reader stack (clearly not async signal safe).
Even functions which happen to be safe now may become unsafe in the future.
This is just the nature of signal handling code. We must ensure that only
async-signal safe syscalls are run, and only functions which are themselves
async-signal safe, which we (try) to designate with the "safe_" prefix.
Commit 941701da3d (Restore some async-signal discipline to SIGTERM,
2025-06-15) made two changes
1. removed a mutex lock in signal handler (regression from 55fd43d86c
(Port reader, 2023-12-22))
2. removed some SIGTERM cleanup
I'm not sure what's the reason for 2, so let's revert it I guess. This code
path already uses FLOG_SAFE for async-signal safety.
There is an avoidable panic when `Outputter::stdoutput()` is already
borrowed. Fix that.
Closes#11597
If a test fails by throwing an exception (in this case, "Too many open files")
then that exception would propagate, be uncaught, and then the remaining tests
would not be await'ed, leading to a hang.
Fix this by properly catching and reporting exceptions.
Manpage `fish_indent(1)` documents the `-c/--check` option, which checks
if a file is already indented as `fish_indent` would. This option is now
included in the completions for `fish_indent`.
There was an issue in autocomplete of ssh.
When you put in ~/.ssh/config line like this:
"Include Include ${HRL_SSH}/onprem_config"
and then trying to use fish complete for ssh, for example:
"ssh -J" and press key <Tab> it throughs an error that fish cannot understand ${HRL_SSH} with brackets.
Both `SKIP_CMDSUBST` and `NO_SPACE_FOR_UNCLOSED_BRACE` used `1 << 14` as their
value accidentally, resulting from `SKIP_CMDSUBST` not being sorted correctly.
Resolve this by using the next (and last in u16) unused bit for `SKIP_CMDSUBST`
and moving it to the end.
Fixes#11651.
Vim supports incrementing & decrementing the number below the cursor (or
after it) via Ctrl-a and Ctrl-x, respectively. Given fish's Vi mode
support, it makes sense to provide similar functionality when working on
the command line, to provide a more natural environment for Vim users.
With this change we add the necessary functionality.
Closes: #8320Closes#11570
Historically, `fish -C "commandline echo"` was silently ignored. Make it do
the expected thing. This won't affect subsequent readers because we only do
it for top-level ones, and reader_pop() will clear the commandline state again.
This improves consistency with the parent commit. We probably don't want to
support arbitrary readline commands before the first reader is initialized,
but setting the initial commandline seems useful: first, it would have helped
me in the past for debugging fish. Second, it would allow one to rewrite
an application launcher:
foot --app-id my-foot-launcher -e fish -C '
set fish_history launcher
bind escape exit
bind ctrl-\[ exit
- function fish_should_add_to_history
- false
- end
- for enter in enter ctrl-j
- bind $enter '\''
- history append -- "$(commandline)"
- commandline "setsid $(commandline) </dev/null >/dev/null 2>&1 & disown && exit"
- commandline -f execute
- '\''
- end
+ commandline "setsid </dev/null >/dev/null 2>&1 & disown && exit"
+ commandline --cursor $(string length "setsid ")
'
which is probably not desirable today because it will disable autosuggestions.
Though that could be fixed eventually by making autosuggestions smarter.
If we find a generally-useful use case, we should mention this in the changelog.
Ref: https://github.com/fish-shell/fish-shell/pull/11570#discussion_r2144544053
Commands like "commandline foo" silently fail, and "complete -C" fails with
a weird "option requires an argument" error.
I think at least the first one can be useful in edge cases, e.g. to test
code that does not separate the `commandline` input and output (#11570),
and to set fish's initial commandline, see the next commit.
I don't think there are super strong reasons to allow these, but if the
existing state is merely due to "no one has ever thought of doing this",
then we should try changing it.
For consistency, also allow "complete -C". I guess an argument for that is
that it's weird to make a command behave differently in non-interactive shells.
For now, keep the historical behavior of disabling access to the command
line in non-interactive shells. If we find a good reason for allowing that
(which seems unlikely), we can.
Ref: https://github.com/fish-shell/fish-shell/pull/11570#discussion_r2144544053
Co-authored-by: Johannes Altmanninger <aclopte@gmail.com>
Historically, ctrl-i sends the same code as tab, ctrl-h sends backspace and
ctrl-j and ctrl-m behave like enter.
Even for terminals that send unambiguous encodings (via the kitty keyboard
protocol), we have kept bindings like ctrl-h, to support existing habits.
We forgot that pressing alt-ctrl-h would behave like alt-backspace (and can
be easier to reach) so maybe we should add that as well.
Don't add ctrl-shift-i because at least on Linux, that's usually intercepted
by the terminal emulator.
Technically there are some more such as "ctrl-2" (which used to do the same as
"ctrl-space") but I don't think anyone uses that over "ctrl-space".
Closes #https://github.com/fish-shell/fish-shell/discussions/11548
(cherry picked from commit 4d67ca7c58)
Historically, ctrl-i sends the same code as tab, ctrl-h sends backspace and
ctrl-j and ctrl-m behave like enter.
Even for terminals that send unambiguous encodings (via the kitty keyboard
protocol), we have kept bindings like ctrl-h, to support existing habits.
We forgot that pressing alt-ctrl-h would behave like alt-backspace (and can
be easier to reach) so maybe we should add that as well.
Don't add ctrl-shift-i because at least on Linux, that's usually intercepted
by the terminal emulator.
Technically there are some more such as "ctrl-2" (which used to do the same as
"ctrl-space") but I don't think anyone uses that over "ctrl-space".
Closes #https://github.com/fish-shell/fish-shell/discussions/11548
Nightlies for opensuse/leap:15.6 are failing because their /bin/python3
is Python 3.6 (the "python311" package creates only /bin/python311).
Python3.6 has been EOL for 3.5 years but OpenSuse leap is not even EOL.
Given that we don't write a lot of Python, let's support this for now.
From commit ba00d721f4 (Correct statvfs call to statfs, 2025-06-19):
> This was missed in the Rust port
To elaborate:
- ec176dc07e (Port path.h, 2023-04-09) didn't change this (as before,
`statvfs` used `ST_LOCAL` and `statfs` used `MNT_LOCAL`)
- 6877773fdd (Fix build on NetBSD (#10270), 2024-01-28) changed the `statvfs`
call to `statfs`, presumably due to the libc-wrapper for
`statvfs` being missing on NetBSD. This change happens
to work fine on NetBSD because they do [`#define ST_LOCAL
MNT_LOCAL`](https://github.com/fish-shell/fish-shell/pull/11486#discussion_r2092408952)
But it was wrong on others like macOS and FreeBSD, which was fixed by
ba00d721f4 (but that broke the build on NetBSD).
- 7228cb15bf (Include sys/statvfs.h for the definition of ST_LOCAL (Rust
port regression), 2025-05-16)
fixed a code clone left behind by the above commit (incorrectly assuming
that the clone had always existed.)
Fix the NetBSD build specifically by using statfs on that platform.
Note that this still doesn't make the behavior equivalent to commit LastC++11.
That one used ST_LOCAL if defined, and otherwise MNT_LOCAL if defined.
If we want perfect equivalence, we could detect both flags in `src/build.rs`.
Then we would also build on operating systems that define neither. Not sure.
Closes#11596
(cherry picked from commit 6644cc9b0e)
Today, when a change introduces warnings, the change author might not see
them. Fix that by making clippy fail on warnings.
AFAICT, "clippy --deny-warnings" will also fail on rustc warnings.
I'd imagine this is what most respectable Rust projects do.
Pin stable rust so we won't get unrelated failures. Alternatively, we could
keep using "dtolnay/rust-toolchain@stable", that should be fine too (as long
as we have the capacity to quickly silence/iron out clippy failures).
While at it, remove some unneeded dependencies. Keep gettext because that
one might enable some cfg-directives (?).
Other cfgs like feature="benchmark" and target_os != "linux" are not yet checked in CI.
See #11584
Extract a github action to reduce the number of references to our MSRV and
stable (to be pinned in the next commit).
While at it, use the MSRV for macOS builds; this means that we'll be less
like accidentally to break the macOS build when bumping the MSRV. I don't
think there is a reason for using 1.73 specifically, other than "it's the
highest we can use on old macOS", so using an even older one should be fine.
From commit ba00d721f4 (Correct statvfs call to statfs, 2025-06-19):
> This was missed in the Rust port
To elaborate:
- ec176dc07e (Port path.h, 2023-04-09) didn't change this (as before,
`statvfs` used `ST_LOCAL` and `statfs` used `MNT_LOCAL`)
- 6877773fdd (Fix build on NetBSD (#10270), 2024-01-28) changed the `statvfs`
call to `statfs`, presumably due to the libc-wrapper for
`statvfs` being missing on NetBSD. This change happens
to work fine on NetBSD because they do [`#define ST_LOCAL
MNT_LOCAL`](https://github.com/fish-shell/fish-shell/pull/11486#discussion_r2092408952)
But it was wrong on others like macOS and FreeBSD, which was fixed by
ba00d721f4 (but that broke the build on NetBSD).
- 7228cb15bf (Include sys/statvfs.h for the definition of ST_LOCAL (Rust
port regression), 2025-05-16)
fixed a code clone left behind by the above commit (incorrectly assuming
that the clone had always existed.)
Fix the NetBSD build specifically by using statfs on that platform.
Note that this still doesn't make the behavior equivalent to commit LastC++11.
That one used ST_LOCAL if defined, and otherwise MNT_LOCAL if defined.
If we want perfect equivalence, we could detect both flags in `src/build.rs`.
Then we would also build on operating systems that define neither. Not sure.
Closes#11596
As desribed in objdump(1), --disassembler-color can be applied to
enable or disable the use of syntax highlighting in disassembly
output.
The options are:
--disassembler-color=off
--disassembler-color=terminal
--disassembler-color=on|color|colour
--disassembler-color=extened|extended-color|extened-colour
Signed-off-by: adamanteye <ada@adamanteye.cc>
Closes#11615
- Added the '__fish_ollama_ps' function to list running models.
- Added the 'stop' subcommand to ollama completions.
- Added running models as arguments to 'stop'.
Use wrapping arithmetic when parsing octal and hex escapes in echo to
prevent panics on overflow and ensure consistent behavior with other
shells. This change allows echo to process escape sequences like \5555
without crashing, keeping the same behavior as 3.7.1.
```
$ ./fish --version
fish, version 3.7.1
$ ./fish -c 'echo -e "\5555"'
m5
```
Commit 97581ed20f (Do send bracketed paste inside midnight commander,
2024-10-12) accidentally started sending CSI commands such as "CSI >5;0m",
which we intentionally didn't do for some old versions of Midnight Commander,
which fail to parse them. Fix that.
Fixes#11617
I sometimes want to run this script in multiple docker containers concurrently,
and possibly modify it while another instance is already running. The behavior
after modification is unpredictable; let's change it to read the whole script
up-front (like Python/fish do).
My
$ sudo docker/docker_run_tests.sh --shell-after docker/jammy-asan.Dockerfile
shows a lot of complaints about
Direct leak of 60 byte(s) in 1 object(s) allocated from:
because some unit tests call reader_init() and reader_deinit(). Work around
this by initializing this value only once. AFAICT, OnceCell is async-signal
safe (unlike Mutex), although I don't think documentation promises that.
It doesn't feel great to change implementation code to accomodate tests but
I think for this specific issue that's what we usually do. Alternatively,
we could add to lsan_suppressions.txt.
If cargo ever wants to write to "target/man", it would collide with our
use of this path. Let's make this less likely by prefixing the name with
"fish-". This also makes it more obvious that this is fish's invention.
(Note: this commit should technically have preceded the "Fix config paths
for disjoint build-dirs and in-tree installs" one, to make that one easier
to follow, but I wasn't 100% sure if this commit is right.)
From https://doc.rust-lang.org/cargo/reference/environment-variables.html
> OUT_DIR — If the package has a build script, this is set to the folder
> where the build script should place its output. See below for more
> information. (Only set during compilation.)
so OUT_DIR is something like "target/debug/build/fish-41da27d587f48978".
Whenever build.rs is re-run, we get a new one.
I don't think we need this flexibility anywhere. It wouldn't protect
concurrent "cargo test" from interfering with each other - that's handled
by a file lock taken by Cargo.
Use "target/" instead (or CMAKE_BINARY_DIR if set).
Namespace the files better, so we don't create weird paths like
target/test/complete_test/...
target/fish_root/
With the upcoming tests/checks/gettext.fish test from #11583, my
sudo docker/docker_run_tests.sh --shell-after docker/focal.Dockerfile
fails writing to "po/template.po" because "/fish-source" is mounted as
read-only. (There should be no need for tests to write to the source tree.)
Since commit 6239cba1e4 (Add dry-run mode to update_translations.fish,
2025-05-30), "build_tools/update_translations.fish" always removes that
template file when done, even without "--dry-run".
I'm not sure if we still have a need for keeping around "po/template.po".
To add a new translation, you can run "build_tools/update_translations
po/xy.po". It could serve as a cache but that would only work if we integrated
it into a build system.
Move it to /tmp, fixing the docker tests.
Use test_driver directly instead of CMake in the docker tests.
Deal with the read-only "/fish-source" by exporting
"CARGO_TARGET_DIR=$HOME/fish-build". It seems correct to also inject this
environment variable into the interactive debugging shells. Add some logging
to make this override more obvious to the user.
Adopt "build_tools/check.sh", because that defines the full set of checks
that we (eventually) want to run in CI.
In particular, this will also run "tests/checks/po-files-up-to-date.fish"
which "cargo b && cargo t && tests/test_driver.py" does not, due to the
REQUIRES clause.
Since most docker images have some lints/warnings today, disable those for
now. Use "docker_run_tests.sh --lint" to override. The default may be changed
in future.
Commit 89282fd9bc (Use CARGO_MANIFEST_DIR to see if we're running from
build dir, 2024-01-20) did
-if exec_path.starts_with(OUT_DIR)
+if exec_path.starts_with(CARGO_MANIFEST_DIR)
where OUT_DIR is the cmake build directory ("./build")
and CARGO_MANIFEST_DIR is our top level source tree.
This allowed "target/debug/fish" to work, but it broke
1. CMake build directories outside the source tree, e.g. "docker/docker_run_tests.sh".
Those incorrectly fall back to the compiled-in-path (/usr/local/share etc)
2. Installations iside the source tree, e.g.
"mkdir build && cd build && cmake .. -DCMAKE_INSTALL_PREFIX=$PWD/../install".
These installations incorrectly use "share/" etc. from the source tree.
Fix this by
1. respecting the CMake-specific FISH_BUILD_DIR, ad
2. if that's not set, use $CARGO_MANIFEST_DIR/target
We have a mixture of 2 and 4 space indent.
4 benchmarks/driver.sh
2 build_tools/check.sh
4 build_tools/git_version_gen.sh
4 build_tools/mac_notarize.sh
2 build_tools/make_pkg.sh
2 build_tools/make_tarball.sh
2 build_tools/make_vendor_tarball.sh
4 docker/docker_run_tests.sh
4 osx/install.sh
2 tests/test_functions/sphinx-shared.sh
Our editorconfig file specifies 2, with no explicit reason.
Our fish and Python scripts use 4, so let's use that.
Commit 5c0fddae70 (Refactor history flushing, 2025-03-28) made three changes:
1. call fsync() when we are finished writing the history file.
2. when appending to (as opposed to vacuuming) history, call write(2)
(followed by flush() and sync()) for each item. Previously, we'd only
call write(2) if our 64k buffer was full, or after processing the last
history item.
3. actually check the return value of flush() (which would retry when flushing
fails -- but std::fs::File::flush() never fails!).
The motivation was to potentially fix#10300 which didn't succeed (see
https://github.com/fish-shell/fish-shell/issues/10300#issuecomment-2876718382).
As for 1 and 2, I don't think the way we use fsync really helps, and flushing
eagerly should not make a difference.
As for 3, there are some explanations in comments, commit message and a [PR
comment](https://github.com/fish-shell/fish-shell/pull/11330#discussion_r2020171339).
To summarize, 5c0fddae70 wants to address the scenario where file.flush()
fails. Prior to that commit we would ostensibly carry on with a corrupted
"first_unwritten_new_item_index" (corrupted because it doesn't match what's
written to disk), which can cause various issues. However this doesn't
ever happen because std::fs::File::flush() never fails because it doesn't
do anything -- std::fs::File::write() does not buffer writes, it always
delegates to write(2).
There can definitely be scenarios like the one described in
https://github.com/fish-shell/fish-shell/pull/11330#discussion_r2020171339
where the disk is full. In that case, either write(2) fails, which we
already check. Or close(3p) fails with EIO, which we have never checked. We
should probably check that.
Undo all three changes for now.
Closes#11495
Systems like NixOS might not have "git-receive-pack" or any other "git-*"
executable in in $PATH -- instead they patch git to use absolute paths.
This is weird. But no reason for us to fail. Silence the error.
Fixes#11590
(cherry picked from commit 4f46d369c4)
Remove dependency on CTest. Parallel execution is handled by `test_driver.py`
internally now, so CTest is no longer relevant for performance.
This also removes CMake targets for single tests. As a replacement,
`test_driver.py` can be called directly with the path to the build directory as
the first argument and the path to the desired test as the second argument.
Ensuring that the executables in the build directory are up to date needs to be
done separately.
For a pure cargo build, an example of running a single test would be:
`cargo b && tests/test_driver.py target/debug tests/checks/abbr.fish`
The recommended way of running tests is `build_tools/check.sh`, which runs more
extensive tests and does not depend on CMake. That script does not work in CI
yet, so CMake testing is retained for now.
Update CI config to use the new `FISH_TEST_MAX_CONCURRENCY`.
Also update the FreeBSD version, since the previous one is outdated and does not
support the semaphore logic in `test_driver.py`.
`mmap` should fail when the length argument is 0. Checking this in advance
allows returning early, without performing unnecessary syscalls.
This also fixes an issue observed on FreeBSD 13.2 where `mmap` does not always
fail when the length is 0, resulting in the `assert!(len > 0)` in
`MmapRegion::new` failing.
https://github.com/fish-shell/fish-shell/issues/11595
Commit cd3da62d24 (fix(completion): unescape strings for __fish_complete_list,
2024-09-17) bravely addressed an issue that exists in a lot of completions.
It did so only for __fish_complete_list. Fair enough.
Unfortunately it unescaped more than just "$(commandline -t)".
This causes the problem described at
https://github.com/fish-shell/fish-shell/issues/11508#issuecomment-2889088934
where completion descriptions containing a backslash followed by "n" are
interpreted as newlines, breaking the completion parser. Fix that.
(cherry picked from commit 60881f1195)
Given a command line like
foo --foo=bar=baz=qux\=argument
(the behavior is the same if '=' is substituted with ':').
fish completes arguments starting from the last unescaped separator, i.e.
foo --foo=bar=baz=qux\=argument
^
__fish_complete_list provides completions like
printf %s\n (commandline -t)(printf %s\n choice1 choice2 ...)
This means that completions include the "--foo=bar=baz=" prefix.
This is wrong. This wasn't a problem until commit f9febba (Fix replacing
completions with a -foo prefix, 2024-12-14), because prior to that, replacing
completions would replace the entire token.
This made it too hard to writ ecompletions like
complete -c foo -s s -l long -xa "hello-world goodbye-friend"
that would work with "foo --long fri" as well as "foo --long=frie".
Replacing the entire token would only work if the completion included that
prefix, but the above command is supposed to just work.
So f9febba made us replace only the part after the separator.
Unfortunately that caused the earlier problem. Work around this. The change
is not pretty, but it's a compromise until we have a better way of telling
which character fish considers to be the separator.
Fixes#11508
(cherry picked from commit 320ebb6859)
Commit cd3da62d24 (fix(completion): unescape strings for __fish_complete_list,
2024-09-17) bravely addressed an issue that exists in a lot of completions.
It did so only for __fish_complete_list. Fair enough.
Unfortunately it unescaped more than just "$(commandline -t)".
This causes the problem described at
https://github.com/fish-shell/fish-shell/issues/11508#issuecomment-2889088934
where completion descriptions containing a backslash followed by "n" are
interpreted as newlines, breaking the completion parser. Fix that.
Given a command line like
foo --foo=bar=baz=qux\=argument
(the behavior is the same if '=' is substituted with ':').
fish completes arguments starting from the last unescaped separator, i.e.
foo --foo=bar=baz=qux\=argument
^
__fish_complete_list provides completions like
printf %s\n (commandline -t)(printf %s\n choice1 choice2 ...)
This means that completions include the "--foo=bar=baz=" prefix.
This is wrong. This wasn't a problem until commit f9febba (Fix replacing
completions with a -foo prefix, 2024-12-14), because prior to that, replacing
completions would replace the entire token.
This made it too hard to writ ecompletions like
complete -c foo -s s -l long -xa "hello-world goodbye-friend"
that would work with "foo --long fri" as well as "foo --long=frie".
Replacing the entire token would only work if the completion included that
prefix, but the above command is supposed to just work.
So f9febba made us replace only the part after the separator.
Unfortunately that caused the earlier problem. Work around this. The change
is not pretty, but it's a compromise until we have a better way of telling
which character fish considers to be the separator.
Fixes#11508
The main purpose of this is avoiding timeouts in CI.
Passing `--max-concurrency=n` to `test_driver.py` will result in at most `n`
tests running concurrently, where `n` is a positive integer.
Not specifying the argument preserves the old behavior of running all tests
concurrently without a limit.
This was missed in the Rust port - C++ had statfs for MNT_LOCAL and not statvfs.
The effect of this is that fish never thought its filesystem was local on macOS
or BSDs (Linux was OK). This caused history race tests to fail, and also could
in rare cases result in history items being dropped with multiple concurrent
sessions.
This fixes the history race tests under macOS and FreeBSD - we weren't locking
because we thought the history was a remote file.
Cherry-picked from ba00d721f4
This was missed in the Rust port - C++ had statfs for MNT_LOCAL and not statvfs.
The effect of this is that fish never thought its filesystem was local on macOS
or BSDs (Linux was OK). This caused history race tests to fail, and also could
in rare cases result in history items being dropped with multiple concurrent
sessions.
This fixes the history race tests under macOS and FreeBSD - we weren't locking
because we thought the history was a remote file.
Within a linked worktree, `$GIT_DIR` and `$GIT_COMMON_DIR` have different
values (see [git-worktree docs](https://git-scm.com/docs/git-worktree#_details)).
The two serve different purposes, in case of stashes `$GIT_COMMON_DIR`
should be used, this way stash detection in the git prompt works also
when inside a `git worktree`.
Closes#11591
Systems like NixOS might not have "git-receive-pack" or any other "git-*"
executable in in $PATH -- instead they patch git to use absolute paths.
This is weird. But no reason for us to fail. Silence the error.
Fixes#11590
Eliminates some code duplication between the two different saving
implementations. These changes are based on
https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2149438316.
One extra change is included here, namely the early return on an empty file
name, indicating private mode. Without this, `history_path.unwrap()` fails in
some tests. Returning early is probably what we want in such situations anyway.
The cached information might become outdated. It is important that all fish
processes use the same mutual exclusion logic (either `flock`-based or the
fallback), because the two methods do not provide mutual exclusion from one
another.
Avoiding caching makes the behavior independent on previous system states,
resulting in fish instances performing file operations at the same time to use
the same locking logic.
More detailed discussion in
https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2134543447
If arguments always have the same value they do not need to be arguments.
For `HistoryImpl::add`, the comments are incorrect (assuming they should
indicate the value of the argument), since both arguments can be true or false
independently.
`History::add` is only called at one location in a test with a constant value of
`false` for `pending`. This might mean that the parameter could be deleted, or
maybe even the entire function, if testing can work without it.
Both history files and universal variables files are accessed by multiple
processes, which need a way to synchronize their accesses.
This synchronization logic is mixed in with the logic for reading and updating
the files' contents, which results in messy code, duplicated locking
implementations, and inconsistencies.
Moreover, the existing implementations are flawed which has resulted in file
corruption (e.g. https://github.com/fish-shell/fish-shell/issues/10300).
The new approach separates the synchronization logic from the rest.
There are two approaches to synchronization.
- The primary one is using `flock(2)` to lock the directory containing the file
which requires synchronized access. We do not lock the file holding the data
directly because this file might be replaced, which can result in locking
succeeding when it should block. Locking the directory solves this problem.
To avoid inconsistent file states, changes are first written to a temporary
file, which is then renamed into place while still holding the lock.
- In some situations `flock` locks are unavailable or take a long time. This
mostly applies to remote file systems. If we think that a directory is located
on a remote file system, we do not attempt to use `flock`.
As a fallback, we have a lockless approach, which uses file metadata (device,
inode, size, ctime, mtime) to identify file versions.
We then read from the file, write the updated data to a temporary file,
check if the file id for the path is the same as before we started reading,
and if so we rename the temporary file such that it replaces the old file.
Note that races are possible between the file id check and the rename syscall.
If we detect a file id mismatch, we retry, up to a predetermined number of
attempts.
The operations which should be performed are passed to the functions handling
synchronization as `Fn`s. Because we might have to run these operations
repeatedly when retrying, they should be executable arbitrarily often without
causing side-effects relevant to the program. This requires some changes to
functions accessing these files. In many cases, they have to work with
non-mutable references, which requires that they return the data which should be
updated in the program state, instead of directly assigning to the appropriate
location.
Locking via `O_EXLOCK`, which was used for the universal variable file, is no
longer supported. That version of locking locks the file operated on directly,
instead of its directory. According to the man pages of {Open,Free,Net}BSD
and macOS, these locks have flock semantics. So if flock is available, we can
use it, and if it is not, the `O_EXLOCK` flag does not help.
This is preparatory work for refactoring the file synchronization approach.
`read_exact` will fail if the file length does not match the expected one, which
means zero padding is useless. (On any reasonable OS it was also useless before,
because anonymous memory mapping would be zero-pages.)
Use `std::io::Result` instead of `Option` as the return type where appropriate,
to allow for better-informed error handling.
Remove explicit checks about the length to be mapped being 0.
From `mmap(3)`:
> If len is zero, mmap() shall fail and no mapping shall be established.
This allows for more informative error handling.
In some cases, the `?` operator can now be applied sensibly instead of more
verbose local error handling.
There is no need for separate implementations for history and uvar file
handling. Having a shared implementation ensures that creating temporary files
is handled consistently and removes clutter from the source files which want to
create temporary files.
This is another step towards making the `load_from_file` function callable
without modifying internal data of `self`. Instead, the required updates for
a successful load should be returned.
For now, `self.last_read_file_id` is still modified
within `load_from_file`, which means it still needs a mutable reference to
`self`.
This is done as a step towards enabling loading from the variables file without
affecting internal variables, such that retrying becomes possible without
issues.
Callbacks are generated by
`src/env_universal_common.rs:generate_callbacks_and_update_exports`.
This function only pushes to the `Vec`, so the content of the `Vec` passed to it
does not matter within this function.
The generated callbacks are used in `src/env/environment.rs:universal_sync`,
which calls `generate_callbacks_and_update_exports` via
`EnvUniversal::sync`,
(optionally `EnvUniversal::load_from_path_narrow`),
`EnvUniversal::load_from_file`.
The only other code making use of these callbacks is in tests.
Because the only real use passes an empty `Vec`, there is no need to to pass the
`Vec` as a mutable reference to the function at all. Instead, we create the `Vec`
in `generate_callbacks_and_update_exports` and return it from there, which is
what the new code does.
This change is made because we want loading from a file to be performed without
mutating data which does not come directly from the file.
Then, we can safely retry loading from the file as many times as we want,
without worrying about side-effects on our data structures.
We want to be able to do this in the case where we cannot properly lock the file
and fall back to lockless reading, where we check file metadata before and after
reading to detect modifications, and retry if modifications are detected.
This fallback logic is not in place yet, and further changes are required for
side-effect free loading.
This allows converting non-UTF-8-conforming bytes from their PUA encoding back
to the original bytes before outputting.
Due to the way Rust handles trait implementations, we cannot use
`impl<T: std::fmt::Display> FloggableDisplay for T`
anymore, as that would result in a conflicting implementation for the types
which get a custom implementation.
Instead, explicitly implement the trait for all types which need it.
The changes to enable terminal protocols (CSI-U, etc) also attempts to
re-disable these when fish exits. In particular it attempts to disable these
from a SIGTERM handler.
Unfortunately none of that machinery is async-signal safe. Indeed our SIGTERM
handler has gotten rather sketchy, with taking a mutex and some other stuff.
Remove the async-signal-unsafe stuff and make SIGTERM manifestly safe.
Unfortunately this means that terminal protocols will remain set after SIGTERM
but that's probably unavoidable.
Calls to redirect_tty_output were added in many places when certain tty-syscalls
returned EIO. See commit 396bf1235d
This was intended to work around a glibc bug in wide character output, but it
was never really justifiable or tested, and we no longer use glibc wide
character output.
Bravely remove these, except in the case where we got SIGHUP and we don't want
to trigger SIGTTIN or SIGTTOU.
Definitions of localizable strings should not be guarded by `cfg`, because then
they might not end up being exported, depending on the compilation config.
The PO file updates can now run in a normal test, eliminating the need for
special handling.
Rename the `check-translations.fish` script, to clarify which part of the checks
happens in it.
This is intended to allow translation updates in contexts where building within
the `fish_xgettext.fish` script is undesirable.
Specifically, this allows checking for PO file updates in the tests run by
`test_driver.py`. Because these use a tmpdir for `$HOME`, building within such a
test requires installing the entire Rust toolchain and doing a clean build,
which is a waste of resources.
With this argument, it is possible to build the template before running the
tests and passing the file path into the script.
When including the tests in the build, string literals passed to `wgettext!`
would be included in the gettext template file, which we do not want here,
because the strings should not be localized for this test.
This function does not need to run when the pager is not focused. Calling it
lazily eliminates the overhead of calling it when it is not needed.
This code runs on each keypress when entering a command, so it makes sense to
keep it as lean as possible. (At the very least it avoids spam when trying to
debug/analyze gettext behavior.)
This test is the one with the longest runtime. Splitting the two targets into
separate tests allows them to run in parallel, which can speed up the tests.
This concerns edge cases when executing a function. Historically, when we parse
fish script, we identify early whether or not it's a function; but only record
the function's name and not its properties (i.e. not its source).
This means that the function can change between parsing and execution. Example:
function foo; echo alpha; end
foo (function foo; echo beta; end)
This has historically output "beta" because the function is replaced as part of
its own arguments.
Worse is if the function is deleted:
function foo; echo alpha; end
foo (functions --erase foo)
This outputs an error but in an awkward place; that's OK since it's very rare.
Let's codify this behavior since someone might be depending on it.
Previously, for Processes which were BlockNodes, we stored the node separately
in the Process via an Option; just promote this to a real field of the
ProcessType::BlockNode.
No user visible changes expected.
Our docker tests are currently broken since we no longer seem to install
"build_root". When I sidestep this issue for now and run
sudo docker/docker_run_tests.sh --shell-before docker/focal.Dockerfile
cd /fish-source
CARGO_TARGET_DIR=$HOME/out
tests/test_driver.py ~/out/debug
the test driver fails in various ways.
This is because Ubuntu Focal provides Python 3.8.
Fix some of the typing incompatibilities. Fix a hang in tests like
"tests/checks/init-command.fish"; apparently fish believes it's interactive
because Python 3.8's create_subprocess_shell() makes the fish child believe
that stdin is a TTY, so it's implicitly interactive.
Our docker/docker_run_tests.sh script runs tests in a container with the fish
source tree mounted as read-only. We have a hack to speed up repeated runs
of the check-all-fish-files test that assumes the source tree is writable.
Paper over this by silencing the error for now.
There were no remaining checks left to match stderr:1:
touch: cannot touch '/fish-source/tests/.last-check-all-files': Read-only file system
As explained in c3740b85be (config_paths: fix compiled-in locale dir,
2025-06-12), fish is "relocatable", i.e. "mv /usr/ /usr2/" will leave
"/usr2/bin/fish" fully functional.
There is one exception: for LOCALEDIR we always use the path determined at
compile time.
This seems wrong; let's use the same relocatable-logic as for other paths.
Inspired by bf65b9e3a7 (Change `gettext` paths to be relocatable (#11195),
2025-03-30).
Commit bf65b9e3a7 (Change `gettext` paths to be relocatable (#11195),
2025-03-30) is difficult to follow because it combines code movement with
two behavior changes. Our parent commit fixed the first behavior change.
The second behavior change made us tolerate trailing NUL bytes in LOCALEDIR.
This was motivated because conda wants to use binary patching to change
the effective prefix at runtime, presumably so the user can move around the
"fish" executable program arbitraily.
This turned out to be unnecessary because fish is already "relocatable"
(see our parent commit).
Let's remove the special case for LOCALEDIR. Treat it like other paths.
Closes#11574Closes#11474
Fish uses this logic to find paths to functions etc.:
1. if $(status fish-path) starts with $CARGO_MANIFEST_DIR,
we use $CARGO_MANIFEST_DIR/share etc.
Aside: this also has the unintended effect that "cmake
-DCMAKE_INSTALL_PREFIX=$PWD/prefix" will not use "$PWD/prefix/share" but
"$PWD/share", at least since eacbd6156d (Port and adopt main written in
Rust, 2023-08-18).
2. Else if $(status fish-path) ends with "bin/fish",
and $(status fish-path)/../share/fish exists, we use that, since 4912967eab
(Large set of changes related to making fish relocatable, and improving
the build and install story, 2012-07-08)
3. Else if $(status fish-path) ends in "fish" (which is very likely),
and $(status fish-path)/share exists, we use that, since
c2a8de4873 (Make fish find config directories in source tree, 2016-09-23).
I think this is for running (without installing) in-tree builds ("cmake .");
this is not recommended but it is used, see
https://github.com/fish-shell/fish-shell/pull/10330
4. If none of the above worked, either because the fish binary has been
moved into a weird directory, or if we fail to get $(status fish-path)
(e.g. on OpenBSD, where "argv[0]" is not available),
then we fall back to reasonable default paths determined at compiled
time.
These paths include data_dir=$PREFIX/share.
We recently added locale_dir too in bf65b9e3a7 (Change `gettext` paths
to be relocatable (#11195), 2025-03-30).
In case 1, we use locale: manifest_dir.join("share/locale"),
In case 2 and 3, we use locale: data_dir.join("locale"),
In case 4, we use locale: data_dir.join("share"),
The last one seems wrong (there is not "/usr/share/share"). Fix that.
Alternatively, we could revert bf65b9e3a7 (and redo the parts we want to keep).
This uses Python's `asyncio` to run tests in parallel, which speeds up test
execution significantly.
The timeout is removed. It would be possible to add a timeout to
`asyncio.as_completed()` if we want that.
This was only used to cache `fish_test_driver`, which can be built in a few tens
of milliseconds on most systems.
This avoids using outdated binaries for testing and simplifies the code and its
usage.
If no `--cachedir` is specifed for `test_driver.py`, it would build
`fish_test_helper` once per test it runs. This is unnecessary. Instead, build it
once in the beginning before running any tests and then use the binary in all
tests.
On terminals that do not implement the kitty keyboard protocol "ctrl-ц" on
a Russian keyboard layout generally sends the same byte as "ctrl-w". This
is because historically there was no standard way to encode "ctrl-ц",
and the "ц" letter happens to be in the same position as "w" on the PC-101
keyboard layout.
Users have gotten used to this, probably because many of them are switching
between a Russian (or Greek etc.) and an English layout.
Vim/Emacs allow opting in to this behavior by setting the "input method"
(which probably means "keyboard layout").
Match key events that have the base layout key set against bindings for
that key.
Closes#11520
---
Alternatively, we could add the relevant preset bindings (for "ctrl-ц" etc.)
but
1. this will be wrong if there is a disagreement on the placement of "ц" between two layouts
2. there are a lot of them
3. it won't work for user bindings (for better or worse)
(cherry picked from commit 7a79728df3)
As explained in the parent commit, "alt-+" is usually preferred over
"alt-shift-=" but both have their moments. We communicate this via a comment
saying "# recommended notation". This is not always true and not super helpful,
especially as we add a third variant for #11520 (physical key), which is
the recommended one for users who switch between English and Cyrillic layouts.
Only explain what each variant does. Based on this the user may figure out
which one to use.
(cherry picked from commit 4cbd1b83f1)
This was copied from C++ code but we have overflow checks, which
forces us to actually handle errors.
While at it, add some basic error logging.
Fixes#11092
(cherry picked from commit 4c28a7771e)
When "self.paste_is_buffering()" is true, "parse_escape_sequence()" explicitly
returns "None" instead of "Some(Escape)". This is irrelevant because this
return value is never read, as long as "self.paste_is_buffering()" remains
true until "parse_escape_sequence()" returns, because the caller will return
early in that case. Paste buffering only ends if we actually read a complete
escape sequence (for ending bracketed paste).
Remove this extra branch.
(cherry picked from commit e5fdd77b09)
The new key notation canonicalizes aggressively, e.g. these two bindings
clash:
bind ctrl-shift-a something
bind shift-ctrl-a something else
This means that key events generally match at most one active binding that
uses the new syntax.
The exception -- two coexisting new-syntax binds that match the same key
event -- was added by commit 50a6e486a5 (Allow explicit shift modifier for
non-ASCII letters, fix capslock behavior, 2025-03-30):
bind ctrl-A 'echo A'
bind ctrl-shift-a 'echo shift-a'
The precedence was determined by definition order.
This doesn't seem very useful.
A following patch wants to resolve#11520 by matching "ctrl-ц" events against
"ctrl-w" bindings. It would be surprising if a "ctrl-w" binding shadowed a
"ctrl-ц" one based on something as subtle as definition order. Additionally,
definition order semantics (which is an unintended cause of the implementation)
is not really obvious. Reverse definition order would make more sense.
Remove the ambiguity by always giving precedence to bindings that use
explicit shift.
Unrelated to this, as established in 50a6e486a5, explicit shift is still
recommended for bicameral letters but not typically for others -- e.g. alt-+
is typically preferred over alt-shift-= because the former also works on a
German keyboard.
See #11520
(cherry picked from commit 08c8afcb12)
We canonicalize "ctrl-shift-i" to "ctrl-I".
Both when deciphering this notation (as given to builtin bind),
and when receiving it as a key event ("\e[105;73;6u")
This has problems:
A. Our bind notation canonicalization only works for 26 English letters.
For example, "ctrl-shift-ä" is not supported -- only "ctrl-Ä" is.
We could try to fix that but this depends on the keyboard layout.
For example "bind alt-shift-=" and "bind alt-+" are equivalent on a "us"
layout but not on a "de" layout.
B. While capslock is on, the key event won't include a shifted key ("73" here).
This is due a quirk in the kitty keyboard protocol[^1]. This means that
fish_key_reader's canonicalization doesn't work (unless we call toupper()
ourselves).
I think we want to support both notations.
It's recommended to match all of these (in this order) when pressing
"ctrl-shift-i".
1. bind ctrl-shift-i do-something
2. bind ctrl-shift-I do-something
3. bind ctrl-I do-something
4. bind ctrl-i do-something
Support 1 and 3 for now, allowing both bindings to coexist. No priorities
for now. This solves problem A, and -- if we take care to use the explicit
shift notation -- problem B.
For keys that are not affected by capslock, problem B does not apply. In this
case, recommend the shifted notation ("alt-+" instead of "alt-shift-=")
since that seems more intuitive.
Though if we prioritized "alt-shift-=" over "alt-+" as per the recommendation,
that's an argument against the shifted key.
Example output for some key events:
$ fish_key_reader -cV
# decoded from: \e\[61:43\;4u
bind alt-+ 'do something' # recommended notation
bind alt-shift-= 'do something'
# decoded from: \e\[61:43\;68u
bind alt-+ 'do something' # recommended notation
bind alt-shift-= 'do something'
# decoded from: \e\[105:73\;6u
bind ctrl-I 'do something'
bind ctrl-shift-i 'do something' # recommended notation
# decoded from: \e\[105\;70u
bind ctrl-shift-i 'do something'
Due to the capslock quirk, the last one has only one matching representation
since there is no shifted key. We could decide to match ctrl-shift-i events
(that don't have a shifted key) to ctrl-I bindings (for ASCII letters), as
before this patch. But that case is very rare, it should only happen when
capslock is on, so it's probably not even a breaking change.
The other way round is supported -- we do match ctrl-I events (typically
with shifted key) to ctrl-shift-i bindings (but only for ASCII letters).
This is mainly for backwards compatibility.
Also note that, bindings without other modifiers currently need to use the
shifted key (like "Ä", not "shift-ä"), since we still get a legacy encoding,
until we request "Report all keys as escape codes".
[^1]: <https://github.com/kovidgoyal/kitty/issues/8493>
(cherry picked from commit 50a6e486a5)
This notation doesn't make sense, use either A or shift-a. We accept it
for ASCII letters only -- things like "bind shift-!" or "bind shift-Ä"
do not work as of today, we don't tolerate extra shift modifiers yet.
So let's remove it for consistency.
Note that the next commit will allow the shift-A notation again, but it will
not match shift-a events.
(cherry picked from commit 7f25d865a9)
Switch to fish_wcstoul because we want the constant to be unsigned.
It's u32 because most callers of function_key() want that.
(cherry picked from commit e9d1cdfe87)
Commit 109ef88831 (Add menu and printscreen keys, 2025-01-01)
accidentally broke an assumption by inverting f1..f12. Fix that.
Fixes#11098
(cherry picked from commit d2b2c5286a)
These aren't typically used in the terminal but they are present on
many keyboards.
Also reorganize the named key constants a bit. Between F500 and
ENCODE_DIRECT_BASE (F600) we have space for 256 named keys.
(cherry picked from commit 109ef88831)
We parse "\e\e[x" as alt-modified "Invalid" key. Due to this extra
modifier, we accidentally add it to the input queue, instead of
dropping this invalid key.
We don't really want to try to extract some valid keys from this
invalid sequence, see also the parent commit.
This allows us to remove misplaced validation that was added by
e8e91c97a6 (fish_key_reader: ignore sentinel key, 2024-04-02) but
later obsoleted by 66c6e89f98 (Don't add collateral sentinel key to
input queue, 2024-04-03).
(cherry picked from commit 84f19a931d)
This situation can be triggered in practice inside a terminal like tmux
3.5 by running
tmux new-session fish -C 'sleep 2' -d reader -o log-file
and typing "alt-escape x"
The log shows that we drop treat this as alt-[ and drop the x on the floor.
reader: Read char alt-\[ -- Key { modifiers: Modifiers { ctrl: false,
alt: true, shift: false }, codepoint: '[' } -- [27, 91, 120]
This input ("\e[x") is ambiguous.
It looks like it could mean "alt-[,x". However that conflicts with a
potential future CSI code, so it makes no sense to try to support this.
Returning "None" from parse_csi() causes this weird behavior of
returning "alt-[" and dropping the rest of the parsed sequence.
This is too easy; it has even crept into a bunch of places
where the input sequence is actually valid like "VT200 button released"
but where we definitely don't want to report any key.
Fix the default: report no key for all unknown sequences and
intentionally-suppressed sequences. Treat it at "alt-[" only when
there is no input byte available, which is more or less unambiguous,
hence a strong enough signal that this is a actually "alt-[".
(cherry picked from commit 3201cb9f01)
When the informative status is disabled, the stashstate variable was
set to 1 if the $git_dir/logs/refs/stash file existed and was readable,
even if the file itself was empty (i.e., no stashes). Now the stashstate
variable is set only if the file is NOT empty.
Commit 22c0054c1e (Add check to test all fish files with -n, 2020-02-17)
added a test that runs "fish --no-execute" on all fish files in share/**.fish
Commit 329cd7d429 (Make functions, completions and tests resilient to
running on an embed-data fish, 2025-03-25) change this to run it on **.fish.
Evidently "the tests are exempt because they contain syntax errors" is no
longer true - this is because we have since changed those files to recursively
run 'fish -c "syntax-error"', which makes it easier to test for multiple
syntax-errors in a single test file. Remove the comment.
Globbing everything seems a bit crass, and there's no explicit
motivation.
$ time find -name '*.fish' >/dev/null
Executed in 431.93 millis
$ time find * -name '*.fish' >/dev/null
Executed in 39.98 millis
Let's go back to testing only directories where we currently have Git-tracked
fish files. This makes uncached "check-all-fish-files.fish" go from 26
seconds to 5 seconds.
According to commit 8a07db8e8f (Revert "Revert "Speed up check-all-fish-files
when executed locally"", 2021-03-06), we can assume "find -newer" is supported.
check-all-fish-files takes a long time (>20 seconds here); which is why we
have a (hacky) optimization to avoid checking files we already checked.
This optimization hasn't worked since commit e96b6e157c (Remove TMPDIR
dependency from tests/, 2021-07-30) which started each test invocation in
a private tmpdir. Fix that.
The optimization is useful because this test is, by far, the bottleneck
for parallel test execution (#11561):
$ cargo b && time tests/test_driver.py target/debug
...
checks/tmux-complete.fish PASSED 8465 ms
checks/check-completions.fish PASSED 10948 ms
checks/check-sphinx.fish PASSED 12949 ms
checks/check-all-fish-files.fish PASSED 29828 ms
200 / 200 passed (0 skipped)
________________________________________________________
Executed in 31.00 secs fish external
usr time 81.02 secs 462.00 micros 81.02 secs
sys time 26.41 secs 272.00 micros 26.41 secs
A cache miss for check-all-fish-files.fish takes 24 seconds (though the
grandchild commit will speed this up), a cache hit 0.5 seconds.
Most Git commands take arbitrary revisions. AFAICT, we usually want the same
order, e.g. list local branches before remote branches before commit IDs etc.
I think there is no particular reason why this order is inconsistent between
various subcommands.
Let's extract a function. This standardizes the order and adds various
revision-types that were missing for some subcommands.
This variable is never defined. It was copied from Git's
contrib/completion/git-completion.bash where $match is probably equivalent
to $(commandline -t). I could not measure a significant speedup from passing
this filter to "git for-each-ref", so let's remove it for now.
This is done to prepare for running the tests in parallel.
With this approach the root tmpdir can be created before any test starts, each
test can create its home dir under the root tmpdir,
and when all tests are done the root tmpdir can be deleted.
Deletion of per-test dirs is more difficult in an async context.
This is intended as a way to run all available checks with a single command.
The script can be used locally and in CI. It is intended to replace
`cmake/Tests.cmake` (but this script also runs checks not present there).
At the moment, `ctest` is not used, which could be added to speed up tests.
Address and thread sanitizers are not run by this script.
Add flags to control behavior.
- `--check` to fail if changes would be made by formatters
- `--force` to skip the prompt about uncommitted changes
Fix behavior when `--all` is not specified. It used to operate on `$files`,
which did not get set in that case.
Not all fish files are considered, mainly because some tests might test how fish
behaves on weirdly formatted files.
For Rust files, `cargo fmt` is used when `--all` is specified.
The `--check` flag for `cargo fmt` is used when appropriate.
Do not try to build `fish_indent`. `make fish_indent` does not work anymore. Let
the user handle building and installing/setting `$PATH`.
This is intended to provide information to programmers where localizations might
be coming from, and potentially help with analyzing issues with localizations.
This new wrapper type can be constructed via macros which invoke the
`gettext_extract` proc macro to extract the string literals for PO file
generation.
The type checking enabled by this wrapper should prevent trying to obtain
translations for a string for which none exist.
Because some strings (e.g. for completions) are not defined in Rust, but rather
in fish scripts, the `LocalizableString` type can also be constructed from
non-literals, in which case no extraction happens.
In such cases, it is the programmer's responsibility to only construct the type
for strings which are available for localization.
This approach is a replacement for the `cargo-expand`-based extraction.
When building with the `FISH_GETTEXT_EXTRACTION_FILE` environment variable set,
the `gettext_extract` proc macro will write the messages marked for extraction
to a file in the directory specified by the variable.
Updates to the po files:
- This is the result of running the `update_translations.fish` script using the
new proc_macro extraction. It finds additional messages compared to the
`cargo-expand` based approach.
- Messages IDs corresponding to paths are removed. The do not have localizations
in any language and localizing paths would not make sense. I have not
investigated how they made it into the po files in the first place.
- Some messages are reordered due to `msguniq` sorting differing from `sort`.
Remove docs about installing `cargo-expand`
These are no longer needed due to the switch to our extraction macro.
This is done in preparation for a proc macro which extracts strings which are
passed to `gettext`. Because the `concat!` macro would get expanded after the
proc macro, the proc macro would still see the `concat!`, which it cannot
handle.
This used to get all the interfaces and ssids when the completions
were loaded. That's obviously wrong, given that ssids especially can, you know, change
(cherry picked from commit 9116c61736)
cherry-picking since this easy to trigger
(seen again in https://github.com/fish-shell/fish-shell/pull/11549)
This mode is intended for testing if the PO files are up-to-date and
well-formed.
At the moment, we only check translations in CI, where this is not particularly
relevant. Once we no longer need `cargo-expand`
(e.g. via https://github.com/fish-shell/fish-shell/pull/11536)
we can extend the `check_translations.fish` test to run
`update_translations.fish --dry-run` and fail if the exit status is nonzero.
As mentioned in the previous few commits and in #11535, running
"set fish_complete_path ..." and "complete -C 'git ...'" may result in
"share/completions/git.fish" being loaded multiple times.
This is usually fine because fish internally erases all cached completions
whenever fish_complete_path changes.
Unfortunately there is at least global variable that grows each time git.fish
is sourced. This doesn't make a functional difference but it does slow
down completions. Fix that by resetting the variable at load time.
(cherry picked from commit 4b5650ee4f)
Commit 5918bca1eb (Make "complete -e" prevent completion autoloading,
2024-08-24) makes "complete -e foo" add a tombstone for "foo", meaning we
will never again load completions for "foo".
Due to an oversight, the same tombstone is added when we clear cached
completions after changing "fish_complete_path", preventing completions from
being loaded in that case. Fix this by restoring the old behavior unless
the user actually used "complete -e".
(cherry picked from commit a7c04890c9)
On terminals that do not implement the kitty keyboard protocol "ctrl-ц" on
a Russian keyboard layout generally sends the same byte as "ctrl-w". This
is because historically there was no standard way to encode "ctrl-ц",
and the "ц" letter happens to be in the same position as "w" on the PC-101
keyboard layout.
Users have gotten used to this, probably because many of them are switching
between a Russian (or Greek etc.) and an English layout.
Vim/Emacs allow opting in to this behavior by setting the "input method"
(which probably means "keyboard layout").
Match key events that have the base layout key set against bindings for
that key.
Closes#11520
---
Alternatively, we could add the relevant preset bindings (for "ctrl-ц" etc.)
but
1. this will be wrong if there is a disagreement on the placement of "ц" between two layouts
2. there are a lot of them
3. it won't work for user bindings (for better or worse)
As explained in the parent commit, "alt-+" is usually preferred over
"alt-shift-=" but both have their moments. We communicate this via a comment
saying "# recommended notation". This is not always true and not super helpful,
especially as we add a third variant for #11520 (physical key), which is
the recommended one for users who switch between English and Cyrillic layouts.
Only explain what each variant does. Based on this the user may figure out
which one to use.
As of the parent commit, "ctrl-shift-x" bindings will take precedence over
"ctrl-X". Have fish_key_reader imply this via the ordering The next commit
will make this more explicit.
The new key notation canonicalizes aggressively, e.g. these two bindings
clash:
bind ctrl-shift-a something
bind shift-ctrl-a something else
This means that key events generally match at most one active binding that
uses the new syntax.
The exception -- two coexisting new-syntax binds that match the same key
event -- was added by commit 50a6e486a5 (Allow explicit shift modifier for
non-ASCII letters, fix capslock behavior, 2025-03-30):
bind ctrl-A 'echo A'
bind ctrl-shift-a 'echo shift-a'
The precedence was determined by definition order.
This doesn't seem very useful.
A following patch wants to resolve#11520 by matching "ctrl-ц" events against
"ctrl-w" bindings. It would be surprising if a "ctrl-w" binding shadowed a
"ctrl-ц" one based on something as subtle as definition order. Additionally,
definition order semantics (which is an unintended cause of the implementation)
is not really obvious. Reverse definition order would make more sense.
Remove the ambiguity by always giving precedence to bindings that use
explicit shift.
Unrelated to this, as established in 50a6e486a5, explicit shift is still
recommended for bicameral letters but not typically for others -- e.g. alt-+
is typically preferred over alt-shift-= because the former also works on a
German keyboard.
See #11520
Interactive fish with output redirected ("fish >/dev/null")
is not a common use case but it is valid.
Perhaps surprisingly, "fish >some-file" *does* print terminal escape codes
(colors, cursor movement etc.) even if terminal output is not a TTY.
This is typically harmless, and potentially useful for debugging.
We also send blocking terminal queries but those are not harmless in this case.
Since no terminal will receive the queries, we hang; indefinitely as of today,
but we should give up after a timeout and print an error. Either way that
seems needlessly surprising. Suppress queries in this case.
In future, we should probably do something similar if stdin is not a terminal;
though in that case we're even less likely to be interactive (only "-i"
I think).
When "self.paste_is_buffering()" is true, "parse_escape_sequence()" explicitly
returns "None" instead of "Some(Escape)". This is irrelevant because this
return value is never read, as long as "self.paste_is_buffering()" remains
true until "parse_escape_sequence()" returns, because the caller will return
early in that case. Paste buffering only ends if we actually read a complete
escape sequence (for ending bracketed paste).
Remove this extra branch.
On startup, we block until the terminal responds to our primary device
attribute query.
As an escape hatch, ctrl-c makes us stop waiting.
No keys are discarded; even ctrl-c is still enqueued. Usually this isn't
noticed because typing "echo<ctrl-c>" will insert a "echo" only to immediately
clear it.
The double interpretation of ctrl-c seems odd.
Additionally, the queuing seems unsafe considering that when typing something
like "echo hello<enter><ctrl-c>" the command will be executed.
Clear the queue instead, including ctrl-c.
This matches other programs like gdb, Kakoune and possibly others.
As mentioned in the previous few commits and in #11535, running
"set fish_complete_path ..." and "complete -C 'git ...'" may result in
"share/completions/git.fish" being loaded multiple times.
This is usually fine because fish internally erases all cached completions
whenever fish_complete_path changes.
Unfortunately there is at least global variable that grows each time git.fish
is sourced. This doesn't make a functional difference but it does slow
down completions. Fix that by resetting the variable at load time.
Commit 5918bca1eb (Make "complete -e" prevent completion autoloading,
2024-08-24) has a weird "!removed" check; it was added because "complete
-e" only needs to create the tombstone if we removed nothing. Otherwise the
autoloader will usually take care of not loading the removed completions again.
We should probably get rid of "!removed".. for now add a test to demonstrate
this behavior.
Commit 5918bca1eb (Make "complete -e" prevent completion autoloading,
2024-08-24) makes "complete -e foo" add a tombstone for "foo", meaning we
will never again load completions for "foo".
Due to an oversight, the same tombstone is added when we clear cached
completions after changing "fish_complete_path", preventing completions from
being loaded in that case. Fix this by restoring the old behavior unless
the user actually used "complete -e".
As reported in https://github.com/fish-shell/fish-shell/issues/11535#issuecomment-2915440295,
a command like "complete -C'git '" gets progressively slower every time.
A diff of "fish_trace=1" output shows that each completion invocation added
more stuff to the global "__fish_git_aliases", resulting in output like:
--> for s db
...
--> for s db s db
...
--> for s db s db s db
Reproducer:
$ touch ~/.local/share/fish/generated_completions/foo.fish
$ cargo install --path . --debug
$ ~/.cargo/bin/fish -d autoload -c 'function foo; end; for i in 1 2; complete -C"foo "; end'
We redundantly autoload the embedded file, which, by definition doesn't change.
This happens when
1. the "embed-data" feature is enabled (default for "cargo install")
2. there is a completion file in generated_completions
which triggers a hack to give precedence to "embedded:completions/git.fish"
over "generated_completions/git.fish".
Since we always load all file-based files first, we clobber the autoload cache
("self.autoloaded_files") with the mtime of the generated completion file, even
if we're never gonna return it. This makes the embed-data logic think that
the asset has changed (which is impossible! But of course it is possible that
"fish_complete_path" changes and causes a need to load "embedded:git.fish").
Fix that by treating embedded files more like normal files. This is closer
to historical behavior where $__fish_data_dir/{functions,completions}
are normal directories. Seems like this should fix a false negative in
"has_attempted_autoload" which feels useful.
Add a dead test, I guess. It's not run with feature="embed-data" yet. In
future we should test this in CI.
This documents an invariant established by 532abaddae (Invalidate stale
autosuggestions eagerly, 2024-12-25). It was initially broken but fixed in
ba4ead6ead (Stop saving autosuggestions that we can't restore, 2025-01-17).
When two fish processes rewrite the uvar file concurrent, they rely on the
uvar file's mtime (queried after taking a lock, if locking is supported) to
tell us whether their view of the uvar file is still up-to-date. If it is,
they proceed to move it into place atomically via rename().
Since the observable mtime only updates on every OS clock tick, we call
futimens() manually to force-update that, to make sure that -- unless both
fish conincide on the same *nanosecond* -- other fish will notice that the
file changed.
Unfortunately, commit 77aeb6a2a8 (Port execution, 2023-10-08) accidentally
made us call futimens() only if clock_gettime() failed, instead of when
it succeeded. This means that we need to wait for the next clock tick to
observe a change in mtime.
Any resulting false negatives might have caused us to drop universal variable updates.
Reported in https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2098948362
See #10300
(cherry picked from commit 8617964d4d)
When two fish processes rewrite the uvar file concurrent, they rely on the
uvar file's mtime (queried after taking a lock, if locking is supported) to
tell us whether their view of the uvar file is still up-to-date. If it is,
they proceed to move it into place atomically via rename().
Since the observable mtime only updates on every OS clock tick, we call
futimens() manually to force-update that, to make sure that -- unless both
fish conincide on the same *nanosecond* -- other fish will notice that the
file changed.
Unfortunately, commit 77aeb6a2a8 (Port execution, 2023-10-08) accidentally
made us call futimens() only if clock_gettime() failed, instead of when
it succeeded. This means that we need to wait for the next clock tick to
observe a change in mtime.
Any resulting false negatives might have caused us to drop universal variable updates.
Reported in https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2098948362
See #10300
When locking the uvar file, we retry whenever flock() fails with EINTR
(e.g. due to ctrl-c).
But not when locking the history file. This seems wrong; all other libc
functions in the "history_file" code path do retry.
Fix that. In future we should extract a function.
Note that there are other inconsistencies; flock_uvar_file() does not
shy away from remote file systems and does not respect ABANDONED_LOCKING.
This means that empirically probably neither are necessary; let's make things
consistent in future.
See https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2095096200
Might help #10300
(cherry picked from commit 4d84e68dd4)
When locking the uvar file, we retry whenever flock() fails with EINTR
(e.g. due to ctrl-c).
But not when locking the history file. This seems wrong; all other libc
functions in the "history_file" code path do retry.
Fix that. In future we should extract a function.
Note that there are other inconsistencies; flock_uvar_file() does not
shy away from remote file systems and does not respect ABANDONED_LOCKING.
This means that empirically probably neither are necessary; let's make things
consistent in future.
See https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2095096200
Might help #10300
clang --version here outputs "clang version 19.1.7"
but it looks like that changed on GHA's Ubuntu runner:
++ clang --version
++ awk 'NR==1 { split($NF, version, "."); print version[1] }'
+ llvm_version='(1ubuntu1)'
which leads to
The CHECK on line 7 wants:
abbr -a -- cuckoo somevalue # imported from a universal variable, see `help abbr`
but there was no remaining output to match.
additional output on stderr:1:111:
=================================================================
==4680==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7bc287a5d402 at pc 0x55e597fa96b6 bp 0x7ffd2bc00700 sp 0x7ffd2bbffea8
READ of size 18 at 0x7bc287a5d402 thread T0
==4680==WARNING: invalid path to external symbolizer!
==4680==WARNING: Failed to use and restart external symbolizer!
Fix that, assuming that "clang --version" always matches the latest symbolizer
that is installed. While at it, leave a "set -x" (which should be the
default for CI), and install llvm explicitly.
WHen "status current-command" is called outside a function it always returns
"fish". An extra newline crept in, fix that.
Fixes 77aeb6a2a8 (Port execution, 2023-10-08).
Fixes#11503
(cherry picked from commit e26b585ce5)
WHen "status current-command" is called outside a function it always returns
"fish". An extra newline crept in, fix that.
Fixes 77aeb6a2a8 (Port execution, 2023-10-08).
Fixes#11503
* Remove `strlen_safe` & `null_terminated_array_length` and use the provided method of `OwningNullTerminatedArray`.
* Remove unneeded traits and make `NullTerminatedArray` private.
2719ae4 adds a special cfg for cygwin to avoid annoying warnings. As cygwin target is usually cross-compiled, cfg! is not enough to detect the correct target. This PR uses CARGO_CFG_TARGET_OS env var instead.
There is no reason to have this file clutter the repo root.
Move it into the `po` directory, and give it a more descriptive name.
Inspired by this discussion:
https://github.com/fish-shell/fish-shell/pull/11463#discussion_r2083453275
I use `template.po` instead of `message.po-template` to be more compatible with
automatic filetype detection. (e.g. vim/nvim detect the former as a po file, but
the latter as a conf file)
This allows msgfmt to detect issues with translations of format strings.
The detection used here is very simple. It just checks if a string contains '%',
and if it does, the entry in the po file is preceded by '#, c-format'.
Any entries with this marker are checked by msgfmt in our tests, so if an issue
arises, we will notice before it is merged.
Another regression from d51f669647 (Vi mode: avoid placing cursor beyond last
character, 2024-02-14) "Unfortunately Vi mode sometimes needs to temporarily
select past end". So do the replace_one mode bindings which were forgotten.
Fix this.
This surfaces a tricky problem: when we use something like
bind '' self-insert some-command
When key event "x" matches this generic binding, we insert both "self-insert"
and "some-command" at the front of the queue, and do *not* consume "x",
since the binding is empty.
Since there is a command (that might call "exit"), we insert a check-exit
event too, after "self-insert some-command" but _before_ "x".
The check-exit event makes "self-insert" do nothing. I don't think there's a
good reason for this; self-insert can only be triggered by a key event that
maps to self-insert; so there must always be a real key available for it to
consume. A "commandline -f self-insert" is a nop. Skip check-exit here.
Fixes#11484
(cherry picked from commit 107e4d11de)
The old version just prints the entire command being profiled as-is.
If such a command consists of more than one line, these lines do not have any
padding, and thus visually interfere with the timings.
This commit adds padding, such that all lines but the first one have padding
prepended, such that the original line content starts at the column in which the
first line starts.
This does not work perfectly for subcommands (in the profiling sense,
where the command starts with (regex) '-+>' instead of just '>').
In such cases, even if the command string is indented in the source, the command
will not start with whitespace. However, subsequent lines are not trimmed, so
the might be indented farther than they should be relative to the first line of
the command.
Another regression from d51f669647 (Vi mode: avoid placing cursor beyond last
character, 2024-02-14) "Unfortunately Vi mode sometimes needs to temporarily
select past end". So do the replace_one mode bindings which were forgotten.
Fix this.
This surfaces a tricky problem: when we use something like
bind '' self-insert some-command
When key event "x" matches this generic binding, we insert both "self-insert"
and "some-command" at the front of the queue, and do *not* consume "x",
since the binding is empty.
Since there is a command (that might call "exit"), we insert a check-exit
event too, after "self-insert some-command" but _before_ "x".
The check-exit event makes "self-insert" do nothing. I don't think there's a
good reason for this; self-insert can only be triggered by a key event that
maps to self-insert; so there must always be a real key available for it to
consume. A "commandline -f self-insert" is a nop. Skip check-exit here.
Fixes#11484
The purpose of this script is to simplify the translation-related workflow for
both developers and translators. It runs the xgettext, msgmerge, msgfmt pipeline
(or only parts of it, depending on the arguments), either for all languages, or
for one specific one.
Developers can use the script with the `--no-mo` flag to update the PO files for
all languages after changes to the Rust/fish sources, to keep the translations
up to date. Ideally, this would run automatically for all changes, such that
translations are always up to date, but for now, it would already be an
improvement to run this script before releasing a new version of fish.
Translators can use the script in the same way as developers, to get up to date
PO files. To see their translations in action, the script can be called with
`--only-mo`, which takes the current version of the PO files and generates MO
files from them, which get placed in a location which fish (built with `cargo
build`) can detect.
Translators might also find it useful to specify the language they want to work
on as a non-option argument. This argument should be the path to the po file
they want to work on. Specifying non-existing files to work on a new language is
allowed, but the files must be in the po directory and follow the naming
convention.
Commit b00899179f (Don't indent multi-line quoted strings; do indent inside
(), 2024-04-28) changed how we compute indents for string tokens with command
substitutions:
echo "begin
not indented
end $(
begin
indented
end)"(
begin
indented
end
)
For the leading quoted part of the string, we compute indentation only for
the first character (the opening quote), see 4c43819d32 (Fix crash indenting
quoted suffix after command substitution, 2024-09-28).
The command substitutions, we do indent as usual.
To implement the above, we need to separate quoted from non-quoted
parts. This logic crashes when indent_string_part() is wrongly passed
is_double_quoted=true.
This is because, given the string "$()"$(), parse_util_locate_cmdsub calls
quote_end() at index 4 (the second quote). This is wrong because that function
should only be called at opening quotes; this is a closing quote. The opening
quote is virtual here. Hack around this.
Fixes#11444
(cherry picked from commit 48704dc612)
Commit df3b0bd89f (Fix commandline state for custom completions with variable
overrides, 2022-01-26) made us push a transient command line for custom
completions based on a tautological null-pointer check ("var_assignments").
Commit 77aeb6a2a8 (Port execution, 2023-10-08) turned the null pointer into
a reference and replaced the check with "!ad.var_assignments.is_empty()".
This broke scenarios that relied on the transient commandline. In particular
the attached test cases rely on the transient commandline implicitly placing
the cursor at the end, irrespective of the cursor in the actual commandline.
I'm not sure if there is an easy way to identify these scenarios.
Let's restore historical behavior by always pushing the transient command line.
Fixes#11423
(cherry picked from commit 97641c7bf6)
Commit f4503af037 (Make alt-{b,f} move in directory history if commandline is
empty, 2025-01-06) had the intentional side effect of making alt-{left,right}
(move in directory history) work in Terminal.app and Ghostty without other,
less reliable workarounds.
That commit says "that [workaround] alone should not be the reason for
this change."; maybe this was wrong.
Extend the workaround to Vi mode. The intention here is to provide
alt-{left,right} in Vi mode. This also adds alt-{b,f} which is odd but
mostly harmless (?) because those don't do anything else in Vi mode.
It might be confusing when studying "bind" output but that one already has
almost 400 lines for Vi mode.
Closes#11479
(cherry picked from commit 3081d0157b)
Specifically, the width and precision format specifiers are interpreted as
referring to the width of the grapheme clusters rather than the byte count of
the string. Note that grapheme clusters can differ in width.
If a precision is specified for a string, meaning its "maximum number of
characters", we consider this to limit the width displayed.
If there is a grapheme cluster whose width is greater than 1,
it might not be possible to get precisely the desired width.
In such cases, this last grapheme cluster is excluded from the output.
Note that the definitions used here are not consistent with the `string length`
builtin at the moment, but this has already been the case.
(cherry picked from commit 09eae92888)
This simplifies the logic a bit and performs a better.
Performance improvements for extract_fish_script_messages (time in
microseconds):
- explicit regex: from 128241 to 83471 (speedup 1.5)
- implicit regex: from 682203 to 463635 (speedup 1.5)
The replaces the `strs` list by a corresponding file, which eliminates the need
for looping over the list.
Use sed to transform strings into gettext po format entries.
Format the file with fish_indent and use more expressive variable name for the
file cargo expand writes to.
Performance improvements (in microseconds):
- sort+format rust strings: from 21750 to 11096 (speedup 2.0)
The fish builtin string functions are significantly slower than grep + sed.
The final replacement of \' to ' also does not make any sense here, because
single quotes appear unescaped in Rust strings.
Performance improvement: from 404880 to 44843 (speedup 9.0)
Profiling details (from separate runs):
Time (μs) Sum (μs) Command
174 404880 > set -a strs (string match -rv 'BUILD_VERSION:|PACKAGE_NAME' <$tmpfile |
string match -rg 'const [A-Z_]*: &str = "(.*)"' | string replace -a "\'" "'")
404706 404706 -> string match -rv 'BUILD_VERSION:|PACKAGE_NAME' <$tmpfile |
string match -rg 'const [A-Z_]*: &str = "(.*)"' | string replace -a "\'" "'"
202 44843 > set -a strs (grep -Ev 'BUILD_VERSION:|PACKAGE_NAME' <$tmpfile |
grep -E 'const [A-Z_]*: &str = "(.*)"' |
sed -E -e 's/^.*const [A-Z_]*: &str = "(.*)".*$/\1/' -e "s_\\\'_'_g")
4952 44641 -> grep -Ev 'BUILD_VERSION:|PACKAGE_NAME' <$tmpfile |
grep -E 'const [A-Z_]*: &str = "(.*)"' |
sed -E -e 's/^.*const [A-Z_]*: &str = "(.*)".*$/\1/' -e "s_\\\'_'_g"
28716 28716 --> command grep --color=auto $argv
10973 10973 --> command grep --color=auto $argv
Using a file is significantly faster.
Profiling overview (times in microseconds):
- cargo expand: from 4959320 to 4503409 (speedup 1.1)
- gettext call pipeline: from 436996 to 13536 (speedup 32.3)
- static string pipeline: from 477429 to 404880 (speedup 1.18)
My phone uses dotted underline to indicate errors; that seems nice, a bit
less aggressive than curly. Unfortunately dotted underlines are not as well
supported in terminal emulators; sometimes they are barely visible. So it's
unlikely that we want to use --underline=dotted for an important theme.
Add double and dashed too I guess, even though I don't have a concrete
use case..
Commit f4503af037 (Make alt-{b,f} move in directory history if commandline is
empty, 2025-01-06) had the intentional side effect of making alt-{left,right}
(move in directory history) work in Terminal.app and Ghostty without other,
less reliable workarounds.
That commit says "that [workaround] alone should not be the reason for
this change."; maybe this was wrong.
Extend the workaround to Vi mode. The intention here is to provide
alt-{left,right} in Vi mode. This also adds alt-{b,f} which is odd but
mostly harmless (?) because those don't do anything else in Vi mode.
It might be confusing when studying "bind" output but that one already has
almost 400 lines for Vi mode.
Closes#11479
For backwards compatibility, fish does not treat "{echo,hello}" as a compound
statement but as brace expansion (effectively "echo hello"). We interpret
"{X...}" as compound statement only if X is whitespace or ';' (which is an
interesting solution).
A brace expansion at the very start of a command
is usually pointless (space separation is shorter).
The exception are cases where the command name and the first few arguments
share a suffix.
$ {,1,2,3,4}echo
1echo 2echo 3echo 4echo
Not sure if anyone uses anything like that. Perhaps we want to trade
compatibility for simplicity. I don't have a strong opinion on this.
Always parse the opening brace as first character of a command token as
compound statement.
Brace expansion can still be used with a trick like: «''{echo,foo}»
Closes#11477
Source locations (file name and line number) where a string originates is not
required by gettext tooling. It can help translators to identify context,
but the value of this is reduced by our lack of context support, meaning that
all occurrences of a string will receive the same translation.
Translators can use `rg` or similar tools to find the source locations.
For further details see this thread:
https://github.com/fish-shell/fish-shell/pull/11463#discussion_r2079378627
The main advantage is that updates to the PO files are now only necessary when
the source strings change, which greatly reduces the diff noise.
A secondary benefit is that the string extraction logic is simplified.
We can now directly extract the strings from fish scripts,
and several issues are fixed alongside, mostly related to quoting.
The regex for extracting implicit messages from fish scripts has been tweaked to
ignore commented-out lines, and properly support lines starting with `and`/`or`.
The old regex has the problem that it does not handle lines containing any
non-space characters in front of ` complete` (or ` function`), which results in
`string replace` leaving this part in the resulting string.
For example,
`and complete -d "foo"`
would turn into
`andN_ foo`
if passed to
`string replace --regex $regex 'N_ $1'` (where `$regex` is the `$implicit_regex`) variable.
Another issue are commented-out lines.
This was added without a use case. Now there is a use case (#11084) that
needs it to include all tokens which the sister option "--tokens-expanded"
should not do. The inconsistency is probably not worth it, given that this
"--tokens-raw" use case can be served by a future "read -zal --tokenize-raw".
completions frequently use
argparse ... -- (commandline -xpc)
The "commandline -xpc" output
contains only string tokens.
A syntactically-valid process ("-p") consistes of only string tokens
and redirection tokens. We skip all non-string tokens, but we do include
redirection targets, which are always strings. This is weird, and confuses
completion scripts such as the one above. Leave out redirection targets too.
Part of #11084
Squashed commit of the following:
commit 23163d40bed2d97c72050990cf15db3944ce2ff0
Author: DaiLu Cao <caodailu@foxmail.com>
Date: Thu Apr 24 10:11:04 2025 +0800
Manually review up to line 1055 and modify all Chinese colons ':' to English ':' to prevent potential unknown errors.
commit dca5fb8182b94bffab5034dc5626b2b98d026b6f
Author: DaiLu Cao <caodailu@foxmail.com>
Date: Thu Apr 17 10:50:13 2025 +0800
Manually proofread up to 340 lines
commit 4b2d91c1138f3c8dec15b68aeb0510f02e15a776
Author: DaiLu Cao <caodailu@foxmail.com>
Date: Thu Apr 17 09:50:21 2025 +0800
use msgfmt check and fix all error
commit e2470d81c01ab7bf46d3d6ffd0291a05d4b38e13
Author: DaiLu Cao <caodailu@foxmail.com>
Date: Wed Apr 16 11:10:54 2025 +0800
Fix translation error converting '\\n' to '\\ n' error
commit 7ff970d06ce950aee35e1fb0ec70338f7bd42c1d
Author: DaiLu Cao <caodailu@foxmail.com>
Date: Wed Apr 16 10:53:38 2025 +0800
Fix make error, local cargo test completed
commit 018dfa225530a85486903ef58d47f4c358956b0b
Author: DaiLu Cao <caodailu@foxmail.com>
Date: Fri Apr 11 16:46:36 2025 +0800
modification of make errors
commit cbebd506a500aecc0669dce7f08422fcfed5615f
Author: DaiLu Cao <caodailu@foxmail.com>
Date: Fri Apr 11 15:45:01 2025 +0800
The second modification of make errors are all symbol problems
commit f75c3f7a2a84ffaea4eb642532b5a24da1c9154f
Author: DaiLu Cao <caodailu@foxmail.com>
Date: Fri Apr 11 15:27:01 2025 +0800
Re-add Chinese translation, try to solve the problem of make failing
commit 58551be20d261e3466a9e4ede290675f633e94a3
Author: DaiLu Cao <caodailu@foxmail.com>
Date: Fri Apr 11 15:06:01 2025 +0800
Supplement Chinese translation
This greatly reduces the number of changes necessary to the PO files when the
Rust/fish source files are updated. (Changes to the line number can be applied
automatically, but this adds a lot of noise to the git history.)
Due to the way we have been extracting Rust strings, differentiation between
the same source string in different contexts has not been possible regardless
of the change.
It seems that duplicate msgid entries are not permitted in PO files, so since we
do not use context to distinguish the strings we extract, there is no way to
have context-/location-dependent translations, so we might as well reduce the
git noise by eliminating line numbers.
Including source locations helps translators with understanding context.
Because we do not distinguish between contexts for a given source string,
this is of limited utility, but keeping file names at least allows to open the
relevant files and search them for the string. This might also be helpful to
identify translations which do not make sense in all context in which they are
used. (Although without adding context support, the only remedy would be to
remove the translation altogether, as far as I can tell.)
For extraction from Rust, additional issues are fixed:
- File name extraction from the grep results now works properly. Previously,
lines not starting with whitespace resulted in missing or corrupted matches.
(missing if the source line contains no colon followed by a whitespace,
corrupted if it does, then the match included the part of the line in front of
the colon, instead of just the location)
- Only a single source location per string was supported (`head -n1`). The new
approach using sed does not have this limitation.
Commit daa692a20b (Remove unnecessary escaping for # and ~ inside key name
tokens, 2025-04-01) stopped escaping ? in fish_key_reader output. This is
generally correct but not if the "qmark-noglob" feature flag is turned off.
Add that back, to be safe.
While at it, pass an environment variable more explicitly in a test.
After nix updated to 0.30, all functions related to file descriptor accepts impl AsFd, e.g., BorrowedFd. This PR is a minimal update. It tries to use impl AsFd as long as possible, but uses BorrowedFd in some places. Yes it introduces unsafe, but doesn't introduce new unsafe code.
This merges a large set of changes to the fish AST, with the intention of
making the code simpler.
There's no expected user-visible changes here, except for some minor
changes in the output of `fish_indent --dump-parse-tree`.
Ast parsing is about 50% faster measured via
`cargo +nightly bench --features=benchmark bench_ast_construction`
and also uses less memory due to some size optimization.
The biggest change is removing the `Type` notion from `Node`. Previously
each Node had an integer type identified with it, like Type::Argument. This
was a relic from C++: types were natural in C++ and we could use LLVM-style
RTTI to identify Nodes, leveraging the fact that C++ has inheritance and so
Type could be at the same location in each Node.
This proved quite awkward in Rust which does not have inheritance. So
instead we switch to a new notion, Kind:
pub enum Kind<'a> {
Redirection(&'a Redirection),
Token(&'a dyn Token),
Keyword(&'a dyn Keyword),
VariableAssignment(&'a VariableAssignment),
...
and a `&dyn Node` can now return its Kind. Basically leveraging Rust's enum
types.
Interesting lesson about the optimal way to construct ASTs in both
languages.
This eliminates a bunch of the different functions from NodeVisitorMut.
It also removes the runtime polymorphism - now it's a generic instead of
using &dyn. The reason is that there's only one implementation of
NodeVisitorMut so there's no size savings from polymorphism.
We can parse two different things via Ast:
1. A regular job list
2. A freestanding argument list, as used in `complete --arguments ...`
This second case is specific to one use.
Prior to this commit, we parsed the Ast and then "forgot" what we parsed,
storing a &dyn Node. Then we had to cast it to the right type, and assert,
and etc.
Make Ast generic over the Node type it parsed, and default the Node type to
JobList. This simplifies call sites.
This begins the process of replacing the underlying Node "type" notion with
Kind. A Kind is an Enum of all of the possible node types, except with
Token and Keyword collapsed into one.
The idea is, rather than this:
if node.type() == Type::Argument {
let arg = node.as_argument().unwrap();
...
}
we can instead do this:
if let Kind::Argument(arg) = node.kind() {
// we already have arg
}
There is also a cast() function:
let arg: Option<Argument> = node.cast()
which may be convenient in some places.
The big thing we lose is the ability to talk about a Node's type without
actually having a Node. But this turns out to not be an issue in practice.
Future commits will begin adopting Kind.
Prior to this commit, each Node in the ast could accept a visitor and visit
children either in order or in reverse order. This reverse feature added a lot
of complexity and the only client is Traversal.
Switch Traversal to reverse the nodes itself and remove the reverse bool
elsewhere, leading to some code simplifications.
In the fish AST, each node falls into one of three "categories":
1. A branch: contains child nodes
2. A leaf: no child nodes, contains a source range
3. A list: a sequence of child nodes and nothing more
Prior to this commit the category was explicit in the code for each Node type;
make it instead derived from the node's type. This continues to shrink our
macros.
No functional change expected.
Commit f38646593c (Allow `export` to set colon-separated `PATH`, `CDPATH`
and `MANPATH`., 2017-02-10)
did something very weird for «export PATH=foo».
It essentially does
set -gx PATH (string replace -- "$PATH" (string join ":" -- $PATH) foo)
which makes no sense. It should set PATH to "foo", no need to involve the
existing value of $PATH.
Additionally, the string split / string join dance is unnecessary. Nowadays,
builtin set already handles path variables as is needed here, so get rid of
this special case.
Fixes#11434
Specifically, the width and precision format specifiers are interpreted as
referring to the width of the grapheme clusters rather than the byte count of
the string. Note that grapheme clusters can differ in width.
If a precision is specified for a string, meaning its "maximum number of
characters", we consider this to limit the width displayed.
If there is a grapheme cluster whose width is greater than 1,
it might not be possible to get precisely the desired width.
In such cases, this last grapheme cluster is excluded from the output.
Note that the definitions used here are not consistent with the `string length`
builtin at the moment, but this has already been the case.
This should prevent occurrences of the search string from being found in other
locations (e.g. in a comment).
The whole approach of string extraction from Rust sources is sketchy,
but this at least prevents producing garbage when the content of a string
appears somewhere else unquoted.
The previous version generates files which do not preserve the line number from
the original fish script file, resulting in translation not working.
The new approach is quite ugly, and might have some issues,
but at least it seems to work in some cases.
Extracting explicit and implicit messages works essentially the same way, which
is also reflected in the code being identical, except for the regex.
Extract the duplicated code into a function.
- Apply lint config to entire workspace
- Inherit workspace config for fish-printf
- Allow stdlib printing in fish-printf tests
The current problem which is addressed by this is that warnings about C-String
literals are generated by clippy for code in fish-printf. These literals are not
available with the current MSRV 1.70, but previously the MSRV setting was not
inherited by fish-printf, causing the warning to appear.
Commit b00899179f (Don't indent multi-line quoted strings; do indent inside
(), 2024-04-28) changed how we compute indents for string tokens with command
substitutions:
echo "begin
not indented
end $(
begin
indented
end)"(
begin
indented
end
)
For the leading quoted part of the string, we compute indentation only for
the first character (the opening quote), see 4c43819d32 (Fix crash indenting
quoted suffix after command substitution, 2024-09-28).
The command substitutions, we do indent as usual.
To implement the above, we need to separate quoted from non-quoted
parts. This logic crashes when indent_string_part() is wrongly passed
is_double_quoted=true.
This is because, given the string "$()"$(), parse_util_locate_cmdsub calls
quote_end() at index 4 (the second quote). This is wrong because that function
should only be called at opening quotes; this is a closing quote. The opening
quote is virtual here. Hack around this.
Fixes#11444
As reported in
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$n20_uqiMqatEQcPG79Ca0c2_YvHBHTr-yCVXTEuze_Y
commit f5fac096c0 (Don't move cursor in delete-char, 2017-04-19) fixed the
behavior of Vi mode keys "delete" and "x" when the cursor is at the end of
the buffer, and commit d51f669647 (Vi mode: avoid placing cursor beyond
last character, 2024-02-14) generalized this fix.
This means that the delete-specific fix is no longer necessary. Remove it.
Note that if the cursor is at end of a line but not the last line, the
behavior of "delete" in Vi mode is still wrong. It should stay on the line.
This is a weird confusion between the "end" and "terminate" token
types.
"end" is the end of the "line" - a newline or ";".
"terminate" is the end of the "file" - like pressing newline
interactively or having the file end.
So this would count things like `if` and `switch` as a "help"
invocation even if followed by a newline, e.g.
```fish
if; echo foo
```
and
```fish
switch
case foo
```
The result of that was that a naked "if" in a script file isn't an
error, but doesn't start a block either, so if you complete the block
it would count the "end" as superfluous, which sends you on a bit of a
hunt to figure out where the block start is missing.
This script was broken by the changes to profiling output in
9d904e1113.
The new version works with both the old and new profiling output, even when
mixed. The script output has been adjusted to match the new profiling style
better.
This also adds basic error handling for situations where the script is invoked
incorrectly and makes the file executable.
The first two attempts skip over empty variables and the last one doesn't.
This is fine but since we need the default case anyway, might as well reuse
it here too. (An empty color variable is treated the same way a missing
color variable is.)
I don't have a runnable test case but this does seem to have bitrotted.
Originally, we only cared about keys and the EOF and check-exit events.
Returning one of the other new events here seems totally wrong.
Try to fix this, and move the logic closer to where it's needed, so we no
longer need to update its name and we're less likely to forget to update it,
and it cannot.
DCS commands stop at ST ("\e\\"). Make sure we don't stop at just "\e". I
don't know of any command that will actually include the escape byte in its
payload but better safe than sorry.
The input queue doesn't want to be blocked, so let's decide later what to
do with a mouse click. This fixes the potential problem where a mouse click
is ignored if it is received while we're waiting for the terminal to repond
to a query.
While we are waiting for a query response from the terminal, we defer any
input processing until we receive our query response
Then that response is promoted to the front of the input queue, and
remaining inputs are processed in order.
We accidentally process focus events, which may run arbitrary code. We can't
do this; it breaks a lot of invariants (for example the it can invalidate
the cursor positions for CursorPositionQuery, or it can cause fish to exit
before fully consumeing a query response).
Make sure we only process known-safe events. We definitely need to process
CheckExit (in case we received SIGHUP). I guess we should also process Eof,
in case the terminal is buggy.
These code paths have a tiny bit of logic in common, share that.
Maybe this should be nested in ImplicitEvent, and maybe Eof and CheckExit
shouldn't be..
This object is initialized once just before we start reading from the terminal.
Once seems to be the appropriate type for this. This gets rid of an awkward
enum variant.
We never need to access this from other threads, so a Mutex is overkill.
Leave behind stale variable names like "wait_guard" to be cleaned up by the
next commit.
Since TestInputEventQueuer is used concurrently in tests,
give it its own private object, to avoid borrowing conflicts.
Same for fish_key_reader; this fixes the issue that fish_key_reader potentially
reads keyboard input before a query is finished.
Whenever config.fish runs (interactive) builtin read, we push and pop a
top-level, before the main shell's reader.
The terminal state outlives all readers, so its scope should reflect that
to avoid redundant initialization. Move it into the parser.
This is also used by a following commit that wants to access the query state
from a builtin. This should work even if no reader is active.
Note that Mutex doesn't really make sense here - the next commit will fix that.
The differences between color variables and set_color implementation have
gotten somewhat small so make them explicit by getting rid of this code clone.
Outputter::set_text_face() has clever caching logic that is not always needed
by builtin set_color -- in fact, it even needs to explicitly disable the
cache for foreground and background colros -- but this might still be worth it.
As reported in https://github.com/fish-shell/fish-shell/issues/11325, we have logic that
implicitly activates bold mode.
Even worse: the test case from https://github.com/fish-shell/fish-shell/issues/11426 shows that
we're not even consistent about that.
To reproduce, use
set -g fish_pager_color_background --background=fff
set -g fish_pager_color_prefix --underline --bold 000
set -g fish_pager_color_completion
set -g fish_pager_color_description
complete : -s a -l all -d asdf
and type ": -" <TAB>
The second prefix is underlined but not bold,
because the implicit bold mode has a subtle bug.
Now if we were to fix this, using
diff --git a/src/terminal.rs b/src/terminal.rs
index b86a7d85fe..7791d34936 100644
--- a/src/terminal.rs
+++ b/src/terminal.rs
@@ -589,7 +589,7 @@
// Lastly, we set bold, underline, italics, dim, and reverse modes correctly.
if style.is_bold()
&& !self.last.style.is_bold()
- && !bg_set
+ && !(bg_set && !last_bg_set)
&& self.write_command(EnterBoldMode)
{
self.last.style.bold = true;
that would make the description bold as well, which would probably cause chaos.
Either way, it seems wrong to expand this hack.
Let's remove it.
For better or worse, we can't safely update the default theme yet on
an existing user's machine, because we have set universal variables.
This means that fish_color_search_match and fish_pager_color_progress on
existing installations are no longer bold. That's probably acceptable.
The former was hard to read for the longest time, until 9af6a64fd2 (Fix
bad contrast in search match highlighting, 2024-04-15). The progress info
is probably not a big deal.
Attentive users may run "fish_config theme choose 'fish default'". Perhaps
we should tell them on upgrade?
Closes#11325
(As suggested in 84e7fbd466 (Make default .theme file consistent with uvars,
2022-02-03))
Historical behavior in default fish is that
1. fish_color_keyword and fish_color_option are unset, meaning they
default to their fallbacks, fish_color_command and fish_color_param.
2. colors not mentioned in the default them, such as
fish_pager_color_secondary_background, are unset
"fish_config theme save fish\ default"
- sets group 1 to a non-empty value (deactivating the fallbacks)
- sets group 2 to an empty value (which has no function change except it
changes completions for builtin set)
Both are probably fine. I guess the historical behavior is a bit nicer.
But the new behavior is simpler. We can definitely optimize it later,
for example by never redundantly setting universal color variables to an
empty value.
The foreground component of fish_color_search_match was first used in commit
9af6a64fd2 (Fix bad contrast in search match highlighting, 2024-04-15)
which also changed it from bryellow to white. Unfortunately it forgot to
update the themes. Probably all of them want to the default, so let's do that.
We only query for the cursor position if either
1. if the terminal sends an XTGETTCAP response indicating it supports scroll
forward (terminfo code indn)
2. if the terminal sends a mouse click event
In practice, the terminals that do either are also capable of reporting the
cursor position, so let's require that for now.
We could definitely make this optional, and degrade gracefully -- that's
what I originally intended.
But maybe we don't need it? Keeps things simpler. In future, we can add a
timeout, and print an error, to help debugging terminals.
Old versions of ConHost and Putty can't parse DCS sequences.
For this reason, we briefly switch to the alternate screen buffer while sending
DCS-format (e.g. XTGETTCAP) queries. For extra paranoia, we wrapped this
procedure in a synchronized update. This doesn't seem to be needed; neither
ConHost nor Putty show glitches when the synchronized update is omitted.
As of today, every terminal that implements XTGETTCAP also implements
synchronized updates but that might change.
Let's remove it, to reduce surprise for users and terminal developers.
As a bonus, this also fixes a glitch on Terminal.app which fails to parse
the synchronized-update query (`printf '\x1b[?2026$p'`) and echoes the "p"
(bug report ID FB17141059). Else we could work around this with another
alternate screen buffer.
Unfortunately, this change surfaces two issues with GNU screen. For one,
they don't allow apps to use the alternate screen features (the user may
allow it with "altscreen on"). Second, screen unconditionally echoes
the payload of DCS commands. A possible fix has been suggested at
https://lists.gnu.org/archive/html/screen-devel/2025-04/msg00010.html
I think this combination of behaviors is unique among terminals. I'm sure
there are more terminals that don't parse DCS commands yet, but I think almost
all terminals implement alternate screen buffer. Probably only terminal
multiplexers are prone to this issue. AFAICT very few multiplexers exists,
so we can work around those until they are fixed.
Disable XTGETTCAP queries for GNU screen specifically. Unfortunately screen
does not implement XTVERSION, so I don't know how to reliably identify
it. Instead, check STY and some commonly-used values TERM values.
This has false negatives in some edge cases.
But the worst thing that happens is that "+q696e646e" will be echoed once
at startup, which is easy to ignore, or work around with something like
function workaround --on-event fish_prompt
commandline -f repaint
functions --erase workaround
end
which I don't think we should apply by default, because it can mask other
issues.
We should give screen more time to respond. I guess I'll open an issue so
we don't forget. In doubt, we can always go back to the previous approach
(but implement it in fish script).
Alternative workaround: instead of the alternative screen buffer, we could
try something like clr_eol/clr_bol to erase the spuriously echoed text. I
tried to do this in various ways but (surprisingly) failed.
"set_color --background=normal" resets all attributes. I don't expect anyone
relied on this behavior. Let's remove it, to reduce surprise. This also
improves consistency with "set_color --underline-color=normal".
As suggested in
https://github.com/fish-shell/fish-shell/issues/11417#issuecomment-2825023522
For backwards compatibility reasons, "set_color normal" still resets
everything though. In future we could make "set_color --foreground=normal"
reset only foreground.
Closes#11418
Some changes fix actual problems, e.g. missing spaces in square bracket tests,
and backticks unintentionally causing code execution when intended as formatting.
Others, such as conservative quoting probably work fine in the old version in
most situations, but it's nice to have some additional safety.
Using `{ ..; }` instead of `(..)` is just a small performance enhancement.
Many of these issues were identified by shellcheck, which might be useful in CI
as well.
Given
set -g fish_color_error --background=red --background=blue
set_color --background=red --background=blue
Historically, the former would use the first color (red) while the equivalent
set_color command uses the second one (blue).
This changed in 037c1896d4 (Reuse wgetopt parsing for set_color for internal
colors, 2025-04-13) which gave set_color semantics to the former.
This seems like the wrong choice set_color is less important.
For foreground colors we already pick the best color in a way that's consistent
across both. Let's extend this approach to background and underline colors
(even though I'd not really recommend using this feature).
Fixes#11420Closes#11421
Consolidate best_color() calls because the following commit
wants to use this for background and underline colors too.
Switch to Result so we can use the "?" syntax.
Commit 6fcb418ae3 (Enable 24-bit RGB colors by default, 2025-04-11)
invalidated some documentation about fallback colors; by default we prefer
RGB unless the user has explicitly set fish_term256=0.
Note that this made fallback colors much less useful, because they are only
active if the user sets fish_term256=0. Note that setting fish_term24bit=0
is *not* enough; in that case we use the 256 color palette (and assume that
it is a subset of the 24-bit colors).
We do have some themes that use fallback colors:
fish_pager_color_description B3A06D yellow
By default, those will be less useful now.
See also https://github.com/fish-shell/fish-shell/issues/11393
Commit df3b0bd89f (Fix commandline state for custom completions with variable
overrides, 2022-01-26) made us push a transient command line for custom
completions based on a tautological null-pointer check ("var_assignments").
Commit 77aeb6a2a8 (Port execution, 2023-10-08) turned the null pointer into
a reference and replaced the check with "!ad.var_assignments.is_empty()".
This broke scenarios that relied on the transient commandline. In particular
the attached test cases rely on the transient commandline implicitly placing
the cursor at the end, irrespective of the cursor in the actual commandline.
I'm not sure if there is an easy way to identify these scenarios.
Let's restore historical behavior by always pushing the transient command line.
Fixes#11423
Commit cebc05f6c1 (Reset is not a color, 2025-04-15) tried to simpilfy
this behavior but forgot about cases like "set_color --background=normal
red --bold" where we do want to continue after resetting background.
Closes#11417
Add a new underline-color option to set_color (instead of adding an optional
color argument to --underline); this allows to set the underline color
independently of underline style (line, curly, etc.). I don't think this
flexibility is very important but this approach is probably the least hacky.
Note that there are two variants:
1. \e[58:5:1m
2. \e[58;5;1m
Variant 1 breaks:
breakage from colon-variant for colored underlines
- cool-retro-term makes text blink
- GNU screen (goes into bold mode)
- terminology (goes into bold mode)
Variant 2 would break:
- mintty (Cygwin terminal) -- it enables bold font instead.
- Windows Terminal (where it paints the foreground yellow)
- JetBrains terminals echo the colons instead of consuming them
- putty
- GNU screen (goes into bold mode)
- st
- urxvt
- xterm
- etc.
So choose variant 1.
Closes#11388Closes#7619
set_color --underline=curly outputs \e[4:3m which breaks the following
terminals:
- Terminal.app interprets it as yellow background
- abduco and dvtm interpret it as green foreground
- JetBrains terminals interprets it as yellow background
- urxvt interprets it as yellow background
terminals that interpret curly as single underline:
- tmux [1]
- emacs ansi-term [2]
- emacs vterm
- GNU screen (also wrongly turns on italic mode)
- terminology (also wrongly turns on italic mode)
- Vim's :terminal
[1]: https://github.com/orgs/tmux/discussions/4477
[2]: https://lists.gnu.org/archive/html/bug-gnu-emacs/2025-04/msg01093.htmlCloses#10957
This workaround was added in commit d66700a0e4 (Color work, 2012-02-11).
I don't understand why it would be necessary, it seems redundant. Bravely
remove it. Would be interesting to know which terminal caused the motivating
problem. Terminal.app and others seem to be unaffected by this change.
This command does not work
set_color --background=reset
These seem to work
set fish_color_normal reset
set fish_color_normal --background=reset
but I don't understand why anyone would do that, since an empty color option
gives the same behavior.
Also "reset" is totally undocumented, since "normal" is our canonical spelling.
Let's simplify things by removing support for reset everywhere except if it's
a foreground color (since there are some uses of "set_color reset" out there).
Also, simplify the set_color logic accordingly.
Our highlighting module allows different highlight roles for foreground
and background.
Other users of our color-parsing logic have no need for this.
Historically we have passed an "is_background" bool and only parsed what we're
interested in. This sort of makes sense because it's exactly what we need,
but it meant that the special behavior spread quite far.
There is no real need for spreading it; a function with the behavior "parse
a text face but honor is_background" is strictly more complex than "parse a
text face". Additionally, any performance optimization is only relevant if
the user specifies faces that won't be used, which is a very unusual case.
Let's isolate this logic in the highlighting module.
The parent commit got rid of the is_background parameter that determined
the meaning of the return value (fg/bg); since we always return both now,
give them names.
A following commit wants to add other underline styles. At most one underline
style can be active at one time. This can't be modelled well by a flat
bitset, so let's use a composable type here.
When the text face changes from bold to non-bold, we need to reset
all attributes since there is no exit_bold_mode.
The same holds for various dim and reverse mode, and future attributes.
A following commit wants to make this logic more robust to addition of future
attributes. Prepare for that by using the new type.
Not sure if this is 100% a good idea but it does remove some duplication.
While at it, change parse_color_maybe_none to actually return Option::None
and not Color::None which means something else (see a following commit).
Our "Color" type also includes text styling (bold, italics, ...). This doesn't
seem like the perfect way to model this, because the background text styles
are always unused (this is noticeable with some fish_color_* variables).
Introduce a type that represents attributes to apply to text, and nothing
else. Prefer to pass this instead of two Color values with redundant text
style is redundant.
We have a a workaround with a comment saying
> We don't know if exit_attribute_mode resets colors, so we set it to
> something known.
I'm pretty sure fish (and other software) makes this assumption.
I'd be very surprised if a relevant terminal behaves differently.
Let's remove our attempt to work around around this.
While at it, extract a function to be used in two other places
(but don't change their behavior yet).
A "None" type color means "don't change it, use the last color. So it makes
no sense to ever set "self.last_fg = NONE". The background-color code path
only sets it in the other cases. Let's copy that for the foreground one.
Also, extract this assignment to simplify both code paths.
fish -c 'set_color --print-colors --background blue' |xxd
does not print color enabling sequences but does print *disabling* sequences.
There's no need for that.
RgbColor can also be a named color, so this name is surprising to readers
who don't have the implicit assumption that named colors are the default
and that RGB support is something novel.
tl;dr reduce memory usage and ast complexity. No functional change expected.
This concerns how our ast is represented. Prior to this commit, and ever
since the new ast was introduced, each Node had a reference to its parent -
the so-called "parent pointer". This made it convenient to "walk around"
the AST - for example we could get a command and then walk up the AST to
determine if that command had a decoration (`time`, etc).
This parent pointer concept was natural in C++ for a few reasons:
1. Pointers are idiomatic in C++.
2. Parent pointers were "thin": just regular pointer-sized, e.g.
8 bytes in x86-64.
3. C++'s inheritance means that the pointer can just be stored as a field
in the base Node class. Super easy and efficient.
But these proved to have significant drawbacks when expressed in Rust:
1. Parent pointers form a cyclic data structure which is very awkward in
Rust. We had to use raw pointers and unsafe code.
2. Parent pointers were a `&dyn Node` which is necessarily "fat" (base
pointer + vtable pointer), taking up 16 bytes on a 64 bit machine. This
greatly bloated the size of the AST because our AST is quite fine (many
detailed node types).
3. The lack of inheritance means that parent pointers had to be repeated
for every node and exposed through the Node trait, which was awkward and
verbose.
In fact storing parent pointers is rather uncommon among AST
implementations. For example, LLVM does not do this; instead it dynamically
constructs a map of parent pointers on demand (see `ParentMapContext`).
fish could do this or something like it, but in fact we can do better: we
can tweak Traversal to provide parent pointers.
As a reminder, Traversal is a way of naturally iterating over all AST nodes
in a for loop:
for node in ast.walk() {...}
This is in-order ("top-down"). A parent node is yielded before its children.
Prior to this commit, this worked as follows: the Traversal maintained a
stack of next-to-be-yielded nodes. The `next()` function would pop off the
next node, push all of its children onto the stack, and then yield that
popped node.
We can easily make Traversal remember the sequence of parents of a given
Node by tweaking the Traversal to remember each Node after popping it. That
is, mark each Node in the stack as "NeedsVisit" or "Visited". Within
`next()`, check the status of the top node:
- NeedsVisit => mark it as Visited, push its children, and return that Node
- Visited => pop it, discard it, and try again
This means that, for any Node returned by `next()`, we can get the sequence
of parents as those Nodes that are marked as Visited on the stack.
The net effect of all of this is a large decrease in ast complexity and
memory usage. For example, __fish_complete_gpg.fish goes from 508 KB to 198 KB,
as measured by `fish_indent --dump-parse-tree`.
There's somewhat higher memory usage for Traversal, but these are transient
allocations, not permanent.
This removes parent back-pointers from ast nodes. Nodes no longer store
references to their parents, resulting in memory size reductions for the ast
(__fish_complete_gpg.fish goes from 508 KB to 198 KB in memory usage).
These depths are used in calculating indents for ast pretty-printing.
This moves away from parent back-pointers, so that we can ultimately remove
them.
Prior to this commit, Traversal was a convenient way to walk the nodes of
an ast in pre-order. This worked simply: it kept a stack of Nodes, and then
when a Node was visited, it was popped off and its children added.
Enhance Traversal to track whether each node on the Stack is `NeedsVisit`
or `Visited`. The idea is that, when a Node is yielded from next(), we can
reconstruct its parents as those Visited nodes on the Traversal stack.
This will allow clients to get the parents of Nodes as they are traversed
without each Node needing to explicitly save its parent.
This function hid a bug! It converted two Nodes to `*const ()` which discards
the vtable pointer, using only the data pointer; but two nodes can and do have
the same data pointer (e.g. if one node is the first item in another).
Add the (statically dispatched) is_same_node function with a warning comment,
and adopt that instead.
Now that we have more confidence in our pointers, we can allocate directly
more often, instead of always through Box. This recovers the performance
lost from the previous commit.
Prior to this commit, lists of items (e.g. an argument list to a command) would
each be Boxed, i.e. we had effectively Vec<Box<Item>>. The rationale here is
that we had raw pointers and pointer stability was important to enforce.
But we have fewer raw pointers now - only the parent pointers - and we can be
confident that the Ast will not change or move after construction. So remove
this intermediate Box, simplifying some logic and reducing ast size by ~5%.
This slows down Ast construction because we're still constructing
the Box and moving things in and out of it - that will be addressed in
subsequent commits.
This saves a decent amount of memory, both because we no longer have excess
capacity sitting around that we'll never use, but also because we no longer need
to store the "capacity" value.
This makes the destinations update dynamically when they are added/removed.
Unquote the echo statement so that it is correctly paresd by the -a options.
Indicate the units of the durations (microseconds).
Right-align the durations for better readability.
Use `format!` instead of `fprintf` for more flexible formatting.
Write to `File` instead of raw fd.
Closes#11396
- Reorganize completions and options so they are easier to read.
- Add destination UUIDs to completetions as well as descriptions
- Add a few missing sub commands
Two issues:
1. typing the codepoint 0x123456 into fish_key_reader:
$ fish_key_reader -cV
# decoded from: \xf4\xa3\x91
bind \xf4 'do something'
# decoded from:
bind \xa3 'do something'
# decoded from:
bind \x91 'do something'
The invalid codepoint is represented in its original encoding, which leaks
to the UI. This was more or less intentionally added by b77d1d0e2b (Stop
crashing on invalid Unicode input, 2024-02-27). That commit rendered it
as replacement byte, but that was removed for other reasons in e25a1358e6
(Work around broken rendering of pasted multibyte chars in non-UTF-8-ish
locale, 2024-08-03).
We no longer insert such (PUA) codepoints into the commandline. The "bind"
comes above would work however. I don't think this is something we want
to support. Discard invalid codepoints in the reader, so they can't be
bound and fish_key_reader shows nothing.
2. builtin read silently drops invalid encodings This builtin is not really
suited to read binary data (#11383 is an error scenario), but I guess it can
be bent to do that. Some of its code paths use str2wcstring which passes
through e.g. invalid UTF-8. The read-one-char-at-a-time code path doesn't.
Fix this.
As mentioned in
https://github.com/fish-shell/fish-shell/pull/9688#discussion_r1155089596,
commit b77d1d0e2b (Stop crashing on invalid Unicode input, 2024-02-27), Rust's
char type doesn't support arbitrary 32-bit values. Out-of-range Unicode
codepoints would cause crashes. That commit addressed this by converting
the encoded bytes (e.g. UTF-8) to special private-use-area characters that
fish knows about. It didn't bother to update the code path in builtin read
that relies on mbrtowc as well.
Fix that. Move and rename parse_codepoint() and rename/reorder its input/output
parameters.
Note that the behavior is still wrong if builtin read can't decode the
input; see the next commit.
Fixes#11383
This also changes the single-byte locale code path to treat keyboard input
like "\x1ba" as alt-a instead of "escape,a". I can't off-hand reproduce
a problem with "LC_ALL=C fish_key_reader", I guess we always use a UTF-8
locale if available?
As reported in
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$BDVmBtBgtKCj45dVfS36rP7Y6Fo7E4uBg1vcH9IIIQg
tmux new-session -c "" fish -C 'echo $PWD'
prints
/home/fishuser/
This is because our path canonicalization function only
removes trailing slashes if there were duplicate slashes in the string.
Else (for the case above), we end up with "trailing == len"
which means we ignore trailing slashes.
I don't think this was intended by 24f1da7f30 (Add a fancy new
paths_are_equivalent function to test for equivalent paths instead of merely
equal ones, 2013-08-27). Fix it.
While at it, also document the command to reset the shape to the default,
which we should probably use. See foot commit 49034bb7 (csi: let CSI 0 q mean
"switch to user configured cursor style", 2019-07-22).
As of today, the XTerm documentation is a not clear on this; in
XTerm itself, CSI 0 q may actually change the cursor because they have an
additional default cursor is configured differently..
Things like branch and tag name can take up a lot of space on the screen. The
empty status may be useful but we're still looking for evidence. For now let's
keep only the conflict status, which is fairly familiar from the Git prompt.
See also #11183
* man: redirect stderr to /dev/null when checking for embedded files
This fixes a bug where `man status` results in "status: fish was not
built with embedded files⏎" printed.
* fish_config and status completions: redirect stderr to /dev/null when checking for embedded files
I am less sure about this commit, can get rid of it.
* status get-file/list-files: add \n to error message when not compiled with embedded files
The original only worked in the manifest directory *and* didn't even
list the right packages.
E.g. for fish it listed "printf", when the package is called
"fish-printf". So we're not keeping it because it's wrong.
Instead let's parse the actual json. It's a shame there is no
simple command to just get it line-delimited, of course.
Fixes#11384
CMake has this entire zoo of weird build types including "MinSizeRel".
I've also seen it set to empty, in distro packages no less.
Since we can't really make them all known to cargo, let's warn.
We could also error, but I'm not convinced there isn't some distro
packager out there setting it to "StrawberriesAndKittens" for some
reason,
and they'd be very cross with us if that stopped working.
See #11376
If you use `set t 10; function fish_prompt; seq $t; set t $(math $t - 1); end` and trigger a repaint, you will see 9 residual lines from the previous prompt.
Now, the right prompt will not be executed only if it is undefined `fish_right_prompt`.
This allows the use of `read -p 'echo left' -R 'echo right'`.
Also changes condition for use of `DEFAULT_PROMPT` for consistency.
I think `set_color ff0000` should default to outputting true-color sequences.
Unfortunately there is no good and widely-supported way to query for true-color
support. `COLORTERM=truecolor` doesn't work in some cases such as ssh.
Since many terminals nowadays implement the RGB sequences, let's try using
them by default.
Note that Emacs's ansi-term implements truecolor now.
See also the discussion around
https://github.com/fish-shell/fish-shell/pull/11345#issuecomment-2794920900Closes#11372
We have basically zero system tests for text coloring/formatting. I have
something in the works that will enable this without forcing tests to parse
the output of "tmux capture-pane -pe".
Fixes#11373
Fixes 17b4b39c8b (Stop reading terminfo database, 2025-03-20).
Use function names which explicitly state their flushing behavior.
When writing history items to a new file, flushing is only done at the end.
When appending items to an existing file, flushing is done for each item, in
order to keep the `first_unwritten_new_item_index` counter consistent with the
file system.
These builds do not use it, and setting it makes it possible to use
stale files.
So instead, we set it to empty. All uses I could find are either fine
with that (`set fish_function_path $__fish_data_dir/functions` - which
would also just be empty, which means it reads the embedded
functions),
or would break even if the variable was set but the directory was
empty (`source $__fish_data_dir/completions/git.fish`).
In case a completion needs a function from another script, run
`complete -C"foo "` to load it, so the full autoloading logic is used.
Otherwise these things break if the path is off. E.g. cargo's version
will fail if you override the cargo completion in
~/.config/fish/completions without also overriding the rustup
completions.
In other cases, fix for empty $__fish_data_dir, which will be coming in the next commit
This reflects better what it is - fish doesn't need to "install"
itself anymore, it just includes the data in the binary.
This also means we could include a separate "embed-man" feature that
can be turned off if you want the man pages to be shipped separately.
Also explain that in the README.
Technically the fish_update_completions files could also be piped to
python, but they'd have to be one file.
So for now, if you start a single-file fish, you'll have to run
fish_update_completions manually.
That fits the idea of having a single file that you move somewhere
better, given that it otherwise would run a script in the background
that creates a bunch of files
Because these are embedded in the fish binary,
we need to rebuild fish once they're changed.
This is only for release builds,
because rust-embed only really embeds in those
(debug builds read from the filesystem).
This is no longer useful, given that we read files from in the binary.
In the upcoming commits, this can be done with status list-files/get-file if you need it
This will load the functions and completions from inside of the fish
binary.
That means its no longer necessary to *install* a self-installable
build for basic functionality.
The functions/completions will be loaded *last*, so they are still
overridable via a file on disk (with the exception of
generated_completions, which we only use as a fallback if no
completions exist).
It still needs to extract files that are to be used by other tools,
including the man pages, fish_config.py, the man page completion
generator.
The remaining issues:
- It no longer prompts to install, but if you tried `fish_config`
after this it would fail to open the tool,
and it would be easy to forget to update those files
So: When and how should this remind you that these files need to be extracted?
Do we want e.g. a builtin that checks the version file (`status installed`)?
This could then be run by `fish_config` and `help` and tell you to run `fish --install`.
- `builtin --help` will fail - we could read these things from inside,
but we'd need groff for that.
Do we want to pre-process these and put them in the builtins themselves?
Do we want to print these on demand in `__fish_print_help` to groff?
- What directories need to still be defined? Does $__fish_data_dir need to keep existing?
Technically this *could* be the main distribution method. Maybe we
could let distro packages skip the embedded documentation and external
files,
but keep the functions/completions in the binary.
This gets the reader out of asting the source and is needed for
autoloader to get it to read a source string directly
Also add an "eval_file_wstr" method as a convenience to run a wstr as if it is a *file*, with a block and stuff
Our use of the terminfo database in /usr/share/terminfo/$TERM is both
1. a way for users to configure app behavior in their terminal (by
setting TERM, copying around and modifying terminfo files)
2. a way for terminal emulator developers to advertise support for
backwards-incompatible features that are not otherwise easily observable.
To 1: this is not ideal (it's very easy to break things). There's not many
things that realistically need configuration; let's use shell variables
instead.
To 2: in practice, feature-probing via terminfo is often wrong. There's not
many backwards-incompatible features that need this; for the ones that do
we can still use terminfo capabilities but query the terminal via XTGETTCAP
directly, skipping the file (which may not exist on the same system as
the terminal).
---
Get rid of terminfo. If anyone finds a $TERM where we need different behavior,
we can hardcode that into fish.
* Allow to override this with `fish_features=no-ignore-terminfo fish`
Not sure if we should document this, since it's supposed to be removed soon,
and if someone needs this (which we don't expect), we'd like to know.
* This is supported on a best-effort basis; it doesn't match the previous
behavior exactly. For simplicity of implementation, it will not change
the fact that we now:
* use parm_left_cursor (CSI Ps D) instead of cursor_left (CSI D) if
terminfo claims the former is supported
* no longer support eat_newline_glitch, which seems no longer present
on today's ConEmu and ConHost
* Tested as described in https://github.com/fish-shell/fish-shell/pull/11345#discussion_r2030121580
* add `man fish-terminal-compatibility` to state our assumptions.
This could help terminal emulator developers.
* assume `parm_up_cursor` is supported if the terminal supports XTGETTCAP
* Extract all control sequences to src/terminal_command.rs.
* Remove the "\x1b(B" prefix from EXIT_ATTRIBUTE_MODE. I doubt it's really
needed.
* assume it's generally okay to output 256 colors
Things have improved since commit 3669805627 (Improve compatibility with
0-16 color terminals., 2016-07-21).
Apparently almost every actively developed terminal supports it, including
Terminal.app and GNU screen.
* That is, we default `fish_term256` to true and keep it only as a way to
opt out of the the full 256 palette (e.g. switching to the 16-color
palette).
* `TERM=xterm-16color` has the same opt-out effect.
* `TERM` is generally ignored but add back basic compatiblity by turning
off color for "ansi-m", "linux-m" and "xterm-mono"; these are probably
not set accidentally.
* Since `TERM` is (mostly) ignored, we don't need the magic "xterm" in
tests. Unset it instead.
* Note that our pexpect tests used a dumb terminal because:
1. it makes fish do a full redraw of the commandline everytime, making it
easier to write assertions.
2. it disables all control sequences for colors, etc, which we usually
don't want to test explicitly.
I don't think TERM=dumb has any other use, so it would be better
to print escape sequences unconditionally, and strip them in
the test driver (leaving this for later, since it's a bit more involved).
Closes#11344Closes#11345
I think multi is always shorter unless we're only moving by one cell.
Also, we want to simplify this for a following commit where we no longer
check if it's supported.
This reverts commit 58347d494a (update PROMPT_SP heuristic, 2016-12-23)
If we write the last column of a line:
printf %0"$COLUMNS"d 0; sleep 3
most terminals will *not* move the cursor to the next line.
This behavior is indicated by the terminfo's xenl (AKA xen or
eat_newline_glitch) boolean capability.
We originally added checks for this capability because ConEmu and Windows
ConHost did not implement it, but they do now.
Also, as mentioned in
https://github.com/fish-shell/fish-shell/pull/11342#issuecomment-2769979520,
we're not aware of any present-day terminal that does not have this behavior,
but the value advertised by terminfo is sometimes wrong.
Let's get rid of this for now. A following commit will document that we
require this behavior.
I don't think we want to support terminals that implement XTGETTCAP but for
some reason don't use CSI Ps S for scroll forward; that would be a needless
complication.
Let's make ctrl-l / scrollback-push fail hard if a terminal does this.
Confusingly kitty and foot use different response formats, but happily we
no longer care.
An upcoming commit will document that we require the CSI Ps S style.
scoped_buffer borrows the screen to be able to flush buffers on drop. This is
a bit intrusive (see also 29ae571afa (Make scoped_push nicer, 2024-12-28)).
Not sure what's the best solution -- probably we should always pass the
outputter as parameter, removing the field.
For now let's at least contain the effects of this.
This part of the code could use some love; when we happen to clear the
selected text, we should end the selection.
But that's not how it works today. This is fine for Vi mode, because Vi
mode never deletes in visual mode.
Let's fix the crash for now.
Fixes#11367
`Duration::as_nanos()`
"Returns the total number of nanoseconds contained by this Duration."
https://doc.rust-lang.org/core/time/struct.Duration.html#method.as_nanos
Because we are indicating the time in milliseconds, we cannot use
`Duration::subsec_nanos()` but we need to manually get the whole duration in
nanoseconds and subtract the duration in milliseconds to get the fractional
part.
With
bind ctrl-r 'sleep 1' history-pager
typing ctrl-r,escape crashes fish in the history pager completion callback,
because the history pager has already been closed.
Prior to 55fd43d86c (Port reader, 2023-12-22), the completion callback
would not crash open a pager -- which causes weird races with the
user input.
Apparently this crash as been triggered by running "playwright",
and -- while that's running typing ctrl-r ligh escape.
Those key strokes were received while the kitty keyboard protocol
was active, possibly a race.
Fixes#11355
This "SpawnedProc(env=os.environ.copy())" seems redundant but it's not, since
the default argument is initialized (with a copy of env) at module-load time.
Reshuffle the code to make it look less odd.
While at it, fix some invalid escape sequence warnings.
We canonicalize "ctrl-shift-i" to "ctrl-I".
Both when deciphering this notation (as given to builtin bind),
and when receiving it as a key event ("\e[105;73;6u")
This has problems:
A. Our bind notation canonicalization only works for 26 English letters.
For example, "ctrl-shift-ä" is not supported -- only "ctrl-Ä" is.
We could try to fix that but this depends on the keyboard layout.
For example "bind alt-shift-=" and "bind alt-+" are equivalent on a "us"
layout but not on a "de" layout.
B. While capslock is on, the key event won't include a shifted key ("73" here).
This is due a quirk in the kitty keyboard protocol[^1]. This means that
fish_key_reader's canonicalization doesn't work (unless we call toupper()
ourselves).
I think we want to support both notations.
It's recommended to match all of these (in this order) when pressing
"ctrl-shift-i".
1. bind ctrl-shift-i do-something
2. bind ctrl-shift-I do-something
3. bind ctrl-I do-something
4. bind ctrl-i do-something
Support 1 and 3 for now, allowing both bindings to coexist. No priorities
for now. This solves problem A, and -- if we take care to use the explicit
shift notation -- problem B.
For keys that are not affected by capslock, problem B does not apply. In this
case, recommend the shifted notation ("alt-+" instead of "alt-shift-=")
since that seems more intuitive.
Though if we prioritized "alt-shift-=" over "alt-+" as per the recommendation,
that's an argument against the shifted key.
Example output for some key events:
$ fish_key_reader -cV
# decoded from: \e\[61:43\;4u
bind alt-+ 'do something' # recommended notation
bind alt-shift-= 'do something'
# decoded from: \e\[61:43\;68u
bind alt-+ 'do something' # recommended notation
bind alt-shift-= 'do something'
# decoded from: \e\[105:73\;6u
bind ctrl-I 'do something'
bind ctrl-shift-i 'do something' # recommended notation
# decoded from: \e\[105\;70u
bind ctrl-shift-i 'do something'
Due to the capslock quirk, the last one has only one matching representation
since there is no shifted key. We could decide to match ctrl-shift-i events
(that don't have a shifted key) to ctrl-I bindings (for ASCII letters), as
before this patch. But that case is very rare, it should only happen when
capslock is on, so it's probably not even a breaking change.
The other way round is supported -- we do match ctrl-I events (typically
with shifted key) to ctrl-shift-i bindings (but only for ASCII letters).
This is mainly for backwards compatibility.
Also note that, bindings without other modifiers currently need to use the
shifted key (like "Ä", not "shift-ä"), since we still get a legacy encoding,
until we request "Report all keys as escape codes".
[^1]: <https://github.com/kovidgoyal/kitty/issues/8493>
This notation doesn't make sense, use either A or shift-a. We accept it
for ASCII letters only -- things like "bind shift-!" or "bind shift-Ä"
do not work as of today, we don't tolerate extra shift modifiers yet.
So let's remove it for consistency.
Note that the next commit will allow the shift-A notation again, but it will
not match shift-a events.
This does two things:
- it stops completing cargo- tools because `cargo --list` already
includes them. This speeds up loading especially with a long $PATH
- it stops using `cargo search` for `cargo add` and install.
this removes a network call, which may be unexpected and can take a
long time
Fixes#11347
While at it, don't escape "?", I don't know why 68e167d576 (f-k-r should
use the user's locale, 2016-06-29) did that. Question mark is only special
in combination with redirections.
This parser was pretty nice but it has some issues with the new syntax.
It's not really needed when most bindings use the new syntax.
Let's remove it altogether.
I don't think there's a relevant terminal where the "bind -k" notation is
still needed. The remaining reason to keep it is backwards compatibility.
But "bind -k" is already subtly broken on terminals that implement either
of modifyOtherKeys, application keypad mode or the kitty keyboard protocol,
since those alter the byte sequences (see #11278).
Having it randomly not work might do more harm than good. Remove it.
This is meant go into 4.1, which means that users who switch back and forth
between 4.1 and 4.0 can already use the new notation.
If someone wants to use the bind config for a wider range of versions they
could use "bind -k 2>/dev/null" etc.
While at it, use the new key names in "bind --key-names", and sort it like
we do in "bind --function-names".
Closes#11342
Extract our own cfg value, to avoid noisy warnings like:
warning: unexpected `cfg` condition value: `cygwin`
--> src/fallback.rs:78:23
|
78 | #[cfg(not(target_os = "cygwin"))]
| ^^^^^^^^^^^^^^^^^^^^
|
The cygwin target will be added to Rust 1.86, so we can get rid of this
after some time.
If the kitty protcol is not supported, we still want to request modifyOtherKeys
and application keypad mode. Since 2d234bb676 (Only request keyboard protocols
once we know if kitty kbd is supported, 2025-01-26), fish_key_reader fails
to turn on those modes if the kitty keyboard protocol is not supported.
FindRust is too clever by half. It tries to do rustup's job for it.
See b38551dde9 for how that can break.
So we simplify it, and only let it check three things:
- Where's rustc? Look in $PATH and ~/.cargo/bin
- Where's cargo? Look in $PATH and ~/.cargo/bin
- What is the rust target (because we pass it explicitly)?
If any of these aren't that simple, we'll ask the user to tell us,
by setting Rust_COMPILER, Rust_CARGO or Rust_CARGO_TARGET.
None of the other things are helpful to us - we do not support windows
or whatever a "unikraft" is, and if the rust version doesn't work
it'll print its own error.
We could add a rustc version check, but that will become less and less
useful because rustc versions since 1.56 (released October 2021) will check rust-version in
Cargo.toml. So even at this point it's only pretty old rust versions already.
If anything changes in one of the listed directories or files, trigger a
rebuild.
Rebuilds are needed to update the version info built into the binaries.
The version info includes an abbreviated git commit hash, as well as information
about whether the repo was in a dirty state (uncommitted changes) when building.
Changes to files not explicitly listed will not trigger a rebuild, so to get
accurate version info upon such changes (also when checking out a different
commit which does not differ in any of the listed files), a rebuild needs to be
triggered manually (e.g. via `cargo clean` or `touch build.rs`).
It appears we're getting the correct output, but in the wrong order,
so pexpect doesn't filter it correctly:
> \r\n\x1b]133;C;cmdline_url=echo%20bar\x07bar\r\n\x1b]133;D;0\x07\x1b[?25h⏎ \r⏎ \r\rprompt 39>\x1b[?2004h
That `\x07bar` should be the \a that marks the end of the escape
sequence, followed by the actual "bar", followed by sequences marking
the end of output...
Text like "simply do" or "just press" is patronizing and unnecessary.
The prose is nicer if it's removed, and in some cases other words are
more specific.
Something like "we'll pretend your prompt is just a ``>``" can stay.
From the cargo docs (https://doc.rust-lang.org/cargo/reference/build-scripts.html#change-detection):
> By default, it takes a conservative approach of always re-running the build script if any file within the package is changed (or the list of files controlled by the exclude and include fields). For most cases, this is not a good choice, so it is recommended that every build script emit at least one of the rerun-if instructions (described below). If these are emitted, then Cargo will only re-run the script if the given value has changed
So, since we emit rerun-if-path-changed, we need to emit *all* the paths.
Failing to do this shows up most visibly as an outdated git version.
Fixes#11332
Consider command line modifications triggered from fish script via abbreviation
expansion:
function my-abbr-func
commandline -r ""
echo expanded
end
abbr -a foo --function my-abbr-func
Prior to commit 8386088b3d (Update commandline state changes eagerly as well,
2024-04-11), we'd silently ignore the command line modification.
This is because the abbreviation machinery runs something similar to
if my-abbr-func
commandline -rt expanded
end
except without running "apply_commandline_state_changes()" after
"my-abbr-func", so the «commandline -r ""» update is lost.
Commit 8386088b3d applies the commandline change immediately in the abbrevation
function callback, invalidating abbrevation-expansion state.
The abbreviation design does not tell us what should happen here. Let's ignore
commandline modifications for now. This mostly matches historical behavior.
Unlike historical behavior we also ignore modifications if the callback fails:
function my-abbr-func
commandline -r ""
false
end
Remove the resulting dead code in editable_line.
See #11324
Commit 50e595503e (completions/git: fix completions for third-party git
commands, 2025-03-03) wasn't quite right, as we can see in the linked
reproduction:
$ fish_trace=1 complete -C 'git machete add --onto '
----> complete -C git-machete\ add\n--onto\
The recursive completion invocation contains a spurious newline, which means
that "--onto" is the command name. The newline is produced by "string escape
-- add --onto" inside a command substitution.
Fix this by interpreting newlines as list separators, and then joining
by spaces.
Fixes#11319
Currently fish errors out with
```fish
fish: Invalid redirection target:
rev <(ls)
^~~~^
```
This isn't very helpful in telling the user what they could be doing instead:
`rev (ls | psub)`.
Closes#11287
We can no longer have a single template that is always inserted. Instead
the web UI shows a menu allowing to select between one of our templates and
a blank one.
Commit f086bc9564 (Maintain ownership when rewriting universal variables
file, 2015-09-26) fixed an issue where "sudo -E fish" would create root-owned
~/.config/fish/fish_variables that break the users's shell.
A simlar issue exists for files in ~/.cache/fish; fix that.
Note that ~/.cache/fish is currently created on first run when we generate
completions from manpages.
See the issue described in #11292
Sometimes, the dirname of a completion is much longer than the basename.
When the dirname is the same for many completions, a long common dirname
prefix makes it hard to see the interesting differences in the basenames.
Fix this by collapsing the dirname prefix to "…/".
In future, we should find a generic way to collapse completions that don't
contain slashes.
Closes#8618Closes#11250
We incorrectly apply highlighting to trailing spaces that follow a command
or argument. This surfaces when the highlighting includes underline, which
is visible even on space characters.
Fix this by and have Claude add a unit test.
Co-Authored-By: Claude <noreply@anthropic.com>
Fixes#11265
In our C++ implementation, these tests were run serially. As pointed out in
https://github.com/fish-shell/fish-shell/issues/11254#issuecomment-2735623229
we run them in parallel now, which means that one test could be changing
the global locale used by another.
In theory this could be fine because all tests are setting setting the
global locale to the same thing but the existence of a lock suggests that
setlocale() is not guaranteed to be atomic, so it's possible that another
thread uses a temporarily-invalid locale.
Fixes#11254
Commit 8bf8b10f68 (Extended & human-friendly keys, 2024-03-30)
add bindings that obsolete the terminfo-based `bind -k` invocations.
The `bind -k` variants were still left around[^*]. Unfortunately it forgot to
add the new syntax for some special keys in Vi mode. This leads to issues if
a terminal that supports the kitty keyboard protocol sends an encoding that
differs from the traditional one. As far as I can tell, this happens when
capslock or numlock is active. Let's add the new key names and consistently
mark `bind -k` invocations as deprecated.
Fixes#11303
[^*]: Support for `bind -k` will probably be removed in a future release -
it leads to issues like https://github.com/fish-shell/fish-shell/issues/11278
where it's better to fail early.
We have this hack where any positional arguments are taken as argument
names if "--argument-names" is given, and that didn't check for
read-only variables.
Fixes#11295
This uses jj's dynamic completions when possible.
This avoids an annoying problem. After 04a4e5c4, jj's dynamic
completions (see the second paragraph of
<https://jj-vcs.github.io/jj/latest/install-and-setup/#command-line-completion>)
do not work very well in fish if the user puts `COMPLETE=fish jj |
source` in their `~/.config/fish/config.fish`. When the user types `jj
<TAB>`, they are instead overridden by fish's built-in non-dynamic
completions.
The difference is subtle. One problem I saw is that `jj new <TAB>` works
as expected (and shows revisions) while `jj new -A <TAB>` becomes broken
(and shows files).
If the user puts `COMPLETE=fish jj | source` in
`~/.config/fish/completions/jj.fish` there is no problem. However, users
might be confused if they run `COMPLETE=fish jj | source` or put it in
their config and it works in a broken fashion. I certainly was.
Meanwhile, I checked that if the user has `jj completion fish | source`
in their `config.fish`, executing `COMPLETE=fish jj
__this_command_does_not_exist | source` afterwards still works
correctly.
Let me know if there's a better approach to this problem.
The chances that xterm-256color breaks anything are miniscule.
In the features we use, there are basically no differences,
especially when you consider that we decode keys independently.
E.g. tmux-256color has differences, but they are either just taste
questions (xterm's clear_screen will also clear scrollback),
or they're just... not actually different?
Terminfo will claim that it uses a different cursor_up and
exit_attribute_mode, but it also understands the xterm ones,
and it sends a different key_home,
but we decode that even with TERM=xterm-256color.
In some cases, terminfo is also just outright *wrong* and will claim
something does not support italics when it does.
So, since the differences are very likely to simply not matter,
throwing a warning is more confusing than it is helpful.
Prior to this commit, the WildCardExpander had one scoped variable, leading to
the annoying "zelf" pattern. Factor this into its own object and pass it around
explicitly, to clean this up.
In C++ it's easy to make an RAII-type object like "increment a counter for
the duration of this function." Such an object might accept a pointer or
reference, increment the value, and then restore it in its destructor. We
do this all the time - for example to mark a region of code as
non-interactive, etc.
Rust makes this more awkward, because now the reference is tracked by the
borrow checker: it "owns" the object for the duration of the function. This
leads to approaches like "zelf" where the object that marks the parser as
non-interactive itself becomes the new parser, but we can't call it "self"
and it's just yucky.
In this commit we introduce a notion of the "scoped data" of the Parser,
factored out of the library data. This is data which is typically set in a
scoped fashion: whether we are a subshell, are interactive, emit fish_trace
debugging info, etc. Crucially we set this as Rc: this allow the scope
itself to share data with the Parser and we can get rid of lots of "zelf"s.
Introduce a new function `Parser::push_scope` which creates a new scope and
allows modifying these variables associated with the scope. This ends up as
a nice simplification.
As part of a plan to overhaul the "scoped_set" pattern, introduce two new
"scoped" types:
ScopedCell is a trivial wrapper around Cell which exposes a function
`scoped_mod`. This allows you to modify the contents of the Cell; the
original contents are restored when the guard is dropped.
ScopedRefCell is similar, except it requires the caller to supply an
accessor which returns a &mut field, and also the new value.
These will be used to replace the rather unsightly scoped_push calls
around the fish codebase.
This concerns completions which wrap other completions. For example, if 'tig'
wraps 'git' then for the duration of the git completions, we need to make a fake
("transient") command line which contains "git" and not "tig".
Previously we had a stack of such command lines, but we never inspected anything
except the last element. Make this a single value.
This add two commands history-last-token-search-backward and
history-last-token-search-forward which behaves like bash's yank-last-arg. So
similar to history-token-search-* but only considers the last argument for
each command.
Closes#10756Closes#11258
As seen in GitHub Actions:
132/193 Test #17: check-completions.fish ...................***Failed 16.28 sec
checks/check-completions.fish..Failure:
There were no remaining checks left to match stdout:1:
OUTPUT from /home/runner/work/fish-shell/fish-shell/share/completions/pulumi.fish: warning: A new version of Pulumi is available. To upgrade from version '3.154.0' to '3.156.0', visit https://pulumi.com/docs/install/ for manual instructions and release notes.
This makes several changes:
- All panes in the current session are now show, instead of just the
current window.
- Instead of using window names when referring to panes (e.g.
"fish-dev.1"), we now use either window indicies ("3.1") or absolute
pane ids (%12). This is mainly because several windows often share the
same window name, e.g. many of my panes are automatically named "fish"
if they are currently running the shell and nothing else.
I put the window names in the descriptions. Because fish uses the
descriptions for completions, completing `fish-dev` is still helpful.
- I include the pane name into the description for a similar reason,
truncated to 15 chars.
- The panes are now ordered carefully, with panes in this window listed
first, then panes are ordered by window, and finally panes are listed
by their id (which does not change when panes are moved between windows)
Example output after `tmux selectp -t <TAB>` for a session with a few
windows. Note that windows 0, 1, and 4 are all named
`fish`. A pane in the current window can be accessed in 3 ways: `3`,
`2.3`, or `%57`.
```
0 (%4 [fish-dev] ~/d/fish-shell <active pane>) 3.1 (%58 [fish] man tmux ~/.c/f...)
1 (%8 [fish-dev] hwatch "jj.logs... <active win.>) 4.0 (%1 [sshd] tmux rename-win...)
2 (%15 [fish-dev] /U/i/d/fish-she... <active win.>) %1 (4.0 [sshd] tmux rename-win...)
3 (%57 [fish-dev] ~/d/fish-shell <active win.>) %4 (2.0 [fish-dev] ~/d/fish-shell <active pane>)
0.0 (%100 [fish] ~) %8 (2.1 [fish-dev] hwatch "jj.logs... <active win.>)
1.0 (%11 [fish] ~/d/_/nixpkgs) %11 (1.0 [fish] ~/d/_/nixpkgs)
1.1 (%38 [fish] ~/.c/f/completi...) %15 (2.2 [fish-dev] /U/i/d/fish-she... <active win.>)
2.0 (%4 [fish-dev] ~/d/fish-shell <active pane>) %38 (1.1 [fish] ~/.c/f/completi...)
2.1 (%8 [fish-dev] hwatch "jj.logs... <active win.>) %41 (3.0 [fish] ~/.c/f/conf.d)
2.2 (%15 [fish-dev] /U/i/d/fish-she... <active win.>) %57 (2.3 [fish-dev] ~/d/fish-shell <active win.>)
2.3 (%57 [fish-dev] ~/d/fish-shell <active win.>) %58 (3.1 [fish] man tmux ~/.c/f...)
3.0 (%41 [fish] ~/.c/f/conf.d) %100 (0.0 [fish] ~)
```
Compared to before:
```
0 (pane) 2 (pane) 0:fish-dev.0 (session:window.pane) 0:fish-dev.2 (session:window.pane) fish-dev (window)
1 (pane) 3 (pane) 0:fish-dev.1 (session:window.pane) 0:fish-dev.3 (session:window.pane)
```
Note that the "before" version describes the same 3 panes several times
in a row, and all the entries involving "fish-dev" are suspect since
there could be another "fish-dev" window (or, more likely, this window
and others could all be named "fish").
Closes#11115
There are some minor updates.
Also, the syntax seems to have changed in tmux 2.4 in 2017,
ef68debc8d/CHANGES (L1484)
Notably, many of the key table commands now use `-T` in place of
the correct `-t`, and the list of key binding tables has changed.
Our versions look like
4.0.0
4.0b1
4.0.1-535-abfef-dirty
But packagers may want to add more information here, and we don't
really care. Note that we no longer ever set the version to "unknown"
since 5abd0e46f5.
Supersedes #11173
Commit 29dc307111 (Insert some completions with quotes instead of backslashes,
2024-04-13) breaks some workflows. Given
touch '[test] file1'
touch '[test] file2'
ls tes<Tab>
we insert completions quoted, which is inconvenient when using globs.
This implicit quoting feature is somewhat minor. But quotes look nicer,
so let's try to keep them. Either way, users can ask for it by starting a
token with «"».
Use quoting only when we insert unique completions.
Closes#11271
This effectively disables "--help", replacing it with just a stand-in
string.
The upshot is that it makes the test suite immune to whether or not it
can find the documentation - until now it needed to *not* find it,
which is weird.
(also it saves some useless lines)
Fixes#11270
The new cursor-end-mode "inclusive" (which is active in Vi mode) is causing
many issues.
One of them is because cancel-commandline wants to move to the end of the
command line before printing "^C". Since "inclusive" cursor mode prevents
the cursor from moving past the last character, that one will be overwritten
with a "^". Hack around this.
Closes#11261
Running
fish_vi_key_bindings
fish_default_key_bindings
ought to maintain cursor shape, at least in the default configuration,
so let's do that.
Fixes 9ef76860e6 (Default Vi cursor shapes for insert/replace mode, 2024-10-26).
Looks like the github actions image now has ninja installed.
This causes a failure; we effectively do
$ (
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo
)
$ make VERBOSE=1
[...]
cd build; cmake .. -G "Ninja" \
-DCMAKE_INSTALL_PREFIX="/usr/local" -DCMAKE_EXPORT_COMPILE_COMMANDS=1
Re-run cmake no build system arguments
CMake Error: Error: generator : Ninja
Does not match the generator used previously: Unix Makefiles
Either remove the CMakeCache.txt file and CMakeFiles directory or choose a different binary directory.
"make" fails because it runs from top-level, with GNUMakefile's logic to
use -GNinja if available. This is at odds with the direct cmake invocation,
which defaults to -G'Unix Makefiles'.
We shouldn't mix direct cmake invocation and the top-level Makefiles, so
run make from the build directory instead.
While at it, update some test invocations missed in 8d6fdfd9de
(Remove cmake "test" target, 2025-02-02). This should
help avoid missing test failure output in CI, see
https://github.com/fish-shell/fish-shell/issues/11116#issuecomment-2629406479
Since commit 0627c9d9af (Render control characters as Unicode Control Pictures,
2020-08-29), we render control character in the commandline as "␇" etc.
They can be inserted via either history search, or bindings such as
bind ctrl-g "commandline -i \a"
That commit incorrectly assumes that the prompt is rendered the same way as
the command line (which goes through "ScreenData" etc).
This is wrong -- prompt text is written to stdout as-is, and a prompt that
outputs \t (tab) or \a (BEL) is valid. The wrong assumption means that we
overestimate the width of prompts containing control characters.
(For some reason, after switching from Vi insert to Vi normal mode, we seem
to get the width right which means the command line jumps around)
Let's revert to the old width computation for any prompt text.
Closes#11252
See f2dde229aa (Revert changes to restore cursor position after undo,
2025-03-05).
I think there are two problems with tmux when doing a final redraw of a
larger-than-screen commandline. One is easy to trigger independent of
f2dde229aa. The other is reproduced by the broken output in the tmux test
removed by that commit. Should root-cause them later.
Use a hack for now; this also happens to fix the broken output in tmux.
For unknown reasons this assertion fails. This means that 1b9b893169 (After
reading corrupted history entry, keep reading older entries, 2024-10-06)
is not fully working. Go back to historical behavior for now.
Closes#11236
* completions/flatpak: don't ignore packages with uppercase in name
`[^A-Z]+` here seems to trim header section in old version flatpak (avoid one
more `tail -n -2`?) but this can ignore packages have uppercase name like
`org.gtk.Gtk3theme.Adwaita-dark`.
* completions/flatpak: use cached `__fish_print_flatpak_packages` for `flatpak install`
rustup has changed its output for 'rustup toolchain list --verbose`.
Teach FindRust.cmake about it, so that it may shamble on.
This was reported against BSD and also affects macOS and ALSO affects Linux; our
CI just doesn't have a new enough rustup. Anyways we can't have nice things.
This feature is nice and desirable, but it was implemented in a intrusive way
by modifying the sequence of bytes we emit when running a command; this in
turn requires changing a bunch of tests.
This sequence hasn't changed in decades and the consequences of changing it
are hard to predict, given that it is likely terminal dependent; we've
already found a regression.
It's fine to reintroduce this but it should be done in a less intrusive way
(conceptually that seems straightforward - we're just remembering the cursor
position).
Revert "Fix spurious blank lines when executing scrolled commandline"
This reverts commit 0e512f8033.
Revert "On undo after execute, restore the cursor position "
This reverts commit 610338cc70.
Most versions of fish don't run any external processes at startup, except
maybe fish_vcs_prompt. This changed recently with a couple additions of uname.
This is probably fine but I guess we can reduce it down to one.
This change feels somewhat wrong. Not sure. I guess we can remove it once
we provide $OSTYPE.
Note that this is also the reason why bindings don't use
bind alt-backspace 'if test "$(uname)" = Darwin ...'
We don't want to expose a private interface in "bind" output.
This fails with:
```
CMake Warning (dev) at cmake/FindRust.cmake:349 (message):
Unexpected output from `rustc --version` for Toolchain
`stable-x86_64-unknown-freebsd`: ``.
Ignoring this toolchain.
Call Stack (most recent call first):
cmake/Rust.cmake:5 (include)
CMakeLists.txt:24 (include)
This warning is for project developers. Use -Wno-dev to suppress it.
-- Rust Toolchain:
CMake Warning at cmake/FindRust.cmake:31 (message):
The rustc executable was not found. Rust not installed or ~/.cargo/bin not
added to path?
Hint: Consider setting `Rust_COMPILER` to the absolute path of `rustc`.
```
For some reason? Disable it for now until someone figures out what's
going on
Commit 6af96a81a8 (Default bindings for token movement commands, 2024-10-05)
has been reverted but not all docs have been.
Key bindings to move by command line argument are quite intuitive, and useful
when moving across URLs or other long arguments.
We have redundant bindings like {alt,ctrl}-left, so let's use one of them
for token movement. We don't want to break the OS-native shortcut for word
movement, so use the other one on the current platform.
Note that Sublime Text does something similar: it uses the native key
binding for word movement, and the vacant one (e.g. `alt-left` on Linux)
for sub-word movement in camel case words.
While there have been 2.5 votes against making this platform dependent,
the majority of feedback was in favor.
This uses uname which seems wrong; we should rather use the OS that the
terminal is running on. I plan to implement this in future, but there's no
consensus yet on whether terminal applications should be allowed to do this.
See #10926
See #11107
As reported on gitter, fish running inside a qemu console randomly fails to
recognize multi-byte sequences like "\e[D" (right); it sometimes recognizes
the first two bytes as "alt-[" and the last byte as the "D" key.
This because 8bf8b10f68 (Extended & human-friendly keys, 2024-03-30) changed
our approach to reading multi-byte key sequences. Previously, we'd wait
forever (or rather fish_sequence_key_delay_ms) for the "D" byte.
As of 8bf8b10f68, we assume the entire sequence is already present in the
input buffer; and stop parsing the sequence if stdin is not readable.
It would be more technically correct to implement the VT state machine but
then we'd probably want to to figure out a timeout or a reset key, in case
of transport or terminal issues.
Returning early is also what we have historically done for multi-byte code
points. Also, other terminal programs have been using it for many years
without problems.
I don't know why this happens in qemu but it seems we can work around by
setting a 1ms timeout. This timeout should be small enough two keys "escape"
and "[" typed by a human will still be seen separate.
Refs:
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$Cfi9wL8FGLAI6_VAQWG2mG_VxsADUPvdPB46P41Jdbshttps://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$O_-LZ1W7Dk6L_4Rj0MyCry6GtO2JQlEas8fH9PrSYT8
As reported in
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$yD_Lutaftf6ytk617kjw5vC-k_OgHRQxIiSRv89uBMI
it's weird that command name completions shadow abbreviation name
completions, given that the abbreviation will the one that will be
executed in the typical cases. Let's put abbreviation completions first;
unique_completions_retaining_order() will take care of removing any command
completions we add later.
When a command like "long-running-command &" exits, the resulting SIGCHLD
is queued in the topic monitor. We do not process this signal immediately
but only after e.g. the next command has finished. Only then do we reap the
child process.
Some terminals, such as Terminal.app, refuse to close when there are unreaped
processes associated with the terminal -- as in, having the same session ID,
see setsid(3).
In future, we might want to reap proactively.
For now, apply an isolated workaround: instead of taking care of a child
process, double-fork to create an orphaned process. Since the orphan will
be reaped by PID 1, we can eventually close Terminal.app without it asking
for confirmation.
/bin/sh -c '( "$@" ) >/dev/null 2>&1 &' -- cmd arg1 arg2
This fix confines the problem to the period during which a background process
is running. To complete the fix, we would need to call setsid to detach the
background process from a controlling terminal. That seems to be desirable
however macOS does provide a setsid utility.
setsid cmd arg1 arg2 >/dev/null 2>&1
Fixes#11181
As of 303af07, iTerm2 3.5.11 on two different machines has two different
behaviors. For unknown reasons, when pressing alt-right fish_key_reader
shows "\e\[1\;9C" on one machine and "\e\[1\;3C" on another.
Feels like iTerm2 interprets modifyOtherKeys differently, depending on
configuration.
We don't want to risk asking for the kitty
keyboard protocol until iTerm2 3.5.12 (see
https://github.com/fish-shell/fish-shell/issues/11004#issuecomment-2571494782).
So let's work around around this weirdness by adding back the legacy
bindings removed in c0bcd817ba (Remove obsolete bindings, 2024-04-28) and
plan to remove them in a few years.
Note that fish_key_reader still reports this as "left", which already has
a different binding, but it looks like literal matches of legacy sequences
have precedence.
Fixes the problem described in
https://github.com/fish-shell/fish-shell/issues/11192#issuecomment-2692247060Closes#11192
Before 798527d79a (completions: fix double evaluation of tokenized commandline, 2024-01-06)
git-foo completions did something like
set -l subcommand_args (commandline -opc)
complete -C "git-foo $subcommand_args "
As mentioned in 368017905e (builtin commandline: -x for expanded tokens,
supplanting -o, 2024-01-06), the "-o" option is bad
because it produces a weird intermediate, half-expanded state.
The immediate goal of 798527d79a was to make sure we do not do any
more expansion on top of this. To that end, it changed the above to
"\$subcommand_args". The meaning is more or less the same[^*] but crucially,
the recursive completion invocation does not see through the variable,
which breaks some completions.
Fix this with the same approach as in 6b5ad163d3 (Fix double expansion of
tokenized command line, 2025-01-19).
[^*]: It wasn't semantically correct before or after -- this was later
corrected by 29f35d6cdf (completion: adopt commandline -x replacing deprecated
-o, 2024-01-22)).
Closes#11205
Given
$ cat ~/.config/kitty/kitty.conf
notify_on_cmd_finish unfocused 0.1 command notify-send "job finished with status: %s" %c
kitty will send a notification whenever a long-running (>.1s) foreground
command finishes while kitty is not focused.
The %c placeholder will be replaced by the commandline.
This is passed via the OSC 133 command start marker, kitty's fish shell
integration.
That integration has been disabled for fish 4.0.0 because it's no longer
necessary since fish already prints OSC 133. But we missed the parameter for
the command string. Fix it. (It's debatable whether the shell or the terminal
should provide this feature but I think we should fix this regression?)
Closes#11203
See https://github.com/kovidgoyal/kitty/issues/8385#issuecomment-2692659161
Something like
write!(f, "foo{}bar", ...)
seems to call f.write_str() thrice.
Splitting a single OSC 133 command into three calls to write(3) might result in
odd situations if one of them fails. Let's try to do it in one in most cases.
Add a new buffered output type that can be used with write!(). This is
somewhat redundant given that we have scoped_buffer(). While at it, remove
the confused error handling. This doesn't fail unless we are OOM (and this
new type makes that more obvious).
This was broken for 4.0 because it used `{}` command grouping.
Instead just do one of the things the fish_git_prompt does.
(the default isn't usable here because it gets the sha from elsewhere)
(cherry picked from commit e925eccad2)
Fix the accidental "git branch" output leaking while making sure we support:
1. unborn branch, where HEAD does not exist (`git init`)
2. detached head (`git checkout --detach`)
Notably computing the branch name should be independent of computing
a diff against HEAD.
In scenario 1 there is a branch but no HEAD,
while in scenario 2 it's the other way round.
Hence we need a separate check to see if we're in a git repo.
"git rev-parse" seems to work. Not sure what's best pracitce.
Also remove the ahead/behind logic, it was broken because it misspelled
@{upstream}.
Fixes#11179
As reported in
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$CLuoHTdvcRj_8-HBBq0p-lmGWeix5khEtKEDxN2Ulfo
Running
fish -C '
fzf_key_bindings
echo fish_vi_key_bindings >>~/.config/fish/config.fish
fzf-history-widget
'
and pressing "enter" will add escape sequences like "[2 q" (cursor shape)
to fish's command line.
This is because fzf-history-widget binds "enter" to a filter
that happens to be a fish script:
set -lx FZF_DEFAULT_OPTS \
... \
"--bind='enter:become:string replace -a -- \n\t \n {2..} | string collect'" \
'--with-shell='(status fish-path)\\ -c)
The above ~/.config/fish/config.fish (redundantly) runs "fish_vi_key_bindings"
even in *noninteractive* shells, then "fish_vi_cursor" will print cursor
sequences in its "fish_exit" handler. The sequence is not printed to the
terminal but to fzf which doesn't parse CSI commands.
This is a regression introduced by a5dfa84f73 (fish_vi_cursor: skip if stdin
is not a tty, 2023-11-14). That commit wanted "fish -c read" to be able to
use Vi cursor. This is a noninteractive shell, but inside "read" we are
"effectively interactive". However "status is-interactive" does not tell
us that.
Let's use a more contained fix to make sure that we print escape sequences only
if either fish is interactive, or if we are evaluating an interactive read.
In general, "fish -c read" is prone to configuration errors, since we
recommend gating configuration (for bind etc) on "status is-interactive"
which will not run here.
Historically, up-arrow search matches have been highlighted by
1. using the usual foreground (from syntax highlighting)
2. using the background from $fish_color_search_match
Commit 9af6a64fd2 (Fix bad contrast in search match highlighting, 2024-04-15)
broke this by also applying the foreground from $fish_color_search_match.
As reported on gitter, there is a meaningful scenario where the foreground
from syntax highlighting should not be overwritten:
set fish_color_search_match --reverse
this copies the foreground from syntax highlighting to the background.
Since commit 9af6a64fd2 overwrites the foreground highlight, the resulting
background will be monocolored (black in my case) instead of whatever is
the syntax-colored foreground.
FWIW the reversed foreground will always be monocolored, because we have
always done 2.
Let's unbreak this scenario by using the foreground from
fish_color_search_match only if it's explicitly set (like we do since
9af6a64fd2).
This is hacky because an empty color is normally the same as "normal", but
it gets us closer to historical behavior. In future we should try to come
up with a better approach to color blending/transparency.
Konsole has a bug: it does not recognize file:://$hostname/path as directory.
When we send that via OSC 7, that breaks Konsole's "Open Folder With"
context menu entry.
OSC 7 producers are strongly encouraged to set a non-empty hostname, but
it's not clear if consumers are supposed to accept an empty hostname (see
https://gitlab.freedesktop.org/terminal-wg/specifications/-/issues/20).
I think it should be fine; implementations should treat it as local path.
Let's work around the Konsole bug by omitting the hostname for now. This
may not be fully correct when using a remote desktop tool to access a
system running Konsole but I guess that's unlikely and understandable.
We're using KONSOLE_VERSION, so it the workaround should not leak into SSH
sessions where a hostname component is important.
Closes#11198
Proposed upstream fix https://invent.kde.org/frameworks/kio/-/merge_requests/1820
As reported in b5736c5535 (Extend iTerm CSI u workaround to < 3.5.12,
2025-02-20), iTerm 3.5.12 has resolved our issues related to the kitty
keyboard protocol. Enable it here too, matching the release branch.
The flag to gate this is set for versions of iTerm that don't have sufficient
support for the kitty keyboard protocol. CSI u is (more or less) the encoding
used by that protocol. Let's name things accordingly. My bad.
Commit 2d234bb676 (Only request keyboard protocols once we know if kitty kbd
is supported, 2025-01-26) queries support for the kitty protocol and acted
upon it after having read next character.
Unfortunately this meant that we don't turn on the kitty protocol until after
we read a character -- since the CSI ? u response does not generate a char
event. Let's query for primary DA additionally, matching what fish does.
In future, we should do a timed wait as well, to avoid terminal responses
leaking when there we exit fish_key_reader too quickly.
Whenever we add logic to print a control sequence that we hadn't printed
before, there is a nonzero risk that a terminal mishandles it.
Terminal-specific workarounds cause pain but are probably better than not
being able to use any new commands provided by terminals.
There is no universal way to identify a terminal. Device attributes (primary
through tertiary) typically get spoofed responses, likely not good enough
for working around bugs in specific versions of a terminal.
The de-facto standard for the terminal name and version is XTVERSION.
It's usually specific to the terminal, except for something like VTE-based
terminals, where we get this (which seems good enough also)
printf '\x1b[>0q'; cat
^[P>|VTE(7803)^[\
Of course querying for XTVERSION can trigger terminal bugs just as well. Let's
start querying for it now -- even without a concrete use case -- to increase
the chance we can use it during crunch time when we don't want to test
anymore. (We typically discover buggy terminals only very late in the release
cycle, most prominently after a release).
When we enable/disable terminal protocols,
we use atomic operations because of issues like
1. halfway through enabling, we might be interrupted by a signal handler.
2. our SIGTERM handler runs the (idempotent) disabling sequences,
so the operations must be async-signal safe.
The flags to keep track of whether things like kitty keyboard protocol are enabled
are "mirrored" between the enabling and disabling logic:
- the enabling logic marks it as enabled *before* enabling anything
- the disabling logic marks it as disabled *after* everything has been disabled
This ensures that we are well-behaved in issue 1; we will always (perhaps
redundantly) disable the kitty keyboard protocol.
We forgot to use the same ordering for bracketed paste.
If we get SIGTERM after this line
BRACKETED_PASTE.store(false, Ordering::Release);
we might exit with bracketed paste still turned on.
Code blocks are often written like
$ echo hello world
hello world
The "$ " is widely understood to introduce a shell command. It's often
easier to copy the whole line than copying everything after "$ ".
This gets more pronounced when there are multiple commands without interleaved
output (either due to omission or the rule of silence). Copying the whole
code block is the most natural first step.
You could argue that this is a presentation issue - the dollar prefix
should be rendered but not copied to clipboard. But in my experience there
are many cases where there is no HTML or Javascript that would allow the
copy-to-clipboard functionality to strip the prefixes.
The "$ " prefix is almost never useful when pasting; strip it automatically.
Privileged commands use "# " as prefix which overlaps with comments, so do
not strip that until we can disambiguate (another potential reason not to
do that would be safety but it's unclear if that really matters).
Add the new logic to the commandline builtin, because we don't know about the
AST in fish script. (Technically, the tokenizer already knows whether a "$
" is in command position and at the beginning of a line, but we don't
have that either (yet).)
Maybe we should move the rest of __fish_paste over as well. I'm not sure what
difference that would make; for one, pasting could no longer be cancelled
by ctrl-c (in theory), which seems like a good direction?
Comments by macOS users have shown that, apparently, on that platform
this isn't wanted.
The functions are there for people to use,
but we need more time to figure out if and how we're going to bind
these by default.
For example, we could change these bindings depending on the OS in future.
This reverts most of commit 6af96a81a8.
Fixes#10926
See #11107
(cherry picked from commit 378f452eaa)
Commit 4f536d6a9b (Update commandline state snapshot lazily,
2024-04-13) add an optimization to update the search field only if
necessary. The optimization accidentally prevents us from resetting
the search field.
Fixes#11161
These are supposed to be small, so we dump the redundant fish_indent
and fish_key_reader - the fish binary can do those jobs too (both as
builtins and if called via symlinks of that name).
We still keep tarballs instead of just compressing so that we have a
file called "fish" and not "fish-amd64-linux"
Commit 82c4896809 (Fix unnecessary undo when exiting the history
pager with an empty cmd and no matches, 2025-02-02) was a nice fix
but failed to account for the code path where we switch from history
search to completion pager (and maybe also the inverse case). In this
case we don't want to undo the transient edit but commit it instead.
Missed write_to_fd calls
Not in 4.0 because fish_indent isn't a builtin there.
This requires str2wcstring, which is awkward but it's not performance-sensitive.
Fixes#11146
I'm running fish 4.0b1 locally and I tried running `help abbr` and
browsing the docs. I noticed one example which wasn't formatted
correctly.
I'm not too familiar with rst, but based on looking at the file, it
seems that this is how example code should be represented.
e697add5b5 (Feature flag to prevent executing off buffered keys, 2025-01-02)
breaks my expectations/habits, and it breaks Midnight Commander.
Additionally, I'm not aware of any case where it actually adds security.
We generally assume that terminal echoback sequences do not contain
control characters except for well-known escape sequences.
This backs out commit e697add5b5.
See #10987, #10991
This can happen if your filesystem on macOS has xattrs, so the newly
created dirs will also have them and `ls` will print an "@" indicator.
Fixes#11137
alt-{left,right} move in the directory history (like in browsers).
Arrow keys can be inconvenient to reach on some keyboards, so
let's alias this to alt-{b,f}, which already have similar behavior.
(historically the behavior was the same; we're considering changing
that back on some platforms).
This happens to fix alt-{left,right} in Terminal.app (where we had
a workaround for some cases), Ghostty, though that alone should not
be the reason for this change.
Closes#11105
Add back the test from 0e512f8033 (Fix spurious blank lines when
executing scrolled commandline, 2025-01-08).
It's flaky in CI (see b8208d72f7 (Remove test for broken tmux output,
2025-01-09)) but that's not a problem for now because we disabled
the entire test CI in 2508cc9de6 (Disable some more tests under CI,
2025-01-14).
Commit c54131c8c5 (Make at least one character of the autosuggestion
always shown, 2025-01-26) draws autosuggetion until exactly the end
of the line, possibly truncated by an ellipsis. The line is "barely"
soft-wrapped; no characters or cursors are on the next line.
This means that the pager can start there (on the next line).
The calculation for available pager height fails to recognize that.
Fix that.
Prior to this change, wcstod_underscores would create a "pruned" string without
underscores, and then parse that. Switch instead to a filtered Iterator, which
can ignore underscores as it traverses the string.
Add a test that completes in a reasonable time only if wcstod_underscores is not
quadratic.
(cherry picked from commit b4577c10e5cf9239bc93c605f431a56d98266a1e)
Currently, when the history pager is selected, fish always one undo away from the original search term. If the search has no matches, the fish replaces the search term with itself (resulting in no visible change, but it is still treated as a transient edit). However, fish ignores undo operations where the replacement is "" by "", leading to an unnecessary undo. For example:
1. Type 'test'.
2. Do ctrl-c.
3. Open the history pager.
4. Make so there are no matches.
5. Exit - you will undo back to 'test'.
This commit also ensures that if you select a pager element that does not change the content of the commandline, it will not be added to the undo history.
Currently, if we return to the present, fish thinks that it still has a transient edit. This results in an unnecessary undo when performing a backward search. For example:
1. Type ': '.
2. Do a backward token search.
3. Do a forward token search.
4. Do another backward token search - this will result in the undo of ': '.
Currently, the search always restarts when moving from the present.
For example:
1. Do a few backward searches.
2. Use PageDown to return to the present.
3. Do another backward search.
4. Now, PageUp does nothing because the search was restarted, even if we maintained search mode.
This adds the ability to complete (and therefore preview) buffer names,
and adds incomplete (aiming to maximize utility/effort, similarly to
b1064ac) bindings to the `tmux` buffer commands.
The main benefit is, IMO, is the tab completion for `tmux paste-buffer
-b` and `tmux show-buffer -b`.
Every reader gets their own wait handle which is wrong and not actually
needed - it's a singleton. We should probaly make it global. Let's
do an intermediate solution for now -- not much time this weekend ;).
Fixes#11110
There is no guarantee that Write::write() will write the entirety of the
provided buffer in one go, regardless of how short it is, because that depends
on the semantics of the underlying write handle (even if it was a
single byte, though in this case that would be because of an interrupt).
The only case I'm aware of that would guarantee a single Write::write() call
would suffice is when writing into a high-level memory-backed buffer, and we
can't make that guarantee (now or in perpetuity).
The current limit can be reached in actual use and still be a usable shell.
E.g. in #11095 someone had `git status` print over 100MiB of file
information.
This isn't propagated correctly:
If $fish_read_limit is set globally, it won't apply to the completion
command substitution, *unless* you set fish_read_limit inside of that
function.
I'm not entirely sure how that happens, but let's work around it for
now by removing that limit.
I'm going to increase the default limit in a future commit, because
it's not something supposed to be reachable in ordinary code.
See #11106
Previously, there were situations where an autosuggestion existed but was not shown at all. This commit guarantees that at least the `ellipsis_char` is shown, regardless of the situation.
This commit ensures that autosuggestions cannot soft wrap. Previous behavior:
- If the first line is not soft wrapped, the autosuggestion will be truncated and not shown on soft-wrapped lines.
- If the first line is soft-wrapped, the autosuggestion will not have any limit.
The right prompt was rendered even if scrolled.
The command line wasn't rendering on the first line, starting from 0 to the left prompt length. Steps to reproduce:
fish -C 'bind ctrl-g \'commandline $(printf %0"$(math $COLUMNS)"d0) $(seq $(math $LINES - 1))\''
# use ctrl-g
# observe that only one '0' is rendered
When drawing a soft wrapped line, the last 2 characters of the previous line are redrawn. If these 2 characters are occupied by the prompt, they are replaced with ' '.
Steps to reproduce:
fish -C 'function fish_prompt; printf %0"$(math $COLUMNS)"d 0; end'
# type anything
# observe that the last two characters of the prompt have been deleted
We need to add a line to the desired screen if the previous line was full or non-existent to prevent the pager from being drawn on empty soft wrapped or new lines.
Steps to reproduce:
fish -C '
function fish_prompt; printf \>; end
bind ctrl-g \'commandline "ls $(printf %0"$(math $COLUMNS - 5)"d 0) "\''
# use ctrl-g and tab
# observe that the pager starts on the line with the cursor
If the prompt occupies the full width of the first line, each new line will soft wrap, leaving empty lines between. This change removes the indentation that matches the start of the line to the end of the prompt if the prompt width equals the terminal width.
Steps to reproduce:
fish -C 'function fish_prompt; printf %0"$COLUMNS"d 0; end'
# type "begin" and Enter
# observe that there was a spurious empty line
To check:
```fish
fish_config theme choose None
set -g fish_pager_color_selected_completion blue
```
Now the selected color will only apply to the parentheses
Missed in 43e2d7b48c (Port pager.cpp)
Commit f36f757fa6 (Never rewrite history file when adding ephemeral
items, 2024-10-06) has a glaring bug: when adding to history ephemeral
items that has potential paths, we fail to re-enable automatic saving,
which effectively disables automatic saving for the entire session.
Only a call to history::save_all() at exit saves us from losing data.
But until exit, other fish will see our history (unless we run history
save/merge or similar).
Fix the imbalanced enable/disable and restructure the code a bit.
Also, extend the change from f36f757fa6 (never vacuum on ephemeral
items) to private mode.
The version where a feature became the default is now described inline,
to make it a single source of truth. I could have fixed the other
section where this was described, but this seemed easier.
I also removed a few details that seem no longer relevant.
This documents some non-argument options for the window and panes
commands. The choice of what to document is somewhat arbitrary,
this commit is biased towards options that I find confusing or
misleading without documentation (is `-a` "all" or "after"?)
and the command that seem more useful to me.
I also didn't cover the options that would be covered by
#10855 (though this PR can be used independently). I'm not
sure how much difference this made, it might not matter at
all.
These dynamic completions are exhaustive, but not as well-documented or
as ergonomic as the manual completions. So, any manual completions
should override them.
This used to get all the interfaces and ssids when the completions
were loaded. That's obviously wrong, given that ssids especially can, you know, change
This uses `git ls-files`, which has a simpler format (just the
filenames on separate lines), in order to print the untracked files.
This allows us to skip them in the `git status` call, which reduces
the output a lot and removes two `string match`.
In a repository with over half a million files (my home directory, if
I made it one), this improves time by a third (12s to 8s).
In a smaller repo (fish-shell) it's barely measurable.
This is consistent with what we do for highlighting history search,
see d7354880e3 (Fix regression causing crash in token history search,
2025-01-27). In future, we should try to find a better fix (and a
better test).
Fixes the other problem described in #11096
Determine if untracked files are off via `__fish_git`, so we get the
repo used on the commandline etc,
and if it isn't, at least don't error out. Yes, this *can* print a
hundred megabytes of filenames.
The two terminals Midnight Commander and dvtm are special in that
they filter requests (or perhaps responses) like
printf "\x1b[0c"
and don't implement the response themselves -- so we never get
one. Let's work around that until we can fix it.
Disable the kitty protocol in mc for now (to keep the code simple),
though we could certainly re-enable it.
Fixes 64859fc242 (Blocking wait for responses to startup queries, 2025-01-25).
`git add` may have to go through literal megabytes of file information
because of tons of untracked files.
So, if the repository is set to not show untracked files (because it's
too slow for the prompt), let's fall back on regular file completions.
(the alternative is to go back to `while read`, but that takes much
longer in repositories of a sensible size)
Fixes#11095
This was copied from C++ code but we have overflow checks, which
forces us to actually handle errors.
While at it, add some basic error logging.
Fixes#11092
Today we might
1. enable modifyOtherKeys
2. get a reply indicating the kitty keyboard protocol is supported
3. because of 2, we never turn off modifyOtherKeys again
Let's get rid of this weird issue by enabling either modifyOtherKeys
or the kitty enhancements only after we know whether the kitty protocol
is supported.
This means we need to call terminal_protocols_enable_ifn() before every
call to readch() until the querying is done. Fortunately, this is
already in place in read_normal_chars(); there are other places that
call readch() but none of those is executed until querying has completed.
At startup we query for
- the cursor position (CSI 6 n)
- kitty keyboard protocol support (CSI ? u)
- terminfo capabilities via XTGETTCAP
Since we don't wait for responses, those can leak into child processes.
Some child processes like fzf cannot decode DCS replies. Plug the
leak by ending each round of querying by asking for the Primary Device
Attribute, and resume input processing only after a response has been
received, (or ctrl-c as an escape hatch).
This is a nice simplification. Tested with the lowest common
denominator (putty, Terminal.app and st).
Fixes#11079
The st terminal wrongly parses CSI ? u as DECRC. A fix has been
proposed upstream. Let's also work around it I guess (not to mention
that querying in the first place is also sort of a workaround).
This reverts commit ebdc3a0393.
Not discussed, includes a new thing that queries the terminal for the client OS
when what is really needed is just a `uname` - which would also work on Terminal.app.
Revert "README for this fork"
This reverts commit 97db461e7f.
Revert "Allow foo=bar global variable assignments"
This reverts commit 45a2017580.
Revert "Interpret () in command position as subshell"
This reverts commit 0199583435.
Revert "Allow special variables $?,$$,$@,$#"
This reverts commit 4a71ee1288.
Revert "Allow $() in command position"
This reverts commit 4b99fe2288.
Revert "Turn off full LTO"
This reverts commit b1213f1385.
Revert "Back out "bind: Remove "c-" and "a-" shortcut notation""
This reverts commit f43abc42f9.
Revert "Un-hide documentation of non-fish shell builtins"
This reverts commit 485201ba2e.
Unlike other builtins, "{" is a separate token, not a keyword-string
token.
Allow the left brace token as command string; produce it when parsing
"{ -h"/"{ --help" (and nowhere else). By using a decorated statement,
we reuse logic for redirections etc.
Other syntax elements like "and" are in the builtin list, which
- adds highlighting logic
- adds it to "builtin --names"
- makes it runnable as builtin
(e.g. "builtin '{'" would hypothetically print the man page)
These don't seem very important (highlighting for '{' needs to match
'}' anyway).
Additionally, making it a real builtin would mean that we'd need to
deactivate a few places that unescape "{" to BRACE_BEGIN.
Let's not add it to the built in list. Instead, simply synthesize
builtin_generic in the right spot.
I'm assuming we want "{ -h" to print help, but '"{" -h' to run an
external command, since the latter is historical behavior. This works
naturally with the above fake builtin approach which never tries to
unescape the left brace.
Commit 798527d79a (completions: fix double evaluation of tokenized
commandline, 2024-01-06) fixed some completions such as the "watchexec"
ones by adding "string escape" here:
set argv (commandline -opc | string escape) (commandline -ct)
This fixed double evaluation when we later call `complete -C"$argv"`.
Unfortunately -- searching for "complete -C" and
"__fish_complete_subcommand" -- it seems like that commit missed some
completions such as sudo. Fix them the same way.
Alternatively, we could defer expansion of those arguments (via
--tokens-raw), since the recursive call to completion will expand
them anyway, and we don't really need to know their value.
But there are (contrived) examples where we do want to expand first,
to correctly figure out where the subcommand starts:
sudo {-u,someuser} make ins
By definition, the tokens returned by `commandline -opc` do not
contain the token at cursor (which we're currently completing).
So the expansion should not hurt us. There is an edge case where
cartesian product expansion would produce too many results, and we
pass on the unexpanded input. In that case the extra escaping is very
unlikely to have negative effects.
Fixes # 11041
Closes # 11067
Co-authored-by: kerty <g.kabakov@inbox.ru>
If a child program crashes with some text rendered below the cursor,
we fail to clear that text. For example run vim, "pkill -9 vim" and
observe that scrollback-push fails to clean up the leftover text.
Fix that.
Custom formats for --pretty/--format option can only be written in [pretty]
section, thus only this section is searched.
[ja: add ? to the regex]
Closes#11065
libc::getpid and getpgrp *cannot fail*, so an unsafe declaration here
is just noise.
I mean sure, if your libc is broken and these fail, but at that point
I'm comfortable declaring your computer a platypus that we do not need
to support.
Wgetopt needs a ":" at the beginning to turn on this type of error.
I'm not sure why that is now, and we might want to change it (but tbh
wgetopt could do with a replacement anyway).
Fixes#11049
Sorry, commit 51adba6ee0 (Restore autosuggestion after corrected
typo, 2025-01-10) was pushed too early. One issue is that it saves
autosuggestions also when we edit in the middle, where we can't
restore it. We'd still restore it in some cases, even though it
doesn't apply. This breaks invariants that may cause various problems
when interacting with the autosuggestion.
Fix it by only saving the autosuggestion when we will be able to
restore it correctly.
We capture the process already, and we use argv by reference for the
other cases.
argv can be big, and this reduces allocations and thereby memory usage
and speed.
E.g. `set -l foo **` with 200k matches has 25% reduced memory usage
and ~5% reduced runtime.
For compound commands we already have begin/end but
> it is long, which it is not convenient for the command line
> it is different than {} which shell users have been using for >50 years
The difference from {} can break muscle memory and add extra steps
when I'm trying to write simple commands that work in any shell.
Fix that by embracing the traditional style too.
---
Since { and } have always been special syntax in fish, we can also
allow
{ }
{ echo }
which I find intuitive even without having used a shell that supports
this (like zsh. The downside is that this doesn't work in some other
shells. The upside is in aesthetics and convenience (this is for
interactive use). Not completely sure about this.
---
This implementation adds a hack to the tokenizer: '{' is usually a
brace expansion. Make it compound command when in command position
(not something the tokenizer would normally know). We need to disable
this when parsing a freestanding argument lists (in "complete somecmd
-a "{true,false}"). It's not really clear what "read -t" should do.
For now, keep the existing behavior (don't parse compound statements).
Add another hack to increase backwards compatibility: parse something
like "{ foo }" as brace statement only if it has a space after
the opening brace. This style is less likely to be used for brace
expansion. Perhaps we can change this in future (I'll make a PR).
Use separate terminal token types for braces; we could make the
left brace an ordinary string token but since string tokens undergo
unescaping during expansion etc., every such place would need to know
whether it's dealing with a command or an argument. Certainly possible
but it seems simpler (especially for tab-completions) to strip braces
in the parser. We could change this.
---
In future we could allow the following alternative syntax (which is
invalid today).
if true {
}
if true; {
}
Closes#10895Closes#10898
Commit bdfbdaafcc (Forbid subcommand keywords in variables-as-commands
(#10249), 2024-02-06) banned "set x command; $x foo" because the
parser will not recognize "$x" as decorator.
That means that we would execute only the builtin stub,
which usually exist only for the --help argument.
This scenario does not apply for keywords that are quoted or contain
line continuations. We should not treat «"command"» differently
from «command». Fix this inconsistency to reduce confusion.
UnLike other aliases (":.["), ! is special in the grammar but in the
few cases like "! -h" where we parse it as decorated statement they
are equals. Add it to the built in list, so the help argument works.
It can still be overridden, so this should not break anything.
Other sigil-aliases ('[' and '_') are reserved words that cannot be
redefined as function. Only '!' is not.
Whereas several users define "function !!", I
found only one public occurrence of "function !":
5c7f87ed07/fish/functions/!.fish
Note that "function !" only works if invoked as "!", "! -h" or
"! --help" or "foo | !". In most other cases we parse it as negation.
We should probably make it a reserved word to reduce confusion.
If we do that, we should also add it to __fish_print_help, to make
"! -h" work.
For now let's rearrange the code so we can recognize "!" as
super-command. This fixes completion-based autosuggestions on "! ".
The commandline "and fis" rightly gets command autosuggestions whereas
"'and' fis" wrongly gets file autosuggestions. The former works via
a hack. Extend it to quoted keywords.
This file has bitrotted; for example commit bc66921ac9 (Optimize
keyword detection, 2019-04-03) removed use of SKIP_KEYWORDS but
confusingly it's still around (even after 0118eafee1 (Remove unused
functions, members (and a variable), 2022-04-09).
Also some keywords appear in multiple lists; the separate lists are
not really used today; there is a comment stating they may be useful
in future.
It would be great to add an optimization back but either way we should
present the set of reserved words in source code as a contiguous list,
to make it easy for humans to see all relevant information.
StatementVariant needs an indirection because for example NotStatement
may contain another whole statement (error[E0072]: recursive type
has infinite size).
This is dealt with by putting each StatementVariant in a Box.
This Box was also used by the AST walk implementation to implement
tagged dispatched for all variant AST nodes (see "visit_union_field").
Because of this, all other variant AST are boxed the same way, even
though they may not by cyclic themselves.
Reduce confusion by boxing only around the nodes that are actually
recursive types, and use a different tag for static dispatch.
This means that simple nodes like most normal commands and arguments
need one fewer allocation.
For better or worse, backward-token completely skips over operators
like > & |.
forward-token is (accidentally?) inconsistent with that. Fix that.
Skipping over those tokens might be wrong weird. Maybe not for
redirections since they are tighly coupled to their target. Maybe we
can improve this in future.
When pasting and executing a full line, the trailing newline character
will be included in history.
I usually manually delete the newline before executing, but sometimes
I forget. When I recall my (typically single-line) commands, it's
surprising that the cursor is on the blank second line.
The newline doesn't seem useful. Let's remove it automagically.
I wonder if anyone will be thrown off by this smart behavior.
In future, we can make this space trimming configurable, similar to
fish_should_add_to_history.
As mentioned in
https://github.com/fish-shell/fish-shell/pull/11045#discussion_r1915994998,
we need to refresh TTY timestamps to avoid timing-based issues.
For some context see
git log --grep='[Rr]efresh.* TTY'
Make things more consistent again. I don't know if all of these are
absolutely necessary, hoping to find out later (and consolidate this
logic in outputter).
tmux-commandline can fail with
```
prompt 4> commandline -i "echo $(printf %0"$COLUMNS"d)"
```
And I just can't even.
job_summary is annoyingly tight.
Also count cancel_event as a *skip*, not success.
And leave the old behavior under the name "cancel-commandline".
This renames "cancel-commandline-traditional" back to
"cancel-commandline", so the old name triggers the old behavior.
Fixes#10935
Saturating all cores easily leads to timeouts.
The system might be doing something else, and it only leaves at most
one core per-test.
E.g. this will cause 90% of runs to fail on a raspberry pi 4.
Note that we set CTEST_PARALLEL_LEVEL on our CI machines anyway, so
this will not affect them.
The issue here is we start some short `sleep`s in the background, wait
for a prompt, and only *then* wait for jobs, and *then* check for the
job end output.
That means if the prompt takes too long, we'll read the job end
messages with the `expect_prompt`.
Instead of increasing the timeouts, just wait on the same line and
remove that prompt.
Bit of a shot in the dark, I've seen this fail and there's no real
need to match the prompt *and* the command you just ran.
(plus wc -l | string trim is unnecessary when we have count)
Commit 4f3d6427ce (Fix regression causing crash in "commandline -j",
2025-01-12) wasn't quite right; it mishandles the edge case where
the current process has no token, fix that.
Zellij 0.41.2 has a bug where it responds to
printf '\x1b[?2026$p'; cat -v
with '^[[2026;2$y' (DECRQM) instead of '^[[?2026;2$y' (DECRPM).
This is fixed by https://github.com/zellij-org/zellij/pull/3884
We fail to parse it, leading to an extra y added to the input queue.
Since it seems easy to work around for us, let's do that, I guess.
Failed on Cirrus Alpine.
The only explanation I can come up with here is that this took over
100ms to start `true | sleep 6`.
The alternative is that it started it and then did not regain control
in 6 seconds to kill that sleep.
Part of #11036
If you don't care about file paths containing '=' or ':', you can
stop reading now.
In tokens like
env var=/some/path
PATH=/bin:/usr/local/b
file completion starts after the last separator (#2178).
Commit db365b5ef8 (Do not treat \: or \= as file completion anchor,
2024-04-19) allowed to override this behavior by escaping separators,
matching Bash.
Commit e97a4fab71 (Escape : and = in file completions, 2024-04-19)
adds this escaping automatically (also matching Bash).
The automatic escaping can be jarring and confusing, because separators
have basically no special meaning in the tokenizer; the escaping is
purely a hint to the completion engine, and often unnecessary.
For "/path/to/some:file", we compute completions for "file" and for
"/path/to/some:file". Usually the former already matches nothing,
meaning that escaping isn't necessary.
e97a4fab71 refers us to f7dac82ed6 (Escape separators (colon and
equals) to improve completion, 2019-08-23) for the original motivation:
$ ls /sys/bus/acpi/devices/d<tab>
$ ls /sys/bus/acpi/devices/device:
device:00/ device:0a/ …
Before automatic escaping, this scenario would suggest all files from
$PWD in addition to the expected completions shown above.
Since this seems to be mainly about the case where the suffix after
the separator is empty,
Let's remove the automatic escaping and add a heuristic to skip suffix
completions if:
1. the suffix is empty, to specifically address the above case.
2. the whole token completes to at least one appending completion.
This makes sure that "git log -- :!:" still gets completions.
(Not sure about the appending requirement)
This heuristic is probably too conservative; we can relax it later
should we hit this again.
Since this reverts most of e97a4fab71, we address the code clone
pointed out in 421ce13be6 (Fix replacing completions spuriously quoting
~, 2024-12-06). Note that e97a4fab71 quietly fixed completions for
variable overrides with brackets.
a=bracket[
But it did so in a pretty intrusive way, forcing a lot of completions
to become replacing. Let's move this logic to a more appropriate place.
---
Additionally, we could sort every whole-token completion before every
suffix-completion. That would probably improve the situation further,
but by itself it wouldn't address the immediate issue.
Closes#11027
Mainly to make the next commit's diff smaller. Not much functional
change: since file completions never have the DONT_SORT flag set,
these results will be sorted, and there are no data dependencies --
unless we're overflowing the max number of completions. But in that
case the whole-token completions seem more important anyway.
Syntax highlighting wants to underline arguments that are files, and in other
cases do disk I/O (such as testing if a command is valid). Factor out this I/O
logic to untangle highlighting, and add some tests. No functional change
expected.
Commit 3fcc6482cb (Fix parse_util_process_extent including too much
on the left, 2024-12-24) changed the process extent based on the
observation that "A\n\n\nB" comprises three tokens with ranges 0..1,
1..2 and 4..5. Prior to that commit, the second process extent was
2..5, which seems a bit weird because it includes newlines.
Weirdness aside, the real reason for changing it was this snippet in
the autosuggestion performer, where we compute the process extent
around cursor, and check if the line at process start matches the
cached search string.
// Search history for a matching item unless this line is not a continuation line or quoted.
if range_of_line_at_cursor(
&command_line,
parse_util_process_extent(&command_line, cursor_pos, None).start,
) == search_string_range
Given "A\n\n\nB" and cursor_pos=1 commit 3fcc6482cb changed the output
from 2..5 to 4..5. This brings problems:
1. leading spaces will not be included (which is probably
inconsequential but still ugly).
2. the specified cursor position is not included in the given range.
We could paper over 2 by computing min(cursor_pos)
but that would leave 1.
For now let's revert and solve the autosuggestion issue in a less
brittle way.
This needs to work both in builtin and command mode.
We should probably clarify how we're passing FDs around, and I suspect
we may close fds in places we don't expect.
Various commits have added bits to .cargo/config.toml. Unfortunately,
this file needs to be changed by the Linux package builds (debuild, RPM,
OBS etc) with the results of `cargo vendor`, to support building in
isolated environments.
These environments - especially Debian's dpkg-buildpackage/debuild - do
not make it easy to alter a file which already exists in the tarball in
an automatic way. dpkg-buildpackage in particular requires all changes
to be made in the form of patches.
Just exclude .cargo/config.toml from the tarballs for now. This means
that the stanzas it includes _will not apply_ to builds made from
tarballs, which includes releases and development builds made using the
OBS/Launchpad PPAs.
This replaces the test_driver.sh/test.fish/interactive.fish system with a test driver written in python that calls into littlecheck directly and runs pexpect in a subprocess.
This means we reduce the reliance on the fish that we're testing, and we remove a posix sh script that is a weird stumbling block (see my recent quest to make it work on directories with spaces).
To run specific tests, e.g. all the tmux tests and bind.py:
tests/test_driver.py target/release/ tests/checks/tmux*.fish tests/pexpects/bind.py
Backspace signals that the user is not happy with the commandline,
and by extension the autosuggestion.
For this reason, backspace suppresses autosuggestions until the next
text insertion.
However if I
1. type something that has an autosuggestion
2. type *one* wrong letter (removing the autosuggestion)
3. type backspace
backspace does not visibly suppress any autosuggestion but rhater
signal that the user wants to go back to the previous state of the
commandline, which does have an autosuggestion.
Enable this scenario by caching the autosuggestion when it's
invalidated. On certain edits that make the cached autosuggestion
valid again, restore it from the cache. Currently, only do this up
to a single backspace. Could extend that in future.
This implementation is really bad.. but it's a start.
Weirdly, it does not restore the cache on undo; but that's
inconsequential because undo doesn't suppress autosuggestion as
of today.
Closes#3549
My history often has erroneous single-line commands followed by
corrected versions. Sometimes the corrected versions only exist within
a multi-line commandline. This means that autosuggestion skips over
the corrected versions and return a false positive.
Fix that by splitting the commandline into lines and suggesting those,
in reverse chronological order.
One other wart: shift-delete won't delete such autosuggestions from
history; instead it will flash the screen.
Line boundaries are not the best heuristic but they are an
improvement for the most part and fits with the current approach
where autosuggestion always operates on the entire line.
In future we should operate on processes and jobs. But it may be
tricky - a backgrounding `&` should probably be included (in both?)
but `&&` or `;` probably not.
See also the discussion in
1c4e5cadf2 (diff-267c9f4da66412a9f439ac08d224356fe24265b5e1cebb6c44c2d55b96414513R59)
If there is no history search or autosuggestion, shift-delete acts
as backspace, matching native macOS behavior.
I'm not sure if we want to keep that amount of overloaded behavior,
but let's assume so for now.
If that assumption holds, it may be confusing that shift-delete
deletes the autosuggestion if the cursor is here
echo some command with autosuggstion
^
So let's only do that if the cursor is actually at the autosuggestion,
I guess.
shift-delete attempts to delete the autosuggestion from history even
if the autosuggestion is not from history.
This is weird. We probably shouldn't do this. Let's flash the
commandline instead to try to reduce confusion.
I think the dynamic detection patch ends up overriding the environment variable
set by CI (if present), because `if(NOT CTEST_PARALLEL_LEVEL)` would define to
false even if an environment variable of that name existed then we end up
explicitly assigning the environment variable by that name upon invocation with
`env`.
This is an experiment to see if it causes any of the tests to flake and/or if it
even appreciably speeds up CI to begin with.
I note that there are tests added in 8bf8b10 that mutate global terminal state
but also note that local tests without CTEST_PARALLEL_LEVEL set at all have been
running to completion just fine without any observed flakiness *and* that our
Cirrus CI tests have this hard-coded to 6.
The new 1.84 release has a new feature that makes `cargo update` MSRV-aware.
This is what it looks like in practice:
Updating crates.io index
Updating git repository `https://github.com/fish-shell/rust-pcre2`
From https://github.com/fish-shell/rust-pcre2
* [new tag] 0.2.9-utf32 -> origin/tags/0.2.9-utf32
Locking 7 packages to latest Rust 1.70 compatible versions
Updating cc v1.2.6 -> v1.2.7
Updating phf v0.11.2 -> v0.11.3
Updating phf_codegen v0.11.2 -> v0.11.3
Updating phf_generator v0.11.2 -> v0.11.3
Updating phf_shared v0.11.2 -> v0.11.3
Updating siphasher v0.3.11 -> v1.0.1
Updating syn v2.0.94 -> v2.0.95
The result of
commandline -i ": '$(seq $LINES)"\n"first scrolled line'"
is a commandline that is scrolled by one line.
Before executing that commandline, we move the cursor down by one
too many line. This is a regression from 610338cc70 (On undo after
execute, restore the cursor position, 2024-12-21). Fix that.
The test also demonstrates an unrelated problem, probably specific
to tmux.
Some terminals such as conhost and putty cannot parse DCS commands,
and will echo them back.
Work around this by making sure that this echoed text will not
be visible.
Do so by temporarily enabling the alternative screen buffer when
sending DCS queries (in this case only XTGETTCAP). The alternative
screen buffer feature seems widely supported, and easier to get right
than trying to clear individual lines etc.
The alternative screen may still be visible for a
short time. Luckily we can use [Synchronized Output](
https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036)
to make sure the screen change is never visible to the user.
Querying support for that is deemed safe since it only requires a
CSI command.
Note that it seems that every terminal that supports Synchronized
Output also parses DCS commands successfully. This means that we
could get away without the alternative screen buffer in practice.
Not sure yet.
The implementation is slightly more complex than necessary in that it
defines a redundant ImplicitEvent. This is for two reasons: 1. I have
a pending change that wants to use it, so this removes diff noise and
2. we historically have sc/input_common.rs not depend on src/output.rs.
I dont' think any are strong reasons though.
Commit b6d76ae: we now use lines like "# RUN: fish=%fish %fish".
If a test exits with 127 we try to look up the command but use the
wrong name, which leads to unintelligible errors if the test exits
with 127 for other reasons.
If I run "sleep 3", type a command and hit enter, then there is no
obvious way to cancel or edit the imminent command other than ctrl-c
but that also cancels sleep, and doesn't allow editing. (ctrl-z sort
of works, but also doesn't allow editing).
Let's try to limit ourselves to inserting the buffered command
(translating enter to a newline), and only execute once the user
actually presses enter after the previous command is done.
Hide it behind a new feature flag for now.
By making things less scary, this might be more user-friendly, at
the risk of breaking expectations in some cases.
This also fixes a class of security issues where a command like
`cat malicious-file.txt` might output escape sequences, causing
the terminal to echo back a malicious command; such files can still
insert into the command line but at least not execute it directly.
(Since it's only fixed partially I'm not really sure if the security
issue is a good enough motivation for this particular change.)
Note that bracketed paste probably has similar motivation as this feature.
Part of #10987Closes#10991
Some terminals like the Linux console don't support indn (scroll
forward). Let's query for the presence of these features, and fall
back to the traditional behavior if absent.
For now, break with the tradition of using the terminfo database that
we read ourselves. Instead ask the terminal directly via XTGETTCAP.
This is a fairly young feature implemented by terminals like xterm,
foot and kitty, however xterm doesn't expose these capabilities at
this point.
This is a good opportunity to try XTGETTCAP, since these are
capabilities we haven't used before. Advantages of XTGETTCAP are that
it works across SSH and is independent of $TERM (of course ignoring
$TERM may also be breaking to some users). Let's see if it sees
adoption in practice.
Tested to work on foot and kitty, allowing the default ctrl-l binding
to work without erasing any screen content.
See #11003
The new ctrl-l implementation relies on Cursor Position Reporting (CPR)
This may not work on exotic terminals that don't support CSI 6n yet
As a workaround, probe for this feature by sending a CSI 6n (CPR)
on startup. Until the terminal responds, have scrollback-push fall
back to clear-screen.
The theoretical problem here is that we might handle scrollback-push
before we have handled the response to our feature probe. That seems
fairly unlikely; also e49dde87cc has the same characteristics.
This could query a capability instead (via XTGETTCAP or otherwise)
but I haven't found one; and this seems at least as reliable.
While at it, change the naming a bit.
See #11003
After we query kitty keyboard protocol support,
we send CSI 5n, to also receive a response if
the protocol is not supported.
However we don't bother to wait for the response, so this extra
message is not really useful (only to get better logs). Remove it.
With tmux 3.0 (from 2019) inside SSH, the CSI 5n response is echoed.
I guess with all other terminals we were just lucky. Move it to
right after where we disable ECHO I guess.
In general, asynchronous requests create a lot of potential for error,
we should try to get away from them.
These aren't typically used in the terminal but they are present on
many keyboards.
Also reorganize the named key constants a bit. Between F500 and
ENCODE_DIRECT_BASE (F600) we have space for 256 named keys.
To make it more familiar to vi/vim users.
In all mode, ctrl-k is bind to kill-line.
In Vi visual mode:
* press v or i turn into normal or insert mode respectively.
* press I turn to insert mode and move the cursor to beginning of line.
* because fish doesn't have upcase/locase-selection, and most people reach for
g-U rather than g-u, g-U binds to togglecase-selection temporarily.
Testing has revealed some problems on BSD and Windows terminals and
the Linux Console, let's revert to the old implementation until these
are fixed. Leaving the changelog entry for now since it shouldn't
take long.
See #11003
The FdReadableSet api was always intended to be converted to use Duration
instead of usec/msec once the ffi was removed. This lets us be explicit about
forever/infinite timeouts and removes the (small) chance of a collision between
u64::MAX and INFINITE.
I tried this out with `type Timeout = Option<Duration>` (only without the alias)
but was unhappy with easy it is to accidentally use `None` when you meant a
timeout of zero.
Commit 1c4e5cadf2 (Autosuggestions in multi-line
command lines, 2024-12-15) accidentally passed an empty
"commandline_before_suggestion" to compute_layout() when there is
no autosuggestion.
Closes#10996
As reported in
https://github.com/fish-shell/fish-shell/issues/10992#issuecomment-2568954940,
the user may reset the terminal and run scrollback-push without
repainting in between. This means that the terminal will report
the cursor position y=0 x=0 which doesn't match what fish renders.
Fortunately, y=0 is a safe fallback value for the scrollback-push
use case.
While at it, fix an off-by-one error in a log.
Before 1c4e5cadf2 (Autosuggestions in multi-line command lines,
2024-12-15), the completion code path in the autosuggestion performer
used to do something weird: it used to request completions for the
entire command line (with the implied cursor at end) but try to apply
the same completion at the actual cursor.
That commit changed this to request completions only up to the cursor
position, which could in theory make us produce valid completions even
if the cursor is not at end of the line. However, that doesn't really
work since autosuggestions can only be rendered at the end of the line.
And the worst of it, that commit tries to compute
line_at_cursor(&full_line, search_string_range.end)
which crashes as out-of-bounds if the completion needs to replace the token
(like a case-correcting completion does).
Let's apply completions to the end, matching how autosuggestions work
in general.
I believe it's possible that the cursor position reported by the
terminal does not match fish's cursor. In that case, overflow. Fix
that since we should not trust the terminal.
Also rename a confusingly named variable.
Mouse-click handling has a similar issue, fix that too.
FWIW, tmux always reports cursor position zero (\x1b[1;1R) when
querying from fish (but not when querying with printf).
Will investigate that next, see the linked issue.
Fixes#10992
jj is often colocated with Git so the Git prompt also works, but
jj is always in a detached HEAD state, which is atypical for Git.
The jj prompt improves things by showing the revision ID which is
usually more useful than the commit ID.
This prompt is mostly adapted from the defaults for "jj log -r @".
Showing conflicting/empty commits seems useful.
Also perhaps bookmarks and tags, not sure.
The main problem with this prompt is that due to --ignore-working-copy,
the information may be stale. That will be rectified after every jj
command, so hopefully this doesn't cause issues.
Added in libc 0.2.163.
The constants for _CS_PATH are not implemented for some of the BSDs yet
(rust-lang/cmake#3612), so we need to keep our linking of this via the C
compiler for now.
If I run
$ command A
$ command B
$ command C
and find myself wanting to re-run the same sequence of commands
multiple times, I like to join them into a single command:
$ command A &&
command B &&
command C
When composing this mega-commandline, history search can recall the
first one; the others I usually inserted with a combination of ctrl-k,
ctrl-x or the ctrl-r (since 232483d89a (History pager to only operate
on the line at cursor, 2024-03-22), which is motivated by exactly
this use case).
It's irritating that autosuggestions are missing, so try adding them.
Today, only single-line commands from history are suggested. In
future, we should perhaps also suggest any line from a multi-line
command from history.
If I type something that invalidates the autosuggestion, the
autosuggestion is still kept around in memory. This is used if
1. there is no valid autosuggestion for the new commandline
2. the user types something like "backspace backspace a"
that both makes the cached autosuggestion valid again, and does
not trigger autosuggestion suppression (hence backspace alone is
not anough)
The fact that an autosuggestion might not match the current command
line makes it more difficult to implement autosuggestions on multiline
command lines.
For now let's invalidate autosuggestions eagerly, to enable the
next commit. This heuristic invalidates too much but I don't think
that matters. We'll simply recompute the autosuggestion in those few
cases which.
This is somewhat subtle:
The #RUN line in a littlecheck file will be run by a posix shell,
which means the substitutions will also be mangled by it.
Now, we *have* shell-quoted them, but unfortunately what we need is to
quote them for inside a pre-existing layer of quotes, e.g.
# RUN: fish -C 'set -g fish %fish'
here, %fish can't be replaced with `'path with spaces/fish'`, because
that ends up as
# RUN: fish -C 'set -g fish 'path with spaces/fish''
which is just broken.
So instead, we pass it as a variable to that fish:
# RUN: fish=%fish fish...
In addition, we need to not mangle the arguments in our test_driver.
For that, because we insist on posix shell, which has only one array,
and we source a file, we *need* to stop having that file use
arguments.
Which is okay - test_env.sh could previously be used to start a test,
and now it no longer can because that is test_*driver*.sh's job.
For the interactive tests, it's slightly different:
pexpect.spawn(foo) is sensitive to shell metacharacters like space.
So we shell-quote it.
But if you pass any args to pexpect.spawn, it no longer uses a shell,
and so we cannot shell-quote it.
There could be a better way to fix this?
We:
1. Set up a nice TMPDIR for our tests to use
2. Immediately `cd` to the directory containing the test runner.
So instead we don't do (2), and stay in the temp directory, and
explicitly use all the things from the test runner directory.
I am fairly certain that cmake papered over this by adding a second
layer of temp dir.
The default is still "../test/root/bin/", but we now pass this
through,
so you *can* run
`FISHDIR=$PWD ../tests/test_driver.sh $PWD/../tests/test.fish`
Fixes#10980.
This would, if a commandline was given, still revert to checking
the *real* commandline if it was empty.
Unfortunately, in those cases, it could have found a command and tried
to complete it.
If a commandline is given, that is what needs to be completed.
(note this means this is basically useless in completions that use it
like `sudo` and could just be replaced with `complete -C"$commandline"`)
As soon as we start processing a scrollback-push readline command, we
pause execution of all other readline commands until scrollback-push
retires. This means that we never get into a situation with two
active scrollback-push commands -- unless we are executing readline
commands via a script running "commandline -f":
since the first part of scrollback-push handling returns immediately,
the script will proceed before scrollback-push retires.
A second scrollback-push fails an assertion. Work around that for now.
In future, scrollback-push should block when invoked by such a script,
just like it does when invoked from bindings.
Commit 83b0294fc9 (ctrl-l to scroll content instead of erasing screen,
2024-12-21) broke tests like tests/checks/tmux-autosuggestion.fish
on macOS CI.
I didn't get to the bottom of this but it's probably because terminfo
is broken on that CI system.
A (related?) failure mode can be observed using
TERM=linux-m ssh my-mac tmux
ctrl-l moves the cursor but fails to scroll the text.
The only reason for using terminfo here was to be consistent with
the rest of the code base. Let's use a hardcoded value instead;
I don't see why any terminal would deviate from xterm here.
This fixes macOS CI and the TERM=linux-m "misconfiguration".
It is possible that we should be using a different escape sequence
here; I'm not sure.
On ctrl-l we send `\e[2J` (Erase in Display). Some terminals interpret
this to scroll the screen content instead of clearing it. This happens
on VTE-based terminals like gnome-terminal for example.
The traditional behavior of ctrl-l erasing the screen (but not the
rest of the scrollback) is weird because:
1. `ctrl-l` is the easiest and most portable way to push the prompt
to the top (and repaint after glitches I guess). But it's also a
destructive action, truncating scrollback. I use it for scrolling
and am frequently surprised when my scroll back is missing
information.
2. the amount of lines erased depends on the window size.
It would be more intuitive to erase by prompts, or erase the text
in the terminal selection.
Let's use scrolling behavior on all terminals.
The new command could also be named "push-to-scrollback", for
consistency with others. But if we anticipate a want to add other
scrollback-related commands, "scrollback-push" is better.
This causes tests/checks/tmux-history-search.fish to fail; that test
seems pretty broken; M-d (alt-d) is supposed to delete the current
search match but there is a rogue "echo" that is supposed to invalidate
the search match. I'm not sure how that ever worked.
Also, pexepect doesn't seem to support cursor position reporting,
so work around that.
Ref: https://codeberg.org/dnkl/foot/wiki#how-do-i-make-ctrl-l-scroll-the-content-instead-of-erasing-it
as of wiki commit b57489e298f95d037fdf34da00ea60a5e8eafd6d
Closes#10934
We parse "\e\e[x" as alt-modified "Invalid" key. Due to this extra
modifier, we accidentally add it to the input queue, instead of
dropping this invalid key.
We don't really want to try to extract some valid keys from this
invalid sequence, see also the parent commit.
This allows us to remove misplaced validation that was added by
e8e91c97a6 (fish_key_reader: ignore sentinel key, 2024-04-02) but
later obsoleted by 66c6e89f98 (Don't add collateral sentinel key to
input queue, 2024-04-03).
This situation can be triggered in practice inside a terminal like tmux
3.5 by running
tmux new-session fish -C 'sleep 2' -d reader -o log-file
and typing "alt-escape x"
The log shows that we drop treat this as alt-[ and drop the x on the floor.
reader: Read char alt-\[ -- Key { modifiers: Modifiers { ctrl: false,
alt: true, shift: false }, codepoint: '[' } -- [27, 91, 120]
This input ("\e[x") is ambiguous.
It looks like it could mean "alt-[,x". However that conflicts with a
potential future CSI code, so it makes no sense to try to support this.
Returning "None" from parse_csi() causes this weird behavior of
returning "alt-[" and dropping the rest of the parsed sequence.
This is too easy; it has even crept into a bunch of places
where the input sequence is actually valid like "VT200 button released"
but where we definitely don't want to report any key.
Fix the default: report no key for all unknown sequences and
intentionally-suppressed sequences. Treat it at "alt-[" only when
there is no input byte available, which is more or less unambiguous,
hence a strong enough signal that this is a actually "alt-[".
When the user clicks somewhere in the prompt, kitty asks the shell
to move the cursor there (since there is not much else to do).
This is currently implemented by sending an array of
forward-char-passive commands. This has problems, for example it
is really slow on large command lines (probably because we repaint
everytime).
Implement kitty's `click_events=1` flag to set the
position directly. To convert from terminal-coordinates
to fish-coordinates, query [CSI 6 n Report Cursor
Position](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html)
and use it to compute the left prompt's terminal-coordinates (which
are (0, 0) in fish-coordinates).
Unfortunately this doesn't yet work correctly while the terminal
is scrolled. This is probably because the cursor position is wrong
if off-screen. To fix that we could probably record the cursor
position while not scrolled, but it doesn't seem terribly important
(the existing implementation also doesn't get it right).
We still turn off mouse reporting. If we turned it on, it
would be harder to select text in the terminal itself (not fish).
This would typically mean that mouse-drag will alter fish's
selection and shift+mouse-drag or alt+mouse-drag can be used.
To improve this, we could try to synchronize the selection: if parts
of the fish commandline are selected in the terminal's selection,
copy that to fish's selection and vice versa.
Or maybe there is an intuitive criteria, like: whenever we receive a
mouse event outside fish, turn off mouse reporting, and turn it back on
whenver we receive new keyboard input. One problem is that we lose
one event (though we could send it back to the terminal). Another
problem is we would turn it back on too late in some scenarios.
Closes#10932
Commit 01dbfb0a3f (replace writestr() with fwprintf() in reader.cpp,
2016-12-20) accidentally replaced a retry-on-EINTR write with a
non-retrying version. Commit 7f31acbf9b (Prevent fish_title output
from triggering a bel, 2022-02-02) fixed this for some cases but
not all, fix that.
This has been removed, see kitty commit cd92d50a0 (Keyboard protocol:
Remove CSI R from the allowed encodings of the F3 key as it conflicts
with the *Cursor Position Report* escape code, 2022-12-24).
cursor_selection_mode=inclusive means the commandline position is
bounded by the last character. Fix a loop that fails to account
for this.
Fixes d51f669647 (Vi mode: avoid placing cursor beyond last character,
2024-02-14).
This change looks very odd because if the commandline is like
echo foo.
it makes us try to uppercase the trailing period even though that's
not part of word range. Hopefully this is harmless.
Note that there seem to be more issues remaining, for example Vi-mode
paste leaves the cursor in an out-of-bounds odd position.
Fixes#10952Closes#10953
Reported-by: Lzu Tao <taolzu@gmail.com>
PR #10953 reports missing coverage for the change to update_buff_pos()
in d51f669647 (Vi mode: avoid placing cursor beyond last character,
2024-02-14).
Add a case demonstrating how $ should not move the cursor past the
last character. Goes without saying that it's really ugly that we
update_buff_pos() must be so defensive here, ideally we wouldn't pass
it out-of-bounds positions.
Before, it unnecessarily stated that there are three `--style` options, when
there are actually four.
I also align the default `--style=script` argument to the beginning of the line
to match the other options visually for easier scanning.
These are quite mechanical, but include all the commands (as of tmux
3.5a) in the "Windows and Panes" section of `man tmux`. For these
commands, I included the target-pane/session/client/window flags and the
-F formatstring flags (but not the less generic flags specific to
individual commands).
Nice completion is implemented for those flags where the helper
functions were already implemented previously.
After this, tmux pane<tab> will hopefully be useful.
A few TODOs mention low-hanging fruit for somebody who better
understands fish's `complete` command syntax (or a future me).
Another piece of low-hanging fruit would be completion for all the
target-window flags. This PR merely lists them.
If base directories (e.g. $HOME/.config/fish) need to be created,
create them with mode 0700 (i.e. restricted to the owner).
This both keeps the behavior of old fish versions (e.g. 3.7.1) and is
compliant with the XDG Base Directory Specification.
See: https://specifications.freedesktop.org/basedir-spec/0.8/#referencing
[Do NOT cherry-pick to 4.0 - this needs more time to be tested]
fish sometimes needs to capture the output of a command or block of
commands. Examples include fish_prompt or any command substitution
("cmdsubs"). It does this the obvious way: by creating a pipe, using dup2
to replace stdout of the command with the write end of the pipe, and then
reading from the read end into a buffer, until EOF or the command
substitution completes. Importantly, this task also overlaps with waiting
for the process to exit; that is when executing:
set var (some_cmd)
fish needs to both wait on `some_cmd` and ALSO read its output into memory.
This is awkward to do in a portable way in a single thread (though maybe
doable on Linux with pidfd). So we wait and read on different threads.
To make things worse, command substitutions may themselves create
additional command substitutions (recursion, etc). Creating a read thread
for every command substitution would result in excessive threads. So rather
than a thread per cmdsub, we have a single dedicated thread that handles
ALL command substitutions, by multiplexing multiple file descriptors via
select/poll. This is the "fd monitor." You hand it a file descriptor and it
lets you know when it's readable, and then you can read from it (via a
callback). Also, it has a "wakeup" fd: if you write to that then the fd
monitor wakes up, figures out what it has to do, and resumes.
When the command substitution ends, we need to remove the fd from the fd
monitor, because we intend to close it. You might object "the commands in
the cmdsub have all completed so the write end of the pipe has been closed
so the fd monitor can just notice that the pipe is closed" but it's not so:
consider the horrible case of `set var (yes &)` and abandon all hope.
The current mechanism for removing the fd from the monitor is called a
"poke." We tell the fd monitor (through a "control" self-pipe) to
explicitly wake up the item. It then invokes the callback ("pokes") the
item on the dedicated fd monitor thread. The item notices that the command
substitution is complete, and it returns a value meaning "remove me" and
the fd monitor does so. The client thread is stuck waiting for this process
to complete.
So basically removing a fd from the monitor requires a round trip to its
dedicated thread. This is slow and also complicated (Rust doesn't have
futures)!
So let's not do that.
The big idea is to remove this round-trip synchronization. That is, when we
intend to remove the fd from the fd monitor, we _just do it_ and then close
the fd. Use a lock rather than a round-trip to the thread. Crucially that
lock is unlocked while the monitor thread waits in select/poll.
This invites all sorts of races:
1. fish might remove and close the fd right before the monitor polls it. It
will thus attempt to poll a closed fd.
2. fish might remove and close the fd, and then something else opens a file
and receives the same fd. Now the fd monitor will poll an fd that was
never added.
3. fish might remove and close the fd _while the fd monitor is polling it_.
What happens then? (Turns out on macOS we get EBADF, and on Linux the fd is
marked readable).
The Big Idea is that *all of these races are benign*. As long as
poll/select doesn't crash or hang, we don't care *what* it returns, because
the source of truth are the set of items stored in the fd monitor and these
item IDs are never recycled. (This also assumes that it's OK to select/poll
on random file descriptors; there ought to be no side effects).
Not only is this a large simplification since we no longer need that round
trip, it's a substantial performance improvement as well. The
"aliases.fish" benchmark goes from 164 to 154 msec on my Mac, and from 124
to 112 msec on my Linux machine - nearly 10%.
Add some tests to verify our assumptions about the behavior of closing or
replacing a file descriptor during poll. But even if these fail, all we
care about is that poll/select doesn't crash or hang.
FdMonitor is used to monitor a set of file descriptors and invoke a callback
when one becomes readable. Prior to this commit, they coudl also have the
callback invoked on timeout. fish used to use this feature but no longer does;
remove it.
Instead of hardcoded 230px margin.
This also makes the ToC only take up a third of the screen when
narrow, and lets you scroll the rest.
Without, you'd have to scroll past the *entire* ToC, which is awkward
Remaining issue is the search box up top. Since this disables the one
in the sidebar once the window gets too narrow, that one is important,
and it isn't *great*
It is, as the name implies, unused - it became SIGSYS, which we
already check.
Since it is entirely undefined on some architectures it causes a build
failure there, see discussion in #10633
The libc crate has a bug on BSD where WEXITSTATUS is not an 8-bit
value, causing assertion failures.
Any libc higher than our 0.2.155 would increase our MSRV, see libc
commit 5ddbdc29f (Bump MSRV to 1.71, 2024-01-07), so we want to
woraround this anyway. It's probably not worth using a patched
version of libc since it's just one line.
While at it, tighten some types I guess.
Upstream fix: https://github.com/rust-lang/libc/pull/4213Closes#10919
__fish_cancel_commandline was unused (even before) and has some issues
on multiline commandlines. Make it use the previously active logic.
Closes#10935
* Pass path to install()
It was dirty that it would re-get $HOME there anyway.
* Import wcs2osstring
* Allow installable builds to use a relocatable tree
If you give a path to `--install`, it will install fish into a
relocatable tree there, so
PATH/share/fish contains the datafiles
PATH/bin/fish contains the fish executable
PATH/etc/fish is sysconf
I am absolutely not sold on that last one - the way I always used
sysconfdir is that it is always /etc. This would be easy to fix but
should probably also be fixed for "regular" relocatable builds (no
idea who uses them).
An attempt at #10916
* Move install path into "install/" subdir
* Disable --install harder if not installable
I forgot that 610338cc70 (On undo after execute, restore the cursor
position, 2024-12-21) would cause a fallout to tests:
It makes us reuse in another place our usual cursor-movement sequences.
This causes failures like this (linebreaks added for readability):
Testing file pexpects/bind.py:Failed to match pattern: (?:\r\n|\x1b\[2 q)[^\n]*def abc\r\n
bind.py:45: timeout from expect_prompt(TO_END + "def abc\r\n") # emacs transpose words, default timeout: no delay
Escaped buffer:
\x1b[?2004h\x1b[>4;1m\x1b[=5u\x1b=\rprompt 2>echo \rprompt 2>echo abc \rprompt 2>echo def abc\r
prompt 2>echo def abc\x1b[?2004l\x1b[>4;0m\x1b[=0u\x1b>\x1b]133;C\x07def abc\r\n\x1b]133;D;0\x07\x1b[?25h⏎
\r⏎ \r\rprompt 3>\x1b[?2004h\x1b[>4;1m\x1b[=5u\x1b=
It seems that we don't print anything where we should print something
like "\r\n" or "\e[2 q" to move the cursor below the command line.
I haven't gotten to the bottom of this but it might be related to
terminfo. Once we get rid of that, we can unconditionally print
our canonical movement sequences.
This issue seems to only affect tests, since fish operates fine in
a sourcehut CI system. Let's ignore it for now.
Ever since 149594f974 (Initial revision, 2005-09-20), we move the
cursor to the end of the commandline just before executing it.
This is so we can move the cursor to the line below the command line,
so moving the cursor is relevant if one presses enter on say, the
first line of a multi-line commandline.
As mentioned in #10838 and others, it can be useful to restore the
cursor position when recalling commandline from history. Make undo
restore the position where enter was pressed, instead of implicitly
moving the cursor to the end. This allows to quickly correct small
mistakes in large commandlines that failed recently.
This requires a new way of moving the cursor below the command line.
Test changes include unrelated cleanup of history.py.
Please tell us which fish version you are using by executing the following:
fish --version
echo $version
Please tell us which operating system and terminal you are using. The output of `uname -a` and `echo $TERM` may be helpful in this regard although other commands might be relevant in your specific situation.
Please tell us which operating system (output of `uname`) and terminal you are using.
Please tell us if you tried fish without third-party customizations by executing this command and whether it affected the behavior you are reporting:
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:
- Many of our new Chinese translations were more confusing than helpful; they have been fixed or removed (:issue:`11833`).
Note that you can work around this type of issue by configuring fish's :doc:`message localization <cmds/_>`:
if your environment contains something like ``LANG=zh_CN.UTF-8``,
you can use ``set -g LC_MESSAGES en`` to use English messages inside fish.
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`).
- 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`).
- Compound commands (``begin; echo 1; echo 2; end``) can now be written using braces (``{ echo1; echo 2 }``), like in other shells.
- fish now supports transient prompts: if :envvar:`fish_transient_prompt` is set to 1, fish will reexecute prompt functions with the ``--final-rendering`` argument before running a commandline (:issue:`11153`).
- Tab completion results are truncated up to the common directory path, instead of somewhere inside that path. E.g. if you complete "share/functions", and it includes the files "foo.fish" and "bar.fish",
the completion pager will now show "…/foo.fish" and "…/bar.fish" (:issue:`11250`).
- Self-installing builds as created by e.g. ``cargo install`` no longer install other files, see :ref:`below <changelog-4.1-embedded>`.
- Our gettext-based message-localization has been reworked,
adding translations to self-installing builds; see :ref:`below <changelog-4.1-gettext>`.
Deprecations and removed features
---------------------------------
-``set_color --background=COLOR`` no longer implicitly activates bold mode.
If your theme is stored in universal variables (the historical default), some bold formatting might be lost.
To fix this, we suggest updating to the latest version of our theme, to explicitly activate bold mode,
for example use ``fish_config theme save "fish default"``.
-``{echo,echo}`` or ``{ echo, echo }`` are no longer interpreted as brace expansion tokens but as :doc:`compound commands <cmds/begin>`.
- Terminfo-style key names (``bind -k nul``) are no longer supported. They had been superseded by fish's :doc:`own key names <cmds/bind>` since 4.0 (:issue:`11342`).
- fish no longer reads the terminfo database, so its behavior is generally no longer affected by the :envvar:`TERM` environment variable (:issue:`11344`).
For the time being, this change can be reversed via the ``ignore-terminfo``:ref:`feature flag <featureflags>`.
To do so, run the following once and restart fish::
set -Ua fish_features no-ignore-terminfo
- The ``--install`` option when fish is built as self-installing is removed, see :ref:`below <changelog-4.1-embedded>`.
-``set_color ff0000`` now outputs 24-bit RGB true-color even if :envvar:`COLORTERM` is unset.
One can override this by setting :envvar:`fish_term24bit` to 0 (:issue:`11372`).
- fish now requires the terminal to respond to queries for the :ref:`Primary Device Attribute <term-compat-primary-da>`.
For now, this can be reversed via a :ref:`feature flag <featureflags>`,
by running (once) ``set -Ua fish_features no-query-term`` and restarting fish.
- Users of GNU screen may experience :ref:`minor glitches <term-compat-dcs-gnu-screen>` when starting fish.
Scripting improvements
----------------------
- The :doc:`argparse <cmds/argparse>` builtin has seen many improvements, see :ref:`below <changelog-4.1-argparse>`.
- The :doc:`string pad <cmds/string-pad>` command now has a ``-C/--center`` option.
- The :doc:`psub <cmds/psub>` command now allows combining ``--suffix`` with ``--fifo`` (:issue:`11729`).
- The :doc:`read <cmds/read>` builtin has learned the ``--tokenize-raw`` option to tokenize without quote removal (:issue:`11084`).
Interactive improvements
------------------------
- Autosuggestions are now also provided in multi-line command lines. Like :kbd:`ctrl-r`, these operate only on the current line.
- Autosuggestions used to not suggest multi-line command-lines from history; now autosuggestions include individual lines from multi-line command-lines.
- The history pager search now preserves ordering between :kbd:`ctrl-s` forward and :kbd:`ctrl-r` backward searches.
- Instead of highlighting events by flashing *all text to the left of the cursor*,
failing history token search (:kbd:`alt-.`) flashes the associated token,
failing tab-completion flashes the to-be-completed token (:issue:`11050`),
deleting an autosuggestion (:kbd:`shift-delete`) flashes the suggestion,
and all other scenarios flash the full command line.
- Pasted commands are now stripped of any :code:`$\` command prefixes, to help pasting code snippets.
- Builtin help options (e.g. ``abbr --help``) now use ``man`` directly, meaning that variables like :envvar:`MANWIDTH` are respected (:issue:`11786`).
-``funced`` will now edit copied functions directly, instead of the file where ``function --copy`` was invoked. (:issue:`11614`)
- Added a simple ``fish_jj_prompt`` which reduces visual noise in the prompt inside `Jujutsu <https://jj-vcs.github.io/jj/latest/>`__ repositories that are colocated with Git.
New or improved bindings
^^^^^^^^^^^^^^^^^^^^^^^^
- On non-macOS systems, :kbd:`alt-left`, :kbd:`alt-right`, :kbd:`alt-backspace` and :kbd:`alt-delete` no longer operate on punctuation-delimited words but on whole arguments, possibly including special characters like ``/`` and quoted spaces.
On macOS, the corresponding :kbd:`ctrl-` prefixed keys operate on whole arguments.
Word operations are still available via the other respective modifier, just like in most web browsers.
-:kbd:`ctrl-z` (undo) after executing a command will restore the previous cursor position instead of placing the cursor at the end of the command line.
- The :kbd:`alt-s` binding will now also use ``run0`` if available.
- Some mouse support has been added: the OSC 133 prompt marking feature has learned about kitty's ``click_events=1`` flag, which allows moving fish's cursor by clicking in the command line,
and selecting pager items (:issue:`10932`).
- Before clearing the screen and redrawing, :kbd:`ctrl-l` now pushes all text located above the prompt to the terminal's scrollback,
via a new special input function :ref:`scrollback-push <special-input-functions-scrollback-push>`.
For compatibility with terminals that do not implement ECMA-48's :ref:`SCROLL UP <term-compat-indn>` command,
this function is only used if the terminal advertises support for that via :ref:`XTGETTCAP <term-compat-xtgettcap>`.
- Vi mode has learned :kbd:`ctrl-a` (increment) and :kbd:`ctrl-x` (decrement) (:issue:`11570`).
Completions
^^^^^^^^^^^
-``git`` completions now show the remote URL as description when completing remotes.
-``systemctl`` completions no longer print escape codes if ``SYSTEMD_COLORS`` happens to be set (:issue:`11465`).
- Added and improved many completion scripts, notably ``tmux``.
Improved terminal support
^^^^^^^^^^^^^^^^^^^^^^^^^
- Support for double, curly, dotted and dashed underlines, for use in ``fish_color_*`` variables and the :doc:`set_color builtin <cmds/set_color>` (:issue:`10957`).
- Underlines can now be colored independent of text (:issue:`7619`).
- New documentation page :doc:`Terminal Compatibility <terminal-compatibility>` (also accessible via ``man fish-terminal-compatibility``) lists the terminal control sequences used by fish.
Other improvements
------------------
- Updated Chinese and German translations.
-``fish_indent --dump-parse-tree`` now emits simple metrics about the tree including its memory consumption.
- We added some tools to improve development workflows, for example ``build_tools/{check,update_translations,release}.sh`` and ``tests/test_driver.py``.
In conjunction with ``cargo``, these enable almost all day-to-day development tasks without using CMake.
For distributors
----------------
- Builtin commands that support the ``--help`` option now require the ``man`` program.
The direct dependency on ``mandoc`` and ``nroff`` has been removed.
- fish no longer uses gettext MO files, see :ref:`below <changelog-4.1-gettext>`.
If you have use cases which are incompatible with our new approach, please let us know.
- The :doc:`fish_indent <cmds/fish_indent>` and :doc:`fish_key_reader <cmds/fish_key_reader>` programs are now also available as builtins.
If fish is invoked via e.g. a symlink with one of these names,
it will act like the given tool (i.e. it's a multi-call binary).
This allows truly distributing fish as a single file (:issue:`10876`).
- The CMake build configuration has been simplified and no longer second-guesses rustup.
It will run rustc and cargo via :envvar:`PATH` or in ~/.cargo/bin/.
If that doesn't match your setup, set the Rust_COMPILER and Rust_CARGO CMake variables (:issue:`11328`).
- Cygwin support has been reintroduced, since `Rust gained a Cygwin target <https://github.com/rust-lang/rust/pull/134999>`__ (:issue:`11238`).
- CMake 3.15 is now required.
.._changelog-4.1-embedded:
Changes to self-installing builds
---------------------------------
The self-installing build type introduced in fish 4.0 has been changed (:issue:`11143`).
Now fish built with embedded data will just read the data straight from its own binary or write it out to temporary files when necessary, instead of requiring an installation step on start.
That means it is now possible to build fish as a single file and copy it to any system with a compatible CPU architecture, including as a different user, without extracting any files.
As before, this is the default when building via ``cargo``, and disabled when building via CMake.
For packagers we continue to recommend CMake.
Note: When fish is built like this, the :envvar:`__fish_data_dir` variable will be empty because that directory no longer has meaning.
You should generally not need these files.
For example, if you want to make sure that completions for "foo" are loaded, use ``complete -C"foo " >/dev/null`` instead).
The raw files are still exposed via :ref:`status subcommands <status-get-file>`, mainly for fish's internal use, but you can also use them as a last resort.
Remaining benefits of a full installation (as currently done by CMake) are:
- man pages like ``fish(1)`` in standard locations, easily accessible from outside fish.
- a local copy of the HTML documentation, typically accessed via the :doc:`help <cmds/help>` function.
In builds with embedded data, ``help`` will redirect to e.g. `<https://fishshell.com/docs/current/>`__
-``fish_indent`` and ``fish_key_reader`` as separate files, making them easily accessible outside fish
- an (empty) ``/etc/fish/config.fish`` as well as empty directories ``/etc/fish/{functions,completions,conf.d}``
-``$PREFIX/share/pkgconfig/fish.pc``, which defines directories for configuration-snippets, like ``vendor_completions.d``
.._changelog-4.1-gettext:
Changes to gettext localization
-------------------------------
We replaced several parts of the gettext functionality with custom implementations (:issue:`11726`).
Most notably, message extraction, which should now work reliably, and the runtime implementation, where we no longer dynamically link to gettext, but instead use our own implementation, whose behavior is similar to GNU gettext, with some :doc:`minor deviations <cmds/_>`.
Our implementation now fully respects fish variables, so locale variables do not have to be exported for fish localizations to work.
They still have to be exported to inform other programs about language preferences.
The :envvar:`LANGUAGE` environment variable is now treated as a path variable, meaning it is an implicitly colon-separated list.
While we no longer have any runtime dependency on gettext, we still need gettext tools for building, most notably ``msgfmt``.
When building without ``msgfmt`` available, localization will not work with the resulting executable.
Localization data is no longer sourced at runtime from MO files on the file system, but instead built into the executable.
This is always done, independently of the other data embedding, so all fish executables will have access to all message catalogs, regardless of the state of the file system.
Disabling our new ``localize-messages`` cargo feature will cause fish to be built without localization support.
CMake builds can continue to use the ``WITH_GETTEXT`` option, with the same semantics as the ``localize-messages`` feature.
The current implementation does not provide any configuration options for controlling which language catalogs are built into the executable (other than disabling them all).
As a workaround, you can delete files in the ``po`` directory before building to exclude unwanted languages.
.._changelog-4.1-argparse:
Changes to the :doc:`argparse <cmds/argparse>` builtin
-``argparse`` now saves recognised options, including option-arguments in :envvar:`argv_opts`, allowing them to be forwarded to other commands (:issue:`6466`).
-``argparse`` options can now be marked to be deleted from :envvar:`argv_opts` (by adding a ``&`` at the end of the option spec, before a ``!`` if present). There is now also a corresponding ``-d`` / ``--delete`` option to ``fish_opt``.
-``argparse --ignore-unknown`` now removes preceding known short options from groups containing unknown options (e.g. when parsing ``-abc``, if ``a`` is known but ``b`` is not, then :envvar:`argv` will contain ``-bc``).
-``argparse`` now has an ``-u`` / ``--move-unknown`` option that works like ``--ignore-unknown`` but preserves unknown options in :envvar:`argv`.
-``argparse`` now has an ``-S`` / ``--strict-longopts`` option that forbids abbreviating long options or passing them with a single dash (e.g. if there is a long option called ``foo``, ``--fo`` and ``--foo`` won't match it).
-``argparse`` now has a ``-U`` / ``--unknown-arguments`` option to specify how to parse unknown option's arguments.
-``argparse`` now allows specifying options that take multiple optional values by using ``=*`` in the option spec (:issue:`8432`).
In addition, ``fish_opt`` has been modified to support such options by using the ``--multiple-vals`` together with ``-o`` / ``--optional-val``; ``-m`` is also now acceptable as an abbreviation for ``--multiple-vals``.
-``fish_opt`` no longer requires you give a short flag name when defining options, provided you give it a long flag name with more than one character.
-``argparse`` option specifiers for long-only options can now start with ``/``, allowing the definition of long options with a single letter. Due to this change, the ``--long-only`` option to ``fish_opt`` is now no longer necessary and is deprecated.
-``fish_opt`` now has a ``-v`` / ``--validate`` option you can use to give a fish script to validate values of the option.
--------------
fish 4.0.9 (released September 27, 2025)
========================================
This release fixes:
- a regression in 4.0.6 causing shifted keys to not be inserted on some terminals (:issue:`11813`).
- a regression in 4.0.6 causing the build to fail on systems where ``char`` is unsigned (:issue:`11804`).
- a regression in 4.0.0 causing a crash on an invalid :doc:`bg <cmds/bg>` invocation.
--------------
fish 4.0.8 (released September 18, 2025)
========================================
This release fixes a regression in 4.0.6 that caused user bindings to be shadowed by either fish's or a plugin's bindings (:issue:`11803`).
--------------
fish 4.0.6 (released September 12, 2025)
========================================
This release of fish fixes a number of issues identified in fish 4.0.2:
- fish now properly inherits $PATH under Windows WSL2 (:issue:`11354`).
- Remote filesystems are detected properly again on non-Linux systems.
- the :doc:`printf <cmds/printf>` builtin no longer miscalculates width of multi-byte characters (:issue:`11412`).
- For many years, fish has been "relocatable" -- it was possible to move the entire ``CMAKE_INSTALL_PREFIX`` and fish would use paths relative to its binary.
Only gettext locale paths were still determined purely at compile time, which has been fixed.
- the :doc:`commandline <cmds/commandline>` builtin failed to print the commandline set by a ``commandline -C`` invocation, which broke some completion scripts.
This has been corrected (:issue:`11423`).
- To work around terminals that fail to parse Operating System Command (OSC) sequences, a temporary feature flag has been added.
It allows you to disable prompt marking (OSC 133) by running (once) ``set -Ua fish_features no-mark-prompt`` and restarting fish (:issue:`11749`).
- The routines to save history and universal variables have seen some robustness improvements.
- builtin :doc:`status current-command <cmds/status>` no longer prints a trailing blank line.
- A crash displaying multi-line quoted command substitutions has been fixed (:issue:`11444`).
- Commands like ``set fish_complete_path ...`` accidentally disabled completion autoloading, which has been corrected.
-``nmcli`` completions have been fixed to query network information dynamically instead of only when completing the first time.
- Git completions no longer print an error when no `git-foo` executable is in :envvar:`PATH`.
- Custom completions like ``complete foo -l long -xa ...`` that use the output of ``commandline -t``.
on a command-line like ``foo --long=`` have been invalidated by a change in 4.0; the completion scripts have been adjusted accordingly (:issue:`11508`).
- Some completions were misinterpreted, which caused garbage to be displayed in the completion list. This has been fixed.
- fish no longer interprets invalid control sequences from the terminal as if they were :kbd:`alt-[` or :kbd:`alt-o` key strokes.
-:doc:`bind <cmds/bind>` has been taught about the :kbd:`printscreen` and :kbd:`menu` keys.
-:kbd:`alt-delete` now deletes the word right of the cursor.
-:kbd:`ctrl-alt-h` erases the last word again (:issue:`11548`).
-:kbd:`alt-left`:kbd:`alt-right` were misinterpreted because they send unexpected sequences on some terminals; a workaround has been added. (:issue:`11479`).
- Key bindings like ``bind shift-A`` are no longer accepted; use ``bind shift-a`` or ``bind A``.
- Key bindings like ``bind shift-a`` take precedence over ``bind A`` when the key event included the shift modifier.
- Bindings using shift with non-ASCII letters (such as :kbd:`ctrl-shift-ä`) are now supported.
- Bindings with modifiers such as ``bind ctrl-w`` work again on non-Latin keyboard layouts such as a Russian one.
This is implemented by allowing key events such as :kbd:`ctrl-ц` to match bindings of the corresponding Latin key, using the kitty keyboard protocol's base layout key (:issue:`11520`).
- Vi mode: The cursor position after pasting via :kbd:`p` has been corrected.
- Vi mode: Trying to replace the last character via :kbd:`r` no longer replaces the last-but-one character (:issue:`11484`).
--------------
fish 4.0.2 (released April 20, 2025)
====================================
@@ -7,7 +417,7 @@ This release of fish fixes a number of issues identified in fish 4.0.1:
- The warning when the terminfo database can't be found has been downgraded to a log message. fish will act as if the terminal behaves like xterm-256color, which is correct for the vast majority of cases (:issue:`11277`, :issue:`11290`).
- Key combinations using the super (Windows/command) key can now (actually) be bound using the :kbd:`super-` prefix (:issue:`11217`). This was listed in the release notes for 4.0.1 but did not work correctly.
-:doc:`function <cmds/function>` is stricter about argument parsing, rather than allowing additional parameters to be silently ignored (:issue:`11295`).
- Using parentheses in the :doc:`test <cmds/test>` builtin works correctly, following a regression in 4.0.0 where they were not recognized (:issue:`11387`).
- Using parentheses in the :doc:`test <cmds/test>` builtin works correctly, following a regression in 4.0.0 where they were not recognized (:issue:`11387`).
-:kbd:`delete` in Vi mode when Num Lock is active will work correctly (:issue:`11303`).
- Abbreviations cannot alter the command-line contents, preventing a crash (:issue:`11324`).
- Improvements to various completions, including new completions for ``wl-randr`` (:issue:`11301`), performance improvements for ``cargo`` completions by avoiding network requests (:issue:`11347`), and other improvements for ``btrfs`` (:issue:`11320`), ``cryptsetup`` (:issue:`11315`), ``git`` (:issue:`11319`, :issue:`11322`, :issue:`11323`), ``jj`` (:issue:`11046`), and ``systemd-analyze`` (:issue:`11314`).
@@ -37,7 +447,7 @@ This release of fish includes the following improvements compared to fish 4.0.0:
- Completions for ``wine`` correctly include files again (:issue:`11202`).
- On macOS, paths from ``/etc/paths`` and ``/etc/manpaths`` containing colons are handled correctly (:issue:`10684`). This functionality was included in the 4.0.0 release notes but was missing from the source code.
- The XTerm ``modifyOtherKeys`` keyboard encoding is no longer used under WezTerm, as it does not work correctly in all layouts (:issue:`11204`).
- kbd:`option-left` and other similar keys should now work in iTerm versions before 3.5.12; the kitty keyboard protocol is now disabled on these versions (:issue:`11192`).
-:kbd:`option-left` and other similar keys should now work in iTerm versions before 3.5.12; the kitty keyboard protocol is now disabled on these versions (:issue:`11192`).
- The kitty keyboard protocol is no longer used under Midnight Commander, as it does not work correctly (:issue:`10640`).
- fish now sends the commandline along with the OSC 133 semantic prompt command start sequence. This fixes a test in the kitty terminal (:issue:`11203`).
- Git completions for third-party commands like "git-absorb" are completed correctly again (:issue:`11205`).
- As part of a larger binding rework, ``bind`` gained a new key notation.
In most cases the old notation should keep working, but in rare cases you may have to change a ``bind`` invocation to use the new notation.
See :ref:`below <changelog-new-bindings>` for details.
See :ref:`below <changelog-4.0-new-bindings>` for details.
-:kbd:`ctrl-c` now calls a new bind function called ``clear-commandline``. The old behavior, which leaves a "^C" marker, is available as ``cancel-commandline`` (:issue:`10935`)
-``random`` will produce different values from previous versions of fish when used with the same seed, and will work more sensibly with small seed numbers.
The seed was never guaranteed to give the same result across systems,
- fish now requests XTerm's ``modifyOtherKeys`` keyboard encoding and `kitty keyboard protocol's <https://sw.kovidgoyal.net/kitty/keyboard-protocol/>`_ progressive enhancements (:issue:`10359`).
Depending on terminal support, this allows to binding more key combinations, including arbitrary combinations of modifiers :kbd:`ctrl`, :kbd:`alt` and :kbd:`shift`, and distinguishing (for example) :kbd:`ctrl-i` from :kbd:`tab`.
@@ -198,7 +608,6 @@ Interactive improvements
The color scheme will not be upgraded for existing installs. If you want, you should select it again via ``fish_config``.
- Command lines which are larger than the terminal are now displayed correctly, instead of multiple blank lines being displayed (:issue:`7296`).
- Prompts that use external commands will no longer produce an infinite loop if the command crashes (:issue:`9796`).
- Undo (:kbd:`ctrl-z`) restores the cursor position too (:issue:`10838`).
- The output of ``jobs`` shows "-" for jobs that have the same process group ID as the fish process, rather than "-2" (:issue:`10833`).
- Job expansion (``%1`` syntax) works properly for jobs that are a mixture of external commands and functions (:issue:`10832`).
- Command lines which have more lines than the terminal can be displayed and edited correctly (:issue:`10827`).
@@ -211,10 +620,11 @@ Interactive improvements
New or improved bindings
^^^^^^^^^^^^^^^^^^^^^^^^
- When the cursor is on a command that resolves to an executable script, :kbd:`alt-o` will now open that script in your editor (:issue:`10266`).
- During up-arrow history search, :kbd:`shift-delete` will delete the current search item and move to the next older item. Previously this was only supported in the history pager.
- During up-arrow history search, :kbd:`shift-delete` will delete the current search item and move to the next older item. Previously this was only supported in the history pager.
-:kbd:`shift-delete` will also remove the currently-displayed autosuggestion from history, and remove it as a suggestion.
-:kbd:`ctrl-Z` (also known as :kbd:`ctrl-shift-z`) is now bound to redo.
- Some improvements to the :kbd:`alt-e` binding which edits the command line in an external editor:
- The editor's cursor position is copied back to fish. This is currently supported for Vim and Kakoune.
- Cursor position synchronization is only supported for a set of known editors, which are now also detected in aliases which use ``complete --wraps``. For example, use ``complete --wraps my-vim vim`` to synchronize cursors when ``EDITOR=my-vim``.
- Multiline commands are indented before being sent to the editor, which matches how they are displayed in fish.
@@ -222,16 +632,19 @@ New or improved bindings
- Bindings like :kbd:`alt-l` that print output in between prompts now work correctly with multiline commandlines.
-:kbd:`alt-d` on an empty command line lists the directory history again. This restores the behavior of version 2.1.
-``history-prefix-search-backward`` and ``-forward`` now maintain the cursor position, instead of moving the cursor to the end of the command line (:issue:`10430`).
- The following keys have refined behavior if the terminal supports :ref:`the new keyboard encodings <changelog-new-bindings>`:
- The following keys have refined behavior if the terminal supports :ref:`the new keyboard encodings <changelog-4.0-new-bindings>`:
-:kbd:`shift-enter` now inserts a newline instead of executing the command line.
-:kbd:`ctrl-backspace` now deletes the last word instead of only one character (:issue:`10741`).
-:kbd:`ctrl-delete` deletes the next word (same as :kbd:`alt-d`).
- New special input functions:
-``forward-char-passive`` and ``backward-char-passive`` are like their non-passive variants but do not accept autosuggestions or move focus in the completion pager (:issue:`10398`).
-``forward-token``, ``backward-token``, ``kill-token``, and ``backward-kill-token`` are similar to the ``*-bigword`` variants but for the whole argument token (which includes escaped spaces) (:issue:`2014`).
-``clear-commandline``, which merely clears the command line, as an alternative to ``cancel-commandline`` which prints ``^C`` and a new prompt (:issue:`10213`).
- The ``accept-autosuggestion`` special input function now returns false when there was nothing to accept (:issue:`10608`).
- Vi mode has seen some improvements but continues to suffer from the lack of people working on it.
- New default cursor shapes for insert and replace mode.
-:kbd:`ctrl-n` in insert mode accepts autosuggestions (:issue:`10339`).
- Outside insert mode, the cursor will no longer be placed beyond the last character on the commandline.
@@ -278,7 +691,7 @@ Improved terminal support
Other improvements
------------------
-``status`` gained a ``buildinfo`` subcommand, to print information on how fish was built, to help with debugging (:issue:`10896`).
-``status`` gained a ``build-info`` subcommand, to print information on how fish was built, to help with debugging (:issue:`10896`).
-``fish_indent`` will now collapse multiple empty lines into one (:issue:`10325`).
-``fish_indent`` now preserves the modification time of files if there were no changes (:issue:`10624`).
- Performance in launching external processes has been improved for many cases (:issue:`10869`).
@@ -569,7 +982,7 @@ fish 3.6.0 (released January 7, 2023)
Notable improvements and fixes
------------------------------
- By default, :kbd:`ctrl-r` now opens the command history in the pager (:issue:`602`). This is fully searchable and syntax-highlighted, as an alternative to the incremental search seen in other shells. The new special input function ``history-pager`` has been added for custom bindings.
- Abbrevations are more flexible (:issue:`9313`, :issue:`5003`, :issue:`2287`):
- Abbreviations are more flexible (:issue:`9313`, :issue:`5003`, :issue:`2287`):
- They may optionally replace tokens anywhere on the command line, instead of only commands
- Matching tokens may be described using a regular expression instead of a literal word
@@ -593,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
@@ -665,7 +1078,7 @@ Interactive improvements
- A new variable, :envvar:`fish_cursor_selection_mode`, can be used to configure whether the command line selection includes the character under the cursor (``inclusive``) or not (``exclusive``). The new default is ``exclusive``; use ``set fish_cursor_selection_mode inclusive`` to get the previous behavior back (:issue:`7762`).
- fish's completion pager now fills half the terminal on first tab press instead of only 4 rows, which should make results visible more often and save key presses, without constantly snapping fish to the top of the terminal (:issue:`9105`, :issue:`2698`).
- The ``complete-and-search`` binding, used with :kbd:`shift-tab` by default, selects the first item in the results immediately (:issue:`9080`).
-``bind`` output is now syntax-highlighted when used interacively.
-``bind`` output is now syntax-highlighted when used interactively.
-:kbd:`alt-h` (the default ``__fish_man_page`` binding) does a better job of showing the manual page of the command under cursor (:issue:`9020`).
- If :envvar:`fish_color_valid_path` contains an actual color instead of just modifiers, those will be used for valid paths even if the underlying color isn't "normal" (:issue:`9159`).
- The key combination for the QUIT terminal sequence, often :kbd:`ctrl-\\` (``\x1c``), can now be used as a binding (:issue:`9234`).
@@ -894,7 +1307,7 @@ Interactive improvements
New or improved bindings
^^^^^^^^^^^^^^^^^^^^^^^^
- The :kbd:`alt-s` binding will now insert ``doas`` instead of ``sudo`` if necessary (:issue:`8942`).
- The ``kill-whole-line`` special input function now kills the newline preceeding the last line. This makes ``dd`` in vi-mode clear the last line properly.
- The ``kill-whole-line`` special input function now kills the newline preceding the last line. This makes ``dd`` in vi-mode clear the last line properly.
- The new ``kill-inner-line`` special input function kills the line without any newlines, allowing ``cc`` in vi-mode to clear the line while preserving newlines (:issue:`8983`).
- On terminals that emit special sequences for these combinations, :kbd:`shift-space` is bound like :kbd:`space`, and :kbd:`ctrl-enter` is bound like :kbd:`return` (:issue:`8874`).
@@ -1003,7 +1416,7 @@ Deprecations and removed features
> set -Ua fish_features ampersand-nobg-in-token
-``$status`` is now forbidden as a command, to prevent a surprisingly common error among new users: Running ``if $status`` (:issue:`8171`). This applies *only* to ``$status``, other variables are still allowed.
-``set --query`` now returns an exit status of 255 if given no variable names. This means ``if set -q $foo`` will not enter the if-block if ``$foo`` is empty or unset. To restore the previous behavior, use ``if not set -q foo; or set -q $foo`` - but this is unlikely to be desireable (:issue:`8214`).
-``set --query`` now returns an exit status of 255 if given no variable names. This means ``if set -q $foo`` will not enter the if-block if ``$foo`` is empty or unset. To restore the previous behavior, use ``if not set -q foo; or set -q $foo`` - but this is unlikely to be desirable (:issue:`8214`).
-``_`` is now a reserved keyword (:issue:`8342`).
- The special input functions ``delete-or-exit``, ``nextd-or-forward-word`` and ``prevd-or-backward-word`` replace fish functions of the same names (:issue:`8538`).
- Mac OS X 10.9 is no longer supported. The minimum Mac version is now 10.10 "Yosemite."
@@ -1018,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`).
@@ -1026,7 +1439,7 @@ Scripting improvements
-``commandline`` gained a ``--paging-full-mode`` option to check if the pager is showing all the possible lines (no "7 more rows" message) (:issue:`8485`).
- List expansion correctly reports an error when used with all zero indexes (:issue:`8213`).
- Running ``fish`` with a directory instead of a script as argument (eg ``fish .``) no longer leads to an infinite loop. Instead it errors out immediately (:issue:`8258`)
- Some error messages occuring after fork, like "text file busy" have been replaced by bespoke error messages for fish (like "File is currently open for writing"). This also restores error messages with current glibc versions that removed sys_errlist (:issue:`8234`, :issue:`4183`).
- Some error messages occurring after fork, like "text file busy" have been replaced by bespoke error messages for fish (like "File is currently open for writing"). This also restores error messages with current glibc versions that removed sys_errlist (:issue:`8234`, :issue:`4183`).
- The ``realpath`` builtin now also squashes leading slashes with the ``--no-symlinks`` option (:issue:`8281`).
- When trying to ``cd`` to a dangling (broken) symbolic link, fish will print an error noting that the target is a broken link (:issue:`8264`).
- On MacOS terminals that are not granted permissions to access a folder, ``cd`` would print a spurious "rotten symlink" error, which has been corrected to "permission denied" (:issue:`8264`).
@@ -1532,7 +1945,7 @@ Interactive improvements
-:kbd:`ctrl-c` handling has been reimplemented in C++ and is therefore quicker (:issue:`5259`), no longer occasionally prints an "unknown command" error (:issue:`7145`) or overwrites multiline prompts (:issue:`3537`).
-:kbd:`ctrl-c` no longer kills background jobs for which job control is
- Autosuggestions work properly after :kbd:`ctrl-c` cancels the current commmand line (:issue:`6937`).
- Autosuggestions work properly after :kbd:`ctrl-c` cancels the current command line (:issue:`6937`).
- History search is now case-insensitive unless the search string contains an uppercase character (:issue:`7273`).
-``fish_update_completions`` gained a new ``--keep`` option, which improves speed by skipping completions that already exist (:issue:`6775`, :issue:`6796`).
- Aliases containing an embedded backslash appear properly in the output of ``alias`` (:issue:`6910`).
@@ -2086,7 +2499,7 @@ Interactive improvements
argument.
- Syntax highlighting works correctly with variables as commands
(:issue:`5658`) and redirections to close file descriptors (:issue:`6092`).
-``help`` works properly on Windows Subsytem for Linux (:issue:`5759`, :issue:`6338`).
-``help`` works properly on Windows Subsystem for Linux (:issue:`5759`, :issue:`6338`).
- A bug where ``disown`` could crash the shell has been fixed (:issue:`5720`).
- fish will not autosuggest files ending with ``~`` unless there are no
other candidates, as these are generally backup files (:issue:`985`).
@@ -3028,7 +3441,7 @@ Other significant changes
- Some systems’``su`` implementations do not set the ``USER``
environment variable; it is now reset for root users (:issue:`3916`).
- Under terminals which support it, bracketed paste is enabled,
escaping problematic characters for security and convience (:issue:`3871`).
escaping problematic characters for security and convenience (:issue:`3871`).
Inside single quotes (``'``), single quotes and backslashes in pasted
text are escaped (:issue:`967`). The ``fish_clipboard_paste`` function (bound
to ``C-v`` by default) is still the recommended pasting method where
@@ -3157,9 +3570,9 @@ Other significant changes
- fish no longer prints a warning when it identifies a running instance
of an old version (2.1.0 and earlier). Changes to universal variables
may not propagate between these old versions and 2.5b1.
- Improved compatiblity with Android (:issue:`3585`), MSYS/mingw (:issue:`2360`), and
- Improved compatibility with Android (:issue:`3585`), MSYS/mingw (:issue:`2360`), and
Solaris (:issue:`3456`, :issue:`3340`).
- Like other shells, the ``test`` builting now returns an error for
- Like other shells, the ``test`` built-in now returns an error for
numeric operations on invalid integers (:issue:`3346`, :issue:`3581`).
-``complete`` no longer recognises ``--authoritative`` and
``--unauthoritative`` options, and they are marked as obsolete.
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
=======
@@ -183,140 +199,155 @@ 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.
-``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 build_tools/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.
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``).
Local testing
-------------
The tests can be run on your local computer on all operating systems.
One neat thing you can do is set a list of languages to check for translations in the order defined
using the ``LANGUAGE`` variable, e.g.::
set LANGUAGE pt_BR de_DE
to try to translate messages to Portuguese, if that fails try German, and if that fails too you will
see the English version defined in the source code.
Modifying existing translations
-------------------------------
If you want to work on translations for a language which already has a corresponding ``po`` file, it
is sufficient to edit this file. No other changes are necessary.
After recompiling fish, you should be able to see your translations in action. See the previous
section for details.
Editing PO files
----------------
Many tools are available for editing translation files, including
command-line and graphical user interface programs. For simple use, you can just use your text editor.
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"
msgstr ""
msgid "%s: No suitable job\n"
msgstr ""
The ``msgid`` here is the "name" of the string to translate, typically the english string to translate. The second line (``msgstr``) is where your translation goes.
The ``msgid`` here is the "name" of the string to translate, typically the English string to translate.
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.
Our tests run ``msgfmt --check-format /path/to/file``, so they would catch mismatched placeholders - otherwise fish would crash at runtime when the string is about to be used.
Be cautious about blindly updating an existing translation file. Trivial
changes to an existing message (eg changing the punctuation) will cause
existing translations to be removed, since the tools do literal string
matching. Therefore, in general, you need to carefully review any
recommended deletions.
Be cautious about blindly updating an existing translation file.
``msgid`` strings should never be updated manually, only by running the appropriate script.
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 (``localization/po/*.po``).
This is only relevant for developers modifying the source files of fish or fish scripts.
Setting Code Up For Translations
--------------------------------
@@ -327,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.
@@ -336,20 +367,26 @@ that the following are **not** valid:
::
echo (_ hello)
_ "goodbye"
echo (_ hello)
_ "goodbye"
Above should be written like this instead:
::
echo (_ "hello")
echo (_ "goodbye")
echo (_ "hello")
echo (_ "goodbye")
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.
and can be installed using the following commands:
::
sudo apt-add-repository ppa:fish-shell/release-3
sudo apt-add-repository ppa:fish-shell/release-4
sudo apt update
sudo apt install fish
@@ -66,7 +66,8 @@ Windows
for Linux with the instructions for the appropriate distribution
listed above under “Packages for Linux”, or from source with the
instructions below.
-fish (4.0 on and onwards) cannot be installed in Cygwin, due to a lack of Rust support.
-Fish can also be installed on all versions of Windows using
`Cygwin <https://cygwin.com/>`__ or `MSYS2 <https://github.com/Berrysoft/fish-msys2>`__.
Building from source
~~~~~~~~~~~~~~~~~~~~
@@ -75,7 +76,7 @@ If packages are not available for your platform, GPG-signed tarballs are
available from `fishshell.com <https://fishshell.com/>`__ and
`fish-shell on
GitHub <https://github.com/fish-shell/fish-shell/releases>`__. See the
`Building <#building>`__ section for instructions.
`Building <#building>`_ section for instructions.
Running fish
------------
@@ -87,23 +88,19 @@ Dependencies
Running fish requires:
- A terminfo database, typically from curses or ncurses (preinstalled on most \*nix systems) - this needs to be the directory tree format, not the "hashed" database.
If this is unavailable, fish uses an included xterm-256color definition.
- some common \*nix system utilities (currently ``mktemp``), in
addition to the basic POSIX utilities (``cat``, ``cut``, ``dirname``,
``uname`` and ``sed`` at least, but the full coreutils plus ``find`` and
``awk`` is preferred)
- The gettext library, if compiled with
translation support
The following optional features also have specific requirements:
- builtin commands that have the ``--help`` option or print usage
messages require ``nroff`` or ``mandoc`` for
display
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
@@ -115,24 +112,22 @@ 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
- gettext (headers and libraries) - optional, for translation support
- gettext (only the msgfmt tool) - optional, for translation support
- an Internet connection, as other dependencies will be downloaded automatically
Sphinx is also optionally required to build the documentation from a
cloned git repository.
Additionally, running the full test suite requires Python 3, 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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -144,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 ..
@@ -159,40 +154,50 @@ CMake Build options
In addition to the normal CMake build options (like ``CMAKE_INSTALL_PREFIX``), fish's CMake build has some other options available to customize it.
-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).
-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.
- 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 build with gettext support for translations.
-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 as self-installable (experimental)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Building fish with Cargo
~~~~~~~~~~~~~~~~~~~~~~~~
You can also build fish as a self-installing binary.
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
On the first interactive run, and whenever it notices they are out of date, it will extract the datafiles to ~/.local/share/fish/install/ (currently, subject to change). You can do this manually by running ``fish --install``.
cargo install --path /path/to/fish # if you have a git clone
cargo install --git https://github.com/fish-shell/fish-shell --tag 4.0 # to build from git once 4.0 is released
cargo install --git https://github.com/fish-shell/fish-shell # to build the current development snapshot without cloning
uv run --no-managed-python \
cargo install --path .
This will place the 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) or translations.
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-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"Argument $arg is not a file in the directory $(realpath $po_dir)."
echo"Non-option arguments must specify paths to files in this directory."
echo""
echo"If you want to add a new language to the translations not the following:"
echo"The filename must identify a language, with a two letter ISO 639-1 language code of the target language (e.g. 'pt' for Portuguese), and use the file extension '.po'."
echo"Optionally, you can specify a regional variant (e.g. 'pt_BR')."
echo"So valid filenames are of the shape 'll.po' or 'll_CC.po'."
/// Width of ambiguous East Asian characters and, as of TR11, all private-use characters.
/// 1 is the typical default, but we accept any non-negative override via `$fish_ambiguous_width`.
@@ -22,7 +18,7 @@
/// This must be configurable because the value changed between Unicode 8 and Unicode 9, `wcwidth()`
/// is emoji-unaware, and terminal emulators do different things.
///
/// See issues like #4539 and https://github.com/neovim/issues/4976 for how painful this is.
/// See issues like [#4539](https://github.com/fish-shell/fish-shell/issues/4539) and <https://github.com/neovim/neovim/issues/4976> for how painful this is.
///
/// Valid values are 1, and 2. 1 is the typical emoji width used in Unicode 8 while some newer
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.