2207 Commits

Author SHA1 Message Date
ritoban23
11d6e92cb5 Show file location when querying bindings with bind
Closes #12215
Closes #12504
Closes #12221
2026-05-31 07:43:32 +08:00
Sean Reifschneider
eb535322d0 Fix cW Vi mode regression deleting trailing space
Missed in 02c0455 (Fix Vi mode cw deleting trailing whitespace, 2026-02-12),

Closes #12790
Closes #12791
2026-05-31 07:38:44 +08:00
Fabian Boehm
25cc01845a string: Fix swapped arguments in error message
Really this could do with a bespoke error, but this'll do for now.
2026-05-29 10:23:59 +02:00
Nahor
240647327a init-unreadable-cwd.fish: replace custom check with __fish_is_cygwin 2026-05-28 11:10:14 -07:00
Johannes Altmanninger
7b358d2122 Fix init-unreadable-cwd test on Windows 2026-05-28 21:10:20 +08:00
Johannes Altmanninger
17ef326c8f Disable cwd-error-reporting test on Windows
On Windows, "chmod 000 .; cd ." doesn't fail, so disable this
test case on Windows.  On the Windows CI runner, "uname" prints
"MINGW64_NT-10.0-26100" so we can't use "__fish_is_cygwin".
2026-05-28 16:40:30 +08:00
Peter Ammon
821efeb99c Justify the continued presence of cwd_fd 2026-05-25 22:25:30 -07:00
Peter Ammon
17fdd2f153 Clean up "strip control characters" changes
Simplify these and move the sanitization closer to the point of output.

Stop worrying about control characters beyond what PCRE2 reports in
"[[:cntrl:]]" for clarity.
2026-05-25 16:48:30 -07:00
saku0512
cbc3cd21f7 prompts: strip control characters from VCS state and PWD
Strip control characters from VCS branch and state strings before writing them in prompts.

