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 _").
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
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.
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
- 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
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.
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 --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.
--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.
My phone uses dotted underline to indicate errors; that seems nice, a bit
less aggressive than curly. Unfortunately dotted underlines are not as well
supported in terminal emulators; sometimes they are barely visible. So it's
unlikely that we want to use --underline=dotted for an important theme.
Add double and dashed too I guess, even though I don't have a concrete
use case..
This was added without a use case. Now there is a use case (#11084) that
needs it to include all tokens which the sister option "--tokens-expanded"
should not do. The inconsistency is probably not worth it, given that this
"--tokens-raw" use case can be served by a future "read -zal --tokenize-raw".
Commit 6fcb418ae3 (Enable 24-bit RGB colors by default, 2025-04-11)
invalidated some documentation about fallback colors; by default we prefer
RGB unless the user has explicitly set fish_term256=0.
Note that this made fallback colors much less useful, because they are only
active if the user sets fish_term256=0. Note that setting fish_term24bit=0
is *not* enough; in that case we use the 256 color palette (and assume that
it is a subset of the 24-bit colors).
We do have some themes that use fallback colors:
fish_pager_color_description B3A06D yellow
By default, those will be less useful now.
See also https://github.com/fish-shell/fish-shell/issues/11393
Add a new underline-color option to set_color (instead of adding an optional
color argument to --underline); this allows to set the underline color
independently of underline style (line, curly, etc.). I don't think this
flexibility is very important but this approach is probably the least hacky.
Note that there are two variants:
1. \e[58:5:1m
2. \e[58;5;1m
Variant 1 breaks:
breakage from colon-variant for colored underlines
- cool-retro-term makes text blink
- GNU screen (goes into bold mode)
- terminology (goes into bold mode)
Variant 2 would break:
- mintty (Cygwin terminal) -- it enables bold font instead.
- Windows Terminal (where it paints the foreground yellow)
- JetBrains terminals echo the colons instead of consuming them
- putty
- GNU screen (goes into bold mode)
- st
- urxvt
- xterm
- etc.
So choose variant 1.
Closes#11388Closes#7619
set_color --underline=curly outputs \e[4:3m which breaks the following
terminals:
- Terminal.app interprets it as yellow background
- abduco and dvtm interpret it as green foreground
- JetBrains terminals interprets it as yellow background
- urxvt interprets it as yellow background
terminals that interpret curly as single underline:
- tmux [1]
- emacs ansi-term [2]
- emacs vterm
- GNU screen (also wrongly turns on italic mode)
- terminology (also wrongly turns on italic mode)
- Vim's :terminal
[1]: https://github.com/orgs/tmux/discussions/4477
[2]: https://lists.gnu.org/archive/html/bug-gnu-emacs/2025-04/msg01093.htmlCloses#10957