Compare commits

...

1689 Commits

Author SHA1 Message Date
Johannes Altmanninger
3fa252677a Release 4.1.2
Created by ./build_tools/release.sh 4.1.2
2025-10-07 22:56:06 +02:00
Johannes Altmanninger
e074b27abf release.sh: fix deployment approval logic 2025-10-07 22:55:04 +02:00
Johannes Altmanninger
a5727e59da tests/checks/fish_config: fix for non-embedded builds
(cherry picked from commit e3ebda3647)
2025-10-07 22:23:51 +02:00
Johannes Altmanninger
4e68f8a130 release.sh: check fish-site worktree staleness
(cherry picked from commit 092e7fa274)
2025-10-07 22:23:51 +02:00
Johannes Altmanninger
417755b6a7 tests/checks/config-paths-standalone.fish: fix bad assertion
Fixes #11906

(cherry picked from commit 724416125e)
2025-10-07 22:00:31 +02:00
Johannes Altmanninger
ef30feda12 Sanitize cursor position report on kitty click_events
This is easy to trigger by having a background process do "echo" to
move the terminal cursor to the next line, and then clicking anywhere.

Fixes #11905

(cherry picked from commit dd47c2baa2)
2025-10-07 21:54:40 +02:00
Johannes Altmanninger
20e3ed23b7 fish_config: fix regression "theme show" not showing custom themes
This regressed in 6f0532460a5~2..6f0532460a5 (fish_config: fix for
non-embedded builds, 2025-09-28).

Fixes #11903

(cherry picked from commit 15065255e9)
2025-10-07 21:54:40 +02:00
Johannes Altmanninger
7bfdb8460d Embedded builds to use $workspace_root/etc again if run from build dir
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)
2025-10-07 15:26:09 +02:00
Johannes Altmanninger
8d9d5816ed Extract constant for resolved build directory
Also use a different name than for the CMake variable, to reduce
confusion.

(cherry picked from commit a0b22077a5)
2025-10-07 15:26:09 +02:00
Johannes Altmanninger
97f6129dea Fix regression on paste in non-interactive read
As reported in
https://github.com/fish-shell/fish-shell/issues/11836#issuecomment-3369973613,
running "fish -c read" and pasting something would result this error
from __fish_paste:

	commandline: Can not set commandline in non-interactive mode

Bisects to 32c36aa5f8 (builtins commandline/complete: allow handling
commandline before reader initialization, 2025-06-13).  That commit
allowed "commandline" to work only in interactive sessions, i.e. if
stdin is a TTY or if overridden with -i.

But this is not the only case where fish might read from the TTY.
The notable other case is builtin read, which also works in
noninteractive shells.
Let's allow "commandline" at least after we have initialized the TTY
for the first reader, which restores the relevant historical behavior
(which is weird, e.g. « fish -c 'read; commandline foo' »).

(cherry picked from commit a958f23f63)
2025-10-06 15:12:13 +02:00
Xiretza
c19de5aeb9 Make command run by __fish_echo output to TTY for color detection
Without this, e.g. Alt-L shows the directory entries one per line and
without colors.

Closes #11888

(cherry picked from commit b7fabb11ac)
2025-10-06 15:12:13 +02:00
Johannes Altmanninger
874fba1108 Don't use kitty keyboard protocol support to decide timeout
As reported in
https://github.com/fish-shell/fish-shell/discussions/11868, some
terminals advertise support for the kitty keyboard protocol despite
it not necessarily being enabled.

We use this flag in 30ff3710a0 (Increase timeout when reading
escape sequences inside paste/kitty kbd, 2025-07-24), to support
the AutoHotKey scenario on terminals that support the kitty keyboard
protocols.

Let's move towards the more comprehensive fix mentioned in abd23d2a1b
(Increase escape sequence timeout while waiting for query response,
2025-09-30), i.e. only apply a low timeout when necessary to actually
distinguish legacy escape.

Let's pick 30ms for now (which has been used successfully for similar
things historically, see 30ff3710a0); a higher timeout let alone
a warning on incomplete sequence seems risky for a patch relase,
and it's also not 100% clear if this is actually a degraded state
because in theory the user might legitimately type "escape [ 1"
(while kitty keyboard protocol is turned off, e.g. before the shell
regains control).

This obsoletes and hence reverts commit 623c14aed0 (Kitty keyboard
protocol is non-functional on old versions of Zellij, 2025-10-04).

(cherry picked from commit 6accc475c9)
2025-10-06 15:12:12 +02:00
Johannes Altmanninger
695f225cb4 Kitty keyboard protocol is non-functional on old versions of Zellij
try_readb() uses a high timeout when the kitty keyboard protocol is
enabled, because in that case it should basically never be necessary
to interpret \e as escape key, see 30ff3710a0 (Increase timeout when
reading escape sequences inside paste/kitty kbd, 2025-07-24).

Zellij before commit 0075548a (fix(terminal): support kitty keyboard
protocol setting with "=" (#3942), 2025-01-17) fails to enable kitty
keyboard protocol, so it sends the raw escape bytes, causing us to
wait 300ms.

Closes #11868

(cherry picked from commit 623c14aed0)
2025-10-04 07:23:59 +02:00
Johannes Altmanninger
9f36adb731 Refresh TTY timestamps after firing focus events
Using a multi-line prompt with focus events on:

	tmux new-session fish -C '
		tmux set -g focus-events on
		set -g fish_key_bindings fish_vi_key_bindings
		function fish_prompt
		    echo (prompt_pwd)
		    echo -n "> "
		end
		tmux split
	'

switching to the fish pane and typing any key sometimes leads to our
two-line-prompt being redawn one line below it's actual place.

Reportedly, it bisects to d27f5a5 which changed when we print things.
I did not verify root cause, but
1. symptoms are very similar to other
   problems with TTY timestamps, see eaa837effa (Refresh TTY
   timestamps again in most cases, 2025-07-24).
2. this seems fixed if we refresh timestamps after
   running the focus events, which print some cursor shaping commands
   to stdout. So bravely do that.

Closes #11870

(cherry picked from commit 7d83dc4758)
2025-10-03 22:41:20 +02:00
Johannes Altmanninger
3ff699d7ea Update changelog for patch release
(cherry picked from commit 493d0bca95)
2025-10-03 22:41:10 +02:00
Étienne Deparis
4b6ad751e8 web_config: Support long options separated with = from their value
Closes #11861

(cherry picked from commit 8adc598e90)
2025-10-03 22:38:25 +02:00
Étienne Deparis
8dd90085b6 web_config: Use None as default for underline style
Underline is no more a boolean and should be one of the accepted style,
or None. By keeping False as default value, web_config was generating
wrong --underline=False settings

Part of #11861

(cherry picked from commit c884c08257)
2025-10-03 22:38:25 +02:00
Johannes Altmanninger
47396e78ce Stop requesting modifyOtherKeys on old Midnight Commander again
This upstream issue was fixed in 0ea77d2ec (Ticket #4597: fix CSI
parser, 2024-10-09); for old mc's we had worked around this but the
workaround was accidentally removed. Add it back for all the versions
that don't have that fix.

Fixes f0e007c439 (Relocate tty metadata and protocols and clean
it up, 2025-06-19) Turns out this was why the "Capability" enum was
added in 2d234bb676 (Only request keyboard protocols once we know
if kitty kbd is supported, 2025-01-26).

Fixes #11869

(cherry picked from commit fcd246064b)
2025-10-03 22:38:25 +02:00
Johannes Altmanninger
77a038541a Harmonize temporary Midnight Commander workarounds a bit
(cherry picked from commit 86a0a348ee)
2025-10-03 22:38:25 +02:00
Johannes Altmanninger
84dbdf4e2a Unbreak hack to strip " (deleted)" suffix from executable path
Commit 49b88868df (Fix stripping of " (deleted)" from non-UTF8 paths
to fish, 2024-10-12) was wrong because Path::ends_with() considers
entire path components. Fix that.

Refs:
- https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$k2IQazfmztFUXrairmIQvx_seS1ZJ7HlFWhmNy479Dg
- https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$4pugfHejL9J9L89zuFU6Bfg41UMjA0y79orc3EaBego

(cherry picked from commit 7b59ae0d82)
2025-10-03 22:38:25 +02:00
Johannes Altmanninger
0a50ba9ef5 release.sh: add next patch milestone
This is still the common case.

(cherry picked from commit ed36e852d2)
2025-10-03 22:38:25 +02:00
Johannes Altmanninger
8b317a192b release.sh: close milestone when done
Don't fail early if this doesn't exist, because it's not needed for
testing this on fish-shell forks that live on GitHub.

(cherry picked from commit da5d93c1e2)
2025-10-03 22:38:25 +02:00
Fabian Boehm
42decbf1da Fix scp completions
Introduced when __fish_mktemp_relative was.

Fixes #11860

(cherry picked from commit 97acc12d62)
2025-10-02 18:40:57 +02:00
Johannes Altmanninger
79b0d24701 release.sh: sunset release announcement email
I'm not sure if our peer projects do this or if it's useful to have
on top of github releases (especially as most releases are patch
releases mainly).

We could certainly use "sphinx-build -b text" in
build_tools/release-notes.sh to extract a nice plaintext changelog
and send that, but that doesn't support links.  Not sure about HTML
email either.

(cherry picked from commit 62543b36a4)
2025-10-01 08:10:20 +02:00
Johannes Altmanninger
1f6cd5fc2d Release 4.1.1
Created by ./build_tools/release.sh 4.1.1
2025-09-30 19:27:13 +02:00
Johannes Altmanninger
635525be96 Changelog update for 4.1.1
(cherry picked from commit 412149a5de)
2025-09-30 19:26:51 +02:00
Johannes Altmanninger
280791c0f5 Increase escape sequence timeout while waiting for query response
Running "fish -d reader" inside SSH inside Windows terminal sometimes
results in hangs on startup (or whenever we run "scrollback-push"),
because not all of the Primary DA response is available for reading
at once:

	reader: Incomplete escape sequence: \e\[?61\;4\;6\;7\;14\;21\;22\;23\;24\;28\;32

Work around this by increasing the read timeout while we're waiting
for query responses.

We should try to find a better (more comprehensive?) fix in future,
but for the patch release, this small change will do.

Fixes #11841

(cherry picked from commit abd23d2a1b)
2025-09-30 19:05:04 +02:00
Johannes Altmanninger
91faa1be49 Changelog for translation fixes from #11833
(cherry picked from commit b774c54a6f)
2025-09-30 19:05:04 +02:00
王宇逸
24e529ea07 zh_CN: fix tier 1 translations
Closes #11833

(cherry picked from commit e4b797405b)
2025-09-30 19:05:04 +02:00
Johannes Altmanninger
595bfda331 release-notes.sh: fix sphinx warning for patch release notes
Integration_4.1.1 fails to generate release notes with

	CHANGELOG.rst:9: WARNING: Bullet list ends without a blank
	line; unexpected unindent. [docutils].

(cherry picked from commit 81a89a5dec)
2025-09-30 19:05:04 +02:00
Johannes Altmanninger
0f358756a2 Primary Device Attribute is a proper noun
We don't care about any specific attributes but we do very much care
about the specific query and response format associated with VT100's
primary device attribute query. Use a proper noun to emphasize that
we want that one and no other.

Ref: https://github.com/fish-shell/fish-shell/pull/11833#discussion_r2385659040
(cherry picked from commit 0da12a6b55)
2025-09-30 12:08:37 +02:00
Johannes Altmanninger
0ace46d127 build.rs: fix MSRV (1.70) clippy
(cherry picked from commit 86ec8994e6)
2025-09-30 12:08:37 +02:00
Johannes Altmanninger
a143a67318 po/de.po: copy-edit German translations
Go through all existing translations except for tier3.

(cherry picked from commit caf426ddb2)
2025-09-30 11:52:43 +02:00
Johannes Altmanninger
047b9d96a0 builtin commandline: fix completion description
(cherry picked from commit 508ae410a6)
2025-09-30 11:52:43 +02:00
Johannes Altmanninger
c942b034ba builtin function: remove dead code
(cherry picked from commit 993b977c9b)
2025-09-30 11:52:42 +02:00
Johannes Altmanninger
0f1caacae4 builtin function: fix a misleading error message
Issue introduced in 7914c92824 (replaced the functions '--rename'
option with '--copy'., 2010-09-09).

(cherry picked from commit a7f0138fc7)
2025-09-30 11:52:42 +02:00
Johannes Altmanninger
f332cdc757 builtin set: fix regression in error message description
(cherry picked from commit ab3c932903)
2025-09-30 11:52:42 +02:00
Johannes Altmanninger
c6912c6721 Remove translations for some error messages that basically never happen
Executable path is empty only in contrived circumstances.

The regex error happens only when the user explicitly turns off a
feature flag.

The orphaned process error seems very unlikely, not worth translating.

(cherry picked from commit ae0fdadcff)
2025-09-30 11:52:42 +02:00
Johannes Altmanninger
678edbd223 Fix short description for builtin wait
(cherry picked from commit e3974989d8)
2025-09-30 11:52:42 +02:00
Johannes Altmanninger
1a78407efe Translation update implied by parent commit
Part of #11833

(cherry picked from commit 080b1e0e4f)
2025-09-30 11:52:41 +02:00
Johannes Altmanninger
3ecf1bc46d po: add section markers to indicate translation priority
Part of #11833

(cherry picked from commit a5db91dd85)
2025-09-30 11:52:41 +02:00
Johannes Altmanninger
4d99e51e62 Translation update implied by parent commit
Part of #11833

(cherry picked from commit b62f54631b)
2025-09-30 11:52:41 +02:00
Johannes Altmanninger
a9576d44e3 Prepare to not localize private function descriptions
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)
2025-09-30 11:52:41 +02:00
Johannes Altmanninger
2c0e912fe1 Mark private functions that don't need localization
See the next commit.

Part of #11833

(cherry picked from commit a53db72564)
2025-09-30 11:52:41 +02:00
Johannes Altmanninger
1f96e58852 functions/realpath: remove weird wrapping
Wrapping the same thing is redundant and wrapping grealpath is kinda
pointless since we only provide completions for realpath.

(cherry picked from commit 61b0368dac)
2025-09-30 11:52:41 +02:00
Integral
03f4bf262a completions/help: correct the spelling of "redirection"
Closes #11839

(cherry picked from commit 568b4a22f9)
2025-09-30 11:52:41 +02:00
Jiangqiu Shen
bb61c948af Re-add translations for share/completions/cjpm.fish
As removed in the parent commit.
Cherry-picked from e4c55131c7 (Update translation, 2025-07-04)

(cherry picked from commit 8abba8a089)
2025-09-30 11:52:41 +02:00
王宇逸
fa59a736bf zh_CN: bad translations are worse than none
Part of #11833

(cherry picked from commit b3b789cd68)
2025-09-30 11:52:40 +02:00
Johannes Altmanninger
97dc8f69d9 functions/seq: use early return
(cherry picked from commit 425a166111)
2025-09-30 11:52:40 +02:00
Johannes Altmanninger
57753474e4 tests/checks/check-all-fish-files.fish: follow naming convention
(cherry picked from commit 1dcc290e29)
2025-09-30 11:52:40 +02:00
Johannes Altmanninger
d5f4cedeb5 build.rs: remove dead code
(cherry picked from commit 863204dbfa)
2025-09-30 11:52:40 +02:00
Sebastian Fleer
ec4700308e webconfig: Replace str.stripprefix with str.removeprefix
str.stripprefix doesn't exist in Python:
https://docs.python.org/3/library/stdtypes.html#str.removeprefix

Closes #11840

(cherry picked from commit 4b21e7c9c7)
2025-09-30 11:52:40 +02:00
Johannes Altmanninger
1d5ae08696 Reliably disable modifyOtherKeys on WezTerm
WezTerm allows applications to enable modifyOtherKeys by default.
Its implementation has issues on non-English or non-QWERTY layouts,
see https://github.com/wezterm/wezterm/issues/6087 and #11204.

fish 4.0.1 disabled modifyOtherKeys on WezTerm specifically
(7ee6d91ba0 (Work around keyboard-layout related bugs in WezTerm's
modifyOtherKeys, 2025-03-03)), fish 4.1.0 didn't, because at that
time, WezTerm would advertise support for the kitty keyboard protocol
(even if applications are not allowed to enable it) which would make
fish skip requesting the legacy modifyOtherKeys.

WezTerm no longer advertises that if config.enable_kitty_keyboard
is false.  Let's work around it in another way.

(cherry picked from commit df5230ff4a)
2025-09-30 11:52:40 +02:00
Johannes Altmanninger
bb5b583d63 Tighten some screws for TTY-specific workarounds
(cherry picked from commit 7cd0943056)
2025-09-30 11:52:40 +02:00
Johannes Altmanninger
7d80a599f2 fish_config: fix for non-embedded builds
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)
2025-09-28 12:31:00 +02:00
Johannes Altmanninger
284d8fa3d1 fish_config: fix "prompt/theme show" in embed-data builds
Fixes #11832

(cherry picked from commit 29a35a7951)
2025-09-28 11:08:14 +02:00
Johannes Altmanninger
a03f52add0 release workflow: install msgfmt for staticbuilds
This makes us actually embed localized messages.

Part of #11828

(cherry picked from commit 0ff0de7efe)
2025-09-28 11:06:21 +02:00
Johannes Altmanninger
89fa81123b build_tools/release.sh: actually add new docs
Not quite sure for which step this is actually needed.  While at it,
fix the errexit issue that caused this blunder.

(cherry picked from commit 97ae05b69d)
2025-09-28 11:06:21 +02:00
Johannes Altmanninger
29b80bbaf9 Release 4.1.0
Created by ./build_tools/release.sh 4.1.0
2025-09-27 22:20:11 +02:00
Johannes Altmanninger
29470358d4 make_macos_pkg: update CMake invocation for MSRV rustc+cargo
Since 205d80c75a (findrust: Simplify (#11328), 2025-03-30), we need
to set Rust_COMPILER and Rust_CARGO instead of Rust_TOOLCHAIN (which
is no longer used).  Adjust macOS builds accordingly.

When I set only one of the two, the error messages were pretty
unintelligible. But I guess few normal users need to override the
Rust version, and they can always look here.

While at it, enable localization.  AFAIK, the only reason why we didn't
do this on macOS were problems related to the gettext shared library /
dependency. We no longer need that, and it's already tested in CI.
2025-09-27 22:15:25 +02:00
Johannes Altmanninger
8fe68781be Release workflow fixups
(cherry picked from commit ce4aa7669d)
2025-09-27 22:06:26 +02:00
Johannes Altmanninger
aba4d26f95 Emphasize that "status {list-files,get-file}" are meant for internal use
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
2025-09-27 14:22:18 +02:00
Johannes Altmanninger
b964072c11 Move scrollback-push feature detection to fish script
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.
2025-09-27 14:22:18 +02:00
Johannes Altmanninger
06bbac8ed6 release-notes.sh: add stats, round off committer list
Instead of adding these to the Markdown directly, add it to the
fake CHANGELOG.rst source, which makes escaping easier, and allows
generating other formats than Markdown in future.
2025-09-27 14:22:18 +02:00
Johannes Altmanninger
aab22a453b Revert "Only load sphinx_markdown_builder extension if it's used"
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.
2025-09-27 14:22:18 +02:00
Johannes Altmanninger
4cc2d2ec30 release-notes.sh: remove line breaks from generated Markdown, for GitHub
GitHub-flavored Markdown translates line breaks to <br/>, which does
not match our intent. Work around that by joining lines when producing
Markdown output.
2025-09-27 14:22:18 +02:00
Johannes Altmanninger
6ed4e54c1e Remove some dead code and unnecessary allocations
complete --subcommand was added in a8e237f0f9 (Let `complete`
show completions for one command if just given `-c`, 2020-09-09)
but never used or documented.
2025-09-27 14:22:18 +02:00
Johannes Altmanninger
829d6bc8fb Move terminal name into status subcommand not variable
Forgot about that; less namespace pollution this way, and it's more
obvious that it's read-only.
2025-09-27 14:22:18 +02:00
Johannes Altmanninger
abae6157d9 Changelog: reduce verbosity a bit, add some more 2025-09-27 14:22:18 +02:00
Daniel Rainer
bce19e7265 Fix typos 2025-09-26 16:34:22 +02:00
Johannes Altmanninger
166b17701a Remove spurious terminal interaction from unit tests
Some of our integration tests require a reader for code execution
and testing cancellation etc., but they never actually read from the
terminal.  So they don't need to call reader_interactive_init(), and
doing so is a bit weird.  Let's stop that; this allows us to assert
that reader_push() is always called with an input file descriptor
that refers to a TTY.
2025-09-26 13:03:20 +02:00
Johannes Altmanninger
f8269be359 Move redundant instances of blocking_query into InputData
We duplicate the same member across all implementations.  Looks like
this never makes sense, so move it to the shared data bag.
2025-09-26 12:59:02 +02:00
Johannes Altmanninger
b907bc775a Use a low TTY query timeout only if first query failed
As mentioned in the comment, query timeouts can happen if either
1. the terminal doesn't support primary device attribute
2. there is extreme (network) latency

In the first case, we want to turn the timeout way down.  In the
second case, probably not, especially because the network latency
may be transient. Let's keep the high timeout in the second case.

Fixes 7ef4e7dfe7 (Time out terminal queries after a while,
2025-09-21).
2025-09-26 12:59:02 +02:00
Johannes Altmanninger
7e3fac561d Query terminal only just before reading from it
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.
2025-09-26 12:59:02 +02:00
Johannes Altmanninger
7713e90aeb Make query response handling more consistent 2025-09-26 12:58:10 +02:00
Johannes Altmanninger
08ad5c26ea Give scroll-forward a less confusing name
ECMA-48 calls CSI S "scroll up", so use something like that but try
to avoid ambiguity.
2025-09-26 12:52:28 +02:00
Johannes Altmanninger
310b7eca68 Only initialize kitty keyboard capability on startup
If the initial query is interrupted by ctrl-c, we leave it unset. A
later rogue "\e[?0u" reply would make us enable it, which seems
surprising. Fix that by always setting the capability if we're gonna
read from stdin.
2025-09-26 12:10:56 +02:00
Johannes Altmanninger
e9ae143bab Fix cursor position reports being ignored
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)
2025-09-26 12:10:04 +02:00
Johannes Altmanninger
74d3832610 Early return in reader_execute_readline_cmd() 2025-09-26 12:10:04 +02:00
yegorc
3c04a05ea4 Added documentation for &>>.
The `&>>` redirection was undocumented.

Closes #11824
2025-09-26 12:10:04 +02:00
Johannes Altmanninger
e6541c5c93 Enable sphinx parallelism also when building markdown release notes
We get a warning about sphinx_markdown_builder not being
parallelizable. Fix that.

Ref: https://github.com/liran-funaro/sphinx-markdown-builder/pull/38
2025-09-26 12:10:04 +02:00
Johannes Altmanninger
7b495497d7 Only load sphinx_markdown_builder extension if it's used
As is, building man pages or HTML docs while sphinx_markdown_builder
is installed, will result in unrelated warnings.  Remove those by
removing it from the extensions config.  Markdown building (only used
for changelog) seems to work without this just fine.
2025-09-26 12:08:51 +02:00
Johannes Altmanninger
6e90d9bd6f Fix markdown changelog generation test
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.
2025-09-26 12:08:51 +02:00
Stevie Alvarez
b8f704e3c4 fish_git_prompt: add diverged upstream char option
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
2025-09-25 11:38:52 +02:00
Johannes Altmanninger
b37b57781b Disable sphinx-markdown-builder in tests again for now
Somehow I didn't realize this breaks the tests/checks/sphinx-* tests.
2025-09-24 16:30:21 +02:00
Fabian Boehm
e3a5725a46 Fix crash if there is no xtversion reply 2025-09-24 16:21:18 +02:00
Karel Balej
3d5a5b8740 completions: add basic completions for udevil
Add a set of basic completions for udevil, which is a program that
allows unpriviledged users to mount devices.

Each command has a corresponding long-option-like syntax variant
(sometimes even multiple ones), such as "udevil monitor" -> "udevil
--monitor", which are omitted here for simplicity.

The project unfortunately seems long abandoned and as such no attempt to
submit these completions upstream has been made.
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
22ffc31b71 release workflow: credit contributors in release notes
While at it, do a 's/^--$/^---/' to fix Markdown syntax for horizontal
line for CommonMark-based parsers.
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
127c02992d Test markdown changelog creation in CI
Extract a github action to install the same version used in the release
workflow.  In future we should probably migrate to requirements.txt
or similar.
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
765ca54d59 release workflow: resolve relative references in changelog properly
Instead of having sphinx-build only build CHANGELOG.rst, build the
entire thing, so relative references (":doc:", ":ref:") can be resolved
properly.  Replace our sed-based hacks with 'markdown_http_base'.
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
1519ea74be release workflow: extract script for generating markdown release notes 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
2895986465 tests/sphinx-man: man page building no longer requires fish_indent 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
e9e7ad24b5 Changelog: also extract changes to embed-data to its own section 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
4f8aa0a78c Show warnings from sphinx-build when building with cargo 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
f821d6dd7f Feature flag for turning off TTY querying
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.
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
4c1da3b2d3 Parse Terminal.app version only if needed 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
a6f975a7e3 Add mark-prompt 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)
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
bbd7205de1 Document GNU screen incompatibily & workarounds
The problem described in 829709c9c4 (Replace synchronized update
workaround, 2025-04-25) doesn't seem too bad; let's document the
workaround.

We could probably also remove our $STY-based workaround.  I'm not
yet sure how many problems that one will cause.

Closes #11437
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
64c8d361b0 status.rst: link to feature flag documentation 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
c31e769f7d Use XTVERSION for terminal-specific workarounds
As mentioned in earlier commit
("Query terminal before reading config").

Closes #11812
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
99854c107a Set kitty keyboard capability only at startup 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
5e317497ef Query terminal before reading config
We still have terminal-specific workarounds based on TERM_PROGRAM and
others, see test/test_driver.py.  In future we should get rid of them.

They are also unreliable, potentially missing inside SSH/containers,
incorrect if a terminal was started from another terminal (#11812);
also TERM can be incorrect for many reasons.

The better criterion for terminal-specific workarounds is XTVERSION,
which has none of the above disadvantages.

Since some of the workarounds (tmux, iTerm2) need to be applied before
we draw the first prompt. This also means: before we read any config
because config may call builtin "read".

Do startup queries before reading config.

Some changes implied by this:
1. Remove a call to init_input() which is already done by env_init()
2. call initialize_tty_metadata() only after queries have returned
3. Since we call initialize_tty_metadata() before the first
   call to tty.enable_tty_protocols() in Reader::readline(),
   we can remove the redundant call from reader_interactive_init().
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
96f63159b5 Be consistent about how we handle bad stdin FD
When poll() or read() on stdin fails, fish's interactive reader
pretends it has received SIGHUP, and subsequently exits.

I don't know if this is the right thing to do, or how to reproduce
this in a realistic scenario.

Unlike fish, fish_key_reader seems to ignore these failures, meaning
it will retry poll()/read() immediately.  This seems less correct,
so use fish's behavior for now.
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
fadb2fac44 Fix some import conventions 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
1b01ac87fa Improve a tcsetpgrp error message 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
4abd390c84 test_driver.py: extend the list of terminal-specific workarounds 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
712bbf00ec fish_key_reader: remove things that don't belong in the builtin
While at it, remove a redundant call to initialize_tty_metadata();
that's done by initial_query().
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
76d1e8d4da fish_key_reader: reuse isatty helper 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
2d457adfec builtin read: use a better type 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
6fdce59572 Extract function for setting shell modes
We do the same thing in several places, with lots of small differences.
Extract the most reasonable behavior and use it everywhere.  Note that
we had an explictly-motivated ENOTTY check; the motivating issues
doesn't seem to reproduce anymore here though I did not bisect yet.
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
21150726d3 Remove confused redundant mutex lock 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
37a0919fee Also check isatty(0) before querying
A process like "fish -i <somefile ..."  probably shouldn't query
because it's not gonna work.

In future we could enable this by sending/receiving queries to/from
/dev/tty rather than stdout/stdin.
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
7a14dd0b7f Be more consistent about when to query the TTY
We are more conservative with querying on startup than we are with
querying for cursor position.

Part of this is oversight (if startup querying is not done, we
basically never get into a position where we query for cursor position,
outside extreme edge cases).

Also, some specific scenarios where we query for cursor position
inside, say, Midnight Commander, are not actually broken, because that
only happens when Midnight Commander gives us control.  But let's
favor consistency for now; the Midnight Commander issue should be
fixed soon anyway.

Use the same logic in both cases.
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
fb0e17d6ea tty_handoff: extract Midnight Commander workaround
A following commit wants to run the full initialize_tty_metadata()
only after querying XTVERSION.

But MC_TMPDIR needs to be checked before querying for XTVERSION.

Remove this cyclic dependency by extracting the MC_TMPDIR check.
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
a6a38b78d6 Don't initialize interactive reader redundantly
Commands like

	fish -C 'read'

create two top-level readers one after the other.  The second one is
the fish REPL.

Both run some initialization of globals and parser variables.  This is
weird; it should not be necessary.

Let's call reader_interactive_init() only once.
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
f5420b1110 Remove stale comment 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
90124c7889 Remove workaround for dvtm/abduco
dvtm and abduco are two terminal session managers with the same
original.

Among other issues, they fail to reply to primary device
attribute.  We have added a workaround for that based on
TERM=dvtm-256color (unreliable). A patch has been submitted for dvtm
https://lists.suckless.org/hackers/2502/19264.html

I don't know of a maintained fork (the original ones have had no
commit in 5 years) and there are better alternatives available
(shpool, tmux).  They have other VT100 compatibility issues as well
(accidental DECRST; something like "ls" Tab Tab Tab causes spurious
bold and underline markup).

Also, as of the parent commit, failure to respond to primary DA is
no longer catastrophic. So let's remove the workaround.  This means
that fish inside dvtm/abduco will pause for 2 seconds on startup and
print a warning (unless interrupted by ctrl-c).
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
7ef4e7dfe7 Time out terminal queries after a while
Add a timeout of 2 seconds queries; if any query takes longer, warn
about that and reduce the timeout  so we stop blocking the UI.  This 2
second delay could also happen when network latency is momentarily
really high, so we might want relax this in future.

Note that this timeout is only triggered by a single uninterrupted
poll() (and measured from the start of poll(), which should happen
shortly after sending the query). Any polls interrupted by signals
or uvars/IO port before the timeout would be hit do not matter.
We could change this in future.

Closes #11108
Closes #11117
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
06ede39ec9 Degrade gracefully when failing to receive cursor position report
Follow up the cursor position report query with a primary device
attribute one.  When that one arrives, any cursor position response
must have arrived too. This allows us to prevent a hang on terminals
that only support primary device attribute.
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
1612576d1c Restructure query response handling logic
Instead of switching only on the response type, switch on the
combination of that and the expected response.  This helps the
following commits, which add more combinations (due to following up
cursor position report with a primary DA, and adding a timeout). No
behavior change here.
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
2260465ed7 Rename enum variants to remove a name clash 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
3bd296ae3d Reuse variable in next_input_event() 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
064a45635c Document inter-dependencies between optional terminal features
- 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.
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
6f01c7b707 Changelog: minor edits 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
6f2a701f81 README: recommend latest release in embedded builds section 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
f79377e4b0 Revert "Temporary workaround for BSD WEXITSTATUS libc bug"
This reverts commit c1b460525c.

We have libc commit 7a7fe4683 (Apply modulo 256 to BSD WEXITSTATUS,
2024-12-19) now.
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
c3626a3031 builtin read: --tokenize-raw option
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
2025-09-24 15:51:32 +02:00
Johannes Altmanninger
f3b27e8d11 Changelog: link to command docs 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
5d71609ff7 Changelog: fix rst syntax for man page output 2025-09-24 15:51:32 +02:00
Johannes Altmanninger
dbd79285cb Contributing: fix rst external link syntax 2025-09-24 15:51:32 +02:00
David Adam
dca571ac4c fixup! fish.spec: also drop %find stanza for lang files 2025-09-23 08:01:04 +08:00
Daniel Rainer
c8f31ceedb Fix release workflow syntax
The previous version results in an immediate workflow failure due to a
syntax error in the YAML. `workflow_dispatch` should be a dictionary
key, with its value being another dictionary (whose only key is `inputs`
at the moment).
2025-09-22 20:25:45 +02:00
Johannes Altmanninger
b1d1ef1b6e github release workflow: fix structure 2025-09-22 18:19:36 +02:00
Johannes Altmanninger
01361b9217 github release workflow: only run on explicit dispatch
Release automation can be tested on any GitHub fork, using

	build_tools/release.sh $version $repository_owner $git_remote

which should work perfectly except for macOS packages (which fail
unless provided GitHub secrets).

People might push tags to their forks, both non-release tags (which
would trigger an early failure in "is-release-tag") or replicas of
our actual release tags (which would create a draft release etc. and
only fail when building macOS packages).

Run on explicit workflow dispatch to make sure it's not triggered by
accident like that.

This means that we'll use the .github/workflows/release.yml from
the default branch (i.e. master), so try to make sure it matches the
version in the release, to prevent accidents.

Closes #11816
2025-09-22 18:15:21 +02:00
Johannes Altmanninger
dab8df1a18 github release workflow: use github context only if needed 2025-09-22 18:15:21 +02:00
Johannes Altmanninger
c771ff06d4 build_tools/make_macos_pkg.sh: fix inconsistent version computation
make_tarball.sh and others do it differently.
2025-09-22 18:15:21 +02:00
David Adam
e5cb1689c5 fish.spec: also drop %find stanza for lang files 2025-09-21 18:45:20 +08:00
David Adam
fa96df3a90 fish.spec: drop find_lang macro
All translations are now handled internally.
2025-09-21 18:11:01 +08:00
Karel Balej
67a9d08778 completions/mpc: conditionally enable file completion for add and insert
When connecting to MPD via a Unix socket, mpc add and insert accept
absolute paths to local files. Offer these in the completion if the
completed token starts with a slash after expansion.
2025-09-20 15:20:19 +02:00
Johannes Altmanninger
5ece9bec6c __fish_print_help: use man as-is
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
2025-09-20 13:56:23 +02:00
Johannes Altmanninger
d422ad603e __fish_print_help: remove error message
__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).
2025-09-20 13:56:23 +02:00
Johannes Altmanninger
26116b477e Fix crash on "bg" of non-job-controlled job
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.
2025-09-20 13:56:23 +02:00
Johannes Altmanninger
87c73b7fbf builtin break/continue: support -h/--help argument
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.
2025-09-20 13:56:23 +02:00
Johannes Altmanninger
c77255aabc tests: consolidate __fish_print_help overrides 2025-09-20 13:56:23 +02:00
Johannes Altmanninger
0063992195 functions/man: consistent switch-case ordering
Match __fish_print_help
2025-09-20 13:56:23 +02:00
Johannes Altmanninger
1fdf37cc4a __fish_echo: fully overwrite lines
With upcoming multi-line autosuggestions, when I run

	$ function foo
	    true
	  end

and type "function", then I'll get a suggestion for the above command.
Now if press "alt-w", it will echo "function - create a function"
and rewdraw the prompt below.  But the previous autosuggestion is
not cleared, so it will look weird like:

	johannes@abc ~/g/fish-shell> function foo
	function - create a function     true

Let's erase these lines before writing them.

There's an issue remaining: the first line of the autosuggestion
(i.e. "foo") is not erased.  Fortunately this is less annoying,
but it shows that __fish_echo needs more support from core.
2025-09-20 13:56:23 +02:00
Johannes Altmanninger
c0c7b364fc builtin status: rename buildinfo to build-info
See: https://github.com/fish-shell/fish-shell/pull/11726#discussion_r2347389523
2025-09-20 13:56:23 +02:00
Johannes Altmanninger
64bbd41f81 build_tools/release.sh: approve macos-codesign github environment 2025-09-20 13:56:23 +02:00
Johannes Altmanninger
955345dd5b completions/sudo-rs: wrap sudo for now, closes #11800 2025-09-20 13:56:23 +02:00
Johannes Altmanninger
012b507128 Workaround for embed-data debug builds on Cygwin
When running a debug build, rust-embed always sources files from disk.
This is currently broken with on Cygwin.

As a temporary workaround, use the "debug-embed" feature to actually
embed the files into the binary, like we do for release builds.

We can probably fix the rust-embed issue fairly easily.
I haven't checked.  For now, I think this hack is preferrable to
not having an easy way to make debug builds on Cygwin.  (CMake
files would need some changes, and I also hit some problems with
installation). At least this would have helped with investigating
https://github.com/msys2/msys2-runtime/issues/308
2025-09-20 13:56:23 +02:00
Johannes Altmanninger
142cec3a96 github release workflow: use a consistent order for static builds 2025-09-20 13:56:23 +02:00
Johannes Altmanninger
cdc57b97a3 Changelog updates 2025-09-20 13:56:23 +02:00
Johannes Altmanninger
bb916f8d73 Fix regression breaking self-insert of kitty shifted codepoint
Commit 50a6e486a5 (Allow explicit shift modifier for non-ASCII
letters, fix capslock behavior, 2025-03-30) delayed handling of kitty
keyboard protocol's shifted codepoints.  It does handle shifted
codepoints when matching keys to mappings; but it fails to handle
them in the self-insert code paths where we want to insert the text
represented by CharEvent::Key.
Fix it by resolving the shifted key.

Fixes #11813
2025-09-20 13:56:23 +02:00
Johannes Altmanninger
8d12dfe065 Move key codepoint computation to key event
For the next commit.
2025-09-20 13:56:23 +02:00
Johannes Altmanninger
9bf58abcae Changelog: move gettext and argparse changes to dedicated sections
By giving them dedicated headlines, they should be easier for users to skip
over if not interested.
2025-09-20 13:56:23 +02:00
Johannes Altmanninger
b325ff6992 Changelog: syntax fixes and rewording 2025-09-20 13:56:23 +02:00
Daniel Rainer
397969ddcc Add message localization tests
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
2025-09-20 13:56:23 +02:00
Daniel Rainer
bee1e122f9 Remove unused locale path code
The locale path was used to tell GNU gettext where to look for MO files
at runtime. Since we now embed the message catalog data into the
executable, we no longer need a locale path.

Part of #11726
2025-09-20 13:56:23 +02:00
Daniel Rainer
ad323d03b6 Switch to builtin gettext implementation
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 #11726
Closes #11583
Closes #11725
Closes #11683
2025-09-20 13:56:23 +02:00
Daniel Rainer
3a196c3a08 Use rsconf::warn! where appropriate
This is a more explicit variant than directly prefixing build script
output with `cargo:warning=`.

Part of #11726
2025-09-20 09:10:39 +02:00
Daniel Rainer
f34dfb8424 Allow 3-letter language codes
Some languages do not have a 2-letter code.
https://www.gnu.org/software/gettext/manual/html_node/Locale-Names.html

Part of #11726
2025-09-20 09:10:39 +02:00
Daniel Rainer
e2a9f0eb50 Make build_dir construction more readable
Part of #11726
2025-09-20 09:10:39 +02:00
Johannes Altmanninger
fb0f9842ae Update to Rust 1.90 2025-09-19 15:43:55 +02:00
Johannes Altmanninger
ff633bd744 github release workflow: make sure that last changelog entry isn't given spurious markup 2025-09-18 10:46:21 +02:00
Johannes Altmanninger
0d46c26988 github release workflow: work around trailing "---"-line in changelog
The extracted release notes trigger a sphinx warning

	/tmp/tmp.V6RGP92nc2/src/index.rst:6:Document may not end with a transition.

which we don't seem to get on the full CHANGELOG.rst.
Let's work around that for now.
2025-09-18 09:58:14 +02:00
Johannes Altmanninger
1840df96a2 build_tools/release.sh: relax assertion about changelog title
I'd like to move to a process where everything goes into master first,
and then flows downstream to any release branches (i.e. no merging
of Integration_* branches back into master).

The only thing we need to change for that is to add release notes for
patch releases eagerly on master.  That implies that we want to use
the actual version instead of ???.  (Only if something goes wrong
in the release process, we need to change this on both branches,
but that should happen too often.)
2025-09-18 09:37:44 +02:00
Johannes Altmanninger
3456b33050 build_tools/release.sh: push to the integration branch when all goes well
Also, ignore any "sendemail.to" Git config, and remove a temporary
statement in release notes.
2025-09-18 09:32:16 +02:00
Johannes Altmanninger
9a04c15894 Fix new-style bindings shadowing raw escape sequence bindings
Given

	bind up "echo user up, new notation"
	bind \e\[A "echo user up, legacy notation"

prior to b9d9e7edc6 (Match bindings with explicit shift
first, 2025-05-24), we prioritized the legacy notation because
input_mapping_insert_sorted() makes us try longer sequences first --
and "up" is only one key compared to the three-key legacy sequence.

This prioritization was broken in b9d9e7edc6, causing plugins that
update to the "bind up" notation to break users who haven't (#11803).

Even worse, it caused preset bindings to shadow user ones:

	bind --preset up "echo preset up, new notation"
	bind \e\[A "echo user up, legacy notation"

Restore backwards compatibility by treating matches against legacy
notation like exact matches again.
2025-09-18 09:28:57 +02:00
David Adam
63585a3e26 Merge branch 'Integration_4.0.6' 2025-09-17 14:38:19 +08:00
David Adam
aa1b64f955 build_tools: make tarball scripts use the build version 2025-09-17 13:56:22 +08:00
Piotr Kubaj
91ee45b0e1 path.rs: fix build on ARM / POWER
error[E0308]: mismatched types
   --> src/path.rs:749:13
    |
748 |         let remoteness = remoteness_via_statfs(
    |                          --------------------- arguments to this function are incorrect
749 |             libc::statfs,
    |             ^^^^^^^^^^^^ expected fn pointer, found fn item
    |
    = note: expected fn pointer `unsafe extern "C" fn(*const i8, _) -> _`
                  found fn item `unsafe extern "C" fn(*const u8, _) -> _ {libc::statfs}`
note: function defined here
   --> src/path.rs:712:12
    |
712 |         fn remoteness_via_statfs<StatFS, Flags>(
    |            ^^^^^^^^^^^^^^^^^^^^^
713 |             statfn: unsafe extern "C" fn(*const i8, *mut StatFS) -> libc::c_int,
    |             -------------------------------------------------------------------

error[E0308]: mismatched types
   --> src/path.rs:725:34
    |
725 |             if unsafe { (statfn)(path.as_ptr(), buf.as_mut_ptr()) } < 0 {
    |                         -------- ^^^^^^^^^^^^^ expected `*const i8`, found `*const u8`
    |                         |
    |                         arguments to this function are incorrect
    |
    = note: expected raw pointer `*const i8`
               found raw pointer `*const u8`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `fish` (lib) due to 2 previous errors
2025-09-16 20:03:40 +02:00
Johannes Altmanninger
f69c2a4d4a fish_config: silence error when compiled without embed-data 2025-09-13 15:14:13 +02:00
Johannes Altmanninger
3f7a576835 Support installing to nested subdirectory of CMAKE_BINARY_DIR
The only install directory that's not supported is
-DCMAKE_INSTALL_PREFIX=$CARGO_MANIFEST_DIR, but that's a bad idea
anyway since share/ is Git-tracked.
2025-09-13 15:12:23 +02:00
Johannes Altmanninger
75cedd8039 config_paths: extract variable 2025-09-13 15:12:23 +02:00
Johannes Altmanninger
a2c6e22d13 build.rs: don't define unused build environment variables
We set a lot of variables that are never used with
--feature=embed-data.  Remove them.  I don't think this change will
cause any problems with caching.
2025-09-13 15:12:23 +02:00
Johannes Altmanninger
aaf5ed7f11 build.rs: fix fallback PATH when embed-data is enabled
On a system where _CS_PATH is not defined (tested by removing that
code path), we get:

	$ cargo b && env -u PATH HOME=$PWD target/debug/fish -c 'set -S PATH'
	$PATH[1]: |.local//bin|
	$PATH[2]: |/usr/bin|
	$PATH[3]: |/bin|

The relative $PATH[1] makes no sense; probably it's an
accident. Restore the traditional $PATH[1]=/usr/local/bin.
2025-09-13 15:12:23 +02:00
Johannes Altmanninger
35d791ed49 config_paths: get rid of global variable, initialize locale predictably
Commit bf65b9e3a7 (Change `gettext` paths to be relocatable (#11195),
2025-03-30) made the locale directory (/usr/local/share/locale)
relocatable as well, so that "mv /usr/local /usr/local2" would not
break translations.

But this introduces a weird circular dependency, which was probably
the reason why the locale directory hadn't been relocatable:
1. option parsing might fail and print error messages, which should
   be localized, hence require detection of config paths
2. detection of config paths calls `FLOG`, which depends on options
   parsing (e.g. "-d config -o /tmp/log")

Since commit bf65b9e3a7, fish initializes the config paths
lazily, as soon as needed by translations.

When initializing config paths, we produce logs.  The logs are off by
default so its' fine in practical cases, but technically we should only
log things after we have handled things like FISH_DEBUG_OUTPUT.

Here's an example where the config directory initialization sneakily
injected by an error message's "wgettext_fmt!" causes logs to be
printed to the wrong file spuriously:

	$ FISH_DEBUG='*' FISH_DEBUG_OUTPUT=/tmp/log build/fish --unknown-arg
	config: exec_path: "./build/fish", argv[0]: "./build/fish"
	config: paths.sysconf: ./etc
	config: paths.bin: ./build
	config: paths.data: ./share
	config: paths.doc: ./user_doc/html
	config: paths.locale: ./share/locale
	fish: --unknown-arg: unknown option

Now we could handle "-d config", "-o", and FISH_DEBUG later, but
that would mean that in this example we don't get any logs at all,
which doesn't seem correct either.

Break the circular dependency by determining config paths earlier,
while making sure to log the config path locations only after parsing
options, because options might affect whether we want to log the
"config" category.

The global variable is only needed for locale, so use explicit argument
passing for everything else, as before.

While at it, make other binaries (fish_key_reader, fish_indent) use
the same localization logic as fish. This means that we need to tweak
the «ends_with("bin/fish")» check.

Closes #11785
2025-09-13 15:12:23 +02:00
Johannes Altmanninger
a7f8e294ba config_paths: remove rogue use of std::env::args() 2025-09-13 15:12:23 +02:00
Johannes Altmanninger
01ae00c653 config_paths: remove weird and redundant path handling
This duplicates work already done in get_executable_path().  No idea
why this was added.
2025-09-13 15:12:23 +02:00
Johannes Altmanninger
ee8a88a101 config_paths: rework logging a little
The executable path is used for embedded builds too, so let's log
it always.
2025-09-13 15:12:23 +02:00
Johannes Altmanninger
b4697231d7 config_paths: remove a comment
I'm not sure if setting PROGRAM_NAME based on argv[0] is a good idea.
2025-09-13 15:12:23 +02:00
Johannes Altmanninger
6cddceb37a config_paths: use immutable/SSA style for determining config paths
This logic is extremely confusing because it creates a ConfigPaths
object only to throw it away later. Fix that.
2025-09-13 15:12:23 +02:00
Johannes Altmanninger
8640ce8148 config_paths: embed-data has no doc dir
This makes no sense:

	$ target/debug/fish -d config
	config: paths.doc: .local/share/doc/fish

so remove it.

While at it, group config paths by whether they can be embedded.
2025-09-13 15:12:23 +02:00
Johannes Altmanninger
f7a2d56046 config_paths: model embed-data dichotomy better
Rather than having every single config path be an Option<Path>,
clarify that we define either all or nothing.

If we want to decide this at runtime, we'd use an enum; but it's all
known at compile time, so we can give the reader even more information.

Unfortunately this means that compile errors in non-embed-data
code paths might go unnoticed for a while, and rust-analyzer often
doesn't work in those code paths. But that's a general problem with
the compile-time feature, it seems orthodox to ifdef away as much
as possible.

There are some odd data paths that don't follow the "all or nothing",
the next commits will fix this.

Note that this breaks localization for target/debug/fish built with
embed-data. But as soon as fish was moved out of the repo, that was
already broken.
2025-09-13 15:12:23 +02:00
Johannes Altmanninger
cacb9f50b8 config_paths: use early return 2025-09-13 15:12:23 +02:00
Johannes Altmanninger
cef60fe585 config_paths: remove obsolete installable vars
Same reason as the grandparent commit.
2025-09-13 15:12:23 +02:00
Johannes Altmanninger
04a2398c90 config_paths: separate ifdef'd path logic into functions
No functional change, only reduce the number of times we check for
presence of the embed-data feature.

While at it, move ConfigPaths?
2025-09-13 15:12:23 +02:00
Johannes Altmanninger
f05ad46980 config_paths: remove vestiges of installable builds
Commit 3dc49d9d93 (Allow installable builds to be installed into a
specific path (#10923), 2024-12-22) added some ifdefs to use installed
config paths for installable builds that have already been installed.

The "installable" feature has been superseded by "embed-data"
which no longer uses config paths to retrieve files,
so remove those code paths. Further cleanup to follow.
2025-09-13 15:12:23 +02:00
Johannes Altmanninger
e9595d4817 config_paths: remove dead code trying to handle in-tree CMake builds
Assuming every in-tree build uses CMake, the source tree must
also be a valid build directory, so we already return in the
env!("FISH_BUILD_DIR") code path above.
2025-09-13 15:12:23 +02:00
Johannes Altmanninger
deabcf5478 config_paths: fix comment 2025-09-13 15:12:23 +02:00
Johannes Altmanninger
e73243b879 Reuse workspace_root() helper from fish-build-helper 2025-09-13 15:12:23 +02:00
Johannes Altmanninger
632b6582c5 builds.rs: canonicalize workspace root and build dir only when necessary
This means we can remove the unwrap() calls from fish-build-helper,
which paves the way for reusing it in the config_paths module.
2025-09-13 15:12:23 +02:00
Johannes Altmanninger
27db0e5fed Rename repo_root to workspace_root
This seems like a slightly better term
because I think it also applies to tarball.
Ref: https://github.com/fish-shell/fish-shell/pull/11785#discussion_r2335280389
2025-09-13 15:12:23 +02:00
Johannes Altmanninger
33735f507a Fix regression causing build/fish to use wrong config paths
Commit 8b102f2571 (Stop using Cargo's OUT_DIR,
2025-06-22) accidentally removed canonicalization of
FISH_BUILD_DIR=${CMAKE_BINARY_DIR}.  This means that if the path to
${CMAKE_BINARY_DIR} includes a symlink, ${CMAKE_BINARY_DIR}/fish will
wrongly use /usr/share/fish instead of ${CARGO_MANIFEST_DIR}/share.
Fix this and reintroduce the comment.
2025-09-13 15:12:23 +02:00
Johannes Altmanninger
bde8a5aa40 path: fix inconsistency in default PATH
path_get_path does not use "getconf PATH", for no apparent reason.
Fix that.
2025-09-13 15:12:23 +02:00
Johannes Altmanninger
e0cd9e2e0a bin/fish.rs: remove dead argv fallback
I think argv[0] is guaranteed to be non-null.
2025-09-13 15:12:23 +02:00
Johannes Altmanninger
7e1123fb42 bin/fish.rs: remove needless clone 2025-09-13 15:12:23 +02:00
Johannes Altmanninger
f7648757f1 autoload: simplify conditional compilation 2025-09-13 15:12:23 +02:00
Johannes Altmanninger
78d46f4b47 fish_indent.rst: remove missing debug options 2025-09-13 15:11:35 +02:00
Johannes Altmanninger
443956b8e3 ci: run clippy without --features=embed-data too
That configuration is already tested, but not clippy-checked yet.
This sometimes causes things like unused imports linger on master.
Let's at least enable clippy for stable Rust.

Also do the same build_tools/check.sh; since that script already runs
"cargo test --no-default-features", this shouldn't add much work,
though I didn't check that.
2025-09-13 15:10:24 +02:00
Johannes Altmanninger
a58cd12c4d Merge pull request #11779 2025-09-13 15:10:24 +02:00
Johannes Altmanninger
89883b791d checks/po-files-up-to-date.fish: mention how to update translations
As pointed out in
https://github.com/fish-shell/fish-shell/issues/11610#issuecomment-3240489072
2025-09-13 15:10:24 +02:00
Johannes Altmanninger
7706ce2e82 Merge pull request #11794 2025-09-13 15:10:24 +02:00
Daniel Rainer
027ea88477 Use deterministic timestamps for embedded data
We do not need timestamps of embedded files, so setting them to 0
reduces the potential for unwanted changes to the binary, allowing for
better build reproducibility.
2025-09-12 16:43:55 +02:00
Daniel Rainer
6cbd655b3d Update to rust-embed 8.7.2
This is the most recent version, which allows using the
`deterministic-timestamps` feature.
2025-09-12 16:43:03 +02:00
Johannes Altmanninger
529f722d2f build_tools/release.sh: fixes for updating fish-site
Also check that "cd fish-site && make && make new-release" doesn't
leave behind untracked files we're not aware of.  This implies that
this script ought to refuse to run if there are untracked files,
at least in fish-site.
2025-09-12 12:49:29 +02:00
Johannes Altmanninger
7619fa316c Release 4.0.6
Created by ./build_tools/release.sh 4.0.6
2025-09-12 11:47:41 +02:00
Johannes Altmanninger
e2005c64b3 Backport release-script related changes from master
Will commit these to master momentarily (#10449).
2025-09-12 11:47:01 +02:00
Johannes Altmanninger
f9dbb4d419 github workflows: actually include the tarballs in the release 2025-09-12 11:46:24 +02:00
Johannes Altmanninger
5e658bf4e9 Release automation script
Things that are not currently happening in this workflow:
- No GPG-signature on the Git tag
- No *.asc signature file for the tarball (or for any other release assets)
- No GPG-signed Debian and other OBS packages

To-do:
- remove the corresponding entries from
  https://github.com/fish-shell/fish-shell/wiki/Release-checklist
  and link to this workflow.
- Maybe add some testing (for the Linux packages)?.
- Let's hope that this doesn't cause security issues.

Usage:
1. run "build_tools/release.sh $version"; this will create and push
   a tag, which kicks off .github/workflows/release.yml
2. wait for the draft release to be created at
   https://github.com/fish-shell/fish-shell/releases/tags/$version
3. publish the draft (manually, for now). This should unblock the
   last part of the workflow (website updates).

Closes #10449

Incremental usage example:

	version=4.0.3
	repository_owner=fish-shell
	remote=origin
	cd ../fish-shell-secondary-worktree
	git tag -d $version ||:
	git push $remote :$version ||:
	git reset --hard origin/Integration_$version
	for d in .github build_tools; do {
		rm -rf $d
		cp -r ../fish-shell/$d .
		git add $d
	} done
	git commit -m 'Backport CI/CD'
	echo "See https://github.com/$repository_owner/fish-shell/actions"
	echo "See the draft release at https://github.com/$repository_owner/fish-shell/releases/$version"
	../fish-shell/build_tools/release.sh $version $repository_owner $remote
2025-09-12 11:42:59 +02:00
Johannes Altmanninger
9ada3e6c16 Group changelog entries 2025-09-12 11:14:52 +02:00
Johannes Altmanninger
0c7e7e3fd9 Add sphinx-markdown-builder for generating release notes
Without this, Sphinx refuses to use the "-b markdown" builder (see next commit).
2025-09-12 10:48:21 +02:00
Johannes Altmanninger
ebcb2eac68 github workflows staticbuild: use stable Rust on Linux
We use the MSRV for CI checks, and for deploying to old macOS.
But for static Linux builds , there should be no reason to use an
old Rust version.  Let's track stable.
2025-09-12 10:48:21 +02:00
Johannes Altmanninger
a7d50c1a62 CHANGELOG: minor updates 2025-09-12 10:48:21 +02:00
Johannes Altmanninger
6056b54ddb Rename build_tools/make_pkg.sh
pkg is a pretty subtle name?
2025-09-11 14:17:40 +02:00
Johannes Altmanninger
bdba2c227d CHANGELOG: update 2025-09-11 13:55:30 +02:00
Johannes Altmanninger
2563adfee1 github workflows: mac_codesign: clean up 2025-09-10 12:41:51 +02:00
Johannes Altmanninger
acad6e6a92 github workflows autolabel: remove stale milestone code
We look for a milestone that no longer exists.
Remove this until we find a solution.
2025-09-10 12:41:51 +02:00
Johannes Altmanninger
9faf78d269 github actions: fix warning about unexpected inputs
CI runs show warnings like

	ubuntu-32bit-static-pcre2
	Unexpected input(s) 'targets', valid inputs are ['']

This is about the rust-toolchain action, which is a composite action, see
https://docs.github.com/en/actions/tutorials/create-actions/create-a-composite-action
not a full workflow
https://docs.github.com/en/actions/how-tos/reuse-automations/reuse-workflows

Looks like composite actions specify inputs at top level.
Also they should not need «on: ["workflow_call"]».

The unexpected inputs are still forwared, so it happens to work.
Fix the warnings.
2025-09-10 12:41:51 +02:00
Johannes Altmanninger
201882e72a CHANGELOG: fix inline literal RST syntax 2025-09-09 07:46:31 +02:00
The0x539
b0565edf85 reader: add case-insensitive history autosuggest
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.
2025-09-08 22:26:02 -05:00
Johannes Altmanninger
80fff4439f Merge pull request #11784 2025-09-08 11:11:21 +02:00
Johannes Altmanninger
54c48e20d3 completions/ansible: update translations 2025-09-08 11:11:21 +02:00
Johannes Altmanninger
c1af3f2a8f Merge pull request #11783 2025-09-08 11:11:21 +02:00
Johannes Altmanninger
01d7f93917 Merge pull request #11782 2025-09-08 11:08:31 +02:00
Johannes Altmanninger
a9be7b0298 Merge pull request #11781 2025-09-08 11:07:56 +02:00
ookami
5d66e02412 create_manpage_completions.py: Fix options_parts_regex
Escape the dot before "RE".

Fix matching options containing "RE", e.g. ADDRESS.
2025-09-08 10:14:21 +08:00
Vincent Rischmann
18ed4f5f10 Add completion for become-password-file option 2025-09-07 00:51:36 +02:00
Lucas Garron
0f609e7054 build_tools/update_translations.fish --no-mo 2025-09-05 21:07:13 -07:00
Lucas Garron
b77ea98ee0 npm install completions: add --save-peer flag
It's unclear if there is a short flag, since `npm install --help` does not list all short flags.
2025-09-05 18:46:53 -07:00
Johannes Altmanninger
1db0ff9f77 Allow overriding __fish_update_cwd_osc to work around terminal bugs
See #11777

While at it, pull in the TERM=dumb check from master.

(cherry picked from commit 898cc3242b)
2025-09-05 09:39:57 +02:00
Johannes Altmanninger
898cc3242b Allow overriding __fish_update_cwd_osc to work around terminal bugs
See #11777
2025-09-05 09:38:25 +02:00
Nathan Chancellor
66940e8369 completions/systemctl: Handle --boot-loader-entry and --boot-loader-menu
systemd 242 added two new options to halt, poweroff, and reboot:

  --boot-loader-entry: Reboot to a specific boot loader entry
  --boot-loader-menu: Reboot into boot loader menu with specified
                      timeout

Add these to the systemctl completion so that it is easy to
interactively select available entries.

Signed-off-by: Nathan Chancellor <nathan@kernel.org>
2025-09-04 19:25:56 -07:00
Johannes Altmanninger
f98bf3d520 functions/man: use "command man", skipping functions
As reported in
https://github.com/fish-shell/fish-shell/issues/11767#issuecomment-3240198608,
the new "man" function uses "rm" which is sometimes overidden to do
"rm -i".

Same as d3dd9400e3 (Make sure the rm command and not a wrapper
function that could change its behaviour is used. 2006-12-12)

While at it, make sure that all users of __fish_mktemp_relative
1. return if mktemp fails
2. actually clean up their temporary directory -- except for help.fish
   which spawns an asynchronous browser window.
2025-08-31 17:33:24 +02:00
Johannes Altmanninger
90862c5c57 edit_command_buffer: remove dead code 2025-08-31 17:29:07 +02:00
Johannes Altmanninger
4abdc8716b share/functions/__fish_mktemp_relative: adopt argparse -u 2025-08-29 22:23:53 +02:00
Johannes Altmanninger
4ba070645d Merge pull request #11763 2025-08-29 22:23:53 +02:00
Johannes Altmanninger
4a12d57711 Merge pull request #11698 2025-08-29 22:23:52 +02:00
Johannes Altmanninger
8741e201de Install fish-terminal-compatibility man page
Not sure about whether "man fish-terminal-compatibility"; it's not
really meant for end-users, but it also doesn't hurt raise awareness
of the existence of this doc.

Either way, we should be consistent with embedded builds, where this
works since the parent commit.
2025-08-29 22:23:52 +02:00
Johannes Altmanninger
c3c3a9518c functions/man: fix for embedded fish-* man pages
"man abbr" works in embed-data builds,
but "man fish-faq" doesn't.

This is because it delegates to

	__fish_print_help fish-faq

which skips all lines until the NAME section:

	contains -- $name NAME; and set have_name 1

but the NAME section doesn't exist for this man pages, it only exists
for docs from doc_src/cmds/*.rst.

Let's use the "man" utility instead; this is also what the user
asked for.  Unfortunately we can't use "status get-file | man -l -"
because that's not supported on BSD man.  Note that man displays the
basename of the file, so make sure it looks good.
2025-08-29 22:23:52 +02:00
Johannes Altmanninger
0ebd41eb9f Extract function for calling mktemp
BSD mktemp doesn't support GNU mktemp's -t or --tmpdir option, so when
we want a named temporary file, we need to compute ${TMPDIR:-/tmp}
ourselves, see 5accc7c6c5 (Fix funced's tmpfile generation on OSX,
2016-05-23).

While at it, use template like "fish.XXXXXX"; seems like a good idea?

Take care to have edit_command_buffer use a pretty filename.
2025-08-29 22:23:27 +02:00
Johannes Altmanninger
35733a0f8d functions/man: allow "man !"
Analogous to the "! -h" code path.
2025-08-29 22:00:25 +02:00
Johannes Altmanninger
c1f6e0c03e CONTRIBUTING: mention sourcehut mailing list 2025-08-29 21:11:24 +02:00
Johannes Altmanninger
c36e7967e2 CONTRIBUTING: recommend build_tools/check.sh 2025-08-29 20:32:58 +02:00
Johannes Altmanninger
7f91e029fb CONTRIBUTING: remove mention of Coverity
Seems stale?
2025-08-29 20:32:58 +02:00
Johannes Altmanninger
ca131f7440 README: mention Python version also in build dependencies 2025-08-29 20:32:58 +02:00
Johannes Altmanninger
df3fc48a21 README: mention /bin/sh dependency
As reported in
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$39FQId4CHJ6yT8B4S4smD4MDbxp4pT8Eio-cGP0KoEU
we currently require "sh -c" for some background tasks.  Document this.
2025-08-29 20:32:58 +02:00
Johannes Altmanninger
9258275fe6 config_paths: fix compiled-in locale dir for installed, non-embed builds
Commit bf65b9e3a7 (Change `gettext` paths to be relocatable (#11195),
2025-03-30) broke the locale path.

Commit c3740b85be (config_paths: fix compiled-in locale dir,
2025-06-12) fixed what it calls "case 4", but "case 2" is also
affected; fix that. Before/after:

	$ ~/.local/opt/fish/bin/fish -d config
	paths.locale: /home/johannes/.local/opt/fish/share/fish/locale
	$ ~/.local/opt/fish/bin/fish -d config
	paths.locale: /home/johannes/.local/opt/fish/share/locale

See https://github.com/fish-shell/fish-shell/issues/11683#issuecomment-3218190662

(cherry picked from commit 21a07f08a3)
2025-08-29 19:29:03 +02:00
Isaac Oscar Gariano
6149ac4e40 Added a -C/--center option to string pad.
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.
2025-08-30 02:57:01 +10:00
Isaac Oscar Gariano
d82442991b Fix argparse documentation to make it clear that -n takes an argument. 2025-08-30 01:55:56 +10:00
Isaac Oscar Gariano
944cfd181e Added a -v/--validate option to fish_opt
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.
2025-08-30 01:55:56 +10:00
Isaac Oscar Gariano
007edac145 Make argparse reject supplying a validator for boolean flags
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.
2025-08-30 01:55:56 +10:00
Isaac Oscar Gariano
c403822fac Modified argparse to support one character long only options.
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).
2025-08-30 01:55:56 +10:00
Isaac Oscar Gariano
663430a925 Added support to fish_opt for defining a long flag with no short flag.
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.
2025-08-30 01:55:56 +10:00
Isaac Oscar Gariano
4db61ee117 Added argparse support for arguments with multiple optional values.
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.
2025-08-30 01:55:56 +10:00
Isaac Oscar Gariano
9d56cdbcbc Added a -U/--unknown-arguments option to argparse
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.
2025-08-30 01:55:56 +10:00
Isaac Oscar Gariano
8ae685cf27 Refactored argparse code by removing ArgCardinality type.
This just uses an ArgType and 'accumulate_args' bool in place of the old
ArgCardinality. Curently only one of the three kinds of an ArgType can
have both a true and false accumulate_args. But this will be extended to
two of three in a future commit.
2025-08-30 01:55:56 +10:00
Isaac Oscar Gariano
24eeed65a2 Added an -S/--strict-longopts option to argparse.
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.
2025-08-30 01:55:56 +10:00
Isaac Oscar Gariano
70dca1e136 Give a more helpful error when a boolean option has an argument.
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).
2025-08-30 01:55:56 +10:00
Isaac Oscar Gariano
c94eddaf4b Replaced all uses of argparse -i with argparse -u
This removes the functions/completions that were using the deprecated
--ignore-unknown option and replaces it with the new --move-unknown.

Although some of the code is now more verbose, it has improved the
functionality of two completions:
    the iwctl completion will now skip over options when detecting
        what subcommand is being used
    the ninja completion wil now handle -- correctly: if the completion
        internally invokes ninja, it will correctly interpret the users
        arguments as being arguments if they start with a - and occur
        after the --.
2025-08-30 01:10:03 +10:00
Isaac Oscar Gariano
51d16f017d Added a -u/--move-unknown option to argparse.
--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.
2025-08-29 23:10:02 +10:00
Isaac Oscar Gariano
5a7e5dc743 Make argparse separate known and unknown options that occur in a group together.
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).
2025-08-29 23:10:02 +10:00
Isaac Oscar Gariano
f780b01ac9 Added way to tell argparse to delete an option from $argv_opts.
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.
2025-08-29 23:10:02 +10:00
Isaac Oscar Gariano
ddcb1813a7 Clarified & fixed documentation for fish_opt options.
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
2025-08-29 23:10:02 +10:00
Isaac Oscar Gariano
e62abc460d Make argparse save parsed options in $argv_opts. (Fixes #6466)
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.
2025-08-29 23:10:02 +10:00
Isaac Oscar Gariano
e6b4f0a696 Stopped argparse tests from leaking local variables.
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.
2025-08-29 23:10:02 +10:00
Johannes Altmanninger
c0c9245d99 completions/java_home: fix version completion due to change of osascript default output
Apparently the last expression outputs to stdout.

Closes #11743
2025-08-27 10:01:51 +02:00
Isaac Oscar Gariano
f843d5bd34 Disable editor hard wrapping for .rst and .md files.
The .md and .rst files allready present do not hard wrap lines (the
style seems to be one line per paragraph, which could be a few hundred
characters long). So this makes those files have no line length limit,
instead of 100.
2025-08-27 10:01:51 +02:00
Johannes Altmanninger
6900b89c82 Add mark-prompt feature flag
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

See #11749
Also #11609
2025-08-27 09:17:35 +02:00
Johannes Altmanninger
4a9fd1bbbb completions/loginctl: accept alphabetic session names
systemd's session_id_valid accepts [a-zA-Z0-9], so allowing only
numbers is wrong.

Fixes #11754

While at it, correct the description; instead of
showing the leader PID, show the seat, which is probably
2025-08-27 08:34:16 +02:00
Daniel Rainer
7b8efe3105 Remove Optional annotation
The is inconsistent with the type annotation of `TestPass.duration_ms`.
The function is only called with `duration_ms` as an int, so there is no
need to declare it `Optional`.
2025-08-26 20:54:02 +08:00
Daniel Rainer
425d487de9 Remove redundant clones 2025-08-25 10:24:03 +02:00
Johannes Altmanninger
21a07f08a3 config_paths: fix compiled-in locale dir for installed, non-embed builds
Commit bf65b9e3a7 (Change `gettext` paths to be relocatable (#11195),
2025-03-30) broke the locale path.

Commit c3740b85be (config_paths: fix compiled-in locale dir,
2025-06-12) fixed what it calls "case 4", but "case 2" is also
affected; fix that. Before/after:

	$ ~/.local/opt/fish/bin/fish -d config
	paths.locale: /home/johannes/.local/opt/fish/share/fish/locale
	$ ~/.local/opt/fish/bin/fish -d config
	paths.locale: /home/johannes/.local/opt/fish/share/locale

Fixes https://github.com/fish-shell/fish-shell/issues/11683#issuecomment-3218190662
2025-08-25 10:11:01 +02:00
David Adam
67e8657109 debian packaging: don't remove Cargo.toml.orig files
Newer versions of cargo include the Cargo.toml.orig file when vendoring,
but dh_clean removes those by default. Try to disable this to fix the
package builds again.
2025-08-23 19:40:53 +08:00
Daniel Rainer
e96300b08e Build man pages in separate crate
Building man pages takes significant time due to Sphinx running for several
seconds, even when no updates are required. Previously, we added custom logic to
avoid calling `sphinx-build` if the inputs to `sphinx-build` had not changed
since a cached timestamp.

By moving this into its own crate, we can tell cargo to rebuild when the input
files changed and unrelated changes will have no effect on this crate. This
allows us to get rid of the custom code for tracking whether to recompile, while
keeping the effect of only calling `sphinx-build` when appropriate.

In order to avoid code duplication, a new `build-helper` crate is added,
which contains some functionality for use in `build.rs`.

Closes #11737
2025-08-22 09:14:56 +02:00
Daniel Rainer
32e5fa0c03 Stop depending on fish_indent for man pages
This allows building man pages without having `fish_indent` available, which is
useful because building man pages can happen during compilation of the fish
binaries, including `fish_indent`, resulting in an annoying cyclic dependency.

This change does not affect the generated man pages, at least with the current
config.
2025-08-22 09:12:10 +02:00
Daniel Rainer
e895f96f8a Do not rely on fish_indent for version in Sphinx
Depending on `fish_indent` when building docs is problematic because the docs
might get built before `fish_indent` is available. Furthermore, a version of
`fish_indent` which does not correspond to the current build might be used,
which would result in incorrect version information.

Use the `git_version_gen.sh` script instead to ensure up-to-date version
information without depending on build output.
2025-08-22 09:12:10 +02:00
Johannes Altmanninger
92f7063acb Use version=0.0.0 for unpublished crates
As discussed in #11737
2025-08-22 09:12:10 +02:00
Daniel Rainer
cd71801360 Use workspace dependencies exclusively
This allows us to track all dependencies in a single place and
automatically avoids using different versions of the same dependency in
different crates.

Sort dependencies alphabetically.

Closes #11751
2025-08-22 09:12:10 +02:00
Daniel Rainer
24898c61af Sync dependency versions of crates
This is done to allow merging all dependencies into workspace
dependencies.
2025-08-21 21:39:35 +02:00
Johannes Altmanninger
62b7c81052 Merge pull request #11742 2025-08-21 20:40:33 +02:00
Daniel Rainer
d32ce89889 Remove unnecessary rebuild paths
Cargo tracks normal Rust dependencies and automatically figures out if changes
to Rust source files, `Cargo.{toml,lock}`, and `build.rs` necessitate a rebuild,
and if so of what. In some cases these checks are smarter than just comparing
file modification times, so not specifying such paths explicitly can reduce the
amount of rebuilding which happens, without skipping necessary rebuilding.

ja: this reverts b2aaf1db52 (Rebuild if src changed, 2025-03-28) and
460b93a (Rebuild on changes relevant to build artifacts, 2025-03-30)
which tried to fix #11332 ("moving Git HEAD does not invalidate cargo
build results").  But that expectation is overbearing.  It's better
to only rebuild if something else of relevance to the build output
has changed.

Closes #11736
2025-08-21 20:40:33 +02:00
Henrik Hørlück Berg
16119377c3 Document --allow-empty, specify -r is only useful w/ -m
As noted in #11744
2025-08-21 00:06:24 +02:00
Kevin F. Konrad
5a45fec730 add completions for stackit CLI 2025-08-20 11:54:57 +02:00
Johannes Altmanninger
d26fd90efd Merge pull request #11741, closes #11741 2025-08-20 10:16:19 +02:00
Daniel Rainer
1c654f23af Put local dependencies in crates directory
With an increasing number of local dependencies, the repo root is getting
somewhat bloated. This commit moves the two current local dependencies into the
newly created `crates` directory, with the intention of using it for all future
local dependencies as well.

Some dependencies which are introduced by currently in-progress pull requests
will need modifications in order for relative paths to work correctly.
2025-08-20 10:16:19 +02:00
Johannes Altmanninger
b828822385 Merge pull request #11695 2025-08-20 10:14:34 +02:00
Johannes Altmanninger
e795ed4061 Merge pull request #11738 2025-08-20 10:14:27 +02:00
Johannes Altmanninger
3363d55ec4 staticbuild.yml: break up long line 2025-08-20 10:14:08 +02:00
Johannes Altmanninger
f8bfb7cb6b editorconfig: commit message line length is 72, not 80
This is more standard. Not sure how many people use editorconfig though.
2025-08-20 10:14:08 +02:00
Daniel Rainer
ce7733c75f Remove unnecessary parentheses
This was spotted by a lint on nightly Rust.
2025-08-19 00:26:21 +02:00
Johannes Altmanninger
feaec20de6 Run update_translations.fish 2025-08-18 14:10:46 +02:00
Daniel Rainer
514d34cc52 Add cargo feature for enabling gettext extraction
This allows having the proc macro crate as an optional dependency and speeds up
compilation in situations where `FISH_GETTEXT_EXTRACTION_FILE` changes, such as
the `build_tools/check.sh` script. Because we don't need to recompile on changes
to the environment variable when the feature is disabled, cargo can reuse
earlier compilation results instead of recompiling everything.
This speeds up the compilation work in `build_tools/check.sh` when no changes
were made which necessitate recompilation.
For such runs of `build_tools/check.sh`, these changes reduce the runtime on my
system by about 10 seconds, from 70 to 60, approximately.
The difference comes from the following two commands recompiling code without
the changes in this commit, but not with them:
- `cargo test --doc --workspace`
- `cargo doc --workspace`
2025-08-18 10:37:59 +02:00
Daniel Rainer
367696b346 Remove unnecessary into_iter call
Starting with Rust 1.90, this `into_iter` call triggers the
`clippy::useless_conversion` lint.
2025-08-17 20:20:09 -07:00
Daniel Rainer
70a9327858 Do not unwrap after checking with is_err
Doing so results in the `clippy::unnecessary_unwrap` lint starting with Rust
1.90 (in beta at the moment).
2025-08-17 20:20:09 -07:00
idealseal
a766c44a18 feat(comp): update networkctl completions 2025-08-17 20:17:00 -07:00
Peter Ammon
13d9aa0002 Changelog PR 11729 2025-08-16 11:22:45 -07:00
Bryce Berger
9273f352a0 allow psub --fifo --suffix ... 2025-08-15 15:02:44 -04:00
Johannes Altmanninger
79135c6c82 Merge pull request #11713, closes #11713 2025-08-15 18:11:07 +02:00
Daniel Rainer
5de43a4e86 Call fsync after appending to history file
This is an attempt to eliminate history file corruption as described in
https://github.com/fish-shell/fish-shell/issues/10300.
In particular, issues raised in
https://github.com/fish-shell/fish-shell/issues/10300#issuecomment-2567063654
can benefit from such synchronization.
2025-08-15 18:10:20 +02:00
Daniel Rainer
188282a27b Don't redundantly unlink() temporary file after renaming
There is an unlikely issue if two shells are concurrently rewriting the
history file:
- fish A runs rename("fish_history.DEADBEEF") (rewriting a history file with)
- fish B starts rewriting the history file; since "fish_history.DEADBEEF" no longer exists, it can in theory use that filename
- fish A runs wunlink("fish_history.DEADBEEF"), destroying fish B's work

Fix this by not calling wunlink() iff we successfully rename it.

[ja: add commit message and fix "!do_save" case]
2025-08-15 17:50:04 +02:00
Johannes Altmanninger
f59e5884bf Merge pull request #11714
Closes #11714
2025-08-15 17:37:34 +02:00
Johannes Altmanninger
51dcadf7c6 completions/makepkg: remove stale --pkg option
Closes #11724
2025-08-15 17:24:18 +02:00
Daniel Rainer
ba2500211b Call fsync and close tmpfile before rename
This is another attempt at eliminating file corruption, primarily in connection
to the history file, as observed in
https://github.com/fish-shell/fish-shell/issues/10300.

Calling `fsync` and closing the tmpfile should ensure that when the renaming
happens, the file content and metadata are already in persistent storage.

Some background can be found in the following links, which were pointed out in
https://github.com/fish-shell/fish-shell/issues/10300#issuecomment-2567063654:
https://www.comp.nus.edu.sg/~lijl/papers/ferrite-asplos16.pdf
https://archive.kernel.org/oldwiki/btrfs.wiki.kernel.org/index.php/FAQ.html#What_are_the_crash_guarantees_of_overwrite-by-rename.3F
2025-08-15 17:24:02 +02:00
Johannes Altmanninger
491ffb356b Merge pull request #11727 2025-08-15 16:48:34 +02:00
Daniel Rainer
b0ae11e769 Write only once when appending items
Building a buffer in advance and writing it once all items are serialized into
the buffer makes for simpler code, makes it easier to ensure that
`self.first_unwritten_new_item_index` is only updated if writing succeeded, and
it actually matches the previous behavior of the code in most realistic cases,
since previously there was only more than one `write_all` call if the serialized
items took up more than `HISTORY_OUTPUT_BUFFER_SIZE` bytes (64 * 1024), which
seems unlikely to occur during normal use, where mostly just a single item will
be appended.
2025-08-15 16:26:52 +02:00
Daniel Rainer
20e268a75c Clear file state earlier
This should not result in behavioral changes in the code, but it eliminates some
redundant variables and is a step in refactoring the function such that early
returns via `?` become sound.

Remove the `drop` since the lock will be dropped at this point anyway, there is
no need to be explicit about it.
2025-08-15 16:26:03 +02:00
Daniel Rainer
9c4c28da9d Use updated file id
This restores behavior from before f438e80f9b.
The file id changes when data is written to the file, so it needs to be updated
with data obtained after the updates to the file are completed.
2025-08-15 16:26:03 +02:00
Johannes Altmanninger
8219dd8af6 Merge pull request #11715 2025-08-15 16:19:03 +02:00
Johannes Altmanninger
781791c00c Revert "Add rust-toolchain.toml"
By default, we make every rustup user use our pinned version.  This might
not be ideal at this point, for a few reasons:
1. we don't have automatic Rust updates yet (see the parent commit),
   so this might unnecessarily install an old version. As a contributor,
   this feels irritating (newer versions are usually strictly better).
2. it will use more bandwidth and perhaps other resources during "git-bisect"
   scenarios
3. somehow rustup will download things redundantly; it will download "1.89.0"
   and "stable" even if they are identical. The user will need to clean
   those up at some point, even if they didn't add them explicitly.

See also
https://github.com/fish-shell/fish-shell/pull/11712#issuecomment-3165388330

Part of the motivation for rust-toolchain.toml is probably the regular
(every 6 weeks) failures due to the update check, but that failure has been
removed in the parent commit.

The other motivation ("fix the issue of local compiles running into lint
warnings from newer compilers") is a fair point but I think we should rather
fix warnings quickly.

Let's remove rust-toolchain.toml again until we have more agreement on what
we should do.

This reverts commits
* f806d35af8 (Ignore rust-toolchain.toml in CI, 2025-08-07)
* 9714b98262 (Explicitly use fully qualified rust version numbers, 2025-08-07)
* 921aaa0786 (Add rust-toolchain.toml, 2025-08-07)

Closes #11718
2025-08-15 16:10:18 +02:00
Johannes Altmanninger
d93fc5eded Revert "build_tools/check.sh: check that stable rust is up-to-date"
As reported in #11711 and #11712, the update-checks make check.sh automatically
fail every 6 weeks, so it pressures people into updating Rust, and (what's
worse), updating fish's pinned Rust version, even when that's not relevant
to their intent (which is to run `clippy -Dwarnings` and all other checks).

The update-checks were added as a "temporary" solution to make sure that
our pinned version doesn't lag too far behind stable, which gives us an
opportunity to fix new warnings before most contributors see them.

As suggested in #11584, reasonable solutions might be either of:
1. stop pinning stable Rust and rely on beta-nightlies to fix CI failures early
2. use renovatebot or similar to automate Rust updates

Until then, remove the update check to reduce friction.
I'll still run it on my machine.

This reverts commit 6d061daa91.
2025-08-15 15:08:48 +02:00
Daniel Rainer
b2dfb3fd6e Add completions for single-letter cargo aliases 2025-08-15 03:09:28 +02:00
Daniel Rainer
55122b127c Wrap renaming code in function
These changes are not intended to change any behavior. They are done to
facilitate closing the tmpfile before renaming, which is required for
correctness on some filesystems (at least btrfs). Using a `ScopeGuard` which
unlinks when the file is closed/dropped does not work in this context, so the
relevant code is wrapped in a function and the tmpfile is unlinked after the
function returns.
2025-08-12 19:50:53 +02:00
brennenputh
0adcbfa2ac Resolve review comments 2025-08-11 20:32:16 -04:00
Johannes Altmanninger
51fd00c98f Merge pull request #11717 2025-08-10 18:59:30 +02:00
Johannes Altmanninger
c123c4e866 Merge pull request #11691 2025-08-10 18:40:01 +02:00
Johannes Altmanninger
9003835452 Merge pull request #11701 2025-08-10 17:12:50 +02:00
Trevor Bender
cf044038e0 fix typo in completions.rst 2025-08-10 07:49:10 -04:00
brennenputh
6561a1d6ba Add distrobox completion script 2025-08-08 20:48:20 -04:00
Xiretza
894d4ecc53 Update to Rust 1.89, address newly added lints 2025-08-07 21:48:17 +00:00
Xiretza
f806d35af8 Ignore rust-toolchain.toml in CI
We set a specific default toolchain with dtolnay/rust-toolchain, we don't want
it to be overridden by the config intended for devs.
2025-08-07 21:47:36 +00:00
Xiretza
9714b98262 Explicitly use fully qualified rust version numbers
The action expands these internally, but then rust-toolchain.toml is interpreted
literally, and 1.88 is technically a different toolchain from 1.88.0.
2025-08-07 21:28:34 +00:00
Xiretza
921aaa0786 Add rust-toolchain.toml
This ensures that, by default, developers use the toolchain that is also tested
in CI, avoiding spurious warnings from lints added in new compiler versions.
2025-08-07 21:13:32 +00:00
Saeed M Rad
45bb8f535b funced: pretend copied functions are defined interactively
After #9542, the format for `functions -Dv` was changed for copied
functions.

```diff
-stdin
-n/a
+[path to copy location]
+[path to original definition]
 [and a few more lines]
```

Some components were (and perhaps are) still expecting the old format,
however. After a search, it looks like `funced` and `fish_config` are
the only two functions using `functions -D` and `functions -Dv` in this
repo (none are using `type -p`).

As noted in issue #11614, `funced` currently edits the file which
copies the given copied function. Another option was to make `funced`
edit the file which originally defined the function. Since the copied
function would not have been updated either way, I modified `funced` so
it would pretend that the copied function was defined interactively,
like it was before.

I did not modify `fish_config`, since it was only used for preset
prompts in the web config, none of which used `functions --copy`.
(Moreover, I believe it would have behaved correctly, since the preset
would not have had to define the function, only copy it.)

Fixes issue #11614
2025-08-07 10:19:42 +00:00
Bacal Mesfin
fa68770c16 Fix missed bottom right artifact 2025-08-04 13:01:19 -04:00
Bacal Mesfin
4b736fd92b Fix fish.png artifacts
The fish.png doc image has grey pixel artifacts in the
top-left, top-right, and bottom-right corners.

This patch takes the original image from 3a5b096
removes the artifacts, and compresses it with squoosh
to a similar file size.
2025-08-03 07:06:42 -04:00
Johannes Altmanninger
54e8ad7e90 Merge pull request #11623 2025-08-03 08:00:18 +02:00
Kid
944da7dba9 Fix copy paste error 2025-08-02 19:39:54 +08:00
Kid
c9945f3439 Use __fish_cache_sourced_completions 2025-08-02 18:05:46 +08:00
Kid
e8b2767dcc Add completion for pnpm 2025-08-02 18:00:23 +08:00
Johannes Altmanninger
5c216f48a3 Attempt to fix Opensuse Leap 15.6 nightlies
This has been failing because it uses Python 3.6.  Until we have figured
out when we can roll platform off (#11679), let's try to fix this.  Untested.
2025-08-02 11:07:22 +02:00
Johannes Altmanninger
320b8235ed Update README to reflect regained Cygwin/Msys2 support 2025-08-02 11:07:22 +02:00
Johannes Altmanninger
9c0086b7af Backport default alt-delete binding
This is standard on macOS and in chrome/firefox.

On master, this was sneakily added in
2bb5cbc959 (Default bindings for token movements v2, 2025-03-04)
and before that in
6af96a81a8 (Default bindings for token movement commands, 2024-10-05)

Ref: https://lobste.rs/s/ndlwoh/wizard_his_shell#c_qvhnvd
2025-08-02 09:53:22 +02:00
Johannes Altmanninger
f218cf2f38 Merge pull request #11686 2025-08-02 09:19:48 +02:00
Johannes Altmanninger
8158c227c3 Merge pull request #11672 2025-08-02 09:19:48 +02:00
Johannes Altmanninger
2549334bae Merge pull request #11693 2025-08-02 09:19:48 +02:00
ndrew222
ec60bf1898 added completions for glow 2025-07-30 13:25:12 +08:00
JJ
17e0f3d96f Add example of string manipulation to prompt_pwd 2025-07-28 19:55:18 -07:00
Branch Vincent
b4b0fc08da completions: add container 2025-07-26 12:13:05 -07:00
Johannes Altmanninger
e200abe39c __fish_seen_subcommand_from: fix regression causing false negatives given multiple arguments
Fixes 2bfa7db7bc (Restructure __fish_seen_subcommand_from, 2024-07-07)
Fixes #11685

(cherry picked from commit 4412164fd4)
2025-07-26 20:36:53 +02:00
Johannes Altmanninger
6d061daa91 build_tools/check.sh: check that stable rust is up-to-date
As suggested in
https://github.com/fish-shell/fish-shell/discussions/11584#discussioncomment-13674983
In future, we should probably make updates automatic again.
2025-07-26 20:36:03 +02:00
Johannes Altmanninger
4412164fd4 __fish_seen_subcommand_from: fix regression causing false negatives given multiple arguments
Fixes 2bfa7db7bc (Restructure __fish_seen_subcommand_from, 2024-07-07)
Fixes #11685
2025-07-26 17:08:15 +02:00
Johannes Altmanninger
0c8f1f4220 Fix async-signal safety in SIGTERM handler
Cherry-picked from
- 941701da3d (Restore some async-signal discipline to SIGTERM, 2025-06-15)
- 81d45caa76e (Restore terminal state on SIGTERM again, 2025-06-21)

Also, be more careful in terminal_protocols_disable_ifn about accessing
reader_current_data(), as pointed out in 65a4cb5245 (Revert "Restore terminal
state on SIGTERM again", 2025-07-19).

See #11597
2025-07-26 13:09:18 +02:00
Johannes Altmanninger
e593da1c2e Increase timeout when reading escape sequences inside paste/kitty kbd
Historically, fish has treated input bytes [0x1b, 'b'] as alt-b (rather than
"escape,b") if the second byte arrives within 30ms of the first.

Since we made builtin bind match key events instead of raw byte sequences,
we have another place where we do similar disambiguation: when we read keys
such as alt-left ("\e[1;3D"), we only consider bytes to be part of this
sequence if stdin is immediately readable (actually "readable after a 1ms
timeout" since e1be842 (Work around torn byte sequences in qemu kbd input
with 1ms timeout, 2025-03-04)).

This is technically wrong but has worked in practice (for Kakoune etc.).

Issue #11668 reports two issues on some Windows terminals feeding a remote
fish shell:
- the "bracketed paste finished" sequence may be split into multiple packets,
  which causes a delay of > 1ms between individual bytes being readable.
- AutoHotKey scripts simulating seven "left" keys result in sequence tearing
  as well.

Try to fix the paste case by increasing the timeout when parsing escape
sequences.

Also increase the timeout for terminals that support the kitty keyboard
protocol.  The user should only notice this new delay after pressing one of
escape,O, escape,P, escape,[, or escape,] **while the kitty keyboard protocol
is disabled** (e.g. while an external command is running).  In this case,
the fish_escape_delay_ms is also virtually increased; hopefully this edge
case is not ever relevant.

Part of #11668

(cherry picked from commit 30ff3710a0)
2025-07-25 18:29:19 +02:00
Johannes Altmanninger
30ff3710a0 Increase timeout when reading escape sequences inside paste/kitty kbd
Historically, fish has treated input bytes [0x1b, 'b'] as alt-b (rather than
"escape,b") if the second byte arrives within 30ms of the first.

Since we made builtin bind match key events instead of raw byte sequences,
we have another place where we do similar disambiguation: when we read keys
such as alt-left ("\e[1;3D"), we only consider bytes to be part of this
sequence if stdin is immediately readable (actually "readable after a 1ms
timeout" since e1be842 (Work around torn byte sequences in qemu kbd input
with 1ms timeout, 2025-03-04)).

This is technically wrong but has worked in practice (for Kakoune etc.).

Issue #11668 reports two issues on some Windows terminals feeding a remote
fish shell:
- the "bracketed paste finished" sequence may be split into multiple packets,
  which causes a delay of > 1ms between individual bytes being readable.
- AutoHotKey scripts simulating seven "left" keys result in sequence tearing
  as well.

Try to fix the paste case by increasing the timeout when parsing escape
sequences.

Also increase the timeout for terminals that support the kitty keyboard
protocol.  The user should only notice this new delay after pressing one of
escape,O, escape,P, escape,[, or escape,] **while the kitty keyboard protocol
is disabled** (e.g. while an external command is running).  In this case,
the fish_escape_delay_ms is also virtually increased; hopefully this edge
case is not ever relevant.

Part of #11668
2025-07-25 18:28:21 +02:00
Johannes Altmanninger
6666c8f1cd Block interrupts and uvar events while decoding key
readb() has only one caller that passes blocking=false: try_readb().
This function is used while decoding keys; anything but a successful read
is treated as "end of input sequence".

This means that key input sequences such as \e[1;3D
can be torn apart by
- signals (EINTR) which is more likely since e1be842 (Work around torn byte
  sequences in qemu kbd input with 1ms timeout, 2025-03-04).
- universal variable notifications (from other fish processes)

Fix this by blocking signals and not listening on the uvar fd.  We do something
similar when matching key sequences against bindings, so extract a function
and use it for key decoding too.

Ref: https://github.com/fish-shell/fish-shell/issues/11668#issuecomment-3101341081
(cherry picked from commit da96172739)
2025-07-25 18:21:27 +02:00
Johannes Altmanninger
3e61036911 Revert "Change readch() into try_readch()"
try_readch() was added to help a fuzzing harness, specifically to avoid a
call to `unreachable!()` in the NothingToRead case.  I don't know much about
that but it seems like we should find a better way to tell the fuzzer that
this can't happen.

Fortunately the next commit will get rid of readb()'s "blocking" argument,
along the NothingToRead enum variant. So we'll no longer need this.

This reverts commit b92830cb17.

(cherry picked from commit fb7ee0db74)
2025-07-25 18:21:27 +02:00
Johannes Altmanninger
f23a479b81 Reduce MaybeUninit lifetime
(cherry picked from commit 137f220225)
2025-07-25 18:21:27 +02:00
王宇逸
e274ff41d0 Use uninit instead of zeroed (src/input_common.rs)
(cherry picked from commit 7c2c7f5874)
2025-07-25 18:21:27 +02:00
Johannes Altmanninger
d2af306f3d Fix some unused-ControlFlow warnings 2025-07-25 18:11:04 +02:00
Johannes Altmanninger
da96172739 Block interrupts and uvar events while decoding key
readb() has only one caller that passes blocking=false: try_readb().
This function is used while decoding keys; anything but a successful read
is treated as "end of input sequence".

This means that key input sequences such as \e[1;3D
can be torn apart by
- signals (EINTR) which is more likely since e1be842 (Work around torn byte
  sequences in qemu kbd input with 1ms timeout, 2025-03-04).
- universal variable notifications (from other fish processes)

Fix this by blocking signals and not listening on the uvar fd.  We do something
similar when matching key sequences against bindings, so extract a function
and use it for key decoding too.

Ref: https://github.com/fish-shell/fish-shell/issues/11668#issuecomment-3101341081
2025-07-25 17:56:49 +02:00
Johannes Altmanninger
fb7ee0db74 Revert "Change readch() into try_readch()"
try_readch() was added to help a fuzzing harness, specifically to avoid a
call to `unreachable!()` in the NothingToRead case.  I don't know much about
that but it seems like we should find a better way to tell the fuzzer that
this can't happen.

Fortunately the next commit will get rid of readb()'s "blocking" argument,
along the NothingToRead enum variant. So we'll no longer need this.

This reverts commit b92830cb17.
2025-07-25 17:56:49 +02:00
Johannes Altmanninger
137f220225 Reduce MaybeUninit lifetime 2025-07-25 17:56:49 +02:00
Johannes Altmanninger
f8b9fa19e8 Merge pull request #11681 2025-07-25 17:56:39 +02:00
A2uria
4508b5b0db Handle cygwin select() returning -1 with errno 0 2025-07-25 22:45:01 +08:00
A2uria
d8e5821a3b Use \n as end of line on windows 2025-07-25 18:44:42 +08:00
A2uria
4162e0efad Fix path_remoteness on cygwin 2025-07-25 18:41:40 +08:00
Johannes Altmanninger
0e7c7f1745 Remove unused import
(cherry picked from commit 07ff4e7df0)
2025-07-25 11:57:21 +02:00
Johannes Altmanninger
07ff4e7df0 Remove unused import 2025-07-25 11:55:10 +02:00
Johannes Altmanninger
3fada80553 Fix regression causing \e[ to be interpreted as ctrl-[
Fixes 3201cb9f01 (Stop parsing invalid CSI/SS3 sequences as alt-[/alt-o,
2024-12-30).

(cherry picked from commit 43d583d991)
2025-07-25 11:49:07 +02:00
Johannes Altmanninger
43d583d991 Fix regression causing \e[ to be interpreted as ctrl-[
Fixes 3201cb9f01 (Stop parsing invalid CSI/SS3 sequences as alt-[/alt-o,
2024-12-30).
2025-07-25 11:47:18 +02:00
Johannes Altmanninger
d69886efe0 completions/protontricks: coding style, translations 2025-07-25 11:15:05 +02:00
Johannes Altmanninger
bd8cc6d317 Merge pull request #11375 2025-07-25 11:10:38 +02:00
Johannes Altmanninger
9c5b3f3d57 Merge pull request #11674 2025-07-25 11:03:53 +02:00
Johannes Altmanninger
5970f34a60 Retry some writes on EINTR again
I guess?
Fixes f0e007c439 (Relocate tty metadata and protocols and clean it up,
2025-06-19).
2025-07-25 10:23:48 +02:00
Johannes Altmanninger
eaa837effa Refresh TTY timestamps again in most cases
See commit 081c3282b7 (Refresh TTY timestamps also in some rare cases,
2025-01-15) and others.
Fixes d27f5a5293 (Adopt TtyHandoff in remaining places, 2025-06-21)
Fixes #11671
2025-07-25 10:23:48 +02:00
Johannes Altmanninger
e52cf2f6a7 Try to restore TTY protocols more reliably after SIGTERM
We might
1. set TTY_PROTOCOLS_ACTIVE to false
2. receive `SIGTERM`
3. due to 1 fail to disable TTY protocols

Fix this by making sure that the disabling of protocols happens-before we
set TTY_PROTOCOLS_ACTIVE to false.

See 37c04745e6 (Avoid potential contention on SIGTERM while enabling terminal
protocols, 2024-10-08).
Fixes d27f5a5293 (Adopt TtyHandoff in remaining places, 2025-06-21)
2025-07-25 10:23:48 +02:00
Johannes Altmanninger
8c7568c0cb Reapply "Disable focus reporting on non-tmux again for now" 2024-04-18
Reapply bdd478bbd0. Amendment to f0e007c439 (Relocate tty metadata and
protocols and clean it up, 2025-06-19).
2025-07-25 10:23:48 +02:00
Johannes Altmanninger
07979782a6 Fix iTerm2 detection on non-iTerm2 terminals
Fixes f0e007c439 (Relocate tty metadata and protocols and clean it up,
2025-06-19).
2025-07-25 10:23:48 +02:00
Johannes Altmanninger
59b43986e9 build_tools/style.fish: fail if formatters are not available
build_tools/check.sh is supposed to fail on formatting violations.  I don't
think we have a good reason for running build_tools/style.fish outside
check.sh.

black is the only formatter not versioned in CI -- but we can probably
satisfy all realistic versions.

Ref: https://github.com/fish-shell/fish-shell/pull/11608#discussion_r2173176621
2025-07-25 10:23:48 +02:00
phisonate
51f3722e02 Fix funced to not expand or execute function name when interactive
Due to unnecessary quotes in the prompt command given to `read` by `funced` when
editing a function interactively (using `-i`), the name of the function to edit
would be evaluated, expanded and even executed (when using command substitution
for example), which is at least annoying when using unusual but valid and
allowed function names like '*' or 'head (cat)'. This commit delays the function
name expansion so that this should no longer happen.
2025-07-24 01:03:02 +02:00
Daniel Rainer
2c11bfa532 Avoid running sphinx-build if possible
Despite the caching in `sphinx-build`, it takes several seconds to run
`sphinx-build` when no rebuilding is necessary, which slows down build times
significantly.

Add custom logic to `build.rs` to avoid calling `sphinx-build` if deemed
unnecessary based on the mtime of the source files.
This is done by writing the most recent timestamp of the source files into a
dedicated file, and only calling `sphinx-build` (and updating the timestamp)
when a cached timestamp is older than the most recent source file mtime.
2025-07-23 18:37:07 +02:00
Daniel Rainer
eae633c4af Extract SPHINX_DOC_SOURCES and handle rebuilds
The sources for Sphinx documentation builds include `CHANGELOG.rst` and
`CONTRIBUTING.rst`. Use `SPHINX_DOC_SOURCES` to clarify this and avoid
repetition.

Rebuilds should happen for debug builds as well, since rebuilding is required
for updating the man files.
2025-07-23 18:28:54 +02:00
Daniel Rainer
ecc004a122 Rebuild if gettext-extraction changed 2025-07-23 18:28:54 +02:00
Peter Ammon
db0f9c1d53 Minor refactoring of make_wait_handle 2025-07-20 13:40:22 -07:00
Peter Ammon
c9901398ed Switch DISOWNED_PIDS from MainThread to Mutex
Preparation for concurrent execution. These can be reaped on any thread.
2025-07-19 17:56:58 -07:00
Peter Ammon
6181ba3b56 Fix an 1.70 clippy 2025-07-19 16:49:51 -07:00
Peter Ammon
d27f5a5293 Adopt TtyHandoff in remaining places
This adopts the tty handoff in remaining places. The idea is to rationalize
when we enable and disable tty protocols (such as CSI-U).

In particular this removes the tty protocol disabling in Parser::eval_node
- that is intended to execute pure fish script and should not be talking to
the tty.
2025-07-19 16:04:13 -07:00
Peter Ammon
c1d165de9d Adopt TtyHandoff in fish_key_reader
Prepare to remove terminal_protocols_enable/disable_ifn
2025-07-19 16:04:13 -07:00
Peter Ammon
f0e007c439 Relocate tty metadata and protocols and clean it up
fish-shell attempts to set up certain terminal protocols (bracketed paste,
CSI-U) while it is in control of the tty, and disable these when passing
off the tty to other processes. These terminal protocols are enabled or
disabled by emitting certain control sequences to the tty.

Today fish-shell does this in a somewhat haphazard way, tracking whether
the protocols are enabled or disabled. Functions like `Parser::exec_node`
then just toggle these, causing data to be written to the terminal in
unexpected places. In particular this is very bad for concurrent execution:
we don't want random threads talking to the tty.

Fortunately we have a controlled place where we can muck with the tty:
`TtyTransfer` which controls handoff of ownership to child processes (via
`tcsetpgrp`). Let's centralize logic around enabling and disabling terminal
protocols there. Put it in a new module and rename it to `TtyHandoff` which is a
little nicer.

This commit moves code around and does some cleanup; it doesn't actually
pull the trigger on centralizing the logic though. Next commit will do that.
2025-07-19 16:04:13 -07:00
Peter Ammon
65a4cb5245 Revert "Restore terminal state on SIGTERM again"
This reverts commit 1d6fa258f6.

This reintroduces commit 941701da3d, which was then reverted in
941701da3d8; this commit reverts the revert to reintroduce 941701da3d.

The reason is that the existing logic in terminal_protocols_disable_ifn does a
bunch of stuff for which nobody has thought about its signal safety, such as
accessing the reader stack (clearly not async signal safe).
Even functions which happen to be safe now may become unsafe in the future.

This is just the nature of signal handling code. We must ensure that only
async-signal safe syscalls are run, and only functions which are themselves
async-signal safe, which we (try) to designate with the "safe_" prefix.
2025-07-19 15:37:00 -07:00
rosavi
c7262d6c05 Add completions for cpan and t-rec
Closes #11647
2025-07-19 22:15:24 +02:00
Johannes Altmanninger
f3c264722d Merge pull request #11666 2025-07-19 22:15:24 +02:00
Johannes Altmanninger
39742cafa0 Merge pull request #11663 2025-07-19 22:15:24 +02:00
Johannes Altmanninger
295d2bd218 update translations for completions/fish_indent 2025-07-19 22:15:24 +02:00
Johannes Altmanninger
3588b41744 Merge pull request #11662 2025-07-19 22:15:24 +02:00
Johannes Altmanninger
82e3311756 Merge pull request #11659 2025-07-19 22:15:24 +02:00
Johannes Altmanninger
b611c96cdd Merge pull request #11654 2025-07-19 22:15:24 +02:00
Johannes Altmanninger
1d6fa258f6 Restore terminal state on SIGTERM again
Commit 941701da3d (Restore some async-signal discipline to SIGTERM,
2025-06-15) made two changes
1. removed a mutex lock in signal handler (regression from 55fd43d86c
   (Port reader, 2023-12-22))
2. removed some SIGTERM cleanup

I'm not sure what's the reason for 2, so let's revert it I guess.  This code
path already uses FLOG_SAFE for async-signal safety.

There is an avoidable panic when `Outputter::stdoutput()` is already
borrowed. Fix that.

Closes #11597
2025-07-19 22:15:24 +02:00
Johannes Altmanninger
6312b1dbd8 Format test_driver.py 2025-07-19 22:15:24 +02:00
Peter Ammon
5fa2f62536 test_driver: increase open file limit
Prevent failures due to file handle exhaustion.
2025-07-19 11:14:37 -07:00
Peter Ammon
bbf7568ebd test_driver.py: Properly report exceptions
If a test fails by throwing an exception (in this case, "Too many open files")
then that exception would propagate, be uncaught, and then the remaining tests
would not be await'ed, leading to a hang.

Fix this by properly catching and reporting exceptions.
2025-07-19 11:01:48 -07:00
Rhidian De Wit
72347517b2 Fix missing bool to string cast causing errors 2025-07-17 20:17:52 +02:00
may
95475c35ff update translation files 2025-07-16 16:36:09 +02:00
may
560d21cd86 complete git rebase --keep-base 2025-07-16 15:49:38 +02:00
nick
bef453f69b fish_indent -c/--check completions
Manpage `fish_indent(1)` documents the `-c/--check` option, which checks
if a file is already indented as `fish_indent` would. This option is now
included in the completions for `fish_indent`.
2025-07-15 15:44:36 -05:00
vcalv
fa832ead65 add suspend-then-hibernate to systemctl.fish
suspend-then-hibernate was missing
2025-07-14 18:09:32 -04:00
Azamat Dinaev
eb7afd2a9c Update __fish_print_hostnames.fish
There was an issue in autocomplete of ssh. 

When you put in ~/.ssh/config line like this:

"Include Include ${HRL_SSH}/onprem_config"

and then trying to use fish complete for ssh, for example:

"ssh -J" and press key <Tab> it throughs an error that fish cannot understand ${HRL_SSH} with brackets.
2025-07-12 14:18:43 +03:00
Johannes Altmanninger
f4ddcfa694 Merge pull request #11652 2025-07-11 12:11:17 +02:00
Johannes Altmanninger
1605d8d6ce Merge pull request #11644 2025-07-11 12:10:49 +02:00
Johannes Altmanninger
a7559a62c4 completions/cjpm: format with fish_indent 2025-07-11 12:09:58 +02:00
Johannes Altmanninger
e9327d234d Merge pull request #11641 2025-07-11 12:08:37 +02:00
Daniel Rainer
a3d03fc0fb Avoid duplicate flag values
Both `SKIP_CMDSUBST` and `NO_SPACE_FOR_UNCLOSED_BRACE` used `1 << 14` as their
value accidentally, resulting from `SKIP_CMDSUBST` not being sorted correctly.
Resolve this by using the next (and last in u16) unused bit for `SKIP_CMDSUBST`
and moving it to the end.

Fixes #11651.
2025-07-10 18:52:10 +02:00
Daniel Rainer
1e981a9827 Support upper/lower casing selection
Fixes #11639.
2025-07-10 16:57:17 +02:00
Daniel Rainer
770f4ce6d1 Add docs for casing shortcuts in normal mode 2025-07-06 20:15:25 +02:00
Daniel Rainer
aa782bdad7 Fix vi mode docs for moving to beginning of line 2025-07-06 20:10:21 +02:00
Jiangqiu Shen
e4c55131c7 Update translation 2025-07-04 18:31:39 -04:00
Jiangqiu Shen
e6ad78cda7 update 2025-07-04 00:30:28 -04:00
Jiangqiu Shen
578e162f35 Add completion for Cangjie programing language
add completion of cjpm
2025-07-04 00:29:11 -04:00
Johannes Altmanninger
e9bb150a41 Merge pull request #11633 2025-07-03 15:19:51 +02:00
Johannes Altmanninger
b5eccdf9f6 Merge pull request #11632 2025-07-03 15:19:51 +02:00
Johannes Altmanninger
75716bd6b0 Merge pull request #11631 2025-07-03 15:19:51 +02:00
Johannes Altmanninger
9e628995da Merge pull request #11629 ("Add completions for tmuxp") 2025-07-03 15:19:51 +02:00
Daniel Müller
5b39efc96d Support incrementing/decrementing the number below the cursor
Vim supports incrementing & decrementing the number below the cursor (or
after it) via Ctrl-a and Ctrl-x, respectively. Given fish's Vi mode
support, it makes sense to provide similar functionality when working on
the command line, to provide a more natural environment for Vim users.
With this change we add the necessary functionality.

Closes: #8320
Closes #11570
2025-07-03 14:38:42 +02:00
Johannes Altmanninger
b5bb50d742 builtin commandline: apply commandline+cursor to first top-level reader
Historically, `fish -C "commandline echo"` was silently ignored.  Make it do
the expected thing.  This won't affect subsequent readers because we only do
it for top-level ones, and reader_pop() will clear the commandline state again.

This improves consistency with the parent commit.  We probably don't want to
support arbitrary readline commands before the first reader is initialized,
but setting the initial commandline seems useful: first, it would have helped
me in the past for debugging fish.  Second, it would allow one to rewrite
an application launcher:

	 foot --app-id my-foot-launcher -e fish -C '
	 	set fish_history launcher
	 	bind escape exit
	 	bind ctrl-\[ exit
	-	function fish_should_add_to_history
	-		false
	-	end
	-	for enter in enter ctrl-j
	-		bind $enter '\''
	-			history append -- "$(commandline)"
	-			commandline "setsid $(commandline) </dev/null >/dev/null 2>&1 & disown && exit"
	-			commandline -f execute
	-		'\''
	-	end
	+	commandline "setsid  </dev/null >/dev/null 2>&1 & disown && exit"
	+	commandline --cursor $(string length "setsid ")
	 '

which is probably not desirable today because it will disable autosuggestions.
Though that could be fixed eventually by making autosuggestions smarter.

If we find a generally-useful use case, we should mention this in the changelog.

Ref: https://github.com/fish-shell/fish-shell/pull/11570#discussion_r2144544053
2025-07-03 14:38:42 +02:00
Daniel Müller
32c36aa5f8 builtins commandline/complete: allow handling commandline before reader initialization
Commands like "commandline foo" silently fail, and "complete -C" fails with
a weird "option requires an argument" error.

I think at least the first one can be useful in edge cases, e.g. to test
code that does not separate the `commandline` input and output (#11570),
and to set fish's initial commandline, see the next commit.

I don't think there are super strong reasons to allow these, but if the
existing state is merely due to "no one has ever thought of doing this",
then we should try changing it.

For consistency, also allow "complete -C". I guess an argument for that is
that it's weird to make a command behave differently in non-interactive shells.

For now, keep the historical behavior of disabling access to the command
line in non-interactive shells. If we find a good reason for allowing that
(which seems unlikely), we can.

Ref: https://github.com/fish-shell/fish-shell/pull/11570#discussion_r2144544053

Co-authored-by: Johannes Altmanninger <aclopte@gmail.com>
2025-07-03 14:16:18 +02:00
merceyz
fc37d8d5a8 feat: add completions for volta 2025-06-29 16:23:49 +02:00
merceyz
8d361b4290 feat: add completions for k9s 2025-06-29 16:18:41 +02:00
merceyz
9789e6b731 feat: add completions for cilium and hubble 2025-06-29 16:09:27 +02:00
Johannes Altmanninger
c7d4acbef8 Update changelog 2025-06-29 16:01:44 +02:00
Johannes Altmanninger
e204a4c126 Add ctrl-alt-h compatibility binding
Historically, ctrl-i sends the same code as tab, ctrl-h sends backspace and
ctrl-j and ctrl-m behave like enter.

Even for terminals that send unambiguous encodings (via the kitty keyboard
protocol), we have kept bindings like ctrl-h, to support existing habits.

We forgot that pressing alt-ctrl-h would behave like alt-backspace (and can
be easier to reach) so maybe we should add that as well.

Don't add ctrl-shift-i because at least on Linux, that's usually intercepted
by the terminal emulator.

Technically there are some more such as "ctrl-2" (which used to do the same as
"ctrl-space") but I don't think anyone uses that over "ctrl-space".

Closes #https://github.com/fish-shell/fish-shell/discussions/11548

(cherry picked from commit 4d67ca7c58)
2025-06-28 14:20:03 +02:00
Johannes Altmanninger
4d67ca7c58 Add ctrl-alt-h compatibility binding
Historically, ctrl-i sends the same code as tab, ctrl-h sends backspace and
ctrl-j and ctrl-m behave like enter.

Even for terminals that send unambiguous encodings (via the kitty keyboard
protocol), we have kept bindings like ctrl-h, to support existing habits.

We forgot that pressing alt-ctrl-h would behave like alt-backspace (and can
be easier to reach) so maybe we should add that as well.

Don't add ctrl-shift-i because at least on Linux, that's usually intercepted
by the terminal emulator.

Technically there are some more such as "ctrl-2" (which used to do the same as
"ctrl-space") but I don't think anyone uses that over "ctrl-space".

Closes #https://github.com/fish-shell/fish-shell/discussions/11548
2025-06-28 14:19:10 +02:00
Patryk Bratkowski
fbe5a53dc9 Add completions for tmuxp 2025-06-28 14:58:37 +03:00
Johannes Altmanninger
dcd93e4c52 Fix compatibility with Python 3.6 for OpenSUSE Leap 15.6
Nightlies for opensuse/leap:15.6 are failing because their /bin/python3
is Python 3.6 (the "python311" package creates only /bin/python311).
Python3.6 has been EOL for 3.5 years but OpenSuse leap is not even EOL.
Given that we don't write a lot of Python, let's support this for now.
2025-06-28 13:36:31 +02:00
Johannes Altmanninger
7acd20dc7e Fix opensuse docker file file extension 2025-06-28 13:27:30 +02:00
Johannes Altmanninger
9af33802ec Use statvfs on NetBSD again to fix build
From commit ba00d721f4 (Correct statvfs call to statfs, 2025-06-19):

> This was missed in the Rust port

To elaborate:

- ec176dc07e (Port path.h, 2023-04-09) didn't change this (as before,
 `statvfs` used `ST_LOCAL` and `statfs` used `MNT_LOCAL`)
- 6877773fdd (Fix build on NetBSD (#10270), 2024-01-28) changed the `statvfs`
  call to `statfs`, presumably due to the libc-wrapper for
  `statvfs` being missing on NetBSD.  This change happens
  to work fine on NetBSD because they do [`#define ST_LOCAL
  MNT_LOCAL`](https://github.com/fish-shell/fish-shell/pull/11486#discussion_r2092408952)
  But it was wrong on others like macOS and FreeBSD, which was fixed by
  ba00d721f4 (but that broke the build on NetBSD).
- 7228cb15bf (Include sys/statvfs.h for the definition of ST_LOCAL (Rust
  port regression), 2025-05-16)
  fixed a code clone left behind by the above commit (incorrectly assuming
  that the clone had always existed.)

Fix the NetBSD build specifically by using statfs on that platform.

Note that this still doesn't make the behavior equivalent to commit LastC++11.
That one used ST_LOCAL if defined, and otherwise MNT_LOCAL if defined.

If we want perfect equivalence, we could detect both flags in `src/build.rs`.
Then we would also build on operating systems that define neither. Not sure.

Closes #11596

(cherry picked from commit 6644cc9b0e)
2025-06-28 11:46:25 +02:00
王宇逸
eecf0814a1 Use uninit instead of zeroed (cherry-pikcked only the change to src/path.rs)
(cherry picked from commit 7c2c7f5874)
2025-06-28 11:46:25 +02:00
Johannes Altmanninger
1d893b77d3 Also flag MSRV rustc/clippy warnings in CI 2025-06-28 11:04:29 +02:00
Johannes Altmanninger
b451650faa Flag stable rustc/clippy warnings in CI
Today, when a change introduces warnings, the change author might not see
them. Fix that by making clippy fail on warnings.

AFAICT, "clippy --deny-warnings" will also fail on rustc warnings.
I'd imagine this is what most respectable Rust projects do.

Pin stable rust so we won't get unrelated failures. Alternatively, we could
keep using "dtolnay/rust-toolchain@stable", that should be fine too (as long
as we have the capacity to quickly silence/iron out clippy failures).

While at it, remove some unneeded dependencies. Keep gettext because that
one might enable some cfg-directives (?).
Other cfgs like feature="benchmark" and target_os != "linux" are not yet checked in CI.

See #11584
2025-06-28 11:02:19 +02:00
Johannes Altmanninger
3e0a53ae4f Resolve an uninlined_format_args warning 2025-06-28 11:02:19 +02:00
Johannes Altmanninger
e01aafab1c Extract github actions for interesting rust toolchain versions
Extract a github action to reduce the number of references to our MSRV and
stable (to be pinned in the next commit).

While at it, use the MSRV for macOS builds; this means that we'll be less
like accidentally to break the macOS build when bumping the MSRV.  I don't
think there is a reason for using 1.73 specifically, other than "it's the
highest we can use on old macOS", so using an even older one should be fine.
2025-06-28 09:50:18 +02:00
Johannes Altmanninger
fd0fba83b9 Fix inconsistency in docker file lint override 2025-06-28 09:50:18 +02:00
Johannes Altmanninger
6644cc9b0e Use statvfs on NetBSD again to fix build
From commit ba00d721f4 (Correct statvfs call to statfs, 2025-06-19):

> This was missed in the Rust port

To elaborate:

- ec176dc07e (Port path.h, 2023-04-09) didn't change this (as before,
 `statvfs` used `ST_LOCAL` and `statfs` used `MNT_LOCAL`)
- 6877773fdd (Fix build on NetBSD (#10270), 2024-01-28) changed the `statvfs`
  call to `statfs`, presumably due to the libc-wrapper for
  `statvfs` being missing on NetBSD.  This change happens
  to work fine on NetBSD because they do [`#define ST_LOCAL
  MNT_LOCAL`](https://github.com/fish-shell/fish-shell/pull/11486#discussion_r2092408952)
  But it was wrong on others like macOS and FreeBSD, which was fixed by
  ba00d721f4 (but that broke the build on NetBSD).
- 7228cb15bf (Include sys/statvfs.h for the definition of ST_LOCAL (Rust
  port regression), 2025-05-16)
  fixed a code clone left behind by the above commit (incorrectly assuming
  that the clone had always existed.)

Fix the NetBSD build specifically by using statfs on that platform.

Note that this still doesn't make the behavior equivalent to commit LastC++11.
That one used ST_LOCAL if defined, and otherwise MNT_LOCAL if defined.

If we want perfect equivalence, we could detect both flags in `src/build.rs`.
Then we would also build on operating systems that define neither. Not sure.

Closes #11596
2025-06-28 09:50:18 +02:00
adamanteye
f5370e6f22 Add colorful disassembler output completion for objdump
As desribed in objdump(1), --disassembler-color can be applied to
enable or disable the use of syntax highlighting in disassembly
output.

The options are:

--disassembler-color=off
--disassembler-color=terminal
--disassembler-color=on|color|colour
--disassembler-color=extened|extended-color|extened-colour

Signed-off-by: adamanteye <ada@adamanteye.cc>

Closes #11615
2025-06-28 09:50:18 +02:00
Patryk Bratkowski
d62fb9cc74 Add 'ollama stop' completions.
- Added the '__fish_ollama_ps' function to list running models.
- Added the 'stop' subcommand to ollama completions.
- Added running models as arguments to 'stop'.
2025-06-28 09:50:18 +02:00
Johannes Altmanninger
88ab024d7d Merge pull request #11627 2025-06-28 09:29:11 +02:00
Johannes Altmanninger
1cc900ab7f Merge pull request #11625 2025-06-28 09:28:58 +02:00
Dezhi Wu
144725e947 fix(echo): handle overflow in octal/hex escape parsing
Use wrapping arithmetic when parsing octal and hex escapes in echo to
prevent panics on overflow and ensure consistent behavior with other
shells. This change allows echo to process escape sequences like \5555
without crashing, keeping the same behavior as 3.7.1.

```
$ ./fish --version
fish, version 3.7.1
$ ./fish -c 'echo -e "\5555"'
m5
```
2025-06-28 11:15:42 +08:00
Dezhi Wu
d969577f0b fix(fmt): Resolve Rust 1.88 clippy warnings
Update formatting macros to use the new inline variable syntax as
recommended by Rust 1.88 clippy.
2025-06-28 09:10:27 +08:00
Johannes Altmanninger
1ceebdf580 Fix some CSI commands being sent to old midnight commander
Commit 97581ed20f (Do send bracketed paste inside midnight commander,
2024-10-12) accidentally started sending CSI commands such as "CSI >5;0m",
which we intentionally didn't do for some old versions of Midnight Commander,
which fail to parse them. Fix that.

Fixes #11617
2025-06-25 13:36:03 +02:00
Johannes Altmanninger
3e098249a5 docker/fish_run_tests.sh: add check command to bash history
Closes #11600
2025-06-24 12:52:35 +02:00
Johannes Altmanninger
7cd7f31a93 build_tools/check.sh: ignore modifications to the running script
I sometimes want to run this script in multiple docker containers concurrently,
and possibly modify it while another instance is already running.  The behavior
after modification is unpredictable; let's change it to read the whole script
up-front (like Python/fish do).
2025-06-24 12:52:35 +02:00
Johannes Altmanninger
5e12d4e99c Use sync::OnceCell for terminal modes, fixing memory leak
My

    $ sudo docker/docker_run_tests.sh --shell-after docker/jammy-asan.Dockerfile

shows a lot of complaints about

    Direct leak of 60 byte(s) in 1 object(s) allocated from:

because some unit tests call reader_init() and reader_deinit().  Work around
this by initializing this value only once.  AFAICT, OnceCell is async-signal
safe (unlike Mutex), although I don't think documentation promises that.

It doesn't feel great to change implementation code to accomodate tests but
I think for this specific issue that's what we usually do.  Alternatively,
we could add to lsan_suppressions.txt.
2025-06-24 12:52:35 +02:00
Johannes Altmanninger
f98d1779dd build_tools/check.sh: respect inherited RUSTFLAGS/RUSTDOCFLAGS
No particular motivation. Seems better?
Also, use long options I guess.
2025-06-24 12:52:35 +02:00
Johannes Altmanninger
6f18a1b314 Also namespace target/man -> target/fish-man
If cargo ever wants to write to "target/man", it would collide with our
use of this path.  Let's make this less likely by prefixing the name with
"fish-".  This also makes it more obvious that this is fish's invention.
2025-06-24 12:52:35 +02:00
Johannes Altmanninger
8b102f2571 Stop using Cargo's OUT_DIR
(Note: this commit should technically have preceded the "Fix config paths
for disjoint build-dirs and in-tree installs" one, to make that one easier
to follow, but I wasn't 100% sure if this commit is right.)

From https://doc.rust-lang.org/cargo/reference/environment-variables.html

> OUT_DIR — If the package has a build script, this is set to the folder
> where the build script should place its output. See below for more
> information. (Only set during compilation.)

so OUT_DIR is something like "target/debug/build/fish-41da27d587f48978".
Whenever build.rs is re-run, we get a new one.

I don't think we need this flexibility anywhere.  It wouldn't protect
concurrent "cargo test" from interfering with each other - that's handled
by a file lock taken by Cargo.

Use "target/" instead (or CMAKE_BINARY_DIR if set).
Namespace the files better, so we don't create weird paths like

	target/test/complete_test/...
	target/fish_root/
2025-06-24 12:52:35 +02:00
Johannes Altmanninger
514eebb002 build_tools/update_translations.fish: move po/template.po to /tmp
With the upcoming tests/checks/gettext.fish test from #11583, my

	sudo docker/docker_run_tests.sh --shell-after docker/focal.Dockerfile

fails writing to "po/template.po" because "/fish-source" is mounted as
read-only.  (There should be no need for tests to write to the source tree.)

Since commit 6239cba1e4 (Add dry-run mode to update_translations.fish,
2025-05-30), "build_tools/update_translations.fish" always removes that
template file when done, even without "--dry-run".

I'm not sure if we still have a need for keeping around "po/template.po".
To add a new translation, you can run "build_tools/update_translations
po/xy.po". It could serve as a cache but that would only work if we integrated
it into a build system.

Move it to /tmp, fixing the docker tests.
2025-06-24 12:52:35 +02:00
Johannes Altmanninger
41eb0a2fd0 build_tools/update_translations.fish: protect against universally-set $tmpdir 2025-06-24 12:51:17 +02:00
Johannes Altmanninger
290d957ab6 build_tools/update_translations.fish: remove forward reference
cleanup_exit references variables that are only defined later.  Fix that.
Also move the definition one block up, to help the next commit.
2025-06-24 12:33:28 +02:00
Johannes Altmanninger
08b03a733a docker_run_tests.sh: stop using cmake
Use test_driver directly instead of CMake in the docker tests.

Deal with the read-only "/fish-source" by exporting
"CARGO_TARGET_DIR=$HOME/fish-build".  It seems correct to also inject this
environment variable into the interactive debugging shells.  Add some logging
to make this override more obvious to the user.

Adopt "build_tools/check.sh", because that defines the full set of checks
that we (eventually) want to run in CI.

In particular, this will also run "tests/checks/po-files-up-to-date.fish"
which "cargo b && cargo t && tests/test_driver.py" does not, due to the
REQUIRES clause.

Since most docker images have some lints/warnings today, disable those for
now. Use "docker_run_tests.sh --lint" to override. The default may be changed
in future.
2025-06-24 12:32:42 +02:00
Johannes Altmanninger
19a17fa981 Fix docker warning by using "ENV key=value" syntax
- LegacyKeyValueFormat: "ENV key=value" should be used instead of
	legacy "ENV key value" format (line 4)
2025-06-24 12:32:42 +02:00
Johannes Altmanninger
13c00c9f79 Fix config paths for disjoint build-dirs and in-tree installs
Commit 89282fd9bc (Use CARGO_MANIFEST_DIR to see if we're running from
build dir, 2024-01-20) did

    -if exec_path.starts_with(OUT_DIR)
    +if exec_path.starts_with(CARGO_MANIFEST_DIR)

where OUT_DIR is the cmake build directory ("./build")
and CARGO_MANIFEST_DIR is our top level source tree.

This allowed "target/debug/fish" to work, but it broke
1. CMake build directories outside the source tree, e.g. "docker/docker_run_tests.sh".
   Those incorrectly fall back to the compiled-in-path (/usr/local/share etc)
2. Installations iside the source tree, e.g.
   "mkdir build && cd build && cmake .. -DCMAKE_INSTALL_PREFIX=$PWD/../install".
   These installations incorrectly use "share/" etc. from the source tree.

Fix this by
1. respecting the CMake-specific FISH_BUILD_DIR, ad
2. if that's not set, use $CARGO_MANIFEST_DIR/target
2025-06-24 12:32:42 +02:00
Johannes Altmanninger
19eceff3bc bulid.rs respect CARGO_TARGET_DIR in man output 2025-06-24 12:32:42 +02:00
Johannes Altmanninger
6a4d3a59ab build.rs: extract constant for cargo manifest dir 2025-06-24 12:32:42 +02:00
Johannes Altmanninger
3b0d5c342b build.rs: extract function for canonicalizing paths
This probably means we should enable Rust backtraces.. not sure though.
2025-06-24 12:32:42 +02:00
Johannes Altmanninger
884a2d100c build.rs: remove redundant include dir
This include was added for config.h in 618834c4b5 (Port
UVAR_FILE_SET_MTIME_HACK, 2023-09-15), but that file no longer exists.
Remove it.
2025-06-24 12:04:57 +02:00
Johannes Altmanninger
a4d355634d docker_run_tests: fix failed build exiting prematurely
My bad; the "set +e" is only active inside the subshell.
The outer shell uses "set -e", which means that it will
exit upon seeing the subshell fail.
2025-06-24 12:04:57 +02:00
Johannes Altmanninger
3c620f56ee test_driver.py: fix compatibility with Python 3.8 / Ubuntu Focal 2025-06-24 12:04:57 +02:00
Johannes Altmanninger
7679be3126 test_driver.py: fix confusing help output 2025-06-24 12:02:13 +02:00
Johannes Altmanninger
49926cfbac Standardize shell script indent level
We have a mixture of 2 and 4 space indent.

    4 benchmarks/driver.sh
    2 build_tools/check.sh
    4 build_tools/git_version_gen.sh
    4 build_tools/mac_notarize.sh
    2 build_tools/make_pkg.sh
    2 build_tools/make_tarball.sh
    2 build_tools/make_vendor_tarball.sh
    4 docker/docker_run_tests.sh
    4 osx/install.sh
    2 tests/test_functions/sphinx-shared.sh

Our editorconfig file specifies 2, with no explicit reason.
Our fish and Python scripts use 4, so let's use that.
2025-06-24 12:02:13 +02:00
Johannes Altmanninger
963c3425a3 Merge pull request #11593 2025-06-24 12:02:13 +02:00
ndrew222
55bddac90a added completion for uv and uvx
Closes #11601
2025-06-24 12:02:13 +02:00
Illia Ostapyshyn
20c67692e1 completions/journalctl: Add --pager-end
Closes #11604
2025-06-24 12:02:13 +02:00
Johannes Altmanninger
1e7088fb6b Merge pull request #11605 2025-06-24 12:02:13 +02:00
Johannes Altmanninger
0f75df7c35 history: remove flush()/fsync() and don't write after each appended item
Commit 5c0fddae70 (Refactor history flushing, 2025-03-28) made three changes:
1. call fsync() when we are finished writing the history file.
2. when appending to (as opposed to vacuuming) history, call write(2)
   (followed by flush() and sync()) for each item. Previously, we'd only
   call write(2) if our 64k buffer was full, or after processing the last
   history item.
3. actually check the return value of flush() (which would retry when flushing
   fails -- but std::fs::File::flush() never fails!).

The motivation was to potentially fix #10300 which didn't succeed (see
https://github.com/fish-shell/fish-shell/issues/10300#issuecomment-2876718382).

As for 1 and 2, I don't think the way we use fsync really helps, and flushing
eagerly should not make a difference.

As for 3, there are some explanations in comments, commit message and a [PR
comment](https://github.com/fish-shell/fish-shell/pull/11330#discussion_r2020171339).
To summarize, 5c0fddae70 wants to address the scenario where file.flush()
fails. Prior to that commit we would ostensibly carry on with a corrupted
"first_unwritten_new_item_index" (corrupted because it doesn't match what's
written to disk), which can cause various issues.  However this doesn't
ever happen because std::fs::File::flush() never fails because it doesn't
do anything -- std::fs::File::write() does not buffer writes, it always
delegates to write(2).

There can definitely be scenarios like the one described in
https://github.com/fish-shell/fish-shell/pull/11330#discussion_r2020171339
where the disk is full. In that case, either write(2) fails, which we
already check.  Or close(3p) fails with EIO, which we have never checked. We
should probably check that.

Undo all three changes for now.

Closes #11495
2025-06-24 12:02:13 +02:00
Asuka Minato
edb0617d13 Update git.fish
Closes #11606
2025-06-24 12:02:12 +02:00
Johannes Altmanninger
d2f7d238f3 Remove obsolete translation entries
I doubt these are very helpful; most of them won't be used again.  We can
still find them in history with "git log -Gpart.of.msgid".
2025-06-24 11:44:46 +02:00
Johannes Altmanninger
335f91babd completions/git: fix spurious error when no subcommand is in $PATH
Systems like NixOS might not have "git-receive-pack" or any other "git-*"
executable in in $PATH -- instead they patch git to use absolute paths.
This is weird. But no reason for us to fail. Silence the error.

Fixes #11590

(cherry picked from commit 4f46d369c4)
2025-06-24 11:59:57 +08:00
Volodymyr Chernetskyi
a7bed39c1e Add info on formatting fish_git_prompt output 2025-06-23 18:46:54 +02:00
Johannes Altmanninger
06646998db fixup! alias: fix indentation 2025-06-23 14:18:15 +02:00
Johannes Altmanninger
096f225579 alias: fix indentation
Fixes #11602
2025-06-23 13:53:43 +02:00
Johannes Altmanninger
ebec8c15ab Merge pull request #11599 2025-06-23 13:46:34 +02:00
Daniel Rainer
92d9646631 Simplify CMake Tests
Remove dependency on CTest. Parallel execution is handled by `test_driver.py`
internally now, so CTest is no longer relevant for performance.

This also removes CMake targets for single tests. As a replacement,
`test_driver.py` can be called directly with the path to the build directory as
the first argument and the path to the desired test as the second argument.
Ensuring that the executables in the build directory are up to date needs to be
done separately.
For a pure cargo build, an example of running a single test would be:
`cargo b && tests/test_driver.py target/debug tests/checks/abbr.fish`

The recommended way of running tests is `build_tools/check.sh`, which runs more
extensive tests and does not depend on CMake. That script does not work in CI
yet, so CMake testing is retained for now.

Update CI config to use the new `FISH_TEST_MAX_CONCURRENCY`.
Also update the FreeBSD version, since the previous one is outdated and does not
support the semaphore logic in `test_driver.py`.
2025-06-22 22:44:46 +02:00
Daniel Rainer
ab1307c63b Do not mmap with len 0
`mmap` should fail when the length argument is 0. Checking this in advance
allows returning early, without performing unnecessary syscalls.

This also fixes an issue observed on FreeBSD 13.2 where `mmap` does not always
fail when the length is 0, resulting in the `assert!(len > 0)` in
`MmapRegion::new` failing.
https://github.com/fish-shell/fish-shell/issues/11595
2025-06-21 22:19:27 +02:00
Johannes Altmanninger
ec66749369 __fish_complete_list: only unescape "$(commandline -t)"
Commit cd3da62d24 (fix(completion): unescape strings for __fish_complete_list,
2024-09-17) bravely addressed an issue that exists in a lot of completions.
It did so only for __fish_complete_list. Fair enough.

Unfortunately it unescaped more than just "$(commandline -t)".

This causes the problem described at
https://github.com/fish-shell/fish-shell/issues/11508#issuecomment-2889088934
where completion descriptions containing a backslash followed by "n" are
interpreted as newlines, breaking the completion parser.  Fix that.

(cherry picked from commit 60881f1195)
2025-06-21 18:58:33 +02:00
Johannes Altmanninger
6e9e33d81d __fish_complete_list: strip "--foo=" prefix from replacing completions
Given a command line like

	foo --foo=bar=baz=qux\=argument

(the behavior is the same if '=' is substituted with ':').

fish completes arguments starting from the last unescaped separator, i.e.

	foo --foo=bar=baz=qux\=argument
			 ^
__fish_complete_list provides completions like

	printf %s\n (commandline -t)(printf %s\n choice1 choice2 ...)

This means that completions include the "--foo=bar=baz=" prefix.

This is wrong. This wasn't a problem until commit f9febba (Fix replacing
completions with a -foo prefix, 2024-12-14), because prior to that, replacing
completions would replace the entire token.
This made it too hard to writ ecompletions like

	complete -c foo -s s -l long -xa "hello-world goodbye-friend"

that would work with "foo --long fri" as well as "foo --long=frie".
Replacing the entire token would only work if the completion included that
prefix, but the above command is supposed to just work.
So f9febba made us replace only the part after the separator.

Unfortunately that caused the earlier problem.  Work around this.  The change
is not pretty, but it's a compromise until we have a better way of telling
which character fish considers to be the separator.

Fixes #11508

(cherry picked from commit 320ebb6859)
2025-06-21 18:58:17 +02:00
Johannes Altmanninger
bebf3c129f Merge pull request #11594 2025-06-21 18:54:22 +02:00
Johannes Altmanninger
60881f1195 __fish_complete_list: only unescape "$(commandline -t)"
Commit cd3da62d24 (fix(completion): unescape strings for __fish_complete_list,
2024-09-17) bravely addressed an issue that exists in a lot of completions.
It did so only for __fish_complete_list. Fair enough.

Unfortunately it unescaped more than just "$(commandline -t)".

This causes the problem described at
https://github.com/fish-shell/fish-shell/issues/11508#issuecomment-2889088934
where completion descriptions containing a backslash followed by "n" are
interpreted as newlines, breaking the completion parser.  Fix that.
2025-06-21 18:53:50 +02:00
Johannes Altmanninger
320ebb6859 __fish_complete_list: strip "--foo=" prefix from replacing completions
Given a command line like

	foo --foo=bar=baz=qux\=argument

(the behavior is the same if '=' is substituted with ':').

fish completes arguments starting from the last unescaped separator, i.e.

	foo --foo=bar=baz=qux\=argument
			 ^
__fish_complete_list provides completions like

	printf %s\n (commandline -t)(printf %s\n choice1 choice2 ...)

This means that completions include the "--foo=bar=baz=" prefix.

This is wrong. This wasn't a problem until commit f9febba (Fix replacing
completions with a -foo prefix, 2024-12-14), because prior to that, replacing
completions would replace the entire token.
This made it too hard to writ ecompletions like

	complete -c foo -s s -l long -xa "hello-world goodbye-friend"

that would work with "foo --long fri" as well as "foo --long=frie".
Replacing the entire token would only work if the completion included that
prefix, but the above command is supposed to just work.
So f9febba made us replace only the part after the separator.

Unfortunately that caused the earlier problem.  Work around this.  The change
is not pretty, but it's a compromise until we have a better way of telling
which character fish considers to be the separator.

Fixes #11508
2025-06-21 18:53:50 +02:00
Daniel Rainer
9bf6112b60 Add option to limit concurrency of tests
The main purpose of this is avoiding timeouts in CI.

Passing `--max-concurrency=n` to `test_driver.py` will result in at most `n`
tests running concurrently, where `n` is a positive integer.
Not specifying the argument preserves the old behavior of running all tests
concurrently without a limit.
2025-06-21 02:36:06 +02:00
Daniel Rainer
ef1a6aba26 Remove unused NEVER_MMAP 2025-06-20 00:44:50 +02:00
Peter Ammon
f3ebc68d5d Correct statvfs call to statfs
This was missed in the Rust port - C++ had statfs for MNT_LOCAL and not statvfs.
The effect of this is that fish never thought its filesystem was local on macOS
or BSDs (Linux was OK). This caused history race tests to fail, and also could
in rare cases result in history items being dropped with multiple concurrent
sessions.

This fixes the history race tests under macOS and FreeBSD - we weren't locking
because we thought the history was a remote file.

Cherry-picked from ba00d721f4
2025-06-19 15:36:19 -07:00
Peter Ammon
ba00d721f4 Correct statvfs call to statfs
This was missed in the Rust port - C++ had statfs for MNT_LOCAL and not statvfs.
The effect of this is that fish never thought its filesystem was local on macOS
or BSDs (Linux was OK). This caused history race tests to fail, and also could
in rare cases result in history items being dropped with multiple concurrent
sessions.

This fixes the history race tests under macOS and FreeBSD - we weren't locking
because we thought the history was a remote file.
2025-06-19 15:30:36 -07:00
Peter Ammon
fe8909e8f2 Fix an off-by-one error in reporting dropped history items
This was introduced in the Rust port. The original C++ was pretty gnarly to be
fair.
2025-06-19 11:08:50 -07:00
Lorenzo Albano
d369614ad9 Use $GIT_COMMON_DIR for stashes detection.
Within a linked worktree, `$GIT_DIR` and `$GIT_COMMON_DIR` have different
values (see [git-worktree docs](https://git-scm.com/docs/git-worktree#_details)).
The two serve different purposes, in case of stashes `$GIT_COMMON_DIR`
should be used, this way stash detection in the git prompt works also
when inside a `git worktree`.

Closes #11591
2025-06-19 11:13:09 +02:00
Johannes Altmanninger
4f4d941760 Merge pull request #11588 2025-06-19 11:13:09 +02:00
Johannes Altmanninger
9b19db5c5f Merge pull request #11492 2025-06-19 11:13:09 +02:00
Johannes Altmanninger
4f46d369c4 completions/git: fix spurious error when no subcommand is in $PATH
Systems like NixOS might not have "git-receive-pack" or any other "git-*"
executable in in $PATH -- instead they patch git to use absolute paths.
This is weird. But no reason for us to fail. Silence the error.

Fixes #11590
2025-06-19 11:13:09 +02:00
Daniel Rainer
977459949f Obtain history file path in HistoryImpl::save
Eliminates some code duplication between the two different saving
implementations. These changes are based on
https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2149438316.

One extra change is included here, namely the early return on an empty file
name, indicating private mode. Without this, `history_path.unwrap()` fails in
some tests. Returning early is probably what we want in such situations anyway.
2025-06-18 21:05:29 +02:00
Daniel Rainer
8cbcfc0b3a Stop caching whether to lock
The cached information might become outdated. It is important that all fish
processes use the same mutual exclusion logic (either `flock`-based or the
fallback), because the two methods do not provide mutual exclusion from one
another.
Avoiding caching makes the behavior independent on previous system states,
resulting in fish instances performing file operations at the same time to use
the same locking logic.

More detailed discussion in
https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2134543447
2025-06-18 21:05:00 +02:00
Daniel Rainer
77738fd646 Remove obsolete comments
If arguments always have the same value they do not need to be arguments.
For `HistoryImpl::add`, the comments are incorrect (assuming they should
indicate the value of the argument), since both arguments can be true or false
independently.
`History::add` is only called at one location in a test with a constant value of
`false` for `pending`. This might mean that the parameter could be deleted, or
maybe even the entire function, if testing can work without it.
2025-06-18 20:54:38 +02:00
Daniel Rainer
f438e80f9b Use shared file locking logic
Both history files and universal variables files are accessed by multiple
processes, which need a way to synchronize their accesses.
This synchronization logic is mixed in with the logic for reading and updating
the files' contents, which results in messy code, duplicated locking
implementations, and inconsistencies.
Moreover, the existing implementations are flawed which has resulted in file
corruption (e.g. https://github.com/fish-shell/fish-shell/issues/10300).

The new approach separates the synchronization logic from the rest.

There are two approaches to synchronization.
- The primary one is using `flock(2)` to lock the directory containing the file
  which requires synchronized access. We do not lock the file holding the data
  directly because this file might be replaced, which can result in locking
  succeeding when it should block. Locking the directory solves this problem.
  To avoid inconsistent file states, changes are first written to a temporary
  file, which is then renamed into place while still holding the lock.
- In some situations `flock` locks are unavailable or take a long time. This
  mostly applies to remote file systems. If we think that a directory is located
  on a remote file system, we do not attempt to use `flock`.
  As a fallback, we have a lockless approach, which uses file metadata (device,
  inode, size, ctime, mtime) to identify file versions.
  We then read from the file, write the updated data to a temporary file,
  check if the file id for the path is the same as before we started reading,
  and if so we rename the temporary file such that it replaces the old file.
  Note that races are possible between the file id check and the rename syscall.
  If we detect a file id mismatch, we retry, up to a predetermined number of
  attempts.

The operations which should be performed are passed to the functions handling
synchronization as `Fn`s. Because we might have to run these operations
repeatedly when retrying, they should be executable arbitrarily often without
causing side-effects relevant to the program. This requires some changes to
functions accessing these files. In many cases, they have to work with
non-mutable references, which requires that they return the data which should be
updated in the program state, instead of directly assigning to the appropriate
location.

Locking via `O_EXLOCK`, which was used for the universal variable file, is no
longer supported. That version of locking locks the file operated on directly,
instead of its directory. According to the man pages of {Open,Free,Net}BSD
and macOS, these locks have flock semantics. So if flock is available, we can
use it, and if it is not, the `O_EXLOCK` flag does not help.
2025-06-18 20:48:27 +02:00
Daniel Rainer
ccb9c8225f Remove CHAOS_MODE
This is dead code. It is never set to true.
2025-06-18 20:31:28 +02:00
Daniel Rainer
33b651ad91 Get remoteness of correct directory
The history file is stored in the data dir, not the config dir, so the
remoteness of the former is the one which matters.
2025-06-18 20:31:28 +02:00
Daniel Rainer
a20712b51d Avoid mutable references for mmap creation
This is preparatory work for refactoring the file synchronization approach.

`read_exact` will fail if the file length does not match the expected one, which
means zero padding is useless. (On any reasonable OS it was also useless before,
because anonymous memory mapping would be zero-pages.)
2025-06-18 20:31:28 +02:00
Daniel Rainer
da426a1b03 Improve error handling in src/history/file.rs
Use `std::io::Result` instead of `Option` as the return type where appropriate,
to allow for better-informed error handling.

Remove explicit checks about the length to be mapped being 0.
From `mmap(3)`:
> If len is zero, mmap() shall fail and no mapping shall be established.
2025-06-18 20:31:28 +02:00
Daniel Rainer
fbb2fcdb06 Improve error handling in src/history.rs
This allows for more informative error handling.

In some cases, the `?` operator can now be applied sensibly instead of more
verbose local error handling.
2025-06-18 20:31:28 +02:00
Daniel Rainer
537b1c3dd5 Extract code for creating temporary files
There is no need for separate implementations for history and uvar file
handling. Having a shared implementation ensures that creating temporary files
is handled consistently and removes clutter from the source files which want to
create temporary files.
2025-06-18 20:31:28 +02:00
Daniel Rainer
b4d0538892 Reduce state mutation in load_from_file
This is another step towards making the `load_from_file` function callable
without modifying internal data of `self`. Instead, the required updates for
a successful load should be returned.

For now, `self.last_read_file_id` is still modified
within `load_from_file`, which means it still needs a mutable reference to
`self`.
2025-06-18 20:31:28 +02:00
Daniel Rainer
9222381769 Update self.vars outside of acquire_variables
This is done as a step towards enabling loading from the variables file without
affecting internal variables, such that retrying becomes possible without
issues.
2025-06-18 20:31:28 +02:00
Daniel Rainer
f2f54919af Remove unnecessary mut specifier 2025-06-18 20:31:28 +02:00
Daniel Rainer
f40e31f675 Return callbacks via return value
Callbacks are generated by
`src/env_universal_common.rs:generate_callbacks_and_update_exports`.
This function only pushes to the `Vec`, so the content of the `Vec` passed to it
does not matter within this function.
The generated callbacks are used in `src/env/environment.rs:universal_sync`,
which calls `generate_callbacks_and_update_exports` via
`EnvUniversal::sync`,
(optionally `EnvUniversal::load_from_path_narrow`),
`EnvUniversal::load_from_file`.

The only other code making use of these callbacks is in tests.
Because the only real use passes an empty `Vec`, there is no need to to pass the
`Vec` as a mutable reference to the function at all. Instead, we create the `Vec`
in `generate_callbacks_and_update_exports` and return it from there, which is
what the new code does.

This change is made because we want loading from a file to be performed without
mutating data which does not come directly from the file.
Then, we can safely retry loading from the file as many times as we want,
without worrying about side-effects on our data structures.
We want to be able to do this in the case where we cannot properly lock the file
and fall back to lockless reading, where we check file metadata before and after
reading to detect modifications, and retry if modifications are detected.

This fallback logic is not in place yet, and further changes are required for
side-effect free loading.
2025-06-18 20:31:28 +02:00
Fabio José Bohnenberger
43fbfa9a0f Extract __fish_cached function (#11526)
- extract __fish_cached function
- add cache for winetricks verb completion
2025-06-18 10:29:00 +02:00
Daniel Rainer
f6dbf17446 Decode WString in FLOG
This allows converting non-UTF-8-conforming bytes from their PUA encoding back
to the original bytes before outputting.

Due to the way Rust handles trait implementations, we cannot use
`impl<T: std::fmt::Display> FloggableDisplay for T`
anymore, as that would result in a conflicting implementation for the types
which get a custom implementation.
Instead, explicitly implement the trait for all types which need it.
2025-06-17 23:37:59 +02:00
Johannes Altmanninger
06578bd03d Merge pull request #11565 2025-06-16 12:25:08 +02:00
Johannes Altmanninger
6491518b97 Merge pull request #11571 2025-06-16 12:23:39 +02:00
Johannes Altmanninger
7e03bebf97 Merge pull request #11582 2025-06-16 12:23:21 +02:00
Peter Ammon
941701da3d Restore some async-signal discipline to SIGTERM
The changes to enable terminal protocols (CSI-U, etc) also attempts to
re-disable these when fish exits. In particular it attempts to disable these
from a SIGTERM handler.

Unfortunately none of that machinery is async-signal safe. Indeed our SIGTERM
handler has gotten rather sketchy, with taking a mutex and some other stuff.

Remove the async-signal-unsafe stuff and make SIGTERM manifestly safe.
Unfortunately this means that terminal protocols will remain set after SIGTERM
but that's probably unavoidable.
2025-06-15 19:06:47 -07:00
Peter Ammon
eb211e1d10 Bravely remove calls to redirect_tty_output
Calls to redirect_tty_output were added in many places when certain tty-syscalls
returned EIO. See commit 396bf1235d

This was intended to work around a glibc bug in wide character output, but it
was never really justifiable or tested, and we no longer use glibc wide
character output.

Bravely remove these, except in the case where we got SIGHUP and we don't want
to trigger SIGTTIN or SIGTTOU.
2025-06-15 18:09:53 -07:00
Daniel Rainer
a317a6acd9 Unconditionally include gettext message
Definitions of localizable strings should not be guarded by `cfg`, because then
they might not end up being exported, depending on the compilation config.
2025-06-15 23:43:31 +02:00
Daniel Rainer
d3f287c520 Retain attributes in localizable_consts
These attributes (such as doc comments) should be retained.
2025-06-15 23:43:31 +02:00
Daniel Rainer
80131acff2 Add PO file update check to tests
The PO file updates can now run in a normal test, eliminating the need for
special handling.

Rename the `check-translations.fish` script, to clarify which part of the checks
happens in it.
2025-06-15 23:43:31 +02:00
Daniel Rainer
85fb937a4d Add --use-existing-template argument
This is intended to allow translation updates in contexts where building within
the `fish_xgettext.fish` script is undesirable.

Specifically, this allows checking for PO file updates in the tests run by
`test_driver.py`. Because these use a tmpdir for `$HOME`, building within such a
test requires installing the entire Rust toolchain and doing a clean build,
which is a waste of resources.
With this argument, it is possible to build the template before running the
tests and passing the file path into the script.
2025-06-15 23:43:31 +02:00
Daniel Rainer
1e571263a0 Ensure translation script is CWD-independent 2025-06-15 23:43:31 +02:00
Daniel Rainer
1a0a6f544d Do not export test strings
When including the tests in the build, string literals passed to `wgettext!`
would be included in the gettext template file, which we do not want here,
because the strings should not be localized for this test.
2025-06-15 23:43:31 +02:00
Daniel Rainer
413ce9fdb3 Call cursor_position() lazily
This function does not need to run when the pager is not focused. Calling it
lazily eliminates the overhead of calling it when it is not needed.
This code runs on each keypress when entering a command, so it makes sense to
keep it as lean as possible. (At the very least it avoids spam when trying to
debug/analyze gettext behavior.)
2025-06-15 23:16:22 +02:00
Daniel Rainer
03e3d0aa3f Split up sphinx HTML and MAN file generation
This test is the one with the longest runtime. Splitting the two targets into
separate tests allows them to run in parallel, which can speed up the tests.
2025-06-15 18:44:58 +02:00
Peter Ammon
00c528c13f Remove parser.assert_can_execute
We don't need this; Rust's Send safety means that a Parser never changes its
thread.
2025-06-14 16:05:54 -07:00
Peter Ammon
60dbb9c8ba Fix a misleading comment. 2025-06-14 15:18:18 -07:00
Peter Ammon
2104f8a18a Remove Rc from Parser's vars
This will help enable Parser to be Send, which will be important for
concurrent execution.
2025-06-14 13:59:17 -07:00
Peter Ammon
6f18a362e6 Remove the process argument to ProcPerformer
Processes can't cross threads, so this doesn't belong here.
Preparation for concurrent execution.
2025-06-14 13:34:04 -07:00
Peter Ammon
d67fdd1f02 Make Job store boxed process list instead of Vec 2025-06-14 12:04:52 -07:00
Creeperxie
d92bb57418 Add description for gzip -d completion 2025-06-14 10:59:44 -07:00
Peter Ammon
eb4cec1fe2 Clean up pgroup assignment and tighten up some post-fork code 2025-06-14 10:34:33 -07:00
Peter Ammon
ef2e30cdc1 Clean up pids
Use OnceLock more often in place of atomics. Tighten up async signal safety.
2025-06-14 10:34:27 -07:00
Peter Ammon
294d589d2f Clean up ProcStatus
Don't need all of these atomics.

In particular use OnceLock in InternalProc as this doesn't doesn't need
locking if there's only a single writer.
2025-06-14 10:34:20 -07:00
Peter Ammon
415232631a Continued refactoring of some exec functions 2025-06-14 10:34:15 -07:00
Peter Ammon
e10a12c0f2 Rationalize certain edge cases for function execution
This concerns edge cases when executing a function. Historically, when we parse
fish script, we identify early whether or not it's a function; but only record
the function's name and not its properties (i.e. not its source).

This means that the function can change between parsing and execution. Example:

    function foo; echo alpha; end
    foo (function foo; echo beta; end)

This has historically output "beta" because the function is replaced as part of
its own arguments.

Worse is if the function is deleted:

    function foo; echo alpha; end
    foo (functions --erase foo)

This outputs an error but in an awkward place; that's OK since it's very rare.

Let's codify this behavior since someone might be depending on it.
2025-06-14 10:34:10 -07:00
Peter Ammon
6fffb76937 Move Process's block node into its Type
Previously, for Processes which were BlockNodes, we stored the node separately
in the Process via an Option; just promote this to a real field of the
ProcessType::BlockNode.

No user visible changes expected.
2025-06-14 10:34:05 -07:00
Peter Ammon
36e385e1fb Make ProcessType not Eq or PartialEq
We are going to give it fields shortly.
2025-06-14 10:33:58 -07:00
Peter Ammon
e598010020 Clean up some Node representations
Use NodeRef more pervasively, leading to simplifications.
2025-06-14 10:33:53 -07:00
Peter Ammon
eba4c906ae Minor cleanup of process creation
Remove some useless types and unnecessary boxing.
2025-06-14 10:33:48 -07:00
Peter Ammon
fbb4a8d853 Adopt Rust naming conventions in JobControl and ProcessType 2025-06-14 10:33:46 -07:00
Peter Ammon
10e525c49c Fix rustdoc warnings on macOS 2025-06-14 10:32:41 -07:00
Johannes Altmanninger
ec27b418e4 test_driver: support Python 3.8 for now
Our docker tests are currently broken since we no longer seem to install
"build_root".  When I sidestep this issue for now and run

	sudo docker/docker_run_tests.sh --shell-before docker/focal.Dockerfile
	cd /fish-source
	CARGO_TARGET_DIR=$HOME/out
	tests/test_driver.py ~/out/debug

the test driver fails in various ways.
This is because Ubuntu Focal provides Python 3.8.

Fix some of the typing incompatibilities.  Fix a hang in tests like
"tests/checks/init-command.fish"; apparently fish believes it's interactive
because Python 3.8's create_subprocess_shell() makes the fish child believe
that stdin is a TTY, so it's implicitly interactive.
2025-06-13 15:04:31 +02:00
Johannes Altmanninger
535a09a5b3 Silence error in check-all-fish-files
Our docker/docker_run_tests.sh script runs tests in a container with the fish
source tree mounted as read-only.  We have a hack to speed up repeated runs
of the check-all-fish-files test that assumes the source tree is writable.
Paper over this by silencing the error for now.

  There were no remaining checks left to match stderr:1:
    touch: cannot touch '/fish-source/tests/.last-check-all-files': Read-only file system
2025-06-13 14:56:02 +02:00
Johannes Altmanninger
4be17bfefb fixup! Extract config path module. NFC
Fix cargo (non-cmake) build.
2025-06-13 12:17:10 +02:00
Johannes Altmanninger
6fd0025f38 Make LOCALEDIR relocatable as well
As explained in c3740b85be (config_paths: fix compiled-in locale dir,
2025-06-12), fish is "relocatable", i.e. "mv /usr/ /usr2/" will leave
"/usr2/bin/fish" fully functional.

There is one exception: for LOCALEDIR we always use the path determined at
compile time.
This seems wrong; let's use the same relocatable-logic as for other paths.

Inspired by bf65b9e3a7 (Change `gettext` paths to be relocatable (#11195),
2025-03-30).
2025-06-13 11:52:46 +02:00
Johannes Altmanninger
052fc18db9 Extract config path module. NFC
This is the "code movement" part of bf65b9e3 ("Change `gettext` paths to be
relocatable (#11195)").

While at it, fix some warnings.
2025-06-13 11:52:46 +02:00
Johannes Altmanninger
d584f36f5d Remove support for elf-patching LOCALEDIR
Commit bf65b9e3a7 (Change `gettext` paths to be relocatable (#11195),
2025-03-30) is difficult to follow because it combines code movement with
two behavior changes. Our parent commit fixed the first behavior change.

The second behavior change made us tolerate trailing NUL bytes in LOCALEDIR.
This was motivated because conda wants to use binary patching to change
the effective prefix at runtime, presumably so the user can move around the
"fish" executable program arbitraily.

This turned out to be unnecessary because fish is already "relocatable"
(see our parent commit).

Let's remove the special case for LOCALEDIR. Treat it like other paths.

Closes #11574
Closes #11474
2025-06-13 11:22:15 +02:00
Johannes Altmanninger
c3740b85be config_paths: fix compiled-in locale dir
Fish uses this logic to find paths to functions etc.:

1. if $(status fish-path) starts with $CARGO_MANIFEST_DIR,
   we use $CARGO_MANIFEST_DIR/share etc.

   Aside: this also has the unintended effect that "cmake
   -DCMAKE_INSTALL_PREFIX=$PWD/prefix" will not use "$PWD/prefix/share" but
   "$PWD/share", at least since eacbd6156d (Port and adopt main written in
   Rust, 2023-08-18).

2. Else if $(status fish-path) ends with "bin/fish",
   and $(status fish-path)/../share/fish exists, we use that, since 4912967eab
   (Large set of changes related to making fish relocatable, and improving
   the build and install story, 2012-07-08)

3. Else if $(status fish-path) ends in "fish" (which is very likely),
   and $(status fish-path)/share exists, we use that, since
   c2a8de4873 (Make fish find config directories in source tree, 2016-09-23).
   I think this is for running (without installing) in-tree builds ("cmake .");
   this is not recommended but it is used, see
   https://github.com/fish-shell/fish-shell/pull/10330

4. If none of the above worked, either because the fish binary has been
   moved into a weird directory, or if we fail to get $(status fish-path)
   (e.g. on OpenBSD, where "argv[0]" is not available),
   then we fall back to reasonable default paths determined at compiled
   time.

   These paths include data_dir=$PREFIX/share.
   We recently added locale_dir too in bf65b9e3a7 (Change `gettext` paths
   to be relocatable (#11195), 2025-03-30).

In case 1, we use               locale: manifest_dir.join("share/locale"),
In case 2 and 3, we use         locale: data_dir.join("locale"),
In case 4, we use               locale: data_dir.join("share"),

The last one seems wrong (there is not "/usr/share/share"). Fix that.

Alternatively, we could revert bf65b9e3a7 (and redo the parts we want to keep).
2025-06-13 11:22:15 +02:00
Johannes Altmanninger
d840fd9a7f config_paths: remove code clone
Another evident problem from bf65b9e3a7 (Change `gettext` paths to be
relocatable (#11195), 2025-03-30). How disrespectful.
2025-06-13 11:22:15 +02:00
Johannes Altmanninger
592b059c30 config_paths: inline function 2025-06-12 11:20:56 +02:00
Johannes Altmanninger
86b9a0b876 test_driver: use isinstance chain to replace Python 3.10's match statement
We still want to support Python 3.9 (debian-oldstable); it's still used by
our (outdated) FreeBSD CI, and, more importantly by (nightly) builders on OBS.

Ref: https://github.com/fish-shell/fish-shell/pull/11560#discussion_r2134556573
2025-06-12 11:20:55 +02:00
Johannes Altmanninger
6822a772fb Merge pull request #11573 2025-06-12 10:29:11 +02:00
Daniel Rainer
912d93c99d Remove tmpdirs at the end of tests 2025-06-11 22:33:32 +02:00
Johannes Altmanninger
74f4742565 Merge pull request #11567 2025-06-11 14:02:07 +02:00
Johannes Altmanninger
a47dcad1ea Clean up staticbuild CI action
- This action does not use CMake or CTest, so remove associated environment variables.
- Remove a seemingly unnecessary check

Tested with "gh --repo krobelus/fish-shell workflow run staticbuild.yml --ref=tmp", see
https://github.com/krobelus/fish-shell/actions/runs/15583255106/job/43883294589
2025-06-11 13:22:09 +02:00
Integral
63a08e53e5 Replace some PathBuf with Path avoid unnecessary heap allocation (#10929)
(cherry picked from commit b19a467ea6)
2025-06-11 11:38:53 +02:00
Erick Howard
62ac23453e Code cleanup in src/bin/fish.rs to make it more idiomatic (#10975)
Code cleanup in `src/bin/fish.rs` to make it more idiomatic

(cherry picked from commit 967c4b2272)
2025-06-11 11:31:05 +02:00
Johannes Altmanninger
69bd7cc9a5 Merge pull request #11561 2025-06-11 11:14:56 +02:00
Daniel Rainer
b56ee16aa9 Parallelize test_driver.py
This uses Python's `asyncio` to run tests in parallel, which speeds up test
execution significantly.

The timeout is removed. It would be possible to add a timeout to
`asyncio.as_completed()` if we want that.
2025-06-10 20:11:43 +02:00
Daniel Rainer
679cef9c0e Add async versions of littlecheck tests
These will be used by a parallelized version of `test_driver.py`.

The old, non-async versions are kept, but just a wrappers around the async
versions.
2025-06-10 20:11:43 +02:00
Daniel Rainer
01b623efce Do not modify env vars in test_driver.py
Such modifications would break tests when they run concurrently, as they will
when this script is parallelized using `asyncio`.
2025-06-10 20:11:36 +02:00
Daniel Rainer
aa627ea935 Allow specifying env for running test
This can be used instead of the default operating system variables.
Useful for running multiple tests which need different environments.
2025-06-10 19:37:47 +02:00
Daniel Rainer
c15a900f31 Fail on compilation failure 2025-06-10 19:37:47 +02:00
Daniel Rainer
1136e656e0 Remove --cachedir for test_driver.py
This was only used to cache `fish_test_driver`, which can be built in a few tens
of milliseconds on most systems.

This avoids using outdated binaries for testing and simplifies the code and its
usage.
2025-06-10 19:37:47 +02:00
Daniel Rainer
456c9254fa Annotate more run_test parameters
This helps with static analysis.

Rename the second argument to clarify what it refers to.
2025-06-10 19:37:47 +02:00
Daniel Rainer
ebc16e51d7 Build fish_test_helper at most once
If no `--cachedir` is specifed for `test_driver.py`, it would build
`fish_test_helper` once per test it runs. This is unnecessary. Instead, build it
once in the beginning before running any tests and then use the binary in all
tests.
2025-06-10 19:37:41 +02:00
Johannes Altmanninger
c052beb4dd Fix build on Rust 1.70 2025-06-10 17:56:21 +02:00
Daniel Rainer
2d7a6063b9 Remove unnecessary trailing space 2025-06-10 17:08:44 +02:00
Daniel Rainer
7c57b746d0 Use Path for some paths
The added type annotations help with static analysis and constructing paths gets
some syntactic sugar.
2025-06-10 17:07:19 +02:00
Johannes Altmanninger
e0cabacdaa kitty keyboard protocol: fall back to base layout key
On terminals that do not implement the kitty keyboard protocol "ctrl-ц" on
a Russian keyboard layout generally sends the same byte as "ctrl-w". This
is because historically there was no standard way to encode "ctrl-ц",
and the "ц" letter happens to be in the same position as "w" on the PC-101
keyboard layout.

Users have gotten used to this, probably because many of them are switching
between a Russian (or Greek etc.) and an English layout.

Vim/Emacs allow opting in to this behavior by setting the "input method"
(which probably means "keyboard layout").

Match key events that have the base layout key set against bindings for
that key.

Closes #11520

---

Alternatively, we could add the relevant preset bindings (for "ctrl-ц" etc.)
but
1. this will be wrong if there is a disagreement on the placement of "ц" between two layouts
2. there are a lot of them
3. it won't work for user bindings (for better or worse)

(cherry picked from commit 7a79728df3)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
59b9f57802 fish_key_reader: unopinionated description for bind notation variants
As explained in the parent commit, "alt-+" is usually preferred over
"alt-shift-=" but both have their moments. We communicate this via a comment
saying "# recommended notation". This is not always true and not super helpful,
especially as we add a third variant for #11520 (physical key), which is
the recommended one for users who switch between English and Cyrillic layouts.

Only explain what each variant does. Based on this the user may figure out
which one to use.

(cherry picked from commit 4cbd1b83f1)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
65fc2b539c Fix some invalid assertions parsing keys
For example the terminal sending « CSI 55296 ; 5 u » would crash fish.

(cherry picked from commit c7391d1026)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
3f1add9e21 Sanitize some inputs in CSI parser
This was copied from C++ code but we have overflow checks, which
forces us to actually handle errors.

While at it, add some basic error logging.

Fixes #11092

(cherry picked from commit 4c28a7771e)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
68d2cafa6e input: remove unnecessary check in bracketed paste code path
When "self.paste_is_buffering()" is true, "parse_escape_sequence()" explicitly
returns "None" instead of "Some(Escape)".  This is irrelevant because this
return value is never read, as long as "self.paste_is_buffering()" remains
true until "parse_escape_sequence()" returns, because the caller will return
early in that case. Paste buffering only ends if we actually read a complete
escape sequence (for ending bracketed paste).

Remove this extra branch.

(cherry picked from commit e5fdd77b09)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
b9d9e7edc6 Match bindings with explicit shift first
The new key notation canonicalizes aggressively, e.g.  these two bindings
clash:

	bind ctrl-shift-a something
	bind shift-ctrl-a something else

This means that key events generally match at most one active binding that
uses the new syntax.

The exception -- two coexisting new-syntax binds that match the same key
event -- was added by commit 50a6e486a5 (Allow explicit shift modifier for
non-ASCII letters, fix capslock behavior, 2025-03-30):

	bind ctrl-A 'echo A'
	bind ctrl-shift-a 'echo shift-a'

The precedence was determined by definition order.
This doesn't seem very useful.

A following patch wants to resolve #11520 by matching "ctrl-ц" events against
"ctrl-w" bindings. It would be surprising if a "ctrl-w" binding shadowed a
"ctrl-ц" one based on something as subtle as definition order.  Additionally,
definition order semantics (which is an unintended cause of the implementation)
is not really obvious.  Reverse definition order would make more sense.

Remove the ambiguity by always giving precedence to bindings that use
explicit shift.

Unrelated to this, as established in 50a6e486a5, explicit shift is still
recommended for bicameral letters but not typically for others -- e.g. alt-+
is typically preferred over alt-shift-= because the former also works on a
German keyboard.

See #11520

(cherry picked from commit 08c8afcb12)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
6b17ec7dae Allow explicit shift modifier for non-ASCII letters, fix capslock behavior
We canonicalize "ctrl-shift-i" to "ctrl-I".
Both when deciphering this notation (as given to builtin bind),
and when receiving it as a key event ("\e[105;73;6u")

This has problems:

A. Our bind notation canonicalization only works for 26 English letters.
   For example, "ctrl-shift-ä" is not supported -- only "ctrl-Ä" is.
   We could try to fix that but this depends on the keyboard layout.
   For example "bind alt-shift-=" and "bind alt-+" are equivalent on a "us"
   layout but not on a "de" layout.
B. While capslock is on, the key event won't include a shifted key ("73" here).
   This is due a quirk in the kitty keyboard protocol[^1].  This means that
   fish_key_reader's canonicalization doesn't work (unless we call toupper()
   ourselves).

I think we want to support both notations.

It's recommended to match all of these (in this order) when pressing
"ctrl-shift-i".

	1. bind ctrl-shift-i do-something
	2. bind ctrl-shift-I do-something
	3. bind ctrl-I do-something
	4. bind ctrl-i do-something

Support 1 and 3 for now, allowing both bindings to coexist. No priorities
for now. This solves problem A, and -- if we take care to use the explicit
shift notation -- problem B.

For keys that are not affected by capslock, problem B does not apply.  In this
case, recommend the shifted notation ("alt-+" instead of "alt-shift-=")
since that seems more intuitive.
Though if we prioritized "alt-shift-=" over "alt-+" as per the recommendation,
that's an argument against the shifted key.

Example output for some key events:

	$ fish_key_reader -cV
	# decoded from: \e\[61:43\;4u
	bind alt-+ 'do something' # recommended notation
	bind alt-shift-= 'do something'
	# decoded from: \e\[61:43\;68u
	bind alt-+ 'do something' # recommended notation
	bind alt-shift-= 'do something'

	# decoded from: \e\[105:73\;6u
	bind ctrl-I 'do something'
	bind ctrl-shift-i 'do something' # recommended notation
	# decoded from: \e\[105\;70u
	bind ctrl-shift-i 'do something'

Due to the capslock quirk, the last one has only one matching representation
since there is no shifted key.  We could decide to match ctrl-shift-i events
(that don't have a shifted key) to ctrl-I bindings (for ASCII letters), as
before this patch. But that case is very rare, it should only happen when
capslock is on, so it's probably not even a breaking change.

The other way round is supported -- we do match ctrl-I events (typically
with shifted key) to ctrl-shift-i bindings (but only for ASCII letters).
This is mainly for backwards compatibility.

Also note that, bindings without other modifiers currently need to use the
shifted key (like "Ä", not "shift-ä"), since we still get a legacy encoding,
until we request "Report all keys as escape codes".

[^1]: <https://github.com/kovidgoyal/kitty/issues/8493>

(cherry picked from commit 50a6e486a5)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
08d796890a Stop accepting "bind shift-A"
This notation doesn't make sense, use either A or shift-a.  We accept it
for ASCII letters only -- things like "bind shift-!" or "bind shift-Ä"
do not work as of today, we don't tolerate extra shift modifiers yet.
So let's remove it for consistency.

Note that the next commit will allow the shift-A notation again, but it will
not match shift-a events.

(cherry picked from commit 7f25d865a9)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
4f98ef36f6 Extract KeyEvent type
The be used in the grandchild commit.

(cherry picked from commit 855a1f702e)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
a09c78491f Extract function for creating key event with modifiers
(cherry picked from commit fabbbba037)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
02932d6b8c Extract constant for the number of function keys
Switch to fish_wcstoul because we want the constant to be unsigned.
It's u32 because most callers of function_key() want that.

(cherry picked from commit e9d1cdfe87)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
7cca98bda2 Fix regression decoding function keys
Commit 109ef88831 (Add menu and printscreen keys, 2025-01-01)
accidentally broke an assumption by inverting f1..f12.  Fix that.

Fixes #11098

(cherry picked from commit d2b2c5286a)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
b77fc28692 Add menu and printscreen keys
These aren't typically used in the terminal but they are present on
many keyboards.

Also reorganize the named key constants a bit.  Between F500 and
ENCODE_DIRECT_BASE (F600) we have space for 256 named keys.

(cherry picked from commit 109ef88831)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
3475531ef7 Also ignore invalid recursive escape sequences
We parse "\e\e[x" as alt-modified "Invalid" key.  Due to this extra
modifier, we accidentally add it to the input queue, instead of
dropping this invalid key.

We don't really want to try to extract some valid keys from this
invalid sequence, see also the parent commit.

This allows us to remove misplaced validation that was added by
e8e91c97a6 (fish_key_reader: ignore sentinel key, 2024-04-02) but
later obsoleted by 66c6e89f98 (Don't add collateral sentinel key to
input queue, 2024-04-03).

(cherry picked from commit 84f19a931d)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
8222ed891b Stop parsing invalid CSI/SS3 sequences as alt-[/alt-o
This situation can be triggered in practice inside a terminal like tmux
3.5 by running

	tmux new-session fish -C 'sleep 2' -d reader -o log-file

and typing "alt-escape x"

The log shows that we drop treat this as alt-[ and drop  the x on the floor.

	reader: Read char alt-\[ -- Key { modifiers: Modifiers { ctrl: false,
	alt: true, shift: false }, codepoint: '[' } -- [27, 91, 120]

This input ("\e[x") is ambiguous.

It looks like it could mean "alt-[,x".  However that conflicts with a
potential future CSI code, so it makes no sense to try to support this.

Returning "None" from parse_csi() causes this weird behavior of
returning "alt-[" and dropping the rest of the parsed sequence.
This is too easy; it has even crept into a bunch of places
where the input sequence is actually valid like "VT200 button released"
but where we definitely don't want to report any key.

Fix the default: report no key for all unknown sequences and
intentionally-suppressed sequences.  Treat it at "alt-[" only when
there is no input byte available, which is more or less unambiguous,
hence a strong enough signal that this is a actually "alt-[".

(cherry picked from commit 3201cb9f01)
2025-06-10 16:50:00 +02:00
Johannes Altmanninger
f787e6858c Fix tests/checks/autoload.fish
Apparently this test runs with "build/tests" as CWD when run with cmake.
2025-06-10 16:50:00 +02:00
Daniel Rainer
64442cb464 Use with syntax for tmpdir root 2025-06-10 16:20:56 +02:00
Lorenzo Albano
07ead04890 Improve fish_git_prompt stashes detection.
When the informative status is disabled, the stashstate variable was
set to 1 if the $git_dir/logs/refs/stash file existed and was readable,
even if the file itself was empty (i.e., no stashes). Now the stashstate
variable is set only if the file is NOT empty.
2025-06-09 13:16:24 +02:00
Johannes Altmanninger
5346d3d491 check-all-fish-files: don't glob the entire worktree
Commit 22c0054c1e (Add check to test all fish files with -n, 2020-02-17)
added a test that runs "fish --no-execute" on all fish files in share/**.fish

Commit 329cd7d429 (Make functions, completions and tests resilient to
running on an embed-data fish, 2025-03-25) change this to run it on **.fish.

Evidently "the tests are exempt because they contain syntax errors" is no
longer true - this is because we have since changed those files to recursively
run 'fish -c "syntax-error"', which makes it easier to test for multiple
syntax-errors in a single test file. Remove the comment.

Globbing everything seems a bit crass, and there's no explicit
motivation.

	$ time find -name '*.fish' >/dev/null
	Executed in  431.93 millis
	$ time find * -name '*.fish' >/dev/null
	Executed in   39.98 millis

Let's go back to testing only directories where we currently have Git-tracked
fish files.  This makes uncached "check-all-fish-files.fish" go from 26
seconds to 5 seconds.
2025-06-09 10:28:49 +02:00
Johannes Altmanninger
138c6c4c40 check-all-fish-files: remove unneeded fallback
According to commit 8a07db8e8f (Revert "Revert "Speed up check-all-fish-files
when executed locally"", 2021-03-06), we can assume "find -newer" is supported.
2025-06-09 10:28:49 +02:00
Johannes Altmanninger
f8751a4f97 check-all-fish-files: fix caching logic
check-all-fish-files takes a long time (>20 seconds here); which is why we
have a (hacky) optimization to avoid checking files we already checked.
This optimization hasn't worked since commit e96b6e157c (Remove TMPDIR
dependency from tests/, 2021-07-30) which started each test invocation in
a private tmpdir. Fix that.

The optimization is useful because this test is, by far, the bottleneck
for parallel test execution (#11561):

	$ cargo b && time tests/test_driver.py target/debug
	...
	checks/tmux-complete.fish                      PASSED    8465 ms
	checks/check-completions.fish                  PASSED   10948 ms
	checks/check-sphinx.fish                       PASSED   12949 ms
	checks/check-all-fish-files.fish               PASSED   29828 ms
	200 / 200 passed (0 skipped)
	________________________________________________________
	Executed in   31.00 secs    fish           external
	   usr time   81.02 secs  462.00 micros   81.02 secs
	   sys time   26.41 secs  272.00 micros   26.41 secs

A cache miss for check-all-fish-files.fish takes 24 seconds (though the
grandchild commit will speed this up), a cache hit 0.5 seconds.
2025-06-09 10:28:49 +02:00
Johannes Altmanninger
cdc2db5eae Update translations for git completions 2025-06-08 14:07:17 +02:00
Johannes Altmanninger
aea9cd6165 completions/git: sort stash completions after branches and others
Completions like "stash@{1}" don't give a lot of information, unlike local
branches which are sorted by recency so let's put those first.
2025-06-08 13:42:01 +02:00
Johannes Altmanninger
d0a490d76b completions/git: extract logic 2025-06-08 13:42:01 +02:00
Johannes Altmanninger
b4392f6f7d completions/git: extract function for adding arbitrary-revision-completion
Most Git commands take arbitrary revisions.  AFAICT, we usually want the same
order, e.g. list local branches before remote branches before commit IDs etc.
I think there is no particular reason why this order is inconsistent between
various subcommands.

Let's extract a function. This standardizes the order and adds various
revision-types that were missing for some subcommands.
2025-06-08 13:42:01 +02:00
Johannes Altmanninger
7f2f5bb2f4 completions/git: remove code clone 2025-06-08 13:26:12 +02:00
Johannes Altmanninger
c47ecf9677 completions/git: rebase --onto requires a revision argument 2025-06-08 13:21:55 +02:00
Johannes Altmanninger
cd45a8c5cc completions/git: add more special refs
These are things like .git/HEAD, i.e. the ones that are typically not
namespaced under .git/refs.  The list is taken from gitrevisions(7).
2025-06-08 13:21:55 +02:00
Johannes Altmanninger
99f78fb0b1 completions/git: fix copy-paste error
This variable is never defined. It was copied from Git's
contrib/completion/git-completion.bash where $match is probably equivalent
to $(commandline -t). I could not measure a significant speedup from passing
this filter to "git for-each-ref", so let's remove it for now.
2025-06-08 13:21:55 +02:00
Johannes Altmanninger
235108e2df CI rust_checks: cargo --workspace obsoletes --all
This flag exists since 1.39, see
https://doc.rust-lang.org/nightly/cargo/CHANGELOG.html#cargo-139-2019-11-07

While at it, remove the "--all" option from "cargo fmt",
since it's not needed for formatting the entire workspace,
and because it would also format path-dependencies, see
https://github.com/fish-shell/fish-shell/pull/11550#discussion_r2133674330
2025-06-08 13:21:12 +02:00
Johannes Altmanninger
e66b13ac3d Merge pull request #11560 2025-06-08 12:09:41 +02:00
Johannes Altmanninger
0c211cbffb Merge pull request #11564 2025-06-08 11:27:01 +02:00
Johannes Altmanninger
da5a394178 Merge pull request #11566 2025-06-08 11:25:41 +02:00
Johannes Altmanninger
59bfd3ba6c Merge pull request #11563 2025-06-08 11:25:32 +02:00
Daniel Rainer
631bde1081 Revert "Hide some calls to localize() via Deref/AsRef"
This reverts commit 894139933d.

Rationale in this comment thread:
https://github.com/fish-shell/fish-shell/pull/11547#discussion_r2133625349
2025-06-08 02:52:01 +02:00
cyclopentane
383d2aa3e9 Fix behaviour upon repeating a vi-mode t/T jump 2025-06-08 01:03:06 +02:00
Daniel Rainer
cac3d0ef16 Build before running style.fish
This makes the latest versions of fish_indent (and fish) available to
`style.fish`.
2025-06-07 20:21:29 +02:00
Daniel Rainer
4721ffe512 Remove unused variables 2025-06-07 19:31:06 +02:00
Daniel Rainer
df097b114c Put test tmpdirs under common root tmpdir
This is done to prepare for running the tests in parallel.
With this approach the root tmpdir can be created before any test starts, each
test can create its home dir under the root tmpdir,
and when all tests are done the root tmpdir can be deleted.
Deletion of per-test dirs is more difficult in an async context.
2025-06-07 19:30:44 +02:00
Daniel Rainer
2ebe3134cf Extract function for running tests
This is done to prepare for running tests concurrently.

Align output and prevent flushing stdout between test name and result.
2025-06-07 19:28:58 +02:00
David Adam
d663f553df document alt-s binding programs more clearly 2025-06-07 22:47:56 +08:00
Shayan
dcde198c94 completions/adb: add listing device files for exec-out subcommand 2025-06-07 22:44:57 +08:00
Daniel Rainer
b5c393dc39 Add simple script for running checks
This is intended as a way to run all available checks with a single command.

The script can be used locally and in CI. It is intended to replace
`cmake/Tests.cmake` (but this script also runs checks not present there).
At the moment, `ctest` is not used, which could be added to speed up tests.

Address and thread sanitizers are not run by this script.
2025-06-07 15:34:53 +02:00
Daniel Rainer
f0a54510c3 Format files using build_tools/style.fish 2025-06-07 15:34:53 +02:00
Daniel Rainer
d18d414745 Improve style.fish
Add flags to control behavior.
- `--check` to fail if changes would be made by formatters
- `--force` to skip the prompt about uncommitted changes

Fix behavior when `--all` is not specified. It used to operate on `$files`,
which did not get set in that case.

Not all fish files are considered, mainly because some tests might test how fish
behaves on weirdly formatted files.

For Rust files, `cargo fmt` is used when `--all` is specified.
The `--check` flag for `cargo fmt` is used when appropriate.

Do not try to build `fish_indent`. `make fish_indent` does not work anymore. Let
the user handle building and installing/setting `$PATH`.
2025-06-07 15:34:53 +02:00
Johannes Altmanninger
ac44b3da91 build_tools/fish_xgettext.fish: fix formatting 2025-06-07 11:15:44 +02:00
Johannes Altmanninger
0903e7a8f2 Merge pull request #11557 2025-06-07 10:20:30 +02:00
Johannes Altmanninger
894139933d Hide some calls to localize() via Deref/AsRef
As suggested in https://github.com/fish-shell/fish-shell/pull/11547#discussion_r2133625349
AsRef is needed for OutputStream::append which has this signature:

	pub fn append<Str: AsRef<wstr>>(&mut self, s: Str) -> bool
2025-06-07 10:20:30 +02:00
Johannes Altmanninger
1aec1d3955 Merge pull request #11547
Supersedes previous approaches:
Closes #11543
Closes #11536
2025-06-07 10:20:30 +02:00
Daniel Rainer
a138bc328b Fix eager cloning
https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned
2025-06-07 00:22:52 +02:00
Daniel Rainer
b9583bb16a Document call sites of from_external_source
This is intended to provide information to programmers where localizations might
be coming from, and potentially help with analyzing issues with localizations.
2025-06-07 00:10:10 +02:00
Daniel Rainer
80033adcf5 Use LocalizableString for gettext
This new wrapper type can be constructed via macros which invoke the
`gettext_extract` proc macro to extract the string literals for PO file
generation.

The type checking enabled by this wrapper should prevent trying to obtain
translations for a string for which none exist.

Because some strings (e.g. for completions) are not defined in Rust, but rather
in fish scripts, the `LocalizableString` type can also be constructed from
non-literals, in which case no extraction happens.
In such cases, it is the programmer's responsibility to only construct the type
for strings which are available for localization.

This approach is a replacement for the `cargo-expand`-based extraction.

When building with the `FISH_GETTEXT_EXTRACTION_FILE` environment variable set,
the `gettext_extract` proc macro will write the messages marked for extraction
to a file in the directory specified by the variable.

Updates to the po files:
- This is the result of running the `update_translations.fish` script using the
  new proc_macro extraction. It finds additional messages compared to the
  `cargo-expand` based approach.
- Messages IDs corresponding to paths are removed. The do not have localizations
  in any language and localizing paths would not make sense. I have not
  investigated how they made it into the po files in the first place.
- Some messages are reordered due to `msguniq` sorting differing from `sort`.

Remove docs about installing `cargo-expand`
These are no longer needed due to the switch to our extraction macro.
2025-06-07 00:10:05 +02:00
Daniel Rainer
51a57870eb Make help error message localizable 2025-06-07 00:02:31 +02:00
Daniel Rainer
98b3ba5e8e Remove concat! macro from localized strings
This is done in preparation for a proc macro which extracts strings which are
passed to `gettext`. Because the `concat!` macro would get expanded after the
proc macro, the proc macro would still see the `concat!`, which it cannot
handle.
2025-06-07 00:02:14 +02:00
Johannes Altmanninger
08bf5c92a9 Merge pull request #11545 2025-06-06 12:54:55 +02:00
Johannes Altmanninger
a84048511e Merge pull request #11542 2025-06-06 11:54:45 +02:00
Fabian Boehm
a014166795 completions/nmcli: Complete at runtime
This used to get all the interfaces and ssids when the completions
were loaded. That's obviously wrong, given that ssids especially can, you know, change

(cherry picked from commit 9116c61736)

cherry-picking since this easy to trigger
(seen again in https://github.com/fish-shell/fish-shell/pull/11549)
2025-06-06 11:52:17 +02:00
Johannes Altmanninger
46e8f12dbf Merge pull request #11554 2025-06-05 14:28:36 +02:00
Dennis Huang
7fe92be405 Add --all option to path
- Add --all option to path
- Add tests
- Add doc
2025-06-05 14:10:47 +02:00
Chinmay Dalal
366034940f Add run0 to alt-s commands
https://www.freedesktop.org/software/systemd/man/devel/run0.html
Since everyone using a systemd distro will have this, it's added
at the end so that it's tried last
2025-06-04 20:00:52 +05:30
Daniel Rainer
6239cba1e4 Add dry-run mode to update_translations.fish
This mode is intended for testing if the PO files are up-to-date and
well-formed.

At the moment, we only check translations in CI, where this is not particularly
relevant. Once we no longer need `cargo-expand`
(e.g. via https://github.com/fish-shell/fish-shell/pull/11536)
we can extend the `check_translations.fish` test to run
`update_translations.fish --dry-run` and fail if the exit status is nonzero.
2025-06-02 03:18:25 +02:00
Daniel Rainer
8c5de9acfb Remove manual contains
See https://rust-lang.github.io/rust-clippy/master/index.html#manual_contains.

The old code results in a clippy warning on Rust 1.87.
2025-05-31 12:56:58 +02:00
Daniel Rainer
75d243faaa Check rustdocs in CI
Setting `RUSTDOCFLAGS='-D warnings'` is needed to fail on warnings.
For `cargo test --doc` no equivalent option seems to exist.
See https://github.com/rust-lang/cargo/issues/14802.
2025-05-30 21:32:40 +02:00
Daniel Rainer
ba86028aaa Fix rustdoc warning 2025-05-30 21:32:40 +02:00
Johannes Altmanninger
f7e639504a completions/git: improve idempotency in case of double load
As mentioned in the previous few commits and in #11535, running
"set fish_complete_path ..."  and "complete -C 'git ...'"  may result in
"share/completions/git.fish" being loaded multiple times.

This is usually fine because fish internally erases all cached completions
whenever fish_complete_path changes.

Unfortunately there is at least global variable that grows each time git.fish
is sourced. This doesn't make a functional difference but it does slow
down completions.  Fix that by resetting the variable at load time.

(cherry picked from commit 4b5650ee4f)
2025-05-29 18:01:22 +02:00
Johannes Altmanninger
028b60cad6 Fix "set fish_complete_path" accidentally disabling autoloading
Commit 5918bca1eb (Make "complete -e" prevent completion autoloading,
2024-08-24) makes "complete -e foo" add a tombstone for "foo", meaning we
will never again load completions for "foo".

Due to an oversight, the same tombstone is added when we clear cached
completions after changing "fish_complete_path", preventing completions from
being loaded in that case.  Fix this by restoring the old behavior unless
the user actually used "complete -e".

(cherry picked from commit a7c04890c9)
2025-05-29 18:01:04 +02:00
Johannes Altmanninger
7a79728df3 kitty keyboard protocol: fall back to base layout key
On terminals that do not implement the kitty keyboard protocol "ctrl-ц" on
a Russian keyboard layout generally sends the same byte as "ctrl-w". This
is because historically there was no standard way to encode "ctrl-ц",
and the "ц" letter happens to be in the same position as "w" on the PC-101
keyboard layout.

Users have gotten used to this, probably because many of them are switching
between a Russian (or Greek etc.) and an English layout.

Vim/Emacs allow opting in to this behavior by setting the "input method"
(which probably means "keyboard layout").

Match key events that have the base layout key set against bindings for
that key.

Closes #11520

---

Alternatively, we could add the relevant preset bindings (for "ctrl-ц" etc.)
but
1. this will be wrong if there is a disagreement on the placement of "ц" between two layouts
2. there are a lot of them
3. it won't work for user bindings (for better or worse)
2025-05-29 17:57:38 +02:00
Johannes Altmanninger
4cbd1b83f1 fish_key_reader: unopinionated description for bind notation variants
As explained in the parent commit, "alt-+" is usually preferred over
"alt-shift-=" but both have their moments. We communicate this via a comment
saying "# recommended notation". This is not always true and not super helpful,
especially as we add a third variant for #11520 (physical key), which is
the recommended one for users who switch between English and Cyrillic layouts.

Only explain what each variant does. Based on this the user may figure out
which one to use.
2025-05-29 17:57:38 +02:00
Johannes Altmanninger
3ab6fcf21c fish_key_reader: show most specific key notation first
As of the parent commit, "ctrl-shift-x" bindings will take precedence over
"ctrl-X". Have fish_key_reader imply this via the ordering The next commit
will make this more explicit.
2025-05-29 17:57:38 +02:00
Johannes Altmanninger
08c8afcb12 Match bindings with explicit shift first
The new key notation canonicalizes aggressively, e.g.  these two bindings
clash:

	bind ctrl-shift-a something
	bind shift-ctrl-a something else

This means that key events generally match at most one active binding that
uses the new syntax.

The exception -- two coexisting new-syntax binds that match the same key
event -- was added by commit 50a6e486a5 (Allow explicit shift modifier for
non-ASCII letters, fix capslock behavior, 2025-03-30):

	bind ctrl-A 'echo A'
	bind ctrl-shift-a 'echo shift-a'

The precedence was determined by definition order.
This doesn't seem very useful.

A following patch wants to resolve #11520 by matching "ctrl-ц" events against
"ctrl-w" bindings. It would be surprising if a "ctrl-w" binding shadowed a
"ctrl-ц" one based on something as subtle as definition order.  Additionally,
definition order semantics (which is an unintended cause of the implementation)
is not really obvious.  Reverse definition order would make more sense.

Remove the ambiguity by always giving precedence to bindings that use
explicit shift.

Unrelated to this, as established in 50a6e486a5, explicit shift is still
recommended for bicameral letters but not typically for others -- e.g. alt-+
is typically preferred over alt-shift-= because the former also works on a
German keyboard.

See #11520
2025-05-29 17:57:38 +02:00
Johannes Altmanninger
3951a858dd reader: do not send queries if stdout is not a terminal
Interactive fish with output redirected ("fish >/dev/null")
is not a common use case but it is valid.

Perhaps surprisingly, "fish >some-file" *does* print terminal escape codes
(colors, cursor movement etc.) even if terminal output is not a TTY.
This is typically harmless, and potentially useful for debugging.

We also send blocking terminal queries but those are not harmless in this case.
Since no terminal will receive the queries, we hang; indefinitely as of today,
but we should give up after a timeout and print an error.  Either way that
seems needlessly surprising. Suppress queries in this case.

In future, we should probably do something similar if stdin is not a terminal;
though in that case we're even less likely to be interactive (only "-i"
I think).
2025-05-29 17:57:38 +02:00
Johannes Altmanninger
c7a19a00ab reader: minor simplification 2025-05-29 17:57:38 +02:00
Johannes Altmanninger
e5fdd77b09 input: remove unnecessary check in bracketed paste code path
When "self.paste_is_buffering()" is true, "parse_escape_sequence()" explicitly
returns "None" instead of "Some(Escape)".  This is irrelevant because this
return value is never read, as long as "self.paste_is_buffering()" remains
true until "parse_escape_sequence()" returns, because the caller will return
early in that case. Paste buffering only ends if we actually read a complete
escape sequence (for ending bracketed paste).

Remove this extra branch.
2025-05-29 17:57:38 +02:00
Johannes Altmanninger
3fcdbe1a19 Discard input queue when ctrl-c is pressed while waiting for query response
On startup, we block until the terminal responds to our primary device
attribute query.
As an escape hatch, ctrl-c makes us stop waiting.

No keys are discarded; even ctrl-c is still enqueued.  Usually this isn't
noticed because typing "echo<ctrl-c>" will insert a "echo" only to immediately
clear it.

The double interpretation of ctrl-c seems odd.
Additionally, the queuing seems unsafe considering that when typing something
like "echo hello<enter><ctrl-c>" the command will be executed.

Clear the queue instead, including ctrl-c.
This matches other programs like gdb, Kakoune and possibly others.
2025-05-29 17:57:38 +02:00
Johannes Altmanninger
2071df126c Idiomatic type for reader_readline nchars argument 2025-05-29 17:57:38 +02:00
Johannes Altmanninger
4b5650ee4f completions/git: improve idempotency in case of double load
As mentioned in the previous few commits and in #11535, running
"set fish_complete_path ..."  and "complete -C 'git ...'"  may result in
"share/completions/git.fish" being loaded multiple times.

This is usually fine because fish internally erases all cached completions
whenever fish_complete_path changes.

Unfortunately there is at least global variable that grows each time git.fish
is sourced. This doesn't make a functional difference but it does slow
down completions.  Fix that by resetting the variable at load time.
2025-05-29 17:57:38 +02:00
Johannes Altmanninger
5657f093e7 Test case for autoload + erase + autoload
Commit 5918bca1eb (Make "complete -e" prevent completion autoloading,
2024-08-24) has a weird "!removed" check; it was added because "complete
-e" only needs to create the tombstone if we removed nothing.  Otherwise the
autoloader will usually take care of not loading the removed completions again.
We should probably get rid of "!removed"..  for now add a test to demonstrate
this behavior.
2025-05-29 17:57:38 +02:00
Johannes Altmanninger
a7c04890c9 Fix "set fish_complete_path" accidentally disabling autoloading
Commit 5918bca1eb (Make "complete -e" prevent completion autoloading,
2024-08-24) makes "complete -e foo" add a tombstone for "foo", meaning we
will never again load completions for "foo".

Due to an oversight, the same tombstone is added when we clear cached
completions after changing "fish_complete_path", preventing completions from
being loaded in that case.  Fix this by restoring the old behavior unless
the user actually used "complete -e".
2025-05-29 17:57:38 +02:00
Johannes Altmanninger
52f23b9752 autoload: add more details to autoload-result log 2025-05-29 17:50:48 +02:00
Johannes Altmanninger
6737872fb7 embed-data: naturalize generated_completions-hack to prevent repeated autoloading
As reported in https://github.com/fish-shell/fish-shell/issues/11535#issuecomment-2915440295,
a command like "complete -C'git '" gets progressively slower every time.

A diff of "fish_trace=1" output shows that each completion invocation added
more stuff to the global "__fish_git_aliases", resulting in output like:

	--> for s db
	...
	--> for s db s db
	...
	--> for s db s db s db

Reproducer:

	$ touch ~/.local/share/fish/generated_completions/foo.fish
	$ cargo install --path . --debug
	$ ~/.cargo/bin/fish -d autoload -c 'function foo; end; for i in 1 2; complete -C"foo "; end'

We redundantly autoload the embedded file, which, by definition doesn't change.
This happens when
1. the "embed-data" feature is enabled (default for "cargo install")
2. there is a completion file in generated_completions

which triggers a hack to give precedence to "embedded:completions/git.fish"
over "generated_completions/git.fish".

Since we always load all file-based files first, we clobber the autoload cache
("self.autoloaded_files") with the mtime of the generated completion file, even
if we're never gonna return it.  This makes the embed-data logic think that
the asset has changed (which is impossible! But of course it is possible that
"fish_complete_path" changes and causes a need to load "embedded:git.fish").

Fix that by treating embedded files more like normal files.  This is closer
to historical behavior where $__fish_data_dir/{functions,completions}
are normal directories. Seems like this should fix a false negative in
"has_attempted_autoload" which feels useful.

Add a dead test, I guess. It's not run with feature="embed-data" yet. In
future we should test this in CI.
2025-05-29 17:38:42 +02:00
Johannes Altmanninger
f88f7e8dd6 autoload: remove code clone 2025-05-29 16:39:52 +02:00
Johannes Altmanninger
b3dbdb90c2 On enter, insert any failed search into the command line
This might help with use cases such as https://github.com/fish-shell/fish-shell/pull/11450.
Not sure.
2025-05-29 16:39:52 +02:00
Johannes Altmanninger
dc129add9e Assert that autosuggestions are always valid
This documents an invariant established by 532abaddae (Invalidate stale
autosuggestions eagerly, 2024-12-25). It was initially broken but fixed in
ba4ead6ead (Stop saving autosuggestions that we can't restore, 2025-01-17).
2025-05-29 16:39:52 +02:00
Johannes Altmanninger
19c3bebdd9 Merge pull request #11506 2025-05-29 16:23:19 +02:00
Johannes Altmanninger
093b468ac1 Merge pull request #11502 2025-05-29 16:06:24 +02:00
Johannes Altmanninger
88bbf5f3ac Merge pull request #11497 2025-05-29 16:06:11 +02:00
Daniel Rainer
ec8fa7485c Improve docs for string join 2025-05-28 17:09:13 +02:00
Daniel Rainer
c2e2237e7c Add a test which fails on sphinx warning/failure 2025-05-28 15:32:13 +02:00
Daniel Rainer
98df97d317 Add CI check for outdated translations 2025-05-27 16:48:33 +02:00
Daniel Rainer
7ca57894cc Update translations via script
No actual translations are added.
2025-05-27 16:48:20 +02:00
Johannes Altmanninger
c7391d1026 Fix some invalid assertions parsing keys
For example the terminal sending « CSI 55296 ; 5 u » would crash fish.
2025-05-27 14:33:09 +02:00
Johannes Altmanninger
1963b0830d Merge pull request #11517 2025-05-27 13:15:34 +02:00
Johannes Altmanninger
74ce965f32 Merge pull request #11522 2025-05-27 13:15:34 +02:00
Johannes Altmanninger
27420aaf8b Merge pull request #11528 2025-05-27 13:15:34 +02:00
Johannes Altmanninger
52cdb7fd62 functions/history: error out immediately if "builtin read" failed
Didn't test all of them..

Closes #11532
2025-05-27 13:15:33 +02:00
exploide
18c4debbc0 __fish_complete_man: cope with gzipped man pages 2025-05-25 11:48:28 +02:00
Johannes Altmanninger
b11e22d905 Fix uvar file mtime force-update (Rust port regression)
When two fish processes rewrite the uvar file concurrent, they rely on the
uvar file's mtime (queried after taking a lock, if locking is supported) to
tell us whether their view of the uvar file is still up-to-date.  If it is,
they proceed to move it into place atomically via rename().

Since the observable mtime only updates on every OS clock tick, we call
futimens() manually to force-update that, to make sure that -- unless both
fish conincide on the same *nanosecond* -- other fish will notice that the
file changed.

Unfortunately, commit 77aeb6a2a8 (Port execution, 2023-10-08) accidentally
made us call futimens() only if clock_gettime() failed, instead of when
it succeeded. This means that we need to wait for the next clock tick to
observe a change in mtime.
Any resulting false negatives might have caused us to drop universal variable updates.

Reported in https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2098948362

See #10300

(cherry picked from commit 8617964d4d)
2025-05-23 08:50:17 +02:00
Johannes Altmanninger
8617964d4d Fix uvar file mtime force-update (Rust port regression)
When two fish processes rewrite the uvar file concurrent, they rely on the
uvar file's mtime (queried after taking a lock, if locking is supported) to
tell us whether their view of the uvar file is still up-to-date.  If it is,
they proceed to move it into place atomically via rename().

Since the observable mtime only updates on every OS clock tick, we call
futimens() manually to force-update that, to make sure that -- unless both
fish conincide on the same *nanosecond* -- other fish will notice that the
file changed.

Unfortunately, commit 77aeb6a2a8 (Port execution, 2023-10-08) accidentally
made us call futimens() only if clock_gettime() failed, instead of when
it succeeded. This means that we need to wait for the next clock tick to
observe a change in mtime.
Any resulting false negatives might have caused us to drop universal variable updates.

Reported in https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2098948362

See #10300
2025-05-23 08:49:41 +02:00
wcbing
0d99859add completions/apt & apt-get: Let autoremove and autopurge take packages
- add complete for apt-get's autopurge
- continue #7095, add complete for apt/apt-get's autoremove and autopurge
2025-05-21 12:11:24 +08:00
nicole
0b8e0b8835 Add more completions to aptitude 2025-05-20 16:39:38 -03:00
Johannes Altmanninger
33f8415785 Fixup history file EINTR loop to actually loop
Fixes d84e68dd4f (Retry history file flock() on EINTR, 2025-05-20).

(cherry picked from commit 3867163193)
2025-05-20 17:19:12 +02:00
Johannes Altmanninger
3867163193 Fixup history file EINTR loop to actually loop
Fixes d84e68dd4f (Retry history file flock() on EINTR, 2025-05-20).
2025-05-20 17:17:12 +02:00
Johannes Altmanninger
5ccd155177 Retry history file flock() on EINTR
When locking the uvar file, we retry whenever flock() fails with EINTR
(e.g. due to ctrl-c).

But not when locking the history file.  This seems wrong; all other libc
functions in the "history_file" code path do retry.

Fix that. In future we should extract a function.

Note that there are other inconsistencies; flock_uvar_file() does not
shy away from remote file systems and does not respect ABANDONED_LOCKING.
This means that empirically probably neither are necessary; let's make things
consistent in future.

See https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2095096200
Might help #10300

(cherry picked from commit 4d84e68dd4)
2025-05-20 15:32:56 +02:00
Johannes Altmanninger
0f8d3a5174 Revert "Temporarily enable history_file debug category by default"
Commit f906a949cf (Temporarily enable history_file debug category by default,
2024-10-09) enabled the "history_file" debug category by default to gather
more data.

Judging from
https://github.com/fish-shell/fish-shell/issues/10300#issuecomment-2876718382
the logs didn't help, or were at least not visible when logging to stderr
(due to reboot).

Let's disable "history_file" logs again to remove potential
noise if the file system is read-only, disk is full etc., see
https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2094781120

See #10300

(cherry picked from commit 285a810814)
2025-05-20 15:31:57 +02:00
Johannes Altmanninger
4d84e68dd4 Retry history file flock() on EINTR
When locking the uvar file, we retry whenever flock() fails with EINTR
(e.g. due to ctrl-c).

But not when locking the history file.  This seems wrong; all other libc
functions in the "history_file" code path do retry.

Fix that. In future we should extract a function.

Note that there are other inconsistencies; flock_uvar_file() does not
shy away from remote file systems and does not respect ABANDONED_LOCKING.
This means that empirically probably neither are necessary; let's make things
consistent in future.

See https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2095096200
Might help #10300
2025-05-20 15:31:33 +02:00
Johannes Altmanninger
285a810814 Revert "Temporarily enable history_file debug category by default"
Commit f906a949cf (Temporarily enable history_file debug category by default,
2024-10-09) enabled the "history_file" debug category by default to gather
more data.

Judging from
https://github.com/fish-shell/fish-shell/issues/10300#issuecomment-2876718382
the logs didn't help, or were at least not visible when logging to stderr
(due to reboot).

Let's disable "history_file" logs again to remove potential
noise if the file system is read-only, disk is full etc., see
https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2094781120

See #10300
2025-05-20 15:31:33 +02:00
Johannes Altmanninger
541a069a91 CI: fix detection of path to llvm-symbolizer
clang --version here outputs "clang version 19.1.7"
but it looks like that changed on GHA's Ubuntu runner:

	++ clang --version
	++ awk 'NR==1 { split($NF, version, "."); print version[1] }'
	+ llvm_version='(1ubuntu1)'

which leads to

	  The CHECK on line 7 wants:
	    abbr -a -- cuckoo somevalue # imported from a universal variable, see `help abbr`

	  but there was no remaining output to match.

	  additional output on stderr:1:111:
	    =================================================================
	    ==4680==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7bc287a5d402 at pc 0x55e597fa96b6 bp 0x7ffd2bc00700 sp 0x7ffd2bbffea8
	    READ of size 18 at 0x7bc287a5d402 thread T0
	    ==4680==WARNING: invalid path to external symbolizer!
	    ==4680==WARNING: Failed to use and restart external symbolizer!

Fix that, assuming that "clang --version" always matches the latest symbolizer
that is installed.  While at it, leave a "set -x" (which should be the
default for CI), and install llvm explicitly.
2025-05-20 14:28:38 +02:00
Johannes Altmanninger
e8864ef441 Fix stack-use-after-scope
I missed this in 7c2c7f5874 (Use uninit instead of zeroed, 2025-05-19).
See #11515
2025-05-20 14:18:04 +02:00
Johannes Altmanninger
2f708a7c0b Fix unused import 2025-05-20 12:49:25 +02:00
Johannes Altmanninger
b7a73710e2 Merge pull request #11515 2025-05-20 12:49:04 +02:00
Johannes Altmanninger
7a54ed66fb Merge pull request #11514 2025-05-20 12:39:04 +02:00
Johannes Altmanninger
99f4c09ed3 Merge pull request #11513 2025-05-20 12:39:04 +02:00
Johannes Altmanninger
c4a26cb2b1 builtin status: remove spurious newline from current-command (Rust port regression)
WHen "status current-command" is called outside a function it always returns
"fish". An extra newline crept in, fix that.

Fixes 77aeb6a2a8 (Port execution, 2023-10-08).
Fixes #11503

(cherry picked from commit e26b585ce5)
2025-05-20 12:33:01 +02:00
Johannes Altmanninger
e26b585ce5 builtin status: remove spurious newline from current-command (Rust port regression)
WHen "status current-command" is called outside a function it always returns
"fish". An extra newline crept in, fix that.

Fixes 77aeb6a2a8 (Port execution, 2023-10-08).
Fixes #11503
2025-05-20 12:32:22 +02:00
王宇逸
7c2c7f5874 Use uninit instead of zeroed 2025-05-19 20:54:12 +08:00
Yuyi Wang
7b3a2900e9 Refactor *NullTerminatedArray
* Remove `strlen_safe` & `null_terminated_array_length` and use the provided method of `OwningNullTerminatedArray`.
* Remove unneeded traits and make `NullTerminatedArray` private.
2025-05-19 17:24:24 +08:00
Yuyi Wang
7a79366f91 Use CStr instead of strlen to improve readability 2025-05-19 16:47:09 +08:00
Yuyi Wang
223b98f2ff Fix build.rs to support cross-compiling to cygwin (#11512)
2719ae4 adds a special cfg for cygwin to avoid annoying warnings. As cygwin target is usually cross-compiled, cfg! is not enough to detect the correct target. This PR uses CARGO_CFG_TARGET_OS env var instead.
2025-05-19 10:27:04 +02:00
Yuyi Wang
01560bf195 Remove libc sem completely on non-linux (#11511)
As it's only used on Linux, we can cfg it out completely on other platforms. It also enables test_topic_monitor_torture on NetBSD & Cygwin.
2025-05-19 10:26:47 +02:00
Daniel Rainer
7fe34ea401 Move and rename messages template file
There is no reason to have this file clutter the repo root.
Move it into the `po` directory, and give it a more descriptive name.

Inspired by this discussion:
https://github.com/fish-shell/fish-shell/pull/11463#discussion_r2083453275

I use `template.po` instead of `message.po-template` to be more compatible with
automatic filetype detection. (e.g. vim/nvim detect the former as a po file, but
the latter as a conf file)
2025-05-18 21:31:00 -07:00
Johannes Altmanninger
7228cb15bf Include sys/statvfs.h for the definition of ST_LOCAL (Rust port regression)
See https://man.netbsd.org/statvfs.5.
According to https://github.com/NetBSD/src/blob/trunk/sys/sys/statvfs.h#L135,
NetBSD has "#define ST_LOCAL MNT_LOCAL".  So this commit likely makes no
difference on existing systems.

While at it
- comment include statements
- remove a code clone

See #11486

(cherry picked from commit d68f8bdd3b)
2025-05-16 08:21:56 +02:00
Alan Somers
d5b46d6535 Fix remote filesystem detection on FreeBSD
Need an extra include to get the definition of MNT_LOCAL

Fixes #11483

(cherry picked from commit 7f4998ad9b)
2025-05-16 08:21:25 +02:00
Johannes Altmanninger
36f035b52c Merge pull request #11501 2025-05-16 07:36:03 +02:00
Johannes Altmanninger
0e8edab872 Fix typo 2025-05-16 07:35:43 +02:00
Johannes Altmanninger
448d630d0c Merge pull request #11500 2025-05-16 07:35:34 +02:00
Johannes Altmanninger
38fb2cfd6d Merge pull request #11499 2025-05-16 07:32:45 +02:00
Johannes Altmanninger
d68f8bdd3b Include sys/statvfs.h for the definition of ST_LOCAL (Rust port regression)
See https://man.netbsd.org/statvfs.5.
According to https://github.com/NetBSD/src/blob/trunk/sys/sys/statvfs.h#L135,
NetBSD has "#define ST_LOCAL MNT_LOCAL".  So this commit likely makes no
difference on existing systems.

While at it
- comment include statements
- remove a code clone

See #11486
2025-05-16 07:31:26 +02:00
Johannes Altmanninger
80bafd5a22 Merge pull request #11486 2025-05-16 07:12:47 +02:00
Daniel Rainer
ae8c5eaab7 Fix rst formatting issues 2025-05-16 00:30:34 +02:00
Daniel Rainer
329d190fbf Update translation docs
This is done in accordance with the recent changes to our translation pipeline.
2025-05-15 22:35:05 +02:00
Daniel Rainer
e5fa047412 Mark format strings in po files
This allows msgfmt to detect issues with translations of format strings.
The detection used here is very simple. It just checks if a string contains '%',
and if it does, the entry in the po file is preceded by '#, c-format'.
Any entries with this marker are checked by msgfmt in our tests, so if an issue
arises, we will notice before it is merged.
2025-05-15 22:09:57 +02:00
Daniel Rainer
cb31887941 Do not hardcode xgettext output path
Instead output on stdout, which lets the caller decide what to do with it.
2025-05-13 21:18:39 +02:00
Johannes Altmanninger
d4b4d44f14 Fix Vi mode glitch when replacing at last character
Another regression from d51f669647 (Vi mode: avoid placing cursor beyond last
character, 2024-02-14) "Unfortunately Vi mode sometimes needs to temporarily
select past end". So do the replace_one mode bindings which were forgotten.

Fix this.

This surfaces a tricky problem: when we use something like

	bind '' self-insert some-command

When key event "x" matches this generic binding, we insert both "self-insert"
and "some-command" at the front of the queue, and do *not* consume "x",
since the binding is empty.

Since there is a command (that might call "exit"), we insert a check-exit
event too, after "self-insert some-command" but _before_ "x".

The check-exit event makes "self-insert" do nothing. I don't think there's a
good reason for this; self-insert can only be triggered by a key event that
maps to self-insert; so there must always be a real key available for it to
consume. A "commandline -f self-insert" is a nop. Skip check-exit here.

Fixes #11484

(cherry picked from commit 107e4d11de)
2025-05-13 00:31:22 +02:00
Johannes Altmanninger
b8cfd6d12b Fix typo causing wrong cursor position after Vi mode paste
Regressed in d51f669647 (Vi mode: avoid placing cursor beyond last character,
2024-02-14).

(cherry picked from commit 50500ec5b9)
2025-05-13 00:31:09 +02:00
Johannes Altmanninger
04fd697ac9 CONTRIBUTING: update docs on how to create a new translation 2025-05-13 00:29:05 +02:00
Johannes Altmanninger
2558d13361 Merge pull request #11488 2025-05-13 00:21:49 +02:00
Daniel Rainer
02ccf25443 Prettify profiling for multi-line commands
The old version just prints the entire command being profiled as-is.
If such a command consists of more than one line, these lines do not have any
padding, and thus visually interfere with the timings.

This commit adds padding, such that all lines but the first one have padding
prepended, such that the original line content starts at the column in which the
first line starts.

This does not work perfectly for subcommands (in the profiling sense,
where the command starts with (regex) '-+>' instead of just '>').
In such cases, even if the command string is indented in the source, the command
will not start with whitespace. However, subsequent lines are not trimmed, so
the might be indented farther than they should be relative to the first line of
the command.
2025-05-13 00:11:33 +02:00
Johannes Altmanninger
a88acb9715 Merge pull request #11487 2025-05-13 00:01:11 +02:00
Johannes Altmanninger
8d3ad0c3c3 Merge pull request #11485 2025-05-13 00:01:11 +02:00
Johannes Altmanninger
660f52ee4f Merge pull request #11463 2025-05-13 00:01:11 +02:00
Johannes Altmanninger
594b8730d8 completions/git: fix regression causing wrong remote-branch completions
Fixes 54971621de (completions/git: show url as description for remote
completion, 2025-04-13).
Fixes #11482
2025-05-13 00:01:11 +02:00
Johannes Altmanninger
107e4d11de Fix Vi mode glitch when replacing at last character
Another regression from d51f669647 (Vi mode: avoid placing cursor beyond last
character, 2024-02-14) "Unfortunately Vi mode sometimes needs to temporarily
select past end". So do the replace_one mode bindings which were forgotten.

Fix this.

This surfaces a tricky problem: when we use something like

	bind '' self-insert some-command

When key event "x" matches this generic binding, we insert both "self-insert"
and "some-command" at the front of the queue, and do *not* consume "x",
since the binding is empty.

Since there is a command (that might call "exit"), we insert a check-exit
event too, after "self-insert some-command" but _before_ "x".

The check-exit event makes "self-insert" do nothing. I don't think there's a
good reason for this; self-insert can only be triggered by a key event that
maps to self-insert; so there must always be a real key available for it to
consume. A "commandline -f self-insert" is a nop. Skip check-exit here.

Fixes #11484
2025-05-13 00:01:11 +02:00
Johannes Altmanninger
50500ec5b9 Fix typo causing wrong cursor position after Vi mode paste
Regressed in d51f669647 (Vi mode: avoid placing cursor beyond last character,
2024-02-14).
2025-05-12 22:57:20 +02:00
Daniel Rainer
3ccce609f0 Add script for updating translations
The purpose of this script is to simplify the translation-related workflow for
both developers and translators. It runs the xgettext, msgmerge, msgfmt pipeline
(or only parts of it, depending on the arguments), either for all languages, or
for one specific one.

Developers can use the script with the `--no-mo` flag to update the PO files for
all languages after changes to the Rust/fish sources, to keep the translations
up to date. Ideally, this would run automatically for all changes, such that
translations are always up to date, but for now, it would already be an
improvement to run this script before releasing a new version of fish.

Translators can use the script in the same way as developers, to get up to date
PO files. To see their translations in action, the script can be called with
`--only-mo`, which takes the current version of the PO files and generates MO
files from them, which get placed in a location which fish (built with `cargo
build`) can detect.
Translators might also find it useful to specify the language they want to work
on as a non-option argument. This argument should be the path to the po file
they want to work on. Specifying non-existing files to work on a new language is
allowed, but the files must be in the po directory and follow the naming
convention.
2025-05-12 22:49:30 +02:00
Johannes Altmanninger
6fb22a4fd1 Fix regression causing crash indenting commandline with "$()"
Commit b00899179f (Don't indent multi-line quoted strings; do indent inside
(), 2024-04-28) changed how we compute indents for string tokens with command
substitutions:

	echo "begin
	not indented
	end $(
	begin
	    indented
	end)"(
	begin
	    indented
	end
	)

For the leading quoted part of the string, we compute indentation only for
the first character (the opening quote), see 4c43819d32 (Fix crash indenting
quoted suffix after command substitution, 2024-09-28).

The command substitutions, we do indent as usual.

To implement the above, we need to separate quoted from non-quoted
parts. This logic crashes when indent_string_part() is wrongly passed
is_double_quoted=true.

This is because, given the string "$()"$(), parse_util_locate_cmdsub calls
quote_end() at index 4 (the second quote). This is wrong because that function
should only be called at opening quotes; this is a closing quote. The opening
quote is virtual here. Hack around this.

Fixes #11444

(cherry picked from commit 48704dc612)
2025-05-12 21:41:10 +02:00
Johannes Altmanninger
35849c57dc Explicit type for "$()" hack in parse_util_locate_cmdsub
(cherry picked from commit 8abab0e2cc)
2025-05-12 21:41:10 +02:00
Johannes Altmanninger
27504658ce Remove code clone in parse_util_locate_cmdsub
(cherry picked from commit bd178c8ba8)
2025-05-12 21:41:10 +02:00
Johannes Altmanninger
db323348c7 Set transient command line in custom completions (Rust port regression)
Commit df3b0bd89f (Fix commandline state for custom completions with variable
overrides, 2022-01-26) made us push a transient command line for custom
completions based on a tautological null-pointer check ("var_assignments").

Commit 77aeb6a2a8 (Port execution, 2023-10-08) turned the null pointer into
a reference and replaced the check with "!ad.var_assignments.is_empty()".
This broke scenarios that relied on the transient commandline.  In particular
the attached test cases rely on the transient commandline implicitly placing
the cursor at the end, irrespective of the cursor in the actual commandline.

I'm not sure if there is an easy way to identify these scenarios.

Let's restore historical behavior by always pushing the transient command line.

Fixes #11423

(cherry picked from commit 97641c7bf6)
2025-05-12 21:39:42 +02:00
Johannes Altmanninger
edb1b5f333 Share alt-{b,f} with Vi mode, to work around Terminal.app/Ghostty more
Commit f4503af037 (Make alt-{b,f} move in directory history if commandline is
empty, 2025-01-06) had the intentional side effect of making alt-{left,right}
(move in directory history) work in Terminal.app and Ghostty without other,
less reliable workarounds.
That commit says "that [workaround] alone should not be the reason for
this change."; maybe this was wrong.

Extend the workaround to Vi mode.  The intention here is to provide
alt-{left,right} in Vi mode.  This also adds alt-{b,f} which is odd but
mostly harmless (?) because those don't do anything else in Vi mode.
It might be confusing when studying "bind" output but that one already has
almost 400 lines for Vi mode.

Closes #11479

(cherry picked from commit 3081d0157b)
2025-05-12 21:35:47 +02:00
Daniel Rainer
2d8d377ddc Make printf unicode-aware
Specifically, the width and precision format specifiers are interpreted as
referring to the width of the grapheme clusters rather than the byte count of
the string. Note that grapheme clusters can differ in width.

If a precision is specified for a string, meaning its "maximum number of
characters", we consider this to limit the width displayed.
If there is a grapheme cluster whose width is greater than 1,
it might not be possible to get precisely the desired width.
In such cases, this last grapheme cluster is excluded from the output.

Note that the definitions used here are not consistent with the `string length`
builtin at the moment, but this has already been the case.

(cherry picked from commit 09eae92888)
2025-05-12 21:33:40 +02:00
Alan Somers
bd26d4b61b Fix use of deprecated symbols in Nix 2025-05-12 13:28:56 -06:00
Alan Somers
7f4998ad9b Fix remote filesystem detection on FreeBSD
Need an extra include to get the definition of MNT_LOCAL

Fixes #11483
2025-05-12 13:18:21 -06:00
Daniel Rainer
122f39de66 Replace loop by pipeline
This simplifies the logic a bit and performs a better.

Performance improvements for extract_fish_script_messages (time in
microseconds):
- explicit regex: from 128241 to 83471 (speedup 1.5)
- implicit regex: from 682203 to 463635 (speedup 1.5)
2025-05-12 20:54:32 +02:00
Daniel Rainer
1df8fbff67 Replace long list by file
The replaces the `strs` list by a corresponding file, which eliminates the need
for looping over the list.

Use sed to transform strings into gettext po format entries.

Format the file with fish_indent and use more expressive variable name for the
file cargo expand writes to.

Performance improvements (in microseconds):
- sort+format rust strings: from 21750 to 11096 (speedup 2.0)
2025-05-12 20:35:41 +02:00
Daniel Rainer
ff5ff50183 Speed up constant string extraction
The fish builtin string functions are significantly slower than grep + sed.
The final replacement of \' to ' also does not make any sense here, because
single quotes appear unescaped in Rust strings.

Performance improvement: from 404880 to 44843 (speedup 9.0)

Profiling details (from separate runs):
Time (μs)   Sum (μs)  Command
       174     404880 > set -a strs (string match -rv 'BUILD_VERSION:|PACKAGE_NAME' <$tmpfile |
             string match -rg 'const [A-Z_]*: &str = "(.*)"' | string replace -a "\'" "'")
    404706     404706 -> string match -rv 'BUILD_VERSION:|PACKAGE_NAME' <$tmpfile |
             string match -rg 'const [A-Z_]*: &str = "(.*)"' | string replace -a "\'" "'"

       202      44843 > set -a strs (grep -Ev 'BUILD_VERSION:|PACKAGE_NAME' <$tmpfile |
             grep -E 'const [A-Z_]*: &str = "(.*)"' |
             sed -E -e 's/^.*const [A-Z_]*: &str = "(.*)".*$/\1/' -e "s_\\\'_'_g")
      4952      44641 -> grep -Ev 'BUILD_VERSION:|PACKAGE_NAME' <$tmpfile |
             grep -E 'const [A-Z_]*: &str = "(.*)"' |
             sed -E -e 's/^.*const [A-Z_]*: &str = "(.*)".*$/\1/' -e "s_\\\'_'_g"
     28716      28716 --> command grep --color=auto $argv
     10973      10973 --> command grep --color=auto $argv
2025-05-12 20:11:05 +02:00
Daniel Rainer
c0d93e4740 Do not use huge fish list
Using a file is significantly faster.

Profiling overview (times in microseconds):
- cargo expand: from 4959320 to 4503409 (speedup 1.1)
- gettext call pipeline: from 436996 to 13536 (speedup 32.3)
- static string pipeline: from 477429 to 404880 (speedup 1.18)
2025-05-12 18:12:37 +02:00
Lucas Melo
3cbb5e384b Shorten and format completions for protontricks, protontricks-launch 2025-05-12 08:36:07 -03:00
Lucas Melo
90b35335ee Add completions for protontricks 2025-05-12 08:24:26 -03:00
Daniel Rainer
55752729d6 Fix escaping in translation 2025-05-12 00:51:07 +02:00
Johannes Altmanninger
41dfb5147f Fix typo in set_color test 2025-05-11 22:55:48 +02:00
Johannes Altmanninger
156fa8081c Underline styles for double/dotted/dashed
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..
2025-05-11 22:18:06 +02:00
Johannes Altmanninger
3081d0157b Share alt-{b,f} with Vi mode, to work around Terminal.app/Ghostty more
Commit f4503af037 (Make alt-{b,f} move in directory history if commandline is
empty, 2025-01-06) had the intentional side effect of making alt-{left,right}
(move in directory history) work in Terminal.app and Ghostty without other,
less reliable workarounds.
That commit says "that [workaround] alone should not be the reason for
this change."; maybe this was wrong.

Extend the workaround to Vi mode.  The intention here is to provide
alt-{left,right} in Vi mode.  This also adds alt-{b,f} which is odd but
mostly harmless (?) because those don't do anything else in Vi mode.
It might be confusing when studying "bind" output but that one already has
almost 400 lines for Vi mode.

Closes #11479
2025-05-11 22:05:00 +02:00
Johannes Altmanninger
13e4736113 completions/commandline: don't offer deprecated option 2025-05-11 22:00:43 +02:00
Johannes Altmanninger
80e30ac756 Always treat brace at command start as compound statement
For backwards compatibility, fish does not treat "{echo,hello}" as a compound
statement but as brace expansion (effectively "echo hello").  We interpret
"{X...}" as compound statement only if X is whitespace or ';' (which is an
interesting solution).

A brace expansion at the very start of a command 
is usually pointless (space separation is shorter).
The exception are cases where the command name and the first few arguments
share a suffix.

	$ {,1,2,3,4}echo
	1echo 2echo 3echo 4echo

Not sure if anyone uses anything like that.  Perhaps we want to trade
compatibility for simplicity. I don't have a strong opinion on this.

Always parse the opening brace as first character of a command token as
compound statement.
Brace expansion can still be used with a trick like: «''{echo,foo}»

Closes #11477
2025-05-11 22:00:43 +02:00
Daniel Rainer
a86a4dfabf Remove source locations from translations
Source locations (file name and line number) where a string originates is not
required by gettext tooling. It can help translators to identify context,
but the value of this is reduced by our lack of context support, meaning that
all occurrences of a string will receive the same translation.
Translators can use `rg` or similar tools to find the source locations.
For further details see this thread:
https://github.com/fish-shell/fish-shell/pull/11463#discussion_r2079378627

The main advantage is that updates to the PO files are now only necessary when
the source strings change, which greatly reduces the diff noise.

A secondary benefit is that the string extraction logic is simplified.
We can now directly extract the strings from fish scripts,
and several issues are fixed alongside, mostly related to quoting.
The regex for extracting implicit messages from fish scripts has been tweaked to
ignore commented-out lines, and properly support lines starting with `and`/`or`.
2025-05-11 21:10:03 +02:00
Daniel Rainer
22bc8e12c9 Fix xgettext implicit regex
The old regex has the problem that it does not handle lines containing any
non-space characters in front of ` complete` (or ` function`), which results in
`string replace` leaving this part in the resulting string.
For example,
`and complete -d "foo"`
would turn into
`andN_ foo`
if passed to
`string replace --regex $regex 'N_ $1'` (where `$regex` is the `$implicit_regex`) variable.
Another issue are commented-out lines.
2025-05-11 21:10:03 +02:00
Peter Ammon
6c23c6f29b Add myself as SECURITY contact and reformat 2025-05-11 11:48:03 -07:00
Josef Andersson
39fd959eea Add initial security policy
Signed-off-by: Josef Andersson <janderssonse@proton.me>
2025-05-11 11:45:15 -07:00
Johannes Altmanninger
cc2ca60baa commandline.rst: deprecate --tokens-raw option
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".
2025-05-11 12:46:08 +02:00
Johannes Altmanninger
83f74f9332 builtin commandline: fix "-x" spuriously including redirection targets
completions frequently use

	argparse ... -- (commandline -xpc)

The "commandline -xpc" output
contains only string tokens.

A syntactically-valid process ("-p") consistes of only string tokens
and redirection tokens.  We skip all non-string tokens, but we do include
redirection targets, which are always strings.  This is weird, and confuses
completion scripts such as the one above.  Leave out redirection targets too.

Part of #11084
2025-05-11 12:46:08 +02:00
Johannes Altmanninger
58af4fa34c builtin commandline: rename tokenization mode 2025-05-11 12:46:08 +02:00
Daniel Rainer
f23501dbdc Add locale directory to config log 2025-05-11 09:27:35 +02:00
DaiLu Cao
035cd369c2 Supplement Chinese translation
Squashed commit of the following:

commit 23163d40bed2d97c72050990cf15db3944ce2ff0
Author: DaiLu Cao <caodailu@foxmail.com>
Date:   Thu Apr 24 10:11:04 2025 +0800

    Manually review up to line 1055 and modify all Chinese colons ':' to English ':' to prevent potential unknown errors.

commit dca5fb8182b94bffab5034dc5626b2b98d026b6f
Author: DaiLu Cao <caodailu@foxmail.com>
Date:   Thu Apr 17 10:50:13 2025 +0800

    Manually proofread up to 340 lines

commit 4b2d91c1138f3c8dec15b68aeb0510f02e15a776
Author: DaiLu Cao <caodailu@foxmail.com>
Date:   Thu Apr 17 09:50:21 2025 +0800

    use msgfmt check and fix all error

commit e2470d81c01ab7bf46d3d6ffd0291a05d4b38e13
Author: DaiLu Cao <caodailu@foxmail.com>
Date:   Wed Apr 16 11:10:54 2025 +0800

    Fix translation error converting '\\n' to '\\ n' error

commit 7ff970d06ce950aee35e1fb0ec70338f7bd42c1d
Author: DaiLu Cao <caodailu@foxmail.com>
Date:   Wed Apr 16 10:53:38 2025 +0800

    Fix make error, local cargo test completed

commit 018dfa225530a85486903ef58d47f4c358956b0b
Author: DaiLu Cao <caodailu@foxmail.com>
Date:   Fri Apr 11 16:46:36 2025 +0800

    modification of make errors

commit cbebd506a500aecc0669dce7f08422fcfed5615f
Author: DaiLu Cao <caodailu@foxmail.com>
Date:   Fri Apr 11 15:45:01 2025 +0800

    The second modification of make errors are all symbol problems

commit f75c3f7a2a84ffaea4eb642532b5a24da1c9154f
Author: DaiLu Cao <caodailu@foxmail.com>
Date:   Fri Apr 11 15:27:01 2025 +0800

    Re-add Chinese translation, try to solve the problem of make failing

commit 58551be20d261e3466a9e4ede290675f633e94a3
Author: DaiLu Cao <caodailu@foxmail.com>
Date:   Fri Apr 11 15:06:01 2025 +0800

    Supplement Chinese translation
2025-05-08 19:17:46 -07:00
Peter Ammon
057dd930b4 Changelog fix for #11354 2025-05-08 18:42:57 -07:00
Cuichen Li
25b944e3e6 Revert "Work around $PATH issues under WSL (#10506)"
This reverts commit 3374692b91.
2025-05-08 18:41:02 -07:00
Cuichen Li
3bef4863cf Revert "Work around $PATH issues under WSL (#10506)"
This reverts commit 3374692b91.
2025-05-08 18:35:56 -07:00
Daniel Rainer
2d58cfe4cb Remove line numbers from translation strings
This greatly reduces the number of changes necessary to the PO files when the
Rust/fish source files are updated. (Changes to the line number can be applied
automatically, but this adds a lot of noise to the git history.)

Due to the way we have been extracting Rust strings, differentiation between
the same source string in different contexts has not been possible regardless
of the change.

It seems that duplicate msgid entries are not permitted in PO files, so since we
do not use context to distinguish the strings we extract, there is no way to
have context-/location-dependent translations, so we might as well reduce the
git noise by eliminating line numbers.

Including source locations helps translators with understanding context.
Because we do not distinguish between contexts for a given source string,
this is of limited utility, but keeping file names at least allows to open the
relevant files and search them for the string. This might also be helpful to
identify translations which do not make sense in all context in which they are
used. (Although without adding context support, the only remedy would be to
remove the translation altogether, as far as I can tell.)

For extraction from Rust, additional issues are fixed:
- File name extraction from the grep results now works properly. Previously,
  lines not starting with whitespace resulted in missing or corrupted matches.
  (missing if the source line contains no colon followed by a whitespace,
  corrupted if it does, then the match included the part of the line in front of
  the colon, instead of just the location)
- Only a single source location per string was supported (`head -n1`). The new
  approach using sed does not have this limitation.
2025-05-08 18:15:56 +02:00
David Adam
df591a2e0f fish.spec/Debian packaging: drop man dependency in favour of groff 2025-05-08 22:16:33 +08:00
Johannes Altmanninger
ecefce2ea8 Fix "help printf" on --features=embed-data builds 2025-05-08 11:11:15 +02:00
Peter Ammon
786239d280 Changelog fix for #11465 2025-05-07 18:28:25 -07:00
Carl Andersson
7a668fb17e Unset SYSTEMD_COLORS for systemd completion
Fixes an issue where systemctl and other systemd commands completions are prefixed by ANSI color escape codes
2025-05-07 18:23:51 -07:00
Johannes Altmanninger
bf2f7ee6c0 Respect feature flags in fish_key_reader, fix display of "?" key
Commit daa692a20b (Remove unnecessary escaping for # and ~ inside key name
tokens, 2025-04-01) stopped escaping ? in fish_key_reader output.  This is
generally correct but not if the "qmark-noglob" feature flag is turned off.
Add that back, to be safe.

While at it, pass an environment variable more explicitly in a test.
2025-05-07 17:19:51 +02:00
Johannes Altmanninger
2f762e2da1 completions/cargo: re-use __fish_cargo
Technically this is in the autogenerated part, but I'm not sure how I can
re-generate it with today's cargo.
2025-05-07 17:17:09 +02:00
Benjamin VERGNAUD
11d8b83838 completions/cargo: enforce color off
Signed-off-by: Benjamin VERGNAUD <ben@bvergnaud.fr>
2025-05-06 15:39:39 +02:00
Yuyi Wang
c2eaef7273 Update nix to 0.30.1 (#11458)
After nix updated to 0.30, all functions related to file descriptor accepts impl AsFd, e.g., BorrowedFd. This PR is a minimal update. It tries to use impl AsFd as long as possible, but uses BorrowedFd in some places. Yes it introduces unsafe, but doesn't introduce new unsafe code.
2025-05-06 10:52:54 +02:00
Yuyi Wang
2f278f4bfa Update errno to 0.3.11 2025-05-06 10:44:18 +08:00
Ethan Fredsti
1e61e6492d fixed typo mentioned in issue #11454
I found the same typo mentioned in issue #11454 in this file and proposed the suggested change.
2025-05-04 19:52:06 -07:00
Peter Ammon
c993fd022c Rework fish AST implementation
This merges a large set of changes to the fish AST, with the intention of
making the code simpler.

There's no expected user-visible changes here, except for some minor
changes in the output of `fish_indent --dump-parse-tree`.

Ast parsing is about 50% faster measured via
`cargo +nightly bench  --features=benchmark bench_ast_construction`
and also uses less memory due to some size optimization.

The biggest change is removing the `Type` notion from `Node`. Previously
each Node had an integer type identified with it, like Type::Argument. This
was a relic from C++: types were natural in C++ and we could use LLVM-style
RTTI to identify Nodes, leveraging the fact that C++ has inheritance and so
Type could be at the same location in each Node.

This proved quite awkward in Rust which does not have inheritance. So
instead we switch to a new notion, Kind:

    pub enum Kind<'a> {
        Redirection(&'a Redirection),
        Token(&'a dyn Token),
        Keyword(&'a dyn Keyword),
        VariableAssignment(&'a VariableAssignment),
                ...

and a `&dyn Node` can now return its Kind. Basically leveraging Rust's enum
types.

Interesting lesson about the optimal way to construct ASTs in both
languages.
2025-05-04 19:45:36 -07:00
Peter Ammon
fe10f65587 ast: Box redirections in ArgumentOrRedirection
Redirections are bigger and less common.

Reduces ast size of __fish_complete_gpg.fish by ~28 KB.
2025-05-04 19:38:08 -07:00
Peter Ammon
b98c5ee897 ast: remove NodeSubTraits
This can be implemented directly in Node.
2025-05-04 19:37:25 -07:00
Peter Ammon
9ccff5ad5d ast: Clean up implement_acceptor_for_branch macro
We no longer need the field types to be passed to the macro.
2025-05-04 18:59:13 -07:00
Peter Ammon
55f70cbb6d ast: Clean up more macros
Factor some logic out of macros into a trait, to reduce the macro
complexity.
2025-05-04 18:59:13 -07:00
Peter Ammon
b7005e8378 ast: clean up NodeVisitorMut
This eliminates a bunch of the different functions from NodeVisitorMut.

It also removes the runtime polymorphism - now it's a generic instead of
using &dyn. The reason is that there's only one implementation of
NodeVisitorMut so there's no size savings from polymorphism.
2025-05-04 18:59:13 -07:00
Peter Ammon
1f79d48a48 ast: further macro cleanup 2025-05-04 18:59:13 -07:00
Peter Ammon
e9036774cb ast: simplify visitor_accept_field macro
This is a relic from when we used to support visiting in reverse order; we can
simplify this.
2025-05-04 18:59:13 -07:00
Peter Ammon
2cd185a4f1 ast: Eliminate ConcreteNode trait
Fold this into Node
2025-05-04 18:59:13 -07:00
Peter Ammon
bb92d82c3b ast: remove types 2025-05-04 18:59:13 -07:00
Peter Ammon
f9ba834788 ast: further migration from type to kind 2025-05-04 18:59:13 -07:00
Peter Ammon
d23b8af60d ast: More migration from type to kind 2025-05-04 18:59:13 -07:00
Peter Ammon
82eacb6d50 ast: Switch from type to kind in is_same_node 2025-05-04 18:59:13 -07:00
Peter Ammon
c62b09d5d1 ast: Switch from some types to kinds
Preparing to remove types entirely
2025-05-04 18:59:13 -07:00
Peter Ammon
ccfe949514 ast: make Ast generic
We can parse two different things via Ast:

1. A regular job list
2. A freestanding argument list, as used in `complete --arguments ...`

This second case is specific to one use.

Prior to this commit, we parsed the Ast and then "forgot" what we parsed,
storing a &dyn Node. Then we had to cast it to the right type, and assert,
and etc.

Make Ast generic over the Node type it parsed, and default the Node type to
JobList. This simplifies call sites.
2025-05-04 18:59:13 -07:00
Peter Ammon
ccc75d08f3 ast: remove all of the as_foo functions from Node
Kind has subsumed these.
2025-05-04 18:59:05 -07:00
Peter Ammon
dfac66082a ast: adopt Kind in yet more places 2025-05-04 18:59:05 -07:00
Peter Ammon
9ae01ae00d ast: adopt Kind in more places 2025-05-04 18:59:05 -07:00
Peter Ammon
51784b090d ast: adopt Kind in parse_util_detect_errors_in_ast 2025-05-04 18:59:05 -07:00
Peter Ammon
8115982485 ast: adopt Kind in highlighting 2025-05-04 18:59:05 -07:00
Peter Ammon
d88a656e9e ast: further adoption of Kind 2025-05-04 18:59:05 -07:00
Peter Ammon
d6ee4ec698 ast: Clean up BlockStatementHeader
Make this a real Node.
2025-05-04 18:59:05 -07:00
Peter Ammon
dbae271fe7 ast: remove StatementVariant
Statement is the new StatementVariant.
2025-05-04 18:59:05 -07:00
Peter Ammon
a4ec30f298 ast: Remove StatementVariant::None
We can do without this.
2025-05-04 18:59:05 -07:00
Peter Ammon
ee9cf33689 ast: Remove Node::category
This is now unused.
2025-05-04 18:59:05 -07:00
Peter Ammon
11b6bf31c0 ast: Minor cleanup of source ranges 2025-05-04 18:59:05 -07:00
Peter Ammon
4f0e11383e ast: Remove as_mut_foo() functions
Kinds have replaced these.
2025-05-04 18:59:05 -07:00
Peter Ammon
bf78309f79 ast: adopt Kinds in more places 2025-05-04 18:59:05 -07:00
Peter Ammon
01bd854f25 ast: introduce Kind and cast
This begins the process of replacing the underlying Node "type" notion with
Kind. A Kind is an Enum of all of the possible node types, except with
Token and Keyword collapsed into one.

The idea is, rather than this:

    if node.type() == Type::Argument {
	    let arg = node.as_argument().unwrap();
		...
	}

we can instead do this:

    if let Kind::Argument(arg) = node.kind() {
	    // we already have arg
	}

There is also a cast() function:

    let arg: Option<Argument> = node.cast()

which may be convenient in some places.

The big thing we lose is the ability to talk about a Node's type without
actually having a Node. But this turns out to not be an issue in practice.

Future commits will begin adopting Kind.
2025-05-04 18:59:05 -07:00
Peter Ammon
0348389195 ast: Remove as_mut_leaf
This was unused.
2025-05-04 18:28:25 -07:00
Peter Ammon
e05ecd6c7d ast: clean up lists
Make working with lists more natural
2025-05-04 18:28:25 -07:00
Peter Ammon
325232bec1 ast: remove the ability to traverse in reverse
Prior to this commit, each Node in the ast could accept a visitor and visit
children either in order or in reverse order. This reverse feature added a lot
of complexity and the only client is Traversal.

Switch Traversal to reverse the nodes itself and remove the reverse bool
elsewhere, leading to some code simplifications.
2025-05-04 17:09:00 -07:00
Peter Ammon
b78d168050 ast: eliminate ArgumentOrRedirectionVariant
Just use ArgumentOrRedirection directly. Continued simplification.
2025-05-04 17:09:00 -07:00
Peter Ammon
31edcf029b ast: factor out as_node
Shrink another macro.
2025-05-04 17:09:00 -07:00
Peter Ammon
27dc4b3c8a ast: Blanket implementation of NodeMut
Continue to shrink the implement_node! macro.

No functional changes expected.
2025-05-04 17:09:00 -07:00
Peter Ammon
77a4f38a13 ast: derive Category from Type
In the fish AST, each node falls into one of three "categories":

    1. A branch: contains child nodes
    2. A leaf: no child nodes, contains a source range
    3. A list: a sequence of child nodes and nothing more

Prior to this commit the category was explicit in the code for each Node type;
make it instead derived from the node's type. This continues to shrink our
macros.

No functional change expected.
2025-05-04 17:09:00 -07:00
Peter Ammon
e9d396615b ast: push try_source_range into default Node implementation
Minor refactoring, reducing macro size.
2025-05-04 17:09:00 -07:00
Peter Ammon
79ec558d08 ast: remove Default implementation
This doesn't make much conceptual sense, and isn't required.

Do some other miscellaneous cleanup.
2025-05-04 17:09:00 -07:00
Peter Ammon
719a5d2909 ast: remove stale parent pointer comment
It no longer applies.
2025-05-04 17:08:59 -07:00
Peter Ammon
93962c82df ast: store &dyn Node and not &dyn NodeMut
Minor simplifications.
2025-05-04 17:08:59 -07:00
Johannes Altmanninger
111922b60f Fix export test on macOS GHA runner
This system sets something like
$MANPATH: originally inherited as |/Applications/Xcode_15.4.app/...|
2025-05-04 18:19:42 +02:00
Johannes Altmanninger
cb92a5530f functions/export: fix for path variables
Commit f38646593c (Allow `export` to set colon-separated `PATH`, `CDPATH`
and `MANPATH`., 2017-02-10)
did something very weird for «export PATH=foo».
It essentially does

	set -gx PATH (string replace -- "$PATH" (string join ":" -- $PATH) foo)

which makes no sense.  It should set PATH to "foo", no need to involve the
existing value of $PATH.

Additionally, the string split / string join dance is unnecessary.  Nowadays,
builtin set already handles path variables as is needed here, so get rid of
this special case.

Fixes #11434
2025-05-04 18:06:18 +02:00
Johannes Altmanninger
dd4c04e2ff Fix empty soft-wrapped line not being removed before execution
Commit 7acc2b7 added an empty line to our screen representation if we are
wrapped. This regressed the fix for #6826.  In the attached test case, there is
a spurious empty line after the first one.  Adjust the fix to remove it again.

Patch-by: kerty <g.kabakov@inbox.ru>
https://github.com/fish-shell/fish-shell/pull/11153#issuecomment-2800087389
2025-05-04 12:50:12 +02:00
Johannes Altmanninger
6fec5ab320 completions/wpctl: fix when "settings" subcommand is not available
The error is printed to stdout, see
https://github.com/fish-shell/fish-shell/pull/11438#discussion_r2072455009
2025-05-04 12:06:01 +02:00
Johannes Altmanninger
ada9aff63e Merge pull request #11453 2025-05-04 12:01:06 +02:00
Johannes Altmanninger
1d63c1f188 Merge pull request #11399 2025-05-04 11:58:05 +02:00
Johannes Altmanninger
a12298152f Merge pull request #11448 2025-05-04 11:57:18 +02:00
Bergbok
83b10c3919 Rephrase set_color tutorial docs
Closes #11446
2025-05-04 11:56:14 +02:00
Johannes Altmanninger
4a3fc5211f Document workaround for making tab focus search field
Closes #11450
Closes #11449
2025-05-04 11:56:14 +02:00
239
9f80e1f225 completions/keybase: update to 6.4.0
Closes #11428
2025-05-04 11:56:14 +02:00
fabiojb
9a8d578142 completion(winetricks): redirect winetricks list-all sderr to /dev/null 2025-05-03 18:25:17 -03:00
Daniel Rainer
09eae92888 Make printf unicode-aware
Specifically, the width and precision format specifiers are interpreted as
referring to the width of the grapheme clusters rather than the byte count of
the string. Note that grapheme clusters can differ in width.

If a precision is specified for a string, meaning its "maximum number of
characters", we consider this to limit the width displayed.
If there is a grapheme cluster whose width is greater than 1,
it might not be possible to get precisely the desired width.
In such cases, this last grapheme cluster is excluded from the output.

Note that the definitions used here are not consistent with the `string length`
builtin at the moment, but this has already been the case.
2025-05-03 22:53:27 +02:00
Daniel Rainer
af6c3eb69f Ensure that strings do not get wrapped in po files 2025-05-03 16:07:20 +02:00
Daniel Rainer
dd5864ce13 Add quotes around gettext string
This should prevent occurrences of the search string from being found in other
locations (e.g. in a comment).

The whole approach of string extraction from Rust sources is sketchy,
but this at least prevents producing garbage when the content of a string
appears somewhere else unquoted.
2025-05-03 16:07:20 +02:00
Daniel Rainer
d31dc9ffd8 Fix fish script translation file generation
The previous version generates files which do not preserve the line number from
the original fish script file, resulting in translation not working.

The new approach is quite ugly, and might have some issues,
but at least it seems to work in some cases.
2025-05-03 16:07:03 +02:00
Daniel Rainer
d5e80d43d9 Extract function for gettext extraction
Extracting explicit and implicit messages works essentially the same way, which
is also reflected in the code being identical, except for the regex.

Extract the duplicated code into a function.
2025-05-03 16:03:03 +02:00
Johannes Altmanninger
0d59e89374 completions/wpctl: silence stderr
In case the command is missing, I guess
See https://github.com/fish-shell/fish-shell/pull/11438
2025-05-03 14:15:33 +02:00
Johannes Altmanninger
8b1f72c54b completions/tmutil: namespace 2025-05-03 14:15:33 +02:00
Johannes Altmanninger
54a5ade57d Merge pull request #11394 2025-05-03 14:15:33 +02:00
Johannes Altmanninger
7c25d6a1ba Merge pull request #11443 2025-05-03 14:15:33 +02:00
Johannes Altmanninger
a5a5dc46e4 Merge pull request #11438 2025-05-03 14:15:33 +02:00
Johannes Altmanninger
1687b3fe7a Merge pull request #11377 2025-05-03 14:15:33 +02:00
Johannes Altmanninger
f3ddf793a3 Merge pull request #11381 2025-05-03 14:15:33 +02:00
Johannes Altmanninger
647ae7da8c Merge pull request #11411 2025-05-03 14:15:33 +02:00
Johannes Altmanninger
0950cd1598 Merge pull request #11422 2025-05-03 14:15:33 +02:00
Johannes Altmanninger
a1b1bff97b Merge pull request #11441 2025-05-03 14:15:33 +02:00
Johannes Altmanninger
a95be351fb Merge pull request #11447 2025-05-03 14:15:33 +02:00
Axlefublr
91b9bbf651 fix single backticks 2025-05-03 19:26:07 +08:00
Johannes Altmanninger
c14e8c1939 Fix assertion error in set_color
This doesn't hold for e.g. TERM=linux-m fish -c 'set_color red'
2025-05-03 12:56:45 +02:00
Daniel Rainer
7e4c3b9fa7 Use workspace config in packages
- Apply lint config to entire workspace

- Inherit workspace config for fish-printf

- Allow stdlib printing in fish-printf tests

The current problem which is addressed by this is that warnings about C-String
literals are generated by clippy for code in fish-printf. These literals are not
available with the current MSRV 1.70, but previously the MSRV setting was not
inherited by fish-printf, causing the warning to appear.
2025-05-02 22:31:39 +02:00
Fabian Boehm
8048e38ea4 docs: Actually document commandline --input
This is a useful option and has been a thing for years.
2025-05-02 20:55:36 +02:00
Fabian Boehm
8a5a547d88 builtins/commandline: Correct error message 2025-05-02 20:54:29 +02:00
Johannes Altmanninger
48704dc612 Fix regression causing crash indenting commandline with "$()"
Commit b00899179f (Don't indent multi-line quoted strings; do indent inside
(), 2024-04-28) changed how we compute indents for string tokens with command
substitutions:

	echo "begin
	not indented
	end $(
	begin
	    indented
	end)"(
	begin
	    indented
	end
	)

For the leading quoted part of the string, we compute indentation only for
the first character (the opening quote), see 4c43819d32 (Fix crash indenting
quoted suffix after command substitution, 2024-09-28).

The command substitutions, we do indent as usual.

To implement the above, we need to separate quoted from non-quoted
parts. This logic crashes when indent_string_part() is wrongly passed
is_double_quoted=true.

This is because, given the string "$()"$(), parse_util_locate_cmdsub calls
quote_end() at index 4 (the second quote). This is wrong because that function
should only be called at opening quotes; this is a closing quote. The opening
quote is virtual here. Hack around this.

Fixes #11444
2025-05-02 08:31:15 +02:00
Johannes Altmanninger
8abab0e2cc Explicit type for "$()" hack in parse_util_locate_cmdsub 2025-05-02 08:31:15 +02:00
Johannes Altmanninger
bd178c8ba8 Remove code clone in parse_util_locate_cmdsub 2025-05-02 08:31:15 +02:00
Johannes Altmanninger
cb719cd418 Remove dead code
Introduced in 149594f974 (Initial revision, 2005-09-20).
2025-05-02 08:31:15 +02:00
Johannes Altmanninger
1ff8f983c4 Remove obsolete Vi mode delete key workaround
As reported in
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$n20_uqiMqatEQcPG79Ca0c2_YvHBHTr-yCVXTEuze_Y

commit f5fac096c0 (Don't move cursor in delete-char, 2017-04-19) fixed the
behavior of Vi mode keys "delete" and "x" when the cursor is at the end of
the buffer, and commit d51f669647 (Vi mode: avoid placing cursor beyond
last character, 2024-02-14) generalized this fix.

This means that the delete-specific fix is no longer necessary. Remove it.

Note that if the cursor is at end of a line but not the last line, the
behavior of "delete" in Vi mode is still wrong.  It should stay on the line.
2025-05-02 06:05:31 +02:00
Johannes Altmanninger
e3517f69b3 Simplify check for bare builtin invocation 2025-05-02 06:05:31 +02:00
Fabian Boehm
f7bde1354d Only count it as a naked invocation at the end of the "file"
This is a weird confusion between the "end" and "terminate" token
types.

"end" is the end of the "line" - a newline or ";".

"terminate" is the end of the "file" - like pressing newline
interactively or having the file end.

So this would count things like `if` and `switch` as a "help"
invocation even if followed by a newline, e.g.

```fish
if; echo foo
```

and

```fish
switch
case foo
```

The result of that was that a naked "if" in a script file isn't an
error, but doesn't start a block either, so if you complete the block
it would count the "end" as superfluous, which sends you on a bit of a
hunt to figure out where the block start is missing.
2025-05-01 14:57:30 +02:00
Axlefublr
1d69226c58 preciser wording for builtin crossmode alt+p binding 2025-05-01 13:58:18 +08:00
Daniel Rainer
d5e71bc46e Fix diff_profiles.fish
This script was broken by the changes to profiling output in
9d904e1113.

The new version works with both the old and new profiling output, even when
mixed. The script output has been adjusted to match the new profiling style
better.

This also adds basic error handling for situations where the script is invoked
incorrectly and makes the file executable.
2025-04-30 19:41:45 +02:00
fabiojb
0d5ab2514c wpctl: add description for settings command options 2025-04-30 11:18:12 -03:00
David Adam
bf0a30b9a8 CHANGELOG: work on 4.1 2025-04-30 14:15:58 +08:00
fabiojb
b54042e512 wpctl: add completion for settings option 2025-04-29 17:11:01 -03:00
Johannes Altmanninger
f79e5d5820 Remove a special case parsing the fish_color_normal fallback
The first two attempts skip over empty variables and the last one doesn't.
This is fine but since we need the default case anyway, might as well reuse
it here too.  (An empty color variable is treated the same way a missing
color variable is.)
2025-04-29 13:59:27 +02:00
Johannes Altmanninger
54e80e65a8 Be more careful to only pass actual keys to self-insert
I don't have a runnable test case but this does seem to have bitrotted.
Originally, we only cared about keys and the EOF and check-exit events.
Returning one of the other new events here seems totally wrong.

Try to fix this, and move the logic closer to where it's needed, so we no
longer need to update its name and we're less likely to forget to update it,
and it cannot.
2025-04-29 13:51:18 +02:00
Johannes Altmanninger
1122bba3c1 Fix typo in docs 2025-04-29 13:51:18 +02:00
Johannes Altmanninger
094e8b29c2 Cleanup some import statements 2025-04-29 13:51:18 +02:00
Johannes Altmanninger
decec955d2 Fix DCS parser spuriously stopping at escape byte
DCS commands stop at ST ("\e\\"). Make sure we don't stop at just "\e". I
don't know of any command that will actually include the escape byte in its
payload but better safe than sorry.
2025-04-29 13:51:18 +02:00
Johannes Altmanninger
4a5e8a8f48 Handle boolean capabilities in XTGETTCAP response parser 2025-04-29 13:51:18 +02:00
Johannes Altmanninger
f8699d2b7e Move mouse click handling from input decoding to the input queue consumer
The input queue doesn't want to be blocked, so let's decide later what to
do with a mouse click.  This fixes the potential problem where a mouse click
is ignored if it is received while we're waiting for the terminal to repond
to a query.
2025-04-29 13:51:18 +02:00
Johannes Altmanninger
168c1a50a4 Don't route query responses until we pop them from the input queue
This makes more sense, see also the next commit.
2025-04-29 13:51:18 +02:00
Johannes Altmanninger
7e393f47e4 Prevent code execution from focus events while blocked on query response
While we are waiting for a query response from the terminal, we defer any
input processing until we receive our query response
 Then that response is promoted to the front of the input queue, and
remaining inputs are processed in order.

We accidentally process focus events, which may run arbitrary code.  We can't
do this; it breaks a lot of invariants (for example the it can invalidate
the cursor positions for CursorPositionQuery, or it can cause fish to exit
before fully consumeing a query response).

Make sure we only process known-safe events.  We definitely need to process
CheckExit (in case we received SIGHUP). I guess we should also process Eof,
in case the terminal is buggy.
2025-04-29 13:51:18 +02:00
Johannes Altmanninger
5897d13333 Dedicated input event type for query responses
These code paths have a tiny bit of logic in common, share that.

Maybe this should be nested in ImplicitEvent, and maybe Eof and CheckExit
shouldn't be..
2025-04-29 13:51:18 +02:00
Johannes Altmanninger
d18cb6ce27 Use OnceCell for terminal query state initialization
This object is initialized once just before we start reading from the terminal.
Once seems to be the appropriate type for this.  This gets rid of an awkward
enum variant.
2025-04-29 13:51:18 +02:00
Johannes Altmanninger
9b44a59b80 Rename terminal-query-state data structure
While at it, extract a function for initialization.  This looks pretty ugly
but it will get better with the next commit.
2025-04-29 13:51:18 +02:00
Johannes Altmanninger
788eddd0e8 Make terminal query data state a RefCell instead of mutex
We never need to access this from other threads, so a Mutex is overkill.
Leave behind stale variable names like "wait_guard" to be cleaned up by the
next commit.

Since TestInputEventQueuer is used concurrently in tests,
give it its own private object, to avoid borrowing conflicts.

Same for fish_key_reader; this fixes the issue that fish_key_reader potentially
reads keyboard input before a query is finished.
2025-04-29 13:50:15 +02:00
Johannes Altmanninger
e7c9f6d47e Move terminal query state data structure into the parser
Whenever config.fish runs (interactive) builtin read, we push and pop a
top-level, before the main shell's reader.

The terminal state outlives all readers, so its scope should reflect that
to avoid redundant initialization. Move it into the parser.

This is also used by a following commit that wants to access the query state
from a builtin. This should work even if no reader is active.

Note that Mutex doesn't really make sense here - the next commit will fix that.
2025-04-29 13:31:13 +02:00
Johannes Altmanninger
bb1e3f3aba Share InputEventQueuer::is_blocked implementation 2025-04-29 13:31:13 +02:00
Johannes Altmanninger
e490ba6fdf Remove stale lint suppression 2025-04-29 13:31:13 +02:00
Johannes Altmanninger
84c48c3f97 themes: sort
Keep fish_color_normal first since it seems to be the only one that's
special enough?
2025-04-29 13:31:13 +02:00
Johannes Altmanninger
fd0f942fd0 builtin set_color: reuse outputter
The differences between color variables and set_color implementation have
gotten somewhat small so make them explicit by getting rid of this code clone.

Outputter::set_text_face() has clever caching logic that is not always needed
by builtin set_color -- in fact, it even needs to explicitly disable the
cache for foreground and background colros -- but this might still be worth it.
2025-04-29 13:31:13 +02:00
Johannes Altmanninger
c8f2471357 Stop --background=somecolor from implicitly setting the bold modifier
As reported in https://github.com/fish-shell/fish-shell/issues/11325, we have logic that
implicitly activates bold mode.

Even worse: the test case from https://github.com/fish-shell/fish-shell/issues/11426 shows that
we're not even consistent about that.

To reproduce, use

    set -g fish_pager_color_background --background=fff
    set -g fish_pager_color_prefix --underline --bold 000
    set -g fish_pager_color_completion
    set -g fish_pager_color_description
    complete : -s a -l all -d asdf

and type ": -" <TAB>

The second prefix is underlined but not bold,
because the implicit bold mode has a subtle bug.

Now if we were to fix this, using

    diff --git a/src/terminal.rs b/src/terminal.rs
    index b86a7d85fe..7791d34936 100644
    --- a/src/terminal.rs
    +++ b/src/terminal.rs
    @@ -589,7 +589,7 @@
             // Lastly, we set bold, underline, italics, dim, and reverse modes correctly.
             if style.is_bold()
                 && !self.last.style.is_bold()
    -            && !bg_set
    +            && !(bg_set && !last_bg_set)
                 && self.write_command(EnterBoldMode)
             {
                 self.last.style.bold = true;

that would make the description bold as well, which would probably cause chaos.
Either way, it seems wrong to expand this hack.

Let's remove it.

For better or worse, we can't safely update the default theme yet on
an existing user's machine, because we have set universal variables.
This means that fish_color_search_match and fish_pager_color_progress on
existing installations are no longer bold. That's probably acceptable.
The former was hard to read for the longest time, until 9af6a64fd2 (Fix
bad contrast in search match highlighting, 2024-04-15). The progress info
is probably not a big deal.

Attentive users may run "fish_config theme choose 'fish default'". Perhaps
we should tell them on upgrade?

Closes #11325
2025-04-29 13:31:13 +02:00
Johannes Altmanninger
742016f455 __fish_config_interactive: reuse default theme
(As suggested in 84e7fbd466 (Make default .theme file consistent with uvars,
2022-02-03))

Historical behavior in default fish is that

1. fish_color_keyword and fish_color_option are unset, meaning they
   default to their fallbacks, fish_color_command and fish_color_param.
2. colors not mentioned in the default them, such as
   fish_pager_color_secondary_background, are unset

"fish_config theme save fish\ default"
- sets group 1 to a non-empty value (deactivating the fallbacks)
- sets group 2 to an empty value (which has no function change except it
  changes completions for builtin set)

Both are probably fine. I guess the historical behavior is a bit nicer.
But the new behavior is simpler. We can definitely optimize it later,
for example by never redundantly setting universal color variables to an
empty value.
2025-04-29 13:31:13 +02:00
Johannes Altmanninger
e71cace5f1 Remove unused fish_color_match
I'm not sure if keeping this helps anything? We can always add it back,
along with an announcement for third-party theme authors.
2025-04-29 13:31:13 +02:00
Johannes Altmanninger
50b93dd5c0 themes: update fish_color_search_match to be consistent with new default
The foreground component of fish_color_search_match was first used in commit
9af6a64fd2 (Fix bad contrast in search match highlighting, 2024-04-15)
which also changed it from bryellow to white.  Unfortunately it forgot to
update the themes. Probably all of them want to the default, so let's do that.
2025-04-29 13:31:13 +02:00
Johannes Altmanninger
364d84e620 Remove unused query for cursor position reporting
We only query for the cursor position if either
1. if the terminal sends an XTGETTCAP response indicating it supports scroll
   forward (terminfo code indn)
2. if the terminal sends a mouse click event

In practice, the terminals that do either are also capable of reporting the
cursor position, so let's require that for now.

We could definitely make this optional, and degrade gracefully -- that's
what I originally intended.

But maybe we don't need it? Keeps things simpler. In future, we can add a
timeout, and print an error, to help debugging terminals.
2025-04-29 13:31:13 +02:00
Johannes Altmanninger
829709c9c4 Replace synchronized update workaround
Old versions of ConHost and Putty can't parse DCS sequences.
For this reason, we briefly switch to the alternate screen buffer while sending
DCS-format (e.g. XTGETTCAP) queries. For extra paranoia, we wrapped this
procedure in a synchronized update. This doesn't seem to be needed; neither
ConHost nor Putty show glitches when the synchronized update is omitted.

As of today, every terminal that implements XTGETTCAP also implements
synchronized updates but that might change.

Let's remove it, to reduce surprise for users and terminal developers.

As a bonus, this also fixes a glitch on Terminal.app which fails to parse
the synchronized-update query (`printf '\x1b[?2026$p'`) and echoes the "p"
(bug report ID FB17141059). Else we could work around this with another
alternate screen buffer.

Unfortunately, this change surfaces two issues with GNU screen.  For one,
they don't allow apps to use the alternate screen features (the user may
allow it with "altscreen on"). Second, screen unconditionally echoes
the payload of DCS commands.  A possible fix has been suggested at
https://lists.gnu.org/archive/html/screen-devel/2025-04/msg00010.html

I think this combination of behaviors is unique among terminals.  I'm sure
there are more terminals that don't parse DCS commands yet, but I think almost
all terminals implement alternate screen buffer. Probably only terminal
multiplexers are prone to this issue. AFAICT very few multiplexers exists,
so we can work around those until they are fixed.

Disable XTGETTCAP queries for GNU screen specifically.  Unfortunately screen
does not implement XTVERSION, so I don't know how to reliably identify
it. Instead, check STY and some commonly-used values TERM values.
This has false negatives in some edge cases.
But the worst thing that happens is that "+q696e646e" will be echoed once
at startup, which is easy to ignore, or work around with something like

	function workaround --on-event fish_prompt
		commandline -f repaint
		functions --erase workaround
	end

which I don't think we should apply by default, because it can mask other
issues.

We should give screen more time to respond. I guess I'll open an issue so
we don't forget. In doubt, we can always go back to the previous approach
(but implement it in fish script).

Alternative workaround: instead of the alternative screen buffer, we could
try something like clr_eol/clr_bol to erase the spuriously echoed text. I
tried to do this in various ways but (surprisingly) failed.
2025-04-29 13:31:13 +02:00
Johannes Altmanninger
7bdb561d24 builtin set_color: stop resetting unrelated attributes on --background=normal
"set_color --background=normal" resets all attributes.  I don't expect anyone
relied on this behavior. Let's remove it, to reduce surprise.  This also
improves consistency with "set_color --underline-color=normal".

As suggested in
https://github.com/fish-shell/fish-shell/issues/11417#issuecomment-2825023522

For backwards compatibility reasons, "set_color normal" still resets
everything though.  In future we could make "set_color --foreground=normal"
reset only foreground.

Closes #11418
2025-04-29 10:14:32 +02:00
Daniel Rainer
e10573088a Clean up shell scripts
Some changes fix actual problems, e.g. missing spaces in square bracket tests,
and backticks unintentionally causing code execution when intended as formatting.

Others, such as conservative quoting probably work fine in the old version in
most situations, but it's nice to have some additional safety.

Using `{ ..; }` instead of `(..)` is just a small performance enhancement.

Many of these issues were identified by shellcheck, which might be useful in CI
as well.
2025-04-29 10:14:06 +02:00
Johannes Altmanninger
b431873ce5 Use fallback colors also for background/underline
Given

	set -g fish_color_error --background=red --background=blue
	set_color --background=red --background=blue

Historically, the former would use the first color (red) while the equivalent
set_color command uses the second one (blue).

This changed in 037c1896d4 (Reuse wgetopt parsing for set_color for internal
colors, 2025-04-13) which gave set_color semantics to the former.

This seems like the wrong choice set_color is less important.

For foreground colors we already pick the best color in a way that's consistent
across both.  Let's extend this approach to background and underline colors
(even though I'd not really recommend using this feature).

Fixes #11420
Closes #11421
2025-04-25 14:14:00 +02:00
Johannes Altmanninger
2c07dc3851 Reuse color parsing logic better
Consolidate best_color() calls because the following commit
wants to use this for background and underline colors too.
Switch to Result so we can use the "?" syntax.
2025-04-25 14:11:54 +02:00
Johannes Altmanninger
95ff22f644 Improve name for missing option argument error 2025-04-25 14:07:10 +02:00
Johannes Altmanninger
73a7d79023 Remove dead code in color parsing 2025-04-25 14:07:10 +02:00
Johannes Altmanninger
1f944c1c54 set_color.rst: update docs on fallback colors
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
2025-04-25 14:07:10 +02:00
Johannes Altmanninger
05508fa551 set_color.rst: remove redundant documentation
Also clarify that only a foreground "normal" resets everything (at least
with https://github.com/fish-shell/fish-shell/pull/11418)
2025-04-25 13:04:16 +02:00
Fabian Boehm
2f9d5ac7d6 docs: Correct "cancel"
This never, AFAIK, emptied the commandline, and I don't think that
would be a sensible thing to do
2025-04-24 19:54:39 +02:00
Fabian Boehm
f222db609f Comment some possible changes if we increase MSRV 2025-04-24 19:54:39 +02:00
Johannes Altmanninger
97641c7bf6 Set transient command line in custom completions (Rust port regression)
Commit df3b0bd89f (Fix commandline state for custom completions with variable
overrides, 2022-01-26) made us push a transient command line for custom
completions based on a tautological null-pointer check ("var_assignments").

Commit 77aeb6a2a8 (Port execution, 2023-10-08) turned the null pointer into
a reference and replaced the check with "!ad.var_assignments.is_empty()".
This broke scenarios that relied on the transient commandline.  In particular
the attached test cases rely on the transient commandline implicitly placing
the cursor at the end, irrespective of the cursor in the actual commandline.

I'm not sure if there is an easy way to identify these scenarios.

Let's restore historical behavior by always pushing the transient command line.

Fixes #11423
2025-04-24 19:35:03 +02:00
Johannes Altmanninger
59d86e8e33 __fish_complete_suffix: don't write to global/universal variables 2025-04-24 19:35:03 +02:00
Anton Bilous
b7b1753716 Mention replace mode in fish_mode_prompt docs 2025-04-24 16:26:45 +03:00
Daniel Rainer
4555768d98 Add clippy lints about using stdlib print macros
Context why we do not want to use these macros:
https://github.com/fish-shell/fish-shell/pull/11397#discussion_r2050759690
https://github.com/fish-shell/fish-shell/pull/11397#discussion_r2050759693
https://github.com/fish-shell/fish-shell/pull/11397#discussion_r2050759696

These lints are not strictly about the macros, but at the moment they are
implemented to flag `print!`, `println!`, `eprint!`, and `eptintln!`.

https://rust-lang.github.io/rust-clippy/master/#print_stdout
https://rust-lang.github.io/rust-clippy/master/#print_stderr
https://doc.rust-lang.org/stable/clippy/lint_configuration.html#allow-print-in-tests
2025-04-23 20:24:12 +02:00
Johannes Altmanninger
07ed77e9a8 builtin set_color: do print other colors if one is reset-all
Commit cebc05f6c1 (Reset is not a color, 2025-04-15) tried to simpilfy
this behavior but forgot about cases like "set_color --background=normal
red --bold" where we do want to continue after resetting background.

Closes #11417
2025-04-23 20:11:24 +02:00
Johannes Altmanninger
709f193b50 builtin set_color: remove obsolete comment
"set_color normal --bold" does set the bold modifier since commit cebc05f6c1
(Reset is not a color, 2025-04-15), so this comment no longer applies.
2025-04-23 20:11:24 +02:00
Fabian Boehm
131f0f3916 CHANGELOG 2025-04-23 16:51:37 +02:00
Fabian Boehm
ae6eb121d9 Ignore some unused ControlFlow returns
Current rust nightly warns on these.
2025-04-23 16:36:16 +02:00
Daniel Rainer
51cf65d7c8 Remove e?println macros
These macros are problematic because:
- They panic when the output stream is closed.
- They are not aware of fish's encoding of arbitrary bytes into a section of a
  Unicode private use area. The custom printf macros handle this.

https://github.com/fish-shell/fish-shell/pull/11397
https://github.com/fish-shell/fish-shell/pull/11402
2025-04-23 15:24:35 +02:00
Anton Bilous
0349a70321 Fix typo in language docs 2025-04-23 21:07:31 +08:00
Ilia Gogotchuri
c0f5fcb089 Update tofu.fish 2025-04-22 14:17:52 +04:00
Johannes Altmanninger
ce631fd2fb Colored underlines in set_color and fish_color_*
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 #11388
Closes #7619
2025-04-21 18:38:11 +02:00
Johannes Altmanninger
cc9849c279 Curly underlines in set_color and fish_color_*
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.html

Closes #10957
2025-04-21 18:12:42 +02:00
Johannes Altmanninger
ef25f1d27b Break up long line 2025-04-21 18:11:44 +02:00
Johannes Altmanninger
692599387b colors: test weird behavior of "--background=normal" 2025-04-21 18:11:44 +02:00
Johannes Altmanninger
c32b7d35ea Document differences between builtin set_color and fish_color_* handling 2025-04-21 18:11:44 +02:00
Johannes Altmanninger
939902eb29 Remove mysterious workaround for buggy sgr0 handling
This workaround was added in commit d66700a0e4 (Color work, 2012-02-11).
I don't understand why it would be necessary, it seems redundant.  Bravely
remove it. Would be interesting to know which terminal caused the motivating
problem.  Terminal.app and others seem to be unaffected by this change.
2025-04-21 18:11:44 +02:00
Johannes Altmanninger
cebc05f6c1 Reset is not a color
This command does not work

	set_color --background=reset

These seem to work

	set fish_color_normal reset
	set fish_color_normal --background=reset

but I don't understand why anyone would do that, since an empty color option
gives the same behavior.

Also "reset" is totally undocumented, since "normal" is our canonical spelling.

Let's simplify things by removing support for reset everywhere except if it's
a foreground color (since there are some uses of "set_color reset" out there).

Also, simplify the set_color logic accordingly.
2025-04-21 18:11:44 +02:00
Johannes Altmanninger
de830644fc webconfig: set_color -b=red is invalid
While at it, support parsing of "set_color -b red".
2025-04-21 18:11:43 +02:00
Johannes Altmanninger
1a63956860 Move separate bg/fg parsing up the call stack
Our highlighting module allows different highlight roles for foreground
and background.

Other users of our color-parsing logic have no need for this.

Historically we have passed an "is_background" bool and only parsed what we're
interested in.  This sort of makes sense because it's exactly what we need,
but it meant that the special behavior spread quite far.

There is no real need for spreading it; a function with the behavior "parse
a text face but honor is_background" is strictly more complex than "parse a
text face". Additionally, any performance optimization is only relevant if
the user specifies faces that won't be used, which is a very unusual case.

Let's isolate this logic in the highlighting module.
2025-04-21 18:11:43 +02:00
Johannes Altmanninger
6a8a02a549 Improve consistency of the CSI m writing logic 2025-04-21 18:11:43 +02:00
Johannes Altmanninger
d33cc5ea24 Replace tuple return value with struct
The parent commit got rid of the is_background parameter that determined
the meaning of the return value (fg/bg); since we always return both now,
give them names.
2025-04-21 18:11:43 +02:00
Johannes Altmanninger
9c39cab239 Make text style bitflags a plain struct
A following commit wants to add other underline styles.  At most one underline
style can be active at one time.  This can't be modelled well by a flat
bitset, so let's use a composable type here.
2025-04-21 18:11:43 +02:00
Johannes Altmanninger
426b242ce5 Outputter: use literals instead of variables 2025-04-21 17:37:36 +02:00
Johannes Altmanninger
69aa492d40 Future-proof text style resetting logic
Some text styles don't have way of unsetting them specifically, so we use
CSI m. Let's make this the default action.
2025-04-21 17:37:36 +02:00
Johannes Altmanninger
45a13a0075 Outputter cache to use text face type
When the text face changes from bold to non-bold, we need to reset
all attributes since there is no exit_bold_mode.

The same holds for various dim and reverse mode, and future attributes.

A following commit wants to make this logic more robust to addition of future
attributes. Prepare for that by using the new type.
2025-04-21 17:37:36 +02:00
Johannes Altmanninger
fada8cfd6c Document weird "set_color normal --bold" behavior 2025-04-21 17:37:36 +02:00
Johannes Altmanninger
a77da2366b builtin set_color: reuse outputter for resetting attributes 2025-04-21 17:37:36 +02:00
Johannes Altmanninger
f36b704098 builtin set_color: remove redundant condition 2025-04-21 17:37:36 +02:00
Johannes Altmanninger
234a9ef777 builtin set_color: remove weird use of lifetime extension
This is correct but seems odd. Converting this value to a reference
does not add convenience since we only use it as method receiver now.
2025-04-21 17:37:36 +02:00
Johannes Altmanninger
dd02a7e662 Remove hack for "set_color --print-colors --background normal"
This is no longer needed.
2025-04-21 17:37:36 +02:00
Johannes Altmanninger
037c1896d4 Reuse wgetopt parsing for set_color for internal colors
Not sure if this is 100% a good idea but it does remove some duplication.

While at it, change parse_color_maybe_none to actually return Option::None
and not Color::None which means something else (see a following commit).
2025-04-21 17:37:36 +02:00
Johannes Altmanninger
b7c4ad455c builtin set_color: extract function 2025-04-21 17:37:36 +02:00
Johannes Altmanninger
8586286837 Remove a needless use of Color::None 2025-04-21 17:37:36 +02:00
Johannes Altmanninger
64c362bb73 Move text face/color parsing functions into new module
No other change.
2025-04-21 17:37:36 +02:00
Johannes Altmanninger
2ce3068465 New type for colors + text styling attributes
Our "Color" type also includes text styling (bold, italics, ...).  This doesn't
seem like the perfect way to model this, because the background text styles
are always unused (this is noticeable with some fish_color_* variables).

Introduce a type that represents attributes to apply to text, and nothing
else. Prefer to pass this instead of two Color values with redundant text
style is redundant.
2025-04-21 17:37:36 +02:00
Johannes Altmanninger
6cf96c5950 sgr0 *does* reset both foreground and background color
We have a a workaround with a comment saying

> We don't know if exit_attribute_mode resets colors, so we set it to
> something known.

I'm pretty sure fish (and other software) makes this assumption.
I'd be very surprised if a relevant terminal behaves differently.
Let's remove our attempt to work around around this.

While at it, extract a function to be used in two other places
(but don't change their behavior yet).
2025-04-21 17:37:36 +02:00
Johannes Altmanninger
5067fa5f1d Harmonize fg/bg color output state transition
A "None" type color means "don't change it, use the last color.  So it makes
no sense to ever set "self.last_fg = NONE".  The background-color code path
only sets it in the other cases.  Let's copy that for the foreground one.

Also, extract this assignment to simplify both code paths.
2025-04-21 17:37:36 +02:00
Johannes Altmanninger
70c25096f2 Outputter: improve field name 2025-04-21 17:37:36 +02:00
Johannes Altmanninger
007eda2f89 builtin set_color: fix inconsistent output in --print-colors
fish -c 'set_color --print-colors --background blue' |xxd

does not print color enabling sequences but does print *disabling* sequences.
There's no need for that.
2025-04-21 17:37:36 +02:00
Johannes Altmanninger
76dbd76c73 builtin set_color: remove dead code 2025-04-21 17:37:36 +02:00
Johannes Altmanninger
82e7281675 Avoid intermediate WString when parsing colors
While at it, remove a check for "color_name.is_empty()" that is always true.
2025-04-21 17:37:36 +02:00
Johannes Altmanninger
1f0ce40408 Pass the RGB type instead of three bytes 2025-04-21 17:37:36 +02:00
Johannes Altmanninger
5b9ba559c7 Rename RgbColor to Color
RgbColor can also be a named color, so this name is surprising to readers
who don't have the implicit assumption that named colors are the default
and that RGB support is something novel.
2025-04-21 17:37:36 +02:00
Johannes Altmanninger
6f65661109 Replace redundant type name with Self 2025-04-21 17:37:36 +02:00
Peter Ammon
489d5d1733 ast: remove Node parent pointers
tl;dr reduce memory usage and ast complexity. No functional change expected.

This concerns how our ast is represented. Prior to this commit, and ever
since the new ast was introduced, each Node had a reference to its parent -
the so-called "parent pointer". This made it convenient to "walk around"
the AST - for example we could get a command and then walk up the AST to
determine if that command had a decoration (`time`, etc).

This parent pointer concept was natural in C++ for a few reasons:

1. Pointers are idiomatic in C++.
2. Parent pointers were "thin": just regular pointer-sized, e.g.
   8 bytes in x86-64.
3. C++'s inheritance means that the pointer can just be stored as a field
   in the base Node class. Super easy and efficient.

But these proved to have significant drawbacks when expressed in Rust:

1. Parent pointers form a cyclic data structure which is very awkward in
   Rust. We had to use raw pointers and unsafe code.
2. Parent pointers were a `&dyn Node` which is necessarily "fat" (base
   pointer + vtable pointer), taking up 16 bytes on a 64 bit machine. This
   greatly bloated the size of the AST because our AST is quite fine (many
   detailed node types).
3. The lack of inheritance means that parent pointers had to be repeated
   for every node and exposed through the Node trait, which was awkward and
   verbose.

In fact storing parent pointers is rather uncommon among AST
implementations. For example, LLVM does not do this; instead it dynamically
constructs a map of parent pointers on demand (see `ParentMapContext`).
fish could do this or something like it, but in fact we can do better: we
can tweak Traversal to provide parent pointers.

As a reminder, Traversal is a way of naturally iterating over all AST nodes
in a for loop:

    for node in ast.walk() {...}

This is in-order ("top-down"). A parent node is yielded before its children.

Prior to this commit, this worked as follows: the Traversal maintained a
stack of next-to-be-yielded nodes. The `next()` function would pop off the
next node, push all of its children onto the stack, and then yield that
popped node.

We can easily make Traversal remember the sequence of parents of a given
Node by tweaking the Traversal to remember each Node after popping it. That
is, mark each Node in the stack as "NeedsVisit" or "Visited". Within
`next()`, check the status of the top node:

  - NeedsVisit => mark it as Visited, push its children, and return that Node
  - Visited => pop it, discard it, and try again

This means that, for any Node returned by `next()`, we can get the sequence
of parents as those Nodes that are marked as Visited on the stack.

The net effect of all of this is a large decrease in ast complexity and
memory usage. For example, __fish_complete_gpg.fish goes from 508 KB to 198 KB,
as measured by `fish_indent --dump-parse-tree`.

There's somewhat higher memory usage for Traversal, but these are transient
allocations, not permanent.
2025-04-20 17:53:48 -07:00
Peter Ammon
e6bc8ffa13 ast: remove dead code
Having removed parent pointers, a bunch of existing ast "as_" functions have
become unused; remove them.
2025-04-20 17:53:43 -07:00
Peter Ammon
ff87e2cf0a ast: remove parent pointers
This removes parent back-pointers from ast nodes. Nodes no longer store
references to their parents, resulting in memory size reductions for the ast
(__fish_complete_gpg.fish goes from 508 KB to 198 KB in memory usage).
2025-04-20 17:53:43 -07:00
Peter Ammon
a528567d5c IndentVisitor to stop using parent pointers
We can just store these ourselves; don't have to be baked into the AST.
2025-04-20 17:53:43 -07:00
Peter Ammon
374b504eeb parse_util_detect_errors_in_ast to stop using ast parent pointers
Continue to move away from parent pointers.
2025-04-20 17:53:43 -07:00
Peter Ammon
119716fbf2 extract_tokens::is_command to stop using ast parent pointers
Simple change to remove a user of parent back-references.
2025-04-20 17:53:43 -07:00
Peter Ammon
68a357be3d fish_indent to stop using ast parent pointers
Reimplement fish_indent to discover parents through traversals, not ast
parent pointers.
2025-04-20 17:53:43 -07:00
Peter Ammon
996b34b5cb ast: pretty-print to stop using ast parent pointers
These depths are used in calculating indents for ast pretty-printing.

This moves away from parent back-pointers, so that we can ultimately remove
them.
2025-04-20 17:53:43 -07:00
Peter Ammon
8f46b617db ast: make Traversal more powerful
Prior to this commit, Traversal was a convenient way to walk the nodes of
an ast in pre-order. This worked simply: it kept a stack of Nodes, and then
when a Node was visited, it was popped off and its children added.

Enhance Traversal to track whether each node on the Stack is `NeedsVisit`
or `Visited`. The idea is that, when a Node is yielded from next(), we can
reconstruct its parents as those Visited nodes on the Traversal stack.

This will allow clients to get the parents of Nodes as they are traversed
without each Node needing to explicitly save its parent.
2025-04-20 17:53:43 -07:00
Peter Ammon
f7543dd447 ast: remove certain as_node() function calls
We can remove all of them once MSRV becomes 1.86, which adds support for trait
upcasting coercion; we can remove a few today.
2025-04-20 17:53:43 -07:00
Peter Ammon
7d98cc8850 ast: stop using Node::ptr_eq
This function hid a bug! It converted two Nodes to `*const ()` which discards
the vtable pointer, using only the data pointer; but two nodes can and do have
the same data pointer (e.g. if one node is the first item in another).

Add the (statically dispatched) is_same_node function with a warning comment,
and adopt that instead.
2025-04-20 17:53:43 -07:00
Peter Ammon
b33795533c ast: remove leaf_as_node()
Plain old as_node() is fine.
2025-04-20 17:53:42 -07:00
Peter Ammon
3f4839e5f2 Optimize ParseKeyword::from(&wstr)
This is a hot function and is easy to optimize.
2025-04-20 17:53:42 -07:00
Peter Ammon
cef7c3c5c4 Switch ParseKeyword to Rust naming conventions 2025-04-20 17:53:42 -07:00
Peter Ammon
a874237bff ast: Bravely stop allocating so much in Boxes
Now that we have more confidence in our pointers, we can allocate directly
more often, instead of always through Box. This recovers the performance
lost from the previous commit.
2025-04-20 17:53:42 -07:00
Peter Ammon
0b4883d07f ast: Bravely stop boxing items in lists
Prior to this commit, lists of items (e.g. an argument list to a command) would
each be Boxed, i.e. we had effectively Vec<Box<Item>>. The rationale here is
that we had raw pointers and pointer stability was important to enforce.

But we have fewer raw pointers now - only the parent pointers - and we can be
confident that the Ast will not change or move after construction. So remove
this intermediate Box, simplifying some logic and reducing ast size by ~5%.

This slows down Ast construction because we're still constructing
the Box and moving things in and out of it - that will be addressed in
subsequent commits.
2025-04-20 17:53:42 -07:00
Peter Ammon
3b3063287b ast: Add some comments about raw pointers and stability 2025-04-20 17:53:42 -07:00
Peter Ammon
be88d103ba ast: Use boxed slice instead of vec for list nodes
This saves a decent amount of memory, both because we no longer have excess
capacity sitting around that we'll never use, but also because we no longer need
to store the "capacity" value.
2025-04-20 17:53:42 -07:00
Peter Ammon
271a85571d Add a benchmark for AST construction
Run with `cargo +nightly bench --features=benchmark`
2025-04-20 17:53:42 -07:00
Peter Ammon
5f0584a6e6 Teach fish_indent to emit basic parse tree size metrics
A good basis to begin optimization.
2025-04-20 17:53:42 -07:00
David Adam
22d2dd6c90 Merge branch 'Integration_4.0.2' 2025-04-21 07:55:38 +08:00
Peter Ammon
485a6fa859 Fix a redundant import 2025-04-20 16:34:10 -07:00
Fabian Boehm
ca8416f18d docs/bind: Fix typo
Fixes #11408
2025-04-20 21:54:57 +02:00
David Adam
f1456f9707 Release 4.0.2 2025-04-20 21:11:52 +08:00
Sam Doran
b9f2275349 Refine when file completions are offered and add a missing short arg 2025-04-19 01:59:47 -04:00
Sam Doran
0b97fa7114 Evaluate completion arguments when called
This makes the destinations update dynamically when they are added/removed.
Unquote the echo statement so that it is correctly paresd by the -a options.
2025-04-19 01:17:58 -04:00
Sam Doran
1a2958d42b No need to reset ID
The values are only echoed if ID matches, so it will always be correct.
2025-04-19 00:59:30 -04:00
Sam Doran
3e8308f6eb Argument not description 2025-04-19 00:54:18 -04:00
Sam Doran
ff987f5f76 Do not use test for evaluating string match
Also add `--` to ensure parameters don't get mixed up with the line itself.
2025-04-19 00:52:31 -04:00
Daniel Rainer
9d904e1113 Improve profiling output
Indicate the units of the durations (microseconds).

Right-align the durations for better readability.

Use `format!` instead of `fprintf` for more flexible formatting.

Write to `File` instead of raw fd.

Closes #11396
2025-04-18 20:22:30 +02:00
David Adam
c88e6827b7 CHANGELOG: work on 4.0.2 2025-04-19 00:06:31 +08:00
Lucas Garron
3d7d57d612 Add completions for iconutil (macOS).
Closes #11392
2025-04-18 18:05:49 +02:00
exploide
fb314b28ff completions(tcpdump): suppress stderr + updates 2025-04-18 17:17:39 +02:00
Daniel Rainer
aa01f984b7 Use File as arg to print_profile 2025-04-17 11:46:35 +02:00
Daniel Rainer
b8bd3a25d7 Improve error handling 2025-04-17 11:46:35 +02:00
Daniel Rainer
01e7ba4b3a Reduce scope of raw_fd 2025-04-17 11:46:35 +02:00
Daniel Rainer
e5c953ea92 Replace read_loop with more idiomatic code 2025-04-17 11:46:35 +02:00
Daniel Rainer
70d682a110 Set file permissions via stdlib method 2025-04-17 11:46:35 +02:00
Daniel Rainer
21e284e548 Rename last_read_file to last_read_file_id
This is done to match the field's type.
2025-04-17 11:46:35 +02:00
Daniel Rainer
c2b8ee5554 Replace fstat with File::metadata() where possible 2025-04-17 11:46:35 +02:00
Daniel Rainer
5e8276ed15 Change file_id_for_fd to file_id_for_file 2025-04-17 11:46:35 +02:00
Sam Doran
a6fdb41940 Update completion for tmutil
- Reorganize completions and options so they are easier to read.
- Add destination UUIDs to completetions as well as descriptions
- Add a few missing sub commands
2025-04-16 11:59:24 -04:00
Johannes Altmanninger
bc3e3ae029 builtin read: always handle out-of-range codepoints (Rust port regression)
As mentioned in
https://github.com/fish-shell/fish-shell/pull/9688#discussion_r1155089596,
commit b77d1d0e2b (Stop crashing on invalid Unicode input, 2024-02-27), Rust's
char type doesn't support arbitrary 32-bit values.  Out-of-range Unicode
codepoints would cause crashes.  That commit addressed this by converting
the encoded bytes (e.g. UTF-8) to special private-use-area characters that
fish knows about.  It didn't bother to update the code path in builtin read
that relies on mbrtowc as well.

Fix that. Move and rename parse_codepoint() and rename/reorder its input/output
parameters.

Fixes #11383

(cherry picked from commit d9ba27f58f)
2025-04-16 11:33:15 +02:00
Johannes Altmanninger
3191ac13e5 Reduce parse_codepoint responsibilities, fixing alt in single-byte locale?
This also changes the single-byte locale code path to treat keyboard input
like "\x1ba" as alt-a instead of "escape,a".  I can't off-hand reproduce
a problem with "LC_ALL=C fish_key_reader", I guess we always use a UTF-8
locale if available?

(cherry picked from commit b061178606)
2025-04-16 11:28:28 +02:00
Johannes Altmanninger
4f810809c8 Fix builtin test assigning wrong range to "! -d /" (Rust port regression)
Fixes #11387

(cherry picked from commit c740c656a8)
2025-04-16 11:25:35 +02:00
Johannes Altmanninger
4e85366416 builtin commandline: minor cleanup 2025-04-16 11:24:33 +02:00
Johannes Altmanninger
0284292392 builtin read to pass through invalid UTF-8; reader to ignore invalid codepoints
Two issues:

1. typing the codepoint 0x123456 into fish_key_reader:

	$ fish_key_reader -cV
	# decoded from: \xf4\xa3\x91
	bind \xf4 'do something'
	# decoded from: 
	bind \xa3 'do something'
	# decoded from: 
	bind \x91 'do something'

The invalid codepoint is represented in its original encoding, which leaks
to the UI. This was more or less intentionally added by b77d1d0e2b (Stop
crashing on invalid Unicode input, 2024-02-27).  That commit rendered it
as replacement byte, but that was removed for other reasons in e25a1358e6
(Work around broken rendering of pasted multibyte chars in non-UTF-8-ish
locale, 2024-08-03).

We no longer insert such (PUA) codepoints into the commandline.  The "bind"
comes above would work however.  I don't think this is something we want
to support.  Discard invalid codepoints in the reader, so they can't be
bound and fish_key_reader shows nothing.

2. builtin read silently drops invalid encodings This builtin is not really
suited to read binary data (#11383 is an error scenario), but I guess it can
be bent to do that.  Some of its code paths use str2wcstring which passes
through e.g. invalid UTF-8.  The read-one-char-at-a-time code path doesn't.
Fix this.
2025-04-16 11:24:33 +02:00
Johannes Altmanninger
d9ba27f58f builtin read: always handle out-of-range codepoints (Rust port regression)
As mentioned in
https://github.com/fish-shell/fish-shell/pull/9688#discussion_r1155089596,
commit b77d1d0e2b (Stop crashing on invalid Unicode input, 2024-02-27), Rust's
char type doesn't support arbitrary 32-bit values.  Out-of-range Unicode
codepoints would cause crashes.  That commit addressed this by converting
the encoded bytes (e.g. UTF-8) to special private-use-area characters that
fish knows about.  It didn't bother to update the code path in builtin read
that relies on mbrtowc as well.

Fix that. Move and rename parse_codepoint() and rename/reorder its input/output
parameters.

Note that the behavior is still wrong if builtin read can't decode the
input; see the next commit.

Fixes #11383
2025-04-16 11:24:33 +02:00
Johannes Altmanninger
b061178606 Reduce parse_codepoint responsibilities, fixing alt in single-byte locale?
This also changes the single-byte locale code path to treat keyboard input
like "\x1ba" as alt-a instead of "escape,a".  I can't off-hand reproduce
a problem with "LC_ALL=C fish_key_reader", I guess we always use a UTF-8
locale if available?
2025-04-16 11:24:33 +02:00
Johannes Altmanninger
a63633edea Remove redundant code in parse_codepoint 2025-04-16 11:24:33 +02:00
Johannes Altmanninger
c740c656a8 Fix builtin test assigning wrong range to "! -d /" (Rust port regression)
Fixes #11387
2025-04-16 11:24:33 +02:00
Johannes Altmanninger
721c9a2c14 completions/set: add some special variables 2025-04-16 11:24:33 +02:00
Johannes Altmanninger
7337bfee47 completions/set: sort 2025-04-16 11:24:33 +02:00
Johannes Altmanninger
5076cfbd71 Fix a case where path canonicalization leaks trailing slash
As reported in
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$BDVmBtBgtKCj45dVfS36rP7Y6Fo7E4uBg1vcH9IIIQg

	tmux new-session -c "" fish -C 'echo $PWD'

prints

	/home/fishuser/

This is because our path canonicalization function only
removes trailing slashes if there were duplicate slashes in the string.
Else (for the case above), we end up with "trailing == len"
which means we ignore trailing slashes.

I don't think this was intended by 24f1da7f30 (Add a fancy new
paths_are_equivalent function to test for equivalent paths instead of merely
equal ones, 2013-08-27). Fix it.
2025-04-16 11:24:33 +02:00
Johannes Altmanninger
2d506245be Rename confusing variables in path_make_canonical
The terms leading/trailing for the read-head and write-head are reasonable
but confusing in this context where trailing (slash) has another meaning.
2025-04-16 11:24:33 +02:00
Johannes Altmanninger
afa517d907 doc/terminal-compatibility: document cursor shaping sequence
While at it, also document the command to reset the shape to the default,
which we should probably use.  See foot commit 49034bb7 (csi: let CSI 0 q mean
"switch to user configured cursor style", 2019-07-22).

As of today, the XTerm documentation is a not clear on this; in
XTerm itself, CSI 0 q may actually change the cursor because they have an
additional default cursor is configured differently..
2025-04-16 11:24:33 +02:00
Johannes Altmanninger
123b262e97 fish_jj_prompt: remove not-so-useful bits
Things like branch and tag name can take up a lot of space on the screen. The
empty status may be useful but we're still looking for evidence.  For now let's
keep only the conflict status, which is fairly familiar from the Git prompt.

See also #11183
2025-04-16 11:24:33 +02:00
Johannes Altmanninger
267b16235d Fix transient prompt mode for single-line prompts
Extend a hack multi-line prompts to the new transient prompt code path.
This fixes transient prompt with single-line prompts; added a test case.

While at it, add a test that covers the need for this hack.

Patch-by: kerty <g.kabakov@inbox.ru>

See https://github.com/fish-shell/fish-shell/pull/11153#issuecomment-2801014723
2025-04-16 11:22:14 +02:00
kpbaks
54971621de completions/git: show url as description for remote completion 2025-04-16 09:56:45 +02:00
Ilya Grigoriev
76a6ffe59e status get/list-files: fix minor bugs when compiled without embedded files (#11390)
* man: redirect stderr to /dev/null when checking for embedded files

This fixes a bug where `man status` results in "status: fish was not
built with embedded files⏎" printed.

* fish_config and status completions: redirect stderr to /dev/null when checking for embedded files

I am less sure about this commit, can get rid of it.

* status get-file/list-files: add \n to error message when not compiled with embedded files
2025-04-16 08:46:22 +02:00
Fabian Boehm
6ede047680 completions/cargo: Fix package completion
The original only worked in the manifest directory *and* didn't even
list the right packages.

E.g. for fish it listed "printf", when the package is called
"fish-printf". So we're not keeping it because it's wrong.

Instead let's parse the actual json. It's a shame there is no
simple command to just get it line-delimited, of course.

Fixes #11384
2025-04-15 20:23:03 +02:00
Fabian Boehm
ab7d52d727 completions/rustup: Simplify listing installable targets 2025-04-15 20:21:10 +02:00
Fabian Boehm
6c75cf75fe Update widestring 2025-04-15 20:13:22 +02:00
ndrew222
827bc32561 added completion for uv and uvx 2025-04-16 00:36:42 +08:00
Peter Ammon
85ea9eefc6 Fight off some clipplies 2025-04-14 21:08:26 -07:00
David Adam
692b53ab85 remove stray file 2025-04-13 09:14:46 +08:00
Johannes Altmanninger
92510c0488 man.fish: fix spurious error on embed-data builds
Commands like "man grep" print an error because __fish_data_dir[1] is no
longer defined. Fix that.
2025-04-12 20:25:08 +02:00
exploide
b6c5f3dc38 completions: improved ip completions
added completions for ip tuntap
standardize help completion
2025-04-12 16:26:15 +02:00
Fabian Boehm
765b700a04 cmake: Warn on unknown build type
CMake has this entire zoo of weird build types including "MinSizeRel".
I've also seen it set to empty, in distro packages no less.

Since we can't really make them all known to cargo, let's warn.

We could also error, but I'm not convinced there isn't some distro
packager out there setting it to "StrawberriesAndKittens" for some
reason,
and they'd be very cross with us if that stopped working.

See #11376
2025-04-12 14:21:56 +02:00
Johannes Altmanninger
b569f0d62f Update docs for transient prompt
Closes #11153
2025-04-12 12:09:08 +02:00
Johannes Altmanninger
6e85e5f6a0 Fix sphinx warning in changelog 2025-04-12 12:07:54 +02:00
Johannes Altmanninger
4b2c707721 Simplify exec_prompt_cmd 2025-04-12 12:07:54 +02:00
kerty
b3e417fd05 Add documentation for transient prompt 2025-04-12 12:07:26 +02:00
kerty
231ab22ce4 Update docs for transient prompt
See #11153
2025-04-12 12:07:26 +02:00
kerty
ca1d7ef863 Fix residual lines after repaint with shrinking prompt
If you use `set t 10; function fish_prompt; seq $t; set t $(math $t - 1); end` and trigger a repaint, you will see 9 residual lines from the previous prompt.
2025-04-12 10:51:35 +02:00
kerty
7ed4dfbd2d Ease condition for the execution of the right prompt
Now, the right prompt will not be executed only if it is undefined `fish_right_prompt`.
This allows the use of `read -p 'echo left' -R 'echo right'`.

Also changes condition for use of `DEFAULT_PROMPT` for consistency.
2025-04-12 10:46:33 +02:00
kerty
cb31f3e092 Refactor Reader::exec_prompt
Also fixes repaint-mode being run interactively
2025-04-12 10:46:33 +02:00
Johannes Altmanninger
b81a55e5f0 Fix bad conflict resolution 2025-04-12 10:34:38 +02:00
Johannes Altmanninger
6fcb418ae3 Enable 24-bit RGB colors by default
I think `set_color ff0000` should default to outputting true-color sequences.
Unfortunately there is no good and widely-supported way to query for true-color
support.  `COLORTERM=truecolor` doesn't work in some cases such as ssh.

Since many terminals nowadays implement the RGB sequences, let's try using
them by default.

Note that Emacs's ansi-term implements truecolor now.

See also the discussion around
https://github.com/fish-shell/fish-shell/pull/11345#issuecomment-2794920900

Closes #11372
2025-04-11 22:20:45 +02:00
Johannes Altmanninger
e7270915ac Update color support on COLORTERM change 2025-04-11 22:20:45 +02:00
Johannes Altmanninger
e45401e403 Fix copy paste error for smso/ritm/rmul sequences
We have basically zero system tests for text coloring/formatting.  I have
something in the works that will enable this without forcing tests to parse
the output of "tmux capture-pane -pe".

Fixes #11373
Fixes 17b4b39c8b (Stop reading terminfo database, 2025-03-20).
2025-04-11 22:20:45 +02:00
Johannes Altmanninger
fee48f8508 Remove stale output buffering code
This is handled above.
2025-04-11 22:20:45 +02:00
Johannes Altmanninger
d622949d26 Fix kill-selection crash when selection start is out-of-bounds
This part of the code could use some love; when we happen to clear the
selected text, we should end the selection.

But that's not how it works today. This is fine for Vi mode, because Vi
mode never deletes in visual mode.

Let's fix the crash for now.

Fixes #11367

(cherry picked from commit af3b49bf9c)
2025-04-11 19:31:09 +02:00
Daniel Rainer
9618a38215 Make control flow more explicit, log errors 2025-04-11 17:52:27 +02:00
Daniel Rainer
5c0fddae70 Refactor history flushing
Use function names which explicitly state their flushing behavior.
When writing history items to a new file, flushing is only done at the end.
When appending items to an existing file, flushing is done for each item, in
order to keep the `first_unwritten_new_item_index` counter consistent with the
file system.
2025-04-11 17:52:27 +02:00
Daniel Rainer
5c8d822ee1 Flush history with sync
- Replace the write_loop call with Writer::write_all.
- Call sync_all on the file to ensure it gets written to storage.
2025-04-11 17:52:27 +02:00
Fabian Boehm
170b3593a0 CHANGELOG 2025-04-11 17:39:56 +02:00
Fabian Boehm
b815fff292 Set $__fish_data_dir to empty for embed-data builds
These builds do not use it, and setting it makes it possible to use
stale files.

So instead, we set it to empty. All uses I could find are either fine
with that (`set fish_function_path $__fish_data_dir/functions` - which
would also just be empty, which means it reads the embedded
functions),

or would break even if the variable was set but the directory was
empty (`source $__fish_data_dir/completions/git.fish`).
2025-04-11 17:29:22 +02:00
Fabian Boehm
329cd7d429 Make functions, completions and tests resilient to running on an embed-data fish
In case a completion needs a function from another script, run
`complete -C"foo "` to load it, so the full autoloading logic is used.

Otherwise these things break if the path is off. E.g. cargo's version
will fail if you override the cargo completion in
~/.config/fish/completions without also overriding the rustup
completions.

In other cases, fix for empty $__fish_data_dir, which will be coming in the next commit
2025-04-11 17:29:22 +02:00
Fabian Boehm
53b2f5511b Rename the "installable" feature to "embed-data"
This reflects better what it is - fish doesn't need to "install"
itself anymore, it just includes the data in the binary.

This also means we could include a separate "embed-man" feature that
can be turned off if you want the man pages to be shipped separately.

Also explain that in the README.
2025-04-11 17:29:22 +02:00
Fabian Boehm
1a96db1708 functions/*: Extract data when needed
Technically the fish_update_completions files could also be piped to
python, but they'd have to be one file.

So for now, if you start a single-file fish, you'll have to run
fish_update_completions manually.

That fits the idea of having a single file that you move somewhere
better, given that it otherwise would run a script in the background
that creates a bunch of files
2025-04-11 17:29:22 +02:00
Fabian Boehm
ee2a6a851d Document and complete status get-file/list-files 2025-04-11 17:29:22 +02:00
Fabian Boehm
b56b876a98 Add status list-files
This allows us to implement fish_config using embedded files
2025-04-11 17:29:22 +02:00
Fabian Boehm
ca3a7f8356 Add status get-file
This allows getting embedded files, so we can use them in functions
2025-04-11 17:29:22 +02:00
Fabian Boehm
c8719fbff5 Rebuild if share/ or doc_src/ changed
Because these are embedded in the fish binary,
we need to rebuild fish once they're changed.

This is only for release builds,
because rust-embed only really embeds in those
(debug builds read from the filesystem).
2025-04-11 17:29:22 +02:00
Fabian Boehm
2a1c5b18e8 Remove --install option
This is no longer useful, given that we read files from in the binary.

In the upcoming commits, this can be done with status list-files/get-file if you need it
2025-04-11 17:29:22 +02:00
Fabian Boehm
2a3a23f53d Teach autoloader to read embedded files
This will load the functions and completions from inside of the fish
binary.

That means its no longer necessary to *install* a self-installable
build for basic functionality.

The functions/completions will be loaded *last*, so they are still
overridable via a file on disk (with the exception of
generated_completions, which we only use as a fallback if no
completions exist).

It still needs to extract files that are to be used by other tools,
including the man pages, fish_config.py, the man page completion
generator.

The remaining issues:

- It no longer prompts to install, but if you tried `fish_config`
  after this it would fail to open the tool,
  and it would be easy to forget to update those files
  So: When and how should this remind you that these files need to be extracted?
  Do we want e.g. a builtin that checks the version file (`status installed`)?
  This could then be run by `fish_config` and `help` and tell you to run `fish --install`.
- `builtin --help` will fail - we could read these things from inside,
  but we'd need groff for that.
  Do we want to pre-process these and put them in the builtins themselves?
  Do we want to print these on demand in `__fish_print_help` to groff?
- What directories need to still be defined? Does $__fish_data_dir need to keep existing?

Technically this *could* be the main distribution method. Maybe we
could let distro packages skip the embedded documentation and external
files,
but keep the functions/completions in the binary.
2025-04-11 17:29:22 +02:00
Fabian Boehm
66d7c00ba3 Let parser eval string directly
This gets the reader out of asting the source and is needed for
autoloader to get it to read a source string directly

Also add an "eval_file_wstr" method as a convenience to run a wstr as if it is a *file*, with a block and stuff
2025-04-11 17:29:22 +02:00
Fabian Boehm
64659e48f8 HACK: Create man1 dir even if not installable 2025-04-11 17:29:22 +02:00
Johannes Altmanninger
17b4b39c8b Stop reading terminfo database
Our use of the terminfo database in /usr/share/terminfo/$TERM is both
1. a way for users to configure app behavior in their terminal (by
   setting TERM, copying around and modifying terminfo files)
2. a way for terminal emulator developers to advertise support for
   backwards-incompatible features that are not otherwise easily observable.

To 1: this is not ideal (it's very easy to break things). There's not many
things that realistically need configuration; let's use shell variables
instead.

To 2: in practice, feature-probing via terminfo is often wrong.  There's not
many backwards-incompatible features that need this; for the ones that do
we can still use terminfo capabilities but query the terminal via XTGETTCAP
directly, skipping the file (which may not exist on the same system as
the terminal).

---

Get rid of terminfo. If anyone finds a $TERM where we need different behavior,
we can hardcode that into fish.

* Allow to override this with `fish_features=no-ignore-terminfo fish`
  Not sure if we should document this, since it's supposed to be removed soon,
  and if someone needs this (which we don't expect), we'd like to know.
  * This is supported on a best-effort basis; it doesn't match the previous
    behavior exactly.  For simplicity of implementation, it will not change
    the fact that we now:
    * use parm_left_cursor (CSI Ps D) instead of  cursor_left (CSI D) if
      terminfo claims the former is supported
    * no longer support eat_newline_glitch, which seems no longer present
      on today's ConEmu and ConHost
* Tested as described in https://github.com/fish-shell/fish-shell/pull/11345#discussion_r2030121580
* add `man fish-terminal-compatibility` to state our assumptions.
  This could help terminal emulator developers.
* assume `parm_up_cursor` is supported if the terminal supports XTGETTCAP
* Extract all control sequences to src/terminal_command.rs.
* Remove the "\x1b(B" prefix from EXIT_ATTRIBUTE_MODE. I doubt it's really
  needed.
* assume it's generally okay to output 256 colors
  Things have improved since commit 3669805627 (Improve compatibility with
  0-16 color terminals., 2016-07-21).
  Apparently almost every actively developed terminal supports it, including
  Terminal.app and GNU screen.
  * That is, we default `fish_term256` to true and keep it only as a way to
    opt out of the the full 256 palette (e.g. switching to the 16-color
    palette).
    * `TERM=xterm-16color` has the same opt-out effect.
* `TERM` is generally ignored but add back basic compatiblity by turning
  off color for "ansi-m", "linux-m" and "xterm-mono"; these are probably
  not set accidentally.
* Since `TERM` is (mostly) ignored, we don't need the magic "xterm" in
  tests. Unset it instead.
* Note that our pexpect tests used a dumb terminal because:
  1. it makes fish do a full redraw of the commandline everytime, making it
     easier to write assertions.
  2. it disables all control sequences for colors, etc, which we usually
     don't want to test explicitly.
  I don't think TERM=dumb has any other use, so it would be better
  to print escape sequences unconditionally, and strip them in
  the test driver (leaving this for later, since it's a bit more involved).

Closes #11344
Closes #11345
2025-04-11 15:11:22 +02:00
Johannes Altmanninger
ad6d7137b8 Simplify selection between "CSI A" and "CSI Ps A"
I think multi is always shorter unless we're only moving by one cell.

Also, we want to simplify this for a following commit where we no longer
check if it's supported.
2025-04-11 15:11:22 +02:00
Johannes Altmanninger
f2e28fa6c4 Drop unnecessary use of is_dumb()
"infocmp dumb" shows that this is redundant.
2025-04-11 15:11:22 +02:00
Johannes Altmanninger
ef7bd4f13a Filter all control sequences but colors and cursor movement in tests
There are more escape sequences that can affect terminal state; let's allow
only the ones that are known-safe.
2025-04-11 15:11:22 +02:00
Johannes Altmanninger
f1aba8e3cd Remove unused terminfo capabilities 2025-04-11 15:11:22 +02:00
Johannes Altmanninger
854e13048b Stop supporting terminals without eat_newline_glitch
This reverts commit 58347d494a (update PROMPT_SP heuristic, 2016-12-23)

If we write the last column of a line:

	printf %0"$COLUMNS"d 0; sleep 3

most terminals will *not* move the cursor to the next line.

This behavior is indicated by the terminfo's xenl (AKA xen or
eat_newline_glitch) boolean capability.

We originally added checks for this capability because ConEmu and Windows
ConHost did not implement it, but they do now.

Also, as mentioned in
https://github.com/fish-shell/fish-shell/pull/11342#issuecomment-2769979520,
we're not aware of any present-day terminal that does not have this behavior,
but the value advertised by terminfo is sometimes wrong.

Let's get rid of this for now. A following commit will document that we
require this behavior.
2025-04-11 15:11:22 +02:00
Johannes Altmanninger
0ca08ce81d Buffer OSC 0 terminal title writing 2025-04-11 15:11:22 +02:00
Johannes Altmanninger
15379ae409 Ignore values XTGETTCAP values for indn/cuu
I don't think we want to support terminals that implement XTGETTCAP but for
some reason don't use CSI Ps S for scroll forward; that would be a needless
complication. 
Let's make ctrl-l / scrollback-push fail hard if a terminal does this.
Confusingly kitty and foot use different response formats, but happily we
no longer care.

An upcoming commit will document that we require the CSI Ps S style.
2025-04-11 15:11:22 +02:00
Johannes Altmanninger
7d5fb623c6 Remove unused variable 2025-04-11 15:11:22 +02:00
Johannes Altmanninger
c0ad15fbc5 Fix missing repaint when TERM changes
E.g.

	set TERM xterm-16color
	set TERM xterm-mono
2025-04-11 15:11:22 +02:00
Johannes Altmanninger
926566bad5 Remove unused parameter 2025-04-11 15:11:22 +02:00
Johannes Altmanninger
aa825c40da Fix RST syntax 2025-04-11 15:11:22 +02:00
Johannes Altmanninger
423a5a20ba Remove dead code checking for uninitialized terminal
See 75f7cda6ab (Add xterm-256color fallback, 2024-01-28).
2025-04-11 15:11:22 +02:00
Johannes Altmanninger
594daf8f64 Use internal RST link for linking to #building 2025-04-11 15:11:22 +02:00
Johannes Altmanninger
d3b4a33ba4 Remove intrusive Screen::scoped_buffer
scoped_buffer borrows the screen to be able to flush buffers on drop.  This is
a bit intrusive (see also 29ae571afa (Make scoped_push nicer, 2024-12-28)).

Not sure what's the best solution -- probably we should always pass the
outputter as parameter, removing the field.

For now let's at least contain the effects of this.
2025-04-11 15:11:22 +02:00
Johannes Altmanninger
ce01b16402 Fix typo 2025-04-11 15:11:22 +02:00
Johannes Altmanninger
39aa478108 Extract unwrapping for buffer-writes that are assumed to not fail 2025-04-11 15:11:22 +02:00
Johannes Altmanninger
9206a91701 Improve BufferedOuputter ergonomics
Factor some redundant logic from call sites into the constructor, even if
it's exactly what the constructor actually needs.
2025-04-11 15:11:22 +02:00
Johannes Altmanninger
af3b49bf9c Fix kill-selection crash when selection start is out-of-bounds
This part of the code could use some love; when we happen to clear the
selected text, we should end the selection.

But that's not how it works today. This is fine for Vi mode, because Vi
mode never deletes in visual mode.

Let's fix the crash for now.

Fixes #11367
2025-04-11 15:11:22 +02:00
Daniel Rainer
ad0e2c17ac Fix profiling time log
`Duration::as_nanos()`
"Returns the total number of nanoseconds contained by this Duration."
https://doc.rust-lang.org/core/time/struct.Duration.html#method.as_nanos

Because we are indicating the time in milliseconds, we cannot use
`Duration::subsec_nanos()` but we need to manually get the whole duration in
nanoseconds and subtract the duration in milliseconds to get the fractional
part.
2025-04-10 19:43:19 +02:00
exploide
83963287d6 completions(resolvectl): updated to newer version 2025-04-09 19:11:59 +08:00
Fabian Boehm
d95b662542 docs: Fix string-match glob examples
`?` no longer is a wildcard.

See #11361

(cherry picked from commit eb4a0b2560)
2025-04-08 17:14:12 +02:00
Fabian Boehm
eb4a0b2560 docs: Fix string-match glob examples
`?` no longer is a wildcard.

See #11361
2025-04-08 17:13:18 +02:00
Johannes Altmanninger
d88d3122c8 Fix crash when history pager is closed before search
With

	bind ctrl-r 'sleep 1' history-pager

typing ctrl-r,escape crashes fish in the history pager completion callback,
because the history pager has already been closed.

Prior to 55fd43d86c (Port reader, 2023-12-22), the completion callback
would not crash open a pager -- which causes weird races with the
user input.

Apparently this crash as been triggered by running "playwright",
and -- while that's running typing ctrl-r ligh escape.
Those key strokes were received while the kitty keyboard protocol
was active, possibly a race.

Fixes #11355

(cherry picked from commit c94e30293a)
2025-04-04 14:37:03 +02:00
Johannes Altmanninger
c94e30293a Fix crash when history pager is closed before search
With

	bind ctrl-r 'sleep 1' history-pager

typing ctrl-r,escape crashes fish in the history pager completion callback,
because the history pager has already been closed.

Prior to 55fd43d86c (Port reader, 2023-12-22), the completion callback
would not crash open a pager -- which causes weird races with the
user input.

Apparently this crash as been triggered by running "playwright",
and -- while that's running typing ctrl-r ligh escape.
Those key strokes were received while the kitty keyboard protocol
was active, possibly a race.

Fixes #11355
2025-04-04 14:34:11 +02:00
Bec Donald-Wilson
68a8ab9667 Fix alt-right binding 2025-04-03 02:01:49 +02:00
Johannes Altmanninger
88e724384c pexpects/history.py: reduce surprise in env setup
This "SpawnedProc(env=os.environ.copy())" seems redundant but it's not, since
the default argument is initialized (with a copy of env) at module-load time.
Reshuffle the code to make it look less odd.

While at it, fix some invalid escape sequence warnings.
2025-04-03 00:51:35 +02:00
Johannes Altmanninger
50a6e486a5 Allow explicit shift modifier for non-ASCII letters, fix capslock behavior
We canonicalize "ctrl-shift-i" to "ctrl-I".
Both when deciphering this notation (as given to builtin bind),
and when receiving it as a key event ("\e[105;73;6u")

This has problems:

A. Our bind notation canonicalization only works for 26 English letters.
   For example, "ctrl-shift-ä" is not supported -- only "ctrl-Ä" is.
   We could try to fix that but this depends on the keyboard layout.
   For example "bind alt-shift-=" and "bind alt-+" are equivalent on a "us"
   layout but not on a "de" layout.
B. While capslock is on, the key event won't include a shifted key ("73" here).
   This is due a quirk in the kitty keyboard protocol[^1].  This means that
   fish_key_reader's canonicalization doesn't work (unless we call toupper()
   ourselves).

I think we want to support both notations.

It's recommended to match all of these (in this order) when pressing
"ctrl-shift-i".

	1. bind ctrl-shift-i do-something
	2. bind ctrl-shift-I do-something
	3. bind ctrl-I do-something
	4. bind ctrl-i do-something

Support 1 and 3 for now, allowing both bindings to coexist. No priorities
for now. This solves problem A, and -- if we take care to use the explicit
shift notation -- problem B.

For keys that are not affected by capslock, problem B does not apply.  In this
case, recommend the shifted notation ("alt-+" instead of "alt-shift-=")
since that seems more intuitive.
Though if we prioritized "alt-shift-=" over "alt-+" as per the recommendation,
that's an argument against the shifted key.

Example output for some key events:

	$ fish_key_reader -cV
	# decoded from: \e\[61:43\;4u
	bind alt-+ 'do something' # recommended notation
	bind alt-shift-= 'do something'
	# decoded from: \e\[61:43\;68u
	bind alt-+ 'do something' # recommended notation
	bind alt-shift-= 'do something'

	# decoded from: \e\[105:73\;6u
	bind ctrl-I 'do something'
	bind ctrl-shift-i 'do something' # recommended notation
	# decoded from: \e\[105\;70u
	bind ctrl-shift-i 'do something'

Due to the capslock quirk, the last one has only one matching representation
since there is no shifted key.  We could decide to match ctrl-shift-i events
(that don't have a shifted key) to ctrl-I bindings (for ASCII letters), as
before this patch. But that case is very rare, it should only happen when
capslock is on, so it's probably not even a breaking change.

The other way round is supported -- we do match ctrl-I events (typically
with shifted key) to ctrl-shift-i bindings (but only for ASCII letters).
This is mainly for backwards compatibility.

Also note that, bindings without other modifiers currently need to use the
shifted key (like "Ä", not "shift-ä"), since we still get a legacy encoding,
until we request "Report all keys as escape codes".

[^1]: <https://github.com/kovidgoyal/kitty/issues/8493>
2025-04-03 00:51:35 +02:00
Johannes Altmanninger
7f25d865a9 Stop accepting "bind shift-A"
This notation doesn't make sense, use either A or shift-a.  We accept it
for ASCII letters only -- things like "bind shift-!" or "bind shift-Ä"
do not work as of today, we don't tolerate extra shift modifiers yet.
So let's remove it for consistency.

Note that the next commit will allow the shift-A notation again, but it will
not match shift-a events.
2025-04-03 00:51:35 +02:00
Johannes Altmanninger
855a1f702e Extract KeyEvent type
The be used in the grandchild commit.
2025-04-03 00:51:35 +02:00
Johannes Altmanninger
fabbbba037 Extract function for creating key event with modifiers 2025-04-03 00:51:35 +02:00
Johannes Altmanninger
2731c4f8c8 Fix compiler warning when building with installable support 2025-04-03 00:51:35 +02:00
Fabian Boehm
a7f717c59c CHANGELOG for 4.0.2 2025-04-02 17:06:55 +02:00
Fabian Boehm
ba49981f17 tests: Just check that the version starts with a digit
Our versions look like

4.0.0
4.0b1
4.0.1-535-abfef-dirty

But packagers may want to add more information here, and we don't
really care. Note that we no longer ever set the version to "unknown"
since 5abd0e46f5.

Supersedes #11173

(cherry picked from commit 411a396fa9)
2025-04-02 17:03:57 +02:00
Farhood Etaati
05ae55b172 Adds git subtree completion
Closes #11063

(cherry picked from commit 48306409ef)
2025-04-02 17:03:57 +02:00
Ilya Grigoriev
b5877ebe44 jj completions: use dynamic completions by default, also fix
This uses jj's dynamic completions when possible.

This avoids an annoying problem. After 04a4e5c4, jj's dynamic
completions (see the second paragraph of
<https://jj-vcs.github.io/jj/latest/install-and-setup/#command-line-completion>)
do not work very well in fish if the user puts `COMPLETE=fish jj |
source` in their `~/.config/fish/config.fish`. When the user types `jj
<TAB>`, they are instead overridden by fish's built-in non-dynamic
completions.

The difference is subtle. One problem I saw is that `jj new <TAB>` works
as expected (and shows revisions) while `jj new -A <TAB>` becomes broken
(and shows files).

If the user puts `COMPLETE=fish jj | source` in
`~/.config/fish/completions/jj.fish` there is no problem. However, users
might be confused if they run `COMPLETE=fish jj | source` or put it in
their config and it works in a broken fashion. I certainly was.

Meanwhile, I checked that if the user has `jj completion fish | source`
in their `config.fish`, executing `COMPLETE=fish jj
__this_command_does_not_exist | source` afterwards still works
correctly.

Let me know if there's a better approach to this problem.

(cherry picked from commit 932010cd04)
2025-04-02 17:03:57 +02:00
Clément Martinez
f9a03215b8 Add wlr-randr completions
(cherry picked from commit ea8e122fad)
2025-04-02 17:03:57 +02:00
memchr
ff0980c4c1 completions/systemd-analyze: add new options and subcommands
options:
- instance
- image
- image-policy
- tldr
- unit
- table
- no-legend
- detailed
- scale-svg
- malloc

subcommands:
- filesystems
- compare-versions
- inspect-elf
- fdstore
- has-tpm2
- pcrs
- srk
- architectures
- smbios11

fix a typo in timespan completion

Signed-off-by: memchr <memchr@proton.me>
(cherry picked from commit 3744c02a01)
2025-04-02 17:03:57 +02:00
memchr
1a58d3f08b completions/cryptsetup: complete device mapping names
The commands 'close', 'resize', and 'status' each take 'name' as their solo argument.

Signed-off-by: memchr <memchr@proton.me>
(cherry picked from commit 5012bcb976)
2025-04-02 17:03:57 +02:00
memchr
b71027f622 completions/git: add --filter option
supported subcommands:
- clone
- fetch
- submodule update
- rev-list

(cherry picked from commit 795d6b6c40)
2025-04-02 17:03:57 +02:00
Jonathan Palardy
84c03c6f26 completions/git: Added autostash option to git merge
(cherry picked from commit 269ed5ddf4)
2025-04-02 17:03:57 +02:00
memchr
bf455bc316 completions/btrfs: add new options and commands
Also add completion for balance filters

(cherry picked from commit 95b93c6bff)
2025-04-02 17:03:57 +02:00
Johannes Altmanninger
6af0378916 Don't insert text from keys like super-i
While at it, use declaration order for modifiers.

(cherry picked from commit 35ae0bf1f2)
2025-04-02 17:03:57 +02:00
Fabian Boehm
de154065fe fish_print_hg_root: Don't break if $PWD includes newlines
Fixes #11348

(cherry picked from commit 5e25cdaa6f)
2025-04-02 17:01:25 +02:00
Fabian Boehm
459e9b7847 completions/cargo: Speed up
This does two things:

- it stops completing cargo- tools because `cargo --list` already
includes them. This speeds up loading especially with a long $PATH
- it stops using `cargo search` for `cargo add` and install.
  this removes a network call, which may be unexpected and can take a
  long time

Fixes #11347

(cherry picked from commit 18371fbd4e)
2025-04-02 17:00:30 +02:00
Fabian Boehm
5e25cdaa6f fish_print_hg_root: Don't break if $PWD includes newlines
Fixes #11348
2025-04-02 16:59:21 +02:00
Fabian Boehm
9c5be2a2d8 completions/cargo: Complete -Z options 2025-04-02 16:58:47 +02:00
Fabian Boehm
18371fbd4e completions/cargo: Speed up
This does two things:

- it stops completing cargo- tools because `cargo --list` already
includes them. This speeds up loading especially with a long $PATH
- it stops using `cargo search` for `cargo add` and install.
  this removes a network call, which may be unexpected and can take a
  long time

Fixes #11347
2025-04-02 16:57:32 +02:00
Johannes Altmanninger
d234ebf484 Fix fuzzy matching for multi-character lowercase sequences
Same as 8668ce336c (Fix common::wcscasecmp() for multi-byte lowercase strings,
2023-05-02).
2025-04-02 02:02:12 +02:00
Johannes Altmanninger
81f1ab75d0 Fix clippy warning about needlessly narrow parameter type 2025-04-02 01:19:13 +02:00
Johannes Altmanninger
daa692a20b Remove unnecessary escaping for # and ~ inside key name tokens
While at it, don't escape "?", I don't know why 68e167d576 (f-k-r should
use the user's locale, 2016-06-29) did that. Question mark is only special
in combination with redirections.
2025-04-02 01:05:51 +02:00
Johannes Altmanninger
892c970bfa webconfig: remove legacy and raw key name parser for now
This parser was pretty nice but it has some issues with the new syntax.
It's not really needed when most bindings use the new syntax.

Let's remove it altogether.
2025-04-02 01:05:51 +02:00
Johannes Altmanninger
defd041863 webconfig: clarify invariant
We're splitting at most twice, so there can only be three or fewer parts.
2025-04-02 01:05:51 +02:00
Johannes Altmanninger
d4082893ae completions/bind: complete super modifier 2025-04-02 01:05:51 +02:00
Johannes Altmanninger
fb2d427a45 Remove "bind -k" terminfo key names, update "bind --key-names"
I don't think there's a relevant terminal where the "bind -k" notation is
still needed. The remaining reason to keep it is backwards compatibility.

But "bind -k" is already subtly broken on terminals that implement either
of modifyOtherKeys, application keypad mode or the kitty keyboard protocol,
since those alter the byte sequences (see #11278).

Having it randomly not work might do more harm than good. Remove it.

This is meant go into 4.1, which means that users who switch back and forth
between 4.1 and 4.0 can already use the new notation.

If someone wants to use the bind config for a wider range of versions they
could use "bind -k 2>/dev/null" etc.

While at it, use the new key names in "bind --key-names", and sort it like
we do in "bind --function-names".

Closes #11342
2025-04-02 01:05:51 +02:00
Johannes Altmanninger
e9d1cdfe87 Extract constant for the number of function keys
Switch to fish_wcstoul because we want the constant to be unsigned.
It's u32 because most callers of function_key() want that.
2025-04-02 01:01:59 +02:00
Johannes Altmanninger
26ca12d5af docs/bind.rst: add missing named keys 2025-04-02 00:53:48 +02:00
Johannes Altmanninger
3fe6d49224 Silence unused-imports warning when not installable 2025-04-01 17:35:58 +02:00
Johannes Altmanninger
2719ae443b Silence unexpected_cfgs error about unknown cygwin target
Extract our own cfg value, to avoid noisy warnings like:

	warning: unexpected `cfg` condition value: `cygwin`
	  --> src/fallback.rs:78:23
	   |
	78 |             #[cfg(not(target_os = "cygwin"))]
	   |                       ^^^^^^^^^^^^^^^^^^^^
	   |

The cygwin target will be added to Rust 1.86, so we can get rid of this
after some time.
2025-04-01 17:30:15 +02:00
王宇逸
ec1c2473c2 Fix tty timestamps handling
Closes #11238
2025-04-01 17:15:48 +02:00
王宇逸
bbf678e718 Reduce warnings when posix_spawn disabled. 2025-04-01 17:15:48 +02:00
王宇逸
e21eea6ac6 Reduce warnings on is_console_session 2025-04-01 17:15:48 +02:00
王宇逸
99fdcd725b Disable test_topic_monitor_torture on cygwin 2025-04-01 17:15:48 +02:00
王宇逸
b35825e618 Fix wc <-> mb conversion 2025-04-01 17:15:48 +02:00
王宇逸
4eceabeaad Fix path env on cygwin when cross compiling from Windows 2025-04-01 17:15:48 +02:00
王宇逸
2e89f37446 Fix wcwidth on cygwin 2025-04-01 17:15:48 +02:00
Johannes Altmanninger
f88470aa3c Address some unused_must_use warnings for ControlFlow
As seen on nightly Rust.
2025-04-01 17:15:48 +02:00
Johannes Altmanninger
415da8fc3b Remove obsolete st \e[P binding for delete
Since we request application keypad mode, st sends \e[3~ instead which we
already decode.
2025-04-01 17:00:48 +02:00
Johannes Altmanninger
18e6074aa7 Fix regression causing fish_key_reader to not request modifyOtherKeys
If the kitty protcol is not supported, we still want to request modifyOtherKeys
and application keypad mode. Since 2d234bb676 (Only request keyboard protocols
once we know if kitty kbd is supported, 2025-01-26), fish_key_reader fails
to turn on those modes if the kitty keyboard protocol is not supported.
2025-04-01 17:00:48 +02:00
Johannes Altmanninger
4c212776bf Remove obsolete st \e[Z binding for shift-tab
We already decode this to shift-tab (not to mention that up-line was the
wrong action, no?).
2025-04-01 17:00:48 +02:00
Hameer Abbasi
bf65b9e3a7 Change gettext paths to be relocatable (#11195)
Move config path logic into its own module and use it for locale as well.
2025-03-30 19:48:47 +02:00
Fabian Boehm
205d80c75a findrust: Simplify (#11328)
FindRust is too clever by half. It tries to do rustup's job for it.

See b38551dde9 for how that can break.

So we simplify it, and only let it check three things:

- Where's rustc? Look in $PATH and ~/.cargo/bin
- Where's cargo? Look in $PATH and ~/.cargo/bin
- What is the rust target (because we pass it explicitly)?

If any of these aren't that simple, we'll ask the user to tell us,
by setting Rust_COMPILER, Rust_CARGO or Rust_CARGO_TARGET.

None of the other things are helpful to us - we do not support windows
or whatever a "unikraft" is, and if the rust version doesn't work
it'll print its own error.

We could add a rustc version check, but that will become less and less
useful because rustc versions since 1.56 (released October 2021) will check rust-version in
Cargo.toml. So even at this point it's only pretty old rust versions already.
2025-03-30 19:47:09 +02:00
Fabian Boehm
446f1344fc completions/patch: Put CYGWIN code first
Just so we don't error with non-0
2025-03-30 19:46:01 +02:00
Daniel Rainer
460b93a5bc Rebuild on changes relevant to build artifacts
If anything changes in one of the listed directories or files, trigger a
rebuild.

Rebuilds are needed to update the version info built into the binaries.
The version info includes an abbreviated git commit hash, as well as information
about whether the repo was in a dirty state (uncommitted changes) when building.
Changes to files not explicitly listed will not trigger a rebuild, so to get
accurate version info upon such changes (also when checking out a different
commit which does not differ in any of the listed files), a rebuild needs to be
triggered manually (e.g. via `cargo clean` or `touch build.rs`).
2025-03-30 19:43:04 +02:00
Fabian Boehm
6dcead7be5 docs: Make --wraps clearer
Fixes #11317
2025-03-30 19:42:00 +02:00
Johannes Altmanninger
35ae0bf1f2 Don't insert text from keys like super-i
While at it, use declaration order for modifiers.
2025-03-30 16:00:38 +02:00
memchr
95b93c6bff completions/btrfs: add new options and commands
Also add completion for balance filters
2025-03-29 13:47:38 +01:00
Fabian Boehm
2dedff2200 tests/abbrs: Disable check that fails on CI
It appears we're getting the correct output, but in the wrong order,
so pexpect doesn't filter it correctly:

> \r\n\x1b]133;C;cmdline_url=echo%20bar\x07bar\r\n\x1b]133;D;0\x07\x1b[?25h⏎                                                                              \r⏎ \r\rprompt 39>\x1b[?2004h

That `\x07bar` should be the \a that marks the end of the escape
sequence, followed by the actual "bar", followed by sequences marking
the end of output...
2025-03-29 13:21:31 +01:00
Jonathan Palardy
269ed5ddf4 completions/git: Added autostash option to git merge 2025-03-29 13:11:35 +01:00
memchr
795d6b6c40 completions/git: add --filter option
supported subcommands:
- clone
- fetch
- submodule update
- rev-list
2025-03-29 13:10:59 +01:00
Fabian Boehm
6ead168c82 docs: Remove "just"/"simply" weasel words
Text like "simply do" or "just press" is patronizing and unnecessary.
The prose is nicer if it's removed, and in some cases other words are
more specific.

Something like "we'll pretend your prompt is just a ``>``" can stay.
2025-03-28 20:12:58 +01:00
Fabian Boehm
b2aaf1db52 Rebuild if src changed
From the cargo docs (https://doc.rust-lang.org/cargo/reference/build-scripts.html#change-detection):

> By default, it takes a conservative approach of always re-running the build script if any file within the package is changed (or the list of files controlled by the exclude and include fields). For most cases, this is not a good choice, so it is recommended that every build script emit at least one of the rerun-if instructions (described below). If these are emitted, then Cargo will only re-run the script if the given value has changed

So, since we emit rerun-if-path-changed, we need to emit *all* the paths.
Failing to do this shows up most visibly as an outdated git version.

Fixes #11332
2025-03-28 18:29:23 +01:00
Johannes Altmanninger
f127323c33 Prevent commandline modification inside abbreviation callbacks
Consider command line modifications triggered from fish script via abbreviation
expansion:

	function my-abbr-func
	    commandline -r ""
	    echo expanded
	end
	abbr -a foo --function my-abbr-func

Prior to commit 8386088b3d (Update commandline state changes eagerly as well,
2024-04-11), we'd silently ignore the command line modification.
This is because the abbreviation machinery runs something similar to

	if my-abbr-func
	    commandline -rt expanded
	end

except without running "apply_commandline_state_changes()" after
"my-abbr-func", so the «commandline -r ""» update is lost.

Commit 8386088b3d applies the commandline change immediately in the abbrevation
function callback, invalidating abbrevation-expansion state.

The abbreviation design does not tell us what should happen here.  Let's ignore
commandline modifications for now. This mostly matches historical behavior.

Unlike historical behavior we also ignore modifications if the callback fails:

	function my-abbr-func
	    commandline -r ""
	    false
	end

Remove the resulting dead code in editable_line.

See #11324

(cherry picked from commit 11c7310f17)
2025-03-28 13:05:22 +01:00
Fabian Boehm
3fc245d829 docs: Readd bind -k to the docs
Fixes #11329

(cherry picked from commit d88f5ddbaf)
2025-03-28 12:59:44 +01:00
Johannes Altmanninger
11c7310f17 Prevent commandline modification inside abbreviation callbacks
Consider command line modifications triggered from fish script via abbreviation
expansion:

	function my-abbr-func
	    commandline -r ""
	    echo expanded
	end
	abbr -a foo --function my-abbr-func

Prior to commit 8386088b3d (Update commandline state changes eagerly as well,
2024-04-11), we'd silently ignore the command line modification.
This is because the abbreviation machinery runs something similar to

	if my-abbr-func
	    commandline -rt expanded
	end

except without running "apply_commandline_state_changes()" after
"my-abbr-func", so the «commandline -r ""» update is lost.

Commit 8386088b3d applies the commandline change immediately in the abbrevation
function callback, invalidating abbrevation-expansion state.

The abbreviation design does not tell us what should happen here.  Let's ignore
commandline modifications for now. This mostly matches historical behavior.

Unlike historical behavior we also ignore modifications if the callback fails:

	function my-abbr-func
	    commandline -r ""
	    false
	end

Remove the resulting dead code in editable_line.

See #11324
2025-03-28 12:58:15 +01:00
Fabian Boehm
d88f5ddbaf docs: Readd bind -k to the docs
Fixes #11329
2025-03-27 15:56:09 +01:00
Fabian Boehm
89b62a56e1 editable_line: guard against empty text
there's got to be a nicer way to do this

Fixes #11324
2025-03-26 19:23:17 +01:00
Johannes Altmanninger
542793a534 completions/git: fix arg completion for third-party git commands, again
Commit 50e595503e (completions/git: fix completions for third-party git
commands, 2025-03-03) wasn't quite right, as we can see in the linked
reproduction:

	$ fish_trace=1 complete -C 'git machete add --onto '
	----> complete -C git-machete\ add\n--onto\

The recursive completion invocation contains a spurious newline, which means
that "--onto" is the command name.  The newline is produced by "string escape
-- add --onto" inside a command substitution.

Fix this by interpreting newlines as list separators, and then joining
by spaces.

Fixes #11319

(cherry picked from commit 360cfdb7ae)
2025-03-25 11:16:38 +01:00
Johannes Altmanninger
360cfdb7ae completions/git: fix arg completion for third-party git commands, again
Commit 50e595503e (completions/git: fix completions for third-party git
commands, 2025-03-03) wasn't quite right, as we can see in the linked
reproduction:

	$ fish_trace=1 complete -C 'git machete add --onto '
	----> complete -C git-machete\ add\n--onto\

The recursive completion invocation contains a spurious newline, which means
that "--onto" is the command name.  The newline is produced by "string escape
-- add --onto" inside a command substitution.

Fix this by interpreting newlines as list separators, and then joining
by spaces.

Fixes #11319
2025-03-25 11:16:18 +01:00
memchr
5012bcb976 completions/cryptsetup: complete device mapping names
The commands 'close', 'resize', and 'status' each take 'name' as their solo argument.

Signed-off-by: memchr <memchr@proton.me>
2025-03-24 18:43:38 +01:00
memchr
3744c02a01 completions/systemd-analyze: add new options and subcommands
options:
- instance
- image
- image-policy
- tldr
- unit
- table
- no-legend
- detailed
- scale-svg
- malloc

subcommands:
- filesystems
- compare-versions
- inspect-elf
- fdstore
- has-tpm2
- pcrs
- srk
- architectures
- smbios11

fix a typo in timespan completion

Signed-off-by: memchr <memchr@proton.me>
2025-03-24 18:43:30 +01:00
5225225
149386a593 mention psub in the error for "Invalid redirection target"
Currently fish errors out with

```fish
fish: Invalid redirection target:
rev <(ls)
    ^~~~^
```

This isn't very helpful in telling the user what they could be doing instead:
`rev (ls | psub)`.

Closes #11287
2025-03-22 14:12:54 +01:00
Johannes Altmanninger
c2121b5a8d Move issue template following GitHub breaking change
We can no longer have a single template that is always inserted. Instead
the web UI shows a menu allowing to select between one of our templates and
a blank one.
2025-03-22 14:09:39 +01:00
Benjamin A. Beasley
a5adb362b0 Update lru to 0.13.0 2025-03-22 13:33:18 +01:00
Clément Martinez
ea8e122fad Add wlr-randr completions 2025-03-22 13:06:01 +01:00
Johannes Altmanninger
66115490d8 Use the cache directory owner for cache entries
Commit f086bc9564 (Maintain ownership when rewriting universal variables
file, 2015-09-26) fixed an issue where "sudo -E fish" would create root-owned
~/.config/fish/fish_variables that break the users's shell.

A simlar issue exists for files in ~/.cache/fish; fix that.

Note that ~/.cache/fish is currently created on first run when we generate
completions from manpages.

See the issue described in #11292
2025-03-21 10:41:39 +01:00
James Falcon
0dbfb4ccb1 Remove directory name prefix in truncated completions
Sometimes, the dirname of a completion is much longer than the basename.

When the dirname is the same for many completions, a long common dirname
prefix makes it hard to see the interesting differences in the basenames.

Fix this by collapsing the dirname prefix to "…/".

In future, we should find a generic way to collapse completions that don't
contain slashes.

Closes #8618
Closes #11250
2025-03-21 00:53:06 +01:00
Johannes Altmanninger
17c072b4bf Fix command highlighting applying underline to trailing spaces
We incorrectly apply highlighting to trailing spaces that follow a command
or argument. This surfaces when the highlighting includes underline, which
is visible even on space characters.

Fix this by and have Claude add a unit test.

Co-Authored-By: Claude <noreply@anthropic.com>

Fixes #11265
2025-03-21 00:40:33 +01:00
Fabian Boehm
e8bd45d760 tests: Remove the need to pass $FISH_SOURCE_DIR
This is only used in check-translations, where we can just use a
relative path from the test script
2025-03-19 18:26:11 +01:00
Johannes Altmanninger
18c231de29 Fix concurrent setlocale() in string escape tests
In our C++ implementation, these tests were run serially.  As pointed out in
https://github.com/fish-shell/fish-shell/issues/11254#issuecomment-2735623229
we run them in parallel now, which means that one test could be changing
the global locale used by another.

In theory this could be fine because all tests are setting setting the
global locale to the same thing but the existence of a lock suggests that
setlocale() is not guaranteed to be atomic, so it's possible that another
thread uses a temporarily-invalid locale.

Fixes #11254

(cherry picked from commit 1d78c8bd42)
2025-03-19 09:46:12 +01:00
Johannes Altmanninger
1d78c8bd42 Fix concurrent setlocale() in string escape tests
In our C++ implementation, these tests were run serially.  As pointed out in
https://github.com/fish-shell/fish-shell/issues/11254#issuecomment-2735623229
we run them in parallel now, which means that one test could be changing
the global locale used by another.

In theory this could be fine because all tests are setting setting the
global locale to the same thing but the existence of a lock suggests that
setlocale() is not guaranteed to be atomic, so it's possible that another
thread uses a temporarily-invalid locale.

Fixes #11254
2025-03-19 09:45:51 +01:00
Johannes Altmanninger
8e78857836 Fix Vi mode delete key bindings while numlock is active
Commit 8bf8b10f68 (Extended & human-friendly keys, 2024-03-30)
add bindings that obsolete the  terminfo-based `bind -k` invocations.

The `bind -k` variants were still left around[^*]. Unfortunately it forgot to
add the new syntax for some special keys in Vi mode.  This leads to issues if
a terminal that supports the kitty keyboard protocol sends an encoding that
differs from the traditional one.  As far as I can tell, this happens when
capslock or numlock is active.  Let's add the new key names and consistently
mark `bind -k` invocations as deprecated.

Fixes #11303

[^*]: Support for `bind -k` will probably be removed in a future release -
it leads to issues like https://github.com/fish-shell/fish-shell/issues/11278
where it's better to fail early.

(cherry picked from commit 733f704267)
2025-03-19 09:27:29 +01:00
Johannes Altmanninger
733f704267 Fix Vi mode delete key bindings while numlock is active
Commit 8bf8b10f68 (Extended & human-friendly keys, 2024-03-30)
add bindings that obsolete the  terminfo-based `bind -k` invocations.

The `bind -k` variants were still left around[^*]. Unfortunately it forgot to
add the new syntax for some special keys in Vi mode.  This leads to issues if
a terminal that supports the kitty keyboard protocol sends an encoding that
differs from the traditional one.  As far as I can tell, this happens when
capslock or numlock is active.  Let's add the new key names and consistently
mark `bind -k` invocations as deprecated.

Fixes #11303

[^*]: Support for `bind -k` will probably be removed in a future release -
it leads to issues like https://github.com/fish-shell/fish-shell/issues/11278
where it's better to fail early.
2025-03-19 09:23:07 +01:00
kekeimiku
841687a1af iOS initial support
Usage:

	IPHONEOS_DEPLOYMENT_TARGET="13.1 cargo build --target aarch64-apple-ios --release
	codesign -d -s - --entitlements build_tools/ios_entitlements.xml target/aarch64-apple-ios/release/fish

Closes #10993
2025-03-18 22:25:55 +01:00
5225225
039df1c7c7 Fix all current rustdoc warnings (apart from mentioning private items) 2025-03-18 22:25:24 +01:00
Fabian Boehm
c7efbf590e function: Also error for read-only var in positional arg
We have this hack where any positional arguments are taken as argument
names if "--argument-names" is given, and that didn't check for
read-only variables.

Fixes #11295

(cherry picked from commit d203ee4d53)
2025-03-17 19:55:25 +01:00
Fabian Boehm
d203ee4d53 function: Also error for read-only var in positional arg
We have this hack where any positional arguments are taken as argument
names if "--argument-names" is given, and that didn't check for
read-only variables.

Fixes #11295
2025-03-17 19:55:14 +01:00
Ilya Grigoriev
932010cd04 jj completions: use dynamic completions by default, also fix
This uses jj's dynamic completions when possible.

This avoids an annoying problem. After 04a4e5c4, jj's dynamic
completions (see the second paragraph of
<https://jj-vcs.github.io/jj/latest/install-and-setup/#command-line-completion>)
do not work very well in fish if the user puts `COMPLETE=fish jj |
source` in their `~/.config/fish/config.fish`. When the user types `jj
<TAB>`, they are instead overridden by fish's built-in non-dynamic
completions.

The difference is subtle. One problem I saw is that `jj new <TAB>` works
as expected (and shows revisions) while `jj new -A <TAB>` becomes broken
(and shows files).

If the user puts `COMPLETE=fish jj | source` in
`~/.config/fish/completions/jj.fish` there is no problem. However, users
might be confused if they run `COMPLETE=fish jj | source` or put it in
their config and it works in a broken fashion. I certainly was.

Meanwhile, I checked that if the user has `jj completion fish | source`
in their `config.fish`, executing `COMPLETE=fish jj
__this_command_does_not_exist | source` afterwards still works
correctly.

Let me know if there's a better approach to this problem.
2025-03-17 19:06:48 +01:00
Fabian Boehm
5771085280 CHANGELOG 2025-03-16 19:15:28 +01:00
Fabian Boehm
76d2419228 Downgrade $TERM warnings to a term-support flog
The chances that xterm-256color breaks anything are miniscule.

In the features we use, there are basically no differences,
especially when you consider that we decode keys independently.

E.g. tmux-256color has differences, but they are either just taste
questions (xterm's clear_screen will also clear scrollback),
or they're just... not actually different?

Terminfo will claim that it uses a different cursor_up and
exit_attribute_mode, but it also understands the xterm ones,
and it sends a different key_home,
but we decode that even with TERM=xterm-256color.

In some cases, terminfo is also just outright *wrong* and will claim
something does not support italics when it does.

So, since the differences are very likely to simply not matter,
throwing a warning is more confusing than it is helpful.

(cherry picked from commit 642ec399ca)
2025-03-16 18:50:46 +01:00
Fabian Boehm
642ec399ca Downgrade $TERM warnings to a term-support flog
The chances that xterm-256color breaks anything are miniscule.

In the features we use, there are basically no differences,
especially when you consider that we decode keys independently.

E.g. tmux-256color has differences, but they are either just taste
questions (xterm's clear_screen will also clear scrollback),
or they're just... not actually different?

Terminfo will claim that it uses a different cursor_up and
exit_attribute_mode, but it also understands the xterm ones,
and it sends a different key_home,
but we decode that even with TERM=xterm-256color.

In some cases, terminfo is also just outright *wrong* and will claim
something does not support italics when it does.

So, since the differences are very likely to simply not matter,
throwing a warning is more confusing than it is helpful.
2025-03-16 18:50:36 +01:00
Johannes Altmanninger
ffbf957fa3 Quote only unique completions, use backslashes for ambiguous ones
Commit 29dc307111 (Insert some completions with quotes instead of backslashes,
2024-04-13) breaks some workflows. Given

	touch '[test] file1'
	touch '[test] file2'
	ls tes<Tab>

we insert completions quoted, which is inconvenient when using globs.

This implicit quoting feature is somewhat minor. But quotes look nicer,
so let's try to keep them.  Either way, users can ask for it by starting a
token with «"».

Use quoting only when we insert unique completions.

Closes #11271

(cherry picked from commit 9f79fe17fc)
2025-03-16 12:12:03 +01:00
Peter Ammon
a0a6edd303 Remove Rc from line_counter
We no longer need this.
2025-03-15 16:43:17 -07:00
Peter Ammon
d1c7e8d96f Make ScopeGuard invoke its function by value
No need for &mut here.
2025-03-15 16:43:17 -07:00
Peter Ammon
a9837a3cbf Remove scoped_push and friends
These are now unused because of the recent migration to scoped cell types.
2025-03-15 16:43:17 -07:00
Peter Ammon
7f8e773b4d Use the new scoped machinery for the current filename 2025-03-15 16:43:17 -07:00
Peter Ammon
6eb9b60250 Refactor wildcard expansion state
Prior to this commit, the WildCardExpander had one scoped variable, leading to
the annoying "zelf" pattern. Factor this into its own object and pass it around
explicitly, to clean this up.
2025-03-15 16:43:17 -07:00
Peter Ammon
e0953cac41 Use new scoped types for line_counter and caller_id 2025-03-15 16:43:17 -07:00
Peter Ammon
adde79259b Move the eval_level into the Parser scoped data
Clean up some ugly atomic stuff.
2025-03-15 16:43:17 -07:00
Peter Ammon
29ae571afa Make scoped_push nicer
In C++ it's easy to make an RAII-type object like "increment a counter for
the duration of this function." Such an object might accept a pointer or
reference, increment the value, and then restore it in its destructor. We
do this all the time - for example to mark a region of code as
non-interactive, etc.

Rust makes this more awkward, because now the reference is tracked by the
borrow checker: it "owns" the object for the duration of the function. This
leads to approaches like "zelf" where the object that marks the parser as
non-interactive itself becomes the new parser, but we can't call it "self"
and it's just yucky.

In this commit we introduce a notion of the "scoped data" of the Parser,
factored out of the library data. This is data which is typically set in a
scoped fashion: whether we are a subshell, are interactive, emit fish_trace
debugging info, etc. Crucially we set this as Rc: this allow the scope
itself to share data with the Parser and we can get rid of lots of "zelf"s.

Introduce a new function `Parser::push_scope` which creates a new scope and
allows modifying these variables associated with the scope. This ends up as
a nice simplification.
2025-03-15 16:43:16 -07:00
Peter Ammon
2930466d53 Introduce ScopedCell and ScopedRefCell
As part of a plan to overhaul the "scoped_set" pattern, introduce two new
"scoped" types:

ScopedCell is a trivial wrapper around Cell which exposes a function
`scoped_mod`. This allows you to modify the contents of the Cell; the
original contents are restored when the guard is dropped.

ScopedRefCell is similar, except it requires the caller to supply an
accessor which returns a &mut field, and also the new value.

These will be used to replace the rather unsightly scoped_push calls
around the fish codebase.
2025-03-15 16:40:31 -07:00
Peter Ammon
a296ee085c Stop returning a value from ScopeGuarding::commit
This was unused outside of the tests.
2025-03-15 16:40:31 -07:00
Peter Ammon
0113db3ff7 Make parser.libdata.is_event a bool instead of an int
Contrary to the comment, this can and should be a bool.
2025-03-15 16:40:31 -07:00
Peter Ammon
7cc72f1306 Make the transient command line a single value, not a stack
This concerns completions which wrap other completions. For example, if 'tig'
wraps 'git' then for the duration of the git completions, we need to make a fake
("transient") command line which contains "git" and not "tig".

Previously we had a stack of such command lines, but we never inspected anything
except the last element. Make this a single value.
2025-03-15 16:40:31 -07:00
carsonzhu
4ce552bf94 Token search commands that only match the last token in each line
This add two commands history-last-token-search-backward and
history-last-token-search-forward which behaves like bash's yank-last-arg. So
similar to history-token-search-* but only considers the last argument for
each command.

Closes #10756
Closes #11258
2025-03-15 21:54:47 +01:00
Farhood Etaati
48306409ef Adds git subtree completion
Closes #11063
2025-03-15 21:54:25 +01:00
Johannes Altmanninger
a18680cb53 timer: use write! instead of intermediate format!
See #10937
2025-03-15 21:54:25 +01:00
Sander Machado
f4a8368c9e builtins: idiomatic error code passing
Remaining code smells:
- exec_subshell_internal needs to convert a number to a result

Closes #10948
2025-03-15 21:30:49 +01:00
Ilya Grigoriev
bdb8f7da3a completion/tmux: quick fixup to conflict resolution in b85e405
Delete a line that should have been replaced with the following line (with --keep-order)

Closes #11288
2025-03-15 21:24:17 +01:00
Johannes Altmanninger
f43b16b1cb completions/pulumi: disable update check
As seen in GitHub Actions:

	132/193 Test  #17: check-completions.fish ...................***Failed   16.28 sec
	checks/check-completions.fish..Failure:

	  There were no remaining checks left to match stdout:1:
	    OUTPUT from /home/runner/work/fish-shell/fish-shell/share/completions/pulumi.fish: warning: A new version of Pulumi is available. To upgrade from version '3.154.0' to '3.156.0', visit https://pulumi.com/docs/install/ for manual instructions and release notes.
2025-03-15 21:24:17 +01:00
Fabian Boehm
65eb6cfbfe docs: Remove pre-2.4 caveats
2.4 is almost 9 years old and 69% of commits to fish behind. It is
well past worth mentioning.
2025-03-15 16:36:13 +01:00
Fabian Boehm
19267ce3fc completions/pulumi: Silence stderr
This apparently checks for updates and warns if one is available on
start.

I don't love it.
2025-03-15 12:59:27 +01:00
Ilya Grigoriev
b85e4057bc completions/tmux: show all session panes in pane completions
This makes several changes:

- All panes in the current session are now show, instead of just the
  current window.

- Instead of using window names when referring to panes (e.g.
  "fish-dev.1"), we now use either window indicies ("3.1") or absolute
pane ids (%12). This is mainly because several windows often share the
same window name, e.g. many of my panes are automatically named "fish"
if they are currently running the shell and nothing else.

  I put the window names in the descriptions. Because fish uses the
descriptions for completions, completing `fish-dev` is still helpful.

- I include the pane name into the description for a similar reason,
  truncated to 15 chars.

- The panes are now ordered carefully, with panes in this window listed
  first, then panes are ordered by window, and finally panes are listed
by their id (which does not change when panes are moved between windows)

Example output after `tmux selectp -t <TAB>` for a session with a few
windows. Note that windows 0, 1, and 4 are all named
`fish`. A pane in the current window can be accessed in 3 ways: `3`,
`2.3`, or `%57`.


```
0         (%4 [fish-dev] ~/d/fish-shell <active pane>)  3.1                    (%58 [fish] man tmux ~/.c/f...)
1     (%8 [fish-dev] hwatch "jj.logs... <active win.>)  4.0                     (%1 [sshd] tmux rename-win...)
2    (%15 [fish-dev] /U/i/d/fish-she... <active win.>)  %1                     (4.0 [sshd] tmux rename-win...)
3        (%57 [fish-dev] ~/d/fish-shell <active win.>)  %4       (2.0 [fish-dev] ~/d/fish-shell <active pane>)
0.0                                    (%100 [fish] ~)  %8   (2.1 [fish-dev] hwatch "jj.logs... <active win.>)
1.0                         (%11 [fish] ~/d/_/nixpkgs)  %11                         (1.0 [fish] ~/d/_/nixpkgs)
1.1                    (%38 [fish] ~/.c/f/completi...)  %15  (2.2 [fish-dev] /U/i/d/fish-she... <active win.>)
2.0       (%4 [fish-dev] ~/d/fish-shell <active pane>)  %38                    (1.1 [fish] ~/.c/f/completi...)
2.1   (%8 [fish-dev] hwatch "jj.logs... <active win.>)  %41                         (3.0 [fish] ~/.c/f/conf.d)
2.2  (%15 [fish-dev] /U/i/d/fish-she... <active win.>)  %57      (2.3 [fish-dev] ~/d/fish-shell <active win.>)
2.3      (%57 [fish-dev] ~/d/fish-shell <active win.>)  %58                    (3.1 [fish] man tmux ~/.c/f...)
3.0                         (%41 [fish] ~/.c/f/conf.d)  %100                                    (0.0 [fish] ~)
```

Compared to before:

```
0  (pane)  2  (pane)  0:fish-dev.0  (session:window.pane)  0:fish-dev.2  (session:window.pane)  fish-dev  (window)
1  (pane)  3  (pane)  0:fish-dev.1  (session:window.pane)  0:fish-dev.3  (session:window.pane)
```

Note that the "before" version describes the same 3 panes several times
in a row, and all the entries involving "fish-dev" are suspect since
there could be another "fish-dev" window (or, more likely, this window
and others could all be named "fish").

Closes #11115
2025-03-15 12:30:00 +01:00
Ilya Grigoriev
f30a85f538 completions/tmux: more send-keys completions, add switch-client key table argument
The switch client option is a bit weird (why does this command have a
key table-related function?), but seems helpful to add.
2025-03-15 12:27:20 +01:00
Ilya Grigoriev
5fecc2e355 completions/tmux: fixups to key table commands, update to post-2017 tmux
There are some minor updates.

Also, the syntax seems to have changed in tmux 2.4 in 2017,
ef68debc8d/CHANGES (L1484)

Notably, many of the key table commands now use `-T` in place of
the correct `-t`, and the list of key binding tables has changed.
2025-03-15 12:27:20 +01:00
Yann Soubeyrand
052a010b57 feat(completions): add argocd, cue, dagger, kubebuilder and pulumi
These tools use the Cobra framework for argument parsing, which can
generate completions ready to be sourced.
2025-03-15 12:27:14 +01:00
lengyijun
517b02899a doc: bind ctrl-c clear-commandline 2025-03-15 10:58:34 +01:00
Fabian Boehm
411a396fa9 tests: Just check that the version starts with a digit
Our versions look like

4.0.0
4.0b1
4.0.1-535-abfef-dirty

But packagers may want to add more information here, and we don't
really care. Note that we no longer ever set the version to "unknown"
since 5abd0e46f5.

Supersedes #11173
2025-03-15 10:54:12 +01:00
Johannes Altmanninger
9f79fe17fc Quote only unique completions, use backslashes for ambiguous ones
Commit 29dc307111 (Insert some completions with quotes instead of backslashes,
2024-04-13) breaks some workflows. Given

	touch '[test] file1'
	touch '[test] file2'
	ls tes<Tab>

we insert completions quoted, which is inconvenient when using globs.

This implicit quoting feature is somewhat minor. But quotes look nicer,
so let's try to keep them.  Either way, users can ask for it by starting a
token with «"».

Use quoting only when we insert unique completions.

Closes #11271
2025-03-14 22:21:42 +01:00
Fabian Boehm
ae3532e9ec screen: Fix crash if prompt contains backspace
fish_wcwidth_visible can return -1, so usize::try_from fails.

Fixes #11280

(cherry picked from commit c03de2086a)
2025-03-14 20:19:49 +01:00
Fabian Boehm
5cd2ef903a key: Add super modifier
Fixes #11217

(cherry picked from commit 9f5e1736a8)
2025-03-14 20:19:49 +01:00
Fabian Boehm
c03de2086a screen: Fix crash if prompt contains backspace
fish_wcwidth_visible can return -1, so usize::try_from fails.

Fixes #11280
2025-03-14 16:23:33 +01:00
Fabian Boehm
6627d403d3 tests: Override __fish_print_help
This effectively disables "--help", replacing it with just a stand-in
string.

The upshot is that it makes the test suite immune to whether or not it
can find the documentation - until now it needed to *not* find it,
which is weird.

(also it saves some useless lines)

Fixes #11270
2025-03-13 18:13:10 +01:00
Fabian Boehm
7224776f80 staticbuilds: Build fish_indent/key_reader binaries to test 2025-03-13 16:38:21 +01:00
Fabian Boehm
6d93e6324a staticbuilds: Rename files
Use x86_64 instead of amd64 because that's what uname calls it,
and try to get the version in there.
2025-03-13 16:32:41 +01:00
David Adam
1477bf7a54 CHANGELOG: fix formatting 2025-03-13 15:48:52 +08:00
David Adam
298d79ef58 CHANGELOG: actually #10838 is out entirely 2025-03-13 12:04:15 +08:00
David Adam
3a86f8e6c7 CHANGELOG: correct version that #10838 is in 2025-03-13 12:01:14 +08:00
David Adam
a1b50b1a0e Merge branch 'Integration_4.0.1' 2025-03-13 12:00:31 +08:00
David Adam
67b6afffd4 Release 4.0.1 2025-03-13 11:16:55 +08:00
David Adam
6df88e1a9f CHANGELOG: work on 4.0.1 2025-03-13 10:59:58 +08:00
David Adam
f8202408f9 cmake: specify MSRV 2025-03-13 10:47:47 +08:00
Johannes Altmanninger
61884bda36 Fix GitHub Actions build now that images come with ninja
Looks like the github actions image now has ninja installed.
This causes a failure; we effectively do

	$ (
		mkdir build && cd build
		cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo
	  )
	$ make VERBOSE=1
	[...]
	cd build; cmake .. -G "Ninja" \
		-DCMAKE_INSTALL_PREFIX="/usr/local" -DCMAKE_EXPORT_COMPILE_COMMANDS=1
	Re-run cmake no build system arguments
	CMake Error: Error: generator : Ninja
	Does not match the generator used previously: Unix Makefiles
	Either remove the CMakeCache.txt file and CMakeFiles directory or choose a different binary directory.

"make" fails because it runs from top-level, with GNUMakefile's logic to
use -GNinja if available.  This is at odds with the direct cmake invocation,
which defaults to -G'Unix Makefiles'.

We shouldn't mix direct cmake invocation and the top-level Makefiles, so
run make from the build directory instead.

While at it, update some test invocations missed in 8d6fdfd9de
(Remove cmake "test" target, 2025-02-02).  This should
help avoid missing test failure output in CI, see
https://github.com/fish-shell/fish-shell/issues/11116#issuecomment-2629406479

(cherry picked from commit b0be53ed6a)
2025-03-13 10:36:28 +08:00
David Adam
66584dadcc CHANGELOG: work on 4.0.1 2025-03-12 23:28:29 +08:00
Johannes Altmanninger
d2cf002e64 Note that only rustup<=1.27 works OOTB for bisecting
See b38551dde9 (Drag FindRust.cmake back into the land of the living,
2025-03-05).
2025-03-12 08:40:44 +01:00
David Adam
5944518e6e docs/fish_title: add example on disabling title changing
Work on #11241.

(cherry picked from commit 3c8e058b75)
2025-03-12 14:39:33 +08:00
David Adam
3c8e058b75 docs/fish_title: add example on disabling title changing
Work on #11241.
2025-03-12 14:36:40 +08:00
Johannes Altmanninger
19502ff9e7 Add hack to fix off-by-one error in Vi-mode cancel-commandline
The new cursor-end-mode "inclusive" (which is active in Vi mode) is causing
many issues.

One of them is because cancel-commandline wants to move to the end of the
command line before printing "^C".  Since "inclusive" cursor mode prevents
the cursor from moving past the last character, that one will be overwritten
with a "^".  Hack around this.

Closes #11261

(cherry picked from commit b08ff33291)
2025-03-11 20:24:04 +01:00
Johannes Altmanninger
b08ff33291 Add hack to fix off-by-one error in Vi-mode cancel-commandline
The new cursor-end-mode "inclusive" (which is active in Vi mode) is causing
many issues.

One of them is because cancel-commandline wants to move to the end of the
command line before printing "^C".  Since "inclusive" cursor mode prevents
the cursor from moving past the last character, that one will be overwritten
with a "^".  Hack around this.

Closes #11261
2025-03-11 20:23:30 +01:00
Johannes Altmanninger
5b94af6367 Restore cursor shape when deactivating Vi mode
Running

	fish_vi_key_bindings
	fish_default_key_bindings

ought to maintain cursor shape, at least in the default configuration,
so let's do that.

Fixes 9ef76860e6 (Default Vi cursor shapes for insert/replace mode, 2024-10-26).
2025-03-11 20:22:27 +01:00
lengyijun
18c4ee4b41 cleanup: rm strange code block 2025-03-11 20:01:49 +01:00
Johannes Altmanninger
b0be53ed6a Fix GitHub Actions build now that images come with ninja
Looks like the github actions image now has ninja installed.
This causes a failure; we effectively do

	$ (
		mkdir build && cd build
		cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo
	  )
	$ make VERBOSE=1
	[...]
	cd build; cmake .. -G "Ninja" \
		-DCMAKE_INSTALL_PREFIX="/usr/local" -DCMAKE_EXPORT_COMPILE_COMMANDS=1
	Re-run cmake no build system arguments
	CMake Error: Error: generator : Ninja
	Does not match the generator used previously: Unix Makefiles
	Either remove the CMakeCache.txt file and CMakeFiles directory or choose a different binary directory.

"make" fails because it runs from top-level, with GNUMakefile's logic to
use -GNinja if available.  This is at odds with the direct cmake invocation,
which defaults to -G'Unix Makefiles'.

We shouldn't mix direct cmake invocation and the top-level Makefiles, so
run make from the build directory instead.

While at it, update some test invocations missed in 8d6fdfd9de
(Remove cmake "test" target, 2025-02-02).  This should
help avoid missing test failure output in CI, see
https://github.com/fish-shell/fish-shell/issues/11116#issuecomment-2629406479
2025-03-11 00:46:41 +01:00
Johannes Altmanninger
e37e1b8f78 Fix regression causing glitches when prompt has control character
Since commit 0627c9d9af (Render control characters as Unicode Control Pictures,
2020-08-29), we render control character in the commandline as "␇" etc.
They can be inserted via either history search, or bindings such as

	bind ctrl-g "commandline -i \a"

That commit incorrectly assumes that the prompt is rendered the same way as
the command line (which goes through "ScreenData" etc).
This is wrong -- prompt text is written to stdout as-is, and a prompt that
outputs \t (tab) or \a (BEL) is valid.  The wrong assumption means that we
overestimate the width of prompts containing control characters.

(For some reason, after switching from Vi insert to Vi normal mode, we seem
to get the width right which means the command line jumps around)

Let's revert to the old width computation for any prompt text.

Closes #11252

(cherry picked from commit 4d81cf8af4)
2025-03-11 00:03:34 +01:00
Johannes Altmanninger
4d81cf8af4 Fix regression causing glitches when prompt has control character
Since commit 0627c9d9af (Render control characters as Unicode Control Pictures,
2020-08-29), we render control character in the commandline as "␇" etc.
They can be inserted via either history search, or bindings such as

	bind ctrl-g "commandline -i \a"

That commit incorrectly assumes that the prompt is rendered the same way as
the command line (which goes through "ScreenData" etc).
This is wrong -- prompt text is written to stdout as-is, and a prompt that
outputs \t (tab) or \a (BEL) is valid.  The wrong assumption means that we
overestimate the width of prompts containing control characters.

(For some reason, after switching from Vi insert to Vi normal mode, we seem
to get the width right which means the command line jumps around)

Let's revert to the old width computation for any prompt text.

Closes #11252
2025-03-11 00:03:12 +01:00
Johannes Altmanninger
5d31be1c3e Fix regression causing crash on empty paste in Vi-mode
Fixes d51f669647 (Vi mode: avoid placing cursor beyond last character,
2024-02-14).

Closes #11256

(cherry picked from commit 2b4f150883)
2025-03-10 22:38:38 +01:00
Johannes Altmanninger
2b4f150883 Fix regression causing crash on empty paste in Vi-mode
Fixes d51f669647 (Vi mode: avoid placing cursor beyond last character,
2024-02-14).

Closes #11256
2025-03-10 22:28:40 +01:00
Johannes Altmanninger
ea6e819a33 completions/set: add fish_cursor_* variables 2025-03-10 22:28:40 +01:00
metamuffin
7a959723ef Print newline on path warnings to stderr instead of stdout (Rust port regression)
(cherry picked from commit 4227f534b4)
2025-03-09 14:13:44 +01:00
metamuffin
4227f534b4 Print newline on path warnings to stderr instead of stdout 2025-03-09 14:12:32 +01:00
Peter Ammon
7d3b157f13 Allow sprintf! macros to accept format string only
This allows something like `sprintf!("foo")`. Previously this was a compile time
error.

Fixes #11243
2025-03-08 20:26:03 -08:00
Peter Ammon
ad0feab86c Fix a Sphinx warning 2025-03-08 10:53:06 -08:00
Peter Ammon
2ecd0d011b Fix some clipplies 2025-03-08 10:52:27 -08:00
Johannes Altmanninger
ad7631093d Remove assertion about history items
For unknown reasons this assertion fails.  This means that 1b9b893169 (After
reading corrupted history entry, keep reading older entries, 2024-10-06)
is not fully working.  Go back to historical behavior for now.

Closes #11236

(cherry picked from commit 4f80e5cb54)
2025-03-08 13:14:44 +01:00
Johannes Altmanninger
2930c85926 Add hack to restore cursor position on undo ofter exec again
See f2dde229aa (Revert changes to restore cursor position after undo,
2025-03-05).

I think there are two problems with tmux when doing a final redraw of a
larger-than-screen commandline.  One is easy to trigger independent of
f2dde229aa.  The other is reproduced by the broken output in the tmux test
removed by that commit. Should root-cause them later.

Use a hack for now; this also happens to fix the broken output in tmux.
2025-03-08 13:12:38 +01:00
Johannes Altmanninger
4f80e5cb54 Remove assertion about history items
For unknown reasons this assertion fails.  This means that 1b9b893169 (After
reading corrupted history entry, keep reading older entries, 2024-10-06)
is not fully working.  Go back to historical behavior for now.

Closes #11236
2025-03-08 13:12:23 +01:00
Johannes Altmanninger
bd8d268255 Extend midnight commander workaround for when numlock/capslock is active
Midnight Commander 4.8.33 knows how to read the CSI u encoding of ctrl-o
(which is the only key it reads while the shell is in control).  But it fails
to when numlock or capslock is active.  Let's disable the kitty keyboard
protocol again until mc indicates that this is fixed.

Closes #10640

The other issue talked about in that issue is an unrelated mc issue, see
https://github.com/MidnightCommander/mc/issues/4597#issuecomment-2705900024
2025-03-07 12:14:56 +01:00
Niklas Liechti
90218821f9 Split content of *KnownHostsFile as this is a supported config option by ssh. 2025-03-06 21:53:30 -08:00
phanium
6e8d6328ee completions/flatpak: don't ignore packages with uppercase in name (#11230)
* completions/flatpak: don't ignore packages with uppercase in name

`[^A-Z]+` here seems to trim header section in old version flatpak (avoid one
more `tail -n -2`?) but this can ignore packages have uppercase name like
`org.gtk.Gtk3theme.Adwaita-dark`.

* completions/flatpak: use cached `__fish_print_flatpak_packages` for `flatpak install`
2025-03-06 21:39:10 -08:00
Peter Ammon
83f29ed09c Drag FindRust.cmake back into the land of the living
rustup has changed its output for 'rustup toolchain list --verbose`.
Teach FindRust.cmake about it, so that it may shamble on.

Cherry-picked from b38551dde9
2025-03-06 10:05:54 -08:00
Fabian Boehm
aca6836103 CHANGELOG add links 2025-03-06 11:37:19 +01:00
Peter Ammon
cc455ff976 Revert "CI: Disable FreeBSD"
With the prior commit, CMake and rustup can continue to talk to each other, for
now.

This reverts commit b69a1b2ffe.
2025-03-05 22:05:00 -08:00
Peter Ammon
b38551dde9 Drag FindRust.cmake back into the land of the living
rustup has changed its output for 'rustup toolchain list --verbose`.
Teach FindRust.cmake about it, so that it may shamble on.

This was reported against BSD and also affects macOS and ALSO affects Linux; our
CI just doesn't have a new enough rustup. Anyways we can't have nice things.
2025-03-05 21:53:54 -08:00
Peter Ammon
f2dde229aa Revert changes to restore cursor position after undo
This feature is nice and desirable, but it was implemented in a intrusive way
by modifying the sequence of bytes we emit when running a command; this in
turn requires changing a bunch of tests.

This sequence hasn't changed in decades and the consequences of changing it
are hard to predict, given that it is likely terminal dependent; we've
already found a regression.

It's fine to reintroduce this but it should be done in a less intrusive way
(conceptually that seems straightforward - we're just remembering the cursor
position).

Revert "Fix spurious blank lines when executing scrolled commandline"

This reverts commit 0e512f8033.

Revert "On undo after execute, restore the cursor position "

This reverts commit 610338cc70.
2025-03-05 17:57:48 -08:00
Peter Ammon
c9f1979b05 Revert "On undo after execute, restore the cursor position"
This reverts commit 815bc054e7.

This is too ambitious for a patch release, given that it affects how every
typed-in command runs.
2025-03-05 15:54:20 -08:00
Peter Ammon
4a35c48ce5 Changelog fix for 11221 2025-03-05 14:11:17 -08:00
Gabriel de Perthuis
f336cf5624 Fix dirent->d_name usage
Closes https://github.com/fish-shell/fish-shell/issues/11221

(cherry picked from commit a0dada5618)
2025-03-05 22:35:01 +01:00
Fabian Boehm
30fa57022a docs: Switch link from gitter to matrix
Gitter is now useless,  matrix is a known thing that people may have
clients and accounts for already
2025-03-05 22:34:38 +01:00
Gabriel de Perthuis
a0dada5618 Fix dirent->d_name usage
Closes https://github.com/fish-shell/fish-shell/issues/11221
2025-03-05 13:29:46 -08:00
Johannes Altmanninger
4ff94b657f __fish_apropos: fixup broken macOS version check
Due to the parens, this prints the version twice.  Fixes 49023adec7
(Consolidate some calls to uname(1) around shell startup, 2025-03-05).
2025-03-05 14:30:06 +01:00
Johannes Altmanninger
1504731d53 Backout new assertion to support old Rust
error[E0015]: cannot call non-const fn `zeroed::<libc::statfs>` in constants
	   --> src/path.rs:712:35
	    |
	712 |             let f_type = unsafe { mem::zeroed::<libc::statfs>() }.f_type;
	    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	    |
	    = note: calls in constants are limited to constant functions, tuple structs and tuple variants

	error: `std::mem::size_of_val` is not yet stable as a const fn
	   --> src/path.rs:713:13
	    |
	713 |             mem::size_of_val(&f_type) <= mem::size_of::<usize>()
	    |             ^^^^^^^^^^^^^^^^^^^^^^^^^

(cherry picked from commit 54f9778003)
2025-03-05 13:02:53 +01:00
Johannes Altmanninger
54f9778003 Backout new assertion to support old Rust
error[E0015]: cannot call non-const fn `zeroed::<libc::statfs>` in constants
	   --> src/path.rs:712:35
	    |
	712 |             let f_type = unsafe { mem::zeroed::<libc::statfs>() }.f_type;
	    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	    |
	    = note: calls in constants are limited to constant functions, tuple structs and tuple variants

	error: `std::mem::size_of_val` is not yet stable as a const fn
	   --> src/path.rs:713:13
	    |
	713 |             mem::size_of_val(&f_type) <= mem::size_of::<usize>()
	    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
2025-03-05 13:02:31 +01:00
Johannes Altmanninger
9dce68fab4 Fix crash on negative stat f_type (Rust-port regression)
Fixes #11219

(cherry picked from commit e5852a6100)
2025-03-05 12:34:59 +01:00
Johannes Altmanninger
49023adec7 Consolidate some calls to uname(1) around shell startup
Most versions of fish don't run any external processes at startup, except
maybe fish_vcs_prompt.  This changed recently with a couple additions of uname.
This is probably fine but I guess we can reduce it down to one.

This change feels somewhat wrong. Not sure.  I guess we can remove it once
we provide $OSTYPE.

Note that this is also the reason why bindings don't use

	bind alt-backspace 'if test "$(uname)" = Darwin ...'

We don't want to expose a private interface in "bind" output.
2025-03-05 12:34:17 +01:00
Johannes Altmanninger
ce40229da6 Fix broken macOS major version detection regex
Not that it matters in practice but this is broken for version 100.
Reduce the surprise.
2025-03-05 12:28:48 +01:00
Johannes Altmanninger
8d8d25ff45 completions/bind: add super modifier 2025-03-05 12:28:48 +01:00
Johannes Altmanninger
e5852a6100 Fix crash on negative stat f_type (Rust-port regression)
Fixes #11219
2025-03-05 12:28:48 +01:00
m1kc (Max Musatov)
db4c999272 De-duplicate install code in fish.rs 2025-03-04 21:44:44 -08:00
Fabian Boehm
b69a1b2ffe CI: Disable FreeBSD
This fails with:

```
CMake Warning (dev) at cmake/FindRust.cmake:349 (message):
  Unexpected output from `rustc --version` for Toolchain
  `stable-x86_64-unknown-freebsd`: ``.

  Ignoring this toolchain.
Call Stack (most recent call first):
  cmake/Rust.cmake:5 (include)
  CMakeLists.txt:24 (include)
This warning is for project developers.  Use -Wno-dev to suppress it.

-- Rust Toolchain:
CMake Warning at cmake/FindRust.cmake:31 (message):
  The rustc executable was not found.  Rust not installed or ~/.cargo/bin not
  added to path?

  Hint: Consider setting `Rust_COMPILER` to the absolute path of `rustc`.
```

For some reason? Disable it for now until someone figures out what's
going on
2025-03-04 17:01:27 +01:00
Fabian Boehm
9f5e1736a8 key: Add super modifier
Fixes #11217
2025-03-04 17:00:26 +01:00
nicole
b3ff27b089 completions/emacs: add completion for argumnet: "--init-directory" (#11165) 2025-03-04 11:56:09 +01:00
Johannes Altmanninger
2bb5cbc959 Default bindings for token movements v2
Commit 6af96a81a8 (Default bindings for token movement commands, 2024-10-05)
has been reverted but not all docs have been.

Key bindings to move by command line argument are quite intuitive, and useful
when moving across URLs or other long arguments.

We have redundant bindings like {alt,ctrl}-left, so let's use one of them
for token movement.  We don't want to break the OS-native shortcut for word
movement, so use the other one on the current platform.

Note that Sublime Text does something similar: it uses the native key
binding for word movement, and the vacant one (e.g. `alt-left` on Linux)
for sub-word movement in camel case words.

While there have been 2.5 votes against making this platform dependent,
the majority of feedback was in favor.

This uses uname which seems wrong; we should rather use the OS that the
terminal is running on. I plan to implement this in future, but there's no
consensus yet on whether terminal applications should be allowed to do this.

See #10926
See #11107
2025-03-04 11:44:47 +01:00
lengyijun
67e95a1ce7 clippy: remove redundant .collect::<Vec<_>>()
Closes #11214
2025-03-04 10:31:14 +01:00
Johannes Altmanninger
815bc054e7 On undo after execute, restore the cursor position
Ever since 149594f974 (Initial revision, 2005-09-20), we move the
cursor to the end of the commandline just before executing it.

This is so we can move the cursor to the line below the command line,
so moving the cursor is relevant if one presses enter on say, the
first line of a multi-line commandline.

As mentioned in #10838 and others, it can be useful to restore the
cursor position when recalling commandline from history. Make undo
restore the position where enter was pressed, instead of implicitly
moving the cursor to the end. This allows to quickly correct small
mistakes in large commandlines that failed recently.

This requires a new way of moving the cursor below the command line.
Test changes include unrelated cleanup of history.py.

(cherry picked from commit 610338cc70)
(cherry picked from commit 0e512f8033)
2025-03-04 10:00:33 +01:00
Johannes Altmanninger
b8af4b20c2 Work around torn byte sequences in qemu kbd input with 1ms timeout
As reported on gitter, fish running inside a qemu console randomly fails to
recognize multi-byte sequences like "\e[D" (right); it sometimes recognizes
the first two bytes as "alt-[" and the last byte as the "D" key.

This because 8bf8b10f68 (Extended & human-friendly keys, 2024-03-30) changed
our approach to reading multi-byte key sequences.  Previously, we'd wait
forever (or rather fish_sequence_key_delay_ms) for the "D" byte.

As of  8bf8b10f68, we assume the entire sequence is already present in the
input buffer; and stop parsing the sequence if stdin is not readable.

It would be more technically correct to implement the VT state machine but
then we'd probably want to to figure out a timeout or a reset key, in case
of transport or terminal issues.

Returning early is also what we have historically done for multi-byte code
points.  Also, other terminal programs have been using it for many years
without problems.

I don't know why this happens in qemu but it seems we can work around by
setting a 1ms timeout.  This timeout should be small enough two keys "escape"
and "[" typed by a human will still be seen separate.

Refs:
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$Cfi9wL8FGLAI6_VAQWG2mG_VxsADUPvdPB46P41Jdbs
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$O_-LZ1W7Dk6L_4Rj0MyCry6GtO2JQlEas8fH9PrSYT8

(cherry picked from commit e1be842167)
2025-03-04 10:00:33 +01:00
Johannes Altmanninger
e1be842167 Work around torn byte sequences in qemu kbd input with 1ms timeout
As reported on gitter, fish running inside a qemu console randomly fails to
recognize multi-byte sequences like "\e[D" (right); it sometimes recognizes
the first two bytes as "alt-[" and the last byte as the "D" key.

This because 8bf8b10f68 (Extended & human-friendly keys, 2024-03-30) changed
our approach to reading multi-byte key sequences.  Previously, we'd wait
forever (or rather fish_sequence_key_delay_ms) for the "D" byte.

As of  8bf8b10f68, we assume the entire sequence is already present in the
input buffer; and stop parsing the sequence if stdin is not readable.

It would be more technically correct to implement the VT state machine but
then we'd probably want to to figure out a timeout or a reset key, in case
of transport or terminal issues.

Returning early is also what we have historically done for multi-byte code
points.  Also, other terminal programs have been using it for many years
without problems.

I don't know why this happens in qemu but it seems we can work around by
setting a 1ms timeout.  This timeout should be small enough two keys "escape"
and "[" typed by a human will still be seen separate.

Refs:
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$Cfi9wL8FGLAI6_VAQWG2mG_VxsADUPvdPB46P41Jdbs
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$O_-LZ1W7Dk6L_4Rj0MyCry6GtO2JQlEas8fH9PrSYT8
2025-03-04 09:45:15 +01:00
Johannes Altmanninger
852cb60ebd Make abbreviation completions shadow commands
As reported in
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$yD_Lutaftf6ytk617kjw5vC-k_OgHRQxIiSRv89uBMI
it's weird that command name completions shadow abbreviation name
completions, given that the abbreviation will the one that will be
executed in the typical cases. Let's put abbreviation completions first;
unique_completions_retaining_order() will take care of removing any command
completions we add later.
2025-03-04 09:45:15 +01:00
Johannes Altmanninger
c06830ccf2 Orphan background tasks to work around terminals being sensitive to unreaped processes
When a command like "long-running-command &" exits, the resulting SIGCHLD
is queued in the topic monitor. We do not process this signal immediately
but only after e.g. the next command has finished. Only then do we reap the
child process.

Some terminals, such as Terminal.app, refuse to close when there are unreaped
processes associated with the terminal -- as in, having the same session ID,
see setsid(3).

In future, we might want to reap proactively.

For now, apply an isolated workaround: instead of taking care of a child
process, double-fork to create an orphaned process. Since the orphan will
be reaped by PID 1, we can eventually close Terminal.app without it asking
for confirmation.

	/bin/sh -c '( "$@" ) >/dev/null 2>&1 &' -- cmd arg1 arg2

This fix confines the problem to the period during which a background process
is running. To complete the fix, we would need to call setsid to detach the
background process from a controlling terminal. That seems to be desirable
however macOS does provide a setsid utility.

	setsid cmd arg1 arg2 >/dev/null 2>&1

Fixes #11181

(cherry picked from commit e015956de7)
2025-03-04 09:18:18 +01:00
Johannes Altmanninger
e015956de7 Orphan background tasks to work around terminals being sensitive to unreaped processes
When a command like "long-running-command &" exits, the resulting SIGCHLD
is queued in the topic monitor. We do not process this signal immediately
but only after e.g. the next command has finished. Only then do we reap the
child process.

Some terminals, such as Terminal.app, refuse to close when there are unreaped
processes associated with the terminal -- as in, having the same session ID,
see setsid(3).

In future, we might want to reap proactively.

For now, apply an isolated workaround: instead of taking care of a child
process, double-fork to create an orphaned process. Since the orphan will
be reaped by PID 1, we can eventually close Terminal.app without it asking
for confirmation.

	/bin/sh -c '( "$@" ) >/dev/null 2>&1 &' -- cmd arg1 arg2

This fix confines the problem to the period during which a background process
is running. To complete the fix, we would need to call setsid to detach the
background process from a controlling terminal. That seems to be desirable
however macOS does provide a setsid utility.

	setsid cmd arg1 arg2 >/dev/null 2>&1

Fixes #11181
2025-03-04 09:16:40 +01:00
Fabian Boehm
f96b9c53ce CHANGELOG for 4.0.1 2025-03-03 21:27:38 +01:00
Johannes Altmanninger
12527d1522 Add back legacy bindings to address modifyOtherKeys regressions in iTerm2<3.5.12
As of 303af07, iTerm2 3.5.11 on two different machines has two different
behaviors. For unknown reasons, when pressing alt-right fish_key_reader
shows "\e\[1\;9C" on one machine and "\e\[1\;3C" on another.

Feels like iTerm2 interprets modifyOtherKeys differently, depending on
configuration.

We don't want to risk asking for the kitty
keyboard protocol until iTerm2 3.5.12 (see
https://github.com/fish-shell/fish-shell/issues/11004#issuecomment-2571494782).

So let's work around around this weirdness by adding back the legacy
bindings removed in c0bcd817ba (Remove obsolete bindings, 2024-04-28) and
plan to remove them in a few years.

Note that fish_key_reader still reports this as "left", which already has
a different binding, but it looks like literal matches of legacy sequences
have precedence.

Fixes the problem described in
https://github.com/fish-shell/fish-shell/issues/11192#issuecomment-2692247060

Closes #11192

(cherry picked from commit 44d5abdc05)
2025-03-03 14:44:49 +01:00
Johannes Altmanninger
46422b6a16 completions/git: fix completions for third-party git commands
Before 798527d79a (completions: fix double evaluation of tokenized commandline, 2024-01-06)
git-foo completions did something like

	set -l subcommand_args (commandline -opc)
	complete -C "git-foo $subcommand_args "

As mentioned in 368017905e (builtin commandline: -x for expanded tokens,
supplanting -o, 2024-01-06), the "-o" option is bad
because it produces a weird intermediate, half-expanded state.

The immediate goal of 798527d79a was to make sure we do not do any
more expansion on top of this.  To that end, it changed the above to
"\$subcommand_args".  The meaning is more or less the same[^*] but crucially,
the recursive completion invocation does not see through the variable,
which breaks some completions.

Fix this with the same approach as in 6b5ad163d3 (Fix double expansion of
tokenized command line, 2025-01-19).

[^*]: It wasn't semantically correct before or after -- this was later
corrected by 29f35d6cdf (completion: adopt commandline -x replacing deprecated
-o, 2024-01-22)).

Closes #11205

(cherry picked from commit 50e595503e)
2025-03-03 14:44:49 +01:00
Johannes Altmanninger
44d5abdc05 Add back legacy bindings to address modifyOtherKeys regressions in iTerm2<3.5.12
As of 303af07, iTerm2 3.5.11 on two different machines has two different
behaviors. For unknown reasons, when pressing alt-right fish_key_reader
shows "\e\[1\;9C" on one machine and "\e\[1\;3C" on another.

Feels like iTerm2 interprets modifyOtherKeys differently, depending on
configuration.

We don't want to risk asking for the kitty
keyboard protocol until iTerm2 3.5.12 (see
https://github.com/fish-shell/fish-shell/issues/11004#issuecomment-2571494782).

So let's work around around this weirdness by adding back the legacy
bindings removed in c0bcd817ba (Remove obsolete bindings, 2024-04-28) and
plan to remove them in a few years.

Note that fish_key_reader still reports this as "left", which already has
a different binding, but it looks like literal matches of legacy sequences
have precedence.

Fixes the problem described in
https://github.com/fish-shell/fish-shell/issues/11192#issuecomment-2692247060

Closes #11192
2025-03-03 14:44:00 +01:00
Johannes Altmanninger
50e595503e completions/git: fix completions for third-party git commands
Before 798527d79a (completions: fix double evaluation of tokenized commandline, 2024-01-06)
git-foo completions did something like

	set -l subcommand_args (commandline -opc)
	complete -C "git-foo $subcommand_args "

As mentioned in 368017905e (builtin commandline: -x for expanded tokens,
supplanting -o, 2024-01-06), the "-o" option is bad
because it produces a weird intermediate, half-expanded state.

The immediate goal of 798527d79a was to make sure we do not do any
more expansion on top of this.  To that end, it changed the above to
"\$subcommand_args".  The meaning is more or less the same[^*] but crucially,
the recursive completion invocation does not see through the variable,
which breaks some completions.

Fix this with the same approach as in 6b5ad163d3 (Fix double expansion of
tokenized command line, 2025-01-19).

[^*]: It wasn't semantically correct before or after -- this was later
corrected by 29f35d6cdf (completion: adopt commandline -x replacing deprecated
-o, 2024-01-22)).

Closes #11205
2025-03-03 14:30:48 +01:00
Johannes Altmanninger
97f0809b62 Add the commandline to the OSC 133 command start
Given

	$ cat ~/.config/kitty/kitty.conf
	notify_on_cmd_finish unfocused 0.1 command notify-send "job finished with status: %s" %c

kitty will send a notification whenever a long-running (>.1s) foreground
command finishes while kitty is not focused.

The %c placeholder will be replaced by the commandline.

This is passed via the OSC 133 command start marker, kitty's fish shell
integration.

That integration has been disabled for fish 4.0.0 because it's no longer
necessary since fish already prints OSC 133. But we missed the parameter for
the command string. Fix it.  (It's debatable whether the shell or the terminal
should provide this feature but I think we should fix this regression?)

Closes #11203

See https://github.com/kovidgoyal/kitty/issues/8385#issuecomment-2692659161

(cherry picked from commit 4378e73fc7)
2025-03-03 11:49:43 +01:00
Johannes Altmanninger
d30a2c5240 Try to reduce write(3) calls for OSC 133 prompt markers
Something like

	write!(f, "foo{}bar", ...)

seems to call f.write_str() thrice.

Splitting a single OSC 133 command into three calls to write(3) might result in
odd situations if one of them fails. Let's try to do it in one in most cases.

Add a new buffered output type that can be used with write!(). This is
somewhat redundant given that we have scoped_buffer().  While at it, remove
the confused error handling.  This doesn't fail unless we are OOM (and this
new type makes that more obvious).

(cherry picked from commit e5e932e970)
2025-03-03 11:48:48 +01:00
Johannes Altmanninger
4378e73fc7 Add the commandline to the OSC 133 command start
Given 

	$ cat ~/.config/kitty/kitty.conf
	notify_on_cmd_finish unfocused 0.1 command notify-send "job finished with status: %s" %c

kitty will send a notification whenever a long-running (>.1s) foreground
command finishes while kitty is not focused.

The %c placeholder will be replaced by the commandline.

This is passed via the OSC 133 command start marker, kitty's fish shell
integration.

That integration has been disabled for fish 4.0.0 because it's no longer
necessary since fish already prints OSC 133. But we missed the parameter for
the command string. Fix it.  (It's debatable whether the shell or the terminal
should provide this feature but I think we should fix this regression?)

Closes #11203

See https://github.com/kovidgoyal/kitty/issues/8385#issuecomment-2692659161
2025-03-03 11:47:50 +01:00
Johannes Altmanninger
e5e932e970 Try to reduce write(3) calls for OSC 133 prompt markers
Something like

	write!(f, "foo{}bar", ...)

seems to call f.write_str() thrice.

Splitting a single OSC 133 command into three calls to write(3) might result in
odd situations if one of them fails. Let's try to do it in one in most cases.

Add a new buffered output type that can be used with write!(). This is
somewhat redundant given that we have scoped_buffer().  While at it, remove
the confused error handling.  This doesn't fail unless we are OOM (and this
new type makes that more obvious).
2025-03-03 11:47:50 +01:00
Johannes Altmanninger
335462697e Remove obsolete clippy suppression
Missed this in b6269438e9.
2025-03-03 11:46:39 +01:00
Johannes Altmanninger
7ee6d91ba0 Work around keyboard-layout related bugs in WezTerm's modifyOtherKeys
modifyOtherKeys with non-English or other non-default keyboard layouts will
cause wrong keys to be sent by WezTerm. Let's try to disable it for now.

Proposed upstream fix: https://github.com/wezterm/wezterm/pull/6748

Closes #11204
2025-03-03 10:13:37 +01:00
Johannes Altmanninger
a94c4e96ab Split /etc/{,man}path by colons too
I don't know how /etc/manpath ends up containing lines like
"path1:path2".  But path_helper splits them so we should do too.

4ea11424b8/path_helper/path_helper.c (L149)

Fixes #10684

(cherry picked from commit 95d61ea0fb)
2025-03-02 22:21:03 +01:00
Peter Ammon
76923de6cf Suppress a dumb clipply 2025-03-02 12:14:14 -08:00
Fabian Boehm
e767bb623f completions/wine: Complete files
wine can be used, and is usually used for things like `wine
setup.exe`,
so it should allow for regular file completion.

Fixes #11202

(cherry picked from commit 86e531b848)
2025-03-02 13:09:57 +01:00
Fabian Boehm
86e531b848 completions/wine: Complete files
wine can be used, and is usually used for things like `wine
setup.exe`,
so it should allow for regular file completion.

Fixes #11202
2025-03-02 13:07:57 +01:00
Fabian Boehm
e0dd983c49 sample_prompts/acidhub: Use the same branch logic as fish_git_prompt
This was broken for 4.0 because it used `{}` command grouping.

Instead just do one of the things the fish_git_prompt does.

(the default isn't usable here because it gets the sha from elsewhere)

(cherry picked from commit e925eccad2)
2025-03-02 12:32:34 +01:00
Fabian Boehm
9dd1f6b634 Release 4.1.0-alpha0 2025-03-02 12:32:29 +01:00
Fabian Boehm
e925eccad2 sample_prompts/acidhub: Use the same branch logic as fish_git_prompt
This was broken for 4.0 because it used `{}` command grouping.

Instead just do one of the things the fish_git_prompt does.

(the default isn't usable here because it gets the sha from elsewhere)
2025-03-02 12:30:29 +01:00
Johannes Altmanninger
200eeffeee sample_prompts/acidhub: fix regression showing all branches
Fix the accidental "git branch" output leaking while making sure we support:
1. unborn branch, where HEAD does not exist (`git init`)
2. detached head (`git checkout --detach`)

Notably computing the branch name should be independent of computing
a diff against HEAD.
In scenario 1 there is a branch but no HEAD,
while in scenario 2 it's the other way round.

Hence we need a separate check to see if we're in a git repo.
"git rev-parse" seems to work. Not sure what's best pracitce.

Also remove the ahead/behind logic, it was broken because it misspelled
@{upstream}.

Fixes #11179

(cherry picked from commit 7b7e744353)
2025-03-02 11:48:17 +01:00
Johannes Altmanninger
7b7e744353 sample_prompts/acidhub: fix regression showing all branches
Fix the accidental "git branch" output leaking while making sure we support:
1. unborn branch, where HEAD does not exist (`git init`)
2. detached head (`git checkout --detach`)

Notably computing the branch name should be independent of computing
a diff against HEAD.
In scenario 1 there is a branch but no HEAD,
while in scenario 2 it's the other way round.

Hence we need a separate check to see if we're in a git repo.
"git rev-parse" seems to work. Not sure what's best pracitce.

Also remove the ahead/behind logic, it was broken because it misspelled
@{upstream}.

Fixes #11179
2025-03-02 11:46:58 +01:00
Jay
0d453039ac fix unknown command __fish_diskutil_volumes
Signed-off-by: Jay <BusyJay@users.noreply.github.com>
(cherry picked from commit c790b1051d)
2025-03-02 11:04:16 +01:00
Jay
c790b1051d fix unknown command __fish_diskutil_volumes
Signed-off-by: Jay <BusyJay@users.noreply.github.com>
2025-03-02 11:03:43 +01:00
Johannes Altmanninger
044afefc5c Fix regression causing cursor shape commands to leak into noninteractive shell
As reported in
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$CLuoHTdvcRj_8-HBBq0p-lmGWeix5khEtKEDxN2Ulfo

Running

	fish -C '
		fzf_key_bindings
		echo fish_vi_key_bindings >>~/.config/fish/config.fish
		fzf-history-widget
	'

and pressing "enter" will add escape sequences like "[2 q" (cursor shape)
to fish's command line.

This is because fzf-history-widget binds "enter" to a filter
that happens to be a fish script:

	set -lx FZF_DEFAULT_OPTS \
		... \
		"--bind='enter:become:string replace -a -- \n\t \n {2..} | string collect'" \
		'--with-shell='(status fish-path)\\ -c)

The above ~/.config/fish/config.fish (redundantly) runs "fish_vi_key_bindings"
even in *noninteractive* shells, then "fish_vi_cursor" will print cursor
sequences in its "fish_exit" handler.  The sequence is not printed to the
terminal but to fzf which doesn't parse CSI commands.

This is a regression introduced by a5dfa84f73 (fish_vi_cursor: skip if stdin
is not a tty, 2023-11-14). That commit wanted "fish -c read" to be able to
use Vi cursor.  This is a noninteractive shell, but inside "read" we are
"effectively interactive".  However "status is-interactive" does not tell
us that.

Let's use a more contained fix to make sure that we print escape sequences only
if either fish is interactive, or if we are evaluating an interactive read.

In general, "fish -c read" is prone to configuration errors, since we
recommend gating configuration (for bind etc) on "status is-interactive"
which will not run here.

(cherry picked from commit 495083249b)
2025-03-02 09:34:51 +01:00
Johannes Altmanninger
5cce0918a9 completions/status: break up long line, add buildinfo
(cherry picked from commit 5278686f55)
2025-03-02 09:34:51 +01:00
Johannes Altmanninger
495083249b Fix regression causing cursor shape commands to leak into noninteractive shell
As reported in
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$CLuoHTdvcRj_8-HBBq0p-lmGWeix5khEtKEDxN2Ulfo

Running

	fish -C '
		fzf_key_bindings
		echo fish_vi_key_bindings >>~/.config/fish/config.fish
		fzf-history-widget
	'

and pressing "enter" will add escape sequences like "[2 q" (cursor shape)
to fish's command line.

This is because fzf-history-widget binds "enter" to a filter
that happens to be a fish script:

	set -lx FZF_DEFAULT_OPTS \
		... \
		"--bind='enter:become:string replace -a -- \n\t \n {2..} | string collect'" \
		'--with-shell='(status fish-path)\\ -c)

The above ~/.config/fish/config.fish (redundantly) runs "fish_vi_key_bindings"
even in *noninteractive* shells, then "fish_vi_cursor" will print cursor
sequences in its "fish_exit" handler.  The sequence is not printed to the
terminal but to fzf which doesn't parse CSI commands.

This is a regression introduced by a5dfa84f73 (fish_vi_cursor: skip if stdin
is not a tty, 2023-11-14). That commit wanted "fish -c read" to be able to
use Vi cursor.  This is a noninteractive shell, but inside "read" we are
"effectively interactive".  However "status is-interactive" does not tell
us that.

Let's use a more contained fix to make sure that we print escape sequences only
if either fish is interactive, or if we are evaluating an interactive read.

In general, "fish -c read" is prone to configuration errors, since we
recommend gating configuration (for bind etc) on "status is-interactive"
which will not run here.
2025-03-02 09:34:06 +01:00
Johannes Altmanninger
5278686f55 completions/status: break up long line, add buildinfo 2025-03-02 09:34:06 +01:00
Peter Rice
d1bb4503d6 edit_command_buffer: pass cursor position to helix 2025-03-02 07:27:06 +01:00
Johannes Altmanninger
3a673aff63 Apply fish_color_search_match foreground only if explicit
Historically, up-arrow search matches have been highlighted by

1. using the usual foreground (from syntax highlighting)
2. using the background from $fish_color_search_match

Commit 9af6a64fd2 (Fix bad contrast in search match highlighting, 2024-04-15)
broke this by also applying the foreground from $fish_color_search_match.

As reported on gitter, there is a meaningful scenario where the foreground
from syntax highlighting should not be overwritten:

	set fish_color_search_match --reverse

this copies the foreground from syntax highlighting to the background.

Since commit 9af6a64fd2 overwrites the foreground highlight, the resulting
background will be monocolored (black in my case) instead of whatever is
the syntax-colored foreground.

FWIW the reversed foreground will always be monocolored, because we have
always done 2.

Let's unbreak this scenario by using the foreground from
fish_color_search_match only if it's explicitly set (like we do since
9af6a64fd2).

This is hacky because an empty color is normally the same as "normal", but
it gets us closer to historical behavior. In future we should try to come
up with a better approach to color blending/transparency.

(cherry picked from commit b6269438e9)
2025-03-02 07:09:44 +01:00
Johannes Altmanninger
b6269438e9 Apply fish_color_search_match foreground only if explicit
Historically, up-arrow search matches have been highlighted by

1. using the usual foreground (from syntax highlighting) 
2. using the background from $fish_color_search_match

Commit 9af6a64fd2 (Fix bad contrast in search match highlighting, 2024-04-15)
broke this by also applying the foreground from $fish_color_search_match.

As reported on gitter, there is a meaningful scenario where the foreground
from syntax highlighting should not be overwritten:

	set fish_color_search_match --reverse

this copies the foreground from syntax highlighting to the background.

Since commit 9af6a64fd2 overwrites the foreground highlight, the resulting
background will be monocolored (black in my case) instead of whatever is
the syntax-colored foreground.

FWIW the reversed foreground will always be monocolored, because we have
always done 2.

Let's unbreak this scenario by using the foreground from
fish_color_search_match only if it's explicitly set (like we do since
9af6a64fd2).

This is hacky because an empty color is normally the same as "normal", but
it gets us closer to historical behavior. In future we should try to come
up with a better approach to color blending/transparency.
2025-03-02 07:08:30 +01:00
Johannes Altmanninger
880aa479bf Work around Konsole not recognizing file:://$hostname/path as local
(This regressed in version 4 which sends OSC 7 to all terminals)

Konsole has a bug: it does not recognize file:://$hostname/path as directory.
When we send that via OSC 7, that breaks Konsole's "Open Folder With"
context menu entry.

OSC 7 producers are strongly encouraged to set a non-empty hostname, but
it's not clear if consumers are supposed to accept an empty hostname (see
https://gitlab.freedesktop.org/terminal-wg/specifications/-/issues/20).
I think it should be fine; implementations should treat it as local path.

Let's work around the Konsole bug by omitting the hostname for now. This
may not be fully correct when using a remote desktop tool to access a
system running Konsole but I guess that's unlikely and understandable.
We're using KONSOLE_VERSION, so it the workaround should not leak into SSH
sessions where a hostname component is important.

Closes #11198

Proposed upstream fix https://invent.kde.org/frameworks/kio/-/merge_requests/1820

(cherry picked from commit c926a87bdb)
2025-03-02 05:47:00 +01:00
Johannes Altmanninger
c926a87bdb Work around Konsole not recognizing file:://$hostname/path as local
Konsole has a bug: it does not recognize file:://$hostname/path as directory.
When we send that via OSC 7, that breaks Konsole's "Open Folder With"
context menu entry.

OSC 7 producers are strongly encouraged to set a non-empty hostname, but
it's not clear if consumers are supposed to accept an empty hostname (see
https://gitlab.freedesktop.org/terminal-wg/specifications/-/issues/20).
I think it should be fine; implementations should treat it as local path.

Let's work around the Konsole bug by omitting the hostname for now. This
may not be fully correct when using a remote desktop tool to access a
system running Konsole but I guess that's unlikely and understandable.
We're using KONSOLE_VERSION, so it the workaround should not leak into SSH
sessions where a hostname component is important.

Closes #11198

Proposed upstream fix https://invent.kde.org/frameworks/kio/-/merge_requests/1820
2025-03-02 05:44:36 +01:00
Peter Ammon
692e14ec82 Fix some silly clipply 2025-03-01 13:27:07 -08:00
Johannes Altmanninger
b8934318f3 Harmonize iTerm kitty keyboard feature gating, fix confusingly named flag
As reported in b5736c5535 (Extend iTerm CSI u workaround to < 3.5.12,
2025-02-20), iTerm 3.5.12 has resolved our issues related to the kitty
keyboard protocol. Enable it here too, matching the release branch.

The flag to gate this is set for versions of iTerm that don't have sufficient
support for the kitty keyboard protocol. CSI u is (more or less) the encoding
used by that protocol.  Let's name things accordingly. My bad.
2025-03-01 16:20:37 +01:00
Johannes Altmanninger
fe7f13e5ad Fix fish_key_reader regression causing kitty protcol not being requested
Commit 2d234bb676 (Only request keyboard protocols once we know if kitty kbd
is supported, 2025-01-26) queries support for the kitty protocol and acted
upon it after having read next character.

Unfortunately this meant that we don't turn on the kitty protocol until after
we read a character -- since the CSI ? u response does not generate a char
event.  Let's query for primary DA additionally, matching what fish does.
In future, we should do a timed wait as well, to avoid terminal responses
leaking when there we exit fish_key_reader too quickly.
2025-03-01 14:31:53 +01:00
Johannes Altmanninger
b401aee4ce Reserve the ability to read XTVERSION
Whenever we add logic to print a control sequence that we hadn't printed
before, there is a nonzero risk that a terminal mishandles it.

Terminal-specific workarounds cause pain but are probably better than not
being able to use any new commands provided by terminals.

There is no universal way to identify a terminal. Device attributes (primary
through tertiary) typically get spoofed responses, likely not good enough
for working around bugs in specific versions of a terminal.

The de-facto standard for the terminal name and version is XTVERSION.
It's usually specific to the terminal, except for something like VTE-based
terminals, where we get this (which seems good enough also)

	printf '\x1b[>0q'; cat
	^[P>|VTE(7803)^[\

Of course querying for XTVERSION can trigger terminal bugs just as well. Let's
start querying for it now -- even without a concrete use case -- to increase
the chance we can use it during crunch time when we don't want to test
anymore. (We typically discover buggy terminals only very late in the release
cycle, most prominently after a release).
2025-03-01 13:03:04 +01:00
Johannes Altmanninger
7c2388fbfc Fix bracketed paste potentially not being disabled on SIGTERM
When we enable/disable terminal protocols,
we use atomic operations because of issues like
1. halfway through enabling, we might be interrupted by a signal handler.
2. our SIGTERM handler runs the (idempotent) disabling sequences,
   so the operations must be async-signal safe.

The flags to keep track of whether things like kitty keyboard protocol are enabled
are "mirrored" between the enabling and disabling logic:

- the enabling logic marks it as enabled *before* enabling anything
- the disabling logic marks it as disabled *after* everything has been disabled

This ensures that we are well-behaved in issue 1; we will always (perhaps
redundantly) disable the kitty keyboard protocol.

We forgot to use the same ordering for bracketed paste.
If we get SIGTERM after this line

	BRACKETED_PASTE.store(false, Ordering::Release);

we might exit with bracketed paste still turned on.
2025-03-01 12:45:11 +01:00
Johannes Altmanninger
f415413bfb Strip "$ " prefixes on paste
Code blocks are often written like

	$ echo hello world
	hello world

The "$ " is widely understood to introduce a shell command.  It's often
easier to copy the whole line than copying everything after "$ ".

This gets more pronounced when there are multiple commands without interleaved
output (either due to omission or the rule of silence). Copying the whole
code block is the most natural first step.

You could argue that this is a presentation issue - the dollar prefix
should be rendered but not copied to clipboard. But in my experience there
are many cases where there is no HTML or Javascript that would allow the
copy-to-clipboard functionality to strip the prefixes.

The "$ " prefix is almost never useful when pasting; strip it automatically.

Privileged commands use "# " as prefix which overlaps with comments, so do
not strip that until we can disambiguate (another potential reason not to
do that would be safety but it's unclear if that really matters).

Add the new logic to the commandline builtin, because we don't know about the
AST in fish script. (Technically, the tokenizer already knows whether a "$
" is in command position and at the beginning of a line, but we don't
have that either (yet).)

Maybe we should move the rest of __fish_paste over as well. I'm not sure what
difference that would make; for one, pasting could no longer be cancelled
by ctrl-c (in theory), which seems like a good direction?
2025-03-01 07:55:53 +01:00
Fabian Boehm
303af078f3 Actually disable CSI u in iTerm < 3.5.12
Fixes #11192
2025-02-28 21:15:44 +01:00
Johannes Altmanninger
84eb06ac14 Remove unused export in Ast 2025-02-28 07:50:14 +01:00
Johannes Altmanninger
fa390f1b14 CHANGELOG: fix RST syntax for nested lists
These would all be rendered in one line.
2025-02-28 03:47:19 +01:00
Fabian Boehm
20e9fe9c95 Revert token movement bindings
Comments by macOS users have shown that, apparently, on that platform
this isn't wanted.

The functions are there for people to use,
but we need more time to figure out if and how we're going to bind
these by default.
For example, we could change these bindings depending on the OS in future.

This reverts most of commit 6af96a81a8.

Fixes #10926
See #11107

(cherry picked from commit 378f452eaa)
2025-02-27 21:10:07 +01:00
Fabian Boehm
a9c61394a8 README: Update Ubuntu PPA version
Fixes #11180
2025-02-27 19:43:45 +01:00
David Adam
ede3f81eef Merge branch 'Integration_4.0.0' 2025-02-27 22:51:11 +08:00
David Adam
5e2ddaace9 debian packaging: use the correct test target 2025-02-27 22:46:23 +08:00
Mo Bitar
11b6fad7ba Fix tag 2025-02-27 22:18:50 +08:00
Laurențiu Nicola
f224ff1d28 Fix create-base-directories.fish with SELinux 2025-02-27 10:33:22 +08:00
David Adam
b82d0fcbcc docs/source: document changes from #10774 2025-02-26 21:30:57 +08:00
David Adam
8ec1a3e7b9 docs/bind: improve description of cancel binding
Closes #9644
2025-02-26 21:23:40 +08:00
Fabian Boehm
3688dd01ba fixup! import sys
I always forget that's not a builtin.
2025-02-21 17:54:25 +01:00
Fabian Boehm
1835f141eb Disable tmux-multiline-prompt.fish and fkr.py tests on CI
See #11036
2025-02-21 17:46:26 +01:00
Fabian Boehm
750fe3bcc1 docs/bind: More on how default mode is normal mode 2025-02-20 19:08:24 +01:00
Fabian Boehm
6c9e6b3baf functions/help: Fix version number for betas 2025-02-19 21:47:00 +01:00
Johannes Altmanninger
afbdb9f268 Fix off-by-one error in new commandline --column
parse_util_lineno() returns 1-based line numbers but
parse_util_get_offset_from_line() expects zero based line offsets.

Fixes #11162
2025-02-19 10:44:00 +01:00
Johannes Altmanninger
72f2433120 Fix search field state not resetting after search field is hidden
Commit 4f536d6a9b (Update commandline state snapshot lazily,
2024-04-13) add an optimization to update the search field only if
necessary.  The optimization accidentally prevents us from resetting
the search field.

Fixes #11161
2025-02-19 10:44:00 +01:00
Peter Ammon
5e38a2a46b Get tmux-history-search2.fish passing on macOS 2025-02-16 13:02:23 -08:00
Peter Ammon
22b944ef4b Get tmux-complete2.fish passing on macOS 2025-02-16 11:44:43 -08:00
Fabian Boehm
8657362d86 Staticbuilds: Only build the fish binary
These are supposed to be small, so we dump the redundant fish_indent
and fish_key_reader - the fish binary can do those jobs too (both as
builtins and if called via symlinks of that name).

We still keep tarballs instead of just compressing so that we have a
file called "fish" and not "fish-amd64-linux"
2025-02-13 20:57:17 +01:00
David Adam
b2eebbe194 docs/interactive: add ctrl-n Vi mode documentation
Noted missing in #11082.
2025-02-13 00:12:34 +08:00
Łukasz Wieczorek
82750bbaec Reformat with black. 2025-02-12 22:59:27 +08:00
David Adam
d32c455269 src/env_dispatch: add clarifying comment for setenv 2025-02-12 22:27:53 +08:00
David Adam
4cb5927e7a rename curses module to terminal
There's no actual use of curses here, just terminfo.
2025-02-12 22:26:23 +08:00
David Adam
ffdec4b485 src/curses: drop CURSES_INITIALIZED lock
setupterm/cur_term does not get used any more
2025-02-12 21:57:27 +08:00
Johannes Altmanninger
cad42a0e53 Fix regression stomping commandline when completing after history search
Commit 82c4896809 (Fix unnecessary undo when exiting the history
pager with an empty cmd and no matches, 2025-02-02) was a nice fix
but failed to account for the code path where we switch from history
search to completion pager (and maybe also the inverse case).  In this
case we don't want to undo the transient edit but commit it instead.
2025-02-12 14:24:06 +01:00
Johannes Altmanninger
b4b0b42792 Tweak replacing completions for directory-variable name
If we're only inserting a prefix of the variable name we're not gonna
add a space. We don't want to add a slash either.
2025-02-12 14:24:06 +01:00
Johannes Altmanninger
7197bc7760 Add a test for replacing completions of directory-variable name 2025-02-12 14:23:45 +01:00
David Adam
15ca164773 BSD/GNUmakefile: update to use new fish_run_tests target 2025-02-12 08:56:38 +08:00
Fabian Boehm
b6fe6b7bf4 Allow fish_indent builtin to be redirected
Missed write_to_fd calls

Not in 4.0 because fish_indent isn't a builtin there.

This requires str2wcstring, which is awkward but it's not performance-sensitive.

Fixes #11146
2025-02-11 22:19:44 +01:00
Fabian Boehm
3350145371 Reader: Fix crash completing incomplete variable name
Regression in 4.1, not present in 4.0.

Fixes #11148
2025-02-11 22:17:09 +01:00
idealseal
7accf4ffa1 feat(comp): update to systemd 257 2025-02-11 22:52:42 +08:00
Max Jacobson
d47a4899b4 Fix formatting of abbr example
I'm running fish 4.0b1 locally and I tried running `help abbr` and
browsing the docs. I noticed one example which wasn't formatted
correctly.

I'm not too familiar with rst, but based on looking at the file, it
seems that this is how example code should be represented.
2025-02-11 22:51:06 +08:00
David Adam
2849cd11ae completions/elm: remove = in long options
elm's argument parser copes just fine without them

Review comment from
https://github.com/fish-shell/fish-shell/pull/10759#discussion_r1786918645
2025-02-11 22:27:53 +08:00
Kemel Zaidan
df6bd36e82 adds completion for the default Elm cli tool 2025-02-11 22:21:18 +08:00
Roland Fredenhagen
d862e7bf26 Complete entries for bootctl
Uses `jq` to parse and doesn't add these extra completions if not available.
2025-02-10 22:15:57 -08:00
Johannes Altmanninger
4b20e3ad91 Back out "Feature flag to prevent executing off buffered keys"
e697add5b5 (Feature flag to prevent executing off buffered keys, 2025-01-02)
breaks my expectations/habits, and it breaks Midnight Commander.
Additionally, I'm not aware of any case where it actually adds security.
We generally assume that terminal echoback sequences do not contain
control characters except for well-known escape sequences.

This backs out commit e697add5b5.

See #10987, #10991
2025-02-09 16:32:49 +01:00
Fabian Boehm
d418d7638a docs: Document split0 and command substitutions harder 2025-02-08 20:09:43 +01:00
Fabian Boehm
ba458052ea Staticbuilds: Update for test_driver.py
(and check for it because github workflows run from the main branch and we
might want to use this to build 4.0)
2025-02-08 18:51:47 +01:00
Fabian Boehm
a1e8628c21 docs: Document fish_clipboard_copy's OSC 52 support 2025-02-08 12:17:55 +01:00
Fabian Boehm
b50c832a35 abbr: Print optional set-cursor arg correctly
Allows the output to round-trip.

Fixes #11141
2025-02-07 12:28:59 +01:00
Fabian Boehm
414293521e tests: Use command ls to avoid indicators
This can happen if your filesystem on macOS has xattrs, so the newly
created dirs will also have them and `ls` will print an "@" indicator.

Fixes #11137
2025-02-07 12:22:23 +01:00
Johannes Altmanninger
f4503af037 Make alt-{b,f} move in directory history if commandline is empty
alt-{left,right} move in the directory history (like in browsers).
Arrow keys can be inconvenient to reach on some keyboards, so
let's alias this to alt-{b,f}, which already have similar behavior.
(historically the behavior was the same; we're considering changing
that back on some platforms).

This happens to fix alt-{left,right} in Terminal.app (where we had
a workaround for some cases), Ghostty, though that alone should not
be the reason for this change.

Closes #11105
2025-02-06 19:12:00 +01:00
Johannes Altmanninger
9e19e419a4 Back out "Remove test for broken tmux output"
Add back the test from 0e512f8033 (Fix spurious blank lines when
executing scrolled commandline, 2025-01-08).

It's flaky in CI (see b8208d72f7 (Remove test for broken tmux output,
2025-01-09)) but that's not a problem for now because we disabled
the entire test CI in 2508cc9de6 (Disable some more tests under CI,
2025-01-14).
2025-02-06 19:12:00 +01:00
Johannes Altmanninger
7db955374b Fix regression causing off-by-one pager height on truncated autosuggestion
Commit c54131c8c5 (Make at least one character of the autosuggestion
always shown, 2025-01-26) draws autosuggetion until exactly the end
of the line, possibly truncated by an ellipsis.  The line is "barely"
soft-wrapped; no characters or cursors are on the next line.

This means that the pager can start there (on the next line).
The calculation for available pager height fails to recognize that.
Fix that.
2025-02-06 19:12:00 +01:00
Fabian Boehm
8ddb078db8 reader: Only maintain cursor position in non-empty prefix search
Otherwise this would always move the cursor to the beginning.

Fixes #11133

(cherry picked from commit db244e0492)
2025-02-05 22:14:47 +01:00
Fabian Boehm
9490c74746 Remove tparm0
This does not do anything
2025-02-05 17:00:25 +01:00
ridiculousfish
49c848ed42 Optimize wcstod_underscores
Prior to this change, wcstod_underscores would create a "pruned" string without
underscores, and then parse that. Switch instead to a filtered Iterator, which
can ignore underscores as it traverses the string.

Add a test that completes in a reasonable time only if wcstod_underscores is not
quadratic.

(cherry picked from commit b4577c10e5cf9239bc93c605f431a56d98266a1e)
2025-02-05 17:00:25 +01:00
kerty
82c4896809 Fix unnecessary undo when exiting the history pager with an empty cmd and no matches
Currently, when the history pager is selected, fish always one undo away from the original search term. If the search has no matches, the fish replaces the search term with itself (resulting in no visible change, but it is still treated as a transient edit). However, fish ignores undo operations where the replacement is "" by "", leading to an unnecessary undo. For example:
1. Type 'test'.
2. Do ctrl-c.
3. Open the history pager.
4. Make so there are no matches.
5. Exit - you will undo back to 'test'.

This commit also ensures that if you select a pager element that does not change the content of the commandline, it will not be added to the undo history.
2025-02-04 10:12:30 +01:00
kerty
5e4f801ad5 Fix unnecessary undo in backward history search after returning to the present
Currently, if we return to the present, fish thinks that it still has a transient edit. This results in an unnecessary undo when performing a backward search. For example:
1. Type ': '.
2. Do a backward token search.
3. Do a forward token search.
4. Do another backward token search - this will result in the undo of ': '.
2025-02-04 10:12:30 +01:00
kerty
c1c23269d2 Don't restart search if we maintain search mode
Currently, the search always restarts when moving from the present.
For example:
1. Do a few backward searches.
2. Use PageDown to return to the present.
3. Do another backward search.
4. Now, PageUp does nothing because the search was restarted, even if we maintained search mode.
2025-02-04 10:12:30 +01:00
Peter Ammon
8a86b4e4fc Remove some stale comments 2025-02-03 15:55:55 -08:00
phanium
1d827d1d2d Fix twice tokenize editor_cmd
```fish
export VISUAL='nvim --cmd let\ g:flatten_wait=1'
funced -s fish_prompt
```

`editor_cmd[3]` would be `let` rather than `let g:flatten_wait=1`
2025-02-02 16:20:12 -08:00
Peter Ammon
7c32cb1b44 Put back noun form of "licence" in mksquashfs comment 2025-02-02 11:48:37 -08:00
Fabian Boehm
8d6fdfd9de Remove cmake "test" target
This can no longer be overridden, which means we have a broken "test"
target now. Instead, you need to call "make fish_run_tests".

Blergh.

Fixes #11116
2025-02-02 13:41:43 +01:00
ccoVeille
0df6fa7915 Fix typos in completions scripts 2025-02-02 17:15:11 +08:00
Ilya Grigoriev
5dd6759d01 completions/tmux: replace embedded tabs with \t 2025-02-01 17:37:38 -08:00
Ilya Grigoriev
2b6f6b8cbc completions/tmux: basic window argument completions 2025-02-01 17:37:38 -08:00
Ilya Grigoriev
5d0e2244bb completions/tmux: add ability to complete buffer names and commands
This adds the ability to complete (and therefore preview) buffer names,
and adds incomplete (aiming to maximize utility/effort, similarly to
b1064ac) bindings to the `tmux` buffer commands.

The main benefit is, IMO, is the tab completion for `tmux paste-buffer
-b` and `tmux show-buffer -b`.
2025-02-01 17:37:38 -08:00
Johannes Altmanninger
66e2b6d8c1 Fix query response wait confusion over builtin read
Every reader gets their own wait handle which is wrong and not actually
needed - it's a singleton.  We should probaly make it global. Let's
do an intermediate solution for now -- not much time this weekend ;).

Fixes #11110
2025-02-01 09:25:53 +01:00
Mahmoud Al-Qudsi
cbedfc8a64 Use Write::write_all(), not write()
There is no guarantee that Write::write() will write the entirety of the
provided buffer in one go, regardless of how short it is, because that depends
on the semantics of the underlying write handle (even if it was a
single byte, though in this case that would be because of an interrupt).

The only case I'm aware of that would guarantee a single Write::write() call
would suffice is when writing into a high-level memory-backed buffer, and we
can't make that guarantee (now or in perpetuity).
2025-01-31 11:25:56 -06:00
Fabian Boehm
9a46b66d04 Increase default read limit to 1GiB
The current limit can be reached in actual use and still be a usable shell.

E.g. in #11095 someone had `git status` print over 100MiB of file
information.
2025-01-31 16:44:25 +01:00
Fabian Boehm
5eee4fc2c7 completions/git: Don't set the read limit
This isn't propagated correctly:

If $fish_read_limit is set globally, it won't apply to the completion
command substitution, *unless* you set fish_read_limit inside of that
function.

I'm not entirely sure how that happens, but let's work around it for
now by removing that limit.

I'm going to increase the default limit in a future commit, because
it's not something supposed to be reachable in ordinary code.

See #11106
2025-01-31 16:37:26 +01:00
Fabian Boehm
6d8f1aeb27 Reset read_limit back to default
Regression introduced in 6638c78b30

Reintroduces #9129

It's unclear why the tests didn't fail
2025-01-31 16:31:39 +01:00
kerty
bfb32cdbd9 Improve calculation of offset for width 2025-01-31 13:37:27 +01:00
kerty
c54131c8c5 Make at least one character of the autosuggestion always shown
Previously, there were situations where an autosuggestion existed but was not shown at all. This commit guarantees that at least the `ellipsis_char` is shown, regardless of the situation.
2025-01-31 13:37:27 +01:00
kerty
0ecf4b1ce0 Fix inconsistent autosuggestion truncation on soft wrapped lines
This commit ensures that autosuggestions cannot soft wrap. Previous behavior:
- If the first line is not soft wrapped, the autosuggestion will be truncated and not shown on soft-wrapped lines.
- If the first line is soft-wrapped, the autosuggestion will not have any limit.
2025-01-31 13:37:27 +01:00
kerty
be95b176bc Fix incorrect first line checks in rendering
The right prompt was rendered even if scrolled.
The command line wasn't rendering on the first line, starting from 0 to the left prompt length. Steps to reproduce:
fish -C 'bind ctrl-g \'commandline $(printf %0"$(math $COLUMNS)"d0) $(seq $(math $LINES - 1))\''
# use ctrl-g
# observe that only one '0' is rendered
2025-01-31 13:37:27 +01:00
kerty
e2c9969840 Fix deletion of prompt in last 2 columns when first line soft wrapped
When drawing a soft wrapped line, the last 2 characters of the previous line are redrawn. If these 2 characters are occupied by the prompt, they are replaced with ' '.
Steps to reproduce:
fish -C 'function fish_prompt; printf %0"$(math $COLUMNS)"d 0; end'
# type anything
# observe that the last two characters of the prompt have been deleted
2025-01-31 13:37:27 +01:00
kerty
9915a07741 Convert Screen::write_char() to usize 2025-01-31 13:37:27 +01:00
kerty
7acc2b7223 Fix pager occupying empty soft wrapped lines
We need to add a line to the desired screen if the previous line was full or non-existent to prevent the pager from being drawn on empty soft wrapped or new lines.
Steps to reproduce:
fish -C '
    function fish_prompt; printf \>; end
    bind ctrl-g \'commandline  "ls $(printf %0"$(math $COLUMNS - 5)"d 0) "\''
# use ctrl-g and tab
# observe that the pager starts on the line with the cursor
2025-01-31 13:37:27 +01:00
kerty
5ecf5aef8a Fix regression causing variable completions to not have description
Regressed in 17bd7d0 (Switch completion_request_options_t from a list of flags to a struct, 2022-06-07).
2025-01-31 13:37:27 +01:00
kerty
1339da330e Fix crash when clicking on empty lines
This fixes a crash that occurred in Kitty when clicking on lines without characters, such as soft wrapped lines or first line without a prompt.
2025-01-31 13:37:27 +01:00
kerty
6bb19cf1f4 Fix not emitting osc_133_prompt_start without prompt
If the left prompt is defined to be empty, osc_133_prompt_start would not be emitted at all.
2025-01-31 13:37:27 +01:00
kerty
d667ec5061 Remove space for prompt if it occupies full line
If the prompt occupies the full width of the first line, each new line will soft wrap, leaving empty lines between. This change removes the indentation that matches the start of the line to the end of the prompt if the prompt width equals the terminal width.

Steps to reproduce:
fish -C 'function fish_prompt; printf %0"$COLUMNS"d 0; end'
# type "begin" and Enter
# observe that there was a spurious empty line
2025-01-31 13:37:27 +01:00
Fabian Boehm
e63fea1127 reader: only flash entire commandline if token is empty
So `git add dsfiojdsoif<TAB>` flashes the token, `git add <TAB>`
flashes the entire commandline because there is no token to flash
2025-01-30 17:13:09 +01:00
Fabian Boehm
4ae3c487a6 reader: flash entire commandline if there's no completion
This is often the case if the token is empty, e.g `git add <TAB>`
outside of a git repo.
2025-01-30 16:24:35 +01:00
Fabian Boehm
6c4d658c15 pager: fix selected color regression
To check:

```fish
fish_config theme choose None
set -g fish_pager_color_selected_completion blue
```

Now the selected color will only apply to the parentheses

Missed in 43e2d7b48c (Port pager.cpp)
2025-01-30 16:22:07 +01:00
Fabian Boehm
ba193665e2 completions: Add missing options for our builtins 2025-01-29 20:38:41 +01:00
Fabian Boehm
66f1aba0f2 completions/commandline: Add missing options 2025-01-29 20:17:46 +01:00
Fabian Boehm
ef4fad763f Remove fish.desktop harder 2025-01-29 17:21:14 +01:00
Justin Zobel
a42c5b4025 Remove fish.desktop file as it was only needed for AppImages which were decided against. 2025-01-29 17:19:39 +01:00
David Adam
be48d73599 docs/fish: minor style/proofing edits 2025-01-29 20:28:00 +08:00
David Adam
1cf71656ef docs/language: update target release for feature flags from 3.8 to 4.0
see also 24abbb6de7
2025-01-29 20:27:14 +08:00
Johannes Altmanninger
acf9ba4195 Fix regression causing missing automatic history saving after adding ephemeral items
Commit f36f757fa6 (Never rewrite history file when adding ephemeral
items, 2024-10-06) has a glaring bug: when adding to history ephemeral
items that has potential paths, we fail to re-enable automatic saving,
which effectively disables automatic saving for the entire session.

Only a call to history::save_all() at exit saves us from losing data.
But until exit, other fish will see our history (unless we run history
save/merge or similar).

Fix the imbalanced enable/disable and restructure the code a bit.
Also, extend the change from f36f757fa6 (never vacuum on ephemeral
items) to private mode.
2025-01-29 10:16:19 +01:00
Ilya Grigoriev
064d867873 language.rst: make description of features more consistent (minor)
The version where a feature became the default is now described inline,
to make it a single source of truth. I could have fixed the other
section where this was described, but this seemed easier.

I also removed a few details that seem no longer relevant.
2025-01-28 21:23:45 -08:00
David Adam
2184aaf9b4 completions/acpi: correct the -c option as cooling
Closes #11068.
2025-01-28 21:47:05 +08:00
Ilya Grigoriev
f241187c4a completions/tmux: some windows and panes boolean flag completions
This documents some non-argument options for the window and panes
commands. The choice of what to document is somewhat arbitrary,
this commit is biased towards options that I find confusing or
misleading without documentation (is `-a` "all" or "after"?)
and the command that seem more useful to me.

I also didn't cover the options that would be covered by
#10855 (though this PR can be used independently). I'm not
sure how much difference this made, it might not matter at
all.
2025-01-28 21:38:34 +08:00
Ilya Grigoriev
77406ddd11 completions/tmux: complete commands inside tmux lscm
Make `tmux lscm <tab>` work.
2025-01-28 21:37:16 +08:00
Ilya Grigoriev
183e20cc3a completions/tmux: complete all flags when tmux lscm is available
These dynamic completions are exhaustive, but not as well-documented or
as ergonomic as the manual completions. So, any manual completions
should override them.
2025-01-28 21:37:16 +08:00
Ilya Grigoriev
27e5ed7456 completions/tmux: complete all subcommands when tmux lscm works
For example, `tmux shell<tab>` now completes to `if-shell` and
`run-shell`, though no additional information is provided.
2025-01-28 21:37:16 +08:00
Johannes Altmanninger
d2b2c5286a Fix regression decoding function keys
Commit 109ef88831 (Add menu and printscreen keys, 2025-01-01)
accidentally broke an assumption by inverting f1..f12.  Fix that.

Fixes #11098
2025-01-27 21:49:29 +01:00
Fabian Boehm
9116c61736 completions/nmcli: Complete at runtime
This used to get all the interfaces and ssids when the completions
were loaded. That's obviously wrong, given that ssids especially can, you know, change
2025-01-27 20:46:38 +01:00
Fabian Boehm
4370fb755d completions/git: Handle untracked files separately
This uses `git ls-files`, which has a simpler format (just the
filenames on separate lines), in order to print the untracked files.

This allows us to skip them in the `git status` call, which reduces
the output a lot and removes two `string match`.

In a repository with over half a million files (my home directory, if
I made it one), this improves time by a third (12s to 8s).

In a smaller repo (fish-shell) it's barely measurable.
2025-01-27 18:24:08 +01:00
kerty
514f4b9e23 Rename some methods of ReaderHistorySearch to improve clarity 2025-01-27 18:19:04 +01:00
Johannes Altmanninger
b73c8abb79 Fix regression causing crash when history token search hits end
This is consistent with what we do for highlighting history search,
see d7354880e3 (Fix regression causing crash in token history search,
2025-01-27).  In future, we should try to find a better fix (and a
better test).

Fixes the other problem described in #11096
2025-01-27 18:13:07 +01:00
Fabian Boehm
5c81e18b2e completions/git: Handle gigantic repos better
Determine if untracked files are off via `__fish_git`, so we get the
repo used on the commandline etc,

and if it isn't, at least don't error out. Yes, this *can* print a
hundred megabytes of filenames.
2025-01-27 17:52:32 +01:00
Fabian Boehm
bba15c6d14 completions/csvlens: Fix missing option 2025-01-27 17:51:35 +01:00
Johannes Altmanninger
d7354880e3 Fix regression causing crash in token history search
I'm not yet sure how to reproduce 4dfcd4cb4e (reader: Check bounds
for color, 2022-08-26).  Commit 55fd43d86c (Port reader, 2023-12-22)
accidentally changed historical behavior, fix that.

Fixes #11096
2025-01-27 06:32:15 +01:00
Johannes Altmanninger
fff421ad9c Work around mc and dvtm not responding to Primary DA
The two terminals Midnight Commander and dvtm are special in that
they filter requests (or perhaps responses) like

	printf "\x1b[0c"

and don't implement the response themselves -- so we never get
one. Let's work around that until we can fix it.

Disable the kitty protocol in mc for now (to keep the code simple),
though we could certainly re-enable it.

Fixes 64859fc242 (Blocking wait for responses to startup queries, 2025-01-25).
2025-01-27 06:32:15 +01:00
ccoVeille
90e916e164 Fix typo in tests 2025-01-26 20:30:48 -08:00
ccoVeille
0047abbe7a Fix typo in code 2025-01-26 20:30:48 -08:00
ccoVeille
b6a1bedab9 Fix typos in comments 2025-01-26 20:30:48 -08:00
Mahmoud Al-Qudsi
88c8992cc3 Add inline attribute 2025-01-26 17:21:49 -06:00
Fabian Boehm
2b2f824b94 completions/git: Handle huge repositories for "add" better
`git add` may have to go through literal megabytes of file information
because of tons of untracked files.

So, if the repository is set to not show untracked files (because it's
too slow for the prompt), let's fall back on regular file completions.

(the alternative is to go back to `while read`, but that takes much
longer in repositories of a sensible size)

Fixes #11095
2025-01-26 21:41:36 +01:00
Johannes Altmanninger
c651a79cb6 Fix regression causing builtin commandline to report wrong relative cursor
Regressed in 55fd43d86c (Port reader, 2023-12-22).

Fixes #11085
2025-01-26 15:51:05 +01:00
Johannes Altmanninger
4c28a7771e Sanitize some inputs in CSI parser
This was copied from C++ code but we have overflow checks, which
forces us to actually handle errors.

While at it, add some basic error logging.

Fixes #11092
2025-01-26 15:39:21 +01:00
Johannes Altmanninger
2d234bb676 Only request keyboard protocols once we know if kitty kbd is supported
Today we might
1. enable modifyOtherKeys
2. get a reply indicating the kitty keyboard protocol is supported
3. because of 2, we never turn off modifyOtherKeys again

Let's get rid of this weird issue by enabling either modifyOtherKeys
or the kitty enhancements only after we know whether the kitty protocol
is supported.

This means we need to call terminal_protocols_enable_ifn() before every
call to readch() until the querying is done.  Fortunately, this is
already in place in read_normal_chars(); there are other places that
call readch() but none of those is executed until querying has completed.
2025-01-26 15:39:21 +01:00
Johannes Altmanninger
64859fc242 Blocking wait for responses to startup queries
At startup we query for
- the cursor position (CSI 6 n)
- kitty keyboard protocol support (CSI ? u)
- terminfo capabilities via XTGETTCAP

Since we don't wait for responses, those can leak into child processes.
Some child processes like fzf cannot decode DCS replies.  Plug the
leak by ending each round of querying by asking for the Primary Device
Attribute, and resume input processing only after a response has been
received, (or ctrl-c as an escape hatch).

This is a nice simplification. Tested with the lowest common
denominator (putty, Terminal.app and st).

Fixes #11079
2025-01-26 14:22:52 +01:00
Johannes Altmanninger
06b49b9721 Update pexpect helper output sanitization 2025-01-26 14:19:40 +01:00
Johannes Altmanninger
630a06cf8f Work around st terminal resetting cursor on CSI ? u
The st terminal wrongly parses CSI ? u as DECRC. A fix has been
proposed upstream.  Let's also work around it I guess (not to mention
that querying in the first place is also sort of a workaround).
2025-01-26 14:19:40 +01:00
Johannes Altmanninger
95d61ea0fb Split /etc/{,man}path by colons too
I don't know how /etc/manpath ends up containing lines like
"path1:path2".  But path_helper splits them so we should do too.

4ea11424b8/path_helper/path_helper.c (L149)

Fixes #10684
2025-01-26 14:19:40 +01:00
Johannes Altmanninger
6e2c5d4365 Add trailing slash (not space) to variable name completions that produce valid paths
Closes #5798
2025-01-26 14:19:40 +01:00
Fabian Boehm
545a23734e Remove some ffi wrappers 2025-01-25 20:03:13 +01:00
Mahmoud Al-Qudsi
d69a9296a6 completions/llm: Complete model alias target 2025-01-25 12:50:03 -06:00
kerty
3fdd2d3fc2 Small refactor of HighlightSpec 2025-01-23 17:09:29 +01:00
kerty
db546da3ca Made undo/redo not update autosuggestion if failed 2025-01-23 17:09:29 +01:00
kerty
6a9f1b925d Make flash highlight autosuggestion on failed deletion 2025-01-23 17:09:29 +01:00
kerty
bffbf0cd57 Make flash highlight relevant commandline section 2025-01-23 17:09:29 +01:00
kerty
b5c869d5e7 Make parse_util_token_extent return its output instead of mutating input. 2025-01-23 17:09:29 +01:00
kerty
4994000a27 Small refactor of Reader::flash 2025-01-23 17:09:29 +01:00
ccoVeille
d5fdcc96c8 Fix typos in .rst files 2025-01-23 22:06:12 +08:00
Johannes Altmanninger
aee729bd44 Update changelog for cancel-commandline 2025-01-23 02:28:00 +01:00
Fabian Boehm
4e13ce33c5 functions/__fish_cancel_commandline: Follow rename of bind function
See #10935
2025-01-22 17:43:59 +01:00
Fabian Boehm
eab9e647f4 checks/tmux-history-pager: Disable on CI in general
Keeps failing for timing reasons and it's already quite slow.

See #11036
2025-01-21 17:32:27 +01:00
Fabian Boehm
e67819f532 Wrap libc::umask 2025-01-21 17:31:15 +01:00
Johannes Altmanninger
29cddabfe4 Fix regression causing fish_key_reader to not request kitty flags
Fixes 081c3282b7 (Refresh TTY timestamps also in some rare cases,
2025-01-15).
2025-01-21 14:09:33 +01:00
David Adam
945a535570 fish_default_key_bindings: remove duplicate ctrl-k binding
It's in the shared bindings since f9b7992.
2025-01-20 19:48:57 +08:00
Johannes Altmanninger
8208a12a76 Back out "Support help argument in "{ -h""
This backs out commit efce176ceb.
2025-01-19 18:57:21 +01:00
Johannes Altmanninger
d3c37de753 Back out "Always treat brace at command start as compound statement"
This backs out commit 98750e1ae5.
2025-01-19 18:57:21 +01:00
Johannes Altmanninger
a7fdd8d002 Back out "Back out "Remove awkward assert""
This backs out commit e0c6384ed3.
2025-01-19 18:57:21 +01:00
Johannes Altmanninger
92bd366c1b Back out "Allow if/then/fi, while/do/done and for/do/done"
This backs out commit e32572e4e6.
2025-01-19 18:57:13 +01:00
Fabian Boehm
5b0622cf00 Disable tmux-history-pager test on ASAN 2025-01-19 18:54:56 +01:00
Fabian Boehm
98a96f5b58 Revert "Swap alt-{left,right,backspace,delete} with ctrl-* on macOS"
This reverts commit ebdc3a0393.

Not discussed, includes a new thing that queries the terminal for the client OS
when what is really needed is just a `uname` - which would also work on Terminal.app.
2025-01-19 18:52:10 +01:00
Fabian Boehm
0494b1b608 tests/checks/exec: Match entire env line 2025-01-19 18:47:28 +01:00
Fabian Boehm
494bdfa013 Revert accidentally pushed fork
Revert "README for this fork"

This reverts commit 97db461e7f.

Revert "Allow foo=bar global variable assignments"

This reverts commit 45a2017580.

Revert "Interpret () in command position as subshell"

This reverts commit 0199583435.

Revert "Allow special variables $?,$$,$@,$#"

This reverts commit 4a71ee1288.

Revert "Allow $() in command position"

This reverts commit 4b99fe2288.

Revert "Turn off full LTO"

This reverts commit b1213f1385.

Revert "Back out "bind: Remove "c-" and "a-" shortcut notation""

This reverts commit f43abc42f9.

Revert "Un-hide documentation of non-fish shell builtins"

This reverts commit 485201ba2e.
2025-01-19 18:34:59 +01:00
Johannes Altmanninger
97db461e7f README for this fork 2025-01-19 18:29:07 +01:00
Johannes Altmanninger
45a2017580 Allow foo=bar global variable assignments
override fixes
2025-01-19 18:29:07 +01:00
Johannes Altmanninger
0199583435 Interpret () in command position as subshell 2025-01-19 18:29:07 +01:00
Johannes Altmanninger
4a71ee1288 Allow special variables $?,$$,$@,$# 2025-01-19 18:29:07 +01:00
Johannes Altmanninger
4b99fe2288 Allow $() in command position 2025-01-19 18:29:07 +01:00
Johannes Altmanninger
b1213f1385 Turn off full LTO 2025-01-19 18:29:07 +01:00
Johannes Altmanninger
f43abc42f9 Back out "bind: Remove "c-" and "a-" shortcut notation"
This backs out commit 6d76b938c7.
2025-01-19 18:29:07 +01:00
Johannes Altmanninger
485201ba2e Un-hide documentation of non-fish shell builtins
This makes "man exec" show the documentation from Linux man-pages.
2025-01-19 18:29:07 +01:00
Johannes Altmanninger
e32572e4e6 Allow if/then/fi, while/do/done and for/do/done 2025-01-19 18:29:07 +01:00
Johannes Altmanninger
ebdc3a0393 Swap alt-{left,right,backspace,delete} with ctrl-* on macOS
See https://github.com/fish-shell/fish-shell/issues/ 10926
2025-01-19 18:29:07 +01:00
Johannes Altmanninger
e0c6384ed3 Back out "Remove awkward assert"
This backs out commit 6126237bc4.
2025-01-19 18:29:07 +01:00
Johannes Altmanninger
98750e1ae5 Always treat brace at command start as compound statement 2025-01-19 18:29:07 +01:00
Johannes Altmanninger
efce176ceb Support help argument in "{ -h"
Unlike other builtins, "{" is a separate token, not a keyword-string
token.

Allow the left brace token as command string; produce it when parsing
"{ -h"/"{ --help" (and nowhere else).  By using a decorated statement,
we reuse logic for redirections etc.

Other syntax elements like "and" are in the builtin list, which
- adds highlighting logic
- adds it to "builtin --names"
- makes it runnable as builtin
  (e.g. "builtin '{'" would hypothetically print the man page)

These don't seem very important (highlighting for '{' needs to match
'}' anyway).

Additionally, making it a real builtin would mean that we'd need to
deactivate a few places that unescape "{" to BRACE_BEGIN.

Let's not add it to the built in list. Instead, simply synthesize
builtin_generic in the right spot.

I'm assuming we want "{ -h" to print help, but '"{" -h' to run an
external command, since the latter is historical behavior.  This works
naturally with the above fake builtin approach which never tries to
unescape the left brace.
2025-01-19 18:29:07 +01:00
kerty
f26ebac8dd Fix macOS quotation issue in test tmux-multiline-prompt.fish 2025-01-19 18:29:07 +01:00
kerty
4ce8037e73 Fix grep regex in test locale-numeric.fish 2025-01-19 18:29:07 +01:00
kerty
8116e80140 Add test for history pager 2025-01-19 18:29:07 +01:00
kerty
3436836b94 Add automatic history search page change when deleting last element on last page 2025-01-19 18:29:07 +01:00
kerty
4e965cba47 Separate SelectionMotion from HistoryPagerInvocation 2025-01-19 18:29:07 +01:00
kerty
9b14408b1b Make history search banner display start and end indexes 2025-01-19 18:29:07 +01:00
kerty
f28e43717b Fix history pager inconsistent ordering and skipping 13th elements 2025-01-19 18:29:07 +01:00
kerty
059e7424c1 Fix refreshing from deletion after forward search 2025-01-19 18:29:07 +01:00
Johannes Altmanninger
6b5ad163d3 Fix double expansion of tokenized command line
Commit 798527d79a (completions: fix double evaluation of tokenized
commandline, 2024-01-06) fixed some completions such as the "watchexec"
ones by adding "string escape" here:

	set argv (commandline -opc | string escape) (commandline -ct)

This fixed double evaluation when we later call `complete -C"$argv"`.

Unfortunately -- searching for "complete -C" and
"__fish_complete_subcommand" -- it seems like that commit missed some
completions such as sudo.  Fix them the same way.

Alternatively, we could defer expansion of those arguments (via
--tokens-raw), since the recursive call to completion will expand
them anyway, and we don't really need to know their value.

But there are (contrived) examples where we do want to expand first,
to correctly figure out where the subcommand starts:

	sudo {-u,someuser} make ins

By definition, the tokens returned by `commandline -opc` do not
contain the token at cursor (which we're currently completing).
So the expansion should not hurt us. There is an edge case where
cartesian product expansion would produce too many results, and we
pass on the unexpanded input. In that case the extra escaping is very
unlikely to have negative effects.

Fixes # 11041
Closes # 11067

Co-authored-by: kerty <g.kabakov@inbox.ru>
2025-01-19 18:29:07 +01:00
Johannes Altmanninger
7ad47c34e8 Fix regression causing scrollback-push to not clear text below cursor
If a child program crashes with some text rendered below the cursor,
we fail to clear that text. For example run vim, "pkill -9 vim" and
observe that scrollback-push fails to clean up the leftover text.
Fix that.
2025-01-19 18:29:07 +01:00
Ilya Grigoriev
a328fd995b Clarify __fish_complete_subcommand comment 2025-01-19 10:49:07 +01:00
Ilya Grigoriev
bcc69da569 tmux completions: complete shell commands 2025-01-19 10:49:07 +01:00
Dmitry Gerasimov
dfa77e6c19 completions/git: show custom aliases for --pretty option
Custom formats for --pretty/--format option can only be written in [pretty]
section, thus only this section is searched.

[ja: add ? to the regex]

Closes #11065
2025-01-19 10:48:01 +01:00
Dmitry Gerasimov
9752b83e65 completions/git: update supported git format options
--format=reference is supported since git 2.25
--format=mboxrd is supported since git 2.27
2025-01-19 10:48:01 +01:00
Ilya Grigoriev
4208798585 completions: add unbuffer completions
unbuffer is sometimes bundled with `expect` (which fish already ships
completions for), and sometimes is bundled separately. It's often
recommended for forcing colors to have color output.

https://manpages.debian.org/bookworm/expect/unbuffer.1.en.html

Ads for unbuffer:

https://wiki.archlinux.org/title/Color_output_in_console#Reading_from_stdin
https://jvns.ca/blog/2024/10/01/terminal-colours/
2025-01-19 10:46:55 +01:00
Mahmoud Al-Qudsi
8a6ba7fc4c Silence unused_imports on newer compilers 2025-01-18 17:10:51 -06:00
Fabian Boehm
f2d2632eca fixup! Add IsSomeAnd backport 2025-01-18 10:00:23 +01:00
Fabian Boehm
1123169bbd Remove some uses of unsafe
libc::getpid and getpgrp *cannot fail*, so an unsafe declaration here
is just noise.

I mean sure, if your libc is broken and these fail, but at that point
I'm comfortable declaring your computer a platypus that we do not need
to support.
2025-01-18 09:55:46 +01:00
Fabian Boehm
79320e3ba7 Remove some .unwrap() 2025-01-18 09:55:44 +01:00
Fabian Boehm
5d55dd9879 docs/fish: Add invocation examples 2025-01-17 20:27:36 +01:00
Fabian Boehm
fb2caf63e5 Fix error for "fish --foo" without option argument
Wgetopt needs a ":" at the beginning to turn on this type of error.

I'm not sure why that is now, and we might want to change it (but tbh
wgetopt could do with a replacement anyway).

Fixes #11049
2025-01-17 10:03:19 +01:00
Johannes Altmanninger
ba4ead6ead Stop saving autosuggestions that we can't restore
Sorry, commit 51adba6ee0 (Restore autosuggestion after corrected
typo, 2025-01-10) was pushed too early.  One issue is that it saves
autosuggestions also when we edit in the middle, where we can't
restore it.  We'd still restore it in some cases, even though it
doesn't apply. This breaks invariants that may cause various problems
when interacting with the autosuggestion.

Fix it by only saving the autosuggestion when we will be able to
restore it correctly.
2025-01-17 09:58:26 +01:00
Johannes Altmanninger
3d797b9eb8 Refactor autosuggestion saving lifecycle a bit 2025-01-17 09:58:26 +01:00
Fabian Boehm
1516c08e89 fmt 2025-01-16 19:55:59 +01:00
Fabian Boehm
6e6495664c Don't clone argv for builtins
We capture the process already, and we use argv by reference for the
other cases.

argv can be big, and this reduces allocations and thereby memory usage
and speed.

E.g. `set -l foo **` with 200k matches has 25% reduced memory usage
and ~5% reduced runtime.
2025-01-16 19:32:15 +01:00
Fabian Boehm
ced5569a25 format
I didn't touch these lines?
2025-01-16 16:42:52 +01:00
Fabian Boehm
37e3111069 Don't send modifyOtherKeys if kitty protocol is supported
No use in doing this and it would trigger an ugly log message from kitty.
2025-01-16 16:37:04 +01:00
Fabian Boehm
6126237bc4 Remove awkward assert
We should really stop asserting for things that at worst don't show an
autosuggestion.

Fixes #11055
2025-01-16 13:03:11 +01:00
Johannes Altmanninger
0cc7ee5511 Fix regression causing crash on unconsumed }
Fixes #11052
2025-01-16 04:40:21 +01:00
David Adam
dd2b9943a7 make_tarball: generate debug binaries
The extended build time isn't worth it for an executable which is run once then thrown away.
2025-01-15 23:29:42 +08:00
David Adam
d6e001ac7e fix tests for 24abbb6de7 2025-01-15 23:28:08 +08:00
David Adam
24abbb6de7 feature_flags: update target release for 3.8 flags to 4.0 2025-01-15 22:11:28 +08:00
Johannes Altmanninger
1bf2b43d30 Allow { } for command grouping, like begin / end
For compound commands we already have begin/end but

> it is long, which it is not convenient for the command line
> it is different than {} which shell users have been using for >50 years

The difference from {} can break muscle memory and add extra steps
when I'm trying to write simple commands that work in any shell.

Fix that by embracing the traditional style too.

---

Since { and } have always been special syntax in fish, we can also
allow

	{ }
	{ echo }

which I find intuitive even without having used a shell that supports
this (like zsh. The downside is that this doesn't work in some other
shells.  The upside is in aesthetics and convenience (this is for
interactive use). Not completely sure about this.

---

This implementation adds a hack to the tokenizer: '{' is usually a
brace expansion. Make it compound command when in command position
(not something the tokenizer would normally know). We need to disable
this when parsing a freestanding argument lists (in "complete somecmd
-a "{true,false}").  It's not really clear what "read -t" should do.
For now, keep the existing behavior (don't parse compound statements).

Add another hack to increase backwards compatibility: parse something
like "{ foo }" as brace statement only if it has a space after
the opening brace.  This style is less likely to be used for brace
expansion. Perhaps we can change this in future (I'll make a PR).

Use separate terminal token types for braces; we could make the
left brace an ordinary string token but since string tokens undergo
unescaping during expansion etc., every such place would need to know
whether it's dealing with a command or an argument.  Certainly possible
but it seems simpler (especially for tab-completions) to strip braces
in the parser.  We could change this.

---

In future we could allow the following alternative syntax (which is
invalid today).

	if true {
	}
	if true; {
	}

Closes #10895
Closes #10898
2025-01-15 11:18:46 +01:00
Johannes Altmanninger
349f62cd7c Sort enum-like AST nodes 2025-01-15 10:54:50 +01:00
Johannes Altmanninger
10dd8a8e73 Add range to closing-unopened brace error
The error on "echo }" is needlessly inconsistent with "echo )" and
"echo (}" etc; fix that I guess.
2025-01-15 10:54:18 +01:00
Johannes Altmanninger
3a6e87744b Minor formatting fixes 2025-01-15 10:54:18 +01:00
Johannes Altmanninger
67ccbdae96 Refine errors on "begin; case"
This will also give better errors for unbalanced braces (which are
sigils for begin/end), see a following commit.
2025-01-15 10:54:18 +01:00
Johannes Altmanninger
debfdf0a39 Fix inconsistent error message on quoted keyword
Commit bdfbdaafcc (Forbid subcommand keywords in variables-as-commands
(#10249), 2024-02-06) banned "set x command; $x foo" because the
parser will not recognize "$x" as decorator.
That means that we would execute only the builtin stub,
which usually exist only for the --help argument.

This scenario does not apply for keywords that are quoted or contain
line continuations. We should not treat «"command"» differently
from «command».  Fix this inconsistency to reduce confusion.
2025-01-15 10:54:18 +01:00
Johannes Altmanninger
6d18f57e96 Make ! a builtin too, fixing "! -h"
UnLike other aliases (":.["), ! is special in the grammar but in the
few cases like "! -h" where we parse it as decorated statement they
are equals. Add it to the built in list, so the help argument works.

It can still be overridden, so this should not break anything.
2025-01-15 10:54:18 +01:00
Johannes Altmanninger
373bb56441 Treat '!' as super-command (it's not reserved!)
Other sigil-aliases ('[' and '_') are reserved words that cannot be
redefined as function. Only '!' is not.

Whereas several users define "function !!", I
found only one public occurrence of "function !":
5c7f87ed07/fish/functions/!.fish

Note that "function !" only works if invoked as "!", "! -h" or
"! --help" or "foo | !".  In most other cases we parse it as negation.

We should probably make it a reserved word to reduce confusion.
If we do that, we should also add it to __fish_print_help, to make
"! -h" work.

For now let's rearrange the code so we can recognize "!" as
super-command. This fixes completion-based autosuggestions on "! ".
2025-01-15 10:54:18 +01:00
Johannes Altmanninger
e678fb8578 Fix autosuggestions on quoted subcommand keyword
The commandline "and fis" rightly gets command autosuggestions whereas
"'and' fis" wrongly gets file autosuggestions.  The former works via
a hack. Extend it to quoted keywords.
2025-01-15 10:54:18 +01:00
Johannes Altmanninger
80a6ece45b Make newline after "else" optional
This makes it consistent with "else if", and with other shells.
2025-01-15 10:53:09 +01:00
Johannes Altmanninger
f5b2928cbb Refactor subcommand keyword detection
This file has bitrotted; for example commit bc66921ac9 (Optimize
keyword detection, 2019-04-03) removed use of SKIP_KEYWORDS but
confusingly it's still around (even after 0118eafee1 (Remove unused
functions, members (and a variable), 2022-04-09).

Also some keywords appear in multiple lists; the separate lists are
not really used today; there is a comment stating they may be useful
in future.

It would be great to add an optimization back but either way we should
present the set of reserved words in source code as a contiguous list,
to make it easy for humans to see all relevant information.
2025-01-15 10:53:09 +01:00
Johannes Altmanninger
c7adb572d0 Address clippy lints 2025-01-15 10:53:09 +01:00
Johannes Altmanninger
de6c4f85bc Don't put every enum-like AST nodes in a box
StatementVariant needs an indirection because for example NotStatement
may contain another whole statement (error[E0072]: recursive type
has infinite size).

This is dealt with by putting each StatementVariant in a Box.
This Box was also used by the AST walk implementation to implement
tagged dispatched for all variant AST nodes (see "visit_union_field").
Because of this, all other variant AST are boxed the same way, even
though they may not by cyclic themselves.

Reduce confusion by boxing only around the nodes that are actually
recursive types, and use a different tag for static dispatch.
This means that simple nodes like most normal commands and arguments
need one fewer allocation.
2025-01-15 10:53:09 +01:00
Johannes Altmanninger
9fd1fd366c Remove stale todo comment
This has been fixed.
2025-01-15 10:53:09 +01:00
Johannes Altmanninger
24a32d5202 Fix format string for internal parser error 2025-01-15 10:53:09 +01:00
Johannes Altmanninger
3695c349c6 Note "Restore autosuggestion after corrected typo" in changelog
Seems easy enough to explain, and somewhat noticeable. Let's see if
it causes problems.
2025-01-15 10:53:09 +01:00
Johannes Altmanninger
40f5aac764 Fix forward-token hiccup at operators
For better or worse, backward-token completely skips over operators
like > & |.
forward-token is (accidentally?) inconsistent with that. Fix that.

Skipping over those tokens might be wrong weird.  Maybe not for
redirections since they are tighly coupled to their target.  Maybe we
can improve this in future.
2025-01-15 10:52:43 +01:00
Johannes Altmanninger
674b7b6f92 Reject commandline --search-field --tokens*
As of today, it makes no sense to tokenize the search field.
We already reject arguments like --current-process.
Extend that to the --tokens family.
2025-01-15 10:52:43 +01:00
Johannes Altmanninger
6f480d1d85 Also trim trailing newlines when adding to history
When pasting and executing a full line, the trailing newline character
will be included in history.

I usually manually delete the newline before executing, but sometimes
I forget. When I recall my (typically single-line) commands, it's
surprising that the cursor is on the blank second line.

The newline doesn't seem useful. Let's remove it automagically.
I wonder if anyone will be thrown off by this smart behavior.

In future, we can make this space trimming configurable, similar to
fish_should_add_to_history.
2025-01-15 10:52:43 +01:00
Johannes Altmanninger
081c3282b7 Refresh TTY timestamps also in some rare cases
As mentioned in
https://github.com/fish-shell/fish-shell/pull/11045#discussion_r1915994998,
we need to refresh TTY timestamps to avoid timing-based issues.

For some context see

	git log --grep='[Rr]efresh.* TTY'

Make things more consistent again. I don't know if all of these are
absolutely necessary, hoping to find out later (and consolidate this
logic in outputter).
2025-01-15 10:52:43 +01:00
Johannes Altmanninger
2e025cfd76 Sort match statement 2025-01-15 10:52:43 +01:00
Johannes Altmanninger
4e29dba1d5 Minimize logic 2025-01-15 10:52:43 +01:00
Johannes Altmanninger
c4b4e90031 Fix file completions for builtin fish_indent 2025-01-15 10:52:43 +01:00
Johannes Altmanninger
c12f853db2 Reformat share/{completions,functions} 2025-01-15 10:50:04 +01:00
kerty
f139d8ebed Improve mouse support 2025-01-15 00:52:15 +01:00
kerty
a0e687965e Fix unsaved screen modification 2025-01-15 00:52:15 +01:00
kerty
644c3a87e3 Refactor mtime_stdout and mtime_stderr into mtime_stdout_stderr 2025-01-15 00:52:15 +01:00
kerty
153300f6d1 Fix incorrect line count calculation 2025-01-15 00:52:15 +01:00
Fabian Boehm
2508cc9de6 Disable some more tests under CI
tmux-commandline can fail with

```
prompt 4>     commandline -i "echo $(printf %0"$COLUMNS"d)"
```

And I just can't even.

job_summary is annoyingly tight.

Also count cancel_event as a *skip*, not success.
2025-01-14 20:31:48 +01:00
Fabian Boehm
28233b0711 Make new ctrl-c behavior "clear-commandline"
And leave the old behavior under the name "cancel-commandline".

This renames "cancel-commandline-traditional" back to
"cancel-commandline", so the old name triggers the old behavior.

Fixes #10935
2025-01-14 20:01:56 +01:00
Fabian Boehm
021b18335c cmake/Tests: Default to half the cores
Saturating all cores easily leads to timeouts.

The system might be doing something else, and it only leaves at most
one core per-test.

E.g. this will cause 90% of runs to fail on a raspberry pi 4.

Note that we set CTEST_PARALLEL_LEVEL on our CI machines anyway, so
this will not affect them.
2025-01-14 17:55:09 +01:00
Fabian Boehm
23f218eb8e pexpects/bind_mode_events: Increase a timeout 2025-01-14 17:55:09 +01:00
Fabian Boehm
d32257c2d5 pexpects/wait: wait on the same line as the background jobs
The issue here is we start some short `sleep`s in the background, wait
for a prompt, and only *then* wait for jobs, and *then* check for the
job end output.

That means if the prompt takes too long, we'll read the job end
messages with the `expect_prompt`.

Instead of increasing the timeouts, just wait on the same line and
remove that prompt.
2025-01-14 16:19:07 +01:00
Fabian Boehm
37a1611b54 tests/pexpects/history: Remove a weird match
Bit of a shot in the dark, I've seen this fail and there's no real
need to match the prompt *and* the command you just ran.

(plus wc -l | string trim is unnecessary when we have count)
2025-01-14 10:57:22 +01:00
Johannes Altmanninger
24e216ae82 Fix regression causing missing autosuggestions after (
Commit 4f3d6427ce (Fix regression causing crash in "commandline -j",
2025-01-12) wasn't quite right; it mishandles the edge case where
the current process has no token, fix that.
2025-01-13 22:22:42 +01:00
Johannes Altmanninger
c77c35152d Work around old Zellij by parsing unsolicited DECRQM
Zellij 0.41.2 has a bug where it responds to

	 printf '\x1b[?2026$p'; cat -v

with '^[[2026;2$y' (DECRQM) instead of '^[[?2026;2$y' (DECRPM).

This is fixed by https://github.com/zellij-org/zellij/pull/3884

We fail to parse it, leading to an extra y added to the input queue.
Since it seems easy to work around for us, let's do that, I guess.
2025-01-13 21:58:21 +01:00
Fabian Boehm
cbbf95ee55 tests: Increase another timeout
Failed on Cirrus Alpine.

The only explanation I can come up with here is that this took over
100ms to start `true | sleep 6`.

The alternative is that it started it and then did not regain control
in 6 seconds to kill that sleep.

Part of #11036
2025-01-13 15:17:16 +01:00
Fabian Boehm
723943fd1f fish_jj_prompt: Return false if nothing was generated
That means we go on to try git etc
2025-01-13 14:54:00 +01:00
Johannes Altmanninger
b6c249be0c Back out "Escape : and = in file completions"
If you don't care about file paths containing '=' or ':', you can
stop reading now.

In tokens like

	env var=/some/path
	PATH=/bin:/usr/local/b

file completion starts after the last separator (#2178).

Commit db365b5ef8 (Do not treat \: or \= as file completion anchor,
2024-04-19) allowed to override this behavior by escaping separators,
matching Bash.

Commit e97a4fab71 (Escape : and = in file completions, 2024-04-19)
adds this escaping automatically (also matching Bash).

The automatic escaping can be jarring and confusing, because separators
have basically no special meaning in the tokenizer; the escaping is
purely a hint to the completion engine, and often unnecessary.

For "/path/to/some:file", we compute completions for "file" and for
"/path/to/some:file".  Usually the former already matches nothing,
meaning that escaping isn't necessary.

e97a4fab71 refers us to f7dac82ed6 (Escape separators (colon and
equals) to improve completion, 2019-08-23) for the original motivation:

	$ ls /sys/bus/acpi/devices/d<tab>
	$ ls /sys/bus/acpi/devices/device:
	device:00/ device:0a/ …

Before automatic escaping, this scenario would suggest all files from
$PWD in addition to the expected completions shown above.

Since this seems to be mainly about the case where the suffix after
the separator is empty, 

Let's remove the automatic escaping and add a heuristic to skip suffix
completions if:
1. the suffix is empty, to specifically address the above case.
2. the whole token completes to at least one appending completion.
   This makes sure that "git log -- :!:" still gets completions.
   (Not sure about the appending requirement)

This heuristic is probably too conservative; we can relax it later
should we hit this again.

Since this reverts most of e97a4fab71, we address the code clone
pointed out in 421ce13be6 (Fix replacing completions spuriously quoting
~, 2024-12-06). Note that e97a4fab71 quietly fixed completions for
variable overrides with brackets.

	a=bracket[

But it did so in a pretty intrusive way, forcing a lot of completions
to become replacing. Let's move this logic to a more appropriate place.

---

Additionally, we could sort every whole-token completion before every
suffix-completion.  That would probably improve the situation further,
but by itself it wouldn't address the immediate issue.

Closes #11027
2025-01-13 09:50:13 +01:00
Johannes Altmanninger
0cfc95993a Swap code blocks for completing separator suffix resp. whole token
Mainly to make the next commit's diff smaller. Not much functional
change: since file completions never have the DONT_SORT flag set,
these results will be sorted, and there are no data dependencies --
unless we're overflowing the max number of completions.  But in that
case the whole-token completions seem more important anyway.
2025-01-13 09:50:13 +01:00
Johannes Altmanninger
b46417c77b Fix broken completions for "mount -ouid="
Regressed in 2e55e34544 (Reformat, 2020-11-22).
2025-01-13 09:47:34 +01:00
Johannes Altmanninger
33d92d2a1f ctrl-u to suppress autosuggestion
ctrl-w and {ctrl,alt}-backspace do the same.
2025-01-13 09:47:34 +01:00
Johannes Altmanninger
0f4e195819 fish_jj_prompt: remove change ID
This is not really helpful because it's somewhat transient; also we
can usually use the @ alias.
2025-01-13 09:47:34 +01:00
Peter Ammon
9785824794 Factor file testing out of highlighting
Syntax highlighting wants to underline arguments that are files, and in other
cases do disk I/O (such as testing if a command is valid). Factor out this I/O
logic to untangle highlighting, and add some tests. No functional change
expected.
2025-01-12 15:10:11 -08:00
Johannes Altmanninger
4f3d6427ce Fix regression causing crash in "commandline -j"
Commit 3fcc6482cb (Fix parse_util_process_extent including too much
on the left, 2024-12-24) changed the process extent based on the
observation that "A\n\n\nB" comprises three tokens with ranges 0..1,
1..2 and 4..5. Prior to that commit, the second process extent was
2..5, which seems a bit weird because it includes newlines.

Weirdness aside, the real reason for changing it was this snippet in
the autosuggestion performer, where we compute the process extent
around cursor, and check if the line at process start matches the
cached search string.

        // Search history for a matching item unless this line is not a continuation line or quoted.
        if range_of_line_at_cursor(
            &command_line,
            parse_util_process_extent(&command_line, cursor_pos, None).start,
        ) == search_string_range

Given "A\n\n\nB" and cursor_pos=1 commit 3fcc6482cb changed the output
from 2..5 to 4..5. This brings problems:
1. leading spaces will not be included (which is probably
   inconsequential but still ugly).
2. the specified cursor position is not included in the given range.

We could paper over 2 by computing min(cursor_pos)
but that would leave 1.

For now let's revert and solve the autosuggestion issue in a less
brittle way.
2025-01-12 19:55:17 +01:00
Fabian Boehm
a1b7c36db5 cmake: Explicitly have tests depend on indent and key_reader 2025-01-12 18:05:50 +01:00
Fabian Boehm
f0eb599ff1 cmake: Remove some more dead gunk
We no longer check for in tree builds anywhere (tests set up their own
tmpdir),
and we no longer support xcode.
2025-01-12 17:52:59 +01:00
Fabian Boehm
7b30745800 cmake: Stop setting up temporary test directory
We already set up a temporary directory for each test in the
test_driver,
so let's stop doing that here.

It took a weirdly long time anyway.
2025-01-12 17:44:31 +01:00
Fabian Boehm
afb1cc21b6 Compile fish_test_helper in CMake again
That means we don't have to recompile it for every test
2025-01-12 17:40:46 +01:00
Fabian Boehm
aa77892be4 fish_indent: Read from stdin, take two
This needs to work both in builtin and command mode.

We should probably clarify how we're passing FDs around, and I suspect
we may close fds in places we don't expect.
2025-01-12 16:17:49 +01:00
David Adam
54fef433e9 Debian packaging: update dependencies
Ubuntu Focal calls the package with col "bsdmainutils", which is a
transitional package on newer version of both Debian and Ubuntu.

Closes #11037.
2025-01-12 21:19:59 +08:00
Fabian Boehm
b2fe405365 Revert "fish_indent: Correctly read from builtin stdin"
Using Arguments here breaks the `command fish_indent` case.

Probably needs to directly use a BufReader.

This reverts commit ab1b6bcea5.
2025-01-12 13:43:51 +01:00
Fabian Boehm
ab1b6bcea5 fish_indent: Correctly read from builtin stdin
This still used read_file, but we don't *really* have an fd if we're
connected to another builtin.
2025-01-12 13:15:39 +01:00
David Adam
1b0c53e30e .gitattributes: fixup e4674cd7
Actually set the attribute on the file 🤦 and also exclude the
directory.
2025-01-12 11:32:34 +08:00
David Adam
44555de69a update .gitattributes
Reflect the current state of the codebase
2025-01-12 10:46:34 +08:00
David Adam
e4674cd7b5 .cargo/config.toml: exclude from tarball
Various commits have added bits to .cargo/config.toml. Unfortunately,
this file needs to be changed by the Linux package builds (debuild, RPM,
OBS etc) with the results of `cargo vendor`, to support building in
isolated environments.

These environments - especially Debian's dpkg-buildpackage/debuild - do
not make it easy to alter a file which already exists in the tarball in
an automatic way. dpkg-buildpackage in particular requires all changes
to be made in the form of patches.

Just exclude .cargo/config.toml from the tarballs for now. This means
that the stanzas it includes _will not apply_ to builds made from
tarballs, which includes releases and development builds made using the
OBS/Launchpad PPAs.
2025-01-12 10:34:16 +08:00
Fabian Boehm
a2c48539cd cmake: Remove cachedir for test_driver
This can race when compiling fish_test_helper (one process compiles,
the other checks, ...)

Part of #11036
2025-01-11 22:08:18 +01:00
Fabian Boehm
d9f3cf332c deny.toml: Add Unicode license 2025-01-11 21:14:01 +01:00
Fabian Boehm
b43b0e0195 Rewrite test driver in python (#11028)
This replaces the test_driver.sh/test.fish/interactive.fish system with a test driver written in python that calls into littlecheck directly and runs pexpect in a subprocess.

This means we reduce the reliance on the fish that we're testing, and we remove a posix sh script that is a weird stumbling block (see my recent quest to make it work on directories with spaces).

To run specific tests, e.g. all the tmux tests and bind.py:

tests/test_driver.py target/release/ tests/checks/tmux*.fish tests/pexpects/bind.py
2025-01-11 21:13:19 +01:00
Johannes Altmanninger
51adba6ee0 Restore autosuggestion after corrected typo
Backspace signals that the user is not happy with the commandline,
and by extension the autosuggestion.

For this reason, backspace suppresses autosuggestions until the next
text insertion.

However if I
1. type something that has an autosuggestion
2. type *one* wrong letter (removing the autosuggestion)
3. type backspace

backspace does not visibly suppress any autosuggestion but rhater
signal that the user wants to go back to the previous state of the
commandline, which does have an autosuggestion.

Enable this scenario by caching the autosuggestion when it's
invalidated. On certain edits that make the cached autosuggestion
valid again, restore it from the cache.  Currently, only do this up
to a single backspace.  Could extend that in future.

This implementation is really bad.. but it's a start.
Weirdly, it does not restore the cache on undo; but that's
inconsequential because undo doesn't suppress autosuggestion as
of today.

Closes #3549
2025-01-11 18:58:49 +01:00
kerty
d06ee1ee9c Fix .cpp to .rs and redundant closure 2025-01-11 18:58:49 +01:00
Johannes Altmanninger
7c539b9539 Rename the readline function for deleting active history item
history-pager-delete now also works for regular history search,
so rename it.
2025-01-11 18:58:49 +01:00
Mahmoud Al-Qudsi
f8b245eb31 completions/zfs: Add encryption-related completions 2025-01-11 10:44:40 -06:00
Johannes Altmanninger
4a6d8d0b3a Allow alt-enter and friends to insert into search field
Since this is user-visible, copy the logic rather than extracting
a function.
2025-01-11 13:50:08 +01:00
Johannes Altmanninger
0f1408e0ea Also autosuggest lines from multi-line command lines in history
My history often has erroneous single-line commands followed by
corrected versions. Sometimes the corrected versions only exist within
a multi-line commandline.  This means that autosuggestion skips over
the corrected versions and return a false positive.

Fix that by splitting the commandline into lines and suggesting those,
in reverse chronological order.

One other wart: shift-delete won't delete such autosuggestions from
history; instead it will flash the screen.

Line boundaries are not the best heuristic but they are an
improvement for the most part and fits with the current approach
where autosuggestion always operates on the entire line.

In future we should operate on processes and jobs.  But it may be
tricky - a backgrounding `&` should probably be included (in both?)
but `&&` or `;` probably not.

See also the discussion in
1c4e5cadf2 (diff-267c9f4da66412a9f439ac08d224356fe24265b5e1cebb6c44c2d55b96414513R59)
2025-01-11 13:50:08 +01:00
Johannes Altmanninger
411745ebce shift-delete to only delete from history if cursor at autosuggestion
If there is no history search or autosuggestion, shift-delete acts
as backspace, matching native macOS behavior.

I'm not sure if we want to keep that amount of overloaded behavior,
but let's assume so for now.

If that assumption holds, it may be confusing that shift-delete
deletes the autosuggestion if the cursor is here

	echo some command with autosuggstion
		^

So let's only do that if the cursor is actually at the autosuggestion,
I guess.
2025-01-11 13:50:08 +01:00
Johannes Altmanninger
f448ddd579 shift-delete to stop trying to delete completion-based autosuggestions from history
shift-delete attempts to delete the autosuggestion from history even
if the autosuggestion is not from history.

This is weird. We probably shouldn't do this. Let's flash the
commandline instead to try to reduce confusion.
2025-01-11 13:50:08 +01:00
Daniel Fleischer
29c45100fa Add lazygit completions (#11019) 2025-01-10 21:21:54 -06:00
Mahmoud Al-Qudsi
a4f91a8543 Don't override CTEST_PARALLEL_LEVEL env variable
I think the dynamic detection patch ends up overriding the environment variable
set by CI (if present), because `if(NOT CTEST_PARALLEL_LEVEL)` would define to
false even if an environment variable of that name existed then we end up
explicitly assigning the environment variable by that name upon invocation with
`env`.
2025-01-10 19:21:28 -06:00
Fabian Boehm
1f45ab63d1 staticbuilds: Build pcre2 statically for macos 2025-01-10 14:44:31 +01:00
Fabian Boehm
0f6e85466a CHANGELOG key_reader/indent as builtins 2025-01-10 14:16:01 +01:00
Mahmoud Al-Qudsi
417b2eb8c6 Re-add dynamic CTEST_PARALLEL_LEVEL detection
When it is not hard-coded in the environment variable of the same name.
2025-01-10 14:12:46 +01:00
Mahmoud Al-Qudsi
3bbfaf532e Bump CTEST_PARALLEL_LEVEL to match CTEST_BUILD_PARALLEL_LEVEL
This is an experiment to see if it causes any of the tests to flake and/or if it
even appreciably speeds up CI to begin with.

I note that there are tests added in 8bf8b10 that mutate global terminal state
but also note that local tests without CTEST_PARALLEL_LEVEL set at all have been
running to completion just fine without any observed flakiness *and* that our
Cirrus CI tests have this hard-coded to 6.
2025-01-10 14:12:46 +01:00
Fabian Boehm
c7358d14c8 Make fish_indent available as a builtin 2025-01-10 14:12:19 +01:00
Fabian Boehm
67eb0e8317 Make fish_key_reader available as a builtin
This brings us closer to making fish available as a single file.
2025-01-10 14:12:19 +01:00
Benjamin Weis
83586aebcc Update German translation 2025-01-10 14:10:36 +01:00
Mahmoud Al-Qudsi
c1a43b896c Skip select ebadf test under WSLv1 due to a WSL bug
WSLv1 won't return EBADF (or any error) if the fd was closed mid-select.
2025-01-09 17:30:08 -06:00
Mahmoud Al-Qudsi
0fcb2f7590 completions/cargo: Add --ignore-rust-version
New to 1.85; bypasses MSRV checks specified by `resolver = 3` or in
.cargo/config.toml
2025-01-09 17:06:31 -06:00
Mahmoud Al-Qudsi
e3868effe1 Update cargo dependencies 2025-01-09 17:00:30 -06:00
Mahmoud Al-Qudsi
b9c6806e45 Configure cargo to respect MSRV
The new 1.84 release has a new feature that makes `cargo update` MSRV-aware.

This is what it looks like in practice:

    Updating crates.io index
    Updating git repository `https://github.com/fish-shell/rust-pcre2`
From https://github.com/fish-shell/rust-pcre2
 * [new tag]         0.2.9-utf32 -> origin/tags/0.2.9-utf32
     Locking 7 packages to latest Rust 1.70 compatible versions
    Updating cc v1.2.6 -> v1.2.7
    Updating phf v0.11.2 -> v0.11.3
    Updating phf_codegen v0.11.2 -> v0.11.3
    Updating phf_generator v0.11.2 -> v0.11.3
    Updating phf_shared v0.11.2 -> v0.11.3
    Updating siphasher v0.3.11 -> v1.0.1
    Updating syn v2.0.94 -> v2.0.95
2025-01-09 16:50:13 -06:00
Fabian Boehm
b8208d72f7 Remove test for broken tmux output
Quite flaky on CI.

See #11036
2025-01-09 21:06:15 +01:00
Fabian Boehm
52cb42ba3d Remove unused fish_iswgraph 2025-01-09 20:20:28 +01:00
Klaus Hipp
5c25d3c3b1 Fix completion typos 2025-01-09 16:51:39 +01:00
phanium
ef7aa793c6 Fix missing of builtin token description 2025-01-09 16:49:41 +01:00
Fabian Boehm
fac29e775a type: Do not translate the type "builtin"
This is a functional string, it should not be translated.

And we do not translate the others.
2025-01-09 16:42:28 +01:00
César Sagaert
00c7baf68c DNF5 completion support (#11035)
* dnf5 completions

* address comments
2025-01-09 16:35:46 +01:00
Johannes Altmanninger
0e512f8033 Fix spurious blank lines when executing scrolled commandline
The result of

	commandline -i ": '$(seq $LINES)"\n"first scrolled line'"

is a commandline that is scrolled by one line.

Before executing that commandline, we move the cursor down by one
too many line. This is a regression from 610338cc70 (On undo after
execute, restore the cursor position, 2024-12-21). Fix that.

The test also demonstrates an unrelated problem, probably specific
to tmux.
2025-01-09 14:43:21 +01:00
Fabian Boehm
8304fd0fd0 tmux-job: Add more sleeps 2025-01-08 19:10:38 +01:00
Fabian Boehm
f4f786633d pexpects/bind: Add missing expect_prompt 2025-01-08 19:10:38 +01:00
Fabian Boehm
ec3b3fe321 pexpects/signals: Decrease a timeout that should be reached
Saves ~10% of the *total* testing time (except for `cargo test`)
2025-01-08 19:10:38 +01:00
Fabian Boehm
d3762f11b5 tmux-commandline: Print $LINES
Maybe this'll show us what the issue on NetBSD is
2025-01-08 19:10:38 +01:00
Fabian Boehm
6db0f39676 exit_nohang: Harden a bit 2025-01-08 19:10:38 +01:00
Branch Vincent
7970ca55af completions: add fish-lsp (#11017) 2025-01-08 11:25:36 -06:00
David Adam
ccbbae95ef update copyright years to be unbounded
There is no legal need to have the year written here and it's a chore to
keep it up to date.
2025-01-08 20:38:43 +08:00
Johannes Altmanninger
6d551b4459 Fix status buildinfo error on invalid args 2025-01-08 12:06:28 +01:00
Johannes Altmanninger
cc9083e220 Add some logging for XTGETTCAP 2025-01-08 12:06:28 +01:00
Johannes Altmanninger
14df28382d Work around terminals that echo DCS queries
Some terminals such as conhost and putty cannot parse DCS commands,
and will echo them back.

Work around this by making sure that this echoed text will not
be visible.

Do so by temporarily enabling the alternative screen buffer when
sending DCS queries (in this case only XTGETTCAP).  The alternative
screen buffer feature seems widely supported, and easier to get right
than trying to clear individual lines etc.

The alternative screen may still be visible for a
short time.  Luckily we can use [Synchronized Output](
https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036)
to make sure the screen change is never visible to the user.

Querying support for that is deemed safe since it only requires a
CSI command.

Note that it seems that every terminal that supports Synchronized
Output also parses DCS commands successfully.  This means that we
could get away without the alternative screen buffer in practice.
Not sure yet.

The implementation is slightly more complex than necessary in that it
defines a redundant ImplicitEvent. This is for two reasons: 1. I have
a pending change that wants to use it, so this removes diff noise and
2. we historically have sc/input_common.rs not depend on src/output.rs.
I dont' think any are strong reasons though.
2025-01-08 12:06:28 +01:00
Johannes Altmanninger
e6d57f2fb2 Minor style fix 2025-01-08 12:06:28 +01:00
Klaus Hipp
4def0ac616 Revert "Fix typo in npm completions: isntall -> install" (#11014)
* Revert "Fix typo in npm completions: isntall -> install"

This reverts commit f4b01bb638.

* Add comments about typos in `npm` completions
2025-01-07 12:32:16 -06:00
Steve Walker
b574a5e4f6 fix python completion #10943 2025-01-07 23:30:27 +08:00
Klaus Hipp
9b67b2ae07 Fix typos in docs (#11015) 2025-01-06 19:40:30 -06:00
Klaus Hipp
ea4e4a4279 Fix completion typos for apt-build, htop and wget (#11016) 2025-01-06 19:39:47 -06:00
Johannes Altmanninger
3405621dee Update littlecheck to fix spurious "not found" error on exit 127
Commit b6d76ae: we now use lines like "# RUN: fish=%fish %fish".
If a test exits with 127 we try to look up the command but use the
wrong name, which leads to unintelligible errors if the test exits
with 127 for other reasons.
2025-01-06 06:40:43 +01:00
Johannes Altmanninger
834001087d Disable kitty keyboard protocol on iTerm again for now
It causes alt-left to be sent as left in some cases; see #11004.

Upstream issue: https://gitlab.com/gnachman/iterm2/-/issues/12105
2025-01-06 06:24:13 +01:00
Johannes Altmanninger
e697add5b5 Feature flag to prevent executing off buffered keys
If I run "sleep 3", type a command and hit enter, then there is no
obvious way to cancel or edit the imminent command other than ctrl-c
but that also cancels sleep, and doesn't allow editing. (ctrl-z sort
of works, but also doesn't allow editing).

Let's try to limit ourselves to inserting the buffered command
(translating enter to a newline), and only execute once the user
actually presses enter after the previous command is done.
Hide it behind a new feature flag for now.

By making things less scary, this might be more user-friendly, at
the risk of breaking expectations in some cases.

This also fixes a class of security issues where a command like
`cat malicious-file.txt` might output escape sequences, causing
the terminal to echo back a malicious command; such files can still
insert into the command line but at least not execute it directly.
(Since it's only fixed partially I'm not really sure if the security
issue is a good enough motivation for this particular change.)

Note that bracketed paste probably has similar motivation as this feature.

Part of #10987
Closes #10991
2025-01-06 06:24:13 +01:00
Johannes Altmanninger
704b911168 Back out "Bind ctrl-l to clear-screen again for now"
As of the parent commits this should no longer cause breakage.

This backs out commit 07dd088d76.
2025-01-06 06:24:13 +01:00
Johannes Altmanninger
af137e5e96 scrollback-push to query for indn/cuu via XTGETTCAP
Some terminals like the Linux console don't support indn (scroll
forward). Let's query for the presence of these features, and fall
back to the traditional behavior if absent.

For now, break with the tradition of using the terminfo database that
we read ourselves. Instead ask the terminal directly via XTGETTCAP.
This is a fairly young feature implemented by terminals like xterm,
foot and kitty, however xterm doesn't expose these capabilities at
this point.

This is a good opportunity to try XTGETTCAP, since these are
capabilities we haven't used before. Advantages of XTGETTCAP are that
it works across SSH and is independent of $TERM (of course ignoring
$TERM may also be breaking to some users). Let's see if it sees
adoption in practice.

Tested to work on foot and kitty, allowing the default ctrl-l binding
to work without erasing any screen content.

See #11003
2025-01-06 06:24:13 +01:00
Johannes Altmanninger
75832b3c5d scrollback-push to fall back to clear-screen if missing CPR feature
The new ctrl-l implementation relies on Cursor Position Reporting (CPR)
This may not work on exotic terminals that don't support CSI 6n yet

As a workaround, probe for this feature by sending a CSI 6n (CPR)
on startup.  Until the terminal responds, have scrollback-push fall
back to clear-screen.

The theoretical problem here is that we might handle scrollback-push
before we have handled the response to our feature probe. That seems
fairly unlikely; also e49dde87cc has the same characteristics.

This could query a capability instead (via XTGETTCAP or otherwise)
but I haven't found one; and this seems at least as reliable.

While at it, change the naming a bit.

See #11003
2025-01-06 05:53:24 +01:00
Johannes Altmanninger
dda4371679 Stop sending CSI 5n when querying for kitty keyboard support
After we query kitty keyboard protocol support,
we send CSI 5n, to also receive a response if
the protocol is not supported.

However we don't bother to wait for the response, so this extra
message is not really useful (only to get better logs).  Remove it.
2025-01-06 05:51:38 +01:00
Johannes Altmanninger
10f1f21a4f Don't send kitty kbd protocol probe until ECHO is disabled
With tmux 3.0 (from 2019) inside SSH, the CSI 5n response is echoed.
I guess with all other terminals we were just lucky.  Move it to
right after where we disable ECHO I guess.

In general, asynchronous requests create a lot of potential for error,
we should try to get away from them.
2025-01-06 05:51:38 +01:00
Johannes Altmanninger
109ef88831 Add menu and printscreen keys
These aren't typically used in the terminal but they are present on
many keyboards.

Also reorganize the named key constants a bit.  Between F500 and
ENCODE_DIRECT_BASE (F600) we have space for 256 named keys.
2025-01-06 05:43:22 +01:00
Lzu Tao
f9b79926f1 Add more convenient key bindings for VI mode
To make it more familiar to vi/vim users.

In all mode, ctrl-k is bind to kill-line.

In Vi visual mode:
* press v or i turn into normal or insert mode respectively.
* press I turn to insert mode and move the cursor to beginning of line.
* because fish doesn't have upcase/locase-selection, and most people reach for
  g-U rather than g-u, g-U binds to togglecase-selection temporarily.
2025-01-05 23:00:21 +08:00
David Adam
6c3150aa05 docs/interactive: update key bindings added for 4.0 2025-01-05 22:27:00 +08:00
Johannes Altmanninger
07dd088d76 Bind ctrl-l to clear-screen again for now
Testing has revealed some problems on BSD and Windows terminals and
the Linux Console, let's revert to the old implementation until these
are fixed.  Leaving the changelog entry for now since it shouldn't
take long.

See #11003
2025-01-05 08:20:53 +01:00
Johannes Altmanninger
93e0a33d41 Log human-readable values also for not-yet-decoded bytes 2025-01-05 03:37:31 +01:00
Stefan Boca
dcddffd222 refactor: misc cleanup (#10998)
* refactor EnvVar: Arc<Box<[WString]>> -> Arc<[WString]>

* remove unnecessary `&mut` from EnvVar methods

* clippy: use eq_ignore_ascii_case instead of manual comparison

see https://rust-lang.github.io/rust-clippy/master/index.html#manual_ignore_case_cmp

* clippy: use `is_some_and` and `is_ok_and` instead of `map_or`

see https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_map_or

* clippy: use `assert!()` instead of `assert_eq!()` with booleans
2025-01-04 19:49:44 -06:00
cornmander
d842a6560e Add completions for Google Cloud commands. (#11005)
The `gcloud` and `gsutil` Google Cloud commands use argcomplete, so integrating them is easy with the `__fish_argcomplete_complete` function.
2025-01-04 19:45:05 -06:00
Mahmoud Al-Qudsi
b4e8cc8b79 Use explicit Timeout enum instead of magic constants
The FdReadableSet api was always intended to be converted to use Duration
instead of usec/msec once the ffi was removed. This lets us be explicit about
forever/infinite timeouts and removes the (small) chance of a collision between
u64::MAX and INFINITE.

I tried this out with `type Timeout = Option<Duration>` (only without the alias)
but was unhappy with easy it is to accidentally use `None` when you meant a
timeout of zero.
2025-01-04 18:40:36 -06:00
Mahmoud Al-Qudsi
83eb25d45f Mark function as test-only 2025-01-04 17:29:09 -06:00
Lzu Tao
7eb254f2ba Add completion for gem-fetch 2025-01-04 21:26:03 +08:00
idealseal
2e12a2b6c4 feat(comp): Update completions for resolvectl 2025-01-04 20:42:31 +08:00
idealseal
a780e4da15 feat(comp): Update completion for md5sum 2025-01-04 20:39:33 +08:00
Thayne McCombs
33dd823f45 fix[completions]: Add set-timeout to bootctl 2025-01-04 20:15:53 +08:00
Johannes Altmanninger
e11e62674f Fix bad layout computation with right prompt
Commit 1c4e5cadf2 (Autosuggestions in multi-line
command lines, 2024-12-15) accidentally passed an empty
"commandline_before_suggestion" to compute_layout() when there is
no autosuggestion.

Closes #10996
2025-01-04 00:54:06 +01:00
Johannes Altmanninger
e49dde87cc Probe for kitty keyboard protocol support
We unconditionally request kitty keyboard protocol's progressive
enhancements.

It seems that a lot of terminals fail to parse CSI commands that
contain '=' such as \x1b[=5u.

1. [Midnight Commander](0ea77d2ec7)
2. Prompt 3 App (private bug tracker)
3. JetBrains IDEs https://youtrack.jetbrains.com/issue/IJPL-166234
4. Termux https://github.com/termux/termux-app/issues/4338
5. Amazon Linux Web Console https://github.com/amazonlinux/amazon-linux-2023/issues/871

It is difficult to fix the four remaining ones in a
timely manner, so let's query for support as described in
https://sw.kovidgoyal.net/kitty/keyboard-protocol/#detection-of-support-for-this-protocol
This uses CSI 5 n (device status report), which is the older brother
of CSI 6 n (cursor position report) we use as of recently.

Query asynchronously and enable progressive enhancements as soon
as we get a response. In theory this allow `cat malicious-file.txt`
leading us to believe the protocol is supported.

See #10994
2025-01-03 23:20:19 +01:00
Fabian Boehm
edfdf210c4 Remove unnecessary use of errno 2025-01-03 19:34:57 +01:00
Johannes Altmanninger
996fec87f4 Demote logs about unexpected cursor position
As reported in
https://github.com/fish-shell/fish-shell/issues/10992#issuecomment-2568954940,
the user may reset the terminal and run scrollback-push without
repainting in between.  This means that the terminal will report
the cursor position y=0 x=0 which doesn't match what fish renders.
Fortunately, y=0 is a safe fallback value for the scrollback-push
use case.

While at it, fix an off-by-one error in a log.
2025-01-03 12:57:00 +01:00
Johannes Altmanninger
870a8f77a0 completions/scp: replace version detection
Version detection seems unreliable (see
https://github.com/fish-shell/fish-shell/issues/10445#issuecomment-2566232705
) so let's test for the actual feature.  On modern versions,"scp -O"
means "Use  the legacy SCP protocol for file transfers instead",
so presence of this feature indicates we are good.
2025-01-03 12:57:00 +01:00
Johannes Altmanninger
d823444c6e Apply autosuggestions from completions also if cursor is not at EOL
Before 1c4e5cadf2 (Autosuggestions in multi-line command lines,
2024-12-15), the completion code path in the autosuggestion performer
used to do something weird: it used to request completions for the
entire command line (with the implied cursor at end) but try to apply
the same completion at the actual cursor.

That commit changed this to request completions only up to the cursor
position, which could in theory make us produce valid completions even
if the cursor is not at end of the line.  However, that doesn't really
work since autosuggestions can only be rendered at the end of the line.
And the worst of it, that commit tries to compute

	line_at_cursor(&full_line, search_string_range.end)

which crashes as out-of-bounds if the completion needs to replace the token
(like a case-correcting completion does).

Let's apply completions to the end, matching how autosuggestions work
in general.
2025-01-03 12:56:04 +01:00
Johannes Altmanninger
abaeb4af2a scrollback-push to sanitize cursor position
I believe it's possible that the cursor position reported by the
terminal does not match fish's cursor.  In that case, overflow. Fix
that since we should not trust the terminal.

Also rename a confusingly named variable.

Mouse-click handling has a similar issue, fix that too.

FWIW, tmux always reports cursor position zero (\x1b[1;1R) when
querying from fish (but not when querying with printf).
Will investigate that next, see the linked issue.

Fixes #10992
2025-01-03 07:55:50 +01:00
David Adam
670541eec8 fish_jj_prompt: don't error if jj not installed 2025-01-03 12:38:14 +08:00
Johannes Altmanninger
0debddc9e5 Add a simple fish_jj_prompt
jj is often colocated with Git so the Git prompt also works, but
jj is always in a detached HEAD state, which is atypical for Git.
The jj prompt improves things by showing the revision ID which is
usually more useful than the commit ID.

This prompt is mostly adapted from the defaults for "jj log -r @".

Showing conflicting/empty commits seems useful.
Also perhaps bookmarks and tags, not sure.

The main problem with this prompt is that due to --ignore-working-copy,
the information may be stale.  That will be rectified after every jj
command, so hopefully this doesn't cause issues.
2025-01-03 00:03:58 +01:00
Erick Howard
837c32f150 Move getrusage wrapper in timer.rs to shared nix wrapper module
Closes #10988
2025-01-02 23:40:41 +01:00
Alexei Mikhailov
9b26fff278 completions/exercism: use generate script
Exercism ships with it's own completions and a generation script, so let's use
that one instead.
2025-01-02 21:57:17 +08:00
Klaus Hipp
2b46d97c68 Update code completions 2025-01-02 14:11:24 +08:00
David Adam
65ced4e2bb Cargo.lock: update downstream dependencies 2025-01-02 13:20:15 +08:00
David Adam
3710142d1d Cargo.lock: update errno 2025-01-02 13:18:54 +08:00
David Adam
0c9c5e3a34 Cargo.toml/lock: upgrade serial_test
Slims the dependency tree down a bit; no breaking changes affect fish.
2025-01-02 13:09:54 +08:00
David Adam
53912777af Cargo.lock: upgrade cc 2025-01-02 12:38:50 +08:00
David Adam
70bd49f612 drop confstr implementation
Added in libc 0.2.163.

The constants for _CS_PATH are not implemented for some of the BSDs yet
(rust-lang/cmake#3612), so we need to keep our linking of this via the C
compiler for now.
2025-01-02 11:06:29 +08:00
David Adam
6714818e5d Cargo.toml: update libc 2025-01-02 10:44:23 +08:00
Peter Ammon
7e9b35be48 Fix a clippy 2025-01-01 17:42:25 -08:00
Peter Ammon
7af9844de0 highlight: make PathFlags an ordinary struct
No need for fancy bitflags.
2025-01-01 17:42:14 -08:00
tranzystorekk
3129c9e939 environment_impl: drop usage of lazy_static 2025-01-01 12:23:24 -08:00
Erick Howard
967c4b2272 Code cleanup in src/bin/fish.rs to make it more idiomatic (#10975)
Code cleanup in `src/bin/fish.rs` to make it more idiomatic
2025-01-01 12:17:48 -06:00
Johannes Altmanninger
1c4e5cadf2 Autosuggestions in multi-line command lines
If I run

	$ command A
	$ command B
	$ command C

and find myself wanting to re-run the same sequence of commands
multiple times, I like to join them into a single command:

	$ command A &&
	    command B &&
	    command C

When composing this mega-commandline, history search can recall the
first one; the others I usually inserted with a combination of ctrl-k,
ctrl-x or the ctrl-r (since 232483d89a (History pager to only operate
on the line at cursor, 2024-03-22), which is motivated by exactly
this use case).

It's irritating that autosuggestions are missing, so try adding them.

Today, only single-line commands from history are suggested. In
future, we should perhaps also suggest any line from a multi-line
command from history.
2025-01-01 17:22:50 +01:00
Johannes Altmanninger
532abaddae Invalidate stale autosuggestions eagerly
If I type something that invalidates the autosuggestion, the
autosuggestion is still kept around in memory. This is used if
1. there is no valid autosuggestion for the new commandline
2. the user types something like "backspace backspace a"
   that both makes the cached autosuggestion valid again, and does
   not trigger autosuggestion suppression (hence backspace alone is
   not anough)

The fact that an autosuggestion might not match the current command
line makes it more difficult to implement autosuggestions on multiline
command lines.

For now let's invalidate autosuggestions eagerly, to enable the
next commit.  This heuristic invalidates too much but I don't think
that matters. We'll simply recompute the autosuggestion in those few
cases which.
2025-01-01 17:22:50 +01:00
Johannes Altmanninger
7049352e61 Extract function for potentially case-insensitive prefix check 2025-01-01 17:22:50 +01:00
Fabian Boehm
a4f4ae76cb staticbuilds: Run tests 2025-01-01 16:45:56 +01:00
Fabian Boehm
c3de539d46 test_driver: Error out if $FISHDIR isn't given
This avoids confusion when you forget to set it and run it on the
wrong fish.
2025-01-01 16:45:43 +01:00
Fabian Boehm
7bb38355e8 test_driver: Some more errors 2025-01-01 16:45:43 +01:00
Fabian Boehm
5520ee3c65 Document 2025-01-01 16:45:43 +01:00
Fabian Boehm
e66f6878b5 Make tests usable with path with spaces
This is somewhat subtle:

The #RUN line in a littlecheck file will be run by a posix shell,
which means the substitutions will also be mangled by it.

Now, we *have* shell-quoted them, but unfortunately what we need is to
quote them for inside a pre-existing layer of quotes, e.g.

    # RUN: fish -C 'set -g fish %fish'

here, %fish can't be replaced with `'path with spaces/fish'`, because
that ends up as

    # RUN: fish -C 'set -g fish 'path with spaces/fish''

which is just broken.

So instead, we pass it as a variable to that fish:

    # RUN: fish=%fish fish...

In addition, we need to not mangle the arguments in our test_driver.

For that, because we insist on posix shell, which has only one array,
and we source a file, we *need* to stop having that file use
arguments.

Which is okay - test_env.sh could previously be used to start a test,
and now it no longer can because that is test_*driver*.sh's job.

For the interactive tests, it's slightly different:

pexpect.spawn(foo) is sensitive to shell metacharacters like space.

So we shell-quote it.

But if you pass any args to pexpect.spawn, it no longer uses a shell,
and so we cannot shell-quote it.

There could be a better way to fix this?
2025-01-01 16:45:43 +01:00
Fabian Boehm
e9b9ee8d63 Fix docs if binary dir has a space
For some reason this is double-quoted if we quote this.
2025-01-01 16:45:43 +01:00
Fabian Boehm
17d57b70d0 littlecheck: Update to shell-quote replacements
Commit bb07435e3e4cbd34fcb667ec927353d176a0b2e8
2025-01-01 16:45:43 +01:00
Fabian Boehm
cb3d004a5a tests: Run filter-ctrl with %fish explicitly 2025-01-01 16:45:43 +01:00
Fabian Boehm
5e10d75a19 Tests: Don't cd to the tests directory!
We:

1. Set up a nice TMPDIR for our tests to use
2. Immediately `cd` to the directory containing the test runner.

So instead we don't do (2), and stay in the temp directory, and
explicitly use all the things from the test runner directory.

I am fairly certain that cmake papered over this by adding a second
layer of temp dir.
2025-01-01 16:45:43 +01:00
Fabian Boehm
050fe09af1 Compile fish_test_helper in the test driver 2025-01-01 16:45:43 +01:00
Fabian Boehm
b531cc8b43 tests: Specifically #require fish_test_helper when needed 2025-01-01 16:45:43 +01:00
Fabian Boehm
63e705a778 Let tests find fish and associated binaries via $FISHDIR
The default is still "../test/root/bin/", but we now pass this
through,
so you *can* run

`FISHDIR=$PWD ../tests/test_driver.sh $PWD/../tests/test.fish`
2025-01-01 16:45:43 +01:00
Fabian Boehm
1df8de06c1 Move littlecheck/pexpect to tests
This removes the need for a bunch of setup, and makes it easier to
make the tests agnostic to our test root setup.
2025-01-01 16:45:43 +01:00
Erick Howard
943adf4dd0 Avoid traversing wait handle list if searching by PID 2025-01-01 16:40:53 +01:00
Erick Howard
53dc7772eb Remove unnecessary clone when opening File for debug output 2025-01-01 16:34:40 +01:00
Hong Xu
64ed47bf4e Update .editorconfig to use "unset" instead of "off" (#10972)
This is inline with the [EditorConfig spec](https://spec.editorconfig.org/). The [EditorConfig Wiki](https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties#max_line_length) was outdated and misleading, but have updated now.
2024-12-31 15:04:37 -06:00
Fabian Boehm
6848e70e87 Disable two tests on NetBSD
One doesn't compile, the other's just borked for weird reasons
possibly related to tmux and $LINES?

With this, the test suite passes on NetBSD.
2024-12-31 13:04:28 +01:00
Fabian Boehm
d5efef1cc5 __fish_complete_subcommand: Just complete -C for a given commandline
Fixes #10980.

This would, if a commandline was given, still revert to checking
the *real* commandline if it was empty.

Unfortunately, in those cases, it could have found a command and tried
to complete it.

If a commandline is given, that is what needs to be completed.

(note this means this is basically useless in completions that use it
like `sudo` and could just be replaced with `complete -C"$commandline"`)
2024-12-30 21:01:21 +01:00
Fabian Boehm
e715c3e3ff help: Add special error for $BROWSER/$fish_help_browser being wrong 2024-12-30 21:01:21 +01:00
Johannes Altmanninger
13763fa318 Fix assertion error in when scrollback-push is enqueued from script
As soon as we start processing a scrollback-push readline command, we
pause execution of all other readline commands until scrollback-push
retires.  This means that we never get into a situation with two
active scrollback-push commands -- unless we are executing readline
commands via a script running "commandline -f":
since the first part of scrollback-push handling returns immediately,
the script will proceed before scrollback-push retires.

A second scrollback-push fails an assertion.  Work around that for now.
In future, scrollback-push should block when invoked by such a script,
just like it does when invoked from bindings.
2024-12-30 14:20:05 +01:00
Johannes Altmanninger
8910390602 Work around broken macOS CI seemingly missing parm_index in terminfo
Commit 83b0294fc9 (ctrl-l to scroll content instead of erasing screen,
2024-12-21) broke tests like tests/checks/tmux-autosuggestion.fish
on macOS CI.

I didn't get to the bottom of this but it's probably because terminfo
is broken on that CI system.

A (related?) failure mode can be observed using

	TERM=linux-m ssh my-mac tmux

ctrl-l moves the cursor but fails to scroll the text.

The only reason for using terminfo here was to be consistent with
the rest of the code base.  Let's use a hardcoded value instead;
I don't see why any terminal would deviate from xterm here.

This fixes macOS CI and the TERM=linux-m "misconfiguration".

It is possible that we should be using a different escape sequence
here; I'm not sure.
2024-12-30 14:20:05 +01:00
Johannes Altmanninger
b6c2a4c5db Remove trivial splice() call 2024-12-30 10:50:38 +01:00
Johannes Altmanninger
a88de9d345 Remove unused data from autosuggestion cache 2024-12-30 10:50:38 +01:00
Johannes Altmanninger
e8801d2ced Minor refactoring to reuse autosuggestion contructor 2024-12-30 10:50:38 +01:00
Johannes Altmanninger
1d620356f8 Deduplicate command line update step when accepting autosuggestions 2024-12-30 10:50:38 +01:00
Johannes Altmanninger
8bb6597b9b Deduplicate layout computation logic 2024-12-30 10:50:38 +01:00
Johannes Altmanninger
8ae12973df Try to simplify commandline change hooks 2024-12-30 10:50:38 +01:00
Johannes Altmanninger
459fc3c887 Fix failing history pager search replacing all lines
History pager search operates only on the current line, so a failing
search should only replace the current line with the search string.
2024-12-30 10:50:38 +01:00
Johannes Altmanninger
a719f9d537 Minor refactoring in handle_execute
A failing ctrl-r search term is inserted back into the command line.
This should go through the same code path as other editions.
2024-12-30 10:50:38 +01:00
Johannes Altmanninger
da0a93b24b Minor optimization in pager_selection_changed 2024-12-30 10:50:38 +01:00
Johannes Altmanninger
8bb442f135 Minor cleanup in push_edit 2024-12-30 10:50:38 +01:00
Johannes Altmanninger
3fcc6482cb Fix parse_util_process_extent including too much on the left 2024-12-30 10:50:38 +01:00
Johannes Altmanninger
83b0294fc9 ctrl-l to scroll content instead of erasing screen
On ctrl-l we send `\e[2J` (Erase in Display).  Some terminals interpret
this to scroll the screen content instead of clearing it. This happens
on VTE-based terminals like gnome-terminal for example.

The traditional behavior of ctrl-l erasing the screen (but not the
rest of the scrollback) is weird because:

1. `ctrl-l` is the easiest and most portable way to push the prompt
   to the top (and repaint after glitches I guess). But it's also a
   destructive action, truncating scrollback. I use it for scrolling
   and am frequently surprised when my scroll back is missing
   information.
2. the amount of lines erased depends on the window size.
   It would be more intuitive to erase by prompts, or erase the text
   in the terminal selection.

Let's use scrolling behavior on all terminals.

The new command could also be named "push-to-scrollback", for
consistency with others. But if we anticipate a want to add other
scrollback-related commands, "scrollback-push" is better.

This causes tests/checks/tmux-history-search.fish to fail; that test
seems pretty broken; M-d (alt-d) is supposed to delete the current
search match but there is a rogue "echo" that is supposed to invalidate
the search match.  I'm not sure how that ever worked.

Also, pexepect doesn't seem to support cursor position reporting,
so work around that.

Ref: https://codeberg.org/dnkl/foot/wiki#how-do-i-make-ctrl-l-scroll-the-content-instead-of-erasing-it
as of wiki commit b57489e298f95d037fdf34da00ea60a5e8eafd6d

Closes #10934
2024-12-30 10:50:38 +01:00
Johannes Altmanninger
84f19a931d Also ignore invalid recursive escape sequences
We parse "\e\e[x" as alt-modified "Invalid" key.  Due to this extra
modifier, we accidentally add it to the input queue, instead of
dropping this invalid key.

We don't really want to try to extract some valid keys from this
invalid sequence, see also the parent commit.

This allows us to remove misplaced validation that was added by
e8e91c97a6 (fish_key_reader: ignore sentinel key, 2024-04-02) but
later obsoleted by 66c6e89f98 (Don't add collateral sentinel key to
input queue, 2024-04-03).
2024-12-30 10:50:38 +01:00
Johannes Altmanninger
3201cb9f01 Stop parsing invalid CSI/SS3 sequences as alt-[/alt-o
This situation can be triggered in practice inside a terminal like tmux
3.5 by running 

	tmux new-session fish -C 'sleep 2' -d reader -o log-file

and typing "alt-escape x"

The log shows that we drop treat this as alt-[ and drop  the x on the floor.

	reader: Read char alt-\[ -- Key { modifiers: Modifiers { ctrl: false,
	alt: true, shift: false }, codepoint: '[' } -- [27, 91, 120]

This input ("\e[x") is ambiguous.

It looks like it could mean "alt-[,x".  However that conflicts with a
potential future CSI code, so it makes no sense to try to support this.

Returning "None" from parse_csi() causes this weird behavior of
returning "alt-[" and dropping the rest of the parsed sequence.
This is too easy; it has even crept into a bunch of places
where the input sequence is actually valid like "VT200 button released"
but where we definitely don't want to report any key.

Fix the default: report no key for all unknown sequences and
intentionally-suppressed sequences.  Treat it at "alt-[" only when
there is no input byte available, which is more or less unambiguous,
hence a strong enough signal that this is a actually "alt-[".
2024-12-30 10:50:38 +01:00
Johannes Altmanninger
e1e963ae66 Move cursor on mouse click via kitty's OSC 133 click_events=1
When the user clicks somewhere in the prompt, kitty asks the shell
to move the cursor there (since there is not much else to do).

This is currently implemented by sending an array of
forward-char-passive commands.  This has problems, for example it
is really slow on large command lines (probably because we repaint
everytime).

Implement kitty's `click_events=1` flag to set the
position directly.  To convert from terminal-coordinates
to fish-coordinates, query [CSI 6 n Report Cursor
Position](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html)
and use it to compute the left prompt's terminal-coordinates (which
are (0, 0) in fish-coordinates).

Unfortunately this doesn't yet work correctly while the terminal
is scrolled.  This is probably because the cursor position is wrong
if off-screen.  To fix that we could probably record the cursor
position while not scrolled, but it doesn't seem terribly important
(the existing implementation also doesn't get it right).

We still turn off mouse reporting.  If we turned it on, it
would be harder to select text in the terminal itself (not fish).
This would typically mean that mouse-drag will alter fish's
selection and shift+mouse-drag or alt+mouse-drag can be used.

To improve this, we could try to synchronize the selection: if parts
of the fish commandline are selected in the terminal's selection,
copy that to fish's selection and vice versa.

Or maybe there is an intuitive criteria, like: whenever we receive a
mouse event outside fish, turn off mouse reporting, and turn it back on
whenver we receive new keyboard input.  One problem is that we lose
one event (though we could send it back to the terminal). Another
problem is we would turn it back on too late in some scenarios.

Closes #10932
2024-12-30 10:50:01 +01:00
Johannes Altmanninger
ca9c5f4cec Move some fake readline commands to a separate type 2024-12-30 10:50:01 +01:00
Johannes Altmanninger
48ae19b4b1 Update some stale doc comments 2024-12-30 10:50:01 +01:00
Johannes Altmanninger
7ec1487016 Deduplicate call to select() 2024-12-30 10:50:01 +01:00
Johannes Altmanninger
bc26481558 Retry writing some escape sequences on EINTR
Maybe we should be using SA_RESTART?
2024-12-30 10:50:01 +01:00
Johannes Altmanninger
41e82c8c9e Protect some cursor movements against untimely ctrl-c
Commit 01dbfb0a3f (replace writestr() with fwprintf() in reader.cpp,
2016-12-20) accidentally replaced a retry-on-EINTR write with a
non-retrying version. Commit 7f31acbf9b (Prevent fish_title output
from triggering a bel, 2022-02-02) fixed this for some cases but
not all, fix that.
2024-12-30 10:50:01 +01:00
Johannes Altmanninger
376bf3a982 Remove redundant return value from write_loop()
This function ought to match the standard write_all().
2024-12-30 10:50:01 +01:00
Johannes Altmanninger
1e384900fa kitty kbd: stop parsing CSI R as F3
This has been removed, see kitty commit cd92d50a0 (Keyboard protocol:
Remove CSI R from the allowed encodings of the F3 key as it conflicts
with the *Cursor Position Report* escape code, 2022-12-24).
2024-12-30 10:50:01 +01:00
Johannes Altmanninger
cde503b0a8 Mention lack of support for ctrl-backspace and alternatives
Closes #10936
2024-12-30 10:50:01 +01:00
Johannes Altmanninger
69f0d960cf Fix off-by-one error in Vi-style upcase-word at commandline end
cursor_selection_mode=inclusive means the commandline position is
bounded by the last character. Fix a loop that fails to account
for this.

Fixes d51f669647 (Vi mode: avoid placing cursor beyond last character,
2024-02-14).

This change looks very odd because if the commandline is like

	echo foo.

it makes us try to uppercase the trailing period even though that's
not part of word range.  Hopefully this is harmless.

Note that there seem to be more issues remaining, for example Vi-mode
paste leaves the cursor in an out-of-bounds odd position.

Fixes #10952
Closes #10953

Reported-by: Lzu Tao <taolzu@gmail.com>
2024-12-30 10:50:01 +01:00
Johannes Altmanninger
ca28d0a78f Add missing test for Vi mode $
PR #10953 reports missing coverage for the change to update_buff_pos()
in d51f669647 (Vi mode: avoid placing cursor beyond last character,
2024-02-14).

Add a case demonstrating how $ should not move the cursor past the
last character. Goes without saying that it's really ugly that we
update_buff_pos() must be so defensive here, ideally we wouldn't pass
it out-of-bounds positions.
2024-12-30 10:50:01 +01:00
Johannes Altmanninger
6043644f52 completions/status: add buildinfo 2024-12-30 10:50:01 +01:00
Grant Hutchins
1227b6765c Improve documentation for string escape
Before, it unnecessarily stated that there are three `--style` options, when
there are actually four.

I also align the default `--style=script` argument to the beginning of the line
to match the other options visually for easier scanning.
2024-12-29 13:48:34 -08:00
Fabian Boehm
905c7310c6 checks/type: Relax sh path even more
Fixes #10970
2024-12-29 22:11:34 +01:00
Ilya Grigoriev
b1064ac3a0 completions/tmux: add skeleton "Windows and Panes" bindings (#10854)
These are quite mechanical, but include all the commands (as of tmux
3.5a) in the "Windows and Panes" section of `man tmux`. For these
commands, I included the target-pane/session/client/window flags and the
-F formatstring flags (but not the less generic flags specific to
individual commands).

Nice completion is implemented for those flags where the helper
functions were already implemented previously.

After this, tmux pane<tab> will hopefully be useful.

A few TODOs mention low-hanging fruit for somebody who better
understands fish's `complete` command syntax (or a future me).

Another piece of low-hanging fruit would be completion for all the
target-window flags. This PR merely lists them.
2024-12-29 15:37:21 +01:00
EmilyGraceSeville7cf
1bda6043c8 feat(completion) support batsh command 2024-12-29 15:36:00 +01:00
EmilyGraceSeville7cf
d8d5913159 feat(completion): support folderify command 2024-12-29 15:35:25 +01:00
Benjamin Kellermann
2ac1523e54 add completion for btrbk (#10752)
* add completion for btrbk

completions for btrbk https://github.com/digint/btrbk/

* change indent + spaces
2024-12-29 15:33:29 +01:00
Łukasz Wieczorek
9cea5e0732 Remove redundant newlines, add .idea to gitignore
* Add .idea/ to git ignored directories.

* Remove redundant newline.

* Remove redundant newline.

* Remove redundant newlines.

* Remove redundant newline.

* Remove redundant newline.

* Add missing newline at end of file.

* Remove redundant newline.

* Remove redundant newlines.
2024-12-29 15:31:03 +01:00
Fabian Boehm
6f9ca42a30 Add status buildinfo (#10896)
This can be used to get some information on how fish was built - the
version, the build system, the operating system and architecture, the
features.
2024-12-29 13:37:28 +01:00
Joan Bruguera Micó
b8df9648f2 Create new base directories with mode 0700
If base directories (e.g. $HOME/.config/fish) need to be created,
create them with mode 0700 (i.e. restricted to the owner).
This both keeps the behavior of old fish versions (e.g. 3.7.1) and is
compliant with the XDG Base Directory Specification.

See: https://specifications.freedesktop.org/basedir-spec/0.8/#referencing
2024-12-28 12:13:48 -08:00
Fabian Boehm
66b80041cc Create release-with-debug cargo profile, hook it up with cmake
Fixes #10959
2024-12-28 16:03:40 +01:00
Kid
a579abb81b docs: Distinguish documents in sidebar 2024-12-28 08:42:46 +01:00
Peter Ammon
b97598fa6c Clean up some logic around handling the parser blocks
Fix a todo. Enforce reverse iteration order.
2024-12-27 16:42:38 -08:00
Peter Ammon
64cb86ac26 Stop copying node sources so aggressively in parse_execution
Eliminates some allocations and fixes a TODO.
2024-12-27 15:47:34 -08:00
Peter Ammon
a14906f52f Fix a todo!
Stop cloning the delimiter unnecessarily in builtin read.
2024-12-27 15:00:59 -08:00
Peter Ammon
36d7049749 Minor cleanup of other unsafe impl 2024-12-27 14:46:46 -08:00
Peter Ammon
4b9767ce83 Remove as_ptr from IoData
We don't need this. Also improve IoChain::remove().
2024-12-27 14:36:55 -08:00
Peter Ammon
f6d76d2057 Remove some unsafe impls of Send / Sync
We no longer have C++ so we don't need these; Rust does the right thing by
default.
2024-12-27 14:14:47 -08:00
Peter Ammon
659c926dbd Additional cleanup of io buffering
Eliminate some ugly bits. No functional change expected.
2024-12-27 14:09:07 -08:00
Peter Ammon
56da15d11f Rework the file descriptor monitor
[Do NOT cherry-pick to 4.0 - this needs more time to be tested]

fish sometimes needs to capture the output of a command or block of
commands. Examples include fish_prompt or any command substitution
("cmdsubs"). It does this the obvious way: by creating a pipe, using dup2
to replace stdout of the command with the write end of the pipe, and then
reading from the read end into a buffer, until EOF or the command
substitution completes. Importantly, this task also overlaps with waiting
for the process to exit; that is when executing:

    set var (some_cmd)

fish needs to both wait on `some_cmd` and ALSO read its output into memory.
This is awkward to do in a portable way in a single thread (though maybe
doable on Linux with pidfd). So we wait and read on different threads.

To make things worse, command substitutions may themselves create
additional command substitutions (recursion, etc). Creating a read thread
for every command substitution would result in excessive threads. So rather
than a thread per cmdsub, we have a single dedicated thread that handles
ALL command substitutions, by multiplexing multiple file descriptors via
select/poll. This is the "fd monitor." You hand it a file descriptor and it
lets you know when it's readable, and then you can read from it (via a
callback). Also, it has a "wakeup" fd: if you write to that then the fd
monitor wakes up, figures out what it has to do, and resumes.

When the command substitution ends, we need to remove the fd from the fd
monitor, because we intend to close it. You might object "the commands in
the cmdsub have all completed so the write end of the pipe has been closed
so the fd monitor can just notice that the pipe is closed" but it's not so:
consider the horrible case of `set var (yes &)` and abandon all hope.

The current mechanism for removing the fd from the monitor is called a
"poke." We tell the fd monitor (through a "control" self-pipe) to
explicitly wake up the item. It then invokes the callback ("pokes") the
item on the dedicated fd monitor thread. The item notices that the command
substitution is complete, and it returns a value meaning "remove me" and
the fd monitor does so. The client thread is stuck waiting for this process
to complete.

So basically removing a fd from the monitor requires a round trip to its
dedicated thread. This is slow and also complicated (Rust doesn't have
futures)!

So let's not do that.

The big idea is to remove this round-trip synchronization. That is, when we
intend to remove the fd from the fd monitor, we _just do it_ and then close
the fd. Use a lock rather than a round-trip to the thread. Crucially that
lock is unlocked while the monitor thread waits in select/poll.

This invites all sorts of races:

1. fish might remove and close the fd right before the monitor polls it. It
   will thus attempt to poll a closed fd.
2. fish might remove and close the fd, and then something else opens a file
   and receives the same fd. Now the fd monitor will poll an fd that was
   never added.
3. fish might remove and close the fd _while the fd monitor is polling it_.
   What happens then? (Turns out on macOS we get EBADF, and on Linux the fd is
   marked readable).

The Big Idea is that *all of these races are benign*. As long as
poll/select doesn't crash or hang, we don't care *what* it returns, because
the source of truth are the set of items stored in the fd monitor and these
item IDs are never recycled. (This also assumes that it's OK to select/poll
on random file descriptors; there ought to be no side effects).

Not only is this a large simplification since we no longer need that round
trip, it's a substantial performance improvement as well. The
"aliases.fish" benchmark goes from 164 to 154 msec on my Mac, and from 124
to 112 msec on my Linux machine - nearly 10%.

Add some tests to verify our assumptions about the behavior of closing or
replacing a file descriptor during poll. But even if these fail, all we
care about is that poll/select doesn't crash or hang.
2024-12-27 13:23:11 -08:00
Peter Ammon
5e59762117 FdMonitor: Use a HashMap instead of Vec of items
Preparing for a substantial optimization.
2024-12-27 13:23:11 -08:00
Peter Ammon
69fdbc89d6 Refactor FdMonitorItem readability checks
No functional change. Preparing for an optimization.
2024-12-27 13:21:44 -08:00
Peter Ammon
244c55f9ce FdMonitor: change_signaller to be held strongly not weakly
There's no reason to use Weak here, especially since we just unwrap it. There's
no reference cycles, so just share the data via Arc.
2024-12-27 13:21:44 -08:00
Peter Ammon
b7ae159824 Remove the ability for FdMonitorItems to have timeouts
FdMonitor is used to monitor a set of file descriptors and invoke a callback
when one becomes readable. Prior to this commit, they coudl also have the
callback invoked on timeout. fish used to use this feature but no longer does;
remove it.
2024-12-27 13:03:49 -08:00
Peter Ammon
6dad396498 Clean up some stale comments 2024-12-27 13:03:49 -08:00
Fabian Boehm
f5a02e590d Fix tmux-multiline-prompt check 2024-12-27 21:02:38 +01:00
Fabian Boehm
36c632889b pexpects: Fix some escapes
Python has become stricter about unknown `\x` in strings, firing a
SyntaxWarning right now.

They need to be `\\x`.
2024-12-27 20:05:10 +01:00
Dmitry Gerasimov
c473aa60a7 completions/dnf: Fix completions for DNF5 (#9862)
Since DNF5 there's no implicit \n in repoquery output. For DNF4 this change
leaves blank lines in the output, but they are ignored anyway.
2024-12-26 12:01:49 -08:00
David Adam
6515862095 Debian packaging: move comments to their own lines 2024-12-26 14:53:04 +08:00
phanium
94dfe1b053 Fix alt-e cursor position restore on Vim <= 8 (#10946) 2024-12-26 06:35:37 +01:00
David Adam
0b52b72ebc Debian packaging: comment on reason for runtime dependencies 2024-12-26 13:22:30 +08:00
David Adam
eade6a5672 Debian packaging: add some missing runtime dependencies 2024-12-26 13:21:33 +08:00
David Adam
044cea1bf3 update CMake requirement
find_rust uses LIST(POP_BACK), which was added in 3.15.
2024-12-26 13:20:00 +08:00
David Adam
74b1247461 Debian packaging: reformat dependencies 2024-12-26 13:19:41 +08:00
Fabian Boehm
9b8793a2df docs: Use grid in the CSS (#10942)
Instead of hardcoded 230px margin.

This also makes the ToC only take up a third of the screen when
narrow, and lets you scroll the rest.

Without, you'd have to scroll past the *entire* ToC, which is awkward

Remaining issue is the search box up top. Since this disables the one
in the sidebar once the window gets too narrow, that one is important,
and it isn't *great*
2024-12-25 14:50:27 +01:00
Blair Noctis
6c63139d23 refactor: macroize SIGNAL_TABLE entries
reducing boilerplate and chance of typo
2024-12-24 15:25:10 +01:00
Mahmoud Al-Qudsi
f3dd4ee022 Fix typo in hard-coded name of SIGSTKFLT 2024-12-23 14:29:00 -06:00
Mahmoud Al-Qudsi
7bafb0d1ae CHANGELOG: Fix Sphinx error on unnamed section 2024-12-23 13:54:21 -06:00
Mahmoud Al-Qudsi
46072e0fd6 completions/llm: Add completions for all subcommands 2024-12-23 13:50:10 -06:00
Mahmoud Al-Qudsi
c09a9246a1 completions/llm: Fix broken completion 2024-12-23 13:47:19 -06:00
Fabian Boehm
e2596d13cd Remove SIGUNUSED
It is, as the name implies, unused - it became SIGSYS, which we
already check.

Since it is entirely undefined on some architectures it causes a build
failure there, see discussion in #10633
2024-12-23 17:06:22 +01:00
Johannes Altmanninger
0153579a4c Fix build in non-colocated jj workspaces 2024-12-23 15:14:13 +01:00
Johannes Altmanninger
c1b460525c Temporary workaround for BSD WEXITSTATUS libc bug
The libc crate has a bug on BSD where WEXITSTATUS is not an 8-bit
value, causing assertion failures.

Any libc higher than our 0.2.155 would increase our MSRV, see libc
commit 5ddbdc29f (Bump MSRV to 1.71, 2024-01-07), so we want to
woraround this anyway.  It's probably not worth using a patched
version of libc since it's just one line.

While at it, tighten some types I guess.

Upstream fix: https://github.com/rust-lang/libc/pull/4213

Closes #10919
2024-12-23 14:34:59 +01:00
Johannes Altmanninger
5de6f4bb3d Provide old implementation of cancel-commandline as fallback
__fish_cancel_commandline was unused (even before) and has some issues
on multiline commandlines. Make it use the previously active logic.

Closes #10935
2024-12-23 14:34:59 +01:00
Johannes Altmanninger
54cc932215 Attempt to fix clippy lints 2024-12-23 14:34:59 +01:00
Johannes Altmanninger
e3864c752a Changelog: move integration branch entries there
See f237fb7b on the integration branch.
2024-12-23 14:34:59 +01:00
Johannes Altmanninger
03a9f4a775 sourcehut builds: remove obsolete "env"
As of efe4083dce (fish.spec/.builds: drop SHOW_INTERACTIVE_LOG,
2022-06-08) this is no longer necessary.
2024-12-23 08:40:02 +01:00
Johannes Altmanninger
7e5af914be Remove interactive-only completion hacks
I don't think these characters cause problems in filenames?
2024-12-23 08:40:02 +01:00
Johannes Altmanninger
ab4606430e Sort parser keywords 2024-12-23 08:40:02 +01:00
Fabian Boehm
774b7c7b5b staticbuilds: Make mac builds statically linked
This is the default on musl, but not other libcen
2024-12-22 22:25:27 +01:00
Fabian Boehm
6b1a9ef7ce staticbuilds: Add macos job 2024-12-22 22:21:42 +01:00
Fabian Boehm
c74afd4198 CHANGELOG 2024-12-22 18:16:07 +01:00
Fabian Boehm
3dc49d9d93 Allow installable builds to be installed into a specific path (#10923)
* Pass path to install()

It was dirty that it would re-get $HOME there anyway.

* Import wcs2osstring

* Allow installable builds to use a relocatable tree

If you give a path to `--install`, it will install fish into a
relocatable tree there, so

PATH/share/fish contains the datafiles
PATH/bin/fish contains the fish executable
PATH/etc/fish is sysconf

I am absolutely not sold on that last one - the way I always used
sysconfdir is that it is always /etc. This would be easy to fix but
should probably also be fixed for "regular" relocatable builds (no
idea who uses them).

An attempt at #10916

* Move install path into "install/" subdir

* Disable --install harder if not installable
2024-12-22 18:16:07 +01:00
Integral
b19a467ea6 Replace some PathBuf with Path avoid unnecessary heap allocation (#10929) 2024-12-21 12:34:27 -06:00
Johannes Altmanninger
381b38af0a Skip tmux multiline prompt test for BusyBox less
BusyBox less is present on alpine CI; it doesn't support the "+q"
command passing style, so it's not directly usable by this test.
2024-12-21 14:41:41 +01:00
Johannes Altmanninger
965bc78d33 Work around weird CI failures due to missing pre-execute \r\n
I forgot that 610338cc70 (On undo after execute, restore the cursor
position, 2024-12-21) would cause a fallout to tests:

It makes us reuse in another place our usual cursor-movement sequences.

This causes failures like this (linebreaks added for readability):

	Testing file pexpects/bind.py:Failed to match pattern: (?:\r\n|\x1b\[2 q)[^\n]*def abc\r\n
	bind.py:45: timeout from expect_prompt(TO_END + "def abc\r\n")  # emacs transpose words, default timeout: no delay

	Escaped buffer:
	\x1b[?2004h\x1b[>4;1m\x1b[=5u\x1b=\rprompt 2>echo \rprompt 2>echo abc \rprompt 2>echo def abc\r
	prompt 2>echo def abc\x1b[?2004l\x1b[>4;0m\x1b[=0u\x1b>\x1b]133;C\x07def abc\r\n\x1b]133;D;0\x07\x1b[?25h⏎
	\r⏎ \r\rprompt 3>\x1b[?2004h\x1b[>4;1m\x1b[=5u\x1b=

It seems that we don't print anything where we should print something
like "\r\n" or "\e[2 q" to move the cursor below the command line.

I haven't gotten to the bottom of this but it might be related to
terminfo. Once we get rid of that, we can unconditionally print
our canonical movement sequences.

This issue seems to only affect tests, since fish operates fine in
a sourcehut CI system. Let's ignore it for now.
2024-12-21 14:37:57 +01:00
Johannes Altmanninger
610338cc70 On undo after execute, restore the cursor position
Ever since 149594f974 (Initial revision, 2005-09-20), we move the
cursor to the end of the commandline just before executing it.

This is so we can move the cursor to the line below the command line,
so moving the cursor is relevant if one presses enter on say, the
first line of a multi-line commandline.

As mentioned in #10838 and others, it can be useful to restore the
cursor position when recalling commandline from history. Make undo
restore the position where enter was pressed, instead of implicitly
moving the cursor to the end. This allows to quickly correct small
mistakes in large commandlines that failed recently.

This requires a new way of moving the cursor below the command line.
Test changes include unrelated cleanup of history.py.
2024-12-21 13:10:34 +01:00
Johannes Altmanninger
f9fb026085 Document possible CMake/Rust versions usable for Git bisect
rustc and CMake are usually backwards compatible but with Corrosion
in the mix this is often not the case.
Here's the canonical place to document it.
2024-12-21 13:07:01 +01:00
905 changed files with 575121 additions and 759015 deletions

View File

@@ -24,4 +24,4 @@ tasks:
ninja
- test: |
cd fish-shell/build
env ninja test
ninja test

View File

@@ -20,4 +20,4 @@ tasks:
ninja
- test: |
cd fish/build
env ninja test
ninja test

8
.cargo/config.toml Normal file
View File

@@ -0,0 +1,8 @@
# This file is _not_ included in the tarballs for now
# Binary builds on Linux packaging infrastructure need to overwrite it to make `cargo vendor` work
# Releases and development builds made using OBS/Launchpad will _not_ reflect the contents of this
# file
[resolver]
# Make cargo 1.84+ respect MSRV (rust-version in Cargo.toml)
incompatible-rust-versions = "fallback"

View File

@@ -20,17 +20,15 @@ linux_task:
# container:
# <<: *step
# image: ghcr.io/krobelus/fish-ci/focal-32bit:latest
tests_script:
# cirrus at times gives us 32 procs and 2 GB of RAM
# Unrestriced parallelism results in OOM
- lscpu || true
- (cat /proc/meminfo | grep MemTotal) || true
- mkdir build && cd build
- cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCTEST_PARALLEL_LEVEL=6 ..
- FISH_TEST_MAX_CONCURRENCY=6 cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ..
- ninja -j 6 fish
- ninja fish_run_tests
only_if: $CIRRUS_REPO_OWNER == 'fish-shell'
linux_arm_task:
@@ -41,34 +39,26 @@ linux_arm_task:
- name: jammy-armv7-32bit
arm_container:
image: ghcr.io/fish-shell/fish-ci/jammy-armv7-32bit
tests_script:
# cirrus at times gives us 32 procs and 2 GB of RAM
# Unrestriced parallelism results in OOM
- lscpu || true
- (cat /proc/meminfo | grep MemTotal) || true
- mkdir build && cd build
- cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCTEST_PARALLEL_LEVEL=6 ..
- FISH_TEST_MAX_CONCURRENCY=6 cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ..
- ninja -j 6 fish
- file ./fish
- ninja fish_run_tests
# CI task disabled during RIIR transition
only_if: false && $CIRRUS_REPO_OWNER == 'fish-shell'
freebsd_task:
matrix:
# - name: FreeBSD 14
# freebsd_instance:
# image_family: freebsd-14-0-snap
- name: FreeBSD 13
- name: FreeBSD 14
freebsd_instance:
image: freebsd-13-2-release-amd64
# - name: FreeBSD 12.3
# freebsd_instance:
# image: freebsd-12-3-release-amd64
image: freebsd-14-3-release-amd64-ufs
tests_script:
- pkg install -y cmake-core devel/pcre2 devel/ninja misc/py-pexpect git-lite terminfo-db
- pkg install -y cmake-core devel/pcre2 devel/ninja gettext git-lite lang/rust misc/py-pexpect
# libclang.so is a required build dependency for rust-c++ ffi bridge
- pkg install -y llvm
# BSDs have the following behavior: root may open or access files even if
@@ -81,16 +71,7 @@ freebsd_task:
- mkdir build && cd build
- chown -R fish-user ..
- sudo -u fish-user -s whoami
# FreeBSD's pkg currently has rust 1.66.0 while we need rust 1.70.0+. Use rustup to install
# the latest, but note that it only installs rust per-user.
- sudo -u fish-user -s fetch -qo - https://sh.rustup.rs > rustup.sh
- sudo -u fish-user -s sh ./rustup.sh -y --profile=minimal
# `sudo -s ...` does not invoke a login shell so we need a workaround to make sure the
# rustup environment is configured for subsequent `sudo -s ...` commands.
# For some reason, this doesn't do the job:
# - sudo -u fish-user sh -c 'echo source \$HOME/.cargo/env >> $HOME/.cshrc'
- sudo -u fish-user -s cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCTEST_PARALLEL_LEVEL=1 ..
- sudo -u fish-user sh -c '. $HOME/.cargo/env; ninja -j 6 fish'
- sudo -u fish-user sh -c '. $HOME/.cargo/env; ninja fish_run_tests'
- sudo -u fish-user -s FISH_TEST_MAX_CONCURRENCY=1 cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ..
- sudo -u fish-user -s ninja -j 6 fish
- sudo -u fish-user -s ninja fish_run_tests
only_if: $CIRRUS_REPO_OWNER == 'fish-shell'

View File

@@ -13,16 +13,20 @@ max_line_length = 100
indent_style = tab
[*.{md,rst}]
max_line_length = unset
trim_trailing_whitespace = false
[*.{sh,ac}]
indent_size = 2
[*.sh]
indent_size = 4
[build_tools/release.sh]
max_line_length = 72
[Dockerfile]
indent_size = 2
[share/{completions,functions}/**.fish]
max_line_length = off
max_line_length = unset
[{COMMIT_EDITMSG,git-revise-todo}]
max_line_length = 80
[{COMMIT_EDITMSG,git-revise-todo,*.jjdescription}]
max_line_length = 72

16
.gitattributes vendored
View File

@@ -1,13 +1,12 @@
# normalize newlines
* text=auto
*.fish text
*.bat eol=crlf
* text=auto eol=lf
# let git show off diff hunk headers, help git diff -L:
# https://git-scm.com/docs/gitattributes
*.cpp diff=cpp
*.c diff=cpp
*.h diff=cpp
*.py diff=py
*.rs diff=rust
# add a [diff "fish"] to git config with pattern
*.fish diff=fish
@@ -21,12 +20,13 @@
/.github/* export-ignore
/.builds export-ignore
/.builds/* export-ignore
# to make cargo vendor work correctly
/.cargo/ export-ignore
/.cargo/config.toml export-ignore
# for linguist; let github identify our project as C++ instead of C due to pcre2
pcre2/** linguist-vendored
# for linguist, which drives GitHub's language statistics
alpine.js linguist-vendored
doc_src/** linguist-documentation
*.fish linguist-language=fish
src/*.h linguist-language=c++
src/builtins/*.h linguist-language=c++
# see 70f2899fcd which attempts to "rig the count"
share/completions/*.fish linguist-documentation

View File

@@ -1,10 +1,18 @@
---
name: "Bug Report"
about: "Simple template for bug reports"
title: ""
labels: []
assignees: []
---
<!--
Please tell us which fish version you are using by executing the following:
fish --version
echo $version
Please tell us which operating system and terminal you are using. The output of `uname -a` and `echo $TERM` may be helpful in this regard although other commands might be relevant in your specific situation.
Please tell us which operating system (output of `uname`) and terminal you are using.
Please tell us if you tried fish without third-party customizations by executing this command and whether it affected the behavior you are reporting:

View File

@@ -0,0 +1,14 @@
name: Install sphinx-markdown-builder
permissions:
contents: read
runs:
using: "composite"
steps:
- shell: bash
run: |
set -x
commit=b259de1dc97573a71470a1d71c3d83535934136b
pip install git+https://github.com/krobelus/sphinx-markdown-builder@"$commit"
python -c 'import sphinx_markdown_builder'

View File

@@ -0,0 +1,20 @@
name: Oldest Supported Rust Toolchain
inputs:
targets:
description: Comma-separated list of target triples to install for this toolchain
required: false
components:
description: Comma-separated list of components to be additionally installed
required: false
permissions:
contents: read
runs:
using: "composite"
steps:
- uses: dtolnay/rust-toolchain@1.70
with:
targets: ${{ inputs.targets }}
components: ${{ inputs.components}}

View File

@@ -0,0 +1,20 @@
name: Stable Rust Toolchain
inputs:
targets:
description: Comma-separated list of target triples to install for this toolchain
required: false
components:
description: Comma-separated list of components to be additionally installed
required: false
permissions:
contents: read
runs:
using: "composite"
steps:
- uses: dtolnay/rust-toolchain@1.90
with:
targets: ${{ inputs.targets }}
components: ${{ inputs.components }}

View File

@@ -8,16 +8,12 @@ jobs:
label-and-milestone:
runs-on: ubuntu-latest
steps:
# - name: Checkout repository
# uses: actions/checkout@v2
- name: Set label and milestone
id: set-label-milestone
uses: actions/github-script@v7
with:
script: |
const completionsLabel = 'completions';
const completionsMilestone = 'fish next-3.x';
// Get changed files in the pull request
const prNumber = context.payload.pull_request.number;
@@ -41,26 +37,4 @@ jobs:
labels: [completionsLabel],
});
console.log(`PR ${prNumber} assigned label "${completionsLabel}"`);
// Get the list of milestones
const { data: milestones } = await github.rest.issues.listMilestones({
owner: context.repo.owner,
repo: context.repo.repo,
});
// Find the milestone id
const milestone = milestones.find(milestone => milestone.title === completionsMilestone);
if (milestone) {
// Set the milestone for the PR
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
milestone: milestone.number
});
console.log(`PR ${prNumber} assigned milestone "${completionsMilestone}"`);
} else {
console.error(`Milestone "${completionsMilestone}" not found`);
}
}

View File

@@ -1,42 +0,0 @@
name: macOS build and codesign
on:
workflow_dispatch: # Enables manual trigger from GitHub UI
jobs:
build-and-code-sign:
runs-on: macos-latest
environment: macos-codesign
steps:
- uses: actions/checkout@v4
- name: Install Rust 1.73.0
uses: dtolnay/rust-toolchain@1.73.0
with:
targets: x86_64-apple-darwin
- name: Install Rust Stable
uses: dtolnay/rust-toolchain@stable
with:
targets: aarch64-apple-darwin
- name: build-and-codesign
run: |
cargo install apple-codesign
mkdir -p "$FISH_ARTEFACT_PATH"
echo "$MAC_CODESIGN_APP_P12_BASE64" | base64 --decode > /tmp/app.p12
echo "$MAC_CODESIGN_INSTALLER_P12_BASE64" | base64 --decode > /tmp/installer.p12
echo "$MACOS_NOTARIZE_JSON" > /tmp/notarize.json
./build_tools/make_pkg.sh -s -f /tmp/app.p12 -i /tmp/installer.p12 -p "$MAC_CODESIGN_PASSWORD" -n -j /tmp/notarize.json
rm /tmp/installer.p12 /tmp/app.p12 /tmp/notarize.json
env:
MAC_CODESIGN_APP_P12_BASE64: ${{ secrets.MAC_CODESIGN_APP_P12_BASE64 }}
MAC_CODESIGN_INSTALLER_P12_BASE64: ${{ secrets.MAC_CODESIGN_INSTALLER_P12_BASE64 }}
MAC_CODESIGN_PASSWORD: ${{ secrets.MAC_CODESIGN_PASSWORD }}
MACOS_NOTARIZE_JSON: ${{ secrets.MACOS_NOTARIZE_JSON }}
# macOS runners keep having issues loading Cargo.toml dependencies from git (GitHub) instead
# of crates.io, so give this a try. It's also sometimes significantly faster on all platforms.
CARGO_NET_GIT_FETCH_WITH_CLI: true
FISH_ARTEFACT_PATH: /tmp/fish-built
- uses: actions/upload-artifact@v4
with:
name: macOS Artefacts
path: /tmp/fish-built/*
if-no-files-found: error

View File

@@ -3,7 +3,7 @@ name: make fish_run_tests
on: [push, pull_request]
env:
CTEST_PARALLEL_LEVEL: "1"
FISH_TEST_MAX_CONCURRENCY: "4"
CMAKE_BUILD_PARALLEL_LEVEL: "4"
permissions:
@@ -16,22 +16,31 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@1.70
- uses: ./.github/actions/rust-toolchain@oldest-supported
- name: Install deps
run: |
sudo apt install gettext libpcre2-dev python3-pexpect tmux
sudo apt install gettext libpcre2-dev python3-pexpect python3-sphinx tmux
# Generate a locale that uses a comma as decimal separator.
sudo locale-gen fr_FR.UTF-8
- uses: ./.github/actions/install-sphinx-markdown-builder
- name: cmake
run: |
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo
- name: make
run: |
make VERBOSE=1
make -C build VERBOSE=1
- name: make fish_run_tests
run: |
make VERBOSE=1 test
make -C build VERBOSE=1 fish_run_tests
- name: translation updates
run: |
# Generate PO files. This should not result it a change in the repo if all translations are
# up to date.
# Ensure that fish is available as an executable.
PATH="$PWD/build:$PATH" build_tools/update_translations.fish
# Show diff output. Fail if there is any.
git --no-pager diff --exit-code || { echo 'There are uncommitted changes after regenerating the gettext PO files. Make sure to update them via `build_tools/update_translations.fish` after changing source files.'; exit 1; }
ubuntu-32bit-static-pcre2:
@@ -39,7 +48,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@1.70
- uses: ./.github/actions/rust-toolchain@oldest-supported
with:
targets: "i586-unknown-linux-gnu" # rust-toolchain wants this comma-separated
- name: Install deps
@@ -54,10 +63,10 @@ jobs:
cmake -DFISH_USE_SYSTEM_PCRE2=OFF -DRust_CARGO_TARGET=i586-unknown-linux-gnu ..
- name: make
run: |
make VERBOSE=1
make -C build VERBOSE=1
- name: make fish_run_tests
run: |
make VERBOSE=1 test
make -C build VERBOSE=1 fish_run_tests
ubuntu-asan:
@@ -82,17 +91,18 @@ jobs:
- name: Install deps
run: |
sudo apt install gettext libpcre2-dev python3-pexpect tmux
sudo apt install llvm # for llvm-symbolizer
- name: cmake
env:
CC: clang
run: |
mkdir build && cd build
# Rust's ASAN requires the build system to explicitly pass a --target triple. We read that
# value from CMake variable Rust_CARGO_TARGET (shared with corrosion).
# value from CMake variable Rust_CARGO_TARGET.
cmake .. -DASAN=1 -DRust_CARGO_TARGET=x86_64-unknown-linux-gnu -DCMAKE_BUILD_TYPE=Debug
- name: make
run: |
make VERBOSE=1
make -C build VERBOSE=1
- name: make fish_run_tests
env:
FISH_CI_SAN: 1
@@ -104,10 +114,10 @@ jobs:
# UPDATE: this can cause spurious leak reports for __cxa_thread_atexit_impl() under glibc.
LSAN_OPTIONS: verbosity=0:log_threads=0:use_tls=1:print_suppressions=0
run: |
llvm_version=$(clang --version | awk 'NR==1 { split($NF, version, "."); print version[1] }')
export ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-$llvm_version
set -x
export ASAN_SYMBOLIZER_PATH=$(command -v /usr/bin/llvm-symbolizer* | sort -n | head -1)
export LSAN_OPTIONS="$LSAN_OPTIONS:suppressions=$PWD/build_tools/lsan_suppressions.txt"
make VERBOSE=1 test
make -C build VERBOSE=1 fish_run_tests
# Our clang++ tsan builds are not recognizing safe rust patterns (such as the fact that Drop
# cannot be called while a thread is using the object in question). Rust has its own way of
@@ -119,7 +129,7 @@ jobs:
#
# steps:
# - uses: actions/checkout@v4
# - uses: dtolnay/rust-toolchain@1.70
# - uses: ./.github/actions/rust-toolchain@oldest-supported
# - name: Install deps
# run: |
# sudo apt install gettext libpcre2-dev python3-pexpect tmux
@@ -135,7 +145,7 @@ jobs:
# make
# - name: make fish_run_tests
# run: |
# make fish_run_tests
# make -C build fish_run_tests
macos:
@@ -147,7 +157,7 @@ jobs:
CARGO_NET_GIT_FETCH_WITH_CLI: true
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@1.70
- uses: ./.github/actions/rust-toolchain@oldest-supported
- name: Install deps
run: |
# --break-system-packages because homebrew has now declared itself "externally managed".
@@ -157,10 +167,10 @@ jobs:
- name: cmake
run: |
mkdir build && cd build
cmake -DWITH_GETTEXT=NO -DCMAKE_BUILD_TYPE=Debug ..
cmake -DCMAKE_BUILD_TYPE=Debug ..
- name: make
run: |
make VERBOSE=1
make -C build VERBOSE=1
- name: make fish_run_tests
run: |
make VERBOSE=1 test
make -C build VERBOSE=1 fish_run_tests

189
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,189 @@
name: Create a new release
on:
workflow_dispatch:
inputs:
version:
description: 'Version to release (tag name)'
required: true
type: string
permissions:
contents: write
jobs:
is-release-tag:
name: Pre-release checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# Workaround for https://github.com/actions/checkout/issues/882
ref: ${{ inputs.version }}
- name: Check if the pushed tag looks like a release
run: |
set -x
commit_subject=$(git log -1 --format=%s)
tag=$(git describe)
[ "$commit_subject" = "Release $tag" ]
source-tarball:
needs: [is-release-tag]
name: Create the source tarball
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
tarball-name: ${{ steps.version.outputs.tarball-name }}
steps:
- uses: actions/checkout@v4
with:
# Workaround for https://github.com/actions/checkout/issues/882
ref: ${{ inputs.version }}
- name: Install dependencies
run: sudo apt install cmake gettext ninja-build python3-pip python3-sphinx
- uses: ./.github/actions/install-sphinx-markdown-builder
- name: Create tarball
run: |
set -x
mkdir /tmp/fish-built
FISH_ARTEFACT_PATH=/tmp/fish-built ./build_tools/make_tarball.sh
relnotes=/tmp/fish-built/release-notes.md
# Need history since the last release (i.e. tag) for stats.
git fetch --tags
git fetch --unshallow
sh -x ./build_tools/release-notes.sh >"$relnotes"
# Delete title
sed -n 1p "$relnotes" | grep -q "^## fish .*"
sed -n 2p "$relnotes" | grep -q '^$'
sed -i 1,2d "$relnotes"
- name: Upload tarball artifact
uses: actions/upload-artifact@v4
with:
name: source-tarball
path: |
/tmp/fish-built/fish-${{ inputs.version }}.tar.xz
/tmp/fish-built/release-notes.md
if-no-files-found: error
packages-for-linux:
needs: [is-release-tag]
name: Build single-file fish for Linux (experimental)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# Workaround for https://github.com/actions/checkout/issues/882
ref: ${{ inputs.version }}
- name: Install Rust Stable
uses: ./.github/actions/rust-toolchain@stable
with:
targets: x86_64-unknown-linux-musl,aarch64-unknown-linux-musl
- name: Install dependencies
run: sudo apt install crossbuild-essential-arm64 gettext musl-tools python3-sphinx
- name: Build statically-linked executables
run: |
set -x
cargo build --release --target x86_64-unknown-linux-musl --bin fish
CFLAGS="-D_FORTIFY_SOURCE=2" \
CC=aarch64-linux-gnu-gcc \
RUSTFLAGS="-C linker=aarch64-linux-gnu-gcc -C link-arg=-lgcc -C link-arg=-D_FORTIFY_SOURCE=0" \
cargo build --release --target aarch64-unknown-linux-musl --bin fish
- name: Compress
run: |
set -x
for arch in x86_64 aarch64; do
tar -cazf fish-$(git describe)-linux-$arch.tar.xz \
-C target/$arch-unknown-linux-musl/release fish
done
- uses: actions/upload-artifact@v4
with:
name: Static builds for Linux
path: fish-${{ inputs.version }}-linux-*.tar.xz
if-no-files-found: error
create-draft-release:
needs:
- is-release-tag
- source-tarball
- packages-for-linux
name: Create release draft
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# Workaround for https://github.com/actions/checkout/issues/882
ref: ${{ inputs.version }}
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
merge-multiple: true
path: /tmp/artifacts
- name: List artifacts
run: find /tmp/artifacts -type f
- name: Create draft release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ inputs.version }}
name: fish ${{ inputs.version }}
body_path: /tmp/artifacts/release-notes.md
draft: true
files: |
/tmp/artifacts/fish-${{ inputs.version }}.tar.xz
/tmp/artifacts/fish-${{ inputs.version }}-linux-*.tar.xz
packages-for-macos:
needs: [is-release-tag, create-draft-release]
name: Build packages for macOS
runs-on: macos-latest
environment: macos-codesign
steps:
- uses: actions/checkout@v4
with:
# Workaround for https://github.com/actions/checkout/issues/882
ref: ${{ inputs.version }}
- name: Install Rust
uses: ./.github/actions/rust-toolchain@oldest-supported
with:
targets: x86_64-apple-darwin
- name: Install Rust Stable
uses: ./.github/actions/rust-toolchain@stable
with:
targets: aarch64-apple-darwin
- name: Build and codesign
run: |
die() { echo >&2 "$*"; exit 1; }
[ -n "$MAC_CODESIGN_APP_P12_BASE64" ] || die "Missing MAC_CODESIGN_APP_P12_BASE64"
[ -n "$MAC_CODESIGN_INSTALLER_P12_BASE64" ] || die "Missing MAC_CODESIGN_INSTALLER_P12_BASE64"
[ -n "$MAC_CODESIGN_PASSWORD" ] || die "Missing MAC_CODESIGN_PASSWORD"
[ -n "$MACOS_NOTARIZE_JSON" ] || die "Missing MACOS_NOTARIZE_JSON"
set -x
export FISH_ARTEFACT_PATH=/tmp/fish-built
# macOS runners keep having issues loading Cargo.toml dependencies from git (GitHub) instead
# of crates.io, so give this a try. It's also sometimes significantly faster on all platforms.
export CARGO_NET_GIT_FETCH_WITH_CLI=true
cargo install apple-codesign
mkdir -p "$FISH_ARTEFACT_PATH"
echo "$MAC_CODESIGN_APP_P12_BASE64" | base64 --decode >/tmp/app.p12
echo "$MAC_CODESIGN_INSTALLER_P12_BASE64" | base64 --decode >/tmp/installer.p12
echo "$MACOS_NOTARIZE_JSON" >/tmp/notarize.json
./build_tools/make_macos_pkg.sh -s -f /tmp/app.p12 \
-i /tmp/installer.p12 -p "$MAC_CODESIGN_PASSWORD" \
-n -j /tmp/notarize.json
version=$(git describe)
[ -f "${FISH_ARTEFACT_PATH}/fish-$version.app.zip" ]
[ -f "${FISH_ARTEFACT_PATH}/fish-$version.pkg" ]
rm /tmp/installer.p12 /tmp/app.p12 /tmp/notarize.json
env:
MAC_CODESIGN_APP_P12_BASE64: ${{ secrets.MAC_CODESIGN_APP_P12_BASE64 }}
MAC_CODESIGN_INSTALLER_P12_BASE64: ${{ secrets.MAC_CODESIGN_INSTALLER_P12_BASE64 }}
MAC_CODESIGN_PASSWORD: ${{ secrets.MAC_CODESIGN_PASSWORD }}
MACOS_NOTARIZE_JSON: ${{ secrets.MACOS_NOTARIZE_JSON }}
- name: Add macOS packages to the release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
version=$(git describe)
gh release upload $version \
/tmp/fish-built/fish-$version.app.zip \
/tmp/fish-built/fish-$version.pkg

View File

@@ -8,34 +8,54 @@ permissions:
jobs:
rustfmt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@stable
- uses: ./.github/actions/rust-toolchain@stable
with:
components: rustfmt
- name: cargo fmt
run: cargo fmt --check --all
run: cargo fmt --check
clippy:
clippy-stable:
runs-on: ubuntu-latest
strategy:
matrix:
features: ["", "--no-default-features"]
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@stable
- uses: ./.github/actions/rust-toolchain@stable
with:
components: clippy
- name: Install deps
run: |
sudo apt install gettext libpcre2-dev
- name: cmake
run: |
cmake -B build
sudo apt install gettext
- name: cargo clippy
# This used to have --deny=warnings, but that turns rust release day
# into automatic CI failure day, so we don't do that.
run: cargo clippy --workspace --all-targets
run: cargo clippy --workspace --all-targets ${{ matrix.features }} -- --deny=warnings
# Disabling for now because it also checks "advisories",
# making CI fail for reasons unrelated to the patch
# cargo-deny:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v3
# - uses: EmbarkStudios/cargo-deny-action@v1
clippy-msrv:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/rust-toolchain@oldest-supported
with:
components: clippy
- name: Install deps
run: |
sudo apt install gettext
- name: cargo clippy
run: cargo clippy --workspace --all-targets -- --deny=warnings
rustdoc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/rust-toolchain@stable
- name: Install deps
run: |
sudo apt install gettext
- name: cargo doc
run: |
RUSTDOCFLAGS='-D warnings' cargo doc --workspace
- name: cargo doctest
run: |
cargo test --doc --workspace

View File

@@ -1,47 +0,0 @@
name: staticbuilds
on:
# release:
# types: [published]
# schedule:
# - cron: "14 13 * * *"
workflow_dispatch:
env:
CTEST_PARALLEL_LEVEL: "1"
CMAKE_BUILD_PARALLEL_LEVEL: "4"
jobs:
staticbuilds:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: dtolnay/rust-toolchain@1.70
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Prepare
run: |
sudo apt install python3-sphinx
rustup target add x86_64-unknown-linux-musl
rustup target add aarch64-unknown-linux-musl
sudo apt install musl-tools crossbuild-essential-arm64 -y
- name: Build
run: |
CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" CMAKE_WITH_GETTEXT=0 CC=aarch64-linux-gnu-gcc RUSTFLAGS="-C linker=aarch64-linux-gnu-gcc -C link-arg=-lgcc -C link-arg=-D_FORTIFY_SOURCE=0" cargo build --release --target aarch64-unknown-linux-musl
cargo build --release --target x86_64-unknown-linux-musl
- name: Compress
run: |
tar -cazf fish-amd64.tar.xz -C target/x86_64-unknown-linux-musl/release/ fish{,_indent,_key_reader}
tar -cazf fish-aarch64.tar.xz -C target/aarch64-unknown-linux-musl/release/ fish{,_indent,_key_reader}
- uses: actions/upload-artifact@v4
with:
name: fish
path: |
fish-amd64.tar.xz
fish-aarch64.tar.xz
retention-days: 14

5
.gitignore vendored
View File

@@ -38,7 +38,6 @@ Desktop.ini
Thumbs.db
ehthumbs.db
messages.pot
.directory
.fuse_hidden*
@@ -77,6 +76,7 @@ __pycache__
/share/__fish_build_paths.fish
/share/pkgconfig
/tests/*.tmp.*
/tests/.last-check-all-files
# xcode
## Build generated
@@ -102,3 +102,6 @@ target/
# Generated by clangd
/.cache
# JetBrains editors.
.idea/

View File

@@ -1,3 +1,314 @@
fish 4.1.2 (released October 07, 2025)
======================================
This release fixes the following regressions identified in 4.1.0:
- Fixed spurious error output when completing remote file paths for ``scp`` (:issue:`11860`).
- Fixed the :kbd:`alt-l` binding not formatting ``ls`` output correctly (one entry per line, no colors) (:issue:`11888`).
- Fixed an issue where focus events (currently only enabled in ``tmux``) would cause multiline prompts to be redrawn in the wrong line (:issue:`11870`).
- Stopped printing output that would cause a glitch on old versions of Midnight Commander (:issue:`11869`).
- Added a fix for some configurations of Zellij where :kbd:`escape` key processing was delayed (:issue:`11868`).
- Fixed a case where the :doc:`web-based configuration tool <cmds/fish_config>` would generate invalid configuration (:issue:`11861`).
- Fixed a case where pasting into ``fish -c read`` would fail with a noisy error (:issue:`11836`).
- Fixed a case where upgrading fish would break old versions of fish that were still running.
In general, fish still needs to be restarted after it is upgraded,
except for `standalone builds <https://github.com/fish-shell/fish-shell/?tab=readme-ov-file#building-fish-with-embedded-data-experimental>`__.
fish 4.1.1 (released September 30, 2025)
========================================
This release fixes the following regressions identified in 4.1.0:
- Many of our new Chinese translations were more confusing than helpful; they have been fixed or removed (:issue:`11833`).
Note that you can work around this type of issue by configuring fish's :doc:`message localization <cmds/_>`:
if your environment contains something like ``LANG=zh_CN.UTF-8``,
you can use ``set -g LC_MESSAGES en`` to use English messages inside fish.
This will not affect fish's child processes unless ``LC_MESSAGES`` was already exported.
- Some :doc:`fish_config <cmds/fish_config>` subcommands for showing prompts and themes had been broken in standalone Linux builds (those using the ``embed-data`` cargo feature), which has been fixed (:issue:`11832`).
- On Windows Terminal, we observed an issue where fish would fail to read the terminal's response to our new startup queries, causing noticeable lags and a misleading error message. A workaround has been added (:issue:`11841`).
- A WezTerm `issue breaking shifted key input <https://github.com/wezterm/wezterm/issues/6087>`__ has resurfaced on some versions of WezTerm; our workaround has been extended to cover all versions for now (:issue:`11204`).
- Fixed a crash in :doc:`the web-based configuration tool <cmds/fish_config>` when using the new underline styles (:issue:`11840`).
fish 4.1.0 (released September 27, 2025)
========================================
.. ignore for 4.1: 10929 10940 10948 10955 10965 10975 10989 10990 10998 11028 11052 11055 11069 11071 11079 11092 11098 11104 11106 11110 11140 11146 11148 11150 11214 11218 11259 11288 11299 11328 11350 11373 11395 11417 11419
Notable improvements and fixes
------------------------------
- Compound commands (``begin; echo 1; echo 2; end``) can now be written using braces (``{ echo1; echo 2 }``), like in other shells.
- fish now supports transient prompts: if :envvar:`fish_transient_prompt` is set to 1, fish will reexecute prompt functions with the ``--final-rendering`` argument before running a commandline (:issue:`11153`).
- Tab completion results are truncated up to the common directory path, instead of somewhere inside that path. E.g. if you complete "share/functions", and it includes the files "foo.fish" and "bar.fish",
the completion pager will now show "…/foo.fish" and "…/bar.fish" (:issue:`11250`).
- Self-installing builds as created by e.g. ``cargo install`` no longer install other files, see :ref:`below <changelog-4.1-embedded>`.
- Our gettext-based message-localization has been reworked,
adding translations to self-installing builds; see :ref:`below <changelog-4.1-gettext>`.
Deprecations and removed features
---------------------------------
- ``set_color --background=COLOR`` no longer implicitly activates bold mode.
If your theme is stored in universal variables (the historical default), some bold formatting might be lost.
To fix this, we suggest updating to the latest version of our theme, to explicitly activate bold mode,
for example use ``fish_config theme save "fish default"``.
- ``{echo,echo}`` or ``{ echo, echo }`` are no longer interpreted as brace expansion tokens but as :doc:`compound commands <cmds/begin>`.
- Terminfo-style key names (``bind -k nul``) are no longer supported. They had been superseded by fish's :doc:`own key names <cmds/bind>` since 4.0 (:issue:`11342`).
- fish no longer reads the terminfo database, so its behavior is generally no longer affected by the :envvar:`TERM` environment variable (:issue:`11344`).
For the time being, this change can be reversed via the ``ignore-terminfo`` :ref:`feature flag <featureflags>`.
To do so, run the following once and restart fish::
set -Ua fish_features no-ignore-terminfo
- The ``--install`` option when fish is built as self-installing is removed, see :ref:`below <changelog-4.1-embedded>`.
- ``set_color ff0000`` now outputs 24-bit RGB true-color even if :envvar:`COLORTERM` is unset.
One can override this by setting :envvar:`fish_term24bit` to 0 (:issue:`11372`).
- fish now requires the terminal to respond to queries for the :ref:`Primary Device Attribute <term-compat-primary-da>`.
For now, this can be reversed via a :ref:`feature flag <featureflags>`,
by running (once) ``set -Ua fish_features no-query-term`` and restarting fish.
- Users of GNU screen may experience :ref:`minor glitches <term-compat-dcs-gnu-screen>` when starting fish.
Scripting improvements
----------------------
- The :doc:`argparse <cmds/argparse>` builtin has seen many improvements, see :ref:`below <changelog-4.1-argparse>`.
- The :doc:`string pad <cmds/string-pad>` command now has a ``-C/--center`` option.
- The :doc:`psub <cmds/psub>` command now allows combining ``--suffix`` with ``--fifo`` (:issue:`11729`).
- The :doc:`read <cmds/read>` builtin has learned the ``--tokenize-raw`` option to tokenize without quote removal (:issue:`11084`).
Interactive improvements
------------------------
- Autosuggestions are now also provided in multi-line command lines. Like :kbd:`ctrl-r`, these operate only on the current line.
- Autosuggestions used to not suggest multi-line command-lines from history; now autosuggestions include individual lines from multi-line command-lines.
- The history pager search now preserves ordering between :kbd:`ctrl-s` forward and :kbd:`ctrl-r` backward searches.
- Instead of highlighting events by flashing *all text to the left of the cursor*,
failing history token search (:kbd:`alt-.`) flashes the associated token,
failing tab-completion flashes the to-be-completed token (:issue:`11050`),
deleting an autosuggestion (:kbd:`shift-delete`) flashes the suggestion,
and all other scenarios flash the full command line.
- Pasted commands are now stripped of any :code:`$\ ` command prefixes, to help pasting code snippets.
- Builtin help options (e.g. ``abbr --help``) now use ``man`` directly, meaning that variables like :envvar:`MANWIDTH` are respected (:issue:`11786`).
- ``funced`` will now edit copied functions directly, instead of the file where ``function --copy`` was invoked. (:issue:`11614`)
- Added a simple ``fish_jj_prompt`` which reduces visual noise in the prompt inside `Jujutsu <https://jj-vcs.github.io/jj/latest/>`__ repositories that are colocated with Git.
New or improved bindings
^^^^^^^^^^^^^^^^^^^^^^^^
- On non-macOS systems, :kbd:`alt-left`, :kbd:`alt-right`, :kbd:`alt-backspace` and :kbd:`alt-delete` no longer operate on punctuation-delimited words but on whole arguments, possibly including special characters like ``/`` and quoted spaces.
On macOS, the corresponding :kbd:`ctrl-` prefixed keys operate on whole arguments.
Word operations are still available via the other respective modifier, just like in most web browsers.
- :kbd:`ctrl-z` (undo) after executing a command will restore the previous cursor position instead of placing the cursor at the end of the command line.
- The :kbd:`alt-s` binding will now also use ``run0`` if available.
- Some mouse support has been added: the OSC 133 prompt marking feature has learned about kitty's ``click_events=1`` flag, which allows moving fish's cursor by clicking in the command line,
and selecting pager items (:issue:`10932`).
- Before clearing the screen and redrawing, :kbd:`ctrl-l` now pushes all text located above the prompt to the terminal's scrollback,
via a new special input function :ref:`scrollback-push <special-input-functions-scrollback-push>`.
For compatibility with terminals that do not implement ECMA-48's :ref:`SCROLL UP <term-compat-indn>` command,
this function is only used if the terminal advertises support for that via :ref:`XTGETTCAP <term-compat-xtgettcap>`.
- Vi mode has learned :kbd:`ctrl-a` (increment) and :kbd:`ctrl-x` (decrement) (:issue:`11570`).
Completions
^^^^^^^^^^^
- ``git`` completions now show the remote URL as description when completing remotes.
- ``systemctl`` completions no longer print escape codes if ``SYSTEMD_COLORS`` happens to be set (:issue:`11465`).
- Added and improved many completion scripts, notably ``tmux``.
Improved terminal support
^^^^^^^^^^^^^^^^^^^^^^^^^
- Support for double, curly, dotted and dashed underlines, for use in ``fish_color_*`` variables and the :doc:`set_color builtin <cmds/set_color>` (:issue:`10957`).
- Underlines can now be colored independent of text (:issue:`7619`).
- New documentation page :doc:`Terminal Compatibility <terminal-compatibility>` (also accessible via ``man fish-terminal-compatibility``) lists the terminal control sequences used by fish.
Other improvements
------------------
- Updated Chinese and German translations.
- ``fish_indent --dump-parse-tree`` now emits simple metrics about the tree including its memory consumption.
- We added some tools to improve development workflows, for example ``build_tools/{check,update_translations,release}.sh`` and ``tests/test_driver.py``.
In conjunction with ``cargo``, these enable almost all day-to-day development tasks without using CMake.
For distributors
----------------
- Builtin commands that support the ``--help`` option now require the ``man`` program.
The direct dependency on ``mandoc`` and ``nroff`` has been removed.
- fish no longer uses gettext MO files, see :ref:`below <changelog-4.1-gettext>`.
If you have use cases which are incompatible with our new approach, please let us know.
- The :doc:`fish_indent <cmds/fish_indent>` and :doc:`fish_key_reader <cmds/fish_key_reader>` programs are now also available as builtins.
If fish is invoked via e.g. a symlink with one of these names,
it will act like the given tool (i.e. it's a multi-call binary).
This allows truly distributing fish as a single file (:issue:`10876`).
- The CMake build configuration has been simplified and no longer second-guesses rustup.
It will run rustc and cargo via :envvar:`PATH` or in ~/.cargo/bin/.
If that doesn't match your setup, set the Rust_COMPILER and Rust_CARGO CMake variables (:issue:`11328`).
- Cygwin support has been reintroduced, since `Rust gained a Cygwin target <https://github.com/rust-lang/rust/pull/134999>`__ (:issue:`11238`).
- CMake 3.15 is now required.
.. _changelog-4.1-embedded:
Changes to self-installing builds
---------------------------------
The self-installing build type introduced in fish 4.0 has been changed (:issue:`11143`).
Now fish built with embedded data will just read the data straight from its own binary or write it out to temporary files when necessary, instead of requiring an installation step on start.
That means it is now possible to build fish as a single file and copy it to any system with a compatible CPU architecture, including as a different user, without extracting any files.
As before, this is the default when building via ``cargo``, and disabled when building via CMake.
For packagers we continue to recommend CMake.
Note: When fish is built like this, the :envvar:`__fish_data_dir` variable will be empty because that directory no longer has meaning.
You should generally not need these files.
For example, if you want to make sure that completions for "foo" are loaded, use ``complete -C"foo " >/dev/null`` instead).
The raw files are still exposed via :ref:`status subcommands <status-get-file>`, mainly for fish's internal use, but you can also use them as a last resort.
Remaining benefits of a full installation (as currently done by CMake) are:
- man pages like ``fish(1)`` in standard locations, easily accessible from outside fish.
- a local copy of the HTML documentation, typically accessed via the :doc:`help <cmds/help>` function.
In builds with embedded data, ``help`` will redirect to e.g. `<https://fishshell.com/docs/current/>`__
- ``fish_indent`` and ``fish_key_reader`` as separate files, making them easily accessible outside fish
- an (empty) ``/etc/fish/config.fish`` as well as empty directories ``/etc/fish/{functions,completions,conf.d}``
- ``$PREFIX/share/pkgconfig/fish.pc``, which defines directories for configuration-snippets, like ``vendor_completions.d``
.. _changelog-4.1-gettext:
Changes to gettext localization
-------------------------------
We replaced several parts of the gettext functionality with custom implementations (:issue:`11726`).
Most notably, message extraction, which should now work reliably, and the runtime implementation, where we no longer dynamically link to gettext, but instead use our own implementation, whose behavior is similar to GNU gettext, with some :doc:`minor deviations <cmds/_>`.
Our implementation now fully respects fish variables, so locale variables do not have to be exported for fish localizations to work.
They still have to be exported to inform other programs about language preferences.
The :envvar:`LANGUAGE` environment variable is now treated as a path variable, meaning it is an implicitly colon-separated list.
While we no longer have any runtime dependency on gettext, we still need gettext tools for building, most notably ``msgfmt``.
When building without ``msgfmt`` available, localization will not work with the resulting executable.
Localization data is no longer sourced at runtime from MO files on the file system, but instead built into the executable.
This is always done, independently of the other data embedding, so all fish executables will have access to all message catalogs, regardless of the state of the file system.
Disabling our new ``localize-messages`` cargo feature will cause fish to be built without localization support.
CMake builds can continue to use the ``WITH_GETTEXT`` option, with the same semantics as the ``localize-messages`` feature.
The current implementation does not provide any configuration options for controlling which language catalogs are built into the executable (other than disabling them all).
As a workaround, you can delete files in the ``po`` directory before building to exclude unwanted languages.
.. _changelog-4.1-argparse:
Changes to the :doc:`argparse <cmds/argparse>` builtin
------------------------------------------------------
- ``argparse`` now saves recognised options, including option-arguments in :envvar:`argv_opts`, allowing them to be forwarded to other commands (:issue:`6466`).
- ``argparse`` options can now be marked to be deleted from :envvar:`argv_opts` (by adding a ``&`` at the end of the option spec, before a ``!`` if present). There is now also a corresponding ``-d`` / ``--delete`` option to ``fish_opt``.
- ``argparse --ignore-unknown`` now removes preceding known short options from groups containing unknown options (e.g. when parsing ``-abc``, if ``a`` is known but ``b`` is not, then :envvar:`argv` will contain ``-bc``).
- ``argparse`` now has an ``-u`` / ``--move-unknown`` option that works like ``--ignore-unknown`` but preserves unknown options in :envvar:`argv`.
- ``argparse`` now has an ``-S`` / ``--strict-longopts`` option that forbids abbreviating long options or passing them with a single dash (e.g. if there is a long option called ``foo``, ``--fo`` and ``--foo`` won't match it).
- ``argparse`` now has a ``-U`` / ``--unknown-arguments`` option to specify how to parse unknown option's arguments.
- ``argparse`` now allows specifying options that take multiple optional values by using ``=*`` in the option spec (:issue:`8432`).
In addition, ``fish_opt`` has been modified to support such options by using the ``--multiple-vals`` together with ``-o`` / ``--optional-val``; ``-m`` is also now acceptable as an abbreviation for ``--multiple-vals``.
- ``fish_opt`` no longer requires you give a short flag name when defining options, provided you give it a long flag name with more than one character.
- ``argparse`` option specifiers for long-only options can now start with ``/``, allowing the definition of long options with a single letter. Due to this change, the ``--long-only`` option to ``fish_opt`` is now no longer necessary and is deprecated.
- ``fish_opt`` now has a ``-v`` / ``--validate`` option you can use to give a fish script to validate values of the option.
--------------
fish 4.0.9 (released September 27, 2025)
========================================
This release fixes:
- a regression in 4.0.6 causing shifted keys to not be inserted on some terminals (:issue:`11813`).
- a regression in 4.0.6 causing the build to fail on systems where ``char`` is unsigned (:issue:`11804`).
- a regression in 4.0.0 causing a crash on an invalid :doc:`bg <cmds/bg>` invocation.
--------------
fish 4.0.8 (released September 18, 2025)
========================================
This release fixes a regression in 4.0.6 that caused user bindings to be shadowed by either fish's or a plugin's bindings (:issue:`11803`).
--------------
fish 4.0.6 (released September 12, 2025)
========================================
This release of fish fixes a number of issues identified in fish 4.0.2:
- fish now properly inherits $PATH under Windows WSL2 (:issue:`11354`).
- Remote filesystems are detected properly again on non-Linux systems.
- the :doc:`printf <cmds/printf>` builtin no longer miscalculates width of multi-byte characters (:issue:`11412`).
- For many years, fish has been "relocatable" -- it was possible to move the entire ``CMAKE_INSTALL_PREFIX`` and fish would use paths relative to its binary.
Only gettext locale paths were still determined purely at compile time, which has been fixed.
- the :doc:`commandline <cmds/commandline>` builtin failed to print the commandline set by a ``commandline -C`` invocation, which broke some completion scripts.
This has been corrected (:issue:`11423`).
- To work around terminals that fail to parse Operating System Command (OSC) sequences, a temporary feature flag has been added.
It allows you to disable prompt marking (OSC 133) by running (once) ``set -Ua fish_features no-mark-prompt`` and restarting fish (:issue:`11749`).
- The routines to save history and universal variables have seen some robustness improvements.
- builtin :doc:`status current-command <cmds/status>` no longer prints a trailing blank line.
- A crash displaying multi-line quoted command substitutions has been fixed (:issue:`11444`).
- Commands like ``set fish_complete_path ...`` accidentally disabled completion autoloading, which has been corrected.
- ``nmcli`` completions have been fixed to query network information dynamically instead of only when completing the first time.
- Git completions no longer print an error when no `git-foo` executable is in :envvar:`PATH`.
- Custom completions like ``complete foo -l long -xa ...`` that use the output of ``commandline -t``.
on a command-line like ``foo --long=`` have been invalidated by a change in 4.0; the completion scripts have been adjusted accordingly (:issue:`11508`).
- Some completions were misinterpreted, which caused garbage to be displayed in the completion list. This has been fixed.
- fish no longer interprets invalid control sequences from the terminal as if they were :kbd:`alt-[` or :kbd:`alt-o` key strokes.
- :doc:`bind <cmds/bind>` has been taught about the :kbd:`printscreen` and :kbd:`menu` keys.
- :kbd:`alt-delete` now deletes the word right of the cursor.
- :kbd:`ctrl-alt-h` erases the last word again (:issue:`11548`).
- :kbd:`alt-left` :kbd:`alt-right` were misinterpreted because they send unexpected sequences on some terminals; a workaround has been added. (:issue:`11479`).
- Key bindings like ``bind shift-A`` are no longer accepted; use ``bind shift-a`` or ``bind A``.
- Key bindings like ``bind shift-a`` take precedence over ``bind A`` when the key event included the shift modifier.
- Bindings using shift with non-ASCII letters (such as :kbd:`ctrl-shift-ä`) are now supported.
- Bindings with modifiers such as ``bind ctrl-w`` work again on non-Latin keyboard layouts such as a Russian one.
This is implemented by allowing key events such as :kbd:`ctrl-ц` to match bindings of the corresponding Latin key, using the kitty keyboard protocol's base layout key (:issue:`11520`).
- Vi mode: The cursor position after pasting via :kbd:`p` has been corrected.
- Vi mode: Trying to replace the last character via :kbd:`r` no longer replaces the last-but-one character (:issue:`11484`).
--------------
fish 4.0.2 (released April 20, 2025)
====================================
This release of fish fixes a number of issues identified in fish 4.0.1:
- Completions are quoted, rather than backslash-escaped, only if the completion is unambiguous. Continuing to edit the token is therefore easier (:issue:`11271`). This changes the behavior introduced in 4.0.0 where all completions were quoted.
- The warning when the terminfo database can't be found has been downgraded to a log message. fish will act as if the terminal behaves like xterm-256color, which is correct for the vast majority of cases (:issue:`11277`, :issue:`11290`).
- Key combinations using the super (Windows/command) key can now (actually) be bound using the :kbd:`super-` prefix (:issue:`11217`). This was listed in the release notes for 4.0.1 but did not work correctly.
- :doc:`function <cmds/function>` is stricter about argument parsing, rather than allowing additional parameters to be silently ignored (:issue:`11295`).
- Using parentheses in the :doc:`test <cmds/test>` builtin works correctly, following a regression in 4.0.0 where they were not recognized (:issue:`11387`).
- :kbd:`delete` in Vi mode when Num Lock is active will work correctly (:issue:`11303`).
- Abbreviations cannot alter the command-line contents, preventing a crash (:issue:`11324`).
- Improvements to various completions, including new completions for ``wl-randr`` (:issue:`11301`), performance improvements for ``cargo`` completions by avoiding network requests (:issue:`11347`), and other improvements for ``btrfs`` (:issue:`11320`), ``cryptsetup`` (:issue:`11315`), ``git`` (:issue:`11319`, :issue:`11322`, :issue:`11323`), ``jj`` (:issue:`11046`), and ``systemd-analyze`` (:issue:`11314`).
- The Mercurial (``hg``) prompt can handle working directories that contain an embedded newline, rather than producing errors (:issue:`11348`).
- A number of crashes have been fixed. Triggers include prompts containing backspace characters (:issue:`11280`), history pager search (:issue:`11355`), invalid UTF-8 in :doc:`read <cmds/read>` (:issue:`11383`), and the ``kill-selection`` binding (:issue:`11367`).
- A race condition in the test suite has been fixed (:issue:`11254`), and a test for fish versioning relaxed to support downstream distributors' modifications (:issue:`11173`).
- Small improvements to the documentation (:issue:`11264`, :issue:`11329`, :issue:`11361`).
--------------
fish 4.0.1 (released March 12, 2025)
====================================
This release of fish includes the following improvements compared to fish 4.0.0:
- Key combinations using the super (Windows/command) key can be bound using the :kbd:`super-` prefix (:issue:`11217`).
- Konsole's menu shows the "Open folder with" option again (:issue:`11198`).
- ``$fish_color_search_match`` will now only be applied to the foreground color if it has an explicit foreground. For example, this allows setting::
set -g fish_color_search_match --reverse
- Cursor shape commands (``\e[2 q``) are no longer sent in non-interactive shells or in redirections (:issue:`11255`).
- :doc:`status <cmds/status>` gained a ``is-interactive-read`` subcommand, to check whether the script is being called from an interactive :doc:`read <cmds/read>` invocation.
- fish's background tasks are now started in a way that avoids an error on macOS Terminal.app (:issue:`11181`).
- Using key combinations within qemu should work correctly.
- Prompts containing control characters no longer cause incorrect display of command lines (:issue:`11252`).
- Cancelling the command-line in Vi mode displays correctly again (:issue:`11261`).
- The acidhub prompt properly displays the git branch again (:issue:`11179`).
- Completions for ``wine`` correctly include files again (:issue:`11202`).
- On macOS, paths from ``/etc/paths`` and ``/etc/manpaths`` containing colons are handled correctly (:issue:`10684`). This functionality was included in the 4.0.0 release notes but was missing from the source code.
- The XTerm ``modifyOtherKeys`` keyboard encoding is no longer used under WezTerm, as it does not work correctly in all layouts (:issue:`11204`).
- :kbd:`option-left` and other similar keys should now work in iTerm versions before 3.5.12; the kitty keyboard protocol is now disabled on these versions (:issue:`11192`).
- The kitty keyboard protocol is no longer used under Midnight Commander, as it does not work correctly (:issue:`10640`).
- fish now sends the commandline along with the OSC 133 semantic prompt command start sequence. This fixes a test in the kitty terminal (:issue:`11203`).
- Git completions for third-party commands like "git-absorb" are completed correctly again (:issue:`11205`).
- Completions for ``diskutil`` no longer produce an error (:issue:`11201`).
- The output of certain error messages no longer prints newlines to standard output (:issue:`11248`).
- A number of crashes have been fixed, including file names longer than 255 bytes (:issue:`11221`), using fish on a btrfs filesystem (:issue:`11219`), history files that do not have the expected format (:issue:`11236`), and pasting into an empty command line (:issue:`11256`).
--------------
fish 4.0.0 (released February 27, 2025)
=======================================
@@ -8,7 +319,7 @@ Notable backwards-incompatible changes
- As part of a larger binding rework, ``bind`` gained a new key notation.
In most cases the old notation should keep working, but in rare cases you may have to change a ``bind`` invocation to use the new notation.
See :ref:`below <changelog-new-bindings>` for details.
See :ref:`below <changelog-4.0-new-bindings>` for details.
- :kbd:`ctrl-c` now calls a new bind function called ``clear-commandline``. The old behavior, which leaves a "^C" marker, is available as ``cancel-commandline`` (:issue:`10935`)
- ``random`` will produce different values from previous versions of fish when used with the same seed, and will work more sensibly with small seed numbers.
The seed was never guaranteed to give the same result across systems,
@@ -30,7 +341,7 @@ Notable backwards-incompatible changes
Notable improvements and fixes
------------------------------
.. _changelog-new-bindings:
.. _changelog-4.0-new-bindings:
- fish now requests XTerm's ``modifyOtherKeys`` keyboard encoding and `kitty keyboard protocol's <https://sw.kovidgoyal.net/kitty/keyboard-protocol/>`_ progressive enhancements (:issue:`10359`).
Depending on terminal support, this allows to binding more key combinations, including arbitrary combinations of modifiers :kbd:`ctrl`, :kbd:`alt` and :kbd:`shift`, and distinguishing (for example) :kbd:`ctrl-i` from :kbd:`tab`.
@@ -149,7 +460,6 @@ Interactive improvements
The color scheme will not be upgraded for existing installs. If you want, you should select it again via ``fish_config``.
- Command lines which are larger than the terminal are now displayed correctly, instead of multiple blank lines being displayed (:issue:`7296`).
- Prompts that use external commands will no longer produce an infinite loop if the command crashes (:issue:`9796`).
- Undo (:kbd:`ctrl-z`) restores the cursor position too (:issue:`10838`).
- The output of ``jobs`` shows "-" for jobs that have the same process group ID as the fish process, rather than "-2" (:issue:`10833`).
- Job expansion (``%1`` syntax) works properly for jobs that are a mixture of external commands and functions (:issue:`10832`).
- Command lines which have more lines than the terminal can be displayed and edited correctly (:issue:`10827`).
@@ -162,10 +472,11 @@ Interactive improvements
New or improved bindings
^^^^^^^^^^^^^^^^^^^^^^^^
- When the cursor is on a command that resolves to an executable script, :kbd:`alt-o` will now open that script in your editor (:issue:`10266`).
- During up-arrow history search, :kbd:`shift-delete` will delete the current search item and move to the next older item. Previously this was only supported in the history pager.
- During up-arrow history search, :kbd:`shift-delete` will delete the current search item and move to the next older item. Previously this was only supported in the history pager.
- :kbd:`shift-delete` will also remove the currently-displayed autosuggestion from history, and remove it as a suggestion.
- :kbd:`ctrl-Z` (also known as :kbd:`ctrl-shift-z`) is now bound to redo.
- Some improvements to the :kbd:`alt-e` binding which edits the command line in an external editor:
- The editor's cursor position is copied back to fish. This is currently supported for Vim and Kakoune.
- Cursor position synchronization is only supported for a set of known editors, which are now also detected in aliases which use ``complete --wraps``. For example, use ``complete --wraps my-vim vim`` to synchronize cursors when ``EDITOR=my-vim``.
- Multiline commands are indented before being sent to the editor, which matches how they are displayed in fish.
@@ -173,16 +484,19 @@ New or improved bindings
- Bindings like :kbd:`alt-l` that print output in between prompts now work correctly with multiline commandlines.
- :kbd:`alt-d` on an empty command line lists the directory history again. This restores the behavior of version 2.1.
- ``history-prefix-search-backward`` and ``-forward`` now maintain the cursor position, instead of moving the cursor to the end of the command line (:issue:`10430`).
- The following keys have refined behavior if the terminal supports :ref:`the new keyboard encodings <changelog-new-bindings>`:
- The following keys have refined behavior if the terminal supports :ref:`the new keyboard encodings <changelog-4.0-new-bindings>`:
- :kbd:`shift-enter` now inserts a newline instead of executing the command line.
- :kbd:`ctrl-backspace` now deletes the last word instead of only one character (:issue:`10741`).
- :kbd:`ctrl-delete` deletes the next word (same as :kbd:`alt-d`).
- New special input functions:
- ``forward-char-passive`` and ``backward-char-passive`` are like their non-passive variants but do not accept autosuggestions or move focus in the completion pager (:issue:`10398`).
- ``forward-token``, ``backward-token``, ``kill-token``, and ``backward-kill-token`` are similar to the ``*-bigword`` variants but for the whole argument token (which includes escaped spaces) (:issue:`2014`).
- ``clear-commandline``, which merely clears the command line, as an alternative to ``cancel-commandline`` which prints ``^C`` and a new prompt (:issue:`10213`).
- The ``accept-autosuggestion`` special input function now returns false when there was nothing to accept (:issue:`10608`).
- Vi mode has seen some improvements but continues to suffer from the lack of people working on it.
- New default cursor shapes for insert and replace mode.
- :kbd:`ctrl-n` in insert mode accepts autosuggestions (:issue:`10339`).
- Outside insert mode, the cursor will no longer be placed beyond the last character on the commandline.
@@ -229,7 +543,7 @@ Improved terminal support
Other improvements
------------------
- ``status`` gained a ``buildinfo`` subcommand, to print information on how fish was built, to help with debugging (:issue:`10896`).
- ``status`` gained a ``build-info`` subcommand, to print information on how fish was built, to help with debugging (:issue:`10896`).
- ``fish_indent`` will now collapse multiple empty lines into one (:issue:`10325`).
- ``fish_indent`` now preserves the modification time of files if there were no changes (:issue:`10624`).
- Performance in launching external processes has been improved for many cases (:issue:`10869`).
@@ -520,7 +834,7 @@ fish 3.6.0 (released January 7, 2023)
Notable improvements and fixes
------------------------------
- By default, :kbd:`ctrl-r` now opens the command history in the pager (:issue:`602`). This is fully searchable and syntax-highlighted, as an alternative to the incremental search seen in other shells. The new special input function ``history-pager`` has been added for custom bindings.
- Abbrevations are more flexible (:issue:`9313`, :issue:`5003`, :issue:`2287`):
- Abbreviations are more flexible (:issue:`9313`, :issue:`5003`, :issue:`2287`):
- They may optionally replace tokens anywhere on the command line, instead of only commands
- Matching tokens may be described using a regular expression instead of a literal word
@@ -616,7 +930,7 @@ Interactive improvements
- A new variable, :envvar:`fish_cursor_selection_mode`, can be used to configure whether the command line selection includes the character under the cursor (``inclusive``) or not (``exclusive``). The new default is ``exclusive``; use ``set fish_cursor_selection_mode inclusive`` to get the previous behavior back (:issue:`7762`).
- fish's completion pager now fills half the terminal on first tab press instead of only 4 rows, which should make results visible more often and save key presses, without constantly snapping fish to the top of the terminal (:issue:`9105`, :issue:`2698`).
- The ``complete-and-search`` binding, used with :kbd:`shift-tab` by default, selects the first item in the results immediately (:issue:`9080`).
- ``bind`` output is now syntax-highlighted when used interacively.
- ``bind`` output is now syntax-highlighted when used interactively.
- :kbd:`alt-h` (the default ``__fish_man_page`` binding) does a better job of showing the manual page of the command under cursor (:issue:`9020`).
- If :envvar:`fish_color_valid_path` contains an actual color instead of just modifiers, those will be used for valid paths even if the underlying color isn't "normal" (:issue:`9159`).
- The key combination for the QUIT terminal sequence, often :kbd:`ctrl-\\` (``\x1c``), can now be used as a binding (:issue:`9234`).
@@ -845,7 +1159,7 @@ Interactive improvements
New or improved bindings
^^^^^^^^^^^^^^^^^^^^^^^^
- The :kbd:`alt-s` binding will now insert ``doas`` instead of ``sudo`` if necessary (:issue:`8942`).
- The ``kill-whole-line`` special input function now kills the newline preceeding the last line. This makes ``dd`` in vi-mode clear the last line properly.
- The ``kill-whole-line`` special input function now kills the newline preceding the last line. This makes ``dd`` in vi-mode clear the last line properly.
- The new ``kill-inner-line`` special input function kills the line without any newlines, allowing ``cc`` in vi-mode to clear the line while preserving newlines (:issue:`8983`).
- On terminals that emit special sequences for these combinations, :kbd:`shift-space` is bound like :kbd:`space`, and :kbd:`ctrl-enter` is bound like :kbd:`return` (:issue:`8874`).
@@ -954,7 +1268,7 @@ Deprecations and removed features
> set -Ua fish_features ampersand-nobg-in-token
- ``$status`` is now forbidden as a command, to prevent a surprisingly common error among new users: Running ``if $status`` (:issue:`8171`). This applies *only* to ``$status``, other variables are still allowed.
- ``set --query`` now returns an exit status of 255 if given no variable names. This means ``if set -q $foo`` will not enter the if-block if ``$foo`` is empty or unset. To restore the previous behavior, use ``if not set -q foo; or set -q $foo`` - but this is unlikely to be desireable (:issue:`8214`).
- ``set --query`` now returns an exit status of 255 if given no variable names. This means ``if set -q $foo`` will not enter the if-block if ``$foo`` is empty or unset. To restore the previous behavior, use ``if not set -q foo; or set -q $foo`` - but this is unlikely to be desirable (:issue:`8214`).
- ``_`` is now a reserved keyword (:issue:`8342`).
- The special input functions ``delete-or-exit``, ``nextd-or-forward-word`` and ``prevd-or-backward-word`` replace fish functions of the same names (:issue:`8538`).
- Mac OS X 10.9 is no longer supported. The minimum Mac version is now 10.10 "Yosemite."
@@ -977,7 +1291,7 @@ Scripting improvements
- ``commandline`` gained a ``--paging-full-mode`` option to check if the pager is showing all the possible lines (no "7 more rows" message) (:issue:`8485`).
- List expansion correctly reports an error when used with all zero indexes (:issue:`8213`).
- Running ``fish`` with a directory instead of a script as argument (eg ``fish .``) no longer leads to an infinite loop. Instead it errors out immediately (:issue:`8258`)
- Some error messages occuring after fork, like "text file busy" have been replaced by bespoke error messages for fish (like "File is currently open for writing"). This also restores error messages with current glibc versions that removed sys_errlist (:issue:`8234`, :issue:`4183`).
- Some error messages occurring after fork, like "text file busy" have been replaced by bespoke error messages for fish (like "File is currently open for writing"). This also restores error messages with current glibc versions that removed sys_errlist (:issue:`8234`, :issue:`4183`).
- The ``realpath`` builtin now also squashes leading slashes with the ``--no-symlinks`` option (:issue:`8281`).
- When trying to ``cd`` to a dangling (broken) symbolic link, fish will print an error noting that the target is a broken link (:issue:`8264`).
- On MacOS terminals that are not granted permissions to access a folder, ``cd`` would print a spurious "rotten symlink" error, which has been corrected to "permission denied" (:issue:`8264`).
@@ -1483,7 +1797,7 @@ Interactive improvements
- :kbd:`ctrl-c` handling has been reimplemented in C++ and is therefore quicker (:issue:`5259`), no longer occasionally prints an "unknown command" error (:issue:`7145`) or overwrites multiline prompts (:issue:`3537`).
- :kbd:`ctrl-c` no longer kills background jobs for which job control is
disabled, matching POSIX semantics (:issue:`6828`, :issue:`6861`).
- Autosuggestions work properly after :kbd:`ctrl-c` cancels the current commmand line (:issue:`6937`).
- Autosuggestions work properly after :kbd:`ctrl-c` cancels the current command line (:issue:`6937`).
- History search is now case-insensitive unless the search string contains an uppercase character (:issue:`7273`).
- ``fish_update_completions`` gained a new ``--keep`` option, which improves speed by skipping completions that already exist (:issue:`6775`, :issue:`6796`).
- Aliases containing an embedded backslash appear properly in the output of ``alias`` (:issue:`6910`).
@@ -2037,7 +2351,7 @@ Interactive improvements
argument.
- Syntax highlighting works correctly with variables as commands
(:issue:`5658`) and redirections to close file descriptors (:issue:`6092`).
- ``help`` works properly on Windows Subsytem for Linux (:issue:`5759`, :issue:`6338`).
- ``help`` works properly on Windows Subsystem for Linux (:issue:`5759`, :issue:`6338`).
- A bug where ``disown`` could crash the shell has been fixed (:issue:`5720`).
- fish will not autosuggest files ending with ``~`` unless there are no
other candidates, as these are generally backup files (:issue:`985`).
@@ -2979,7 +3293,7 @@ Other significant changes
- Some systems ``su`` implementations do not set the ``USER``
environment variable; it is now reset for root users (:issue:`3916`).
- Under terminals which support it, bracketed paste is enabled,
escaping problematic characters for security and convience (:issue:`3871`).
escaping problematic characters for security and convenience (:issue:`3871`).
Inside single quotes (``'``), single quotes and backslashes in pasted
text are escaped (:issue:`967`). The ``fish_clipboard_paste`` function (bound
to ``C-v`` by default) is still the recommended pasting method where
@@ -3108,9 +3422,9 @@ Other significant changes
- fish no longer prints a warning when it identifies a running instance
of an old version (2.1.0 and earlier). Changes to universal variables
may not propagate between these old versions and 2.5b1.
- Improved compatiblity with Android (:issue:`3585`), MSYS/mingw (:issue:`2360`), and
- Improved compatibility with Android (:issue:`3585`), MSYS/mingw (:issue:`2360`), and
Solaris (:issue:`3456`, :issue:`3340`).
- Like other shells, the ``test`` builting now returns an error for
- Like other shells, the ``test`` built-in now returns an error for
numeric operations on invalid integers (:issue:`3346`, :issue:`3581`).
- ``complete`` no longer recognises ``--authoritative`` and
``--unauthoritative`` options, and they are marked as obsolete.

View File

@@ -7,9 +7,6 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(DEFAULT_BUILD_TYPE "RelWithDebInfo")
# Generate Xcode schemas (but not for tests).
set(CMAKE_XCODE_GENERATE_SCHEME 1)
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to default '${DEFAULT_BUILD_TYPE}'")
set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}")
@@ -17,9 +14,6 @@ endif()
# Set up standard directories.
include(GNUInstallDirs)
add_definitions(-D_UNICODE=1)
include(cmake/gettext.cmake)
# Set up PCRE2
# This sets an environment variable that needs to be available before the Rust stanzas
@@ -30,12 +24,6 @@ include(cmake/Rust.cmake)
# Work around issue where archive-built libs go in the wrong place.
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
set(FISH_IN_TREE_BUILD TRUE)
else()
set(FISH_IN_TREE_BUILD FALSE)
endif()
# Set up the machinery around FISH-BUILD-VERSION-FILE
# This defines the FBVF variable.
include(Version)
@@ -46,6 +34,11 @@ get_filename_component(REAL_CMAKE_SOURCE_DIR "${CMAKE_SOURCE_DIR}" REALPATH)
add_definitions(-DCMAKE_BINARY_DIR="${REAL_CMAKE_BINARY_DIR}")
add_definitions(-DCMAKE_SOURCE_DIR="${REAL_CMAKE_SOURCE_DIR}")
set(build_types Release RelWithDebInfo Debug "")
if(NOT "${CMAKE_BUILD_TYPE}" IN_LIST build_types)
message(WARNING "Unsupported build type ${CMAKE_BUILD_TYPE}. If this doesn't build, try one of Release, RelWithDebInfo or Debug")
endif()
# Define a function to build and link dependencies.
function(CREATE_TARGET target)
add_custom_target(
@@ -59,8 +52,8 @@ function(CREATE_TARGET target)
$<$<CONFIG:RelWithDebInfo>:--profile=release-with-debug>
--target ${Rust_CARGO_TARGET}
--no-default-features
--features=${FISH_CARGO_FEATURES}
${CARGO_FLAGS}
${FEATURES_ARG}
&&
"${CMAKE_COMMAND}" -E
copy "${rust_target_dir}/${rust_profile}/${target}" "${CMAKE_CURRENT_BINARY_DIR}"
@@ -81,8 +74,6 @@ create_target(fish_key_reader)
# Set up the docs.
include(cmake/Docs.cmake)
# A helper for running tests.
add_executable(fish_test_helper src/fish_test_helper.c)
# Set up tests.
include(cmake/Tests.cmake)

View File

@@ -126,4 +126,3 @@ enforcement ladder](https://github.com/mozilla/diversity).
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View File

@@ -11,10 +11,17 @@ Contributions are welcome, and there are many ways to contribute!
Whether you want to change some of the core Rust source, enhance or add a completion script or function,
improve the documentation or translate something, this document will tell you how.
Getting Set Up
==============
Fish is developed on Github, at https://github.com/fish-shell/fish-shell.
Mailing List
============
Send patches to the public mailing list: mailto:~krobelus/fish-shell@lists.sr.ht.
Archives are available at https://lists.sr.ht/~krobelus/fish-shell/.
GitHub
======
Fish is available on Github, at https://github.com/fish-shell/fish-shell.
First, you'll need an account there, and you'll need a git clone of fish.
Fork it on Github and then run::
@@ -29,7 +36,7 @@ For that, you'll require:
- Rust - when in doubt, try rustup
- CMake
- PCRE2 (headers and libraries) - optional, this will be downloaded if missing
- gettext (headers and libraries) - optional, for translation support
- gettext (only the msgfmt tool) - optional, for translation support
- Sphinx - optional, to build the documentation
Of course not everything is required always - if you just want to contribute something to the documentation you'll just need Sphinx,
@@ -43,14 +50,14 @@ Guidelines
In short:
- Be conservative in what you need (keep to the agreed minimum supported Rust version, limit new dependencies)
- Use automated tools to help you (including ``make fish_run_tests`` and ``build_tools/style.fish``)
- Use automated tools to help you (``build_tools/check.sh``)
Contributing completions
========================
Completion scripts are the most common contribution to fish, and they are very welcome.
In general, we'll take all well-written completion scripts for a command that is publically available.
In general, we'll take all well-written completion scripts for a command that is publicly available.
This means no private tools or personal scripts, and we do reserve the right to reject for other reasons.
Before you try to contribute them to fish, consider if the authors of the tool you are completing want to maintain the script instead.
@@ -196,8 +203,14 @@ The tests can be found in three places:
- tests/pexpects for interactive tests using `pexpect <https://pexpect.readthedocs.io/en/stable/>`__
When in doubt, the bulk of the tests should be added as a littlecheck test in tests/checks, as they are the easiest to modify and run, and much faster and more dependable than pexpect tests. The syntax is fairly self-explanatory. It's a fish script with the expected output in ``# CHECK:`` or ``# CHECKERR:`` (for stderr) comments.
If your littlecheck test has a specific dependency, use ``# REQUIRE: ...`` with a posix sh script.
The pexpects are written in python and can simulate input and output to/from a terminal, so they are needed for anything that needs actual interactivity. The runner is in build_tools/pexpect_helper.py, in case you need to modify something there.
The pexpects are written in python and can simulate input and output to/from a terminal, so they are needed for anything that needs actual interactivity. The runner is in tests/pexpect_helper.py, in case you need to modify something there.
These tests can be run via the tests/test_driver.py python script, which will set up the environment.
It sets up a temporary $HOME and also uses it as the current directory, so you do not need to create a temporary directory in them.
If you need a command to do something weird to test something, maybe add it to the ``fish_test_helper`` binary (in tests/fish_test_helper.c), or see if it can already do it.
Local testing
-------------
@@ -209,6 +222,15 @@ The tests can be run on your local computer on all operating systems.
cmake path/to/fish-shell
make fish_run_tests
Or you can run them on a fish, without involving cmake::
cargo build
cargo test # for the unit tests
tests/test_driver.py target/debug # for the script and interactive tests
Here, the first argument to test_driver.py refers to a directory with ``fish``, ``fish_indent`` and ``fish_key_reader`` in it.
In this example we're in the root of the git repo and have run ``cargo build`` without ``--release``, so it's a debug build.
Git hooks
---------
@@ -228,83 +250,109 @@ One possibility is a pre-push hook script like this one:
# Git gives us lines like "refs/heads/frombranch SOMESHA1 refs/heads/tobranch SOMESHA1"
# We're only interested in the branches
isprotected=false
while read from _ to _; do
if [ "x$to" = "xrefs/heads/$protected_branch" ]; then
isprotected=1
if [ "$to" = "refs/heads/$protected_branch" ]; then
isprotected=true
fi
done
if [ "x$isprotected" = x1 ]; then
echo "Running tests before push to master"
make fish_run_tests
RESULT=$?
if [ $RESULT -ne 0 ]; then
echo "Tests failed for a push to master, we can't let you do that" >&2
exit 1
fi
if "$isprotected"; then
echo "Running checks before push to master"
build_tools/check.sh
fi
exit 0
This will check if the push is to the master branch and, if it is, only
allow the push if running ``make fish_run_tests`` succeeds. In some circumstances
allow the push if running ``build_tools/check.sh`` succeeds. In some circumstances
it may be advisable to circumvent this check with
``git push --no-verify``, but usually that isnt necessary.
To install the hook, place the code in a new file
``.git/hooks/pre-push`` and make it executable.
Coverity Scan
-------------
We use Coveritys static analysis tool which offers free access to open
source projects. While access to the tool itself is restricted,
fish-shell organization members should know that they can login
`here <https://scan.coverity.com/projects/fish-shell-fish-shell?tab=overview>`__
with their GitHub account. Currently, tests are triggered upon merging
the ``master`` branch into ``coverity_scan_master``. Even if you are not
a fish developer, you can keep an eye on our statistics there.
Contributing Translations
=========================
Fish uses the GNU gettext library to translate messages from English to
other languages.
Fish uses GNU gettext to translate messages from English to other languages.
We use custom tools for extracting messages from source files and to localize at runtime.
This means that we do not have a runtime dependency on the gettext library.
It also means that some features are not supported, such as message context and plurals.
We also expect all files to be UTF-8-encoded.
In practice, this should not matter much for contributing translations.
Creating and updating translations requires the Gettext tools, including
``xgettext``, ``msgfmt`` and ``msgmerge``. Translation sources are
stored in the ``po`` directory, named ``LANG.po``, where ``LANG`` is the
two letter ISO 639-1 language code of the target language (eg ``de`` for
German).
Translation sources are
stored in the ``po`` directory, named ``ll_CC.po``, where ``ll`` is the
two (or possibly three) letter ISO 639-1 language code of the target language
(e.g. ``pt`` for Portuguese). ``CC`` is an ISO 3166 country/territory code,
(e.g. ``BR`` for Brazil).
An example for a valid name is ``pt_BR.po``, indicating Brazilian Portuguese.
These are the files you will interact with when adding translations.
To create a new translation:
Adding translations for a new language
--------------------------------------
* generate a ``messages.pot`` file by running ``build_tools/fish_xgettext.fish`` from
the source tree
* copy ``messages.pot`` to ``po/LANG.po``
Creating new translations requires the Gettext tools.
More specifically, you will need ``msguniq`` and ``msgmerge`` for creating translations for a new
language.
To create a new translation, run::
To update a translation:
build_tools/update_translations.fish po/ll_CC.po
* generate a ``messages.pot`` file by running
``build_tools/fish_xgettext.fish`` from the source tree
This will create a new PO file containing all messages available for translation.
If the file already exists, it will be updated.
* update the existing translation by running
``msgmerge --update --no-fuzzy-matching po/LANG.po messages.pot``
After modifying a PO file, you can recompile fish, and it will integrate the modifications you made.
This requires that the ``msgfmt`` utility is installed (comes as part of ``gettext``).
It is important that the ``localize-messages`` cargo feature is enabled, which it is by default.
You can explicitly enable it using::
The ``--no-fuzzy-matching`` is important as we have had terrible experiences with gettext's "fuzzy" translations in the past.
cargo build --features=localize-messages
Use environment variables to tell fish which language to use, e.g.::
LANG=pt_BR.utf8 fish
or within the running fish shell::
set LANG pt_BR.utf8
For more options regarding how to choose languages, see
`the corresponding gettext documentation
<https://www.gnu.org/software/gettext/manual/html_node/Locale-Environment-Variables.html>`__.
One neat thing you can do is set a list of languages to check for translations in the order defined
using the ``LANGUAGE`` variable, e.g.::
set LANGUAGE pt_BR de_DE
to try to translate messages to Portuguese, if that fails try German, and if that fails too you will
see the English version defined in the source code.
Modifying existing translations
-------------------------------
If you want to work on translations for a language which already has a corresponding ``po`` file, it
is sufficient to edit this file. No other changes are necessary.
After recompiling fish, you should be able to see your translations in action. See the previous
section for details.
Editing PO files
----------------
Many tools are available for editing translation files, including
command-line and graphical user interface programs. For simple use, you can just use your text editor.
command-line and graphical user interface programs. For simple use, you can use your text editor.
Open up the po file, for example ``po/sv.po``, and you'll see something like::
Open up the PO file, for example ``po/sv.po``, and you'll see something like::
msgid "%ls: No suitable job\n"
msgstr ""
msgid "%ls: No suitable job\n"
msgstr ""
The ``msgid`` here is the "name" of the string to translate, typically the english string to translate. The second line (``msgstr``) is where your translation goes.
The ``msgid`` here is the "name" of the string to translate, typically the English string to translate.
The second line (``msgstr``) is where your translation goes.
For example::
msgid "%ls: No suitable job\n"
msgstr "%ls: Inget passande jobb\n"
msgid "%ls: No suitable job\n"
msgstr "%ls: Inget passande jobb\n"
Any ``%s`` / ``%ls`` or ``%d`` are placeholders that fish will use for formatting at runtime. It is important that they match - the translated string should have the same placeholders in the same order.
@@ -312,11 +360,17 @@ Also any escaped characters, like that ``\n`` newline at the end, should be kept
Our tests run ``msgfmt --check-format /path/to/file``, so they would catch mismatched placeholders - otherwise fish would crash at runtime when the string is about to be used.
Be cautious about blindly updating an existing translation file. Trivial
changes to an existing message (eg changing the punctuation) will cause
existing translations to be removed, since the tools do literal string
matching. Therefore, in general, you need to carefully review any
recommended deletions.
Be cautious about blindly updating an existing translation file.
``msgid`` strings should never be updated manually, only by running the appropriate script.
Modifications to strings in source files
----------------------------------------
If a string changes in the sources, the old translations will no longer work.
They will be preserved in the PO files, but commented-out (starting with ``#~``).
If you add/remove/change a translatable strings in a source file,
run ``build_tools/update_translations.fish`` to propagate this to all translation files (``po/*.po``).
This is only relevant for developers modifying the source files of fish or fish scripts.
Setting Code Up For Translations
--------------------------------
@@ -327,7 +381,7 @@ macros:
::
streams.out.append(wgettext_fmt!("%ls: There are no jobs\n", argv[0]));
streams.out.append(wgettext_fmt!("%ls: There are no jobs\n", argv[0]));
All messages in fish script must be enclosed in single or double quote
characters for our message extraction script to find them.
@@ -336,15 +390,15 @@ that the following are **not** valid:
::
echo (_ hello)
_ "goodbye"
echo (_ hello)
_ "goodbye"
Above should be written like this instead:
::
echo (_ "hello")
echo (_ "goodbye")
echo (_ "hello")
echo (_ "goodbye")
You can use either single or double quotes to enclose the
message to be translated. You can also optionally include spaces after

View File

@@ -1,7 +1,7 @@
Fish is a smart and user-friendly command line shell.
Copyright (C) 2005-2009 Axel Liljencrantz
Copyright (C) 2009-2024 fish-shell contributors
Copyright (C) 2009- fish-shell contributors
fish is free software.

315
Cargo.lock generated
View File

@@ -4,9 +4,9 @@ version = 3
[[package]]
name = "allocator-api2"
version = "0.2.18"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "autocfg"
@@ -31,9 +31,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.1.30"
version = "1.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945"
checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7"
dependencies = [
"jobserver",
"libc",
@@ -54,9 +54,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "cpufeatures"
version = "0.2.14"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
dependencies = [
"libc",
]
@@ -71,19 +71,6 @@ dependencies = [
"typenum",
]
[[package]]
name = "dashmap"
version = "5.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
dependencies = [
"cfg-if",
"hashbrown 0.14.5",
"lock_api",
"once_cell",
"parking_lot_core",
]
[[package]]
name = "digest"
version = "0.10.7"
@@ -102,43 +89,95 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.9"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
dependencies = [
"libc",
"windows-sys 0.52.0",
"windows-sys",
]
[[package]]
name = "fastrand"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "fish"
version = "4.0.0"
version = "4.1.2"
dependencies = [
"bitflags",
"cc",
"errno",
"fish-build-helper",
"fish-build-man-pages",
"fish-gettext-extraction",
"fish-gettext-maps",
"fish-gettext-mo-file-parser",
"fish-printf",
"lazy_static",
"libc",
"lru",
"nix",
"num-traits",
"once_cell",
"pcre2",
"phf 0.12.1",
"phf_codegen 0.12.1",
"portable-atomic",
"rand",
"rsconf",
"rust-embed",
"serial_test",
"terminfo",
"unix_path",
"widestring",
]
[[package]]
name = "fish-build-helper"
version = "0.0.0"
dependencies = [
"rsconf",
]
[[package]]
name = "fish-build-man-pages"
version = "0.0.0"
dependencies = [
"fish-build-helper",
"rsconf",
]
[[package]]
name = "fish-gettext-extraction"
version = "0.0.0"
dependencies = [
"proc-macro2",
]
[[package]]
name = "fish-gettext-maps"
version = "0.0.0"
dependencies = [
"fish-build-helper",
"fish-gettext-mo-file-parser",
"phf 0.12.1",
"phf_codegen 0.12.1",
"rsconf",
]
[[package]]
name = "fish-gettext-mo-file-parser"
version = "0.0.0"
[[package]]
name = "fish-printf"
version = "0.2.1"
dependencies = [
"libc",
"unicode-segmentation",
"unicode-width",
"widestring",
]
@@ -150,9 +189,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foldhash"
version = "0.1.3"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
[[package]]
name = "generic-array"
@@ -166,15 +205,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.14.5"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "hashbrown"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
dependencies = [
"allocator-api2",
"equivalent",
@@ -190,17 +223,11 @@ dependencies = [
"libc",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.159"
version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "lock_api"
@@ -220,11 +247,11 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "lru"
version = "0.12.5"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465"
dependencies = [
"hashbrown 0.15.0",
"hashbrown",
]
[[package]]
@@ -241,9 +268,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "nix"
version = "0.29.0"
version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
dependencies = [
"bitflags",
"cfg-if",
@@ -321,38 +348,76 @@ dependencies = [
[[package]]
name = "phf"
version = "0.11.2"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
dependencies = [
"phf_shared",
"phf_shared 0.11.3",
]
[[package]]
name = "phf"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7"
dependencies = [
"phf_shared 0.12.1",
]
[[package]]
name = "phf_codegen"
version = "0.11.2"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a"
checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
dependencies = [
"phf_generator",
"phf_shared",
"phf_generator 0.11.3",
"phf_shared 0.11.3",
]
[[package]]
name = "phf_codegen"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efbdcb6f01d193b17f0b9c3360fa7e0e620991b193ff08702f78b3ce365d7e61"
dependencies = [
"phf_generator 0.12.1",
"phf_shared 0.12.1",
]
[[package]]
name = "phf_generator"
version = "0.11.2"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
dependencies = [
"phf_shared",
"phf_shared 0.11.3",
"rand",
]
[[package]]
name = "phf_shared"
version = "0.11.2"
name = "phf_generator"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
checksum = "2cbb1126afed61dd6368748dae63b1ee7dc480191c6262a3b4ff1e29d86a6c5b"
dependencies = [
"fastrand",
"phf_shared 0.12.1",
]
[[package]]
name = "phf_shared"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
dependencies = [
"siphasher",
]
[[package]]
name = "phf_shared"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981"
dependencies = [
"siphasher",
]
@@ -365,24 +430,24 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "portable-atomic"
version = "1.9.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6"
[[package]]
name = "proc-macro2"
version = "1.0.87"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
@@ -404,9 +469,9 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[package]]
name = "redox_syscall"
version = "0.5.7"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
dependencies = [
"bitflags",
]
@@ -422,9 +487,9 @@ dependencies = [
[[package]]
name = "rust-embed"
version = "8.5.0"
version = "8.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa66af4a4fdd5e7ebc276f115e895611a34739a9c1c01028383d612d550953c0"
checksum = "025908b8682a26ba8d12f6f2d66b987584a4a87bc024abc5bbc12553a8cd178a"
dependencies = [
"rust-embed-impl",
"rust-embed-utils",
@@ -433,22 +498,22 @@ dependencies = [
[[package]]
name = "rust-embed-impl"
version = "8.5.0"
version = "8.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6125dbc8867951125eec87294137f4e9c2c96566e61bf72c45095a7c77761478"
checksum = "6065f1a4392b71819ec1ea1df1120673418bf386f50de1d6f54204d836d4349c"
dependencies = [
"proc-macro2",
"quote",
"rust-embed-utils",
"syn 2.0.79",
"syn",
"walkdir",
]
[[package]]
name = "rust-embed-utils"
version = "8.5.0"
version = "8.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e5347777e9aacb56039b0e1f28785929a8a3b709e87482e7442c72e7c12529d"
checksum = "f6cc0c81648b20b70c491ff8cce00c1c3b223bb8ed2b5d41f0e54c6c4c0a3594"
dependencies = [
"sha2",
"walkdir",
@@ -463,6 +528,15 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "scc"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28e1c91382686d21b5ac7959341fcb9780fa7c03773646995a87c950fa7be640"
dependencies = [
"sdd",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
@@ -470,26 +544,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serial_test"
version = "1.0.0"
name = "sdd"
version = "3.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "538c30747ae860d6fb88330addbbd3e0ddbe46d662d032855596d8a8ca260611"
checksum = "478f121bb72bbf63c52c93011ea1791dca40140dfe13f8336c4c5ac952c33aa9"
[[package]]
name = "serial_test"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9"
dependencies = [
"dashmap",
"lazy_static",
"once_cell",
"parking_lot",
"scc",
"serial_test_derive",
]
[[package]]
name = "serial_test_derive"
version = "1.0.0"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "079a83df15f85d89a68d64ae1238f142f172b1fa915d0d76b26a7cba1b659a69"
checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
"syn",
]
[[package]]
@@ -511,9 +591,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "siphasher"
version = "0.3.11"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
[[package]]
name = "smallvec"
@@ -523,20 +603,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "syn"
version = "1.0.109"
version = "2.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a"
dependencies = [
"proc-macro2",
"quote",
@@ -551,8 +620,8 @@ checksum = "d4ea810f0692f9f51b382fff5893887bb4580f5fa246fde546e0b13e7fcee662"
dependencies = [
"fnv",
"nom",
"phf",
"phf_codegen",
"phf 0.11.3",
"phf_codegen 0.11.3",
]
[[package]]
@@ -563,9 +632,36 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-ident"
version = "1.0.13"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]]
name = "unicode-segmentation"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unicode-width"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
[[package]]
name = "unix_path"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af8e291873ae77c4c8d9c9b34d0bee68a35b048fb39c263a5155e0e353783eaf"
dependencies = [
"unix_str",
]
[[package]]
name = "unix_str"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ace0b4755d0a2959962769239d56267f8a024fef2d9b32666b3dcd0946b0906"
[[package]]
name = "version_check"
@@ -585,9 +681,9 @@ dependencies = [
[[package]]
name = "widestring"
version = "1.1.0"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d"
[[package]]
name = "winapi-util"
@@ -595,16 +691,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
"windows-sys",
]
[[package]]

View File

@@ -1,10 +1,58 @@
[workspace]
resolver = "2"
members = ["printf"]
members = ["crates/*"]
[workspace.package]
# To build revisions that use Corrosion (those before 2024-01), use CMake 3.19, Rustc 1.78 and Rustup 1.27.
rust-version = "1.70"
edition = "2021"
repository = "https://github.com/fish-shell/fish-shell"
[workspace.dependencies]
bitflags = "2.5.0"
cc = "1.0.94"
errno = "0.3.0"
fish-build-helper = { path = "crates/build-helper" }
fish-build-man-pages = { path = "crates/build-man-pages" }
fish-gettext-extraction = { path = "crates/gettext-extraction" }
fish-gettext-maps = { path = "crates/gettext-maps" }
fish-gettext-mo-file-parser = { path = "crates/gettext-mo-file-parser" }
fish-printf = { path = "crates/printf", features = ["widestring"] }
libc = "0.2.155"
# lru pulls in hashbrown by default, which uses a faster (though less DoS resistant) hashing algo.
# disabling default features uses the stdlib instead, but it doubles the time to rewrite the history
# files as of 22 April 2024.
lru = "0.13.0"
nix = { version = "0.30.1", default-features = false, features = [
"event",
"inotify",
"resource",
"fs",
] }
num-traits = "0.2.19"
once_cell = "1.19.0"
pcre2 = { git = "https://github.com/fish-shell/rust-pcre2", tag = "0.2.9-utf32", default-features = false, features = [
"utf32",
] }
phf = { version = "0.12", default-features = false }
phf_codegen = { version = "0.12" }
portable-atomic = { version = "1", default-features = false, features = [
"fallback",
] }
proc-macro2 = "1.0"
# Don't use the "getrandom" feature as it requires "getentropy" which was not
# available on macOS < 10.12. We can enable "getrandom" when we raise the
# minimum supported version to 10.12.
rand = { version = "0.8.5", default-features = false, features = ["small_rng"] }
rsconf = "0.2.2"
rust-embed = { version = "8.7.2", features = ["deterministic-timestamps"] }
serial_test = { version = "3", default-features = false }
# We need 0.9.0 specifically for some crash fixes.
terminfo = "0.9.0"
widestring = "1.2.0"
unicode-segmentation = "1.12.0"
unicode-width = "0.2.0"
unix_path = "1.0.1"
[profile.release]
overflow-checks = true
@@ -16,60 +64,55 @@ debug = true
[package]
name = "fish"
version = "4.0.0"
version = "4.1.2"
edition.workspace = true
rust-version.workspace = true
default-run = "fish"
# see doc_src/license.rst for details
# don't forget to update COPYING and debian/copyright too
license = "GPL-2.0-only AND LGPL-2.0-or-later AND MIT AND PSF-2.0"
repository = "https://github.com/fish-shell/fish-shell"
homepage = "https://fishshell.com"
readme = "README.rst"
[dependencies]
pcre2 = { git = "https://github.com/fish-shell/rust-pcre2", tag = "0.2.9-utf32", default-features = false, features = [
"utf32",
] }
bitflags = "2.5.0"
errno = "0.3.0"
lazy_static = "1.4.0"
libc = "0.2.155"
# lru pulls in hashbrown by default, which uses a faster (though less DoS resistant) hashing algo.
# disabling default features uses the stdlib instead, but it doubles the time to rewrite the history
# files as of 22 April 2024.
lru = "0.12.3"
nix = { version = "0.29.0", default-features = false, features = [
"event",
"inotify",
"resource",
"fs",
] }
num-traits = "0.2.19"
once_cell = "1.19.0"
fish-printf = { path = "./printf", features = ["widestring"] }
# Don't use the "getrandom" feature as it requires "getentropy" which was not
# available on macOS < 10.12. We can enable "getrandom" when we raise the
# minimum supported version to 10.12.
rand = { version = "0.8.5", default-features = false, features = ["small_rng"] }
widestring = "1.1.0"
# We need 0.9.0 specifically for some crash fixes.
terminfo = "0.9.0"
rust-embed = { version = "8.2.0", optional = true }
bitflags.workspace = true
errno.workspace = true
fish-build-helper.workspace = true
fish-build-man-pages = { workspace = true, optional = true }
fish-gettext-extraction = { workspace = true, optional = true }
fish-gettext-maps = { workspace = true, optional = true }
fish-printf.workspace = true
libc.workspace = true
lru.workspace = true
nix.workspace = true
num-traits.workspace = true
once_cell.workspace = true
pcre2.workspace = true
phf = { workspace = true, optional = true }
rand.workspace = true
terminfo.workspace = true
widestring.workspace = true
[target.'cfg(not(target_has_atomic = "64"))'.dependencies]
portable-atomic = { version = "1", default-features = false, features = [
"fallback",
] }
portable-atomic.workspace = true
[target.'cfg(windows)'.dependencies]
rust-embed = { workspace = true, optional = true, features = ["deterministic-timestamps", "debug-embed"] }
[target.'cfg(not(windows))'.dependencies]
rust-embed = { workspace = true, optional = true, features = ["deterministic-timestamps"] }
[dev-dependencies]
serial_test = { version = "1.0.0", default-features = false }
serial_test.workspace = true
[build-dependencies]
cc = "1.0.94"
rsconf = "0.2.2"
cc.workspace = true
fish-build-helper.workspace = true
fish-gettext-mo-file-parser.workspace = true
phf_codegen = { workspace = true, optional = true }
rsconf.workspace = true
[target.'cfg(windows)'.build-dependencies]
unix_path.workspace = true
[lib]
crate-type = ["rlib"]
@@ -88,15 +131,23 @@ name = "fish_key_reader"
path = "src/bin/fish_key_reader.rs"
[features]
default = ["installable"]
default = ["embed-data", "localize-messages"]
benchmark = []
installable = ["dep:rust-embed"]
embed-data = ["dep:rust-embed", "dep:fish-build-man-pages"]
# Enable gettext localization at runtime. Requires the `msgfmt` tool to generate catalog data at
# build time.
localize-messages = ["dep:phf", "dep:fish-gettext-maps"]
# This feature is used to enable extracting messages from the source code for localization.
# It only needs to be enabled if updating these messages (and the corresponding PO files) is
# desired. This happens when running tests via `build_tools/check.sh` and when calling
# `build_tools/update_translations.fish`, so there should not be a need to enable it manually.
gettext-extract = ["dep:fish-gettext-extraction"]
# The following features are auto-detected by the build-script and should not be enabled manually.
asan = []
tsan = []
[lints]
[workspace.lints]
rust.non_camel_case_types = "allow"
rust.non_upper_case_globals = "allow"
rust.unknown_lints = "allow"
@@ -104,3 +155,12 @@ rust.unstable_name_collisions = "allow"
clippy.manual_range_contains = "allow"
clippy.needless_return = "allow"
clippy.needless_lifetimes = "allow"
# We do not want to use the e?print(ln)?! macros.
# These lints flag their use.
# In the future, they might change to flag other methods of printing.
clippy.print_stdout = "deny"
clippy.print_stderr = "deny"
[lints]
workspace = true

View File

@@ -16,4 +16,3 @@ WORKDIR /src
RUN cmake3 . &&\
make &&\
make install

View File

@@ -47,12 +47,12 @@ Linux/CentOS are available from the `openSUSE Build
Service <https://software.opensuse.org/download.html?project=shells%3Afish&package=fish>`__.
Packages for Ubuntu are available from the `fish
PPA <https://launchpad.net/~fish-shell/+archive/ubuntu/release-3>`__,
PPA <https://launchpad.net/~fish-shell/+archive/ubuntu/release-4>`__,
and can be installed using the following commands:
::
sudo apt-add-repository ppa:fish-shell/release-3
sudo apt-add-repository ppa:fish-shell/release-4
sudo apt update
sudo apt install fish
@@ -66,7 +66,8 @@ Windows
for Linux with the instructions for the appropriate distribution
listed above under “Packages for Linux”, or from source with the
instructions below.
- fish (4.0 on and onwards) cannot be installed in Cygwin, due to a lack of Rust support.
- Fish can also be installed on all versions of Windows using
`Cygwin <https://cygwin.com/>`__ or `MSYS2 <https://github.com/Berrysoft/fish-msys2>`__.
Building from source
~~~~~~~~~~~~~~~~~~~~
@@ -75,7 +76,7 @@ If packages are not available for your platform, GPG-signed tarballs are
available from `fishshell.com <https://fishshell.com/>`__ and
`fish-shell on
GitHub <https://github.com/fish-shell/fish-shell/releases>`__. See the
`Building <#building>`__ section for instructions.
`Building <#building>`_ section for instructions.
Running fish
------------
@@ -87,21 +88,16 @@ Dependencies
Running fish requires:
- A terminfo database, typically from curses or ncurses (preinstalled on most \*nix systems) - this needs to be the directory tree format, not the "hashed" database.
If this is unavailable, fish uses an included xterm-256color definition.
- some common \*nix system utilities (currently ``mktemp``), in
addition to the basic POSIX utilities (``cat``, ``cut``, ``dirname``,
``file``, ``ls``, ``mkdir``, ``mkfifo``, ``rm``, ``sort``, ``tee``, ``tr``,
``file``, ``ls``, ``mkdir``, ``mkfifo``, ``rm``, ``sh``, ``sort``, ``tee``, ``tr``,
``uname`` and ``sed`` at least, but the full coreutils plus ``find`` and
``awk`` is preferred)
- The gettext library, if compiled with
translation support
The following optional features also have specific requirements:
- builtin commands that have the ``--help`` option or print usage
messages require ``nroff`` or ``mandoc`` for
display
messages require ``man`` for display
- automated completion generation from manual pages requires Python 3.5+
- the ``fish_config`` web configuration tool requires Python 3.5+ and a web browser
- system clipboard integration (with the default Ctrl-V and Ctrl-X
@@ -126,13 +122,13 @@ Compiling fish requires:
- CMake (version 3.15 or later)
- a C compiler (for system feature detection and the test helper binary)
- PCRE2 (headers and libraries) - optional, this will be downloaded if missing
- gettext (headers and libraries) - optional, for translation support
- gettext (only the msgfmt tool) - optional, for translation support
- an Internet connection, as other dependencies will be downloaded automatically
Sphinx is also optionally required to build the documentation from a
cloned git repository.
Additionally, running the full test suite requires Python 3, tmux, and the pexpect package.
Additionally, running the full test suite requires Python 3.5+, tmux, and the pexpect package.
Building from source with CMake
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -159,38 +155,42 @@ CMake Build options
In addition to the normal CMake build options (like ``CMAKE_INSTALL_PREFIX``), fish's CMake build has some other options available to customize it.
- Rust_COMPILER=path - the path to rustc. If not set, cmake will check $PATH and ~/.cargo/bin
- Rust_CARGO=path - the path to cargo. If not set, cmake will check $PATH and ~/.cargo/bin
- Rust_CARGO_TARGET=target - the target to pass to cargo. Set this for cross-compilation.
- BUILD_DOCS=ON|OFF - whether to build the documentation. This is automatically set to OFF when Sphinx isn't installed.
- INSTALL_DOCS=ON|OFF - whether to install the docs. This is automatically set to on when BUILD_DOCS is or prebuilt documentation is available (like when building in-tree from a tarball).
- FISH_USE_SYSTEM_PCRE2=ON|OFF - whether to use an installed pcre2. This is normally autodetected.
- MAC_CODESIGN_ID=String|OFF - the codesign ID to use on Mac, or "OFF" to disable codesigning.
- WITH_GETTEXT=ON|OFF - whether to build with gettext support for translations.
- WITH_GETTEXT=ON|OFF - whether to include translations.
- extra_functionsdir, extra_completionsdir and extra_confdir - to compile in an additional directory to be searched for functions, completions and configuration snippets
Building fish as self-installable (experimental)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Building fish with embedded data (experimental)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can also build fish as a self-installing binary.
You can also build fish with the data files embedded.
This will include all the datafiles like the included functions or web configuration tool in the main ``fish`` binary.
On the first interactive run, and whenever it notices they are out of date, it will extract the datafiles to ~/.local/share/fish/install/ (currently, subject to change). You can do this manually by running ``fish --install``.
Fish will then read these right from its own binary, and print them out when needed. Some files, like the webconfig tool and the manpage completion generator, will be extracted to a temporary directory on-demand. You can list the files with ``status list-files`` and print one with ``status get-file path/to/file`` (e.g. ``status get-file functions/fish_prompt.fish`` to get the default prompt).
To install fish as self-installable, just use ``cargo``, like::
To install fish with embedded files, just use ``cargo``, like::
cargo install --path /path/to/fish # if you have a git clone
cargo install --git https://github.com/fish-shell/fish-shell --tag 4.0 # to build from git once 4.0 is released
cargo install --git https://github.com/fish-shell/fish-shell # to build the current development snapshot without cloning
cargo install --git https://github.com/fish-shell/fish-shell --tag "$(curl -s https://api.github.com/repos/fish-shell/fish-shell/releases/latest | jq -r .tag_name)" # to build the latest release
cargo install --git https://github.com/fish-shell/fish-shell # to build the latest development snapshot
This will place the binaries in ``~/.cargo/bin/``, but you can place them wherever you want.
This build won't have the HTML docs (``help`` will open the online version) or translations.
This will place the standalone binaries in ``~/.cargo/bin/``, but you can place them wherever you want.
This build won't have the HTML docs (``help`` will open the online version).
It will try to build the man pages with sphinx-build. If that is not available and you would like to include man pages, you need to install it and retrigger the build script, e.g. by setting FISH_BUILD_DOCS=1::
FISH_BUILD_DOCS=1 cargo install --path .
Setting it to "0" disables the inclusion of man pages.
To disable translations, disable the ``localize-messages`` feature by passing ``--no-default-features --features=embed-data`` to cargo.
You can also link this build statically (but not against glibc) and move it to other computers.
Contributing Changes to the Code

35
SECURITY.md Normal file
View File

@@ -0,0 +1,35 @@
# Security Reporting
If you wish to report a security vulnerability privately, we appreciate your diligence. Please follow the guidelines below to submit your report.
## Reporting
To report a security vulnerability, please provide the following information:
1. **PROJECT**
- Include the URL of the project repository - Example: <https://github.com/fish-shell/fish-shell>
2. **PUBLIC**
- Indicate whether this vulnerability has already been publicly discussed or disclosed.
- If so, provide relevant links.
3. **DESCRIPTION**
- Provide a detailed description of the security vulnerability.
- Include as much information as possible to help us understand and address the issue.
Send this information, along with any additional relevant details, to <rf@fishshell.com>.
## Confidentiality
We kindly ask you to keep the report confidential until a public announcement is made.
## Notes
- Vulnerabilities will be handled on a best-effort basis.
- You may request an advance copy of the patched release, but we cannot guarantee early access before the public release.
- You will be notified via email simultaneously with the public announcement.
- We will respond within a few weeks to confirm whether your report has been accepted or rejected.
Thank you for helping to improve the security of our project!

View File

@@ -8,5 +8,4 @@ for file in *.fish
echo FAILING FILE $file
end
end
end

View File

@@ -1,6 +1,6 @@
#!/bin/sh
if [ "$#" -gt 2 -o "$#" -eq 0 ]; then
if [ "$#" -gt 2 ] || [ "$#" -eq 0 ]; then
echo "Usage: driver.sh /path/to/fish [/path/to/other/fish]"
exit 1
fi

340
build.rs
View File

@@ -1,32 +1,32 @@
#![allow(clippy::uninlined_format_args)]
use rsconf::{LinkType, Target};
use fish_build_helper::{fish_build_dir, workspace_root};
use rsconf::Target;
use std::env;
use std::error::Error;
use std::path::{Path, PathBuf};
fn canonicalize<P: AsRef<Path>>(path: P) -> PathBuf {
std::fs::canonicalize(path).unwrap()
}
fn main() {
setup_paths();
// Add our default to enable tools that don't go through CMake, like "cargo test" and the
// language server.
// FISH_BUILD_DIR is set by CMake, if we are using it.
// OUT_DIR is set by Cargo when the build script is running (not compiling)
let default_build_dir = env::var("OUT_DIR").unwrap();
let build_dir = option_env!("FISH_BUILD_DIR").unwrap_or(&default_build_dir);
let build_dir = std::fs::canonicalize(build_dir).unwrap();
let build_dir = build_dir.to_str().unwrap();
rsconf::set_env_value("FISH_BUILD_DIR", build_dir);
rsconf::set_env_value(
"FISH_RESOLVED_BUILD_DIR",
// If set by CMake, this might include symlinks. Since we want to compare this to the
// dir fish is executed in we need to canonicalize it.
canonicalize(fish_build_dir()).to_str().unwrap(),
);
// We need to canonicalize (i.e. realpath) the manifest dir because we want to be able to
// compare it directly as a string at runtime.
rsconf::set_env_value(
"CARGO_MANIFEST_DIR",
std::fs::canonicalize(env!("CARGO_MANIFEST_DIR"))
.unwrap()
.as_path()
.to_str()
.unwrap(),
canonicalize(workspace_root()).to_str().unwrap(),
);
// Some build info
@@ -41,23 +41,19 @@ fn main() {
std::env::set_var("FISH_BUILD_VERSION", version);
#[cfg(feature = "installable")]
#[cfg(not(clippy))]
{
let cman = std::fs::canonicalize(env!("CARGO_MANIFEST_DIR")).unwrap();
let targetman = cman.as_path().join("target").join("man");
build_man(&targetman);
}
rsconf::rebuild_if_path_changed("src/libc.c");
cc::Build::new()
.file("src/libc.c")
.include(build_dir)
.compile("flibc.a");
// These are necessary if built with embedded functions,
// but only in release builds (because rust-embed in debug builds reads from the filesystem).
#[cfg(feature = "embed-data")]
#[cfg(any(windows, not(debug_assertions)))]
rsconf::rebuild_if_path_changed("share");
let mut build = cc::Build::new();
// Add to the default library search path
build.flag_if_supported("-L/usr/local/lib/");
rsconf::add_library_search_path("/usr/local/lib");
#[cfg(feature = "gettext-extract")]
rsconf::rebuild_if_env_changed("FISH_GETTEXT_EXTRACTION_FILE");
rsconf::rebuild_if_path_changed("src/libc.c");
cc::Build::new().file("src/libc.c").compile("flibc.a");
let build = cc::Build::new();
let mut target = Target::new_from(build).unwrap();
// Keep verbose mode on until we've ironed out rust build script stuff
target.set_verbose(true);
@@ -84,58 +80,60 @@ fn detect_cfgs(target: &mut Target) {
for (name, handler) in [
// Ignore the first entry, it just sets up the type inference. Model new entries after the
// second line.
(
"",
&(|_: &Target| Ok(false)) as &dyn Fn(&Target) -> Result<bool, Box<dyn Error>>,
),
("", &(|_: &Target| false) as &dyn Fn(&Target) -> bool),
("apple", &detect_apple),
("bsd", &detect_bsd),
("gettext", &have_gettext),
("cygwin", &detect_cygwin),
("small_main_stack", &has_small_stack),
// See if libc supports the thread-safe localeconv_l(3) alternative to localeconv(3).
("localeconv_l", &|target| {
Ok(target.has_symbol("localeconv_l"))
target.has_symbol("localeconv_l")
}),
("FISH_USE_POSIX_SPAWN", &|target| {
Ok(target.has_header("spawn.h"))
target.has_header("spawn.h")
}),
("HAVE_PIPE2", &|target| {
Ok(target.has_symbol("pipe2"))
target.has_symbol("pipe2")
}),
("HAVE_EVENTFD", &|target| {
// FIXME: NetBSD 10 has eventfd, but the libc crate does not expose it.
if cfg!(target_os = "netbsd") {
Ok(false)
false
} else {
Ok(target.has_header("sys/eventfd.h"))
target.has_header("sys/eventfd.h")
}
}),
("HAVE_WAITSTATUS_SIGNAL_RET", &|target| {
Ok(target.r#if("WEXITSTATUS(0x007f) == 0x7f", &["sys/wait.h"]))
target.r#if("WEXITSTATUS(0x007f) == 0x7f", &["sys/wait.h"])
}),
] {
match handler(target) {
Err(e) => {
rsconf::warn!("{}: {}", name, e);
rsconf::declare_cfg(name, false);
},
Ok(enabled) => rsconf::declare_cfg(name, enabled),
}
rsconf::declare_cfg(name, handler(target))
}
}
fn detect_apple(_: &Target) -> bool {
cfg!(any(target_os = "ios", target_os = "macos"))
}
fn detect_cygwin(_: &Target) -> bool {
// Cygwin target is usually cross-compiled.
std::env::var("CARGO_CFG_TARGET_OS").unwrap() == "cygwin"
}
/// Detect if we're being compiled for a BSD-derived OS, allowing targeting code conditionally with
/// `#[cfg(bsd)]`.
///
/// Rust offers fine-grained conditional compilation per-os for the popular operating systems, but
/// doesn't necessarily include less-popular forks nor does it group them into families more
/// specific than "windows" vs "unix" so we can conditionally compile code for BSD systems.
fn detect_bsd(_: &Target) -> Result<bool, Box<dyn Error>> {
fn detect_bsd(_: &Target) -> bool {
// Instead of using `uname`, we can inspect the TARGET env variable set by Cargo. This lets us
// support cross-compilation scenarios.
let mut target = std::env::var("TARGET").unwrap();
if !target.chars().all(|c| c.is_ascii_lowercase()) {
target = target.to_ascii_lowercase();
}
#[allow(clippy::let_and_return)] // for old clippy
let is_bsd = target.ends_with("bsd") || target.ends_with("dragonfly");
#[cfg(any(
target_os = "dragonfly",
@@ -144,52 +142,7 @@ fn detect_bsd(_: &Target) -> Result<bool, Box<dyn Error>> {
target_os = "openbsd",
))]
assert!(is_bsd, "Target incorrectly detected as not BSD!");
Ok(is_bsd)
}
/// Detect libintl/gettext and its needed symbols to enable internationalization/localization
/// support.
fn have_gettext(target: &Target) -> Result<bool, Box<dyn Error>> {
// The following script correctly detects and links against gettext, but so long as we are using
// C++ and generate a static library linked into the C++ binary via CMake, we need to account
// for the CMake option WITH_GETTEXT being explicitly disabled.
rsconf::rebuild_if_env_changed("CMAKE_WITH_GETTEXT");
if let Some(with_gettext) = std::env::var_os("CMAKE_WITH_GETTEXT") {
if with_gettext.eq_ignore_ascii_case("0") {
return Ok(false);
}
}
// In order for fish to correctly operate, we need some way of notifying libintl to invalidate
// its localizations when the locale environment variables are modified. Without the libintl
// symbol _nl_msg_cat_cntr, we cannot use gettext even if we find it.
let mut libraries = Vec::new();
let mut found = 0;
let symbols = ["gettext", "_nl_msg_cat_cntr"];
for symbol in &symbols {
// Historically, libintl was required in order to use gettext() and co, but that
// functionality was subsumed by some versions of libc.
if target.has_symbol(symbol) {
// No need to link anything special for this symbol
found += 1;
continue;
}
for library in ["intl", "gettextlib"] {
if target.has_symbol_in(symbol, &[library]) {
libraries.push(library);
found += 1;
continue;
}
}
}
match found {
0 => Ok(false),
1 => Err(format!("gettext found but cannot be used without {}", symbols[1]).into()),
_ => {
rsconf::link_libraries(&libraries, LinkType::Default);
Ok(true)
}
}
is_bsd
}
/// Rust sets the stack size of newly created threads to a sane value, but is at at the mercy of the
@@ -198,15 +151,15 @@ fn have_gettext(target: &Target) -> Result<bool, Box<dyn Error>> {
///
/// 0.5 MiB is small enough that we'd have to drastically reduce MAX_STACK_DEPTH to less than 10, so
/// we instead use a workaround to increase the main thread size.
fn has_small_stack(_: &Target) -> Result<bool, Box<dyn Error>> {
#[cfg(not(any(target_os = "macos", target_os = "netbsd")))]
return Ok(false);
fn has_small_stack(_: &Target) -> bool {
#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "netbsd")))]
return false;
// NetBSD 10 also needs this but can't find pthread_get_stacksize_np.
#[cfg(target_os = "netbsd")]
return Ok(true);
return true;
#[cfg(target_os = "macos")]
#[cfg(any(target_os = "ios", target_os = "macos"))]
{
use core::ffi;
@@ -220,14 +173,17 @@ fn has_small_stack(_: &Target) -> Result<bool, Box<dyn Error>> {
let stack_size = unsafe { pthread_get_stacksize_np(pthread_self()) };
const TWO_MIB: usize = 2 * 1024 * 1024 - 1;
match stack_size {
0..=TWO_MIB => Ok(true),
_ => Ok(false),
0..=TWO_MIB => true,
_ => false,
}
}
}
fn setup_paths() {
fn get_path(name: &str, default: &str, onvar: PathBuf) -> PathBuf {
#[cfg(windows)]
use unix_path::{Path, PathBuf};
fn get_path(name: &str, default: &str, onvar: &Path) -> PathBuf {
let mut var = PathBuf::from(env::var(name).unwrap_or(default.to_string()));
if var.is_relative() {
var = onvar.join(var);
@@ -235,53 +191,44 @@ fn get_path(name: &str, default: &str, onvar: PathBuf) -> PathBuf {
var
}
let (prefix_from_home, prefix) = if let Ok(pre) = env::var("PREFIX") {
(false, PathBuf::from(pre))
} else {
(true, PathBuf::from(".local/"))
};
// If someone gives us a $PREFIX, we need it to be absolute.
// Otherwise we would try to get it from $HOME and that won't really work.
if !prefix_from_home && prefix.is_relative() {
panic!("Can't have relative prefix");
}
let prefix = PathBuf::from(env::var("PREFIX").unwrap_or("/usr/local".to_string()));
rsconf::rebuild_if_env_changed("PREFIX");
rsconf::set_env_value("PREFIX", prefix.to_str().unwrap());
let datadir = get_path("DATADIR", "share/", prefix.clone());
rsconf::set_env_value("DATADIR", datadir.to_str().unwrap());
rsconf::rebuild_if_env_changed("DATADIR");
let datadir_subdir = if prefix_from_home {
"fish/install"
} else {
"fish"
};
rsconf::set_env_value("DATADIR_SUBDIR", datadir_subdir);
let bindir = get_path("BINDIR", "bin/", prefix.clone());
rsconf::set_env_value("BINDIR", bindir.to_str().unwrap());
rsconf::rebuild_if_env_changed("BINDIR");
let datadir = get_path("DATADIR", "share/", &prefix);
let sysconfdir = get_path(
"SYSCONFDIR",
// If we get our prefix from $HOME, we should use the system's /etc/
// ~/.local/share/etc/ makes no sense
if prefix_from_home { "/etc/" } else { "etc/" },
datadir.clone(),
// Embedded builds use "/etc," not "./share/etc".
if cfg!(feature = "embed-data") {
"/etc/"
} else {
"etc/"
},
&datadir,
);
rsconf::set_env_value("SYSCONFDIR", sysconfdir.to_str().unwrap());
rsconf::rebuild_if_env_changed("SYSCONFDIR");
let localedir = get_path("LOCALEDIR", "locale/", datadir.clone());
rsconf::set_env_value("LOCALEDIR", localedir.to_str().unwrap());
rsconf::rebuild_if_env_changed("LOCALEDIR");
#[cfg(not(feature = "embed-data"))]
{
rsconf::set_env_value("DATADIR", datadir.to_str().unwrap());
rsconf::rebuild_if_env_changed("DATADIR");
let docdir = get_path("DOCDIR", "doc/fish", datadir.clone());
rsconf::set_env_value("DOCDIR", docdir.to_str().unwrap());
rsconf::rebuild_if_env_changed("DOCDIR");
let bindir = get_path("BINDIR", "bin/", &prefix);
rsconf::set_env_value("BINDIR", bindir.to_str().unwrap());
rsconf::rebuild_if_env_changed("BINDIR");
let localedir = get_path("LOCALEDIR", "locale/", &datadir);
let localedir = localedir.to_str().unwrap();
assert!(!localedir.is_empty(), "empty LOCALEDIR is not supported");
rsconf::set_env_value("LOCALEDIR", localedir);
rsconf::rebuild_if_env_changed("LOCALEDIR");
let docdir = get_path("DOCDIR", "doc/fish", &datadir);
rsconf::set_env_value("DOCDIR", docdir.to_str().unwrap());
rsconf::rebuild_if_env_changed("DOCDIR");
}
}
fn get_version(src_dir: &Path) -> String {
@@ -292,9 +239,9 @@ fn get_version(src_dir: &Path) -> String {
return var;
}
let path = PathBuf::from(src_dir).join("version");
let path = src_dir.join("version");
if let Ok(strver) = read_to_string(path) {
return strver.to_string();
return strver;
}
let args = &["describe", "--always", "--dirty=-dirty"];
@@ -321,17 +268,37 @@ fn get_version(src_dir: &Path) -> String {
// or because it refused (safe.directory applies to `git describe`!)
// So we read the SHA ourselves.
fn get_git_hash() -> Result<String, Box<dyn std::error::Error>> {
let gitdir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(".git");
let workspace_root = workspace_root();
let gitdir = workspace_root.join(".git");
let jjdir = workspace_root.join(".jj");
let commit_id = if gitdir.exists() {
// .git/HEAD contains ref: refs/heads/branch
let headpath = gitdir.join("HEAD");
let headstr = read_to_string(headpath)?;
let headref = headstr.split(' ').nth(1).unwrap().trim();
// .git/HEAD contains ref: refs/heads/branch
let headpath = gitdir.join("HEAD");
let headstr = read_to_string(headpath)?;
let headref = headstr.split(' ').collect::<Vec<_>>()[1].trim();
// .git/refs/heads/branch contains the SHA
let refpath = gitdir.join(headref);
// Shorten to 9 characters (what git describe does currently)
let refstr = &read_to_string(refpath)?[0..9];
// .git/refs/heads/branch contains the SHA
let refpath = gitdir.join(headref);
// Shorten to 9 characters (what git describe does currently)
read_to_string(refpath)?
} else if jjdir.exists() {
let output = Command::new("jj")
.args([
"log",
"--revisions",
"@",
"--no-graph",
"--ignore-working-copy",
"--template",
"commit_id",
])
.output()
.unwrap();
String::from_utf8_lossy(&output.stdout).to_string()
} else {
return Err("did not find either of .git or .jj".into());
};
let refstr = &commit_id[0..9];
let refstr = refstr.trim();
let version = env!("CARGO_PKG_VERSION").to_owned();
@@ -340,74 +307,3 @@ fn get_git_hash() -> Result<String, Box<dyn std::error::Error>> {
get_git_hash().expect("Could not get a version. Either set $FISH_BUILD_VERSION or install git.")
}
#[cfg(feature = "installable")]
// disable clippy because otherwise it would panic without sphinx
#[cfg(not(clippy))]
fn build_man(build_dir: &Path) {
use std::process::Command;
let mandir = build_dir;
let sec1dir = mandir.join("man1");
let docsrc_path = std::fs::canonicalize(env!("CARGO_MANIFEST_DIR"))
.unwrap()
.as_path()
.join("doc_src");
let docsrc = docsrc_path.to_str().unwrap();
let args = &[
"-j",
"auto",
"-q",
"-b",
"man",
"-c",
docsrc,
// doctree path - put this *above* the man1 dir to exclude it.
// this is ~6M
"-d",
mandir.to_str().unwrap(),
docsrc,
sec1dir.to_str().unwrap(),
];
let _ = std::fs::create_dir_all(sec1dir.to_str().unwrap());
rsconf::rebuild_if_env_changed("FISH_BUILD_DOCS");
if env::var("FISH_BUILD_DOCS") == Ok("0".to_string()) {
println!("cargo:warning=Skipping man pages because $FISH_BUILD_DOCS is set to 0");
return;
}
// We run sphinx to build the man pages.
// Every error here is fatal so cargo doesn't cache the result
// - if we skipped the docs with sphinx not installed, installing it would not then build the docs.
// That means you need to explicitly set $FISH_BUILD_DOCS=0 (`FISH_BUILD_DOCS=0 cargo install --path .`),
// which is unfortunate - but the docs are pretty important because they're also used for --help.
match Command::new("sphinx-build").args(args).spawn() {
Err(x) if x.kind() == std::io::ErrorKind::NotFound => {
if env::var("FISH_BUILD_DOCS") == Ok("1".to_string()) {
panic!("Could not find sphinx-build to build man pages.\nInstall sphinx or disable building the docs by setting $FISH_BUILD_DOCS=0.");
}
println!("cargo:warning=Cannot find sphinx-build to build man pages.");
println!("cargo:warning=If you install it now you need to run `cargo clean` and rebuild, or set $FISH_BUILD_DOCS=1 explicitly.");
}
Err(x) => {
// Another error - permissions wrong etc
panic!("Error starting sphinx-build to build man pages: {:?}", x);
}
Ok(mut x) => match x.wait() {
Err(err) => {
panic!(
"Error waiting for sphinx-build to build man pages: {:?}",
err
);
}
Ok(out) => {
if out.success() {
// Success!
return;
} else {
panic!("sphinx-build failed to build the man pages.");
}
}
},
}
}

62
build_tools/check.sh Executable file
View File

@@ -0,0 +1,62 @@
#!/bin/sh
{
set -ex
lint=true
if [ "$FISH_CHECK_LINT" = false ]; then
lint=false
fi
cargo_args=$FISH_CHECK_CARGO_ARGS
target_triple=$FISH_CHECK_TARGET_TRIPLE
if [ -n "$target_triple" ]; then
cargo_args="$cargo_args --target=$FISH_CHECK_TARGET_TRIPLE"
fi
cargo() {
subcmd=$1
shift
# shellcheck disable=2086
command cargo "$subcmd" $cargo_args "$@"
}
cleanup () {
if [ -n "$template_file" ] && [ -e "$template_file" ]; then
rm "$template_file"
fi
}
trap cleanup EXIT INT TERM HUP
if $lint; then
export RUSTFLAGS="--deny=warnings ${RUSTFLAGS}"
export RUSTDOCFLAGS="--deny=warnings ${RUSTDOCFLAGS}"
fi
workspace_root="$(dirname "$0")/.."
target_dir=${CARGO_TARGET_DIR:-$workspace_root/target}
if [ -n "$target_triple" ]; then
target_dir="$target_dir/$target_triple"
fi
# The directory containing the binaries produced by cargo/rustc.
# Currently, all builds are debug builds.
build_dir="$target_dir/debug"
template_file=$(mktemp)
FISH_GETTEXT_EXTRACTION_FILE=$template_file cargo build --workspace --all-targets --features=gettext-extract
if $lint; then
PATH="$build_dir:$PATH" "$workspace_root/build_tools/style.fish" --all --check
for features in "" --no-default-features; do
cargo clippy --workspace --all-targets $features
done
fi
cargo test --no-default-features --workspace --all-targets
cargo test --doc --workspace
if $lint; then
cargo doc --workspace
fi
FISH_GETTEXT_EXTRACTION_FILE=$template_file "$workspace_root/tests/test_driver.py" "$build_dir"
exit
}

15
build_tools/diff_profiles.fish Normal file → Executable file
View File

@@ -5,6 +5,13 @@
#
# Usage: ./diff_profiles.fish profile1.log profile2.log > profile_diff.log
if test (count $argv) -ne 2
echo "Incorrect number of arguments."
echo "Usage: "(status filename)" profile1.log profile2.log"
exit 1
end
set -l profile1 (cat $argv[1])
set -l profile2 (cat $argv[2])
@@ -15,13 +22,13 @@ while set -l next_line_no (math $line_no + 1) && set -q profile1[$next_line_no]
set -l line1 $profile1[$line_no]
set -l line2 $profile2[$line_no]
if not string match -qr '^\d+\t\d+' $line1
if not string match -qr '^\s*\d+\s+\d+' $line1
echo $line1
continue
end
set -l results1 (string match -r '^(\d+)\t(\d+)\s+(.*)' $line1)
set -l results2 (string match -r '^(\d+)\t(\d+)\s+(.*)' $line2)
set -l results1 (string match -r '^\s*(\d+)\s+(\d+)\s+(.*)' $line1)
set -l results2 (string match -r '^\s*(\d+)\s+(\d+)\s+(.*)' $line2)
# times from both files
set -l time1 $results1[2..3]
@@ -42,5 +49,5 @@ while set -l next_line_no (math $line_no + 1) && set -q profile1[$next_line_no]
set diff[1] (math $time1[1] - $time2[1])
set diff[2] (math $time1[2] - $time2[2])
echo $diff[1] $diff[2] $remainder1
printf '%10d %10d %s\n' $diff[1] $diff[2] $remainder1
end

View File

@@ -1,68 +1,139 @@
#!/usr/bin/env fish
#
# Tool to generate messages.pot
# Tool to generate gettext messages template file.
# Writes to stdout.
# Intended to be called from `update_translations.fish`.
# Create temporary directory for these operations. OS X `mktemp` is somewhat restricted, so this block
# works around that - based on share/functions/funced.fish.
set -q TMPDIR
or set -l TMPDIR /tmp
set -l tmpdir (mktemp -d $TMPDIR/fish.XXXXXX)
or exit 1
argparse use-existing-template= -- $argv
or exit $status
# This is a gigantic crime.
# xgettext still does not support rust *at all*, so we use cargo-expand to get all our wgettext invocations.
set -l expanded (cargo expand --lib; for f in fish{,_indent,_key_reader}; cargo expand --bin $f; end)
begin
# Write header. This is required by msguniq.
# Note that this results in the file being overwritten.
# This is desired behavior, to get rid of the results of prior invocations
# of this script.
begin
echo 'msgid ""'
echo 'msgstr ""'
echo '"Content-Type: text/plain; charset=UTF-8\n"'
echo ""
end
# Extract any gettext call
set -l strs (printf '%s\n' $expanded | grep -A1 wgettext_static_str |
grep 'widestring::internals::core::primitive::str =' |
string match -rg '"(.*)"' | string match -rv '^%ls$|^$' |
# escaping difference between gettext and cargo-expand: single-quotes
string replace -a "\'" "'" | sort -u)
set -g workspace_root (path resolve (status dirname)/..)
# Extract any constants
set -a strs (string match -rv 'BUILD_VERSION:|PACKAGE_NAME' -- $expanded |
string match -rg 'const [A-Z_]*: &str = "(.*)"' | string replace -a "\'" "'")
set -l rust_extraction_file
if set -l --query _flag_use_existing_template
set rust_extraction_file $_flag_use_existing_template
else
set rust_extraction_file (mktemp)
# We need to build to ensure that the proc macro for extracting strings runs.
FISH_GETTEXT_EXTRACTION_FILE=$rust_extraction_file cargo check --features=gettext-extract
or exit 1
end
# We construct messages.pot ourselves instead of forcing this into msgmerge or whatever.
# The escaping so far works out okay.
for str in $strs
# grep -P needed for string escape to be compatible (PCRE-style),
# -H gives the filename, -n the line number.
# If you want to run this on non-GNU grep: Don't.
echo "#:" (grep -PHn -r -- (string escape --style=regex -- $str) src/ |
head -n1 | string replace -r ':\s.*' '')
echo "msgid \"$str\""
echo 'msgstr ""'
end >messages.pot
echo '# fish-section-tier1-from-rust'
# Get rid of duplicates and sort.
msguniq --no-wrap --strict --sort-output $rust_extraction_file
or exit 1
# This regex handles descriptions for `complete` and `function` statements. These messages are not
# particularly important to translate. Hence the "implicit" label.
set -l implicit_regex '(?:^| +)(?:complete|function).*? (?:-d|--description) (([\'"]).+?(?<!\\\\)\\2).*'
if not set -l --query _flag_use_existing_template
rm $rust_extraction_file
end
# This regex handles explicit requests to translate a message. These are more important to translate
# than messages which should be implicitly translated.
set -l explicit_regex '.*\( *_ (([\'"]).+?(?<!\\\\)\\2) *\).*'
function extract_fish_script_messages_impl
set -l regex $argv[1]
set -e argv[1]
# Using xgettext causes more trouble than it helps.
# This is due to handling of escaping in fish differing from formats xgettext understands
# (e.g. POSIX shell strings).
# We work around this issue by manually writing the file content.
mkdir -p $tmpdir/implicit/share/completions $tmpdir/implicit/share/functions
mkdir -p $tmpdir/explicit/share/completions $tmpdir/explicit/share/functions
# Steps:
# 1. We extract strings to be translated from the relevant files and drop the rest. This step
# depends on the regex matching the entire line, and the first capture group matching the
# string.
# 2. We unescape. This gets rid of some escaping necessary in fish strings.
# 3. The resulting strings are sorted alphabetically. This step is optional. Not sorting would
# result in strings from the same file appearing together. Removing duplicates is also
# optional, since msguniq takes care of that later on as well.
# 4. Single backslashes are replaced by double backslashes. This results in the backslashes
# being interpreted as literal backslashes by gettext tooling.
# 5. Double quotes are escaped, such that they are not interpreted as the start or end of
# a msgid.
# 6. We transform the string into the format expected in a PO file.
cat $argv |
string replace --filter --regex $regex '$1' |
string unescape |
sort -u |
sed -E -e 's_\\\\_\\\\\\\\_g' -e 's_"_\\\\"_g' -e 's_^(.*)$_msgid "\1"\nmsgstr ""\n_'
end
for f in share/config.fish share/completions/*.fish share/functions/*.fish
# Extract explicit attempts to translate a message. That is, those that are of the form
# `(_ "message")`.
string replace --filter --regex $explicit_regex '$1' <$f | string unescape \
| string replace --all '"' '\\"' | string replace -r '(.*)' 'N_ "$1"' >$tmpdir/explicit/$f
function extract_fish_script_messages
set -l tier $argv[1]
set -e argv[1]
if not set -q argv[1]
return
end
# This regex handles explicit requests to translate a message. These are more important to translate
# than messages which should be implicitly translated.
set -l explicit_regex '.*\( *_ (([\'"]).+?(?<!\\\\)\\2) *\).*'
echo "# fish-section-$tier-from-script-explicitly-added"
extract_fish_script_messages_impl $explicit_regex $argv
# Handle `complete` / `function` description messages. The `| fish` is subtle. It basically
# avoids the need to use `source` with a command substitution that could affect the current
# shell.
string replace --filter --regex $implicit_regex '$1' <$f | string unescape \
| string replace --all '"' '\\"' | string replace -r '(.*)' 'N_ "$1"' >$tmpdir/implicit/$f
end
# This regex handles descriptions for `complete` and `function` statements. These messages are not
# particularly important to translate. Hence the "implicit" label.
set -l implicit_regex '^(?:\s|and |or )*(?:complete|function).*? (?:-d|--description) (([\'"]).+?(?<!\\\\)\\2).*'
echo "# fish-section-$tier-from-script-implicitly-added"
extract_fish_script_messages_impl $implicit_regex $argv
end
xgettext -j -k -kN_ -LShell --from-code=UTF-8 -cDescription --no-wrap -o messages.pot $tmpdir/{ex,im}plicit/share/*/*.fish
set -g share_dir $workspace_root/share
# Remove the tmpdir from the location to avoid churn
sed -i 's_^#: /.*/share/_#: share/_' messages.pot
set -l tier1 $share_dir/config.fish
set -l tier2
set -l tier3
rm -r $tmpdir
for file in $share_dir/completions/*.fish $share_dir/functions/*.fish
# set -l tier (string match -r '^# localization: .*' <$file)
set -l tier (string replace -rf -m1 \
'^# localization: (.*)$' '$1' <$file)
if set -q tier[1]
switch "$tier"
case tier1 tier2 tier3
set -a $tier $file
case 'skip*'
case '*'
echo >&2 "$file:1 unexpected localization tier: $tier"
exit 1
end
continue
end
set -l dirname (path basename (path dirname $file))
set -l command_name (path basename --no-extension $file)
if test $dirname = functions &&
string match -q -- 'fish_*' $command_name
set -a tier1 $file
continue
end
if test $dirname != completions
echo >&2 "$file:1 missing localization tier for function file"
exit 1
end
if test -e $workspace_root/doc_src/cmds/$command_name.rst
set -a tier1 $file
else
set -a tier3 $file
end
end
extract_fish_script_messages tier1 $tier1
extract_fish_script_messages tier2 $tier2
extract_fish_script_messages tier3 $tier3
end |
# At this point, all extracted strings have been written to stdout,
# starting with the ones taken from the Rust sources,
# followed by strings explicitly marked for translation in fish scripts,
# and finally the strings from fish scripts which get translated implicitly.
# Because we do not eliminate duplicates across these categories,
# we do it here, since other gettext tools expect no duplicates.
msguniq --no-wrap

View File

@@ -47,7 +47,7 @@ then
# HACK: Git failed, so we keep the current version file.
# This helps in case you built fish as a normal user
# and then try to `sudo make install` it.
date +%s > ${OUTPUT_DIR}fish-build-version-witness.txt
date +%s > "${OUTPUT_DIR}"fish-build-version-witness.txt
exit 0
fi
@@ -67,4 +67,4 @@ test "$VN" = "$VC" || {
# Output the fish-build-version-witness.txt
# See https://cmake.org/cmake/help/v3.4/policy/CMP0058.html
date +%s > ${OUTPUT_DIR}fish-build-version-witness.txt
date +%s > "${OUTPUT_DIR}"fish-build-version-witness.txt

View File

@@ -0,0 +1,392 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>platform-application</key>
<true/>
<key>com.apple.private.security.no-container</key>
<true/>
<key>com.apple.private.security.container-manager</key>
<true/>
<key>com.apple.private.skip-library-validation</key>
<true/>
<key>com.apple.private.MobileContainerManager.allowed</key>
<true/>
<key>com.apple.private.security.storage.adprivacyd</key>
<true/>
<key>com.apple.private.security.storage.amfid</key>
<true/>
<key>com.apple.private.security.storage.AppBundles</key>
<true/>
<key>com.apple.private.security.storage.AppDataContainers</key>
<true/>
<key>com.apple.private.security.storage.automation-mode</key>
<true/>
<key>com.apple.private.security.storage.Biome</key>
<true/>
<key>com.apple.private.security.storage.Calendar</key>
<true/>
<key>com.apple.private.security.storage.CallHistory</key>
<true/>
<key>com.apple.private.security.storage.CarrierBundles</key>
<true/>
<key>com.apple.private.security.storage.chronod</key>
<true/>
<key>com.apple.private.security.storage.CloudDocsDB</key>
<true/>
<key>com.apple.private.security.storage.CloudKit</key>
<true/>
<key>com.apple.private.security.storage.containers</key>
<true/>
<key>com.apple.private.security.storage.CoreFollowUp</key>
<true/>
<key>com.apple.private.security.storage.CoreKnowledge</key>
<true/>
<key>com.apple.private.security.storage.Cryptex</key>
<true/>
<key>com.apple.private.security.storage.demo_backup</key>
<true/>
<key>com.apple.private.security.storage.DocumentRevisions</key>
<true/>
<key>com.apple.private.security.storage.DumpPanic</key>
<true/>
<key>com.apple.private.security.storage.ExposureNotification</key>
<true/>
<key>com.apple.private.security.storage.FaceTime</key>
<true/>
<key>com.apple.private.security.storage.familycircled</key>
<true/>
<key>com.apple.private.security.storage.FindMy</key>
<true/>
<key>com.apple.private.security.storage.fpsd</key>
<true/>
<key>com.apple.private.security.storage.Health</key>
<true/>
<key>com.apple.private.security.storage.HomeAI</key>
<true/>
<key>com.apple.private.security.storage.HomeKit</key>
<true/>
<key>com.apple.private.security.storage.iCloudDrive</key>
<true/>
<key>com.apple.private.security.storage.idcredd</key>
<true/>
<key>com.apple.private.security.storage.IdentityServices</key>
<true/>
<key>com.apple.private.security.storage.kbd</key>
<true/>
<key>com.apple.private.security.storage.Keychains</key>
<true/>
<key>com.apple.private.security.storage.Lockdown</key>
<true/>
<key>com.apple.private.security.storage.Mail</key>
<true/>
<key>com.apple.private.security.storage.Messages</key>
<true/>
<key>com.apple.private.security.storage.MessagesMetaData</key>
<true/>
<key>com.apple.private.security.storage.MobileContainerManager</key>
<true/>
<key>com.apple.private.security.storage.MobileDocuments</key>
<true/>
<key>com.apple.private.security.storage.MobileIdentityService</key>
<true/>
<key>com.apple.private.security.storage.mobilesync</key>
<true/>
<key>com.apple.private.security.storage.multimodalsearchd</key>
<true/>
<key>com.apple.private.security.storage.NanoTimeKit.FaceSupport</key>
<true/>
<key>com.apple.private.security.storage.News</key>
<true/>
<key>com.apple.private.security.storage.Notes</key>
<true/>
<key>com.apple.private.security.storage.Photos</key>
<true/>
<key>com.apple.private.security.storage.PhotosLibraries</key>
<true/>
<key>com.apple.private.security.storage.pipelined</key>
<true/>
<key>com.apple.private.security.storage.preferences</key>
<true/>
<key>com.apple.private.security.storage.PrivacyAccounting</key>
<true/>
<key>com.apple.private.security.storage.Safari</key>
<true/>
<key>com.apple.private.security.storage.SearchParty</key>
<true/>
<key>com.apple.private.security.storage.SecureElementService</key>
<true/>
<key>com.apple.private.security.storage.SensorKit</key>
<true/>
<key>com.apple.private.security.storage.SFAnalytics</key>
<true/>
<key>com.apple.private.security.storage.SiriInference</key>
<true/>
<key>com.apple.private.security.storage.SiriReferenceResolution</key>
<true/>
<key>com.apple.private.security.storage.SiriVocabulary</key>
<true/>
<key>com.apple.private.security.storage.SoC</key>
<true/>
<key>com.apple.private.security.storage.SpeechPersonalizedLM</key>
<true/>
<key>com.apple.private.security.storage.Spotlight</key>
<true/>
<key>com.apple.private.security.storage.StatusKit</key>
<true/>
<key>com.apple.private.security.storage.Stocks</key>
<true/>
<key>com.apple.private.security.storage.Suggestions</key>
<true/>
<key>com.apple.private.security.storage.SymptomFramework</key>
<true/>
<key>com.apple.private.security.storage.sysdagnose.ScreenshotServicesService</key>
<true/>
<key>com.apple.private.security.storage.TCC</key>
<true/>
<key>com.apple.private.security.storage.TimeMachine</key>
<true/>
<key>com.apple.private.security.storage.triald</key>
<true/>
<key>com.apple.private.security.storage.trustd</key>
<true/>
<key>com.apple.private.security.storage.trustd-private</key>
<true/>
<key>com.apple.private.security.storage.universalaccess</key>
<true/>
<key>com.apple.private.security.storage.Voicemail</key>
<true/>
<key>com.apple.private.security.storage.Wireless</key>
<true/>
<key>com.apple.private.security.disk-device-access</key>
<true/>
<key>com.apple.rootless.storage.ane_model_cache</key>
<true/>
<key>com.apple.rootless.storage.apfs_boot_mount</key>
<true/>
<key>com.apple.rootless.storage.clientScripter</key>
<true/>
<key>com.apple.rootless.storage.com.apple.mediaanalysisd</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.CarPlayAppBlacklist</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.DeviceCheck</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.DictionaryServices.dictionary2</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.DuetExpertCenterAsset</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.EmbeddedNL</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Font5</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Font6</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.HealthKt.FeatureAvailability</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.HomeKit</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.MacinTalkVoiceAssets</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.MailDynamicData</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.MXLongFormVideoApps</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.network.networknomicon</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.PKITrustSupplementals</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.SharingDeviceAssets</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.SiriShortcutsMobileAsset</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.TimeZoneUpdate</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.VoiceServices.CombinedVocalizerVoices</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.VoiceServices.CustomVoice</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.VoiceServices.GryphonVoice</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.VoiceServicesVocalizerVoice</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.VoiceServices.VoiceResources</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.VoiceTriggerAssets</key>
<true/>
<key>com.apple.rootless.storage.CoreAnalytics</key>
<true/>
<key>com.apple.rootless.storage.coreduet_knowledge_store</key>
<true/>
<key>com.apple.rootless.storage.coreidvd</key>
<true/>
<key>com.apple.rootless.storage.coreknowledge</key>
<true/>
<key>com.apple.rootless.storage.CoreRoutine</key>
<true/>
<key>com.apple.rootless.storage.CoreSpeech</key>
<true/>
<key>com.apple.rootless.storage.dmd</key>
<true/>
<key>com.apple.rootless.storage.dprivacyd_storage</key>
<true/>
<key>com.apple.rootless.storage.ExtensibleSSO</key>
<true/>
<key>com.apple.rootless.storage.facekit</key>
<true/>
<key>com.apple.rootless.storage.fpsd</key>
<true/>
<key>com.apple.rootless.storage.MobileStorageMounter</key>
<true/>
<key>com.apple.rootless.storage.MusicApp</key>
<true/>
<key>com.apple.rootless.storage.nsurlsessiond</key>
<true/>
<key>com.apple.rootless.storage.pearl-field-diagnostics</key>
<true/>
<key>com.apple.rootless.storage.proactivepredictions</key>
<true/>
<key>com.apple.rootless.storage.QLThumbnailCache</key>
<true/>
<key>com.apple.rootless.storage.remotemanagementd</key>
<true/>
<key>com.apple.rootless.storage.RoleAccountStaging</key>
<true/>
<key>com.apple.rootless.storage.sensorkit</key>
<true/>
<key>com.apple.rootless.storage.shortcuts</key>
<true/>
<key>com.apple.rootless.storage.siriremembers</key>
<true/>
<key>com.apple.rootless.storage.timezone</key>
<true/>
<key>com.apple.rootless.storage.triald</key>
<true/>
<key>com.apple.rootless.storage.voiceshortcuts</key>
<true/>
<key>com.apple.private.security.storage-exempt.heritable</key>
<true/>
<key>com.apple.private.security.storage.AppleMediaServices</key>
<true/>
<key>com.apple.private.security.storage.ContactlessReader</key>
<true/>
<key>com.apple.private.security.storage.CoreRoutine</key>
<true/>
<key>com.apple.private.security.storage.DiagnosticReports</key>
<true/>
<key>com.apple.private.security.storage.DiagnosticReports.read-write</key>
<true/>
<key>com.apple.private.security.storage.DoNotDisturb</key>
<true/>
<key>com.apple.private.security.storage.Home</key>
<true/>
<key>com.apple.private.security.storage.IntelligencePlatform</key>
<true/>
<key>com.apple.private.security.storage.Location</key>
<true/>
<key>com.apple.private.security.storage.ManagedConfiguration</key>
<true/>
<key>com.apple.private.security.storage.MapsSync</key>
<true/>
<key>com.apple.private.security.storage.MobileBackup</key>
<true/>
<key>com.apple.private.security.storage.MobileStorageMounter</key>
<true/>
<key>com.apple.private.security.storage.PassKit</key>
<true/>
<key>com.apple.private.security.storage.SiriFeatureStore</key>
<true/>
<key>com.apple.private.security.storage.SiriSELF</key>
<true/>
<key>com.apple.private.security.storage.SoundProfileAsset</key>
<true/>
<key>com.apple.private.security.storage.TextUnderstanding</key>
<true/>
<key>com.apple.private.security.storage.Weather</key>
<true/>
<key>com.apple.private.security.storage.appleaccountd</key>
<true/>
<key>com.apple.private.security.storage.ciconia</key>
<true/>
<key>com.apple.private.security.storage.clipserviced</key>
<true/>
<key>com.apple.private.security.storage.coreduet_knowledge_store</key>
<true/>
<key>com.apple.private.security.storage.driverkitd</key>
<true/>
<key>com.apple.private.security.storage.geoanalyticsd</key>
<true/>
<key>com.apple.private.security.storage.geod</key>
<true/>
<key>com.apple.private.security.storage.launchd</key>
<true/>
<key>com.apple.private.security.storage.sessionkitd</key>
<true/>
<key>com.apple.private.security.storage.sysdiagnose.ScreenshotServicesService</key>
<true/>
<key>com.apple.private.security.storage.sysdiagnose.sysdiagnose</key>
<true/>
<key>com.apple.private.security.storage.tmp</key>
<true/>
<key>com.apple.rootless.critical</key>
<true/>
<key>com.apple.rootless.datavault.metadata</key>
<true/>
<key>com.apple.rootless.install</key>
<true/>
<key>com.apple.rootless.install.heritable</key>
<true/>
<key>com.apple.rootless.restricted-block-devices</key>
<true/>
<key>com.apple.rootless.storage.MobileAssetDownload</key>
<true/>
<key>com.apple.rootless.storage.amsengagementd</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.HealthKit.FeatureAvailability</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriDialogAssets</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriExperienceCam</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriFindMyConfigurationFiles</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriInferredHelpfulness</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriTextToSpeech</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriUnderstandingAsrAssistant</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriUnderstandingAsrHammer</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriUnderstandingAsrUaap</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriUnderstandingAttentionAssets</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriUnderstandingMorphun</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriUnderstandingNL</key>
<true/>
<key>com.apple.rootless.storage.com.apple.MobileAsset.Trial.Siri.SiriUnderstandingNLOverrides</key>
<true/>
<key>com.apple.rootless.storage.coreparsec_feedbacks</key>
<true/>
<key>com.apple.rootless.storage.coreparsec_uploadables</key>
<true/>
<key>com.apple.rootless.storage.early_boot_mount</key>
<true/>
<key>com.apple.rootless.storage.screentime</key>
<true/>
<key>com.apple.rootless.volume.ISCRecovery</key>
<true/>
<key>com.apple.rootless.volume.Preboot</key>
<true/>
<key>com.apple.rootless.volume.Recovery</key>
<true/>
<key>com.apple.rootless.volume.Update</key>
<true/>
<key>com.apple.rootless.volume.VM</key>
<true/>
<key>com.apple.rootless.volume.iSCPreboot</key>
<true/>
</dict>
</plist>

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/sh
# Helper to notarize an .app.zip or .pkg file.
@@ -13,7 +13,7 @@ for INPUT in "$@"; do
echo "Processing $INPUT"
test -f "$INPUT" || die "Not a file: $INPUT"
ext="${INPUT##*.}"
(test "$ext" = "zip" || test "$ext" = "pkg") || die "Unrecognized extension: $ext"
{ test "$ext" = "zip" || test "$ext" = "pkg"; } || die "Unrecognized extension: $ext"
xcrun notarytool submit "$INPUT" --keychain-profile AC_PASSWORD --wait
@@ -21,9 +21,7 @@ for INPUT in "$@"; do
TMPDIR=$(mktemp -d)
echo "Extracting to $TMPDIR"
unzip -q "$INPUT" -d "$TMPDIR"
# Force glob expansion.
STAPLE_TARGET="$TMPDIR"/*
STAPLE_TARGET=$(echo $STAPLE_TARGET)
STAPLE_TARGET=$(echo "$TMPDIR"/*)
else
STAPLE_TARGET="$INPUT"
fi
@@ -35,7 +33,7 @@ for INPUT in "$@"; do
INPUT_FULL=$(realpath "$INPUT")
rm -f "$INPUT"
cd "$(dirname "$STAPLE_TARGET")"
zip -r -q "$INPUT_FULL" $(basename "$STAPLE_TARGET")
zip -r -q "$INPUT_FULL" "$(basename "$STAPLE_TARGET")"
fi
echo "Processed $INPUT"

177
build_tools/make_macos_pkg.sh Executable file
View File

@@ -0,0 +1,177 @@
#!/usr/bin/env bash
# Script to produce an OS X installer .pkg and .app(.zip)
usage() {
echo "Build macOS packages, optionally signing and notarizing them."
echo "Usage: $0 options"
echo "Options:"
echo " -s Enables code signing"
echo " -f <APP_KEY.p12> Path to .p12 file for application signing"
echo " -i <INSTALLER_KEY.p12> Path to .p12 file for installer signing"
echo " -p <PASSWORD> Password for the .p12 files (necessary to access the certificates)"
echo " -e <entitlements file> (Optional) Path to an entitlements XML file"
echo " -n Enables notarization. This will fail if code signing is not also enabled."
echo " -j <API_KEY.JSON> Path to JSON file generated with \`rcodesign encode-app-store-connect-api-key\` (required for notarization)"
echo
exit 1
}
set -x
set -e
SIGN=
NOTARIZE=
ARM64_DEPLOY_TARGET='MACOSX_DEPLOYMENT_TARGET=11.0'
X86_64_DEPLOY_TARGET='MACOSX_DEPLOYMENT_TARGET=10.9'
# As of this writing, the most recent Rust release supports macOS back to 10.12.
# The first supported version of macOS on arm64 is 10.15, so any Rust is fine for arm64.
# We wish to support back to 10.9 on x86-64; the last version of Rust to support that is
# version 1.73.0.
RUST_VERSION_X86_64=1.70.0
while getopts "sf:i:p:e:nj:" opt; do
case $opt in
s) SIGN=1;;
f) P12_APP_FILE=$(realpath "$OPTARG");;
i) P12_INSTALL_FILE=$(realpath "$OPTARG");;
p) P12_PASSWORD="$OPTARG";;
e) ENTITLEMENTS_FILE=$(realpath "$OPTARG");;
n) NOTARIZE=1;;
j) API_KEY_FILE=$(realpath "$OPTARG");;
\?) usage;;
esac
done
if [ -n "$SIGN" ] && { [ -z "$P12_APP_FILE" ] || [ -z "$P12_INSTALL_FILE" ] || [ -z "$P12_PASSWORD" ]; }; then
usage
fi
if [ -n "$NOTARIZE" ] && [ -z "$API_KEY_FILE" ]; then
usage
fi
VERSION=$(build_tools/git_version_gen.sh --stdout 2>/dev/null)
echo "Version is $VERSION"
PKGDIR=$(mktemp -d)
echo "$PKGDIR"
SRC_DIR=$PWD
OUTPUT_PATH=${FISH_ARTEFACT_PATH:-~/fish_built}
mkdir -p "$PKGDIR/build_x86_64" "$PKGDIR/build_arm64" "$PKGDIR/root" "$PKGDIR/intermediates" "$PKGDIR/dst"
# Build and install for arm64.
# Pass FISH_USE_SYSTEM_PCRE2=OFF because a system PCRE2 on macOS will not be signed by fish,
# and will probably not be built universal, so the package will fail to validate/run on other systems.
# Note CMAKE_OSX_ARCHITECTURES is still relevant for the Mac app.
{ cd "$PKGDIR/build_arm64" \
&& cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_EXE_LINKER_FLAGS="-Wl,-ld_classic" \
-DRust_CARGO_TARGET=aarch64-apple-darwin \
-DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' \
-DFISH_USE_SYSTEM_PCRE2=OFF \
"$SRC_DIR" \
&& env $ARM64_DEPLOY_TARGET make VERBOSE=1 -j 12 \
&& env DESTDIR="$PKGDIR/root/" $ARM64_DEPLOY_TARGET make install;
}
# Build for x86-64 but do not install; instead we will make some fat binaries inside the root.
# Set RUST_VERSION_X86_64 to the last version of Rust that supports macOS 10.9.
{ cd "$PKGDIR/build_x86_64" \
&& cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_EXE_LINKER_FLAGS="-Wl,-ld_classic" \
-DRust_TOOLCHAIN="$RUST_VERSION_X86_64" \
-DRust_CARGO_TARGET=x86_64-apple-darwin \
-DRust_COMPILER="$(rustup +$RUST_VERSION_X86_64 which rustc)" \
-DRust_CARGO="$(rustup +$RUST_VERSION_X86_64 which cargo)" \
-DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' \
-DFISH_USE_SYSTEM_PCRE2=OFF "$SRC_DIR" \
&& env $X86_64_DEPLOY_TARGET make VERBOSE=1 -j 12; }
# Fatten them up.
for FILE in "$PKGDIR"/root/usr/local/bin/*; do
X86_FILE="$PKGDIR/build_x86_64/$(basename "$FILE")"
rcodesign macho-universal-create --output "$FILE" "$FILE" "$X86_FILE"
chmod 755 "$FILE"
done
if test -n "$SIGN"; then
echo "Signing executables"
ARGS=(
--p12-file "$P12_APP_FILE"
--p12-password "$P12_PASSWORD"
--code-signature-flags runtime
--for-notarization
)
if [ -n "$ENTITLEMENTS_FILE" ]; then
ARGS+=(--entitlements-xml-file "$ENTITLEMENTS_FILE")
fi
for FILE in "$PKGDIR"/root/usr/local/bin/*; do
(set +x; rcodesign sign "${ARGS[@]}" "$FILE")
done
fi
pkgbuild --scripts "$SRC_DIR/build_tools/osx_package_scripts" --root "$PKGDIR/root/" --identifier 'com.ridiculousfish.fish-shell-pkg' --version "$VERSION" "$PKGDIR/intermediates/fish.pkg"
productbuild --package-path "$PKGDIR/intermediates" --distribution "$SRC_DIR/build_tools/osx_distribution.xml" --resources "$SRC_DIR/build_tools/osx_package_resources/" "$OUTPUT_PATH/fish-$VERSION.pkg"
if test -n "$SIGN"; then
echo "Signing installer"
ARGS=(
--p12-file "$P12_INSTALL_FILE"
--p12-password "$P12_PASSWORD"
--code-signature-flags runtime
--for-notarization
)
(set +x; rcodesign sign "${ARGS[@]}" "$OUTPUT_PATH/fish-$VERSION.pkg")
fi
# Make the app
(cd "$PKGDIR/build_arm64" && env $ARM64_DEPLOY_TARGET make -j 12 fish_macapp)
(cd "$PKGDIR/build_x86_64" && env $X86_64_DEPLOY_TARGET make -j 12 fish_macapp)
# Make the app's /usr/local/bin binaries universal. Note fish.app/Contents/MacOS/fish already is, courtesy of CMake.
cd "$PKGDIR/build_arm64"
for FILE in fish.app/Contents/Resources/base/usr/local/bin/*; do
X86_FILE="$PKGDIR/build_x86_64/fish.app/Contents/Resources/base/usr/local/bin/$(basename "$FILE")"
rcodesign macho-universal-create --output "$FILE" "$FILE" "$X86_FILE"
# macho-universal-create screws up the permissions.
chmod 755 "$FILE"
done
if test -n "$SIGN"; then
echo "Signing app"
ARGS=(
--p12-file "$P12_APP_FILE"
--p12-password "$P12_PASSWORD"
--code-signature-flags runtime
--for-notarization
)
if [ -n "$ENTITLEMENTS_FILE" ]; then
ARGS+=(--entitlements-xml-file "$ENTITLEMENTS_FILE")
fi
(set +x; rcodesign sign "${ARGS[@]}" "fish.app")
fi
cp -R "fish.app" "$OUTPUT_PATH/fish-$VERSION.app"
cd "$OUTPUT_PATH"
# Maybe notarize.
if test -n "$NOTARIZE"; then
echo "Notarizing"
rcodesign notarize --staple --wait --max-wait-seconds 1800 --api-key-file "$API_KEY_FILE" "$OUTPUT_PATH/fish-$VERSION.pkg"
rcodesign notarize --staple --wait --max-wait-seconds 1800 --api-key-file "$API_KEY_FILE" "$OUTPUT_PATH/fish-$VERSION.app"
fi
# Zip it up.
zip -r "fish-$VERSION.app.zip" "fish-$VERSION.app" && rm -Rf "fish-$VERSION.app"
rm -rf "$PKGDIR"

View File

@@ -1,183 +0,0 @@
#!/usr/bin/env bash
# Script to produce an OS X installer .pkg and .app(.zip)
usage() {
echo "Build macOS packages, optionally signing and notarizing them."
echo "Usage: $0 options"
echo "Options:"
echo " -s Enables code signing"
echo " -f <APP_KEY.p12> Path to .p12 file for application signing"
echo " -i <INSTALLER_KEY.p12> Path to .p12 file for installer signing"
echo " -p <PASSWORD> Password for the .p12 files (necessary to access the certificates)"
echo " -e <entitlements file> (Optional) Path to an entitlements XML file"
echo " -n Enables notarization. This will fail if code signing is not also enabled."
echo " -j <API_KEY.JSON> Path to JSON file generated with `rcodesign encode-app-store-connect-api-key` (required for notarization)"
echo
exit 1
}
set -x
set -e
SIGN=
NOTARIZE=
ARM64_DEPLOY_TARGET='MACOSX_DEPLOYMENT_TARGET=11.0'
X86_64_DEPLOY_TARGET='MACOSX_DEPLOYMENT_TARGET=10.9'
# As of this writing, the most recent Rust release supports macOS back to 10.12.
# The first supported version of macOS on arm64 is 10.15, so any Rust is fine for arm64.
# We wish to support back to 10.9 on x86-64; the last version of Rust to support that is
# version 1.73.0.
RUST_VERSION_X86_64=1.73.0
while getopts "sf:i:p:e:nj:" opt; do
case $opt in
s) SIGN=1;;
f) P12_APP_FILE=$(realpath "$OPTARG");;
i) P12_INSTALL_FILE=$(realpath "$OPTARG");;
p) P12_PASSWORD="$OPTARG";;
e) ENTITLEMENTS_FILE=$(realpath "$OPTARG");;
n) NOTARIZE=1;;
j) API_KEY_FILE=$(realpath "$OPTARG");;
\?) usage;;
esac
done
if [ -n "$SIGN" ] && ([ -z "$P12_APP_FILE" ] || [-z "$P12_INSTALL_FILE"] || [ -z "$P12_PASSWORD" ]); then
usage
fi
if [ -n "$NOTARIZE" ] && [ -z "$API_KEY_FILE" ]; then
usage
fi
VERSION=$(git describe --always --dirty 2>/dev/null)
if test -z "$VERSION" ; then
echo "Could not get version from git"
if test -f version; then
VERSION=$(cat version)
fi
fi
echo "Version is $VERSION"
PKGDIR=$(mktemp -d)
echo "$PKGDIR"
SRC_DIR=$PWD
OUTPUT_PATH=${FISH_ARTEFACT_PATH:-~/fish_built}
mkdir -p "$PKGDIR/build_x86_64" "$PKGDIR/build_arm64" "$PKGDIR/root" "$PKGDIR/intermediates" "$PKGDIR/dst"
# Build and install for arm64.
# Pass FISH_USE_SYSTEM_PCRE2=OFF because a system PCRE2 on macOS will not be signed by fish,
# and will probably not be built universal, so the package will fail to validate/run on other systems.
# Note CMAKE_OSX_ARCHITECTURES is still relevant for the Mac app.
{ cd "$PKGDIR/build_arm64" \
&& cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_EXE_LINKER_FLAGS="-Wl,-ld_classic" \
-DWITH_GETTEXT=OFF \
-DRust_CARGO_TARGET=aarch64-apple-darwin \
-DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' \
-DFISH_USE_SYSTEM_PCRE2=OFF \
"$SRC_DIR" \
&& env $ARM64_DEPLOY_TARGET make VERBOSE=1 -j 12 \
&& env DESTDIR="$PKGDIR/root/" $ARM64_DEPLOY_TARGET make install;
}
# Build for x86-64 but do not install; instead we will make some fat binaries inside the root.
# Set RUST_VERSION_X86_64 to the last version of Rust that supports macOS 10.9.
{ cd "$PKGDIR/build_x86_64" \
&& cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_EXE_LINKER_FLAGS="-Wl,-ld_classic" \
-DWITH_GETTEXT=OFF \
-DRust_TOOLCHAIN="$RUST_VERSION_X86_64" \
-DRust_CARGO_TARGET=x86_64-apple-darwin \
-DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' \
-DFISH_USE_SYSTEM_PCRE2=OFF "$SRC_DIR" \
&& env $X86_64_DEPLOY_TARGET make VERBOSE=1 -j 12; }
# Fatten them up.
for FILE in "$PKGDIR"/root/usr/local/bin/*; do
X86_FILE="$PKGDIR/build_x86_64/$(basename $FILE)"
rcodesign macho-universal-create --output "$FILE" "$FILE" "$X86_FILE"
chmod 755 "$FILE"
done
if test -n "$SIGN"; then
echo "Signing executables"
ARGS=(
--p12-file "$P12_APP_FILE"
--p12-password "$P12_PASSWORD"
--code-signature-flags runtime
--for-notarization
)
if [ -n "$ENTITLEMENTS_FILE" ]; then
ARGS+=(--entitlements-xml-file "$ENTITLEMENTS_FILE")
fi
for FILE in "$PKGDIR"/root/usr/local/bin/*; do
(set +x; rcodesign sign "${ARGS[@]}" "$FILE")
done
fi
pkgbuild --scripts "$SRC_DIR/build_tools/osx_package_scripts" --root "$PKGDIR/root/" --identifier 'com.ridiculousfish.fish-shell-pkg' --version "$VERSION" "$PKGDIR/intermediates/fish.pkg"
productbuild --package-path "$PKGDIR/intermediates" --distribution "$SRC_DIR/build_tools/osx_distribution.xml" --resources "$SRC_DIR/build_tools/osx_package_resources/" "$OUTPUT_PATH/fish-$VERSION.pkg"
if test -n "$SIGN"; then
echo "Signing installer"
ARGS=(
--p12-file "$P12_INSTALL_FILE"
--p12-password "$P12_PASSWORD"
--code-signature-flags runtime
--for-notarization
)
(set +x; rcodesign sign "${ARGS[@]}" "$OUTPUT_PATH/fish-$VERSION.pkg")
fi
# Make the app
(cd "$PKGDIR/build_arm64" && env $ARM64_DEPLOY_TARGET make -j 12 fish_macapp)
(cd "$PKGDIR/build_x86_64" && env $X86_64_DEPLOY_TARGET make -j 12 fish_macapp)
# Make the app's /usr/local/bin binaries universal. Note fish.app/Contents/MacOS/fish already is, courtesy of CMake.
cd "$PKGDIR/build_arm64"
for FILE in fish.app/Contents/Resources/base/usr/local/bin/*; do
X86_FILE="$PKGDIR/build_x86_64/fish.app/Contents/Resources/base/usr/local/bin/$(basename $FILE)"
rcodesign macho-universal-create --output "$FILE" "$FILE" "$X86_FILE"
# macho-universal-create screws up the permissions.
chmod 755 "$FILE"
done
if test -n "$SIGN"; then
echo "Signing app"
ARGS=(
--p12-file "$P12_APP_FILE"
--p12-password "$P12_PASSWORD"
--code-signature-flags runtime
--for-notarization
)
if [ -n "$ENTITLEMENTS_FILE" ]; then
ARGS+=(--entitlements-xml-file "$ENTITLEMENTS_FILE")
fi
(set +x; rcodesign sign "${ARGS[@]}" "fish.app")
fi
cp -R "fish.app" "$OUTPUT_PATH/fish-$VERSION.app"
cd "$OUTPUT_PATH"
# Maybe notarize.
if test -n "$NOTARIZE"; then
echo "Notarizing"
rcodesign notarize --staple --wait --max-wait-seconds 1800 --api-key-file "$API_KEY_FILE" "$OUTPUT_PATH/fish-$VERSION.pkg"
rcodesign notarize --staple --wait --max-wait-seconds 1800 --api-key-file "$API_KEY_FILE" "$OUTPUT_PATH/fish-$VERSION.app"
fi
# Zip it up.
zip -r "fish-$VERSION.app.zip" "fish-$VERSION.app" && rm -Rf "fish-$VERSION.app"
rm -rf "$PKGDIR"

1
build_tools/make_pkg.sh Symbolic link
View File

@@ -0,0 +1 @@
make_macos_pkg.sh

View File

@@ -9,38 +9,38 @@
# Exit on error
set -e
# We wil generate a tarball with a prefix "fish-VERSION"
# We will generate a tarball with a prefix "fish-VERSION"
# git can do that automatically for us via git-archive
# but to get the documentation in, we need to make a symlink called "fish-VERSION"
# and tar from that, so that the documentation gets the right prefix
# Use Ninja if available, as it automatically paralellises
# Use Ninja if available, as it automatically parallelises
BUILD_TOOL="make"
BUILD_GENERATOR="Unix Makefiles"
if command -v ninja >/dev/null; then
BUILD_TOOL="ninja"
BUILD_GENERATOR="Ninja"
BUILD_TOOL="ninja"
BUILD_GENERATOR="Ninja"
fi
# We need GNU tar as that supports the --mtime and --transform options
TAR=notfound
for try in tar gtar gnutar; do
if $try -Pcf /dev/null --mtime now /dev/null >/dev/null 2>&1; then
TAR=$try
break
fi
if $try -Pcf /dev/null --mtime now /dev/null >/dev/null 2>&1; then
TAR=$try
break
fi
done
if [ "$TAR" = "notfound" ]; then
echo 'No suitable tar (supporting --mtime) found as tar/gtar/gnutar in PATH'
exit 1
echo 'No suitable tar (supporting --mtime) found as tar/gtar/gnutar in PATH'
exit 1
fi
# Get the current directory, which we'll use for symlinks
wd="$PWD"
# Get the version from git-describe
VERSION=$(git describe --dirty 2>/dev/null)
# Get the version
VERSION=$(build_tools/git_version_gen.sh --stdout 2>/dev/null)
# The name of the prefix, which is the directory that you get when you untar
prefix="fish-$VERSION"
@@ -59,11 +59,11 @@ git archive --format=tar --prefix="$prefix"/ HEAD > "$path"
PREFIX_TMPDIR=$(mktemp -d)
cd "$PREFIX_TMPDIR"
echo "$VERSION" > version
cmake -G "$BUILD_GENERATOR" "$wd"
cmake -G "$BUILD_GENERATOR" -DCMAKE_BUILD_TYPE=Debug "$wd"
$BUILD_TOOL doc
TAR_APPEND="$TAR --append --file=$path --mtime=now --owner=0 --group=0 \
--mode=g+w,a+rX --transform s/^/$prefix\//"
--mode=g+w,a+rX --transform s/^/$prefix\//"
$TAR_APPEND --no-recursion user_doc
$TAR_APPEND user_doc/html user_doc/man
$TAR_APPEND version

View File

@@ -11,22 +11,22 @@ set -e
# We need GNU tar as that supports the --mtime and --transform options
TAR=notfound
for try in tar gtar gnutar; do
if $try -Pcf /dev/null --mtime now /dev/null >/dev/null 2>&1; then
TAR=$try
break
fi
if $try -Pcf /dev/null --mtime now /dev/null >/dev/null 2>&1; then
TAR=$try
break
fi
done
if [ "$TAR" = "notfound" ]; then
echo 'No suitable tar (supporting --mtime) found as tar/gtar/gnutar in PATH'
exit 1
echo 'No suitable tar (supporting --mtime) found as tar/gtar/gnutar in PATH'
exit 1
fi
# Get the current directory, which we'll use for telling Cargo where to find the sources
wd="$PWD"
# Get the version from git-describe
VERSION=$(git describe --dirty 2>/dev/null)
VERSION=$(build_tools/git_version_gen.sh --stdout 2>/dev/null)
# The name of the prefix, which is the directory that you get when you untar
prefix="fish-$VERSION"
@@ -45,7 +45,7 @@ cd "$PREFIX_TMPDIR"
mkdir .cargo
cargo vendor --manifest-path "$wd/Cargo.toml" > .cargo/config.toml
tar cfvJ $path.xz vendor .cargo
tar cfvJ "$path".xz vendor .cargo
cd -
rm -r "$PREFIX_TMPDIR"

View File

@@ -8,7 +8,6 @@
code, tt {
font-family: ui-monospace, Menlo, monospace;
}
</style>
</head>
<body>

View File

@@ -4,12 +4,12 @@
if test $# -eq 0
then
echo usage: $0 shellname [shellname ...]
echo "usage: $0 shellname [shellname ...]"
exit 1
fi
scriptname=`basename "$0"`
if [[ $UID -ne 0 ]]; then
scriptname=$(basename "$0")
if [ "$(id -u)" -ne 0 ]; then
echo "${scriptname} must be run as root"
exit 1
fi
@@ -20,6 +20,7 @@ tmpfile=${file}.tmp
set -o noclobber
# shellcheck disable=SC2064
trap "rm -f $tmpfile" EXIT
if ! cat $file > $tmpfile
@@ -32,15 +33,13 @@ EOF
fi
# Append a newline if it doesn't exist
if [ "$(tail -c1 "$tmpfile"; echo x)" != $'\nx' ]; then
echo "" >> "$tmpfile"
fi
[ -z "$(tail -c1 "$tmpfile")" ] || echo "" >> "$tmpfile"
for i
do
if ! grep -q "^${i}$" "$tmpfile"
then
echo $i >> "$tmpfile"
echo "$i" >> "$tmpfile"
fi
done

View File

@@ -1,3 +1,3 @@
#!/bin/sh -x
./add-shell ${DSTVOLUME}usr/local/bin/fish
./add-shell "${DSTVOLUME}"usr/local/bin/fish

View File

@@ -1,7 +1,7 @@
#!/bin/sh -x
echo "Removing any previous installation"
pkgutil --pkg-info ${INSTALL_PKG_SESSION_ID} && pkgutil --only-files --files ${INSTALL_PKG_SESSION_ID} | while read installed
do rm -v ${DSTVOLUME}${installed}
pkgutil --pkg-info "${INSTALL_PKG_SESSION_ID}" && pkgutil --only-files --files "${INSTALL_PKG_SESSION_ID}" | while read -r installed
do rm -v "${DSTVOLUME}${installed}"
done
echo "... removed"

104
build_tools/release-notes.sh Executable file
View File

@@ -0,0 +1,104 @@
#!/bin/sh
set -e
workspace_root=$(dirname "$0")/..
relnotes_tmp=$(mktemp -d)
mkdir -p "$relnotes_tmp/fake-workspace" "$relnotes_tmp/out"
(
cd "$workspace_root"
cp -r doc_src CONTRIBUTING.rst README.rst "$relnotes_tmp/fake-workspace"
)
version=$(sed 's,^fish \(\S*\) .*,\1,; 1q' "$workspace_root/CHANGELOG.rst")
previous_version=$(
cd "$workspace_root"
awk <CHANGELOG.rst '
( /^fish \S*\.\S*\.\S* \(released .*\)$/ &&
NR > 1 &&
# Skip tags that have not been created yet..
system("git rev-parse --verify >/dev/null --quiet refs/tags/"$2) == 0 \
) {
print $2; ok = 1; exit
}
END { exit !ok }
'
)
minor_version=${version%.*}
previous_minor_version=${previous_version%.*}
{
sed -n 1,2p <"$workspace_root/CHANGELOG.rst"
ListCommitters() {
comm "$@" "$relnotes_tmp/committers-then" "$relnotes_tmp/committers-now"
}
(
cd "$workspace_root"
git log "$previous_version" --format="%aN" | sort -u >"$relnotes_tmp/committers-then"
git log "$previous_version".. --format="%aN" | sort -u >"$relnotes_tmp/committers-now"
ListCommitters -13 >"$relnotes_tmp/committers-new"
ListCommitters -12 >"$relnotes_tmp/committers-returning"
)
if [ "$minor_version" != "$previous_minor_version" ]; then
(
cd "$workspace_root"
num_commits=$(git log --no-merges --format=%H "$previous_version".. | wc -l)
num_authors=$(wc -l <"$relnotes_tmp/committers-now")
num_new_authors=$(wc -l <"$relnotes_tmp/committers-new")
printf %s \
"This release comprises $num_commits commits since $previous_version," \
" contributed by $num_authors authors, $num_new_authors of which are new committers."
echo
echo
)
fi
printf '%s\n' "$(awk <"$workspace_root/CHANGELOG.rst" '
NR <= 2 || /^\.\. ignore / { next }
/^===/ { exit }
{ print }
' | sed '$d')" |
sed -e '$s/^----*$//' # Remove spurious transitions at the end of the document.
if [ "$minor_version" != "$previous_minor_version" ]; then {
JoinEscaped() {
sed 's/\S/\\&/g' |
awk '
NR != 1 { printf ",\n" }
{ printf "%s", $0 }
END { printf "\n" }
'
}
echo ""
echo "---"
echo ""
echo "Thanks to everyone who contributed through issue discussions, code reviews, or code changes."
echo
printf "Welcome our new committers: "
JoinEscaped <"$relnotes_tmp/committers-new"
echo
printf "Welcome back our returning committers: "
JoinEscaped <"$relnotes_tmp/committers-returning"
} fi
echo
echo "---"
echo
echo "*Download links: To download the source code for fish, we suggest the file named \"fish-$version.tar.xz\". The file downloaded from \"Source code (tar.gz)\" will not build correctly.*"
echo
echo "*The files called fish-$version-linux-\*.tar.xz are experimental packages containing a single standalone ``fish`` binary for any Linux with the given CPU architecture.*"
} >"$relnotes_tmp/fake-workspace"/CHANGELOG.rst
sphinx-build >&2 -j auto \
-W -E -b markdown -c "$workspace_root/doc_src" \
-d "$relnotes_tmp/doctree" "$relnotes_tmp/fake-workspace/doc_src" "$relnotes_tmp/out" \
-D markdown_http_base="https://fishshell.com/docs/$minor_version" \
-D markdown_uri_doc_suffix=".html" \
-D markdown_github_flavored=1 \
"$@"
# Skip changelog header
sed -n 1p "$relnotes_tmp/out/relnotes.md" | grep -Fxq "# Release notes"
sed -n 2p "$relnotes_tmp/out/relnotes.md" | grep -Fxq ''
sed 1,2d "$relnotes_tmp/out/relnotes.md"
rm -r "$relnotes_tmp"

253
build_tools/release.sh Executable file
View File

@@ -0,0 +1,253 @@
#!/bin/sh
{
set -ex
version=$1
repository_owner=fish-shell
remote=origin
if [ -n "$2" ]; then
set -u
repository_owner=$2
remote=$3
set +u
[ $# -eq 3 ]
fi
[ -n "$version" ]
for tool in \
bundle \
gh \
jq \
ruby \
timeout \
; do
if ! command -v "$tool" >/dev/null; then
echo >&2 "$0: missing command: $1"
exit 1
fi
done
repo_root="$(dirname "$0")/.."
fish_site=$repo_root/../fish-site
fish_site_repo=git@github.com:$repository_owner/fish-site
for path in . "$fish_site"
do
if ! git -C "$path" diff HEAD --quiet ||
git ls-files --others --exclude-standard | grep .; then
echo >&2 "$0: index and worktree must be clean"
exit 1
fi
done
(
cd "$fish_site"
[ "$(git rev-parse HEAD)" = \
"$(git ls-remote "$fish_site_repo" refs/heads/master |
awk '{print $1}')" ]
)
if git tag | grep -qxF "$version"; then
echo >&2 "$0: tag $version already exists"
exit 1
fi
integration_branch=$(
git for-each-ref --points-at=HEAD 'refs/heads/Integration_*' \
--format='%(refname:strip=2)'
)
[ -n "$integration_branch" ] ||
git merge-base --is-ancestor $remote/master HEAD
sed -n 1p CHANGELOG.rst | grep -q '^fish .*(released .*)$'
sed -n 2p CHANGELOG.rst | grep -q '^===*$'
changelog_title="fish $version (released $(date +'%B %d, %Y'))"
sed -i \
-e "1c$changelog_title" \
-e "2c$(printf %s "$changelog_title" | sed s/./=/g)" \
CHANGELOG.rst
CommitVersion() {
sed -i "s/^version = \".*\"/version = \"$1\"/g" Cargo.toml
cargo fetch --offline
git add CHANGELOG.rst Cargo.toml Cargo.lock
git commit -m "$2
Created by ./build_tools/release.sh $version"
}
CommitVersion "$version" "Release $version"
# N.B. this is not GPG-signed.
git tag --annotate --message="Release $version" $version
git push $remote $version
TIMEOUT=
gh() {
command ${TIMEOUT:+timeout $TIMEOUT} \
gh --repo "$repository_owner/fish-shell" "$@"
}
gh workflow run release.yml --ref="$version" \
--raw-field="version=$version"
run_id=
while [ -z "$run_id" ] && sleep 5
do
run_id=$(gh run list \
--json=databaseId --jq=.[].databaseId \
--workflow=release.yml --limit=1 \
--commit="$(git rev-parse "$version^{commit}")")
done
# Update fishshell.com
tag_oid=$(git rev-parse "$version")
tmpdir=$(mktemp -d)
# TODO This works on draft releases only if "gh" is configured to
# have write access to the fish-shell repository. Unless we are fine
# publishing the release at this point, we should at least fail if
# "gh" doesn't have write access.
while ! \
gh release download "$version" --dir="$tmpdir" \
--pattern="fish-$version.tar.xz"
do
TIMEOUT=30 gh run watch "$run_id" ||:
sleep 5
done
actual_tag_oid=$(git ls-remote "$remote" |
awk '$2 == "refs/tags/'"$version"'" { print $1 }')
[ "$tag_oid" = "$actual_tag_oid" ]
( cd "$tmpdir" && tar xf fish-$version.tar.xz )
CopyDocs() {
rm -rf "$fish_site/site/docs/$1"
cp -r "$tmpdir/fish-$version/user_doc/html" "$fish_site/site/docs/$1"
git -C $fish_site add "site/docs/$1"
}
minor_version=${version%.*}
CopyDocs "$minor_version"
latest_release=$(
releases=$(git tag | grep '^[0-9]*\.[0-9]*\.[0-9]*.*' |
sed $(: "De-prioritize release candidates (1.2.3-rc0)") \
's/-/~/g' | LC_ALL=C sort --version-sort)
printf %s\\n "$releases" | tail -1
)
if [ "$version" = "$latest_release" ]; then
CopyDocs current
fi
rm -rf "$tmpdir"
(
cd "$fish_site"
make
git add -u
git add docs
if git ls-files --others --exclude-standard | grep .; then
exit 1
fi
git commit --message="$(printf %s "\
| Release $version (docs)
|
| Created by ../fish-shell/build_tools/release.sh
" | sed 's,^\s*| \?,,')"
)
gh_api_repo() {
path=$1
shift
command gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/$repository_owner/fish-shell/$path" \
"$@"
}
# Approve macos-codesign
# TODO what if current user can't approve?
gh_pending_deployments() {
gh_api_repo "actions/runs/$run_id/pending_deployments" "$@"
}
while {
environment_id=$(gh_pending_deployments | jq .[].environment.id)
[ -z "$environment_id" ]
}
do
sleep 5
done
echo '
{
"environment_ids": ['"$environment_id"'],
"state": "approved",
"comment": "Approved via ./build_tools/release.sh"
}
' |
gh_pending_deployments --method POST --input=-
# Await completion.
gh run watch "$run_id"
while {
! draft=$(gh release view "$version" --json=isDraft --jq=.isDraft) \
|| [ "$draft" = true ]
}
do
sleep 20
done
(
cd "$fish_site"
make new-release
git add -u
git add docs
if git ls-files --others --exclude-standard | grep .; then
exit 1
fi
git commit --message="$(printf %s "\
| Release $version (release list update)
|
| Created by ../fish-shell/build_tools/release.sh
" | sed 's,^\s*| \?,,')"
# This takes care to support remote names that are different from
# fish-shell remote name. Also, support detached HEAD state.
git push "$fish_site_repo" HEAD:master
)
if [ -n "$integration_branch" ]; then {
git push $remote "$version^{commit}":refs/heads/$integration_branch
} else {
changelog=$(cat - CHANGELOG.rst <<EOF
fish ?.?.? (released ???)
=========================
EOF
)
printf %s\\n "$changelog" >CHANGELOG.rst
CommitVersion ${version}-snapshot "start new cycle"
git push $remote HEAD:master
} fi
milestone_number=$(
gh_api_repo milestones?state=open |
jq '.[] | select(.title == "fish '"$version"'") | .number'
)
gh_api_repo --method PATCH milestones/$milestone_number \
--raw-field state=closed
next_patch_version=$(
echo "$version" | awk -F. '
NF == 3 && $3 ~ /[0-9]+/ {
printf "%s.%s.%s", $1, $2, $3+1
}
'
)
if [ -n "$next_patch_version" ]; then
gh_api_repo --method POST milestones \
--raw-field title="fish $next_patch_version"
fi
exit
}

View File

@@ -1,38 +1,53 @@
#!/usr/bin/env fish
#
# This runs C++ files and fish scripts (*.fish) through their respective code
# formatting programs.
# This runs Python files, fish scripts (*.fish), and Rust files
# through their respective code formatting programs.
#
# `--all`: Format all eligible files instead of the ones specified as arguments.
# `--check`: Instead of reformatting, fail if a file is not formatted correctly.
# `--force`: Proceed without asking if uncommitted changes are detected.
# Only relevant if `--all` is specified but `--check` is not specified.
set -l fish_files
set -l python_files
set -l rust_files
set -l all no
if test "$argv[1]" = --all
argparse all check force -- $argv
or exit $status
if set -l -q _flag_all
set all yes
set -e argv[1]
if set -q argv[1]
echo "Unexpected arguments: '$argv'"
exit 1
end
end
if set -q argv[1]
echo "Unexpected arguments: '$argv'"
exit 1
end
set -l workspace_root (status dirname)/..
if test $all = yes
set -l files (git status --porcelain --short --untracked-files=all | sed -e 's/^ *[^ ]* *//')
if set -q files[1]
echo
echo 'You have uncommitted changes. Are you sure you want to restyle?'
read -P 'y/N? ' -n1 -l ans
if not string match -qi y -- $ans
exit 1
if not set -l -q _flag_force; and not set -l -q _flag_check
# Potential for false positives: Not all fish files are formatted, see the `fish_files`
# definition below.
set -l relevant_uncommitted_changes (git status --porcelain --short --untracked-files=all | sed -e 's/^ *[^ ]* *//' | grep -E '.*\.(fish|py|rs)$')
if set -q relevant_uncommitted_changes[1]
for changed_file in $relevant_uncommitted_changes
echo $changed_file
end
echo
echo 'You have uncommitted changes (listed above). Are you sure you want to restyle?'
read -P 'y/N? ' -n1 -l ans
if not string match -qi y -- $ans
exit 1
end
end
end
set fish_files share/**.fish
set fish_files $workspace_root/{benchmarks,build_tools,etc,share}/**.fish
set python_files {doc_src,share,tests}/**.py
set rust_files fish-rust/src/**.rs
else
# Extract just the fish files.
# Format the files specified as arguments.
set -l files $argv
set fish_files (string match -r '^.*\.fish$' -- $files)
set python_files (string match -r '^.*\.py$' -- $files)
set rust_files (string match -r '^.*\.rs$' -- $files)
@@ -40,37 +55,70 @@ end
set -l red (set_color red)
set -l green (set_color green)
set -l blue (set_color blue)
set -l yellow (set_color yellow)
set -l normal (set_color normal)
# Run the fish reformatter if we have any fish files.
if set -q fish_files[1]
if not type -q fish_indent
make fish_indent
set PATH . $PATH
echo
echo $yellow'Could not find `fish_indent` in `$PATH`.'$normal
exit 127
end
echo === Running "$green"fish_indent"$normal"
fish_indent -w -- $fish_files
if set -l -q _flag_check
if not fish_indent --check -- $fish_files
echo $red"Fish files are not formatted correctly."$normal
exit 1
end
else
fish_indent -w -- $fish_files
end
end
if set -q python_files[1]
if not type -q black
echo
echo Please install "`black`" to style python
echo
echo $yellow'Please install `black` to style python'$normal
exit 127
end
echo === Running "$green"black"$normal"
if set -l -q _flag_check
if not black --check $python_files
echo $red"Python files are not formatted correctly."$normal
exit 1
end
else
echo === Running "$blue"black"$normal"
black $python_files
end
end
if set -q rust_files[1]
if not type -q rustfmt
echo
echo Please install "`rustfmt`" to style rust
echo
if not cargo fmt --version >/dev/null
echo
echo $yellow'Please install "rustfmt" to style Rust, e.g. via:'
echo "rustup component add rustfmt"$normal
exit 127
end
echo === Running "$green"rustfmt"$normal"
if set -l -q _flag_check
if set -l -q _flag_all
if not cargo fmt --check
echo $red"Rust files are not formatted correctly."$normal
exit 1
end
else
echo === Running "$blue"rustfmt"$normal"
rustfmt $rust_files
if set -q rust_files[1]
if not rustfmt --check --files-with-diff $rust_files
echo $red"Rust files are not formatted correctly."
exit 1
end
end
end
else
if set -l -q _flag_all
cargo fmt
else
if set -q rust_files[1]
rustfmt $rust_files
end
end
end

View File

@@ -0,0 +1,165 @@
#!/usr/bin/env fish
# Updates the files used for gettext translations.
# By default, the whole xgettext + msgmerge pipeline runs,
# which extracts the messages from the source files into $template_file,
# and updates the PO files for each language from that.
#
# Use cases:
# For developers:
# - Run with no args to update all PO files after making changes to Rust/fish sources.
# For translators:
# - Specify the language you want to work on as an argument, which must be a file in the po/
# directory. You can specify a language which does not have translations yet by specifying the
# name of a file which does not yet exist. Make sure to follow the naming convention.
# For testing:
# - Specify `--dry-run` to see if any updates to the PO files would by applied by this script.
# If this flag is specified, the script will exit with an error if there are outstanding
# changes, and will display the diff. Do not specify other flags if `--dry-run` is specified.
#
# Specify `--use-existing-template=FILE` to prevent running cargo for extracting an up-to-date
# version of the localized strings. This flag is intended for testing setups which make it
# inconvenient to run cargo here, but run it in an earlier step to ensure up-to-date values.
# This argument is passed on to the `fish_xgettext.fish` script and has no other uses.
# `FILE` must be the path to a gettext template file generated from our compilation process.
# It can be obtained by running:
# set -l FILE (mktemp)
# FISH_GETTEXT_EXTRACTION_FILE=$FILE cargo check --features=gettext-extract
# The sort utility is locale-sensitive.
# Ensure that sorting output is consistent by setting LC_ALL here.
set -gx LC_ALL C.UTF-8
set -l build_tools (status dirname)
set -g tmpdir
set -l po_dir $build_tools/../po
set -l extract
set -l po
argparse dry-run use-existing-template= -- $argv
or exit $status
if test -z $argv[1]
# Update everything if not specified otherwise.
set -g po_files $po_dir/*.po
else
set -l po_dir_id (stat --format='%d:%i' -- $po_dir)
for arg in $argv
set -l arg_dir_id (stat --format='%d:%i' -- (dirname $arg))
if test $po_dir_id != $arg_dir_id
echo "Argument $arg is not a file in the directory $(realpath $po_dir)."
echo "Non-option arguments must specify paths to files in this directory."
echo ""
echo "If you want to add a new language to the translations not the following:"
echo "The filename must identify a language, with a two letter ISO 639-1 language code of the target language (e.g. 'pt' for Portuguese), and use the file extension '.po'."
echo "Optionally, you can specify a regional variant (e.g. 'pt_BR')."
echo "So valid filenames are of the shape 'll.po' or 'll_CC.po'."
exit 1
end
if not basename $arg | grep -qE '^[a-z]{2,3}(_[A-Z]{2})?\.po$'
echo "Filename does not match the expected format ('ll.po' or 'll_CC.po')."
exit 1
end
end
set -g po_files $argv
end
set -g template_file (mktemp)
# Protect from externally set $tmpdir leaking into this script.
set -g tmpdir
function cleanup_exit
set -l exit_status $status
rm $template_file
if set -g --query tmpdir[1]
rm -r $tmpdir
end
exit $exit_status
end
if set -l --query extract
set -l xgettext_args
if set -l --query _flag_use_existing_template
set xgettext_args --use-existing-template=$_flag_use_existing_template
end
$build_tools/fish_xgettext.fish $xgettext_args >$template_file
or cleanup_exit
end
if set -l --query _flag_dry_run
# On a dry run, we do not modify po/ but write to a temporary directory instead and check if
# there is a difference between po/ and the tmpdir after re-generating the PO files.
set -g tmpdir (mktemp -d)
# Ensure tmpdir has the same initial state as the po dir.
cp -r $po_dir/* $tmpdir
end
function merge_po_files --argument-names template_file po_file
msgmerge --no-wrap --update --no-fuzzy-matching --backup=none --quiet \
$po_file $template_file
or cleanup_exit
set -l new_po_file (mktemp) # TODO Remove on failure.
and msgattrib --no-wrap --no-obsolete -o $new_po_file $po_file
or cleanup_exit
begin
echo "# fish-note-sections: Translations are divided into sections, each starting with a fish-section-* comment."
echo "# fish-note-sections: The first few sections are more important."
echo "# fish-note-sections: Ignore the tier3 sections unless you have a lot of time."
sed -i '
/^# fish-note-sections:/d;
/^# fish-section-/d;
' $new_po_file
set -l next_line 1
set -l section
awk <$template_file '
/^# fish-section-\S*$/ {
section = $0
}
section != "" && /^msgid ".+"$/ {
print section
print $0
section = ""
}
' |
while read -l section
read -l msgid_line
set -l line_number (grep -m1 -Fxn $msgid_line $new_po_file | string split :)[1]
sed -n "$next_line,$(math $line_number - 1)"p $new_po_file
echo $section
set next_line $line_number
# set section
end
sed -n "$next_line,\$"p $new_po_file
end >$po_file
rm $new_po_file
end
for po_file in $po_files
if set --query tmpdir[1]
set po_file $tmpdir/(basename $po_file)
end
if set -l --query po
if test -e $po_file
merge_po_files $template_file $po_file
else
cp $template_file $po_file
end
end
end
if set -g --query tmpdir[1]
diff -ur $po_dir $tmpdir
or begin
echo ERROR: translations in ./po/ are stale. Try running build_tools/update_translations.fish
cleanup_exit
end
end
cleanup_exit

View File

@@ -29,7 +29,7 @@ add_custom_target(sphinx-docs
# sphinx-manpages needs the fish_indent binary for the version number
add_custom_target(sphinx-manpages
env FISH_BUILD_VERSION_FILE="${CMAKE_CURRENT_BINARY_DIR}/${FBVF}"
env FISH_BUILD_VERSION_FILE=${CMAKE_CURRENT_BINARY_DIR}/${FBVF}
${SPHINX_EXECUTABLE}
-j auto
-q -b man

View File

@@ -1,286 +1,18 @@
#[=======================================================================[.rst:
FindRust
--------
Find Rust
This module finds an installed rustc compiler and the cargo build tool. If Rust
is managed by rustup it determines the available toolchains and returns a
concrete Rust version, not a rustup proxy.
Imported from Corrosion https://github.com/corrosion-rs/corrosion/
Copyright (c) 2018 Andrew Gaspar
Licensed under the MIT license
However this is absolutely gutted and reduced to the bare minimum.
#]=======================================================================]
include(FindPackageHandleStandardArgs)
cmake_minimum_required(VERSION 3.12)
# search for Cargo here and set up a bunch of cool flags and stuff
include(FindPackageHandleStandardArgs)
list(APPEND CMAKE_MESSAGE_CONTEXT "FindRust")
# Print error message and return.
macro(_findrust_failed)
if("${Rust_FIND_REQUIRED}")
message(FATAL_ERROR ${ARGN})
elseif(NOT "${Rust_FIND_QUIETLY}")
message(WARNING ${ARGN})
endif()
# Note: PARENT_SCOPE is the scope of the caller of the caller of this macro.
set(Rust_FOUND "" PARENT_SCOPE)
return()
endmacro()
# Checks if the actual version of a Rust toolchain matches the VERSION requirements specified in find_package.
function(_findrust_version_ok ACTUAL_VERSION OUT_IS_OK)
if(DEFINED Rust_FIND_VERSION_RANGE)
if(Rust_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE")
set(COMPARSION_OPERATOR "VERSION_LESS_EQUAL")
elseif(Rust_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE")
set(COMPARSION_OPERATOR "VERSION_LESS")
else()
message(FATAL_ERROR "Unexpected value in `<PackageName>_FIND_VERSION_RANGE_MAX`: "
"`${Rust_FIND_VERSION_RANGE_MAX}`.")
endif()
if(("${ACTUAL_VERSION}" VERSION_GREATER_EQUAL "${Rust_FIND_VERSION_RANGE_MIN}")
AND
( "${ACTUAL_VERSION}" ${COMPARSION_OPERATOR} "${Rust_FIND_VERSION_RANGE_MAX}" )
)
set("${OUT_IS_OK}" TRUE PARENT_SCOPE)
else()
set("${OUT_IS_OK}" FALSE PARENT_SCOPE)
endif()
elseif(DEFINED Rust_FIND_VERSION)
if(Rust_VERSION_EXACT)
set(COMPARISON_OPERATOR VERSION_EQUAL)
else()
set(COMPARISON_OPERATOR VERSION_GREATER_EQUAL)
endif()
if(_TOOLCHAIN_${_TOOLCHAIN_SELECTED}_VERSION "${COMPARISON_OPERATOR}" Rust_FIND_VERSION)
set("${OUT_IS_OK}" TRUE PARENT_SCOPE)
else()
set("${OUT_IS_OK}" FALSE PARENT_SCOPE)
endif()
else()
# if no VERSION requirement was specified, the version is always okay.
set("${OUT_IS_OK}" TRUE PARENT_SCOPE)
endif()
endfunction()
function(_corrosion_strip_target_triple input_triple_or_path output_triple)
# If the target_triple is a path to a custom target specification file, then strip everything
# except the filename from `target_triple`.
get_filename_component(target_triple_ext "${input_triple_or_path}" EXT)
set(target_triple "${input_triple_or_path}")
if(target_triple_ext)
if(target_triple_ext STREQUAL ".json")
get_filename_component(target_triple "${input_triple_or_path}" NAME_WE)
endif()
endif()
set(${output_triple} "${target_triple}" PARENT_SCOPE)
endfunction()
function(_corrosion_parse_target_triple target_triple out_arch out_vendor out_os out_env)
_corrosion_strip_target_triple(${target_triple} target_triple)
# The vendor part may be left out from the target triple, and since `env` is also optional,
# we determine if vendor is present by matching against a list of known vendors.
set(known_vendors
"apple"
"esp[a-z0-9]*" # espressif, e.g. riscv32imc-esp-espidf or xtensa-esp32s3-none-elf
"fortanix"
"kmc"
"pc"
"nintendo"
"nvidia"
"openwrt"
"alpine"
"chimera"
"unikraft"
"unknown"
"uwp" # aarch64-uwp-windows-msvc
"wrs" # e.g. aarch64-wrs-vxworks
"sony"
"sun"
)
# todo: allow users to add additional vendors to the list via a cmake variable.
list(JOIN known_vendors "|" known_vendors_joined)
# vendor is optional - We detect if vendor is present by matching against a known list of
# vendors. The next field is the OS, which we assume to always be present, while the last field
# is again optional and contains the environment.
string(REGEX MATCH
"^([a-z0-9_\.]+)-((${known_vendors_joined})-)?([a-z0-9_]+)(-([a-z0-9_]+))?$"
whole_match
"${target_triple}"
)
if((NOT whole_match) AND (NOT CORROSION_NO_WARN_PARSE_TARGET_TRIPLE_FAILED))
message(WARNING "Failed to parse target-triple `${target_triple}`."
"Corrosion determines some information about the output artifacts based on OS "
"specified in the Rust target-triple.\n"
"Currently this is relevant for windows and darwin (mac) targets, since file "
"extensions differ.\n"
"Note: If you are targeting a different OS you can suppress this warning by"
" setting the CMake cache variable "
"`CORROSION_NO_WARN_PARSE_TARGET_TRIPLE_FAILED`."
"Please consider opening an issue on github if you you need to add a new vendor to the list."
)
endif()
message(DEBUG "Parsed Target triple: arch: ${CMAKE_MATCH_1}, vendor: ${CMAKE_MATCH_3}, "
"OS: ${CMAKE_MATCH_4}, env: ${CMAKE_MATCH_6}")
set("${out_arch}" "${CMAKE_MATCH_1}" PARENT_SCOPE)
set("${out_vendor}" "${CMAKE_MATCH_3}" PARENT_SCOPE)
set("${out_os}" "${CMAKE_MATCH_4}" PARENT_SCOPE)
set("${out_env}" "${CMAKE_MATCH_6}" PARENT_SCOPE)
endfunction()
function(_corrosion_determine_libs_new target_triple out_libs)
set(package_dir "${CMAKE_BINARY_DIR}/corrosion/required_libs")
# Cleanup on reconfigure to get a cleans state (in case we change something in the future)
file(REMOVE_RECURSE "${package_dir}")
file(MAKE_DIRECTORY "${package_dir}")
set(manifest "[package]\nname = \"required_libs\"\nedition = \"2018\"\nversion = \"0.1.0\"\n")
string(APPEND manifest "\n[lib]\ncrate-type=[\"staticlib\"]\npath = \"lib.rs\"\n")
string(APPEND manifest "\n[workspace]\n")
file(WRITE "${package_dir}/Cargo.toml" "${manifest}")
file(WRITE "${package_dir}/lib.rs" "pub fn add(left: usize, right: usize) -> usize {left + right}\n")
execute_process(
COMMAND ${CMAKE_COMMAND} -E env
"CARGO_BUILD_RUSTC=${Rust_COMPILER_CACHED}"
${Rust_CARGO_CACHED} rustc --verbose --color never --target=${target_triple} -- --print=native-static-libs
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/corrosion/required_libs"
RESULT_VARIABLE cargo_build_result
ERROR_VARIABLE cargo_build_error_message
)
if(cargo_build_result)
message(DEBUG "Determining required native libraries - failed: ${cargo_build_result}.")
message(TRACE "The cargo build error was: ${cargo_build_error_message}")
message(DEBUG "Note: This is expected for Rust targets without std support")
return()
else()
# The pattern starts with `native-static-libs:` and goes to the end of the line.
if(cargo_build_error_message MATCHES "native-static-libs: ([^\r\n]+)\r?\n")
string(REPLACE " " ";" "libs_list" "${CMAKE_MATCH_1}")
set(stripped_lib_list "")
set(was_last_framework OFF)
foreach(lib ${libs_list})
# merge -framework;lib -> "-framework lib" as CMake does de-duplication of link libraries, and -framework prefix is required
if (lib STREQUAL "-framework")
set(was_last_framework ON)
continue()
endif()
if (was_last_framework)
list(APPEND stripped_lib_list "-framework ${lib}")
set(was_last_framework OFF)
continue()
endif()
# Strip leading `-l` (unix) and potential .lib suffix (windows)
string(REGEX REPLACE "^-l" "" "stripped_lib" "${lib}")
string(REGEX REPLACE "\.lib$" "" "stripped_lib" "${stripped_lib}")
list(APPEND stripped_lib_list "${stripped_lib}")
endforeach()
set(libs_list "${stripped_lib_list}")
# Special case `msvcrt` to link with the debug version in Debug mode.
list(TRANSFORM libs_list REPLACE "^msvcrt$" "\$<\$<CONFIG:Debug>:msvcrtd>")
else()
message(DEBUG "Determining required native libraries - failed: Regex match failure.")
message(DEBUG "`native-static-libs` not found in: `${cargo_build_error_message}`")
return()
endif()
endif()
set("${out_libs}" "${libs_list}" PARENT_SCOPE)
endfunction()
if (NOT "${Rust_TOOLCHAIN}" STREQUAL "$CACHE{Rust_TOOLCHAIN}")
# Promote Rust_TOOLCHAIN to a cache variable if it is not already a cache variable
set(Rust_TOOLCHAIN ${Rust_TOOLCHAIN} CACHE STRING "Requested rustup toolchain" FORCE)
endif()
set(_RESOLVE_RUSTUP_TOOLCHAINS_DESC "Indicates whether to descend into the toolchain pointed to by rustup")
set(Rust_RESOLVE_RUSTUP_TOOLCHAINS ON CACHE BOOL ${_RESOLVE_RUSTUP_TOOLCHAINS_DESC})
# This block checks to see if we're prioritizing a rustup-managed toolchain.
if (DEFINED Rust_TOOLCHAIN)
# If the user specifies `Rust_TOOLCHAIN`, then look for `rustup` first, rather than `rustc`.
find_program(Rust_RUSTUP rustup PATHS "$ENV{HOME}/.cargo/bin")
if(NOT Rust_RUSTUP)
if(NOT "${Rust_FIND_QUIETLY}")
message(
WARNING "CMake variable `Rust_TOOLCHAIN` specified, but `rustup` was not found. "
"Ignoring toolchain and looking for a Rust toolchain not managed by rustup.")
endif()
endif()
else()
# If we aren't definitely using a rustup toolchain, look for rustc first - the user may have
# a toolchain installed via a method other than rustup higher in the PATH, which should be
# preferred. However, if the first-found rustc is a rustup proxy, then we'll revert to
# finding the preferred toolchain via rustup.
# Uses `Rust_COMPILER` to let user-specified `rustc` win. But we will still "override" the
# user's setting if it is pointing to `rustup`. Default rustup install path is provided as a
# backup if a toolchain cannot be found in the user's PATH.
if (DEFINED Rust_COMPILER)
set(_Rust_COMPILER_TEST "${Rust_COMPILER}")
set(_USER_SPECIFIED_RUSTC ON)
if(NOT (EXISTS "${_Rust_COMPILER_TEST}" AND NOT IS_DIRECTORY "${_Rust_COMPILER_TEST}"))
set(_ERROR_MESSAGE "Rust_COMPILER was set to `${Rust_COMPILER}`, but this file does "
"not exist."
)
_findrust_failed(${_ERROR_MESSAGE})
return()
endif()
else()
find_program(_Rust_COMPILER_TEST rustc PATHS "$ENV{HOME}/.cargo/bin")
if(NOT EXISTS "${_Rust_COMPILER_TEST}")
set(_ERROR_MESSAGE "`rustc` not found in PATH or `$ENV{HOME}/.cargo/bin`.\n"
"Hint: Check if `rustc` is in PATH or manually specify the location "
"by setting `Rust_COMPILER` to the path to `rustc`.")
_findrust_failed(${_ERROR_MESSAGE})
endif()
endif()
# Check if the discovered rustc is actually a "rustup" proxy.
execute_process(
COMMAND
${CMAKE_COMMAND} -E env
RUSTUP_FORCE_ARG0=rustup
"${_Rust_COMPILER_TEST}" --version
OUTPUT_VARIABLE _RUSTC_VERSION_RAW
ERROR_VARIABLE _RUSTC_VERSION_STDERR
RESULT_VARIABLE _RUSTC_VERSION_RESULT
)
if(NOT (_RUSTC_VERSION_RESULT EQUAL "0"))
_findrust_failed("`${_Rust_COMPILER_TEST} --version` failed with ${_RUSTC_VERSION_RESULT}\n"
"rustc stderr:\n${_RUSTC_VERSION_STDERR}"
)
endif()
if (_RUSTC_VERSION_RAW MATCHES "rustup [0-9\\.]+")
# Get `rustup` next to the `rustc` proxy
get_filename_component(_RUST_PROXIES_PATH "${_Rust_COMPILER_TEST}" DIRECTORY)
find_program(Rust_RUSTUP rustup HINTS "${_RUST_PROXIES_PATH}" NO_DEFAULT_PATH)
endif()
unset(_Rust_COMPILER_TEST CACHE)
endif()
# At this point, the only thing we should have evaluated is a path to `rustup` _if that's what the
# best source for a Rust toolchain was determined to be_.
if (NOT Rust_RUSTUP)
set(Rust_RESOLVE_RUSTUP_TOOLCHAINS OFF CACHE BOOL ${_RESOLVE_RUSTUP_TOOLCHAINS_DESC} FORCE)
endif()
# List of user variables that will override any toolchain-provided setting
set(_Rust_USER_VARS Rust_COMPILER Rust_CARGO Rust_CARGO_TARGET Rust_CARGO_HOST_TARGET)
set(_Rust_USER_VARS Rust_COMPILER Rust_CARGO Rust_CARGO_TARGET)
foreach(_VAR ${_Rust_USER_VARS})
if (DEFINED "${_VAR}")
set(${_VAR}_CACHED "${${_VAR}}" CACHE INTERNAL "Internal cache of ${_VAR}")
@@ -289,482 +21,55 @@ foreach(_VAR ${_Rust_USER_VARS})
endif()
endforeach()
# Discover what toolchains are installed by rustup, if the discovered `rustc` is a proxy from
# `rustup` and the user hasn't explicitly requested to override this behavior, then select either
# the default toolchain, or the requested toolchain Rust_TOOLCHAIN
if (Rust_RESOLVE_RUSTUP_TOOLCHAINS)
execute_process(
COMMAND
"${Rust_RUSTUP}" toolchain list --verbose
OUTPUT_VARIABLE _TOOLCHAINS_RAW
)
string(REPLACE "\n" ";" _TOOLCHAINS_RAW "${_TOOLCHAINS_RAW}")
set(_DISCOVERED_TOOLCHAINS "")
set(_DISCOVERED_TOOLCHAINS_RUSTC_PATH "")
set(_DISCOVERED_TOOLCHAINS_CARGO_PATH "")
set(_DISCOVERED_TOOLCHAINS_VERSION "")
foreach(_TOOLCHAIN_RAW ${_TOOLCHAINS_RAW})
if (_TOOLCHAIN_RAW MATCHES "([a-zA-Z0-9\\._\\-]+)[ \t\r\n]?(\\(default\\) \\(override\\)|\\(default\\)|\\(override\\))?[ \t\r\n]+(.+)")
set(_TOOLCHAIN "${CMAKE_MATCH_1}")
set(_TOOLCHAIN_TYPE "${CMAKE_MATCH_2}")
set(_TOOLCHAIN_PATH "${CMAKE_MATCH_3}")
set(_TOOLCHAIN_${_TOOLCHAIN}_PATH "${CMAKE_MATCH_3}")
if (_TOOLCHAIN_TYPE MATCHES ".*\\(default\\).*")
set(_TOOLCHAIN_DEFAULT "${_TOOLCHAIN}")
endif()
if (_TOOLCHAIN_TYPE MATCHES ".*\\(override\\).*")
set(_TOOLCHAIN_OVERRIDE "${_TOOLCHAIN}")
endif()
execute_process(
COMMAND
"${_TOOLCHAIN_PATH}/bin/rustc" --version
OUTPUT_VARIABLE _TOOLCHAIN_RAW_VERSION
)
if (_TOOLCHAIN_RAW_VERSION MATCHES "rustc ([0-9]+)\\.([0-9]+)\\.([0-9]+)(-nightly)?")
list(APPEND _DISCOVERED_TOOLCHAINS "${_TOOLCHAIN}")
list(APPEND _DISCOVERED_TOOLCHAINS_RUSTC_PATH "${_TOOLCHAIN_PATH}/bin/rustc")
list(APPEND _DISCOVERED_TOOLCHAINS_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
# We need this variable to determine the default toolchain, since `foreach(... IN ZIP_LISTS ...)`
# requires CMake 3.17. As a workaround we define this variable to lookup the version when iterating
# through the `_DISCOVERED_TOOLCHAINS` lists.
set(_TOOLCHAIN_${_TOOLCHAIN}_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
if(CMAKE_MATCH_4)
set(_TOOLCHAIN_${_TOOLCHAIN}_IS_NIGHTLY "TRUE")
else()
set(_TOOLCHAIN_${_TOOLCHAIN}_IS_NIGHTLY "FALSE")
endif()
if(EXISTS "${_TOOLCHAIN_PATH}/bin/cargo")
list(APPEND _DISCOVERED_TOOLCHAINS_CARGO_PATH "${_TOOLCHAIN_PATH}/bin/cargo")
else()
list(APPEND _DISCOVERED_TOOLCHAINS_CARGO_PATH "NOTFOUND")
endif()
else()
message(AUTHOR_WARNING "Unexpected output from `rustc --version` for Toolchain `${_TOOLCHAIN}`: "
"`${_TOOLCHAIN_RAW_VERSION}`.\n"
"Ignoring this toolchain."
)
endif()
else()
message(AUTHOR_WARNING "Didn't recognize toolchain: ${_TOOLCHAIN_RAW}. Ignoring this toolchain.\n"
"Rustup toolchain list output( `${Rust_RUSTUP} toolchain list --verbose`):\n"
"${_TOOLCHAINS_RAW}"
)
endif()
endforeach()
# Expose a list of available rustup toolchains.
list(LENGTH _DISCOVERED_TOOLCHAINS _toolchain_len)
list(LENGTH _DISCOVERED_TOOLCHAINS_RUSTC_PATH _toolchain_rustc_len)
list(LENGTH _DISCOVERED_TOOLCHAINS_CARGO_PATH _toolchain_cargo_len)
list(LENGTH _DISCOVERED_TOOLCHAINS_VERSION _toolchain_version_len)
if(NOT
(_toolchain_len EQUAL _toolchain_rustc_len
AND _toolchain_cargo_len EQUAL _toolchain_version_len
AND _toolchain_len EQUAL _toolchain_cargo_len)
)
message(FATAL_ERROR "Internal error - list length mismatch."
"List lengths: ${_toolchain_len} toolchains, ${_toolchain_rustc_len} rustc, ${_toolchain_cargo_len} cargo,"
" ${_toolchain_version_len} version. The lengths should be the same."
)
endif()
set(Rust_RUSTUP_TOOLCHAINS CACHE INTERNAL "List of available Rustup toolchains" "${_DISCOVERED_TOOLCHAINS}")
set(Rust_RUSTUP_TOOLCHAINS_RUSTC_PATH
CACHE INTERNAL
"List of the rustc paths corresponding to the toolchain at the same index in `Rust_RUSTUP_TOOLCHAINS`."
"${_DISCOVERED_TOOLCHAINS_RUSTC_PATH}"
)
set(Rust_RUSTUP_TOOLCHAINS_CARGO_PATH
CACHE INTERNAL
"List of the cargo paths corresponding to the toolchain at the same index in `Rust_RUSTUP_TOOLCHAINS`. \
May also be `NOTFOUND` if the toolchain does not have a cargo executable."
"${_DISCOVERED_TOOLCHAINS_CARGO_PATH}"
)
set(Rust_RUSTUP_TOOLCHAINS_VERSION
CACHE INTERNAL
"List of the rust toolchain version corresponding to the toolchain at the same index in \
`Rust_RUSTUP_TOOLCHAINS`."
"${_DISCOVERED_TOOLCHAINS_VERSION}"
)
# Rust_TOOLCHAIN is preferred over a requested version if it is set.
if (NOT DEFINED Rust_TOOLCHAIN)
if (NOT DEFINED _TOOLCHAIN_OVERRIDE)
set(_TOOLCHAIN_SELECTED "${_TOOLCHAIN_DEFAULT}")
else()
set(_TOOLCHAIN_SELECTED "${_TOOLCHAIN_OVERRIDE}")
endif()
# Check default toolchain first.
_findrust_version_ok("_TOOLCHAIN_${_TOOLCHAIN_SELECTED}_VERSION" _VERSION_OK)
if(NOT "${_VERSION_OK}")
foreach(_TOOLCHAIN "${_DISCOVERED_TOOLCHAINS}")
_findrust_version_ok("_TOOLCHAIN_${_TOOLCHAIN}_VERSION" _VERSION_OK)
if("${_VERSION_OK}")
set(_TOOLCHAIN_SELECTED "${_TOOLCHAIN}")
break()
endif()
endforeach()
# Check if we found a suitable version in the for loop.
if(NOT "${_VERSION_OK}")
string(REPLACE ";" "\n" _DISCOVERED_TOOLCHAINS "${_DISCOVERED_TOOLCHAINS}")
_findrust_failed("Failed to find a Rust toolchain matching the version requirements of "
"${Rust_FIND_VERSION}. Available toolchains: ${_DISCOVERED_TOOLCHAINS}")
endif()
endif()
endif()
set(Rust_TOOLCHAIN "${_TOOLCHAIN_SELECTED}" CACHE STRING "The rustup toolchain to use")
set_property(CACHE Rust_TOOLCHAIN PROPERTY STRINGS "${_DISCOVERED_TOOLCHAINS}")
if(NOT Rust_FIND_QUIETLY)
message(STATUS "Rust Toolchain: ${Rust_TOOLCHAIN}")
endif()
if (NOT Rust_TOOLCHAIN IN_LIST _DISCOVERED_TOOLCHAINS)
# If the precise toolchain wasn't found, try appending the default host
execute_process(
COMMAND
"${Rust_RUSTUP}" show
RESULT_VARIABLE _SHOW_RESULT
OUTPUT_VARIABLE _SHOW_RAW
)
if(NOT "${_SHOW_RESULT}" EQUAL "0")
_findrust_failed("Command `${Rust_RUSTUP} show` failed")
endif()
if (_SHOW_RAW MATCHES "Default host: ([a-zA-Z0-9_\\-]*)\n")
set(_DEFAULT_HOST "${CMAKE_MATCH_1}")
else()
_findrust_failed("Failed to parse \"Default host\" from `${Rust_RUSTUP} show`. Got: ${_SHOW_RAW}")
endif()
if (NOT "${Rust_TOOLCHAIN}-${_DEFAULT_HOST}" IN_LIST _DISCOVERED_TOOLCHAINS)
set(_NOT_FOUND_MESSAGE "Could not find toolchain '${Rust_TOOLCHAIN}'\n"
"Available toolchains:\n"
)
foreach(_TOOLCHAIN ${_DISCOVERED_TOOLCHAINS})
list(APPEND _NOT_FOUND_MESSAGE " `${_TOOLCHAIN}`\n")
endforeach()
_findrust_failed(${_NOT_FOUND_MESSAGE})
endif()
set(_RUSTUP_TOOLCHAIN_FULL "${Rust_TOOLCHAIN}-${_DEFAULT_HOST}")
else()
set(_RUSTUP_TOOLCHAIN_FULL "${Rust_TOOLCHAIN}")
endif()
set(_RUST_TOOLCHAIN_PATH "${_TOOLCHAIN_${_RUSTUP_TOOLCHAIN_FULL}_PATH}")
if(NOT "${Rust_FIND_QUIETLY}")
message(VERBOSE "Rust toolchain ${_RUSTUP_TOOLCHAIN_FULL}")
message(VERBOSE "Rust toolchain path ${_RUST_TOOLCHAIN_PATH}")
endif()
# Is overridden if the user specifies `Rust_COMPILER` explicitly.
find_program(
Rust_COMPILER_CACHED
rustc
HINTS "${_RUST_TOOLCHAIN_PATH}/bin"
NO_DEFAULT_PATH)
elseif (Rust_RUSTUP)
get_filename_component(_RUST_TOOLCHAIN_PATH "${Rust_RUSTUP}" DIRECTORY)
get_filename_component(_RUST_TOOLCHAIN_PATH "${_RUST_TOOLCHAIN_PATH}" DIRECTORY)
find_program(
Rust_COMPILER_CACHED
rustc
HINTS "${_RUST_TOOLCHAIN_PATH}/bin"
NO_DEFAULT_PATH)
else()
find_program(Rust_COMPILER_CACHED rustc)
if (EXISTS "${Rust_COMPILER_CACHED}")
# rustc is expected to be at `<toolchain_path>/bin/rustc`.
get_filename_component(_RUST_TOOLCHAIN_PATH "${Rust_COMPILER_CACHED}" DIRECTORY)
get_filename_component(_RUST_TOOLCHAIN_PATH "${_RUST_TOOLCHAIN_PATH}" DIRECTORY)
endif()
if (NOT DEFINED Rust_CARGO_CACHED)
find_program(Rust_CARGO_CACHED cargo PATHS "$ENV{HOME}/.cargo/bin")
endif()
if (NOT EXISTS "${Rust_CARGO_CACHED}")
message(FATAL_ERROR "The cargo executable ${Rust_CARGO_CACHED} was not found. "
"Consider setting `Rust_CARGO_CACHED` to the absolute path of `cargo`."
)
endif()
if (NOT DEFINED Rust_COMPILER_CACHED)
find_program(Rust_COMPILER_CACHED rustc PATHS "$ENV{HOME}/.cargo/bin")
endif()
if (NOT EXISTS "${Rust_COMPILER_CACHED}")
set(_NOT_FOUND_MESSAGE "The rustc executable was not found. "
"Rust not installed or ~/.cargo/bin not added to path?\n"
"Hint: Consider setting `Rust_COMPILER` to the absolute path of `rustc`."
)
_findrust_failed(${_NOT_FOUND_MESSAGE})
endif()
if (Rust_RESOLVE_RUSTUP_TOOLCHAINS)
set(_NOT_FOUND_MESSAGE "Rust was detected to be managed by rustup, but failed to find `cargo` "
"next to `rustc` in `${_RUST_TOOLCHAIN_PATH}/bin`. This can happen for custom toolchains, "
"if cargo was not built. "
"Please manually specify the path to a compatible `cargo` by setting `Rust_CARGO`."
)
find_program(
Rust_CARGO_CACHED
cargo
HINTS "${_RUST_TOOLCHAIN_PATH}/bin"
NO_DEFAULT_PATH
)
# note: maybe can use find_package_handle_standard_args here, if we remove the _CACHED postfix.
# not sure why that is here...
if(NOT EXISTS "${Rust_CARGO_CACHED}")
_findrust_failed(${_NOT_FOUND_MESSAGE})
endif()
set(Rust_TOOLCHAIN_IS_RUSTUP_MANAGED TRUE CACHE INTERNAL "" FORCE)
else()
set(_NOT_FOUND_MESSAGE "Failed to find `cargo` in PATH and `${_RUST_TOOLCHAIN_PATH}/bin`.\n"
"Please ensure cargo is in PATH or manually specify the path to a compatible `cargo` by "
"setting `Rust_CARGO`."
)
# On some systems (e.g. NixOS) cargo is not managed by rustup and also not next to rustc.
find_program(
Rust_CARGO_CACHED
cargo
HINTS "${_RUST_TOOLCHAIN_PATH}/bin"
)
# note: maybe can use find_package_handle_standard_args here, if we remove the _CACHED postfix.
# not sure why that is here...
if(NOT EXISTS "${Rust_CARGO_CACHED}")
_findrust_failed(${_NOT_FOUND_MESSAGE})
endif()
endif()
execute_process(
COMMAND "${Rust_CARGO_CACHED}" --version --verbose
OUTPUT_VARIABLE _CARGO_VERSION_RAW
RESULT_VARIABLE _CARGO_VERSION_RESULT
)
# todo: check if cargo is a required component!
if(NOT ( "${_CARGO_VERSION_RESULT}" EQUAL "0" ))
_findrust_failed("Failed to get cargo version.\n"
"`${Rust_CARGO_CACHED} --version` failed with error: `${_CARGO_VERSION_RESULT}"
)
endif()
# todo: don't set cache variables here, but let find_package_handle_standard_args do the promotion
# later.
if (_CARGO_VERSION_RAW MATCHES "cargo ([0-9]+)\\.([0-9]+)\\.([0-9]+)")
set(Rust_CARGO_VERSION_MAJOR "${CMAKE_MATCH_1}" CACHE INTERNAL "" FORCE)
set(Rust_CARGO_VERSION_MINOR "${CMAKE_MATCH_2}" CACHE INTERNAL "" FORCE)
set(Rust_CARGO_VERSION_PATCH "${CMAKE_MATCH_3}" CACHE INTERNAL "" FORCE)
set(Rust_CARGO_VERSION "${Rust_CARGO_VERSION_MAJOR}.${Rust_CARGO_VERSION_MINOR}.${Rust_CARGO_VERSION_PATCH}" CACHE INTERNAL "" FORCE)
# Workaround for the version strings where the `cargo ` prefix is missing.
elseif(_CARGO_VERSION_RAW MATCHES "([0-9]+)\\.([0-9]+)\\.([0-9]+)")
set(Rust_CARGO_VERSION_MAJOR "${CMAKE_MATCH_1}" CACHE INTERNAL "" FORCE)
set(Rust_CARGO_VERSION_MINOR "${CMAKE_MATCH_2}" CACHE INTERNAL "" FORCE)
set(Rust_CARGO_VERSION_PATCH "${CMAKE_MATCH_3}" CACHE INTERNAL "" FORCE)
set(Rust_CARGO_VERSION "${Rust_CARGO_VERSION_MAJOR}.${Rust_CARGO_VERSION_MINOR}.${Rust_CARGO_VERSION_PATCH}" CACHE INTERNAL "" FORCE)
else()
_findrust_failed(
"Failed to parse cargo version. `cargo --version` evaluated to (${_CARGO_VERSION_RAW}). "
"Expected a <Major>.<Minor>.<Patch> version triple."
message(FATAL_ERROR "The rustc executable ${Rust_COMPILER} was not found. "
"Consider setting `Rust_COMPILER` to the absolute path of `rustc`."
)
endif()
execute_process(
# Figure out the target by just using the host target.
# If you want to cross-compile, you'll have to set Rust_CARGO_TARGET
if(NOT Rust_CARGO_TARGET_CACHED)
execute_process(
COMMAND "${Rust_COMPILER_CACHED}" --version --verbose
OUTPUT_VARIABLE _RUSTC_VERSION_RAW
RESULT_VARIABLE _RUSTC_VERSION_RESULT
)
)
if(NOT ( "${_RUSTC_VERSION_RESULT}" EQUAL "0" ))
_findrust_failed("Failed to get rustc version.\n"
"${Rust_COMPILER_CACHED} --version failed with error: `${_RUSTC_VERSION_RESULT}`")
endif()
if(NOT ( "${_RUSTC_VERSION_RESULT}" EQUAL "0" ))
message(FATAL_ERROR "Failed to get rustc version.\n"
"${Rust_COMPILER} --version failed with error: `${_RUSTC_VERSION_RESULT}`")
endif()
if (_RUSTC_VERSION_RAW MATCHES "rustc ([0-9]+)\\.([0-9]+)\\.([0-9]+)(-nightly)?")
set(Rust_VERSION_MAJOR "${CMAKE_MATCH_1}" CACHE INTERNAL "" FORCE)
set(Rust_VERSION_MINOR "${CMAKE_MATCH_2}" CACHE INTERNAL "" FORCE)
set(Rust_VERSION_PATCH "${CMAKE_MATCH_3}" CACHE INTERNAL "" FORCE)
set(Rust_VERSION "${Rust_VERSION_MAJOR}.${Rust_VERSION_MINOR}.${Rust_VERSION_PATCH}" CACHE INTERNAL "" FORCE)
if(CMAKE_MATCH_4)
set(Rust_IS_NIGHTLY 1 CACHE INTERNAL "" FORCE)
else()
set(Rust_IS_NIGHTLY 0 CACHE INTERNAL "" FORCE)
endif()
else()
_findrust_failed("Failed to parse rustc version. `${Rust_COMPILER_CACHED} --version --verbose` "
"evaluated to:\n`${_RUSTC_VERSION_RAW}`"
)
endif()
if (_RUSTC_VERSION_RAW MATCHES "host: ([a-zA-Z0-9_\\-]*)\n")
if (_RUSTC_VERSION_RAW MATCHES "host: ([a-zA-Z0-9_\\-]*)\n")
set(Rust_DEFAULT_HOST_TARGET "${CMAKE_MATCH_1}")
set(Rust_CARGO_HOST_TARGET_CACHED "${Rust_DEFAULT_HOST_TARGET}" CACHE STRING "Host triple")
else()
_findrust_failed(
"Failed to parse rustc host target. `rustc --version --verbose` evaluated to:\n${_RUSTC_VERSION_RAW}"
else()
message(FATAL_ERROR
"Failed to parse rustc host target. `rustc --version --verbose` evaluated to:\n${_RUSTC_VERSION_RAW}"
)
endif()
endif()
if (_RUSTC_VERSION_RAW MATCHES "LLVM version: ([0-9]+)\\.([0-9]+)(\\.([0-9]+))?")
set(Rust_LLVM_VERSION_MAJOR "${CMAKE_MATCH_1}" CACHE INTERNAL "" FORCE)
set(Rust_LLVM_VERSION_MINOR "${CMAKE_MATCH_2}" CACHE INTERNAL "" FORCE)
# With the Rust toolchain 1.44.1 the reported LLVM version is 9.0, i.e. without a patch version.
# Since cmake regex does not support non-capturing groups, just ignore Match 3.
set(Rust_LLVM_VERSION_PATCH "${CMAKE_MATCH_4}" CACHE INTERNAL "" FORCE)
set(Rust_LLVM_VERSION "${Rust_LLVM_VERSION_MAJOR}.${Rust_LLVM_VERSION_MINOR}.${Rust_LLVM_VERSION_PATCH}" CACHE INTERNAL "" FORCE)
elseif(NOT Rust_FIND_QUIETLY)
message(
WARNING
"Failed to parse rustc LLVM version. `rustc --version --verbose` evaluated to:\n${_RUSTC_VERSION_RAW}"
if(CMAKE_CROSSCOMPILING)
message(FATAL_ERROR "CMake is in cross-compiling mode."
"Manually set `Rust_CARGO_TARGET`."
)
endif()
if (NOT Rust_CARGO_TARGET_CACHED)
unset(_CARGO_ARCH)
unset(_CARGO_ABI)
if (WIN32)
if (CMAKE_VS_PLATFORM_NAME)
string(TOLOWER "${CMAKE_VS_PLATFORM_NAME}" LOWER_VS_PLATFORM_NAME)
if ("${LOWER_VS_PLATFORM_NAME}" STREQUAL "win32")
set(_CARGO_ARCH i686)
elseif("${LOWER_VS_PLATFORM_NAME}" STREQUAL "x64")
set(_CARGO_ARCH x86_64)
elseif("${LOWER_VS_PLATFORM_NAME}" STREQUAL "arm64")
set(_CARGO_ARCH aarch64)
else()
message(WARNING "VS Platform '${CMAKE_VS_PLATFORM_NAME}' not recognized")
endif()
endif()
# Fallback path
if(NOT DEFINED _CARGO_ARCH)
# Possible values for windows when not cross-compiling taken from here:
# https://learn.microsoft.com/en-us/windows/win32/winprog64/wow64-implementation-details
# When cross-compiling the user is expected to supply the value, so we match more variants.
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(AMD64|amd64|x86_64)$")
set(_CARGO_ARCH x86_64)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(ARM64|arm64|aarch64)$")
set(_CARGO_ARCH aarch64)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(X86|x86|i686)$")
set(_CARGO_ARCH i686)
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "i586")
set(_CARGO_ARCH i586)
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "IA64")
message(FATAL_ERROR "No rust target for Intel Itanium.")
elseif(NOT "${CMAKE_SYSTEM_PROCESSOR}")
message(WARNING "Failed to detect target architecture. Please set `CMAKE_SYSTEM_PROCESSOR`"
" to your target architecture or set `Rust_CARGO_TARGET` to your cargo target triple."
)
else()
message(WARNING "Failed to detect target architecture. Please set "
"`Rust_CARGO_TARGET` to your cargo target triple."
)
endif()
endif()
set(_CARGO_VENDOR "pc-windows")
# The MSVC Generators will always target the msvc ABI.
# For other generators we check the compiler ID and compiler target (if present)
# If no compiler is set and we are not cross-compiling then we just choose the
# default rust host target.
if(DEFINED MSVC
OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC"
OR "${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC"
OR "${CMAKE_CXX_COMPILER_TARGET}" MATCHES "-msvc$"
OR "${CMAKE_C_COMPILER_TARGET}" MATCHES "-msvc$"
)
set(_CARGO_ABI msvc)
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU"
OR "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU"
OR "${CMAKE_CXX_COMPILER_TARGET}" MATCHES "-gnu$"
OR "${CMAKE_C_COMPILER_TARGET}" MATCHES "-gnu$"
OR (NOT CMAKE_CROSSCOMPILING AND "${Rust_DEFAULT_HOST_TARGET}" MATCHES "-gnu$")
)
set(_CARGO_ABI gnu)
elseif(NOT "${CMAKE_CROSSCOMPILING}" AND "${Rust_DEFAULT_HOST_TARGET}" MATCHES "-msvc$")
# We first check if the gnu branch matches to ensure this fallback is only used
# if no compiler is enabled.
set(_CARGO_ABI msvc)
else()
message(WARNING "Could not determine the target ABI. Please specify `Rust_CARGO_TARGET` manually.")
endif()
if(DEFINED _CARGO_ARCH AND DEFINED _CARGO_VENDOR AND DEFINED _CARGO_ABI)
set(Rust_CARGO_TARGET_CACHED "${_CARGO_ARCH}-${_CARGO_VENDOR}-${_CARGO_ABI}"
CACHE STRING "Target triple")
endif()
elseif (ANDROID)
if (CMAKE_ANDROID_ARCH_ABI STREQUAL armeabi-v7a)
if (CMAKE_ANDROID_ARM_MODE)
set(_Rust_ANDROID_TARGET armv7-linux-androideabi)
else ()
set(_Rust_ANDROID_TARGET thumbv7neon-linux-androideabi)
endif()
elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL arm64-v8a)
set(_Rust_ANDROID_TARGET aarch64-linux-android)
elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL x86)
set(_Rust_ANDROID_TARGET i686-linux-android)
elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL x86_64)
set(_Rust_ANDROID_TARGET x86_64-linux-android)
endif()
if (_Rust_ANDROID_TARGET)
set(Rust_CARGO_TARGET_CACHED "${_Rust_ANDROID_TARGET}" CACHE STRING "Target triple")
endif()
endif()
# Fallback to the default host target
if(NOT Rust_CARGO_TARGET_CACHED)
if(CMAKE_CROSSCOMPILING)
message(WARNING "CMake is in cross-compiling mode, but the cargo target-triple could not be inferred."
"Falling back to the default host target. Please consider manually setting `Rust_CARGO_TARGET`."
)
endif()
set(Rust_CARGO_TARGET_CACHED "${Rust_DEFAULT_HOST_TARGET}" CACHE STRING "Target triple")
endif()
message(STATUS "Rust Target: ${Rust_CARGO_TARGET_CACHED}")
endif()
if(Rust_CARGO_TARGET_CACHED STREQUAL Rust_DEFAULT_HOST_TARGET)
set(Rust_CROSSCOMPILING FALSE CACHE INTERNAL "Rust is configured for cross-compiling")
else()
set(Rust_CROSSCOMPILING TRUE CACHE INTERNAL "Rust is configured for cross-compiling")
endif()
_corrosion_parse_target_triple("${Rust_CARGO_TARGET_CACHED}" rust_arch rust_vendor rust_os rust_env)
_corrosion_parse_target_triple("${Rust_CARGO_HOST_TARGET_CACHED}" rust_host_arch rust_host_vendor rust_host_os rust_host_env)
set(Rust_CARGO_TARGET_ARCH "${rust_arch}" CACHE INTERNAL "Target architecture")
set(Rust_CARGO_TARGET_VENDOR "${rust_vendor}" CACHE INTERNAL "Target vendor")
set(Rust_CARGO_TARGET_OS "${rust_os}" CACHE INTERNAL "Target Operating System")
set(Rust_CARGO_TARGET_ENV "${rust_env}" CACHE INTERNAL "Target environment")
set(Rust_CARGO_HOST_ARCH "${rust_host_arch}" CACHE INTERNAL "Host architecture")
set(Rust_CARGO_HOST_VENDOR "${rust_host_vendor}" CACHE INTERNAL "Host vendor")
set(Rust_CARGO_HOST_OS "${rust_host_os}" CACHE INTERNAL "Host Operating System")
set(Rust_CARGO_HOST_ENV "${rust_host_env}" CACHE INTERNAL "Host environment")
if(NOT DEFINED CACHE{Rust_CARGO_TARGET_LINK_NATIVE_LIBS})
message(STATUS "Determining required link libraries for target ${Rust_CARGO_TARGET_CACHED}")
unset(required_native_libs)
_corrosion_determine_libs_new("${Rust_CARGO_TARGET_CACHED}" required_native_libs)
if(DEFINED required_native_libs)
message(STATUS "Required static libs for target ${Rust_CARGO_TARGET_CACHED}: ${required_native_libs}" )
endif()
# In very recent corrosion versions it is possible to override the rust compiler version
# per target, so to be totally correct we would need to determine the libraries for
# every installed Rust version, that the user could choose from.
# In practice there aren't likely going to be any major differences, so we just do it once
# for the target and once for the host target (if cross-compiling).
set(Rust_CARGO_TARGET_LINK_NATIVE_LIBS "${required_native_libs}" CACHE INTERNAL
"Required native libraries when linking Rust static libraries")
endif()
if(Rust_CROSSCOMPILING AND NOT DEFINED CACHE{Rust_CARGO_HOST_TARGET_LINK_NATIVE_LIBS})
message(STATUS "Determining required link libraries for target ${Rust_CARGO_HOST_TARGET_CACHED}")
unset(host_libs)
_corrosion_determine_libs_new("${Rust_CARGO_HOST_TARGET_CACHED}" host_libs)
if(DEFINED host_libs)
message(STATUS "Required static libs for host target ${Rust_CARGO_HOST_TARGET_CACHED}: ${host_libs}" )
endif()
set(Rust_CARGO_HOST_TARGET_LINK_NATIVE_LIBS "${host_libs}" CACHE INTERNAL
"Required native libraries when linking Rust static libraries for the host target")
endif()
set(Rust_CARGO_TARGET_CACHED "${Rust_DEFAULT_HOST_TARGET}" CACHE STRING "Target triple")
endif()
# Set the input variables as non-cache variables so that the variables are available after
@@ -777,24 +82,6 @@ endforeach()
find_package_handle_standard_args(
Rust
REQUIRED_VARS Rust_COMPILER Rust_VERSION Rust_CARGO Rust_CARGO_VERSION Rust_CARGO_TARGET Rust_CARGO_HOST_TARGET
VERSION_VAR Rust_VERSION
REQUIRED_VARS Rust_COMPILER Rust_CARGO Rust_CARGO_TARGET
)
if(NOT TARGET Rust::Rustc)
add_executable(Rust::Rustc IMPORTED GLOBAL)
set_property(
TARGET Rust::Rustc
PROPERTY IMPORTED_LOCATION "${Rust_COMPILER_CACHED}"
)
add_executable(Rust::Cargo IMPORTED GLOBAL)
set_property(
TARGET Rust::Cargo
PROPERTY IMPORTED_LOCATION "${Rust_CARGO_CACHED}"
)
set(Rust_FOUND true)
endif()
list(POP_BACK CMAKE_MESSAGE_CONTEXT)

View File

@@ -37,10 +37,12 @@ set(MANUALS ${CMAKE_CURRENT_BINARY_DIR}/user_doc/man/man1/fish.1
${CMAKE_CURRENT_BINARY_DIR}/user_doc/man/man1/fish-tutorial.1
${CMAKE_CURRENT_BINARY_DIR}/user_doc/man/man1/fish-language.1
${CMAKE_CURRENT_BINARY_DIR}/user_doc/man/man1/fish-interactive.1
${CMAKE_CURRENT_BINARY_DIR}/user_doc/man/man1/fish-terminal-compatibility.1
${CMAKE_CURRENT_BINARY_DIR}/user_doc/man/man1/fish-completions.1
${CMAKE_CURRENT_BINARY_DIR}/user_doc/man/man1/fish-prompt-tutorial.1
${CMAKE_CURRENT_BINARY_DIR}/user_doc/man/man1/fish-for-bash-users.1
${CMAKE_CURRENT_BINARY_DIR}/user_doc/man/man1/fish-faq.1)
${CMAKE_CURRENT_BINARY_DIR}/user_doc/man/man1/fish-faq.1
)
# Determine which man page we don't want to install.
# On OS X, don't install a man page for open, since we defeat fish's open
@@ -154,24 +156,8 @@ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/user_doc/html/ # Trailing slash is
DESTINATION ${docdir} OPTIONAL)
install(FILES CHANGELOG.rst DESTINATION ${docdir})
# These files are built by cmake/gettext.cmake, but using GETTEXT_PROCESS_PO_FILES's
# INSTALL_DESTINATION leads to them being installed as ${lang}.gmo, not fish.mo
# The ${languages} array comes from cmake/gettext.cmake
if(GETTEXT_FOUND)
foreach(lang ${languages})
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${lang}.gmo DESTINATION
${CMAKE_INSTALL_LOCALEDIR}/${lang}/LC_MESSAGES/ RENAME fish.mo)
endforeach()
endif()
if (NOT APPLE)
install(FILES fish.desktop DESTINATION ${rel_datadir}/applications)
install(FILES ${SPHINX_SRC_DIR}/python_docs_theme/static/fish.png DESTINATION ${rel_datadir}/pixmaps)
endif()
# Group install targets into a InstallTargets folder
set_property(TARGET build_fish_pc CHECK-FISH-BUILD-VERSION-FILE
tests_buildroot_target
PROPERTY FOLDER cmake/InstallTargets)
# Make a target build_root that installs into the buildroot directory, for testing.

View File

@@ -24,7 +24,7 @@ add_executable(fish_macapp EXCLUDE_FROM_ALL
# Compute the version. Note this is done at generation time, not build time,
# so cmake must be re-run after version changes for the app to be updated. But
# generally this will be run by make_pkg.sh which always re-runs cmake.
# generally this will be run by make_macos_pkg.sh which always re-runs cmake.
execute_process(
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build_tools/git_version_gen.sh --stdout
COMMAND cut -d- -f1
@@ -32,7 +32,7 @@ execute_process(
OUTPUT_STRIP_TRAILING_WHITESPACE)
# Note CMake appends .app, so the real output name will be fish.app.
# Note CMake appends .app, so the real output name will be fish.app.
# This target does not include the 'base' resource.
set_target_properties(fish_macapp PROPERTIES OUTPUT_NAME "fish")

View File

@@ -1,7 +1,3 @@
# Trying to build using the resolved toolchain causes all kinds of weird errors
# Just let rustup do its job
set(Rust_RESOLVE_RUSTUP_TOOLCHAINS Off)
include(FindRust)
find_package(Rust REQUIRED)
@@ -9,11 +5,11 @@ set(FISH_RUST_BUILD_DIR "${CMAKE_BINARY_DIR}/cargo/build")
if(DEFINED ASAN)
list(APPEND CARGO_FLAGS "-Z" "build-std")
list(APPEND FISH_CRATE_FEATURES "asan")
list(APPEND FISH_CARGO_FEATURES_LIST "asan")
endif()
if(DEFINED TSAN)
list(APPEND CARGO_FLAGS "-Z" "build-std")
list(APPEND FISH_CRATE_FEATURES "tsan")
list(APPEND FISH_CARGO_FEATURES_LIST "tsan")
endif()
if (Rust_CARGO_TARGET)
@@ -25,39 +21,26 @@ endif()
set(rust_profile $<IF:$<CONFIG:Debug>,debug,$<IF:$<CONFIG:RelWithDebInfo>,release-with-debug,release>>)
set(rust_debugflags "$<$<CONFIG:Debug>:-g>$<$<CONFIG:RelWithDebInfo>:-g>")
# Temporary hack to propogate CMake flags/options to build.rs. We need to get CMake to evaluate the
# truthiness of the strings if they are set.
set(CMAKE_WITH_GETTEXT "1")
if(DEFINED WITH_GETTEXT AND NOT "${WITH_GETTEXT}")
set(CMAKE_WITH_GETTEXT "0")
option(WITH_GETTEXT "Build with gettext localization support. Requires `msgfmt` to work." ON)
# Enable gettext feature unless explicitly disabled.
if(NOT DEFINED WITH_GETTEXT OR "${WITH_GETTEXT}")
list(APPEND FISH_CARGO_FEATURES_LIST "localize-messages")
endif()
if(FISH_CRATE_FEATURES)
set(FEATURES_ARG ${FISH_CRATE_FEATURES})
list(PREPEND FEATURES_ARG "--features")
endif()
get_property(
RUSTC_EXECUTABLE
TARGET Rust::Rustc PROPERTY IMPORTED_LOCATION
)
list(JOIN FISH_CARGO_FEATURES_LIST , FISH_CARGO_FEATURES)
# Tell Cargo where our build directory is so it can find Cargo.toml.
set(VARS_FOR_CARGO
"FISH_BUILD_DIR=${CMAKE_BINARY_DIR}"
"PREFIX=${CMAKE_INSTALL_PREFIX}"
# Temporary hack to propogate CMake flags/options to build.rs.
"CMAKE_WITH_GETTEXT=${CMAKE_WITH_GETTEXT}"
# Cheesy so we can tell cmake was used to build
"CMAKE=1"
"DOCDIR=${CMAKE_INSTALL_FULL_DOCDIR}"
"DATADIR=${CMAKE_INSTALL_FULL_DATADIR}"
"SYSCONFDIR=${CMAKE_INSTALL_FULL_SYSCONFDIR}"
"BINDIR=${CMAKE_INSTALL_FULL_BINDIR}"
"LOCALEDIR=${CMAKE_INSTALL_FULL_LOCALEDIR}"
"CARGO_TARGET_DIR=${FISH_RUST_BUILD_DIR}"
"CARGO_BUILD_RUSTC=${RUSTC_EXECUTABLE}"
"CARGO_BUILD_RUSTC=${Rust_COMPILER}"
"${FISH_PCRE2_BUILDFLAG}"
"RUSTFLAGS=$ENV{RUSTFLAGS} ${rust_debugflags}"
)

View File

@@ -1,127 +1,33 @@
# This adds ctest support to the project
enable_testing()
# Put in a tests folder to reduce the top level targets in IDEs.
set(CMAKE_FOLDER tests)
# We will use 125 as a reserved exit code to indicate that a test has been skipped, i.e. it did not
# pass but it should not be considered a failed test run, either.
set(SKIP_RETURN_CODE 125)
# Even though we are using CMake's ctest for testing, we still define our own `make fish_run_tests` target
# rather than use its default for many reasons:
# * CMake doesn't run tests in-proc or even add each tests as an individual node in the ninja
# dependency tree, instead it just bundles all tests into a target called `test` that always just
# shells out to `ctest`, so there are no build-related benefits to not doing that ourselves.
# * The only way to have a test depend on a binary is to add a fake test with a name like
# "build_fish" that executes CMake recursively to build the `fish` target.
# * Circling back to the point about individual tests not being actual Makefile targets, CMake does
# not offer any way to execute a named test via the `make`/`ninja`/whatever interface; the only
# way to manually invoke test `foo` is to to manually run `ctest` and specify a regex matching
# `foo` as an argument, e.g. `ctest -R ^foo$`... which is really crazy.
# The top-level test target is "fish_run_tests".
add_custom_target(fish_run_tests
COMMAND env FISH_FORCE_COLOR=1
FISH_SOURCE_DIR=${CMAKE_SOURCE_DIR}
${CMAKE_CTEST_COMMAND} --force-new-ctest-process # --verbose
--output-on-failure --progress
DEPENDS tests_dir funcs_dir tests_buildroot_target
USES_TERMINAL
)
# The "test" directory.
set(TEST_DIR ${CMAKE_CURRENT_BINARY_DIR}/test)
# The directory into which fish is installed.
set(TEST_INSTALL_DIR ${TEST_DIR}/buildroot)
# The directory where the tests expect to find the fish root (./bin, etc)
set(TEST_ROOT_DIR ${TEST_DIR}/root)
# Copy needed directories for out-of-tree builds
if(NOT FISH_IN_TREE_BUILD)
add_custom_target(funcs_dir)
add_custom_command(TARGET funcs_dir
POST_BUILD
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/share
# Don't run ln twice or it will create a new link in the link.
COMMAND test -e ${CMAKE_BINARY_DIR}/share/functions || ln -sf
${CMAKE_SOURCE_DIR}/share/functions/ ${CMAKE_BINARY_DIR}/share/functions
COMMENT "Symlinking fish functions to binary dir"
VERBATIM)
add_custom_target(tests_dir DEPENDS tests)
add_custom_command(TARGET tests_dir
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/tests/ ${CMAKE_BINARY_DIR}/tests/
COMMENT "Copying test files to binary dir"
VERBATIM)
endif()
# Copy littlecheck.py
configure_file(build_tools/littlecheck.py littlecheck.py COPYONLY)
# Copy pexpect_helper.py
configure_file(build_tools/pexpect_helper.py pexpect_helper.py COPYONLY)
# Suppress generating Xcode schemes for all tests, there's too many.
set(CMAKE_XCODE_GENERATE_SCHEME 0)
# CMake being CMake, you can't just add a DEPENDS argument to add_test to make it depend on any of
# your binaries actually being built before `make fish_run_tests` is executed (requiring `make all` first),
# and the only dependency a test can have is on another test. So we make building fish
# prerequisites to our entire top-level `test` target.
function(add_test_target NAME)
string(REPLACE "/" "-" NAME ${NAME})
add_custom_target("test_${NAME}" COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -R "^${NAME}$$"
DEPENDS tests_dir funcs_dir tests_buildroot_target USES_TERMINAL )
endfunction()
add_custom_target(tests_buildroot_target
# Make the directory in which to run tests:
COMMAND ${CMAKE_COMMAND} -E make_directory ${TEST_INSTALL_DIR}
COMMAND env DESTDIR=${TEST_INSTALL_DIR} ${CMAKE_COMMAND}
--build ${CMAKE_CURRENT_BINARY_DIR} --target install
# Put fish_test_helper there too:
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/fish_test_helper
${TEST_INSTALL_DIR}/${CMAKE_INSTALL_PREFIX}/bin
# Also symlink fish to where the tests expect it to be:
COMMAND ${CMAKE_COMMAND} -E create_symlink
${TEST_INSTALL_DIR}/${CMAKE_INSTALL_PREFIX}
${TEST_ROOT_DIR}
DEPENDS fish fish_test_helper)
add_executable(fish_test_helper tests/fish_test_helper.c)
FILE(GLOB FISH_CHECKS CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/tests/checks/*.fish)
foreach(CHECK ${FISH_CHECKS})
get_filename_component(CHECK_NAME ${CHECK} NAME)
get_filename_component(CHECK ${CHECK} NAME_WE)
add_test(NAME ${CHECK_NAME}
COMMAND sh ${CMAKE_CURRENT_BINARY_DIR}/tests/test_driver.sh
${CMAKE_CURRENT_BINARY_DIR}/tests/test.fish ${CHECK}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests
add_custom_target(
test_${CHECK_NAME}
COMMAND ${CMAKE_SOURCE_DIR}/tests/test_driver.py ${CMAKE_CURRENT_BINARY_DIR}
checks/${CHECK_NAME}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
DEPENDS fish fish_indent fish_key_reader fish_test_helper
USES_TERMINAL
)
set_tests_properties(${CHECK_NAME} PROPERTIES SKIP_RETURN_CODE ${SKIP_RETURN_CODE})
set_tests_properties(${CHECK_NAME} PROPERTIES ENVIRONMENT FISH_FORCE_COLOR=1)
add_test_target("${CHECK_NAME}")
endforeach(CHECK)
FILE(GLOB PEXPECTS CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/tests/pexpects/*.py)
foreach(PEXPECT ${PEXPECTS})
get_filename_component(PEXPECT ${PEXPECT} NAME)
add_test(NAME ${PEXPECT}
COMMAND sh ${CMAKE_CURRENT_BINARY_DIR}/tests/test_driver.sh
${CMAKE_CURRENT_BINARY_DIR}/tests/interactive.fish ${PEXPECT}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests
add_custom_target(
test_${PEXPECT}
COMMAND ${CMAKE_SOURCE_DIR}/tests/test_driver.py ${CMAKE_CURRENT_BINARY_DIR}
pexpects/${PEXPECT}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
DEPENDS fish fish_indent fish_key_reader fish_test_helper
USES_TERMINAL
)
set_tests_properties(${PEXPECT} PROPERTIES SKIP_RETURN_CODE ${SKIP_RETURN_CODE})
set_tests_properties(${PEXPECT} PROPERTIES ENVIRONMENT FISH_FORCE_COLOR=1)
add_test_target("${PEXPECT}")
endforeach(PEXPECT)
set(cargo_test_flags)
# Rust stuff.
set(cargo_test_flags)
if(DEFINED ASAN)
# Rust w/ -Zsanitizer=address requires explicitly specifying the --target triple or else linker
# errors pertaining to asan symbols will ensue.
@@ -142,10 +48,17 @@ if(DEFINED Rust_CARGO_TARGET)
list(APPEND cargo_test_flags "--lib")
endif()
add_test(
NAME "cargo-test"
COMMAND env ${VARS_FOR_CARGO} cargo test --no-default-features ${CARGO_FLAGS} --workspace --target-dir ${rust_target_dir} ${cargo_test_flags}
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
set(max_concurrency_flag)
if(DEFINED ENV{FISH_TEST_MAX_CONCURRENCY})
list(APPEND max_concurrency_flag "--max-concurrency" $ENV{FISH_TEST_MAX_CONCURRENCY})
endif()
# The top-level test target is "fish_run_tests".
add_custom_target(fish_run_tests
# TODO: This should be replaced with a unified solution, possibly build_tools/check.sh.
COMMAND ${CMAKE_SOURCE_DIR}/tests/test_driver.py ${max_concurrency_flag} ${CMAKE_CURRENT_BINARY_DIR}
COMMAND env ${VARS_FOR_CARGO} cargo test --no-default-features ${CARGO_FLAGS} --workspace --target-dir ${rust_target_dir} ${cargo_test_flags}
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
DEPENDS fish fish_indent fish_key_reader fish_test_helper
USES_TERMINAL
)
set_tests_properties("cargo-test" PROPERTIES SKIP_RETURN_CODE ${SKIP_RETURN_CODE})
add_test_target("cargo-test")

View File

@@ -1,22 +0,0 @@
set(languages de en fr pl pt_BR sv zh_CN)
include(FeatureSummary)
option(WITH_GETTEXT "translate messages if gettext is available" ON)
if(WITH_GETTEXT)
find_package(Gettext)
endif()
add_feature_info(gettext GETTEXT_FOUND "translate messages with gettext")
# Define translations
if(GETTEXT_FOUND)
# Group pofile targets into their own folder, as there's a lot of them.
set(CMAKE_FOLDER pofiles)
foreach(lang ${languages})
# Our translations aren't set up entirely as CMake expects, so installation is done in
# cmake/Install.cmake instead of using INSTALL_DESTINATION
gettext_process_po_files(${lang} ALL
PO_FILES po/${lang}.po)
endforeach()
set(CMAKE_FOLDER)
endif()

View File

@@ -0,0 +1,12 @@
[package]
name = "fish-build-helper"
edition.workspace = true
rust-version.workspace = true
version = "0.0.0"
repository.workspace = true
[dependencies]
rsconf.workspace = true
[lints]
workspace = true

View File

@@ -0,0 +1,31 @@
use std::{borrow::Cow, env, path::Path};
pub fn workspace_root() -> &'static Path {
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
manifest_dir.ancestors().nth(2).unwrap()
}
fn cargo_target_dir() -> Cow<'static, Path> {
option_env!("CARGO_TARGET_DIR")
.map(|d| Cow::Borrowed(Path::new(d)))
.unwrap_or(Cow::Owned(workspace_root().join("target")))
}
pub fn fish_build_dir() -> Cow<'static, Path> {
// This is set if using CMake.
option_env!("FISH_BUILD_DIR")
.map(|d| Cow::Borrowed(Path::new(d)))
.unwrap_or(cargo_target_dir())
}
// TODO Move this to rsconf
pub fn rebuild_if_path_changed<P: AsRef<Path>>(path: P) {
rsconf::rebuild_if_path_changed(path.as_ref().to_str().unwrap());
}
// TODO Move this to rsconf
pub fn rebuild_if_paths_changed<P: AsRef<Path>, I: IntoIterator<Item = P>>(paths: I) {
for path in paths {
rsconf::rebuild_if_path_changed(path.as_ref().to_str().unwrap());
}
}

View File

@@ -0,0 +1,13 @@
[package]
name = "fish-build-man-pages"
edition.workspace = true
rust-version.workspace = true
version = "0.0.0"
repository.workspace = true
[build-dependencies]
fish-build-helper.workspace = true
rsconf.workspace = true
[lints]
workspace = true

View File

@@ -0,0 +1,98 @@
#[cfg(not(clippy))]
use std::path::Path;
fn main() {
let mandir = fish_build_helper::fish_build_dir().join("fish-man");
let sec1dir = mandir.join("man1");
// Running `cargo clippy` on a clean build directory panics, because when rust-embed tries to
// embed a directory which does not exist it will panic.
let _ = std::fs::create_dir_all(sec1dir.to_str().unwrap());
#[cfg(not(clippy))]
build_man(&mandir);
}
#[cfg(not(clippy))]
fn build_man(man_dir: &Path) {
use std::{
env,
process::{Command, Stdio},
};
use fish_build_helper::workspace_root;
let workspace_root = workspace_root();
let man_str = man_dir.to_str().unwrap();
let sec1_dir = man_dir.join("man1");
let sec1_str = sec1_dir.to_str().unwrap();
let docsrc_dir = workspace_root.join("doc_src");
let docsrc_str = docsrc_dir.to_str().unwrap();
let sphinx_doc_sources = [
workspace_root.join("CHANGELOG.rst"),
workspace_root.join("CONTRIBUTING.rst"),
docsrc_dir.clone(),
];
fish_build_helper::rebuild_if_paths_changed(sphinx_doc_sources);
let args = &[
"-j", "auto", "-q", "-b", "man", "-c", docsrc_str,
// doctree path - put this *above* the man1 dir to exclude it.
// this is ~6M
"-d", man_str, docsrc_str, sec1_str,
];
let _ = std::fs::create_dir_all(sec1_str);
rsconf::rebuild_if_env_changed("FISH_BUILD_DOCS");
if env::var("FISH_BUILD_DOCS") == Ok("0".to_string()) {
rsconf::warn!("Skipping man pages because $FISH_BUILD_DOCS is set to 0");
return;
}
// We run sphinx to build the man pages.
// Every error here is fatal so cargo doesn't cache the result
// - if we skipped the docs with sphinx not installed, installing it would not then build the docs.
// That means you need to explicitly set $FISH_BUILD_DOCS=0 (`FISH_BUILD_DOCS=0 cargo install --path .`),
// which is unfortunate - but the docs are pretty important because they're also used for --help.
let sphinx_build = match Command::new("sphinx-build")
.args(args)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
{
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
if env::var("FISH_BUILD_DOCS") == Ok("1".to_string()) {
panic!("Could not find sphinx-build to build man pages.\nInstall sphinx or disable building the docs by setting $FISH_BUILD_DOCS=0.");
}
rsconf::warn!("Cannot find sphinx-build to build man pages.");
rsconf::warn!("If you install it now you need to run `cargo clean` and rebuild, or set $FISH_BUILD_DOCS=1 explicitly.");
return;
}
Err(e) => {
// Another error - permissions wrong etc
panic!("Error starting sphinx-build to build man pages: {:?}", e);
}
Ok(sphinx_build) => sphinx_build,
};
match sphinx_build.wait_with_output() {
Err(err) => {
panic!(
"Error waiting for sphinx-build to build man pages: {:?}",
err
);
}
Ok(out) => {
if !out.stderr.is_empty() {
rsconf::warn!("sphinx-build: {}", String::from_utf8_lossy(&out.stderr));
}
assert_eq!(&String::from_utf8_lossy(&out.stdout), "");
if !out.status.success() {
panic!("sphinx-build failed to build the man pages.");
}
}
}
}

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,16 @@
[package]
name = "fish-gettext-extraction"
edition.workspace = true
rust-version.workspace = true
version = "0.0.0"
repository.workspace = true
description = "proc-macro for extracting strings for gettext translation"
[lib]
proc-macro = true
[dependencies]
proc-macro2.workspace = true
[lints]
workspace = true

View File

@@ -0,0 +1,107 @@
extern crate proc_macro;
use proc_macro::TokenStream;
use std::{ffi::OsString, fs::OpenOptions, io::Write};
fn unescape_multiline_rust_string(s: String) -> String {
if !s.contains('\n') {
return s;
}
let mut unescaped = String::new();
enum State {
Ground,
Escaped,
ContinuationLineLeadingWhitespace,
}
use State::*;
let mut state = Ground;
for c in s.chars() {
match state {
Ground => match c {
'\\' => state = Escaped,
_ => {
unescaped.push(c);
}
},
Escaped => match c {
'\\' => {
unescaped.push('\\');
state = Ground
}
'\n' => state = ContinuationLineLeadingWhitespace,
_ => panic!("Unsupported escape sequence '\\{c}' in message string '{s}'"),
},
ContinuationLineLeadingWhitespace => match c {
' ' | '\t' => (),
_ => {
unescaped.push(c);
state = Ground
}
},
}
}
unescaped
}
fn append_po_entry_to_file(message: &TokenStream, file_name: &OsString) {
let mut file = OpenOptions::new()
.create(true)
.append(true)
.open(file_name)
.unwrap_or_else(|e| panic!("Could not open file {file_name:?}: {e}"));
let message_string = unescape_multiline_rust_string(message.to_string());
if message_string.contains('\n') {
panic!("Gettext strings may not contain unescaped newlines. Unescaped newline found in '{message_string}'")
}
// Crude check for format strings. This might result in false positives.
let format_string_annotation = if message_string.contains('%') {
"#, c-format\n"
} else {
""
};
let po_entry = format!("{format_string_annotation}msgid {message_string}\nmsgstr \"\"\n\n");
file.write_all(po_entry.as_bytes()).unwrap();
}
/// The `message` is passed through unmodified.
/// If `FISH_GETTEXT_EXTRACTION_FILE` is defined in the environment,
/// this file is used to write the message,
/// so that it can then be used for generating gettext PO files.
/// The `message` must be a string literal.
///
/// # Panics
///
/// This macro panics if the `FISH_GETTEXT_EXTRACTION_FILE` variable is set and `message` has an
/// unexpected format.
/// Note that for example `concat!(...)` cannot be passed to this macro, because expansion works
/// outside in, meaning this macro would still see the `concat!` macro invocation, instead of a
/// string literal.
#[proc_macro]
pub fn gettext_extract(message: TokenStream) -> TokenStream {
if let Some(file_path) = std::env::var_os("FISH_GETTEXT_EXTRACTION_FILE") {
let pm2_message = proc_macro2::TokenStream::from(message.clone());
let mut token_trees = pm2_message.into_iter();
let first_token = token_trees
.next()
.expect("gettext_extract got empty token stream. Expected one token.");
if token_trees.next().is_some() {
panic!("Invalid number of tokens passed to gettext_extract. Expected one token, but got more.")
}
if let proc_macro2::TokenTree::Group(group) = first_token {
let mut group_tokens = group.stream().into_iter();
let first_group_token = group_tokens
.next()
.expect("gettext_extract expected one group token but got none.");
if group_tokens.next().is_some() {
panic!("Invalid number of tokens in group passed to gettext_extract. Expected one token, but got more.")
}
if let proc_macro2::TokenTree::Literal(_) = first_group_token {
append_po_entry_to_file(&message, &file_path);
} else {
panic!("Expected literal in gettext_extract, but got: {first_group_token:?}");
}
} else {
panic!("Expected group in gettext_extract, but got: {first_token:?}");
}
}
message
}

View File

@@ -0,0 +1,18 @@
[package]
name = "fish-gettext-maps"
edition.workspace = true
rust-version.workspace = true
version = "0.0.0"
repository.workspace = true
[dependencies]
phf.workspace = true
[build-dependencies]
fish-build-helper.workspace = true
fish-gettext-mo-file-parser.workspace = true
phf_codegen.workspace = true
rsconf.workspace = true
[lints]
workspace = true

View File

@@ -0,0 +1,142 @@
use std::{
env,
ffi::OsStr,
path::{Path, PathBuf},
process::Command,
};
fn main() {
let cache_dir =
PathBuf::from(fish_build_helper::fish_build_dir()).join("fish-localization-map-cache");
embed_localizations(&cache_dir);
fish_build_helper::rebuild_if_path_changed(fish_build_helper::workspace_root().join("po"));
}
fn embed_localizations(cache_dir: &Path) {
use fish_gettext_mo_file_parser::parse_mo_file;
use std::{
fs::File,
io::{BufWriter, Write},
};
let po_dir = fish_build_helper::workspace_root().join("po");
// Ensure that the directory is created, because clippy cannot compile the code if the
// directory does not exist.
std::fs::create_dir_all(cache_dir).unwrap();
let localization_map_path =
Path::new(&env::var("OUT_DIR").unwrap()).join("localization_maps.rs");
let mut localization_map_file = BufWriter::new(File::create(&localization_map_path).unwrap());
// This will become a map which maps from language identifiers to maps containing localizations
// for the respective language.
let mut catalogs = phf_codegen::Map::new();
match Command::new("msgfmt").arg("-h").status() {
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
rsconf::warn!(
"Cannot find msgfmt to build gettext message catalogs. Localization will not work."
);
rsconf::warn!(
"If you install it now you need to trigger a rebuild to get localization support."
);
rsconf::warn!(
"One way to achieve that is running `touch po` followed by the build command."
);
}
Err(e) => {
panic!("Error when trying to run `msgfmt -h`: {e:?}");
}
Ok(_) => {
for dir_entry_result in po_dir.read_dir().unwrap() {
let dir_entry = dir_entry_result.unwrap();
let po_file_path = dir_entry.path();
if po_file_path.extension() != Some(OsStr::new("po")) {
continue;
}
let lang = po_file_path
.file_stem()
.expect("All entries in the po directory must be regular files.");
let language = lang.to_str().unwrap().to_owned();
// Each language gets its own static map for the mapping from message in the source code to
// the localized version.
let map_name = format!("LANG_MAP_{language}");
let cached_map_path = cache_dir.join(lang);
// Include the file containing the map for this language in the main generated file.
writeln!(
&mut localization_map_file,
"include!(\"{}\");",
cached_map_path.display()
)
.unwrap();
// Map from the language identifier to the map containing the localizations for this
// language.
catalogs.entry(language, format!("&{map_name}"));
if let Ok(metadata) = std::fs::metadata(&cached_map_path) {
// Cached map file exists, but might be outdated.
let cached_map_mtime = metadata.modified().unwrap();
let po_mtime = dir_entry.metadata().unwrap().modified().unwrap();
if cached_map_mtime > po_mtime {
// Cached map file is considered up-to-date.
continue;
};
}
// Generate the map file.
// Try to create new MO data and load it into `mo_data`.
let output = Command::new("msgfmt")
.arg("--check-format")
.arg("--output-file=-")
.arg(&po_file_path)
.output()
.unwrap();
let mo_data = output.stdout;
// Extract map from MO data.
let language_localizations = parse_mo_file(&mo_data).unwrap();
// This file will contain the localization map for the current language.
let mut cached_map_file = File::create(&cached_map_path).unwrap();
let mut single_language_localization_map = phf_codegen::Map::new();
// The values will be written into the source code as is, meaning escape sequences and
// double quotes in the data will be interpreted by the Rust compiler, which is undesirable.
// Converting them to raw strings prevents this. (As long as no input data contains `"###`.)
fn to_raw_str(s: &str) -> String {
assert!(!s.contains("\"###"));
format!("r###\"{s}\"###")
}
for (msgid, msgstr) in language_localizations {
single_language_localization_map.entry(
String::from_utf8(msgid.into()).unwrap(),
to_raw_str(&String::from_utf8(msgstr.into()).unwrap()),
);
}
writeln!(&mut cached_map_file, "#[allow(non_upper_case_globals)]").unwrap();
write!(
&mut cached_map_file,
"static {}: phf::Map<&'static str, &'static str> = {}",
&map_name,
single_language_localization_map.build()
)
.unwrap();
writeln!(&mut cached_map_file, ";").unwrap();
}
}
}
write!(
&mut localization_map_file,
"pub static CATALOGS: phf::Map<&str, &phf::Map<&str, &str>> = {}",
catalogs.build()
)
.unwrap();
writeln!(&mut localization_map_file, ";").unwrap();
}

View File

@@ -0,0 +1 @@
include!(concat!(env!("OUT_DIR"), "/localization_maps.rs"));

View File

@@ -0,0 +1,9 @@
[package]
name = "fish-gettext-mo-file-parser"
edition.workspace = true
rust-version.workspace = true
version = "0.0.0"
repository.workspace = true
[lints]
workspace = true

View File

@@ -0,0 +1,131 @@
use std::collections::HashMap;
const U32_SIZE: usize = std::mem::size_of::<u32>();
fn read_le_u32(bytes: &[u8]) -> u32 {
u32::from_le_bytes(bytes[..U32_SIZE].try_into().unwrap())
}
fn read_be_u32(bytes: &[u8]) -> u32 {
u32::from_be_bytes(bytes[..U32_SIZE].try_into().unwrap())
}
fn get_u32_reader_from_magic_number(magic_number: &[u8]) -> std::io::Result<fn(&[u8]) -> u32> {
match magic_number {
[0x95, 0x04, 0x12, 0xde] => Ok(read_be_u32),
[0xde, 0x12, 0x04, 0x95] => Ok(read_le_u32),
_ => Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"First 4 bytes of MO file must correspond to magic number 0x950412de, either big or little endian.",
)),
}
}
/// Returns an error if an unknown major revision is detected.
/// There are no relevant differences between supported revisions.
fn check_if_revision_is_supported(revision: u32) -> std::io::Result<()> {
// From the reference:
// A program seeing an unexpected major revision number should stop reading the MO file entirely;
// whereas an unexpected minor revision number means that the file can be read
// but will not reveal its full contents,
// when parsed by a program that supports only smaller minor revision numbers.
let major_revision = revision >> 16;
match major_revision {
0 | 1 => {
// At time of writing, these are the only major revisions which exist.
// There is no documented difference and the GNU gettext code does not seem to
// differentiate between the two either.
// All features we care about are supported in minor revision 0,
// so we do not need to care about the minor revision.
Ok(())
}
_ => Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"Major revision must be 0 or 1",
)),
}
}
fn as_usize(value: u32) -> usize {
use std::mem::size_of;
const _: () = assert!(size_of::<u32>() <= size_of::<usize>());
usize::try_from(value).unwrap()
}
fn parse_strings(
file_content: &[u8],
num_strings: usize,
table_offset: usize,
read_u32: fn(&[u8]) -> u32,
) -> std::io::Result<Vec<&[u8]>> {
let file_too_short_error = || {
Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"MO file is too short.",
))
};
if table_offset + num_strings * 2 * U32_SIZE > file_content.len() {
return file_too_short_error();
}
let mut strings = Vec::with_capacity(num_strings);
let mut offset = table_offset;
let mut get_next_u32 = || {
let val = read_u32(&file_content[offset..]);
offset += U32_SIZE;
val
};
for _ in 0..num_strings {
// not including NUL terminator
let string_length = as_usize(get_next_u32());
let string_offset = as_usize(get_next_u32());
let string_end = string_offset.checked_add(string_length).unwrap();
if string_end > file_content.len() {
return file_too_short_error();
}
// Contexts are stored by storing the concatenation of the context, a EOT byte, and the original string, instead of the original string.
// Contexts are not supported by this implementation.
// The format allows plural forms to appear behind singular forms, separated by a NUL byte,
// where `string_length` includes the length of both.
// This is not supported here.
// Do not include the NUL terminator in the slice.
strings.push(&file_content[string_offset..string_end]);
}
Ok(strings)
}
/// Parse a MO file.
/// Format reference used: <https://www.gnu.org/software/gettext/manual/html_node/MO-Files.html>
pub fn parse_mo_file(file_content: &[u8]) -> std::io::Result<HashMap<&[u8], &[u8]>> {
if file_content.len() < 7 * U32_SIZE {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"File too short to contain header.",
));
}
// The first 4 bytes are a magic number, from which the endianness can be determined.
let read_u32 = get_u32_reader_from_magic_number(&file_content[0..U32_SIZE])?;
let mut offset = U32_SIZE;
let mut get_next_u32 = || {
let val = read_u32(&file_content[offset..]);
offset += U32_SIZE;
val
};
let file_format_revision = get_next_u32();
check_if_revision_is_supported(file_format_revision)?;
let num_strings = as_usize(get_next_u32());
let original_strings_offset = as_usize(get_next_u32());
let translation_strings_offset = as_usize(get_next_u32());
let original_strings =
parse_strings(file_content, num_strings, original_strings_offset, read_u32)?;
let translated_strings = parse_strings(
file_content,
num_strings,
translation_strings_offset,
read_u32,
)?;
let mut translation_map = HashMap::with_capacity(num_strings);
for i in 0..num_strings {
translation_map.insert(original_strings[i], translated_strings[i]);
}
Ok(translation_map)
}

17
crates/printf/Cargo.toml Normal file
View File

@@ -0,0 +1,17 @@
[package]
name = "fish-printf"
edition.workspace = true
rust-version.workspace = true
version = "0.2.1"
repository.workspace = true
description = "printf implementation, based on musl"
license = "MIT"
[dependencies]
libc.workspace = true
widestring = { workspace = true, optional = true }
unicode-segmentation.workspace = true
unicode-width.workspace = true
[lints]
workspace = true

View File

@@ -0,0 +1 @@
allow-print-in-tests = true

View File

@@ -139,6 +139,12 @@ fn to_arg(self) -> Arg<'a> {
}
}
impl<'a> ToArg<'a> for &'a std::io::Error {
fn to_arg(self) -> Arg<'a> {
Arg::String(self.to_string())
}
}
impl<'a> ToArg<'a> for f32 {
fn to_arg(self) -> Arg<'a> {
Arg::Float(self.into())

View File

@@ -221,7 +221,7 @@ pub fn round_to_fractional_digits(&mut self, desired_frac_digits: i32) {
// Round up if necessary.
if self.should_round_up(last_digit_idx, remainder_to_round, mod_base) {
self[last_digit_idx] += mod_base;
// Propogate carry.
// Propagate carry.
while self[last_digit_idx] >= DIGIT_BASE {
self[last_digit_idx] = 0;
last_digit_idx -= 1;

View File

@@ -279,6 +279,8 @@ fn format_a(mut y: f64, params: FormatParams<'_, impl Write>) -> Result<usize, E
// Compute the number of hex digits in the mantissa after the decimal.
// -1 for leading 1 bit (we are to the range [1, 2)), then divide by 4, rounding up.
#[allow(unknown_lints)] // for old clippy
#[allow(clippy::manual_div_ceil)]
const MANTISSA_HEX_DIGITS: usize = (MANTISSA_BITS - 1 + 3) / 4;
if had_prec && prec < MANTISSA_HEX_DIGITS {
// Decide how many least-significant bits to round off the mantissa.
@@ -494,7 +496,7 @@ fn format_mantissa_e(
let digit = if d < decimal.len_i32() { decimal[d] } else { 0 };
let min_width = if d > 0 { DIGIT_WIDTH } else { 1 };
buf.clear();
write!(buf, "{:0width$}", digit, width = min_width)?;
write!(buf, "{digit:0min_width$}")?;
let mut s = buf.as_str();
if d == 0 {
// First digit. Emit it, and likely also a decimal point.

View File

@@ -32,13 +32,12 @@ macro_rules! sprintf {
// Write to a newly allocated String, and return it.
// This panics if the format string or arguments are invalid.
(
$fmt:expr, // Format string, which should implement FormatString.
$($arg:expr),* // arguments
$(,)? // optional trailing comma
$fmt:expr // Format string, which should implement FormatString.
$(, $($arg:expr),*)? // arguments
) => {
{
let mut target = String::new();
$crate::sprintf!(=> &mut target, $fmt, $($arg),*);
$crate::sprintf!(=> &mut target, $fmt $(, $($arg),*)?);
target
}
};
@@ -47,9 +46,8 @@ macro_rules! sprintf {
// The target should implement std::fmt::Write.
(
=> $target:expr, // target string
$fmt:expr, // format string
$($arg:expr),* // arguments
$(,)? // optional trailing comma
$fmt:expr // format string
$(, $($arg:expr),*)? // arguments
) => {
{
// May be no args!
@@ -58,7 +56,7 @@ macro_rules! sprintf {
$crate::printf_c_locale(
$target,
$fmt,
&mut [$($arg.to_arg()),*],
&mut [$( $($arg.to_arg()),* )?],
).unwrap()
}
};
@@ -73,7 +71,7 @@ macro_rules! sprintf {
/// - `args`: Iterator over the arguments to format.
///
/// # Returns
/// A `Result` which is `Ok` containing the number of characters written on success, or an `Error`.
/// A `Result` which is `Ok` containing the width of the string written on success, or an `Error`.
///
/// # Example
///

View File

@@ -5,6 +5,8 @@
use std::fmt::{self, Write};
use std::mem;
use std::result::Result;
use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr;
#[cfg(feature = "widestring")]
use widestring::Utf32Str as wstr;
@@ -382,7 +384,7 @@ pub fn sprintf_locale(
}
// Read field width. We do not support $.
let width = if s.at(0) == Some('*') {
let desired_width = if s.at(0) == Some('*') {
let arg_width = args.next().ok_or(Error::MissingArg)?.as_sint()?;
s.advance_by(1);
if arg_width < 0 {
@@ -397,7 +399,7 @@ pub fn sprintf_locale(
};
// Optionally read precision. We do not support $.
let mut prec: Option<usize> = if s.at(0) == Some('.') && s.at(1) == Some('*') {
let mut desired_precision: Option<usize> = if s.at(0) == Some('.') && s.at(1) == Some('*') {
// "A negative precision is treated as though it were missing."
// Here we assume the precision is always signed.
s.advance_by(2);
@@ -410,7 +412,7 @@ pub fn sprintf_locale(
None
};
// Disallow precisions larger than i32::MAX, in keeping with C.
if prec.unwrap_or(0) > i32::MAX as usize {
if desired_precision.unwrap_or(0) > i32::MAX as usize {
return Err(Error::Overflow);
}
@@ -429,7 +431,7 @@ pub fn sprintf_locale(
// "If a precision is given with a numeric conversion (d, i, o, u, i, x, and X),
// the 0 flag is ignored." p is included here.
let spec_is_numeric = matches!(conv_spec, CS::d | CS::u | CS::o | CS::p | CS::x | CS::X);
if spec_is_numeric && prec.is_some() {
if spec_is_numeric && desired_precision.is_some() {
flags.zero_pad = false;
}
@@ -443,17 +445,26 @@ pub fn sprintf_locale(
CS::e | CS::f | CS::g | CS::a | CS::E | CS::F | CS::G | CS::A => {
// Floating point types handle output on their own.
let float = arg.as_float()?;
let len = format_float(f, float, width, prec, flags, locale, conv_spec, buf)?;
let len = format_float(
f,
float,
desired_width,
desired_precision,
flags,
locale,
conv_spec,
buf,
)?;
out_len = out_len.checked_add(len).ok_or(Error::Overflow)?;
continue 'main;
}
CS::p => {
const PTR_HEX_DIGITS: usize = 2 * mem::size_of::<*const u8>();
prec = prec.map(|p| p.max(PTR_HEX_DIGITS));
desired_precision = desired_precision.map(|p| p.max(PTR_HEX_DIGITS));
let uint = arg.as_uint()?;
if uint != 0 {
prefix = "0x";
write!(buf, "{:x}", uint)?;
write!(buf, "{uint:x}")?;
}
buf
}
@@ -467,9 +478,9 @@ pub fn sprintf_locale(
prefix = if lower { "0x" } else { "0X" };
}
if lower {
write!(buf, "{:x}", uint)?;
write!(buf, "{uint:x}")?;
} else {
write!(buf, "{:X}", uint)?;
write!(buf, "{uint:X}")?;
}
}
buf
@@ -477,17 +488,17 @@ pub fn sprintf_locale(
CS::o => {
let uint = arg.as_uint()?;
if uint != 0 {
write!(buf, "{:o}", uint)?;
write!(buf, "{uint:o}")?;
}
if flags.alt_form && prec.unwrap_or(0) <= buf.len() + 1 {
prec = Some(buf.len() + 1);
if flags.alt_form && desired_precision.unwrap_or(0) <= buf.len() + 1 {
desired_precision = Some(buf.len() + 1);
}
buf
}
CS::u => {
let uint = arg.as_uint()?;
if uint != 0 {
write!(buf, "{}", uint)?;
write!(buf, "{uint}")?;
}
buf
}
@@ -514,10 +525,38 @@ pub fn sprintf_locale(
CS::s => {
// also 'S'
let s = arg.as_str(buf)?;
let p = prec.unwrap_or(s.len()).min(s.len());
prec = Some(p);
flags.zero_pad = false;
&s[..p]
match desired_precision {
Some(precision) => {
// from man printf(3)
// "the maximum number of characters to be printed from a string"
// We interpret this to mean the maximum width when printed, as defined by
// Unicode grapheme cluster width.
let mut byte_len = 0;
let mut width = 0;
let mut graphemes = s.graphemes(true);
// Iteratively add single grapheme clusters as long as the fit within the
// width limited by precision.
while width < precision {
match graphemes.next() {
Some(grapheme) => {
let grapheme_width = grapheme.width();
if width + grapheme_width <= precision {
byte_len += grapheme.len();
width += grapheme_width;
} else {
break;
}
}
None => break,
}
}
let p = precision.min(width);
desired_precision = Some(p);
&s[..byte_len]
}
None => s,
}
}
};
// Numeric output should be empty iff the value is 0.
@@ -528,23 +567,26 @@ pub fn sprintf_locale(
// Decide if we want to apply thousands grouping to the body, and compute its size.
// Note we have already errored out if grouped is set and this is non-numeric.
let wants_grouping = flags.grouped && locale.thousands_sep.is_some();
let body_len = match wants_grouping {
let body_width = match wants_grouping {
// We assume that text representing numbers is ASCII, so len == width.
true => body.len() + locale.separator_count(body.len()),
false => body.len(),
false => body.width(),
};
// Resolve the precision.
// In the case of a non-numeric conversion, update the precision to at least the
// length of the string.
let prec = if !spec_is_numeric {
prec.unwrap_or(body_len)
let desired_precision = if !spec_is_numeric {
desired_precision.unwrap_or(body_width)
} else {
prec.unwrap_or(1).max(body_len)
desired_precision.unwrap_or(1).max(body_width)
};
let prefix_len = prefix.len();
let unpadded_width = prefix_len.checked_add(prec).ok_or(Error::Overflow)?;
let width = width.max(unpadded_width);
let prefix_width = prefix.width();
let unpadded_width = prefix_width
.checked_add(desired_precision)
.ok_or(Error::Overflow)?;
let width = desired_width.max(unpadded_width);
// Pad on the left with spaces to the desired width?
if !flags.left_adj && !flags.zero_pad {
@@ -560,7 +602,8 @@ pub fn sprintf_locale(
}
// Pad on the left to the given precision?
pad(f, '0', prec, body_len)?;
// TODO: why pad with 0 here?
pad(f, '0', desired_precision, body_width)?;
// Output the actual value, perhaps with grouping.
if wants_grouping {

View File

@@ -13,6 +13,7 @@ macro_rules! sprintf_check {
$(,)? // optional trailing comma
) => {
{
use unicode_width::UnicodeWidthStr;
let mut target = String::new();
let mut args = [$($arg.to_arg()),*];
let len = $crate::printf_c_locale(
@@ -20,7 +21,7 @@ macro_rules! sprintf_check {
$fmt.as_ref() as &str,
&mut args,
).expect("printf failed");
assert!(len == target.len(), "Wrong length returned: {} vs {}", len, target.len());
assert_eq!(len, target.width(), "Wrong length returned");
target
}
};
@@ -84,7 +85,7 @@ fn smoke() {
#[test]
fn test_format_string_str() {
let mut s: &str = "hello%world%%%%%";
assert_eq!(s.is_empty(), false);
assert!(!s.is_empty());
for (idx, c) in s.char_indices() {
assert_eq!(s.at(idx), Some(c));
}
@@ -98,7 +99,7 @@ fn test_format_string_str() {
assert_eq!(s.take_literal(&mut buffer), "world%%");
s.advance_by(1); // advancing over one more %
assert_eq!(s.is_empty(), true); // remaining content is empty
assert!(s.is_empty()); // remaining content is empty
}
#[cfg(feature = "widestring")]
@@ -122,7 +123,7 @@ fn test_format_string_wstr() {
assert_eq!(s.take_literal(&mut buffer), "world%%");
s.advance_by(1); // advancing over one more %
assert_eq!(s.is_empty(), true); // remaining content is empty
assert!(s.is_empty()); // remaining content is empty
}
#[test]
@@ -659,6 +660,18 @@ fn test_crate_macros() {
target = crate::sprintf!("%d ok %d", 3, 4);
assert_eq!(target, "3 ok 4");
let target = crate::sprintf!("noargs1");
assert_eq!(target, "noargs1");
let target = crate::sprintf!("noargs1",);
assert_eq!(target, "noargs1");
let mut target = String::new();
crate::sprintf!(=> &mut target, "noargs2");
assert_eq!(target, "noargs2");
let mut target = String::new();
crate::sprintf!(=> &mut target, "noargs2", );
assert_eq!(target, "noargs2");
}
#[test]
@@ -723,6 +736,18 @@ fn test_huge_precision_g() {
sprintf_err!("%.2147483648g", f => Error::Overflow);
}
#[test]
fn test_non_ascii() {
assert_fmt!("%3s", "ö" => " ö");
assert_fmt!("%3s", "🇺🇳" => " 🇺🇳");
assert_fmt!("%.3s", "🇺🇳🇺🇳" => "🇺🇳");
assert_fmt!("%.3s", "a🇺🇳" => "a🇺🇳");
assert_fmt!("%.3s", "aa🇺🇳" => "aa");
assert_fmt!("%3.3s", "aa🇺🇳" => " aa");
assert_fmt!("%.1s", "𒈙a" => "𒈙");
assert_fmt!("%3.3s", "👨‍👨‍👧‍👧" => " 👨‍👨‍👧‍👧");
}
#[test]
fn test_errors() {
use Error::*;
@@ -865,7 +890,7 @@ fn test_exhaustive(rust_fmt: &str, c_fmt: *const c_char) {
// "There's only 4 billion floats so test them all."
// This tests a format string expected to be of the form "%.*g" or "%.*e".
// That is, it takes a precision and a double.
println!("Testing {}", rust_fmt);
println!("Testing {rust_fmt}");
let mut rust_str = String::with_capacity(128);
let mut c_storage = [0u8; 128];
let c_storage_ptr = c_storage.as_mut_ptr() as *mut c_char;

7
debian/control vendored
View File

@@ -20,13 +20,16 @@ Vcs-Browser: https://github.com/fish-shell/fish-shell
Package: fish
Architecture: any
Depends: bsdextrautils,
# for col and lock - bsdmainutils is required in Ubuntu focal
Depends: bsdextrautils | bsdmainutils,
file,
# for the msgfmt command
gettext-base,
groff-base,
# for man
man-db,
# for terminal definitions
ncurses-base,
# for kill
procps,
python3 (>=3.5),
${misc:Depends},

4
debian/copyright vendored
View File

@@ -5,12 +5,12 @@ Source: https://fishshell.com/
Files: *
Copyright: 2005-2009 Axel Liljencrantz <axel@liljencrantz.se>
2009-2024 fish-shell contributors
2009- fish-shell contributors
License: GPL-2
Files: doc_src/python_docs_theme/*
Copyright: 2001-2017 Python Software Foundation
2020-2024 fish-shell contributors
2020- fish-shell contributors
License: Python
Files: share/tools/web_config/js/alpine.js

5
debian/rules vendored
View File

@@ -17,6 +17,9 @@ override_dh_auto_configure:
dh_auto_configure --buildsystem=cmake -- -DCMAKE_BUILD_TYPE=RelWithDebInfo
override_dh_clean:
dh_clean
dh_clean --exclude=Cargo.toml.orig
-unlink .cargo
-unlink vendor
override_dh_auto_test:
make fish_run_tests

View File

@@ -13,10 +13,11 @@ allow = [
"MPL-2.0",
"PSF-2.0",
"Unicode-DFS-2016",
"Unicode-3.0",
"WTFPL",
"Zlib",
]
[sources.allow-org]
# 1 or more github.com organizations to allow git sources for
github = ["fish-shell"]
github = ["fish-shell"]

View File

@@ -23,10 +23,10 @@ Steps:
## Building locally (no code signing)
To build locally without notarizing and code signing, use the `build_tools/make_pkg.sh` script:
To build locally without notarizing and code signing, use the `build_tools/make_macos_pkg.sh` script:
```
> ./build_tools/make_pkg.sh
> ./build_tools/make_macos_pkg.sh
```
Packages will be placed in `~/fish_built` by default.
@@ -45,7 +45,7 @@ You will need the following:
An example run:
```
> ./build_tools/make_pkg.sh -s \
> ./build_tools/make_macos_pkg.sh -s \
-f fish-developer-id-application.p12 \
-i fish-developer-id-installer.p12 \
-p "$NOTARIZE_PASSWORD" \

View File

@@ -15,12 +15,15 @@ Description
``_`` translates its arguments into the current language, if possible.
It is equivalent to ``gettext fish STRING``, meaning it can only be used to look up fish's own translations.
This only works with messages which are translated as part of fish's own sources, so using it as part of your own fish scripts which are not upstreamed into the fish repo will not work unless the exact same message also exists upstream.
It requires fish to be built with gettext support. If that support is disabled, or there is no translation it will simply echo the argument back.
It requires fish to be built with gettext support. If that support is disabled or there is no translation it will echo the argument back.
The language depends on the current locale, set with :envvar:`LANG` and :envvar:`LC_MESSAGES`.
The language depends on the current locale, set with :envvar:`LANG`, :envvar:`LC_MESSAGES`, :envvar:`LC_ALL`, and :envvar:`LANGUAGE`.
These variables do not have to be exported for fish to use them, and fish's variable scopes are supported.
If other programs launched via fish should respect these locale variables they have to be exported to make them available outside of fish.
For :envvar:`LANGUAGE` you can use a list, or use colons to separate multiple languages.
Options
-------
@@ -30,7 +33,20 @@ Options
Examples
--------
::
Use German translations::
> _ File
> set LANG de_DE.UTF-8
> _ file
Datei
Specify a precedence of languages (only works with :envvar:`LANGUAGE`)::
> set LANGUAGE pt de
> _ file # This message has a Portuguese translation.
arquivo
> _ "Invalid arguments" # This message does not have a Portuguese translation, but a German one.
Ungültige Argumente
> _ untranslatable # No translation in Portuguese, nor in German.
untranslatable
Note that the specific examples may change if translations are added/modified.

View File

@@ -14,21 +14,21 @@ Synopsis
Description
-----------
This command makes it easy for fish scripts and functions to handle arguments. You pass arguments that define the known options, followed by a literal **--**, then the arguments to be parsed (which might also include a literal **--**). ``argparse`` then sets variables to indicate the passed options with their values, and sets ``$argv`` to the remaining arguments. See the :ref:`usage <cmd-argparse-usage>` section below.
This command makes it easy for fish scripts and functions to handle arguments. You pass arguments that define the known options, followed by a literal **--**, then the arguments to be parsed (which might also include a literal **--**). ``argparse`` then sets variables to indicate the passed options with their values, sets ``$argv_opts`` to the options and their values, and sets ``$argv`` to the remaining arguments. See the :ref:`usage <cmd-argparse-usage>` section below.
Each option specification (``OPTION_SPEC``) is written in the :ref:`domain specific language <cmd-argparse-option-specification>` described below. All OPTION_SPECs must appear after any argparse flags and before the ``--`` that separates them from the arguments to be parsed.
Each option that is seen in the ARG list will result in variables named ``_flag_X``, where **X** is the short flag letter and the long flag name (if they are defined). For example a **--help** option could cause argparse to define one variable called ``_flag_h`` and another called ``_flag_help``.
The variables will be set with local scope (i.e., as if the script had done ``set -l _flag_X``). If the flag is a boolean (that is, it just is passed or not, it doesn't have a value) the values are the short and long flags seen. If the option is not a boolean the values will be zero or more values corresponding to the values collected when the ARG list is processed. If the flag was not seen the flag variable will not be set.
The variables will be set with local scope (i.e., as if the script had done ``set -l _flag_X``). If the flag is a boolean (that is, it is passed or not, it doesn't have a value) the values are the short and long flags seen. If the option is not a boolean the values will be zero or more values corresponding to the values collected when the ARG list is processed. If the flag was not seen the flag variable will not be set.
Options
-------
The following ``argparse`` options are available. They must appear before all *OPTION_SPEC*\ s:
**-n** or **--name**
The command name for use in error messages. By default the current function name will be used, or ``argparse`` if run outside of a function.
**-n** or **--name** *NAME*
Use *NAME* in error messages. By default the current function name will be used, or ``argparse`` if run outside of a function.
**-x** or **--exclusive** *OPTIONS*
A comma separated list of options that are mutually exclusive. You can use this more than once to define multiple sets of mutually exclusive options.
@@ -40,8 +40,44 @@ The following ``argparse`` options are available. They must appear before all *O
**-X** or **--max-args** *NUMBER*
The maximum number of acceptable non-option arguments. The default is infinity.
**-u** or **--move-unknown**
Allow unknown options, and move them from ``$argv`` to ``$argv_opts``. By default, Unknown options are treated as if they take optional arguments (i.e. have option spec ``=?``).
The above means that if a group of short options contains an unknown short option *followed* by a known short option, the known short option is
treated as an argument to the unknown one (e.g. ``--move-unknown h -- -oh`` will treat ``h`` as the argument to ``-o``, and so ``_flag_h`` will *not* be set).
In contrast, if the known option comes first (and does not take any arguments), the known option will be recognised (e.g. ``argparse --move-unknown h -- -ho`` *will* set ``$_flag_h`` to ``-h``)
**-i** or **--ignore-unknown**
Ignores unknown options, keeping them and their arguments in $argv instead.
Deprecated. This is like **--move-unknown**, except that unknown options and their arguments are kept in ``$argv`` and not moved to ``$argv_opts``. Unlike **--move-unknown**, this option makes it impossible to distinguish between an unknown option and non-option argument that starts with a ``-`` (since any ``--`` seperator in ``$argv`` will be removed).
**-S** or **--strict-longopts**
This makes the parsing of long options more strict. In particular, *without* this flag, if ``long`` is a known long option flag, ``--long`` and ``--long=<value>`` can be abbreviated as:
- ``-long`` and ``-long=<value>``, but *only* if there is no short flag ``l``.
- ``--lo`` and ``--lo=<value>``, but *only* if there is no other long flag that starts with ``lo``. Similarly with any other non-empty prefix of ``long``.
- ``-lo`` and ``-lo=<value>`` (i.e. combining the above two).
With the ``--strict-longopts`` flag, the above three are parse errors: one must use the syntax ``--long`` or ``--long=<value>`` to use a long option called ``long``.
This flag has no effect on the parsing of unknown options (which are parsed as if this flag is on).
This option may be on all the time in the future, so do not rely on the behaviour without it.
**--unknown-arguments** *KIND*
This option implies **--move-unknown**, unless **--ignore-unknown** is also given.
This will modify the parsing behaviour of unknown options depending on the value of *KIND*:
- **optional** (the default), allows each unknown option to take an optional argument (i.e. as if it had ``=?`` or ``=*`` in its option specification). For example, ``argparse --ignore-unknown --unknown-arguments=optional ab -- -u -a -ub`` will set ``_flag_a`` but *not* ``_flag_b``, as the ``b`` is treated as an argument to the second use of ``-u``.
- **required** requires each unknown option to take an argument (i.e. as if it had ``=`` or ``=+`` in its option specification). If the above example was changed to use ``--unknown-arguments=required``, *neither* ``_flag_a`` nor ``_flag_b`` would be set: the ``-a`` will be treated as an argument to the first use of ``-u``, and the ``b`` as an argument to the second.
- **none** forbids each unknown option from taking an argument (i.e. as if it had no ``=`` in its option specification). If the above example was changed to use ``--unknown-arguments=none``, *both* ``_flag_a`` and ``_flag_b`` would be set, as neither use of ``-u`` will be passed as taking an argument.
Note that the above assumes that unknown long flags use the ``--`` "GNU-style" (e.g. if *KIND* is ``none``, and there is no ``bar`` long option, ``-bar`` is interpreted as three short flags, ``b``, ``a``, and ``r``; but if ``bar`` is known, ``-bar`` is treated the same as ``--bar``).
When using ``--unknown-arguments=required``, you will get an error if the provided arguments end in an unknown option, since it has no argument. Similarly, with ``--unknown-arguments=none``, you will get an error if you use the ``--flag=value`` syntax and ``flag`` is an unknown option.
**-s** or **--stop-nonopt**
Causes scanning the arguments to stop as soon as the first non-option argument is seen. Among other things, this is useful to implement subcommands that have their own options.
@@ -91,7 +127,7 @@ But this is not::
set -l argv
argparse 'h/help' 'n/name' $argv
The first ``--`` seen is what allows the ``argparse`` command to reliably separate the option specifications and options to ``argparse`` itself (like ``--ignore-unknown``) from the command arguments, so it is required.
The first ``--`` seen is what allows the ``argparse`` command to reliably separate the option specifications and options to ``argparse`` itself (like ``--move-unknown``) from the command arguments, so it is required.
.. _cmd-argparse-option-specification:
@@ -100,9 +136,13 @@ Option Specifications
Each option specification consists of:
- An optional alphanumeric short flag character, followed by a ``/`` if the short flag can be used by someone invoking your command or, for backwards compatibility, a ``-`` if it should not be exposed as a valid short flag (in which case it will also not be exposed as a flag variable).
- An optional alphanumeric short flag character.
- An optional long flag name, which if not present the short flag can be used, and if that is also not present, an error is reported
- An optional long flag name preceded by a ``/``. If neither a short flag nor long flag are present, an error is reported.
- If there is no short flag, and the long flag name is more than one character, the ``/`` can be omitted.
- For backwards compatibility, if there is a short and a long flag, a ``-`` can be used in place of the ``/``, if the short flag is not to be usable by users (in which case it will also not be exposed as a flag variable).
- Nothing if the flag is a boolean that takes no argument or is an integer flag, or
@@ -110,9 +150,15 @@ Each option specification consists of:
- **=?** if it takes an optional value and only the last instance of the flag is saved, or
- **=+** if it requires a value and each instance of the flag is saved.
- **=+** if it requires a value and each instance of the flag is saved, or
- Optionally a ``!`` followed by fish script to validate the value. Typically this will be a function to run. If the exit status is zero the value for the flag is valid. If non-zero the value is invalid. Any error messages should be written to stdout (not stderr). See the section on :ref:`Flag Value Validation <flag-value-validation>` for more information.
- **=\*** if it takes an optional value *and* each instance of the flag is saved, storing the empty string when the flag was not given a value.
- Optionally a ``&``, indicating that the option and any attached values are not to be saved in ``$argv`` or ``$argv_opts``. This does not affect the the ``_flag_`` variables.
- Nothing if the flag is a boolean that takes no argument, or
- ``!`` followed by fish script to validate the value. Typically this will be a function to run. If the exit status is zero the value for the flag is valid. If non-zero the value is invalid. Any error messages should be written to stdout (not stderr). See the section on :ref:`Flag Value Validation <flag-value-validation>` for more information.
See the :doc:`fish_opt <fish_opt>` command for a friendlier but more verbose way to create option specifications.
@@ -132,7 +178,7 @@ This does not read numbers given as ``+NNN``, only those that look like flags -
Note: Optional arguments
------------------------
An option defined with ``=?`` can take optional arguments. Optional arguments have to be *directly attached* to the option they belong to.
An option defined with ``=?`` or ``=*`` can take optional arguments. Optional arguments have to be *directly attached* to the option they belong to.
That means the argument will only be used for the option if you use it like::
@@ -165,7 +211,7 @@ This isn't specific to argparse but common to all things using ``getopt(3)`` (if
Flag Value Validation
---------------------
Sometimes you need to validate the option values. For example, that it is a valid integer within a specific range, or an ip address, or something entirely different. You can always do this after ``argparse`` returns but you can also request that ``argparse`` perform the validation by executing arbitrary fish script. To do so simply append an ``!`` (exclamation-mark) then the fish script to be run. When that code is executed three vars will be defined:
Sometimes you need to validate the option values. For example, that it is a valid integer within a specific range, or an ip address, or something entirely different. You can always do this after ``argparse`` returns but you can also request that ``argparse`` perform the validation by executing arbitrary fish script. To do so append an ``!`` (exclamation-mark) then the fish script to be run. When that code is executed three vars will be defined:
- ``_argparse_cmd`` will be set to the value of the value of the ``argparse --name`` value.
@@ -177,7 +223,7 @@ These variables are passed to the function as local exported variables.
The script should write any error messages to stdout, not stderr. It should return a status of zero if the flag value is valid otherwise a non-zero status to indicate it is invalid.
Fish ships with a ``_validate_int`` function that accepts a ``--min`` and ``--max`` flag. Let's say your command accepts a ``-m`` or ``--max`` flag and the minimum allowable value is zero and the maximum is 5. You would define the option like this: ``m/max=!_validate_int --min 0 --max 5``. The default if you just call ``_validate_int`` without those flags is to simply check that the value is a valid integer with no limits on the min or max value allowed.
Fish ships with a ``_validate_int`` function that accepts a ``--min`` and ``--max`` flag. Let's say your command accepts a ``-m`` or ``--max`` flag and the minimum allowable value is zero and the maximum is 5. You would define the option like this: ``m/max=!_validate_int --min 0 --max 5``. The default if you call ``_validate_int`` without those flags is to check that the value is a valid integer with no limits on the min or max value allowed.
Here are some examples of flag validations::
@@ -199,16 +245,22 @@ Some *OPTION_SPEC* examples:
- ``help`` means that only ``--help`` is valid. The flag is a boolean and can be used more than once. If it is used then ``_flag_help`` will be set as above. Also ``h-help`` (with an arbitrary short letter) for backwards compatibility.
- ``help&`` is similar (it will *remove* ``--help`` from ``$argv``), the difference is that ``--help``` will *not* placed in ``$argv_opts``.
- ``longonly=`` is a flag ``--longonly`` that requires an option, there is no short flag or even short flag variable.
- ``n/name=`` means that both ``-n`` and ``--name`` are valid. It requires a value and can be used at most once. If the flag is seen then ``_flag_n`` and ``_flag_name`` will be set with the single mandatory value associated with the flag.
- ``n/name=?`` means that both ``-n`` and ``--name`` are valid. It accepts an optional value and can be used at most once. If the flag is seen then ``_flag_n`` and ``_flag_name`` will be set with the value associated with the flag if one was provided else it will be set with no values.
- ``n/name=*`` is similar, but the flag can be used more than once. If the flag is seen then ``_flag_n`` and ``_flag_name`` will be set with the values associated with each occurence. Each value will be the value given to the option, or the empty string if no value was given.
- ``name=+`` means that only ``--name`` is valid. It requires a value and can be used more than once. If the flag is seen then ``_flag_name`` will be set with the values associated with each occurrence.
- ``x`` means that only ``-x`` is valid. It is a boolean that can be used more than once. If it is seen then ``_flag_x`` will be set as above.
- ``/x`` is similar, but only ``--x`` is valid (instead of ``-x``).
- ``x=``, ``x=?``, and ``x=+`` are similar to the n/name examples above but there is no long flag alternative to the short flag ``-x``.
- ``#max`` (or ``#-max``) means that flags matching the regex "^--?\\d+$" are valid. When seen they are assigned to the variable ``_flag_max``. This allows any valid positive or negative integer to be specified by prefixing it with a single "-". Many commands support this idiom. For example ``head -3 /a/file`` to emit only the first three lines of /a/file.
@@ -217,7 +269,7 @@ Some *OPTION_SPEC* examples:
- ``#longonly`` causes the last integer option to be stored in ``_flag_longonly``.
After parsing the arguments the ``argv`` variable is set with local scope to any values not already consumed during flag processing. If there are no unbound values the variable is set but ``count $argv`` will be zero.
After parsing the arguments the ``argv`` variable is set with local scope to any values not already consumed during flag processing. If there are no unbound values the variable is set but ``count $argv`` will be zero. Similarly, the ``argv_opts`` variable is set with local scope to the arguments that *were* consumed during flag processing. This allows forwarding ``$argv_opts`` to another command, together with additional arguments.
If an error occurs during argparse processing it will exit with a non-zero status and print error messages to stderr.
@@ -234,7 +286,7 @@ A simple use::
return 0
end
This just wants one option - ``-h`` / ``--help``. Any other option is an error. If it is given it prints help and exits.
This supports one option - ``-h`` / ``--help``. Any other option is an error. If it is given it prints help and exits.
How :doc:`fish_add_path` parses its args::
@@ -259,17 +311,41 @@ After this it figures out which variable it should operate on according to the `
and set $var $result
Limitations
-----------
An example of using ``$argv_opts`` to forward known options to another command, whilst adding new options::
One limitation with **--ignore-unknown** is that, if an unknown option is given in a group with known options, the entire group will be kept in $argv. ``argparse`` will not do any permutations here.
function my-head
# The following option is the only existing one to head that takes arguments
# (we will forward it verbatim).
set -l opt_spec n/lines=
# --qwords is a new option, but --bytes is an existing one which we will modify below
set -a opt_spec "qwords=&" "c/bytes=&"
argparse --strict-longopts --move-unknown --unknown-arguments=none $opt_spec -- $argv || return
if set -q _flag_qwords
# --qwords allows specifying the size in multiples of 8 bytes
set -a argv_opts --bytes=(math -- $_flag_qwords \* 8 || return)
else if set -q _flag_bytes
# Allows using a 'q' suffix, e.g. --bytes=4q to mean 4*8 bytes.
if string match -qr 'q$' -- $_flag_bytes
set -a argv_opts --bytes=(math -- (string replace -r 'q$' '*8' -- $_flag_bytes) || return)
else
# Keep the users setting
set -a argv_opts --bytes=$_flag_bytes
end
For instance::
end
argparse --ignore-unknown h -- -ho
echo $_flag_h # is -h, because -h was given
echo $argv # is still -ho
if test (count $argv) -eq 0
# Default to heading /dev/kmsg (whereas head defaults to stdin)
set -l argv /dev/kmsg
end
This limitation may be lifted in future.
# Call the real head with our modified options and arguments.
head $argv_opts -- $argv
end
Additionally, it can only parse known options up to the first unknown option in the group - the unknown option could take options, so it isn't clear what any character after an unknown option means.
The argparse call above saves all the options we do *not* want to process in ``$argv_opts``. (The ``--qwords`` and ``--bytes`` options are *not* saved there as their option spec's end in a ``~``). The code then processes the ``--qwords`` and ``--bytess`` options using the the ``$_flag_OPTION`` variables, and puts the transformed options in ``$argv_opts`` (which already contains all the original options, *other* than ``--qwords`` and ``--bytes``).
Note that because the ``argparse`` call above uses ``--move-unknown`` and ``--unknown-arguments=none``, we only need to tell it the arguments to ``head`` that take a value. This allows the wrapper script to accurately work out the *non*-option arguments (i.e. ``$argv``, the filenames that ``head`` is to operate on). Using ``--unknown-arguments=optional`` and explicitly listing all the known options to ``head`` however would have the advantage that if ``head`` were to add new options, they could still be used with the wrapper script using the "stuck" form for arguments (e.g. ``-o<arg>``, or ``--opt=<arg>``).
Note that the ``--strict-longopts`` is required to be able to correctly pass short options, e.g. without it ``my-head -q --bytes 10q``, will actually parse the ``-q`` as shorthand for ``--qwords``.

View File

@@ -9,6 +9,7 @@ Synopsis
.. synopsis::
begin; [COMMANDS ...]; end
{ [COMMANDS ...] }
Description
-----------
@@ -21,6 +22,8 @@ The block is unconditionally executed. ``begin; ...; end`` is equivalent to ``if
``begin`` does not change the current exit status itself. After the block has completed, ``$status`` will be set to the status returned by the most recent command.
Some other shells only support the ``{ [COMMANDS ...] ; }`` notation.
The **-h** or **--help** option displays help about using this command.
Example

View File

@@ -11,6 +11,7 @@ Synopsis
bind [(-M | --mode) MODE] [--preset] [--user] [KEYS]
bind [-a | --all] [--preset] [--user]
bind (-f | --function-names)
bind (-K | --key-names)
bind (-L | --list-modes)
bind (-e | --erase) [(-M | --mode) MODE] [--preset] [--user] [-a | --all] | KEYS ...
@@ -20,10 +21,11 @@ Description
``bind`` manages key bindings.
If both ``KEYS`` and ``COMMAND`` are given, ``bind`` adds (or replaces) a binding in ``MODE``.
If only ``KEYS`` is given, any existing binding in the given ``MODE`` will be printed.
If only ``KEYS`` is given, any existing binding for those keys in the given ``MODE`` will be printed.
If no ``KEYS`` argument is provided, all bindings (in the given ``MODE``) are printed.
``KEYS`` is a comma-separated list of key names.
Modifier keys can be specified by prefixing a key name with a combination of ``ctrl-``, ``alt-`` and ``shift-``.
Modifier keys can be specified by prefixing a key name with a combination of ``ctrl-``, ``alt-``, ``shift-`` and ``super-`` (i.e. the "windows" or "command" key).
For example, pressing :kbd:`w` while holding the Alt modifier is written as ``alt-w``.
Key names are case-sensitive; for example ``alt-W`` is the same as ``alt-shift-w``.
``ctrl-x,ctrl-e`` would mean pressing :kbd:`ctrl-x` followed by :kbd:`ctrl-e`.
@@ -41,9 +43,11 @@ They are:
- ``f1`` through ``f12``.
- ``home``,
- ``insert``,
- ``menu``,
- ``minus`` (``-``),
- ``pageup``,
- ``pagedown``,
- ``printscreen``,
- ``space`` and
- ``tab``,
@@ -58,9 +62,7 @@ To find the name of a key combination you can use :doc:`fish_key_reader <fish_ke
.. note::
If a script changes the commandline, it should finish by calling the ``repaint`` special input function.
If no ``KEYS`` argument is provided, all bindings (in the given ``MODE``) are printed. If ``KEYS`` is provided but no ``COMMAND``, just the binding matching that sequence is printed.
Key bindings may use "modes", which mimics vi's modal input behavior. The default mode is "default". Every key binding applies to a single mode; you can specify which one with ``-M MODE``. If the key binding should change the mode, you can specify the new mode with ``-m NEW_MODE``. The mode can be viewed and changed via the ``$fish_bind_mode`` variable. If you want to change the mode from inside a fish function, use ``set fish_bind_mode MODE``.
Key bindings may use "modes", which mimics vi's modal input behavior. The default mode is "default" (in vi-mode, that's vi's "normal" mode). Every key binding applies to a single mode; you can specify which one with ``-M MODE``. If the key binding should change the mode, you can specify the new mode with ``-m NEW_MODE``. The mode can be viewed and changed via the ``$fish_bind_mode`` variable. If you want to change the mode from inside a fish function, use ``set fish_bind_mode MODE``.
To save custom key bindings, put the ``bind`` statements into :ref:`config.fish <configuration>`. Alternatively, fish also automatically executes a function called ``fish_user_key_bindings`` if it exists.
@@ -71,11 +73,16 @@ The following options are available:
**-f** or **--function-names**
Display a list of available input functions
**-K** or **--key-names**
Display a list of available named keys such as ``backspace``.
**-L** or **--list-modes**
Display a list of defined bind modes
**-M MODE** or **--mode** *MODE*
Specify a bind mode that the bind is used in. Defaults to "default"
Specify a bind mode that the bind is used in. Defaults to "default".
If you use :ref:`vi bindings <vi-mode>`, that's the *command* mode,
what vi calls "normal" mode.
**-m NEW_MODE** or **--sets-mode** *NEW_MODE*
Change the current mode to *NEW_MODE* after this binding is executed
@@ -162,7 +169,7 @@ The following special input functions are available:
start selecting text
``cancel``
close the pager if it is open, or undo the most recent completion if one was just inserted, or otherwise cancel the current commandline and replace it with a new empty one
close the pager if it is open, or undo the most recent completion if one was just inserted
``cancel-commandline``
cancel the current commandline and replace it with a new empty one, leaving the old one in place with a marker to show that it was cancelled
@@ -174,7 +181,13 @@ The following special input functions are available:
empty the entire commandline
``clear-screen``
clears the screen and redraws the prompt. if the terminal doesn't support clearing the screen it is the same as ``repaint``.
clears the screen and redraws the prompt.
.. _special-input-functions-scrollback-push:
``scrollback-push``
pushes earlier output to the terminal scrollback, positioning the prompt at the top.
This requires the terminal to implement the ECMA-48 :ref:`SCROLL UP <term-compat-indn>` command and :ref:`cursor position reporting <term-compat-cursor-position-report>`.
``complete``
guess the remainder of the current token
@@ -240,7 +253,7 @@ The following special input functions are available:
``history-pager``
invoke the searchable pager on history (incremental search); or if the history pager is already active, search further backwards in time.
``history-pager-delete``
``history-delete``
permanently delete the current history item, either from the history pager or from an active up-arrow history search
``history-search-backward``
@@ -261,6 +274,12 @@ The following special input functions are available:
``history-token-search-forward``
search the history for the next matching argument
``history-last-token-search-backward``
search the history for the previous matching last argument
``history-last-token-search-forward``
search the history for the next matching last argument
``forward-jump`` and ``backward-jump``
read another character and jump to its next occurrence after/before the cursor
@@ -409,6 +428,24 @@ Launch ``git diff`` and repaint the commandline afterwards when :kbd:`ctrl-g` is
bind ctrl-g 'git diff' repaint
Swap :kbd:`tab` and :kbd:`shift-tab`, making tab focus the search field.
But if the search field is already active, keep the behavior (:kbd:`tab` cycles forward, :kbd:`shift-tab` backward).::
bind tab '
if commandline --search-field >/dev/null
commandline -f complete
else
commandline -f complete-and-search
end
'
bind shift-tab '
if commandline --search-field >/dev/null
commandline -f complete-and-search
else
commandline -f complete
end
'
.. _cmd-bind-termlimits:
Terminal Limitations

View File

@@ -19,7 +19,7 @@ Description
``break`` halts a currently running loop (*LOOP_CONSTRUCT*), such as a :doc:`for <for>` or :doc:`while <while>` loop. It is usually added inside of a conditional block such as an :doc:`if <if>` block.
There are no parameters for ``break``.
The **-h** or **--help** option displays help about using this command.
Example
-------

View File

@@ -45,8 +45,9 @@ The following options change the way ``commandline`` updates the command line bu
**-a** or **--append**
Do not remove the current commandline, append the specified string at the end of it.
**-i** or **--insert**
Do not remove the current commandline, insert the specified string at the current cursor position
**-i**, **--insert** or **--insert-smart**
Do not remove the current commandline, insert the specified string at the current cursor position.
The **--insert-smart** option turns on a Do-What-I-Mean (DWIM) mode: it strips any **$** prefix from the first command on each line.
**-r** or **--replace**
Remove the current commandline and replace it with the specified string (default)
@@ -73,6 +74,9 @@ The following options change what part of the commandline is printed or updated:
**--search-field**
Use the pager search field instead of the command line. Returns false if the search field is not shown.
**--input=INPUT**
Operate on this string instead of the commandline. Useful for using options like **--tokens-expanded**.
The following options change the way ``commandline`` prints the current commandline buffer:
**-c** or **--cut-at-cursor**
@@ -86,10 +90,7 @@ The following options change the way ``commandline`` prints the current commandl
Perform argument expansion on the selection and print one argument per line.
Command substitutions are not expanded but forwarded as-is.
**--tokens-raw**
Print arguments in the selection as they appear on the command line, one per line.
**-o** or **tokenize**
**-o**, **tokenize**, **--tokens-raw**
Deprecated; do not use.
If ``commandline`` is called during a call to complete a given string using ``complete -C STRING``, ``commandline`` will consider the specified string to be the current contents of the command line.

View File

@@ -63,7 +63,9 @@ The following options are available:
Add a description for this completion, to be shown in the completion pager.
**-w** or **--wraps** *WRAPPED_COMMAND*
Causes the specified command to inherit completions from *WRAPPED_COMMAND* (see below for details).
Causes the specified command to inherit completions from *WRAPPED_COMMAND*.
This is used for "this command completes like that other command" kinds of relationships.
See below for details.
**-n** or **--condition** *CONDITION*
This completion should only be used if the *CONDITION* (a shell command) returns 0. This makes it possible to specify completions that should only be used in some cases. If multiple conditions are specified, fish will try them in the order they are specified until one fails or all succeeded.

View File

@@ -15,6 +15,8 @@ Description
``continue`` skips the remainder of the current iteration of the current inner loop, such as a :doc:`for <for>` loop or a :doc:`while <while>` loop. It is usually added inside of a conditional block such as an :doc:`if <if>` statement or a :doc:`switch <switch>` statement.
The **-h** or **--help** option displays help about using this command.
Example
-------

View File

@@ -24,7 +24,8 @@ The :ref:`tutorial <tutorial>` is available as HTML via ``help tutorial`` or in
The following options are available:
**-c** or **--command=COMMAND**
Evaluate the specified commands instead of reading from the commandline, passing additional positional arguments through ``$argv``.
Evaluate the specified commands instead of reading from the commandline.
Any additional positional arguments are used as ``$argv``.
**-C** or **--init-command=COMMANDS**
Evaluate specified commands after reading the configuration but before executing command specified by **-c** or reading interactive input.
@@ -40,12 +41,6 @@ The following options are available:
**-i** or **--interactive**
The shell is interactive.
**--install[=PATH]**
When built as self-installable (via cargo), this will unpack fish's data files and place them in ``~/.local/share/fish/install/``.
fish will also ask to do this automatically when run interactively.
If PATH is given, fish will install itself into a relocatable directory tree rooted at that path.
That means it will install the data files to PATH/share/fish and copy itself to PATH/bin/fish.
**-l** or **--login**
Act as if invoked as a login shell.
@@ -106,3 +101,33 @@ These options can also be changed via the :envvar:`FISH_DEBUG` and :envvar:`FISH
The categories enabled via **--debug** are *added* to the ones enabled by $FISH_DEBUG, so they can be disabled by prefixing them with **-** (**reader-*,-ast*** enables reader debugging and disables ast debugging).
The file given in **--debug-output** takes precedence over the file in :envvar:`FISH_DEBUG_OUTPUT`.
Examples
--------
To just start fish::
fish
To run a file with fish::
fish /path/to/script.fish
To run some commands with fish::
fish -c 'echo Hi there!'
You can also pass arguments to those commands::
> fish -c 'printf %s\n $argv' "first line" "second line"
first line
second line
To run a script, except read this other file first::
fish --init-cmd "source otherfile" script.fish
To :ref:`profile <profiling>` fish's startup and find what takes the most time in your configuration::
fish --profile-startup /tmp/start.prof -ic exit
sort -nk2 /tmp/start.prof

View File

@@ -29,6 +29,7 @@ Currently supported are:
- ``wl-copy`` using wayland
- ``xsel`` and ``xclip`` for X11
- ``clip.exe`` on Windows.
- The :ref:`OSC 52 clipboard sequence <term-compat-osc-52>`, which your terminal might support
See also
--------

View File

@@ -8,7 +8,7 @@ Synopsis
.. synopsis::
fish_git_prompt
fish_git_prompt [FORMAT]
::
@@ -24,6 +24,8 @@ The ``fish_git_prompt`` function displays information about the current git repo
`Git <https://git-scm.com>`_ must be installed.
It is possible to modify the output format by passing an argument. The default value is ``" (%s)"``.
There are numerous customization options, which can be controlled with git options or fish variables. git options, where available, take precedence over the fish variable with the same function. git options can be set on a per-repository or global basis. git options can be set with the ``git config`` command, while fish variables can be set as usual with the :doc:`set <set>` command.
Boolean options (those which enable or disable something) understand "1", "yes" or "true" to mean true and every other value to mean false.
@@ -108,7 +110,7 @@ Variables used with ``showupstream`` (also implied by informative status):
- ``$__fish_git_prompt_char_upstream_ahead`` (>, ↑) - the character for the commits this repository is ahead of upstream
- ``$__fish_git_prompt_char_upstream_behind`` (<, ↓) - the character for the commits this repository is behind upstream
- ``$__fish_git_prompt_char_upstream_diverged`` (<>) - the symbol if this repository is both ahead and behind upstream
- ``$__fish_git_prompt_char_upstream_diverged`` (<>, ↓↑) - the symbol if this repository is both ahead and behind upstream
- ``$__fish_git_prompt_char_upstream_equal`` (=) - the symbol if this repo is equal to upstream
- ``$__fish_git_prompt_char_upstream_prefix`` ('')
- ``$__fish_git_prompt_color_upstream``

View File

@@ -38,17 +38,11 @@ The following options are available:
Displays the current :program:`fish` version and then exits.
**--ansi**
Colorizes the output using ANSI escape sequences, appropriate for the current :envvar:`TERM`, using the colors defined in the environment (such as :envvar:`fish_color_command`).
Colorizes the output using ANSI escape sequences using the colors defined in the environment (such as :envvar:`fish_color_command`).
**--html**
Outputs HTML, which supports syntax highlighting if the appropriate CSS is defined. The CSS class names are the same as the variable names, such as ``fish_color_command``.
**-d** or **--debug=DEBUG_CATEGORIES**
Enable debug output and specify a pattern for matching debug categories. See :ref:`Debugging <debugging-fish>` in :doc:`fish <fish>` (1) for details.
**-o** or **--debug-output=DEBUG_FILE**
Specify a file path to receive the debug output, including categories and ``fish_trace``. The default is standard error.
**--dump-parse-tree**
Dumps information about the parsed statements to standard error. This is likely to be of interest only to people working on the fish source code.

View File

@@ -22,7 +22,7 @@ Description
The ``fish_mode_prompt`` function outputs the mode indicator for use in vi mode.
The default ``fish_mode_prompt`` function will output indicators about the current vi editor mode displayed to the left of the regular prompt. Define your own function to customize the appearance of the mode indicator. The ``$fish_bind_mode variable`` can be used to determine the current mode. It will be one of ``default``, ``insert``, ``replace_one``, or ``visual``.
The default ``fish_mode_prompt`` function will output indicators about the current vi editor mode displayed to the left of the regular prompt. Define your own function to customize the appearance of the mode indicator. The ``$fish_bind_mode variable`` can be used to determine the current mode. It will be one of ``default``, ``insert``, ``replace_one``, ``replace``, or ``visual``.
You can also define an empty ``fish_mode_prompt`` function to remove the vi mode indicators::
@@ -31,6 +31,8 @@ You can also define an empty ``fish_mode_prompt`` function to remove the vi mode
``fish_mode_prompt`` will be executed when the vi mode changes. If it produces any output, it is displayed and used. If it does not, the other prompt functions (:doc:`fish_prompt <fish_prompt>` and :doc:`fish_right_prompt <fish_right_prompt>`) will be executed as well in case they contain a mode display.
If :envvar:`fish_transient_prompt` is set to 1, ``fish_mode_prompt --final-rendering`` is run before executing the commandline.
Example
-------
@@ -49,6 +51,9 @@ Example
case replace_one
set_color --bold green
echo 'R'
case replace
set_color --bold bryellow
echo 'R'
case visual
set_color --bold brmagenta
echo 'V'

View File

@@ -8,7 +8,7 @@ Synopsis
.. synopsis::
fish_opt [(-slor | --multiple-vals=) OPTNAME]
fish_opt [-s ALPHANUM] [-l LONG-NAME] [-ormd] [--long-only] [-v COMMAND OPTIONS ... ]
fish_opt --help
Description
@@ -18,14 +18,14 @@ This command provides a way to produce option specifications suitable for use wi
The following ``argparse`` options are available:
**-s** or **--short**
Takes a single letter that is used as the short flag in the option being defined. This option is mandatory.
**-s** or **--short** *ALPHANUM*
Takes a single letter or number that is used as the short flag in the option being defined. Either this option or the **--long** option must be provided.
**-l** or **--long**
**-l** or **--long** *LONG-NAME*
Takes a string that is used as the long flag in the option being defined. This option is optional and has no default. If no long flag is defined then only the short flag will be allowed when parsing arguments using the option specification.
**--long-only**
The option being defined will only allow the long flag name to be used. The short flag name must still be defined (i.e., **--short** must be specified) but it cannot be used when parsing arguments using this option specification.
Deprecated. The option being defined will only allow the long flag name to be used, even if the short flag is defined (i.e., **--short** is specified).
**-o** or **--optional-val**
The option being defined can take a value, but it is optional rather than required. If the option is seen more than once when parsing arguments, only the last value seen is saved. This means the resulting flag variable created by ``argparse`` will zero elements if no value was given with the option else it will have exactly one element.
@@ -33,8 +33,15 @@ The following ``argparse`` options are available:
**-r** or **--required-val**
The option being defined requires a value. If the option is seen more than once when parsing arguments, only the last value seen is saved. This means the resulting flag variable created by ``argparse`` will have exactly one element.
**--multiple-vals**
The option being defined requires a value each time it is seen. Each instance is stored. This means the resulting flag variable created by ``argparse`` will have one element for each instance of this option in the arguments.
**-m** or **--multiple-vals**
The value of each instance of the option is accumulated. If **--optional-val** is provided, the value is optional, and an empty string is stored if no value is provided. Otherwise, the **--requiured-val** option is implied and each instance of the option requires a value. This means the resulting flag variable created by ``argparse`` will have one element for each instance of this option in the arguments, even for instances that did not provide a value.
**-d** or **--delete**
The option and any values will be deleted from the ``$argv_opts`` variables set by ``argparse``
(as with other options, it will also be deleted from ``$argv``).
**-v** or **--validate** *COMMAND* *OPTION...*
This option must be the last one, and requires one of ``-o``, ``-r``, or ``-m``. All the remaining arguments are interpreted a fish script to run to validate the value of the argument, see ``argparse`` documentation for more details. Note that the interpretation of *COMMAND* *OPTION...* is similar to ``eval``, so you may need to quote or escape special characters *twice* if you want them to be interpreted literally when the validate script is run.
**-h** or **--help**
Displays help about using this command.
@@ -59,18 +66,25 @@ Same as above but with a second flag that requires a value:
::
set -l options (fish_opt -s h -l help)
set options $options (fish_opt -s m -l max --required-val)
set options $options (fish_opt -s m -l max -r)
argparse $options -- $argv
Same as above but the value of the second flag cannot be the empty string:
Same as above but with a third flag that can be given multiple times saving the value of each instance seen and only the long flag name (``--token``) can be used:
::
set -l options (fish_opt -s h -l help)
set options $options (fish_opt -s m -l max -rv test \$_flag_valu != "''")
argparse $options -- $argv
Same as above but with a third flag that can be given multiple times saving the value of each instance seen and only a long flag name (``--token``) is defined:
::
set -l options (fish_opt --short=h --long=help)
set options $options (fish_opt --short=m --long=max --required-val)
set options $options (fish_opt --short=t --long=token --multiple-vals --long-only)
set options $options (fish_opt --short=m --long=max --required-val --validate test \$_flag_valu != "''")
set options $options (fish_opt --long=token --multiple-vals)
argparse $options -- $argv

View File

@@ -24,6 +24,8 @@ The ``fish_prompt`` function is executed when the prompt is to be shown, and the
The exit status of commands within ``fish_prompt`` will not modify the value of :ref:`$status <variables-status>` outside of the ``fish_prompt`` function.
If :envvar:`fish_transient_prompt` is set to 1, ``fish_prompt --final-rendering`` is run before executing the commandline.
``fish`` ships with a number of example prompts that can be chosen with the ``fish_config`` command.

Some files were not shown because too many files have changed in this diff Show More