Also route the informative and minimalist sample prompts through prompt_pwd instead of printing PWD directly.
2026-05-25 15:51:41 -07:00
Nahor
954c68c0b1 Fix comment typo (CLO_EXEC -> CLOEXEC)
Closes #12774
2026-05-23 00:59:56 +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
June Kim
f69f074f66 Add failing test for git prompt rename miscount (issue #11296)
git status --porcelain -z outputs the rename source filename as a
separate NUL-delimited entry after the status line. When the source
filename starts with [ACDMRTU], the informative prompt miscounts it
as an additional staged change.

Part of #12754
2026-05-13 19:58:52 +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
Nahor
01b9fd9e31 complete: remove unescaping of -c/-p values
This removes the need to double-escape the values on the command line
(once for the command line parser, another for the option handling)

This also brings it in line with the implicit case (`complete cmd ...`)

Fixes #12712

Closes #12718
2026-05-13 18:01:48 +08:00
Johannes Altmanninger
30976d8970 uvar migration: recogize more historical defaults as such
During our one-time migration away from universal variables,
we create ~/.config/fish/conf.d/fish_frozen_theme.fish
if we think that the current theme is different from the default.

The default uvar-backed theme had changed over time, but existing
installations would not be upgraded.  Because of this, we have
a heuristic that assumes that values coinciding with historical
default values also stem from a default.  Some historical values are
missing. Add them.

There are more left, see 03b23dd1b6 (Update default colors,
2022-01-27).

Fixes #12725
2026-05-11 10:41:14 +08:00
Johannes Altmanninger
3dc36f74bc Don't print greetings in interactive read in fake-interactive shell
If a user passes "-i" when running a script, they ought to expect
weird behavior i.e. fish might run the user's interactive-only
configuration which might print things to TTY etc.  But at least
for our part of the configuration, we can avoid depending on the
user-settable interactive bit.

__fish_config_interactive is already only called when we paint the
first prompt, either for a prompt (which implies we're an interactive
shell) or for builtin read (which does not imply anything about the
interactivity of the shell).

Only print greetings when not in interactive read. Notably, "status
is-interactive-read" is not overridable by the user.

This helps us get rid of more "status is-interactive" switches.
2026-05-11 10:21:56 +08:00
Fabian Boehm
5c6acdee09 string shorten: Don't produce output with --quiet
This would've printed stuff in case it didn't have to shorten (which
means it "failed" because the logic is "did something").

Fixes #12732
2026-05-10 11:16:41 +02:00
Peter Ammon
aa5ecd0efa Make the tmux-history-search2 test more reliable 2026-05-09 18:37:07 -07:00
Nahor
ed6fe3f315 tmux-history-search2: fix test on WSL or in console sessions
Those two do not use the "return symbol"

Closes #12704
2026-05-05 14:57:42 +08:00
Nahor
4f539dffaf cd: fix path when trying to cd out of the root directory
Part of #12704
2026-05-05 14:57:42 +08:00
Peter Ammon
b638aa198f Make the tmux-history-search2.fish test pass reliably on macOS 2026-05-03 19:50:26 -07:00
Johannes Altmanninger
71d6ec4ab9 wcsfilecmp: make sure trailing slashes sort first
This command

	cd $(mktemp -d)
	mkdir a "a b"
	complete -C": "

prints

	a b/
	a/

which is wrong ordering.
Usually the trailing slash should not be compared.

Fix this by always sorting slashes first.  Not sure if this is correct
for middle slashes but I couldn't find a case where it matters.

Closes #12695
2026-05-03 20:04:21 +08:00
Daniel Rainer
4e3898d0d7 feat: xtask gettext
Rewrite the PO file handling logic in Rust and make it available via an
xtask. Replaces the
`build_tools/{update_translations,fish_xgettext}.fish` scripts.

Main benefits:
- Better ergonomics
- Better error handling
- Eliminates the need for a fish executable for updating PO files,
  which is particularly useful in CI
- Improved performance, mainly due to concurrent threads working on the
  PO files in parallel

The behavior is mostly unchanged, with the minor exception that section
headers for empty sections are now omitted in PO files.
The interface for invoking the tooling is quite different. Instead of
working with flags, `cargo xtask gettext` has 3 subcommands:
- `update` modifies the PO files to match the current sources
- `check` is like update, but instead of modifying the PO files, it
  shows diffs between the current version of the PO files and what they
  would look like after updating. When there is a difference, the xtask
  exits non-zero, making it useful for checks to detect outdated PO
  files.
- `new` creates a new PO file for the given language.

Both the `update` and `check` command take any number of file paths to
specify the PO files to consider. If none are specified, all files in
`localization/po/` are considered.

Extracting gettext messages from Rust still requires compiling with the
`gettext-extract` feature active. In situations where compilation is
needed for other purposes as well, it can make sense to only build once
and then tell the gettext xtask about the directory into which the
messages have been extracted. This can be done via the
`--rust-extraction-dir` flag. If we stop having gettext messages in
Rust, this logic can be removed.

Closes #12676
2026-04-30 17:31:03 +00: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
1034945690 Fix regression causing "nosuchcommand || hello" to short-circuit
Commit 3534c07584 (Adopt the new AST in parse_execution, 2020-07-03)
added to parse_execution_context_t::run_job_conjunction an early
return when any job in a job conjunction fails to launch.  This causes
"nosuchcommand || echo hello" to not execute the continuation.

Fix this by restoring the previous behavior.

Fixes #12654
2026-04-29 01:55:32 +08:00
Johannes Altmanninger
e2b18fc5b6 config.fish: don't load default theme in noninteractive shells
We define colors in noninteractive shells for historical reasons
(because colors used to be universal variables).

The other potential reason is to get regular syntax highlighting for
commands like:

	fish -c 'read --shell'

but if anyone actually uses that they can probably load a theme
explicitly.

Stop defining colors in noninteractive shells.  It's usually not
a good idea to make them behave differently from interactive ones,
but color seems only relevant for interactive shells?

Let's see if anyone complains.. we may end up reverting this if people
want to use noninteractive fish to query colors..  but I'm not sure
why that would be necessary.

Closes #12673
2026-04-29 01:48:47 +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
Nahor
27fb4d6731 Always heightenize file descriptors
Fixes #12618

Closes #12681
2026-04-28 13:51:24 +08:00
Johannes Altmanninger
006fa86ef4 tests/checks/tmux-source.fish: reduce flakiness
As seen in
https://github.com/fish-shell/fish-shell/actions/runs/24944417077/job/73043241890?pr=12171

	Failure:

	  The CHECK on line 12 wants:
	    prompt 1> source -

	  which failed to match line stdout:3:
	    source -

	  Context:
	    prompt 0> source
	    source: missing filename argument or input redirection
	    source - <= no check matches this, previous check on line 11
	    prompt 1> source -
	    prompt 1>
2026-04-26 13:15:23 +08:00
Johannes Altmanninger
923d0b7974 config: use default XDG_DATA_DIRS when unset or empty
Installing a program like sway to /usr/local installs fish
completions to /usr/local/share/fish/vendor_completions.d/sway.fish.
When $XDG_DATA_DIRS is empty, these will typically not
be picked up.

(Since "__extra_completionsdir" is usually
"/usr/share/fish/vendor_completions.d/", this issue typically only
affects "/usr/share", not "/usr".)

Fix this by using the correct fallback value for XDG_DATA_DIRS.

Fixes #11349

Closes #12656
2026-04-22 14:21:09 +08:00
Johannes Altmanninger
fa33f6f0e0 tests/checks/disown.fish: improve test robustness
If the job never gets into stopped state, it will keep running forever.
Narrow the wait condition, to prevent a timeout in failure scenarios.
2026-04-20 17:03:09 +08:00
Nahor
944ab91fab tests: various fixes for Cygwin itself and ACL mounts
Most notably:
- Unlike MSYS, Cygwin seems to always properly handle symlinks (at least
in common scenarios)
- With ACL, "x" permission also requires "r" do to anything, be it files
or directories

Closes #12642
2026-04-19 17:09:36 +08:00
Johannes Altmanninger
34535fcb61 tests/checks/disown: fix signal delivery race
Intermittent test failure suggests that kill(3p) returns before the
signal is delivered.  Fix the failure by waiting until the signal
has been delivered before continuing the test.

Fixes #12635
2026-04-19 17:07:39 +08:00
Johannes Altmanninger
5eb7687a64 tests/checks/tmux-complete4.fish: fix for macOS sed 2026-04-17 03:22:56 +08:00
Johannes Altmanninger
85e76ba356 Fix option substr completions not being filtered out
Commit 3546ffa3ef (reader handle_completions(): remove dead filtering code,
2026-01-02) gives a proof of correctness that still makes sense;
The first lemma ("if will_replace_token") is trivially true, so no need to
assert it.
The second lemma ("if !will_replace_token") is violated in some edge cases:
we claim that given a token "-c", the option completion "--clip" is an exact match,
which is not true, it's a substring match.

Fix that, asserting the claim.
2026-04-17 01:31:29 +08:00
Johannes Altmanninger
fee4288122 complete: reuse string fuzzy match when completing ~$USER
If we get to this code path, we'll only get completions for user
names, so technically the full StringFuzzyMatch with its ranking of
samecase/smartcase/icase (only showing the best) might be overkill,
but it seems like a good idea to treat this the same way as other
completions.

The occasion for this commit is to correct a wrong
StringFuzzyMatch::exact_match() in the icase branch; which will be
important for a following commit.  Add a test for that.
2026-04-17 01:28:54 +08:00
Peter Ammon
2bab8b5830 prompt_pwd: strip control characters
If a directory has a control sequence in it, then prompt_pwd (used in
the default prompt) would emit it to the console, which could cause
the terminal to interpret the escape sequence.

Strip control sequences from within prompt_pwd, in the same way as
we do in __fish_paste.fish, to sanitize it.

Closes #12629
2026-04-14 16:56:43 +08:00
Nahor
440e7fcbc1 Fix failing system tests on Cygwin
The main changes are:
- disabling some checks related to POSIX file permissions when a filesystem is
mounted with "noacl" (default on MSYS2)
- disabling some checks related to symlinks when using fake ones (file copy)

Windows with acl hasn't been tested because 1) Cygwin itself does not have any
Rust package yet to compile fish, and 2) MSYS2 defaults to `noacl`

