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
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)
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)
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
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).
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)
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)
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)
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 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 "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)
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)
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)
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 --no-mo` after changing source files.'; exit 1; }
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; }
-Compound commands (``begin; echo 1; echo 2; end``) can now be now be abbreviated 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`).
-When tab completion results are truncated, any common directory name is omitted. 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". This will make the candidates shorter and allow for more to be shown at once (:issue:`11250`).
- The self-installing configuration introduced in fish 4.0 has been changed.
Now fish built with embedded data will just read the data straight from its own binary or write it out 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 a compatible system, 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`, and for packagers we continue to recommend cmake.
Note: When fish is built like this, the `$__fish_data_dir` variable will be empty because that directory no longer has meaning. If you need to load files from there,
use `status get-file` or find alternatives (like loading completions for "foo" via `complete -C"foo "`).
We're considering making data embedding mandatory in future releases because it has a few advantages even for installation from a package (like making file conflicts with other packages impossible). (:issue:`11143`)
-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
---------------------------------
-Tokens like ``{echo,echo}`` or ``{ echo, echo }`` in command position are no longer interpreted as brace expansion but as compound command.
- Terminfo-style key names (``bind -k``) are no longer supported. They had been superseded by the native notation since 4.0,
and currently they would map back to information from terminfo, which does not match what terminals would send with the kitty keyboard protocol (:issue:`11342`).
- fish no longer reads the terminfo database, so its behavior is no longer affected by the :envvar:`TERM` environment variable (:issue:`11344`).
For the time being, this can be turned off via the "ignore-terminfo" feature flag::
set -Ua fish_features no-ignore-terminfo
- The ``--install`` option when fish is built as self-installable was removed. If you need to write out fish's data you can use the new ``status list-files`` and ``status get-file`` subcommands, but it should no longer be necessary. (:issue:`11143`)
- RGB colors (``set_color ff0000``) now default to using 24-bit RGB true-color commands, even if $COLORTERM is unset, because that is often lost e.g. over ssh (:issue:`11372`)
- To go back to using the nearest match from the 256-color palette, use ``set fish_term24bit 0`` or set $COLORTERM to a value that is not "24bit" or "truecolor".
To make the nearest-match logic use the 16 color palette instead, use ``set fish_term256 0``.
- Inside macOS Terminal.app, fish makes an attempt to still use the palette colors.
If that doesn't work, use ``set fish_term24bit 0``.
-``set_color --background=COLOR`` no longer implicitly activates bold mode.
To mitigate this change on existing installations that use a default theme, update your theme with ``fish_config theme choose`` or ``fish_config theme save``.
Scripting improvements
----------------------
-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
------------------------
-Autosuggestions are now also provided in multi-line command lines. Like `ctrl-r`, autosuggestions operate only on the current line.
-Autosuggestions used to not suggest multi-line commandlines from history; now autosuggestions include individual lines from multi-line command lines.
-The history search now preserves ordering between :kbd:`ctrl-s` forward and :kbd:`ctrl-r` backward searches.
-Left mouse click (as requested by `click_events <terminal-compatibility.html#click-events>`__) can now select pager items (:issue:`10932`).
- Instead of flashing all the text to the left of the cursor, fish now flashes the matched token during history token search, the completed token during completion (:issue:`11050`), the autosuggestion when deleting it, and the full command line in all other cases.
- Pasted commands are now stripped of any ``$`` prefix.
- The :kbd:`alt-s` binding will now also use ``run0`` if available.
-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`,:kbd:`alt-delete` no longer operate on punctuation-delimited words but on whole arguments, possibly including special characters like ``/`` and quoted spaces.
- 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, same as in the browser.
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 OSC 133 prompt marking feature has learned about kitty's ``click_events=1`` flag, which allows moving fish's cursor by clicking.
-:kbd:`ctrl-l` now pushes all text located above the prompt to the terminal's scrollback, before clearing and redrawing the screen (via a new special input function ``scrollback-push``).
For compatibility with terminals that do not provide the scroll-forward command,
this is only enabled by default if the terminal advertises support for the ``indn`` capability via XTGETTCAP.
- Bindings using shift with non-ASCII letters (such as :kbd:`ctrl-shift-ä`) are now supported.
If there is any modifier other than shift, this is the recommended notation (as opposed to :kbd:`ctrl-Ä`).
- 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 a description when completing remotes.
-``systemctl`` completions no longer print escape codes if ``SYSTEMD_COLORS``is set (:issue:`11465`).
-``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 in `fish_color_*` variables and :doc:`set_color <cmds/set_color>` (:issue:`10957`).
- 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 `Terminal Compatibility <terminal-compatibility.html>`_ (also accessible via ``man fish-terminal-compatibility``) lists required and optional terminal control sequences used by fish.
- 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
------------------
-``fish_indent`` and ``fish_key_reader`` are now available as builtins, and if fish is called with that name it will act like the given tool (as a multi-call binary).
This allows truly distributing fish as a single file. (:issue:`10876`)
-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
----------------
-``fish_indent`` and ``fish_key_reader`` are still built as separate binaries for now, but can also be replaced with a symlink if you want to save disk space (:issue:`10876`).
- The CMake system was simplified and no longer second-guesses rustup. It will run rustc and cargo via $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`).
-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`).
--------------
@@ -100,7 +334,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`).
- 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`.
@@ -303,7 +537,7 @@ 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:
@@ -315,7 +549,7 @@ 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`).
@@ -374,7 +608,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`).
@@ -689,7 +923,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
@@ -1114,7 +1348,7 @@ Scripting improvements
two
'blue '
-``$fish_user_paths`` is now automatically deduplicated to fix a common user error of appending to it in config.fish when it is universal (:issue:`8117`). :ref:`fish_add_path <cmd-fish_add_path>` remains the recommended way to add to $PATH.
-``$fish_user_paths`` is now automatically deduplicated to fix a common user error of appending to it in config.fish when it is universal (:issue:`8117`). :doc:`fish_add_path <cmds/fish_add_path>` remains the recommended way to add to $PATH.
-``return`` can now be used outside functions. In scripts, it does the same thing as ``exit``. In interactive mode,it sets ``$status`` without exiting (:issue:`8148`).
- An oversight prevented all syntax checks from running on commands given to ``fish -c`` (:issue:`8171`). This includes checks such as ``exec`` not being allowed in a pipeline, and ``$$`` not being a valid variable. Generally, another error was generated anyway.
-``fish_indent`` now correctly reformats tokens that end with a backslash followed by a newline (:issue:`8197`).
Use ``cargo fmt`` and ``cargo clippy``. Clippy warnings can be turned off if there's a good reason to.
We support at least the version of ``rustc`` available in Debian Stable.
Testing
=======
@@ -189,105 +181,65 @@ You are strongly encouraged to add tests when changing the functionality
of fish, especially if you are fixing a bug to help ensure there are no
regressions in the future (i.e., we don’t reintroduce the bug).
The tests can be found in three places:
Unit tests live next to the implementation in Rust source files, in inline submodules (``mod tests {}``).
- src/tests for unit tests.
- tests/checks for script tests, run by `littlecheck <https://github.com/ridiculousfish/littlecheck>`__
- tests/pexpects for interactive tests using `pexpect <https://pexpect.readthedocs.io/en/stable/>`__
System tests live in ``tests/``:
When in doubt, the bulk of the tests should be added as a littlecheck test in tests/checks, as they are the easiest to modify and run, and much faster and more dependable than pexpect tests. The syntax is fairly self-explanatory. It's a fish script with the expected output in ``# CHECK:`` or ``# CHECKERR:`` (for stderr) comments.
If your littlecheck test has a specific dependency, use ``# REQUIRE: ...`` with a posix sh script.
-``tests/checks`` are run by `littlecheck <https://github.com/ridiculousfish/littlecheck>`__
and test noninteractive (script) behavior,
except for ``tests/checks/tmux-*`` which test interactive scenarios.
-``tests/pexpects`` tests interactive scenarios using `pexpect <https://pexpect.readthedocs.io/en/stable/>`__
The pexpects are written in python and can simulate input and output to/from a terminal, so they are needed for anything that needs actual interactivity. The runner is in tests/pexpect_helper.py, in case you need to modify something there.
When in doubt, the bulk of the tests should be added as a littlecheck test in tests/checks, as they are the easiest to modify and run, and much faster and more dependable than pexpect tests.
The syntax is fairly self-explanatory.
It's a fish script with the expected output in ``# CHECK:`` or ``# CHECKERR:`` (for stderr) comments.
If your littlecheck test has a specific dependency, use ``# REQUIRE: ...`` with a POSIX sh script.
These tests can be run via the tests/test_driver.py python script, which will set up the environment.
The pexpect tests are written in Python and can simulate input and output to/from a terminal, so they are needed for anything that needs actual interactivity.
The runner is in tests/pexpect_helper.py, in case you need to modify something there.
These tests can be run via the tests/test_driver.py Python script, which will set up the environment.
It sets up a temporary $HOME and also uses it as the current directory, so you do not need to create a temporary directory in them.
If you need a command to do something weird to test something, maybe add it to the ``fish_test_helper`` binary (in tests/fish_test_helper.c), or see if it can already do it.
If you need a command to do something weird to test something, maybe add it to the ``fish_test_helper`` binary (in ``tests/fish_test_helper.c``).
Local testing
-------------
The tests can be run on your local computer on all operating systems.
The tests can be run on your local system::
::
cmake path/to/fish-shell
make fish_run_tests
Or you can run them on a fish, without involving cmake::
cargo build
cargo test # for the unit tests
tests/test_driver.py target/debug # for the script and interactive tests
to update the binary ``mo`` used by fish. Check the information for adding new languages for a
description on how you can get fish to use these files.
Running this script requires a fish executable and the gettext ``msgfmt`` tool.
After recompiling fish, you should be able to see your translations in action. See the previous
section for details.
Editing PO files
----------------
@@ -333,20 +295,20 @@ Editing PO files
Many tools are available for editing translation files, including
command-line and graphical user interface programs. For simple use, you can use your text editor.
Open up the po file, for example ``po/sv.po``, and you'll see something like::
Open up the PO file, for example ``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.
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.
@@ -359,7 +321,7 @@ Modifications to strings in source files
----------------------------------------
If a string changes in the sources, the old translations will no longer work.
They will be preserved in the ``po`` files, but commented-out (starting with ``#~``).
They will be preserved in the PO files, but commented-out (starting with ``#~``).
If you add/remove/change a translatable strings in a source file,
run ``build_tools/update_translations.fish`` to propagate this to all translation files (``po/*.po``).
This is only relevant for developers modifying the source files of fish or fish scripts.
@@ -373,7 +335,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.
@@ -382,20 +344,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.
``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
@@ -113,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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -142,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 ..
@@ -164,36 +161,44 @@ In addition to the normal CMake build options (like ``CMAKE_INSTALL_PREFIX``), f
- 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).
- 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 with embedded data (experimental)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Building fish with Cargo
~~~~~~~~~~~~~~~~~~~~~~~~
You can also build fish with the data files embedded.
You can also build fish with Cargo.
This example uses `uv <https://github.com/astral-sh/uv>`__ to install Sphinx (which is used for man-pages and ``--help`` options).
You can also install Sphinx another way and drop the ``uv run --no-managed-python`` prefix.
This will include all the datafiles like the included functions or web configuration tool in the main ``fish`` binary.
..code::shell
Fish will then read these right from its own binary, and print them out when needed. Some files, like the webconfig tool and the manpage completion generator, will be extracted to a temporary directory on-demand. You can list the files with ``status list-files`` and print one with ``status get-file path/to/file`` (e.g. ``status get-file functions/fish_prompt.fish`` to get the default prompt).
cargo install --path /path/to/fish # if you have a git clone
cargo install --git https://github.com/fish-shell/fish-shell --tag 4.0.0 # to build from git with a specific version
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-data`` 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.
- 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}``.
``_`` translates its arguments into the current language, if possible.
It is equivalent to ``gettext fish STRING``, meaning it can only be used to look up fish's own translations.
This only works with messages which are translated as part of fish's own sources, so using it as part of your own fish scripts which are not upstreamed into the fish repo will not work unless the exact same message also exists upstream.
It requires fish to be built with gettext support. If that support is disabled, or there is no translation it will echo the argument back.
It requires fish to be built with gettext support. If that support is disabled or there is no translation it will echo the argument back.
The language depends on the current locale, set with :envvar:`LANG` and:envvar:`LC_MESSAGES`.
The language depends on the current locale, set with :envvar:`LANG`,:envvar:`LC_MESSAGES`, :envvar:`LC_ALL`, and :envvar:`LANGUAGE`.
These variables do not have to be exported for fish to use them, and fish's variable scopes are supported.
If other programs launched via fish should respect these locale variables they have to be exported to make them available outside of fish.
For :envvar:`LANGUAGE` you can use a list, or use colons to separate multiple languages.
Options
-------
@@ -30,7 +31,20 @@ Options
Examples
--------
::
Use German translations::
> _ File
> set LANG de_DE.UTF-8
> _ file
Datei
Specify a precedence of languages (only works with :envvar:`LANGUAGE`)::
> set LANGUAGE pt de
> _ file # This message has a Portuguese translation.
arquivo
> _ "Invalid arguments" # This message does not have a Portuguese translation, but a German one.
Ungültige Argumente
> _ untranslatable # No translation in Portuguese, nor in German.
untranslatable
Note that the specific examples may change if translations are added/modified.
This command makes it easy for fish scripts and functions to handle arguments. You pass arguments that define the known options, followed by a literal **--**, then the arguments to be parsed (which might also include a literal **--**). ``argparse`` then sets variables to indicate the passed options with their values, and sets ``$argv`` to the remaining arguments. See the :ref:`usage <cmd-argparse-usage>` section below.
This command makes it easy for fish scripts and functions to handle arguments. You pass arguments that define the known options, followed by a literal **--**, then the arguments to be parsed (which might also include a literal **--**). ``argparse`` then sets variables to indicate the passed options with their values, sets ``$argv_opts`` to the options and their values, and sets ``$argv`` to the remaining arguments. See the :ref:`usage <cmd-argparse-usage>` section below.
Each option specification (``OPTION_SPEC``) is written in the :ref:`domain specific language <cmd-argparse-option-specification>` described below. All OPTION_SPECs must appear after any argparse flags and before the ``--`` that separates them from the arguments to be parsed.
@@ -27,8 +25,8 @@ Options
The following ``argparse`` options are available. They must appear before all *OPTION_SPEC*\ s:
**-n** or **--name**
The command name for use in error messages. By default the current function name will be used, or ``argparse`` if run outside of a function.
**-n** or **--name***NAME*
Use *NAME* in error messages. By default the current function name will be used, or ``argparse`` if run outside of a function.
**-x** or **--exclusive***OPTIONS*
A comma separated list of options that are mutually exclusive. You can use this more than once to define multiple sets of mutually exclusive options.
@@ -40,8 +38,44 @@ The following ``argparse`` options are available. They must appear before all *O
**-X** or **--max-args***NUMBER*
The maximum number of acceptable non-option arguments. The default is infinity.
**-u** or **--move-unknown**
Allow unknown options, and move them from ``$argv`` to ``$argv_opts``. By default, Unknown options are treated as if they take optional arguments (i.e. have option spec ``=?``).
The above means that if a group of short options contains an unknown short option *followed* by a known short option, the known short option is
treated as an argument to the unknown one (e.g. ``--move-unknown h -- -oh`` will treat ``h`` as the argument to ``-o``, and so ``_flag_h`` will *not* be set).
In contrast, if the known option comes first (and does not take any arguments), the known option will be recognised (e.g. ``argparse --move-unknown h -- -ho``*will* set ``$_flag_h`` to ``-h``)
**-i** or **--ignore-unknown**
Ignores unknown options, keeping them and their arguments in $argv instead.
Deprecated. This is like **--move-unknown**, except that unknown options and their arguments are kept in ``$argv`` and not moved to ``$argv_opts``. Unlike **--move-unknown**, this option makes it impossible to distinguish between an unknown option and non-option argument that starts with a ``-`` (since any ``--`` seperator in ``$argv`` will be removed).
**-S** or **--strict-longopts**
This makes the parsing of long options more strict. In particular, *without* this flag, if ``long`` is a known long option flag, ``--long`` and ``--long=<value>`` can be abbreviated as:
-``-long`` and ``-long=<value>``, but *only* if there is no short flag ``l``.
-``--lo`` and ``--lo=<value>``, but *only* if there is no other long flag that starts with ``lo``. Similarly with any other non-empty prefix of ``long``.
-``-lo`` and ``-lo=<value>`` (i.e. combining the above two).
With the ``--strict-longopts`` flag, the above three are parse errors: one must use the syntax ``--long`` or ``--long=<value>`` to use a long option called ``long``.
This flag has no effect on the parsing of unknown options (which are parsed as if this flag is on).
This option may be on all the time in the future, so do not rely on the behaviour without it.
**--unknown-arguments***KIND*
This option implies **--move-unknown**, unless **--ignore-unknown** is also given.
This will modify the parsing behaviour of unknown options depending on the value of *KIND*:
-**optional** (the default), allows each unknown option to take an optional argument (i.e. as if it had ``=?`` or ``=*`` in its option specification). For example, ``argparse --ignore-unknown --unknown-arguments=optional ab -- -u -a -ub`` will set ``_flag_a`` but *not*``_flag_b``, as the ``b`` is treated as an argument to the second use of ``-u``.
-**required** requires each unknown option to take an argument (i.e. as if it had ``=`` or ``=+`` in its option specification). If the above example was changed to use ``--unknown-arguments=required``, *neither*``_flag_a`` nor ``_flag_b`` would be set: the ``-a`` will be treated as an argument to the first use of ``-u``, and the ``b`` as an argument to the second.
-**none** forbids each unknown option from taking an argument (i.e. as if it had no ``=`` in its option specification). If the above example was changed to use ``--unknown-arguments=none``, *both*``_flag_a`` and ``_flag_b`` would be set, as neither use of ``-u`` will be passed as taking an argument.
Note that the above assumes that unknown long flags use the ``--`` "GNU-style" (e.g. if *KIND* is ``none``, and there is no ``bar`` long option, ``-bar`` is interpreted as three short flags, ``b``, ``a``, and ``r``; but if ``bar`` is known, ``-bar`` is treated the same as ``--bar``).
When using ``--unknown-arguments=required``, you will get an error if the provided arguments end in an unknown option, since it has no argument. Similarly, with ``--unknown-arguments=none``, you will get an error if you use the ``--flag=value`` syntax and ``flag`` is an unknown option.
**-s** or **--stop-nonopt**
Causes scanning the arguments to stop as soon as the first non-option argument is seen. Among other things, this is useful to implement subcommands that have their own options.
@@ -91,7 +125,7 @@ But this is not::
set -l argv
argparse 'h/help' 'n/name' $argv
The first ``--`` seen is what allows the ``argparse`` command to reliably separate the option specifications and options to ``argparse`` itself (like ``--ignore-unknown``) from the command arguments, so it is required.
The first ``--`` seen is what allows the ``argparse`` command to reliably separate the option specifications and options to ``argparse`` itself (like ``--move-unknown``) from the command arguments, so it is required.
.._cmd-argparse-option-specification:
@@ -100,9 +134,13 @@ Option Specifications
Each option specification consists of:
- An optional alphanumeric short flag character, followed by a ``/`` if the short flag can be used by someone invoking your command or, for backwards compatibility, a ``-`` if it should not be exposed as a valid short flag (in which case it will also not be exposed as a flag variable).
- An optional alphanumeric short flag character.
- An optional long flag name, which if not present the short flag can be used, and if that is also not present, an error is reported
- An optional long flag name preceded by a ``/``. If neither a short flag nor long flag are present, an error is reported.
- If there is no short flag, and the long flag name is more than one character, the ``/`` can be omitted.
- For backwards compatibility, if there is a short and a long flag, a ``-`` can be used in place of the ``/``, if the short flag is not to be usable by users (in which case it will also not be exposed as a flag variable).
- Nothing if the flag is a boolean that takes no argument or is an integer flag, or
@@ -110,9 +148,15 @@ Each option specification consists of:
- **=?** if it takes an optional value and only the last instance of the flag is saved, or
- **=+** if it requires a value and each instance of the flag is saved.
- **=+** if it requires a value and each instance of the flag is saved, or
- Optionally a ``!`` followed by fish script to validate the value. Typically this will be a function to run. If the exit status is zero the value for the flag is valid. If non-zero the value is invalid. Any error messages should be written to stdout (not stderr). See the section on :ref:`Flag Value Validation <flag-value-validation>` for more information.
- **=\*** if it takes an optional value *and* each instance of the flag is saved, storing the empty string when the flag was not given a value.
- Optionally a ``&``, indicating that the option and any attached values are not to be saved in ``$argv`` or ``$argv_opts``. This does not affect the the ``_flag_`` variables.
- Nothing if the flag is a boolean that takes no argument, or
- ``!`` followed by fish script to validate the value. Typically this will be a function to run. If the exit status is zero the value for the flag is valid. If non-zero the value is invalid. Any error messages should be written to stdout (not stderr). See the section on :ref:`Flag Value Validation <flag-value-validation>` for more information.
See the :doc:`fish_opt <fish_opt>` command for a friendlier but more verbose way to create option specifications.
@@ -132,7 +176,7 @@ This does not read numbers given as ``+NNN``, only those that look like flags -
Note: Optional arguments
------------------------
An option defined with ``=?`` can take optional arguments. Optional arguments have to be *directly attached* to the option they belong to.
An option defined with ``=?`` or ``=*`` can take optional arguments. Optional arguments have to be *directly attached* to the option they belong to.
That means the argument will only be used for the option if you use it like::
@@ -199,16 +243,22 @@ Some *OPTION_SPEC* examples:
-``help`` means that only ``--help`` is valid. The flag is a boolean and can be used more than once. If it is used then ``_flag_help`` will be set as above. Also ``h-help`` (with an arbitrary short letter) for backwards compatibility.
-``help&`` is similar (it will *remove*``--help`` from ``$argv``), the difference is that ``--help``` will *not* placed in ``$argv_opts``.
-``longonly=`` is a flag ``--longonly`` that requires an option, there is no short flag or even short flag variable.
-``n/name=`` means that both ``-n`` and ``--name`` are valid. It requires a value and can be used at most once. If the flag is seen then ``_flag_n`` and ``_flag_name`` will be set with the single mandatory value associated with the flag.
-``n/name=?`` means that both ``-n`` and ``--name`` are valid. It accepts an optional value and can be used at most once. If the flag is seen then ``_flag_n`` and ``_flag_name`` will be set with the value associated with the flag if one was provided else it will be set with no values.
-``n/name=*`` is similar, but the flag can be used more than once. If the flag is seen then ``_flag_n`` and ``_flag_name`` will be set with the values associated with each occurence. Each value will be the value given to the option, or the empty string if no value was given.
-``name=+`` means that only ``--name`` is valid. It requires a value and can be used more than once. If the flag is seen then ``_flag_name`` will be set with the values associated with each occurrence.
-``x`` means that only ``-x`` is valid. It is a boolean that can be used more than once. If it is seen then ``_flag_x`` will be set as above.
-``/x`` is similar, but only ``--x`` is valid (instead of ``-x``).
-``x=``, ``x=?``, and ``x=+`` are similar to the n/name examples above but there is no long flag alternative to the short flag ``-x``.
-``#max`` (or ``#-max``) means that flags matching the regex "^--?\\d+$" are valid. When seen they are assigned to the variable ``_flag_max``. This allows any valid positive or negative integer to be specified by prefixing it with a single "-". Many commands support this idiom. For example ``head -3 /a/file`` to emit only the first three lines of /a/file.
@@ -217,7 +267,7 @@ Some *OPTION_SPEC* examples:
-``#longonly`` causes the last integer option to be stored in ``_flag_longonly``.
After parsing the arguments the ``argv`` variable is set with local scope to any values not already consumed during flag processing. If there are no unbound values the variable is set but ``count $argv`` will be zero.
After parsing the arguments the ``argv`` variable is set with local scope to any values not already consumed during flag processing. If there are no unbound values the variable is set but ``count $argv`` will be zero. Similarly, the ``argv_opts`` variable is set with local scope to the arguments that *were* consumed during flag processing. This allows forwarding ``$argv_opts`` to another command, together with additional arguments.
If an error occurs during argparse processing it will exit with a non-zero status and print error messages to stderr.
@@ -259,17 +309,41 @@ After this it figures out which variable it should operate on according to the `
and set $var $result
Limitations
-----------
An example of using ``$argv_opts`` to forward known options to another command, whilst adding new options::
One limitation with **--ignore-unknown** is that, if an unknown option is given in a group with known options, the entire group will be kept in $argv. ``argparse`` will not do any permutations here.
function my-head
# The following option is the only existing one to head that takes arguments
# (we will forward it verbatim).
set -l opt_spec n/lines=
# --qwords is a new option, but --bytes is an existing one which we will modify below
# --qwords allows specifying the size in multiples of 8 bytes
set -a argv_opts --bytes=(math -- $_flag_qwords \* 8 || return)
else if set -q _flag_bytes
# Allows using a 'q' suffix, e.g. --bytes=4q to mean 4*8 bytes.
if string match -qr 'q$' -- $_flag_bytes
set -a argv_opts --bytes=(math -- (string replace -r 'q$' '*8' -- $_flag_bytes) || return)
else
# Keep the users setting
set -a argv_opts --bytes=$_flag_bytes
end
For instance::
end
argparse --ignore-unknown h -- -ho
echo $_flag_h # is -h, because -h was given
echo $argv # is still -ho
if test (count $argv) -eq 0
# Default to heading /dev/kmsg (whereas head defaults to stdin)
set -l argv /dev/kmsg
end
This limitation may be lifted in future.
# Call the real head with our modified options and arguments.
head $argv_opts -- $argv
end
Additionally, it can only parse known options up to the first unknown option in the group - the unknown option could take options, so it isn't clear what any character after an unknown option means.
The argparse call above saves all the options we do *not* want to process in ``$argv_opts``. (The ``--qwords`` and ``--bytes`` options are *not* saved there as their option spec's end in a ``~``). The code then processes the ``--qwords`` and ``--bytess`` options using the the ``$_flag_OPTION`` variables, and puts the transformed options in ``$argv_opts`` (which already contains all the original options, *other* than ``--qwords`` and ``--bytes``).
Note that because the ``argparse`` call above uses ``--move-unknown`` and ``--unknown-arguments=none``, we only need to tell it the arguments to ``head`` that take a value. This allows the wrapper script to accurately work out the *non*-option arguments (i.e. ``$argv``, the filenames that ``head`` is to operate on). Using ``--unknown-arguments=optional`` and explicitly listing all the known options to ``head`` however would have the advantage that if ``head`` were to add new options, they could still be used with the wrapper script using the "stuck" form for arguments (e.g. ``-o<arg>``, or ``--opt=<arg>``).
Note that the ``--strict-longopts`` is required to be able to correctly pass short options, e.g. without it ``my-head -q --bytes 10q``, will actually parse the ``-q`` as shorthand for ``--qwords``.
@@ -183,8 +181,11 @@ The following special input functions are available:
``clear-screen``
clears the screen and redraws the prompt.
.._special-input-functions-scrollback-push:
``scrollback-push``
pushes earlier output to the terminal scrollback, positioning the prompt at the top.
This requires the terminal to implement the ECMA-48 :ref:`SCROLL UP <term-compat-indn>` command and :ref:`cursor position reporting <term-compat-cursor-position-report>`.
``break`` halts a currently running loop (*LOOP_CONSTRUCT*), such as a :doc:`for <for>` or :doc:`while <while>` loop. It is usually added inside of a conditional block such as an :doc:`if <if>` block.
There are no parameters for ``break``.
The**-h** or **--help** option displays help about using this command.
``continue`` skips the remainder of the current iteration of the current inner loop, such as a :doc:`for <for>` loop or a :doc:`while <while>` loop. It is usually added inside of a conditional block such as an :doc:`if <if>` statement or a :doc:`switch <switch>` statement.
The **-h** or **--help** option displays help about using this command.
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.