Commit Graph

23019 Commits

Author SHA1 Message Date
Tristan Partin
4e8d2c706d fish_git_prompt: rename single-letter variables for clarity
Rename $r, $b, $c, $p, $f, and $rbc to $operation, $branch,
$bare_prefix, $upstream, $flags, and $branch_state respectively. The
short names were not very descriptive, and made it quite a bit harder to
understand what the code was doing.

Closes #12803
2026-06-18 15:15:29 +08:00
Michael Morgan
0066defac8 completions/cargo: remove nonexistent subcommand complete
This was never added to cargo, and the PR was closed without merging.
See <https://github.com/rust-lang/cargo/pull/9288>.

cargo is in the process of stabilizing a new completions feature:
`CARGO_COMPLETE=fish cargo +nightly`.

Closes #12800
2026-06-18 15:15:09 +08:00
Johannes Altmanninger
d1042ef032 wcsringutil trim(): remove allocation 2026-06-18 14:52:22 +08:00
cyphercodes
7012f8bea3 Fix nested brace space trimming
Delay restoring protected brace spaces until recursive brace
expansion is complete, so nested brace items can strip boundary
spaces consistently.

Fixes #12794.

Closes #12806
Closes #12813
2026-06-18 14:30:21 +08:00
Tunglies
6dc7d53439 lint(clippy): redundant_clone
Closes #12812
2026-06-18 14:09:43 +08:00
Daniel Rainer
0d7d06f357 ci: rename step to check
Match the name of the xtask it runs, which does more than just run
tests.

Closes #12818
2026-06-18 14:09:43 +08:00
Daniel Rainer
e99e60ec4d ci: remove redundant build step
`cargo xtask check` already takes care of building, so there is no point
in having a separate build step, especially because the build options
used by `cargo xtask check` will trigger a rebuild of most of our code
to handle extraction for localization.

Part of #12818
2026-06-18 14:09:43 +08:00
Johannes Altmanninger
c8d7476576 history: don't ignore re-added history items after vacuum
As root-caused in
https://github.com/fish-shell/fish-shell/issues/10300#issuecomment-4674848354,
we sometimes temporarily forget about history items:

Steps:

	1. start fish1
	2. fish1: run "echo remember me"
	3. start fish2
	4. fish1: run "echo something else"
	5. fish1: run "echo remember me"
	6. fish1: run up to VACUUM_FREQUENCY commands, until vacuum happens
	   (can watch ~/.config/fish/${fish_history:-fish}_history)
	7. fish2: run "echo reload"

Now fish2 can't recall "echo remember me" anymore.

This is because when re-running that command, fish1 updates the
command's history entry's "when" timestamp to something younger
than fish2.  When fish2 reloads the history, it ignores history
entries younger than itself (except for the entries created by itself).

Fix this by introducing a second timestamp called "added_when",
the immutable creation time.  Use this for determining the cutoff,
fixing the above scenario.

Keep the "when" key for forward compatibility.  Keep its semantics
(update it whenever we re-run a command; used for sorting); if we'd
instead let "when" be the creation time, then old fish will sort
wrongly commands that are run again in concurrent new fish. (If new
fish vacuums again, it will correct the ordering automatically.)

Alternatively, we could replace "added_when" with another
monotonically increasing number, maybe a integer sequence, with the
per-history next number stored on disk.  We only use it to compare
against the boundary timestamp in "offset_of_next_item_fish_2_0()"
and "rewrite_to_temporary_file()".  I haven't explored this yet because
"SystemTime" is easy and already used for "last added time".

Assisted-by: Theo Beers
Assisted-by: Daniel Rainer

Closes #10300
Closes #12817
2026-06-18 14:09:43 +08:00
Johannes Altmanninger
784c53eb32 Remove attempt to recover history files corrupted by fish 1.x
Simplifies the following commit.
2026-06-18 14:09:43 +08:00
Johannes Altmanninger
ed95a89e5d history: remove some allocations when merging valid paths 2026-06-18 14:09:43 +08:00
Johannes Altmanninger
c3853a9b18 history file: fix comment in offset decoding
This comment is incorrect because we don't read the entire item,
especially if no cutoff timestamp is given.
2026-06-18 14:09:43 +08:00
Johannes Altmanninger
2778ac1987 history: extract test function and add test
RawHistoryFile::offsets() looks at every history item, even though it
could probably stop early once the cutoff timestamp has been reached.
An upcoming change makes the cutoff logic independent of the order
within the file. This will render such a naive optimization incorrect.
Add a test to document this.