Part of #12171
2026-04-11 18:55:00 +08:00
Nahor
52495c8124 tests: make realpath tests easier to debug
- Use the different strings for different checks to more easily narrow down
where a failure happens
- Move CHECK comments outside a `if...else...end` to avoid giving the impression
that the check only runs in the `if` case.

Part of #12171
2026-04-11 18:44:22 +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
Johannes Altmanninger
ff284d642e tests/checks/tmux-abbr.fish: fix on BusyBox less (alpine CI) 2026-04-11 17:03:46 +08:00
Nahor
30e6aa85e2 error rewrite: use new Error to report errors
To homogenize error reporting format, use a new Error struct. Currently this
is used for builtins and ensuring a common cmd/subcmd prefix.

Part of #12556
2026-04-08 14:11:31 +08:00
Johannes Altmanninger
f5c48038b5 Skip tmux-abbr's "pipe builtin into less" test on BusyBox less
Fails on Alpine CI.
2026-04-08 14:04:15 +08:00
Johannes Altmanninger
2193e88423 Pass job group down to builtin_print_help
Repro:

	$ abbr -h | less
	fish: Job 1, 'abbr --help | less' has stopped

Bisects to 5ece9bec6c (__fish_print_help: use man as-is, 2025-08-29).

Root cause is similar to
https://github.com/fish-shell/fish-shell/issues/8699#issuecomment-1030762748
except it's specific to how __fish_print_help is invoked, since
"__fish_print_help abbr | less" works fine.

