Commit Graph

175 Commits

Author SHA1 Message Date
Johannes Altmanninger
a31768bf9e history: remove code for migrating from ~/.config/fish/fish_history
Commit 2971887bbd (Access fish_history from $XDG_DATA_HOME, 2015-09-16)
changed the history file path to ~/.local/share/fish/fish_history.

Migration is done by commit b13f0701a4 (Migrate fish_history from
config to data dir, 2015-09-18).

This should no longer be needed in practice. Remove it.

FWIW, we used a similar-length grace period (10 years) when dropping
support for history file format version 1 in 77aeb6a2a8 (Port
execution, 2023-10-08).
2026-06-09 22:24:07 +09:00
Johannes Altmanninger
a98000cb36 Add all terminal commands to reader log 2026-06-09 22:24:07 +09:00
Johannes Altmanninger
86f92cb1a2 Remove crate-wide suppression of non_camel_case_types lint 2026-06-09 22:24:07 +09:00
Johannes Altmanninger
f2e2c622bb input/input_common: reorganize modules
While at it, rename "input mapping" to "binding", to be consistent
with builtin bind. The "input" bit is already implied by the module
hierarchy.

Also, merge definitions of "enum ReadlineCmd" and
"INPUT_FUNCTION_METADATA" using a macro.

Review with

	git show --color-moved=zebra --color-moved-ws=allow-indentation-change
2026-06-09 22:24:07 +09:00
Johannes Altmanninger
a580d82407 Stop exposing internal module names when we can use re-exports
Types like Environment are sometimes imported using their FQN and
sometimes via their re-export in the parent module; it seems better
to have one canonical name. I think we usually use the re-exports
already, so use them always.

It't not as trivial to enforce this in child modules (such as "mod
tests" which) but that's not a big loss.

While at it, make some other consistency improvements to imports.
2026-06-09 22:24:07 +09:00
Johannes Altmanninger
336df7793a Comment about handing over input data to reader on init 2026-06-09 22:24:07 +09:00
Johannes Altmanninger
1284527fac Path component movement to skip all escaped characters
Extend the hack added in ebc140a3ea (Hack path component movement to
skip escaped spaces, 2025-12-16) to apply to all characters, such as
";" that may be part of a file name.
2026-05-18 16:18:52 +08:00
Johannes Altmanninger
1f18b9715f Fix repeated tab causing repeated smartcase completion insertion
Doing

	firefox --pro TAB TAB TAB

results in

	firefox --profile --ProfileManager

git-bisect points to 3546ffa3ef (reader
handle_completions(): remove dead filtering code, 2026-01-02)
but that regression has already been fixed by 85e76ba356
(Fix option substr completions not being filtered out, 2026-04-16).

However in between those two commits, the above case has also been
broken by 2f6b1eaaf9 (reader handle_completions(): don't consider
odd replacing completions for common prefix, 2026-01-02)

The first TAB inserts "--profile ", including the trailing space.
However it also shows the completion pager, which means that subsequent
TABs will insert after the space.

The trailing space does not make sense unless we navigate the pager.
Remove it in all cases, to fix this smartcase scenario.

Alternatively, we could start navigating the pager in this case
(and keep the trailing space), but that's probably too inconsistent.
2026-05-14 16:17:41 +08:00
Johannes Altmanninger
c003ec3795 vi mode: fix "x" command in builtin read
When we push a new reader for builtin read, we use the default
CursorSelectionMode::Exclusive, which is wrong in Vi mode.
Add a haphazard fix for that.
This is very ugly, we should improve this.

Closes #12724
2026-05-13 19:58:52 +08:00
Johannes Altmanninger
ef8e62727c Pass Parser by exclusive reference
As described in
https://github.com/fish-shell/fish-shell/pull/9990#discussion_r1382494440,
prior to 77aeb6a2a8 (Port execution, 2023-10-08), "Parser" was
passed by mutable reference ("parser_t&"), even though operation
context was passed as "const operation_context_t &".  This worked
because C++ doesn't propagate const to pointers by default (see
https://en.cppreference.com/cpp/experimental/propagate_const).

	class operation_context_t {
		std::shared_ptr<parser_t> parser;
		...
	};