Part of #12817
2026-06-18 14:09:43 +08:00
Johannes Altmanninger
decf11c838 history file: inline a function 2026-06-18 14:09:43 +08:00
Daniel Rainer
8bcbc9497f l10n: port some more argparse messages to Fluent
Closes #11928
2026-06-18 14:09:43 +08:00
Daniel Rainer
ec129b94c7 l10n: port argparse message from gettext to Fluent
Make use of the new `Error::from_fluent_message` function.

This message in particular was chosen to demonstrate Fluent's ability to
use variables in arbitrary order. The suggestion in
https://github.com/fish-shell/fish-shell/pull/11833#issuecomment-3343835252
to allow reordering variables was one of the reasons for switching to a
more flexible localization system. `zh_CN.ftl` has been modified
accordingly. The effect can be seen with

```fish
for LC_MESSAGES in fr zh_CN zh_TW
    argparse h-
end
```

Part of #11928
2026-06-18 14:09:43 +08:00
Daniel Rainer
cbc6b24138 l10n: allow creating errors from Fluent messages
Part of #11928
2026-06-18 14:09:43 +08:00
Daniel Rainer
dfa14b90d6 l10n: add system tests for Fluent
Part of #11928
2026-06-18 14:09:43 +08:00
Daniel Rainer
88acc9cfda l10n: add first Fluent message
This migrates the fish version info message from gettext to Fluent. It
can be used to see Fluent-based localization in action.

Because this commit adds new FTL files, these languages show up in the
Fluent language precedence, requiring an update to the corresponding
tests.

Part of #11928
2026-06-18 14:09:43 +08:00
Daniel Rainer
8816960b87 l10n: add Fluent localization system
Add an implementation allowing to use Fluent for localization in Rust.

Fluent is significantly more expressive than gettext. It uses message
IDs which, unlike in gettext, are not necessarily the default message
string. This allows for proper support of messages which happen to be
identical in English, but not in other languages. In gettext, this could
be solved to some extent with contexts, but our gettext implementation
does not support that. In Fluent, arguments to the message are specified
as key-value pairs, which gives translators more semantic information
and allows reordering the arguments in the translation, which is
impossible with gettext. Fluent also allows for more complex grammatical
features, such as different plural forms, grammatical cases, and
adapting phrases to the correct gender.

This commit only introduces the infrastructure for using Fluent instead
of gettext, with the goal of eventually replacing gettext for
localization in Rust. Making use of the new infrastructure is left to
follow-up commits.

To localize a message with Fluent, the new `localize!` macro should be
used. Its arguments are key-value pairs. The first pair must consist of
two string literals. The key is a Fluent message ID and the value the
corresponding definition of the message in English. It must be valid
Fluent syntax for a message definition. The remaining key-value pairs
are used for Fluent variables which appear in the message definition.
Each key must match the name of a variable present in the message
definition, and the value is some Rust value which can be displayed by
Fluent. The variable in the Fluent message definition will be replaced
by that value. Example syntax:

