This regressed in 6f0532460a5~2..6f0532460a5 (fish_config: fix for
non-embedded builds, 2025-09-28).
Fixes#11903
(cherry picked from commit 15065255e9)
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
(cherry picked from commit 3fec9c8145)
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
(cherry picked from commit d835c5252a)
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).
(cherry picked from commit 6f0532460a)
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.
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.
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.
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)
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.
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)
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
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.
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
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.
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 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).
--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.
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.