So "*ctx->parser" was a "parser_t&", not "const parser_t&".

Rust has stricter const propagation rules which means that const
operation context can't simply hand out a non-const reference to parser.

To be able to port code without changing its structure,
77aeb6a2a8 passed "Parser" by shared reference, using interior
mutability (RefCell) to modify parser fields. This is a bit ugly
(c.f. https://doc.rust-lang.org/std/cell/index.html "interior mutability
is something of a last resort") and means that some borrowing conflicts
are not found at compile time but runtime.

Pass both parser and operation context by exclusive reference, and
remove the interior mutability wrappers from parser's fields.
Since "libdata" is no longer inside a "RefCell", add a "ScopedRefCell"
around "transient_commandline".

The downside is that "ScopeGuard" use can become more intrusive
when we pass "Parser" or "OperationContext" as context (especially
when we use "zelf" since we can't shadow "self"), see
* 2930466d53 (Introduce ScopedCell and ScopedRefCell, 2025-03-15)
* 29ae571afa (Make scoped_push nicer, 2024-12-28)
Avoid this in some cases, specifically when using "ScopedCell" or
"ScopedRefCell". Since "&mut Parser" prevents the "ScopeCell"'s
"ScopeGuard" from holding a shared reference, use an "Rc" to capture
a dynamically-checked reference to the Cell. We could also use raw
pointers instead.

Change "Completer::apply_var_assignments" to return  a block ID, to
avoid the need to return a "zelf" "ScopeGuard".  In future, we could
probably untangle completer and get away with returning a "ScopeGuard"
called "ctx".

Closes #12694
2026-05-11 10:41:14 +08:00
Johannes Altmanninger
638777a4de Remove unused ScopeGuarding trait
As of commit 0441bdc634 (Remove ScopeGuard::commit in favor of drop,
2026-04-30), this trait is empty so there's not much use having it
for now.
2026-05-11 10:41:14 +08:00
Johannes Altmanninger
4b069b51e7 Remove "get_" prefix from some getters
In C++ we can't have a field and method sharing a name,
but in Rust we can.

For some structs, most getters don't have a "get_", so it's weird
that some do.  Remove the "get_" prefix where it's obvious enough.

While at it, give some related getters better names.
2026-05-01 18:35:41 +08:00
Johannes Altmanninger
398fc17b81 reader: use simpler test environment constructor
A following commit wants to pass parser by exclusive reference,
which disallows passing "parser" as well as "parser.vars()"
in one function call.  This use case also doesn't make sense.
The "OperationContext::test_only_foreground" constructor is used to
inject a special "PwdEnvironment" into the context.  When we don't need
this environment, we can use a regular constructor, which already uses
"parser.vars()".
2026-05-01 18:03:13 +08:00
Johannes Altmanninger
12fa0d8b3d reader: make exec_prompt_cmd a free function
A following commit will pass parser as "&mut Parser".  This would
create aliasing issues in our calls to exec_prompt_cmd; make it a
free function so rustc can understand how the borrows are split.
2026-05-01 18:03:13 +08:00
Johannes Altmanninger
8328e53050 reader: reduce variable scope 2026-05-01 18:03:13 +08:00
Johannes Altmanninger
d2c2b23d1f Fix "fish -d reader" crash on left mouse click
See #12693
2026-05-01 18:00:37 +08:00
Johannes Altmanninger
281399561b Distinguish builtin read history session ID from private mode
Fixes #12662
2026-04-29 01:55:32 +08:00
Johannes Altmanninger
e5f57b1daf history: fix constructor naming
The only public constructor should be called new().
2026-04-29 01:55:32 +08:00
Johannes Altmanninger
81e8eebd8d Use UpperCamelCase for enum variants
Missed in 17ba602acf (Use PascalCase for Enums, 2025-12-14).

Fixes #12647
2026-04-28 23:11:33 +08:00
Johannes Altmanninger
f2b0706494 reader: repaint commands to not disable "last_cmd"-based UI states (pager etc.)
"commandline -f repaint" might be triggered for various reasons;
since this sets "last_cmd", it will reset some UI states, notably
pager selection:

1. press tab
2. trigger repaint
3. press tab

The repaint prevents us from selecting the first candidate.

Work around this by ignoring repaint events for the last_cmd logic.

Fixes #12683
2026-04-28 14:43:55 +08:00
Johannes Altmanninger
523e25df17 reader: fix improper use of get_or_init() 2026-04-23 19:12:40 +08:00
Johannes Altmanninger
c8b28d4d24 cargo-test: remove unnecessary TTY initialization 2026-04-23 19:12:40 +08:00
Johannes Altmanninger
1dfc75bb9c Better name for async-signal-safe functions
In Rust, "safety" is usually used in the context of unsafe functions,
which have documented preconditions.  Our async-signal-safe functions
are different; they offer extra safety properties. Rename them to
reduce confusion.

Ref: https://github.com/fish-shell/fish-shell/pull/12625#discussion_r3067819966
2026-04-20 21:21:24 +08:00
Johannes Altmanninger
413246a93d reader handle_completions(): move loop-invariant code 2026-04-17 01:28:02 +08:00
Johannes Altmanninger
1286745e78 Remove bits for async-signal-safety of old SIGTERM handler
This is implied by the parent commit.

To enable this, stop trying to run cleanup in panic handlers if we
panic on a background thread.
2026-04-11 18:25:26 +08:00
Yakov Till
b99ae291d6 Save history on SIGTERM and SIGHUP before exit
Previously, SIGTERM immediately re-raised with SIG_DFL, killing
fish without saving history. SIGHUP deferred via a flag but never
re-raised, so the parent saw a normal exit instead of signal death.

Unify both signals: the handler stores the signal number in a single
AtomicI32, the reader loop exits normally, throwing_main() saves
history and re-raises with SIG_DFL so the parent sees WIFSIGNALED.

Fixes #10300

Closes #12615
2026-04-11 18:06:02 +08:00
Daniel Rainer
8ae71c80f4 refactor: extract string escape and unescape funcs
Move the functions for escaping and unescaping strings from
`src/common.rs` into `fish_common`. It might make sense to move them
into a dedicated crate at some point, but for now just move them to the
preexisting crate to unblock other extraction.

Closes #12625
2026-04-11 17:49:50 +08:00
Daniel Rainer
816077281d refactor: move encoding functions to widestring
The decoding functions for our widestrings are already in the
`fish_widestring` crate, so by symmetry, it makes sense to put the
encoding functions there as well. This also makes it easier to depend on
these functions, giving more options when it comes to further code
extraction.

Part of #12625
2026-04-11 17:49:47 +08:00
Daniel Rainer
78ea24a262 refactor: move char definitions into widestring
Use `fish_widestring` as the place where char definitions live. This has
the advantage that all our code can depend on `fish_widestring` without
introducing dependency cycles. Having a common place for character
definitions also makes it easier to see which chars have a special
meaning assigned to them.

This change also unblocks some follow-up refactoring by removing a
dependency cycle between `src/common.rs` and `src/wildcard.rs`.

Part of #12625
2026-04-11 17:49:46 +08:00
Daniel Rainer
b7b786aabf cleanup: move escape_string_with_quote
It makes a lot more sense to have this function in the same module as
the other escaping functions. There was no usage of this function in
`parse_util` except for the test, so it makes little sense to keep the
function there. Moving it also eliminates a pointless cyclic dependency
between `common` and `parse_util`.

Part of #12625
2026-04-11 17:49:43 +08:00
Daniel Rainer
9c819c020e refactor: don't reexport fish_common in common
Not reexporting means that imports have to change to directly import
from `fish_common`. This makes it easier to see which dependencies on
`src/common.rs` actually remain, which helps with identifying candidates
for extraction.

While at it, group some imports.

Part of #12625
2026-04-11 17:49:41 +08:00
Daniel Rainer
85311546de refactor: extract fish-feature-flags crate
Another step in splitting up the main library crate.

Note that this change requires removing the `#[cfg(test)]` annotations
around the `LOCAL_OVERRIDE_STACK` code, because otherwise the code would
be removed in test builds for other packages, making the `#[cfg(test)]`
functions unusable from other packages, and functions with such feature
gates in their body would have the code guarded by these gates removed
in test builds for tests in other packages.

Closes #12494
2026-04-07 17:49:57 +08:00
Daniel Rainer
65bc9b9e3e refactor: stop aliasing feature_test function
Having a public function named `test` is quite unspecific. Exporting it
both as `test` and `feature_test` results in inconsistent usage. Fix
this by renaming the function to `feature_test` and removing the alias.

Part of #12494
2026-04-07 17:49:57 +08:00
Johannes Altmanninger
01ee6f968d Support backward-word-end when cursor is past end
Closes #12581
2026-03-30 13:57:27 +08:00
Johannes Altmanninger
7f6dcde5e0 Fix backward-delete-char not stopping after control characters
Fixes 146384abc6 (Stop using wcwidth entirely, 2026-03-15)

Fixes #12583
2026-03-30 13:57:27 +08:00
Johannes Altmanninger
34fc573668 Modernize wcwidth API
Return None rather than -1 for nonprintables.  We probably still
differ from wcwidth which is bad (given we use the same name), but
hopefully not in a way that matters.

Fixes 146384abc6 (Stop using wcwidth entirely, 2026-03-15).
2026-03-30 13:57:10 +08:00
Johannes Altmanninger
dde33bab7e Clean up word-end special case handling in forward-word 2026-03-27 22:22:29 +08:00
Fabian Boehm
8561008513 Unconditionally default emoji width to 2
"Emoji width" refers to the width of emoji codepoints. Since Unicode
9, they're classified as "wide" according to
TR11 (https://www.unicode.org/reports/tr11/).

Unicode 9 was released in 2016, and this slowly percolated into C
libraries and terminals. Glibc updated its default in 2.26, released
in August 2017.

Until now, we'd guess support for unicode 9 by checking the system
wcwidth function for an emoji - if it returned 2, we'd set our emoji
width to 2 as well.

However, that's a problem in the common case of using ssh to connect
to an old server - modern desktop OS, old server LTS OS, boom.

So now we instead just figure you've got a system that's *displaying*
the emoji that has been updated in the last 9 years.

In effect we're putting the burden on those who run old RHEL et al as
their client OS. They need to set $fish_emoji_width to 1.

Fixes #12500

Part of #12562
2026-03-27 21:31:19 +08:00
Daan De Meyer
484032fa9e Support SHELL_PROMPT_PREFIX, SHELL_PROMPT_SUFFIX, and SHELL_WELCOME
Add support for the SHELL_PROMPT_PREFIX, SHELL_PROMPT_SUFFIX, and
SHELL_WELCOME environment variables as standardized by systemd v257.

SHELL_PROMPT_PREFIX and SHELL_PROMPT_SUFFIX are automatically prepended
and appended to the left prompt at the shell level, so all prompts
(default, custom, and sample) pick them up without modification.

SHELL_WELCOME is displayed after the greeting when an interactive shell
starts.

These variables provide a standard interface for tools like systemd's
run0 to communicate session context to the shell.

Fixes https://github.com/fish-shell/fish-shell/issues/10924

Closes #12570
2026-03-26 15:45:50 +08:00
Johannes Altmanninger
fdd10ba9b2 Fix forward-word regression on single-char words followed by punctuation
The `forward-word` readline command on "a-a-a" is wrong (jumps to
"a"); on "aa-aa-aa" it's right (jumps to "-"); that's a regression
from bbb2f0de8d (feat(vi-mode): make word movements vi-compliant,
2026-01-10).

The is_word_end check for ForwardWordEmacs only tests for blank
(whitespace) after the current char. In the Punctuation style, words
also end before punctuation.

Fix this.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

See https://github.com/fish-shell/fish-shell/issues/12543#issuecomment-4125223455
2026-03-26 15:31:00 +08:00
Johannes Altmanninger
b5c367f8bf Bounds check backward-word-end
While at it, narrow the bounds check for forward movements,
no need to check for impossible cases.

Fixes #12555
2026-03-25 17:36:21 +08:00
Nahor
6e8c32eb12 Remove the Default trait for text face/styling
The notion of default is context dependent: there is the default for
the state (default color, non-bold, no underline, ...) and the default
for a change (no color change, no underline change, ...).

Currently, using a single default works because either the style
attributes cannot be turned off individually (the user is expected
to reset to default then re-set necessary attributes), or the code
has special handling for specific scenarios (e.g. highlighting).

So in preparation for later commits, where attribute can be turned off
individually, make the two defaults explicit.

Part of #12507
2026-03-13 14:06:21 +08:00
Daniel Rainer
0223edc639 cleanup: use nix version of getpid
Alternatively, we could also use `nix::unistd::Pid::this()`.

Part of #12502
2026-03-09 16:52:08 +11:00
Daniel Rainer
7992fda9fe refactor: extract perror
Part of #12502
2026-03-09 16:52:08 +11:00
Daniel Rainer
bf5fa4f681 feat: implement perror_nix
Similar to `perror_io`, we don't need to make a libc call for `nix`
results, since the error variant contains the errno, from which a static
mapping to an error message exists. Avoid using `perror` and instead use
`perror_io` or `perror_nix` as appropriate where possible.

The `perror_io` and `perror_nix` functions could be combined by
implementing `fish_printf::ToArg` for `nix::errno::Errno`, but such a
function would violate type safety, as it would allow passing any
formattable argument, not necessarily limited to functions with a `%s`
formatting.

Part of #12502
2026-03-09 16:52:08 +11:00
Daniel Rainer
c0bb0d6584 refactor: extract write_to_fd into util crate
Part of #12502
2026-03-09 16:52:07 +11:00
Daniel Rainer
c5e4fed021 format: use 4-space indents in more files
Change some files which have lines whose indentation is not a multiple
of the 4 spaces specified in the editorconfig file.

Some of these changes are fixes or clear improvements (e.g. in Rust
macros which rustfmt can't format properly). Other changes don't clearly
improve the code style, and in some cases it might actually get worse.

The goal is to eventually be able to use our editorconfig for automated
style checks, but there are a lot of cases where conforming to the
limited editorconfig style spec does not make sense, so I'm not sure how
useful such automated checks can be.

Closes #12408
2026-03-09 16:52:07 +11:00
Daniel Rainer
1df7a8ba29 cleanup: remove obsolete ellipsis complexity
Previously, we chose the ellipsis character/string based on the locale.
We now assume a UTF-8 locale, and accordingly always use the Unicode
HORIZONTAL ELLIPSIS U+2026 `…`. When this was changed, some of the logic
for handling different ellipsis values was left behind. It no longer
serves a purpose, so remove it.

The functions returning constants are replaced by constants. Since the
ellipsis as a `wstr` is only used in a single file, make it a local
const there and define it via the `ELLIPSIS_CHAR` const.

Put the `ELLIPSIS_CHAR` definition into `fish-widestring`, removing the
dependency of `fish-wcstringutil` on `fish-common`, helping future
extraction efforts.

One localized message contains an ellipsis, which was inserted via a
placeholder, preventing translators from localizing it. Since the
ellipsis is a constant, put it directly into the localized string.

Closes #12493
2026-03-03 15:14:39 +11:00
Peter Ammon
b65649725e Cleanup ParserTestErrorBits
This was a weird type that made sense in C++ but not so much in Rust.
Let's clean this up.
2026-02-16 22:29:30 -08:00
xtqqczze
4eac5f4d9d clippy: fix unused_trait_names lint
https://rust-lang.github.io/rust-clippy/master/index.html#unused_trait_names

Closes #12450
2026-02-17 11:28:58 +11:00