Fix this by letting __fish_print_help access the terminal.

Fixes #12612

Solved by Claude in a single prompt:

---

 ▐▛███▜▌   Claude Code v2.1.92
▝▜█████▛▘  Sonnet 4.6
  ▘▘ ▝▝    ~/git/fish-shell

❯ "abbr -h | less" gets a signal, resulting in the message "fish: Job 1, 'abbr -h | less' has stopped"
whereas "__fish_print_help abbr | less" works just fine, even though "abbr -h" should run exactly that.
Why this difference?

[...]

● Now I can give you a clear answer.

  ---
  The difference comes down to job group inheritance when man is
  spawned.

  The deferred execution order

  In abbr -h | less, fish uses the "deferred process" optimization:
  since abbr is a non-external process piping into an external one,
  fish launches less first,
   transfers the terminal to less's process group, then runs the
   deferred abbr builtin. By the time abbr's help function spawns man,
   the terminal already
  belongs to less's pgroup.

  Same thing happens with __fish_print_help abbr | less — the outer
  less is launched first and gets the terminal.

  Where the paths diverge

  Function case (__fish_print_help abbr | less):
  get_performer_for_function (exec.rs:1050) captures job.group.clone()
  and passes it to eval_node. So when command man runs inside the
  function, it's given the outer pipeline's job group — the same
  one that owns the terminal. man's inner less pager joins that group
  and can read from the terminal freely. ✓

  Builtin case (abbr -h | less): builtin_print_help calls
  parser.eval(&cmd, streams.io_chain) (shared.rs:652). parser.eval
  is defined as:

  pub fn eval(&self, cmd: &wstr, io: &IoChain) -> EvalRes {
      self.eval_with(cmd, io, None, BlockType::top, false)
      //                      ^^^^ job_group = None
  }

  job_group = None means man creates a brand-new job group with no
  terminal access. When man spawns its less pager, the pager tries
  to read keyboard input from
   the terminal, but the terminal belongs to the outer less's process
   group. The pager receives SIGTTIN → stops → the whole job is
   reported as stopped.

  The fix

  builtin_print_help should pass streams.job_group to the eval call
  (which is already populated at exec.rs:1192). Changing line 652 from:

  let res = parser.eval(&cmd, streams.io_chain);

  to:

  let res = parser.eval_with(&cmd, streams.io_chain, streams.job_group.as_ref(), BlockType::top, false);

  would give man the outer job's job group, letting its pager access
  the terminal just like the function case.

✻ Sautéed for 13m 0s
2026-04-07 20:21:38 +08:00
Nahor
d2653b7cac tmux-set.fish: fix spurious CI failure
Part of #12556
2026-04-07 17:49:57 +08:00
Nahor
99d63c21f1 Add tests to exercise all builtin error messages
With a few exceptions, only one test is added for a given message, even
when there are multiple ways to trigger the same message (e.g. different
invalid option combinations, or triggered in shared functions such as
`builtin_unknown_option`)

Includes a few very minor fixes, such as missing a newline, or using the
wrong var name.

Closes #12603
2026-04-05 00:22:42 +08:00
Nahor
8d92016e72 string: error messages fixes
- fix wrong pattern used in `string replace` error message
- replace unreachable error with `unreachable!` in `string`
- fix cmd being used in place of subcmd 

Part of #12603
2026-04-05 00:22:41 +08:00
Nahor
2f9c2df10d set: report an error when called with -a,-p and no NAME
Previously executing `set -a` or `set -p` would just list all the
variables, which does not make sense since the user specifically ask
for an action (append/prepend).

Update the help page synopsis

Part of #12603
2026-04-05 00:22:40 +08:00
Johannes Altmanninger
e25b4b6f05 tests/checks/realpath.fish: fix on macOS 2026-04-03 23:26:37 +08:00
Nahor
68453843d4 set: fix unreachable error messages
- Remove unreachable error message in `handle_env_return()`
While we could have put an empty block in `handle_env_return()` and
removed the condition on `NotFound` in `erase()`, we prefered to use
`unreachable!` in case `handle_env_return()` gets called in new scenarios
in the future

- Make reachable the error message when asking to show a slice

Part of #12603
2026-04-03 13:53:42 +08:00