```rust
localize!(
    "fish-version" = "{ $package_name }, version { $version }",
    package_name = "fish",
    version = crate::BUILD_VERSION,
)
````

If a message should be available in more than one place, define a
function containing the `localize!` macro and call that function from
the different locations needing access to the message, instead of
putting multiple `localize!` macros with the same message ID into the
code. The `localize_fn!` macro can help with that.

By having the message definition in the Rust sources, we have all the
relevant information for showing English messages in Rust, without
needing to rely on external sources. However, the Fluent library expects
data for all languages in the FTL format, so we have tooling to
automatically generate `en.ftl` from the Rust sources. Having this file
is also useful for other Fluent tooling, as well as being able to track
modifications to messages, which we also have tooling for.

To add translations for a new language, translators can create a new FTL
file in the `localization/fluent` directory with the appropriate file
name. No additional setup is needed. Translations for an individual
message can be added by copying the message from `en.ftl` and adjusting
the definition for the respective language.

These FTL files are included via `rust-embed` and parsed on demand at
runtime, ensuring that only languages specified in the user's language
settings are considered, saving the effort or parsing unneeded files.
`en.ftl` is always parsed, as it implicitly is the last fallback
option, when no other language in the user's precedence list has a
translation for a message ID. We know that `en.ftl` contains a
translation for all message IDs we use because message IDs can only be
used by putting them into the `localize!` macro with a corresponding
English message definition, and `en.ftl` is auto-generated from these
definitions. This generation happens as a 2-step process: First, we
compile with the `fluent-extract` feature, with the
`FISH_FLUENT_EXTRACTION_DIR` environment variable set to point to an
empty directory. This will result in the `localize!` macro passing the
message ID, definition, and variable names specified in subsequent
key-value pairs, to a proc macro which performs some checks on the
provided data and writes the message definition in the FTL format to a
fresh file in `FISH_FLUENT_EXTRACTION_DIR`. This results in one file per
`localize!` macro invocation. In the second step, the data from all
these files is combined into a single file, `en.ftl`, which is
automatically formatted. Before overwriting the old `en.ftl`, checks are
performed to look for changes to message definitions. If any change is
detected, translations of the message might have to be updated.
Some changes, like removal of a message, can be handled automatically,
by deleting all translations. For changes which cannot be handled fully
automatically, the affected translations are marked with an annotation,
which causes our checks to fail while it is present. It is the
responsibility of the developer who changed the message definition to
handle updates to its translations. This can be done manually, by
editing the affected translations and removing the annotation, which
should be the preferred option when translations need to be modified and
the developer knows the language. Otherwise, there is automation in the
form of `cargo xtask fluent resolve-outdated`, which allows specifying
what should happen to some or all translations of a message, with the
available option being:
- delete the translation, used when the meaning of the English message
  changed so much that keeping the old translations would be misleading
- delete the annotation, used when changes to the English message have
  no impact on translations, e.g. for typo fixes
- change the annotation to indicate that translator review is desired,
  used when the meaning or wording of the English message changed
  slightly, but not enough to invalidate the translations

There are several tools available as subcommands of `cargo xtask
fluent`:
- `check`: Checks the FTL files, ensuring that they can be parsed
  without errors, that no duplicate IDs are specified, that they are
  formatted correctly, and that there are no extra IDs, i.e. IDs not
  present in `en.ftl`, which is expected to be complete. More rigorous
  checks could be added, such as checking whether the same set of
  variables are used for a certain ID in all languages. The complexity
  of Fluent's syntax makes this non-trivial, which is the reason it's
  not already implemented.
- `format`: Formats the specified FTL files (or all by default). Also
  has a mode suitable for editor integration to format files from the
  editor. Examples for setting that up in Vim are provided in the
  `CONTRIBUTING.rst` docs.
- `rename`: Renames IDs or associated variables across all FTL files.
- `resolve-outdated`: Described above.
- `show-missing`: Shows which IDs don't have a translation yet.
- `update`: Runs the generation pipeline for `en.ftl` and potential
  translation updates/annotations.

There is one additional tool, which is designed to help with porting
existing messages localized via gettext to the new Fluent
implementation. This is intentionally not added to fish, because it
is only useful for the transition. Once we have ported all messages to
Fluent we won't have a use for it anymore. If you are interested in
using it to port messages, it's the `po-convert` binary in the
`fluent-ftl-tools` package. The CLI is somewhat convoluted, but can be
simplified by wrapping it with a script which hard-codes the path to the
relevant PO and FTL file directories. Then, the remaining information
which needs to be specified is:
- a line number in a PO file to identify the message to be ported
- the new message ID
- the name of each variable, in the order the formatting specifiers
  appear in the gettext msgid.
Specifying the line number and invoking the wrapper script can be
partially automated by using a custom editor shortcut.
The tool will port the msgstr for each language which has one defined,
and always generate and entry for `en.po` based on the msgid.
The tool does not edit Rust code, but suggests a Rust code snippet on
stdout based on the specified message ID and variable names.

Some of our tooling relies on features of the `fluent` package which
are not exported by default, so we use a fork which changes that until
our PR for adding it upstream is accepted.

Part of #11928
2026-06-18 14:09:43 +08:00
Johannes Altmanninger
3968025421 Don't try to download vermin during test execution
The "vermin" test fails when offline; fix that by adding "vermin"
to the virtulenv.
2026-06-18 14:09:43 +08:00
Johannes Altmanninger
1c7653cc70 Fix typo 2026-06-18 10:49:20 +08:00
Johannes Altmanninger
d50c12e142 Better-named and idiomatic return type for cmdsub parsing
Commit 2f6ed61833 (parse_util_cmdsubst_extent to return an exclusive
range, 2024-04-27) used the "Parentheses" naming in preparation for
raw quotes.  We still don't have them, so let's clean that up for now.
Also, reuse the Result and Option types.
2026-06-18 10:49:20 +08:00
Johannes Altmanninger
7f9e1a89d6 Unit-test completion inside brace expansion with separators
Remove an incorrect comment. Completion does work, in a limited set
of cases.
2026-06-18 10:49:20 +08:00
Johannes Altmanninger
28ef1b33ac Update changelog 2026-06-18 10:49:20 +08:00
Johannes Altmanninger
b6447722bf tempfile: warn when temp file/dir is dropped without use 2026-06-18 10:33:51 +08:00
visrosa
7ee171949f completions/emerge: update against portage 3.0.79
Add missing options, descriptions, y/n completions, and correct short
flags throughout. Drop --changelog (removed from portage). Fix several
wrong option names in stubs (--ignore-built-slot-operator-deps,
--rebuilt-binaries, --sync-submodule, etc.). Use -xa for mandatory
boolean args and -a for optional ones.

Closes #12810
2026-06-18 10:33:51 +08:00
Johannes Altmanninger
ae299a27e7 Disable OSC 133 integration for Konsole specifically
When a command fails, Konsole draws a fat red line on the left edge
of the command output. Sadly the line overlaps with command output.
Since I'm not sure how important the rest of Konsole's semantic
integration is, let's disable it.
https://github.com/fish-shell/fish-shell/issues/11409
https://bugs.kde.org/show_bug.cgi?id=503125
2026-06-18 10:33:51 +08:00
Peter Ammon
8768b458a6 Correct user/sys time printing
These were swapped.
2026-06-13 12:41:38 -07:00
Mark Otzen
452651f79a Remove extraneous dash in path basename description 2026-06-13 12:40:44 -07:00
Peter Ammon
077d58d0d8 Changelog fix for #12700 2026-06-11 22:48:53 -07:00
Peter Ammon
d13ab22a27 Cleanup and add tests for cd builtin
Add a test for the following behavior: if we try to `cd` to a directory,
and it fails, and so we call realpath and discover that our $PWD is stale,
and correct it and then try to `cd` again, and it STILL fails, then:

1. We report the error for the second (better) failure.
2. $PWD is not modified.
2026-06-11 22:48:52 -07:00
Peter Ammon
119bb872d8 Miscellaneous cleanup of the cd builtin
Add some missing comments and make some C++-isms more Rust-friendly.
No user-visible behavior changes expected.
2026-06-11 22:46:25 -07:00
Vishrut Sachan
411a43254b env: fix stale $PWD after mv $PWD elsewhere
Fixes #12700
2026-06-11 21:17:44 -07:00
Johannes Altmanninger
de0e519b22 test unreadable-config-paths: skip on windows
See 17ef326c8f.
2026-06-10 00:44:54 +09:00
Johannes Altmanninger
6d0cd3d9b5 Merge changes to config paths 2026-06-09 22:31:14 +09:00
Johannes Altmanninger
9303e64708 env_init: remove unused argument 2026-06-09 22:31:14 +09:00
Johannes Altmanninger
74ff7d2c6c Make internal path variables read-only
It does not make sense to change these.

If anything, we should make them computed electric variable, so they
change whenever one of $HOME, $XDG_CONFIG_HOME and friends change.

Make them electric variables, purely because that's our only
way of marking variables as read-only.  In future we can add a
EnvVarFlags::READ_ONLY instead.  We'll want this anyway for "set
--read-only".
2026-06-09 22:31:14 +09:00
Johannes Altmanninger
654041895b Stop using universal __fish_initialized to detect first launch
As of 7640e95bd7 (Create user config file/directories only on
first startup again, 2025-12-29) we interpret absence of the
__fish_initialized variable as "this is the first run, so create
~/.config/fish/conf.d etc.".

As reported in #11226, the presence of this universal variable causes
friction to users who track ~/.config/fish/fish_variables in version
control.

Also, __fish_initialized is the only universal variable we create
by default.

Use another way to detect the first run: since we already create
~/.config/fish on every run, assume that a successful mkdir() means
we should also create the subdirectories.

This has false negatives (if the user already created the directory)
and false positives (if the user doesn't want ~/.config/fish to exist)
but at least the latter should not really matter because historically
we always created it, at least for ~/.config/fish/fish_variables.

Alternatively, we could create a file at ~/.cache/fish/first-run-done.
But let's not add more state unless there's a good reason.
2026-06-09 22:31:14 +09:00
Johannes Altmanninger
511006833c config.fish template: add back indentation
Fixes 3e7c5ae399 (__fish_config_interactive: make config file
initialization independent of uvars, 2025-11-24).
2026-06-09 22:31:14 +09:00
Johannes Altmanninger
a79ca0cb29 Create ~/.config/fish/{completions,conf.d,functions} with mode 700
Same as ~/config/fish and other directories we create.
2026-06-09 22:31:14 +09:00
Johannes Altmanninger
041f601050 make_base_directory: remove dead optimization code
path is never empty. Remove the check. Simplify the remaining code.
2026-06-09 22:31:14 +09:00
Johannes Altmanninger
59135087d7 make_base_directory: remove unused function path_get_config_remoteness
I think the remoteness check is handled by fish::fs::LockedFile
nowadays.
2026-06-09 22:31:14 +09:00
Johannes Altmanninger
93f483467f make_base_directory: remove extra trailing slash from statfs argument
This was added in d1fd3d5825 (Detect at startup whether config and
data paths are remote, 2021-05-08); I don't understand why
this would be necessary. On my system, statfs("/tmp") and
statfs("/tmp/") both yields f_type=TMPFS_MAGIC.
2026-06-09 22:31:14 +09:00
Johannes Altmanninger
a66a7b2b30 fs: correct path formatting in an error message
Convert to WString which uses our PUA escaping trick.
2026-06-09 22:31:14 +09:00
Johannes Altmanninger
45765f4e00 env_init: minor refactoring for initializating user path vars 2026-06-09 22:31:14 +09:00
Johannes Altmanninger
f525b8a7b6 Merge misc fixes 2026-06-09 22:24:07 +09:00
Johannes Altmanninger
c075982f4a env: electric variables to hold their computation-function directly
In addition to the entry in ELECTRIC_VARIABLES, each computed electric
variable has a piece of code in "try_get_computed()".  Makes more
sense to store this directly in the electric variable itself, no?

use consts for the getter functions, so we can reuse the type.
This is a bit weird..
2026-06-09 22:24:07 +09:00
Johannes Altmanninger
8585def79d Merge key decoding fixes 2026-06-09 22:24:07 +09:00
Johannes Altmanninger
bb6774bef8 CHANGELOG improvements 2026-06-09 22:24:07 +09:00
Johannes Altmanninger
66ac8d3e11 electric vars: no general-purpose $history var on background threads
try_get_computed() returns None if the variable is not computed.

That's the case for "$history" on (future) background threads.

This is a weird edge case, because we don't ever return None for any
other electric variable.  This will become especially apparent when
an upcoming commit adds the computing-function to ElectricVar.

Given that the main thread already can't use "$history" from being
used as general purpose variable, there seems to be little harm in
banning it for all of them.
2026-06-09 22:24:07 +09:00