Compare commits

...

69 Commits

Author SHA1 Message Date
David Adam
f1456f9707 Release 4.0.2 2025-04-20 21:11:52 +08:00
David Adam
c88e6827b7 CHANGELOG: work on 4.0.2 2025-04-19 00:06:31 +08: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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
Fabian Boehm
303af078f3 Actually disable CSI u in iTerm < 3.5.12
Fixes #11192
2025-02-28 21:15:44 +01:00
56 changed files with 791 additions and 318 deletions

View File

@@ -28,10 +28,10 @@ jobs:
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
ubuntu-32bit-static-pcre2:
@@ -54,10 +54,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:
@@ -92,7 +92,7 @@ jobs:
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
@@ -107,7 +107,7 @@ jobs:
llvm_version=$(clang --version | awk 'NR==1 { split($NF, version, "."); print version[1] }')
export ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-$llvm_version
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
@@ -135,7 +135,7 @@ jobs:
# make
# - name: make fish_run_tests
# run: |
# make fish_run_tests
# make -C build fish_run_tests
macos:
@@ -160,7 +160,7 @@ jobs:
cmake -DWITH_GETTEXT=NO -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

View File

@@ -1,3 +1,52 @@
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)
=======================================

2
Cargo.lock generated
View File

@@ -112,7 +112,7 @@ dependencies = [
[[package]]
name = "fish"
version = "4.0.0"
version = "4.0.2"
dependencies = [
"bitflags",
"cc",

View File

@@ -16,7 +16,7 @@ debug = true
[package]
name = "fish"
version = "4.0.0"
version = "4.0.2"
edition.workspace = true
rust-version.workspace = true
default-run = "fish"

View File

@@ -306,18 +306,23 @@ if (Rust_RESOLVE_RUSTUP_TOOLCHAINS)
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]+(.+)")
# We're going to try to parse the output of `rustup toolchain list --verbose`.
# We expect output like this:
# stable-random-toolchain-junk (parenthesized-random-stuff-like-active-or-default) /path/to/toolchain/blah/more-blah
# In the following regex, we capture the toolchain name, any parenthesized stuff, and then the path.
message(STATUS "Parsing toolchain: ${_TOOLCHAIN_RAW}")
if (_TOOLCHAIN_RAW MATCHES "([^\t ]+)[\t ]*(\\(.*\\))?[\t ]*(.+)")
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\\).*")
if (_TOOLCHAIN_TYPE MATCHES "default")
set(_TOOLCHAIN_DEFAULT "${_TOOLCHAIN}")
endif()
if (_TOOLCHAIN_TYPE MATCHES ".*\\(override\\).*")
if (_TOOLCHAIN_TYPE MATCHES "override")
set(_TOOLCHAIN_OVERRIDE "${_TOOLCHAIN}")
endif()

View File

@@ -23,7 +23,7 @@ If both ``KEYS`` and ``COMMAND`` are given, ``bind`` adds (or replaces) a bindin
If only ``KEYS`` is given, any existing binding in the given ``MODE`` will be 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`.
@@ -99,6 +99,12 @@ The following options are available:
**-s** or **--silent**
Silences some of the error messages, including for unknown key names and unbound sequences.
**-k KEY_NAME** or **--key KEY_NAME**
This looks up KEY_NAME in terminfo and binds that sequence instead of a key that fish would decode.
To view a list of the terminfo keys fish knows about, use ``bind --key-names`` or ``bind -K``.
This is deprecated and provided for compatibility with older fish versions. You should bind the keys directly.
Instead of ``bind -k sright`` use ``bind shift-right``, instead of ``bind -k nul`` use ``bind ctrl-space`` and so on.
**-h** or **--help**
Displays help about using this command.

View File

@@ -26,15 +26,12 @@ The first argument to fish_title contains the most recently executed foreground
This requires that your terminal supports programmable titles and the feature is turned on.
To disable setting the title, use an empty function (see below).
Example
-------
A simple title:
::
A simple title::
function fish_title
set -q argv[1]; or set argv fish
@@ -43,3 +40,7 @@ A simple title:
echo (fish_prompt_pwd_dir_length=1 prompt_pwd): $argv;
end
Do not change the title::
function fish_title
end

View File

@@ -11,6 +11,7 @@ Synopsis
status
status is-login
status is-interactive
status is-interactive-read
status is-block
status is-breakpoint
status is-command-substitution
@@ -50,6 +51,9 @@ The following operations (subcommands) are available:
**is-interactive**, **-i** or **--is-interactive**
Returns 0 if fish is interactive - that is, connected to a keyboard.
**is-interactive-read** or **--is-interactive-read**
Returns 0 if fish is running an interactive :doc:`read <read>` builtin which is connected to a keyboard.
**is-login**, **-l** or **--is-login**
Returns 0 if fish is a login shell - that is, if fish should perform login tasks such as setting up :envvar:`PATH`.

View File

@@ -52,13 +52,13 @@ Match Glob Examples
::
>_ string match '?' a
>_ string match 'a' a
a
>_ string match 'a*b' axxb
axxb
>_ string match -i 'a??B' Axxb
>_ string match -i 'a*B' Axxb
Axxb
>_ string match -- '-*' -h foo --version bar
@@ -67,7 +67,7 @@ Match Glob Examples
-h
--version
>_ echo 'ok?' | string match '*\?'
>_ echo 'ok?' | string match '*?'
ok?
# Note that only the second STRING will match here.
@@ -79,7 +79,7 @@ Match Glob Examples
foo
foo2
>_ string match 'foo?' 'foo1' 'foo' 'foo2'
>_ string match 'foo*' 'foo1' 'foo' 'foo2'
foo1
foo2

View File

@@ -102,33 +102,36 @@ complete -f -c btrfs -n $restore -s S -l symlink -d 'Restore symbolic links'
complete -f -c btrfs -n $restore -s v -l verbose -d Verbose
complete -f -c btrfs -n $restore -s i -l ignore-errors -d 'Ignore errors'
complete -f -c btrfs -n $restore -s o -l overwrite -d Overwrite
complete -f -c btrfs -n $restore -s t -d 'Tree location'
complete -f -c btrfs -n $restore -s f -d 'Filesystem location'
complete -f -c btrfs -n $restore -s u -l super -d 'Super mirror'
complete -f -c btrfs -n $restore -s r -l root -d 'Root objectid'
complete -f -c btrfs -n $restore -s t -r -d 'Tree location'
complete -f -c btrfs -n $restore -s f -r -d 'Filesystem location'
complete -f -c btrfs -n $restore -s u -l super -r -d 'Super mirror'
complete -f -c btrfs -n $restore -s r -l root -r -d 'Root objectid'
complete -f -c btrfs -n $restore -s d -d 'Find dir'
complete -f -c btrfs -n $restore -s l -l list-roots -d 'List tree roots'
complete -f -c btrfs -n $restore -s D -l dry-run -d 'Only list files that would be recovered'
complete -f -c btrfs -n $restore -l path-regex -d 'Restore only filenames matching regex'
complete -f -c btrfs -n $restore -l path-regex -r -d 'Restore only filenames matching regex'
complete -f -c btrfs -n $restore -s c -d 'Ignore case (--path-regex only)'
# btrfs send
complete -f -c btrfs -n $send -s e -d ''
complete -f -c btrfs -n $send -s p -d 'Send an incremental stream from <parent> to <subvol>'
complete -f -c btrfs -n $send -s c -d 'Use this snapshot as a clone source for an incremental send'
complete -f -c btrfs -n $send -s f -d 'Output is normally written to stdout'
complete -f -c btrfs -n $send -s p -r -d 'Send an incremental stream from <parent> to <subvol>'
complete -f -c btrfs -n $send -s c -r -d 'Use this snapshot as a clone source for an incremental send'
complete -f -c btrfs -n $send -s f -r -d 'Output is normally written to stdout'
complete -f -c btrfs -n $send -l no-data -d 'send in NO_FILE_DATA mode'
complete -f -c btrfs -n $send -s v -l verbose -d 'Enable verbose output to stderr'
complete -f -c btrfs -n $send -s q -l quiet -d 'Suppress all messages, except errors'
complete -f -c btrfs -n $send -l proto -a '0 1 2' -r -d 'Use send protocol version'
complete -f -c btrfs -n $send -l proto -l compressed-data -d 'Send compressed data directly'
# btrfs receive
complete -f -c btrfs -n $receive -s v -d 'Increase verbosity about performed actions'
complete -f -c btrfs -n $receive -s q -l quiet -d 'Suppress all messages, except errors'
complete -f -c btrfs -n $receive -s f -d 'Read the stream from FILE instead of stdin'
complete -f -c btrfs -n $receive -s f -r -d 'Read the stream from FILE instead of stdin'
complete -f -c btrfs -n $receive -s e -d 'Terminate after receiving an <end cmd> marker in the stream'
complete -f -c btrfs -n $receive -s C -l chroot -d 'Confine the process to <mount> using chroot'
complete -f -c btrfs -n $receive -s E -l max-errors -d 'Terminate when NUMBER errors occur'
complete -f -c btrfs -n $receive -s m -d 'The root mount point of the destination filesystem'
complete -f -c btrfs -n $receive -s E -l max-errors -r -d 'Terminate when NUMBER errors occur'
complete -f -c btrfs -n $receive -s m -r -d 'The root mount point of the destination filesystem'
complete -f -c btrfs -n $receive -l force-decompress -r -d 'Always decompress data'
complete -f -c btrfs -n $receive -l dump -d 'Dump stream metadata'
# btrfs help
@@ -147,9 +150,11 @@ complete -f -c btrfs -n $subvolume -a show -d 'Show more information about the s
complete -f -c btrfs -n $subvolume -a sync -d 'Wait until given subvolume(s) are completely removed from the filesystem.'
# btrfs subvolume create
complete -f -c btrfs -n '__btrfs_command_groups subvolume create' -s i -d 'Add subvolume to a qgroup (can be given multiple times)'
complete -f -c btrfs -n '__btrfs_command_groups subvolume create' -s p -d 'Create any missing parent directories'
# btrfs subvolume delete
complete -f -c btrfs -n '__btrfs_command_groups subvolume delete' -s c -l commit-after -d 'Wait for transaction commit at the end of the operation'
complete -f -c btrfs -n '__btrfs_command_groups subvolume delete' -s C -l commit-each -d 'Wait for transaction commit after deleting each subvolume'
complete -f -c btrfs -n '__btrfs_command_groups subvolume delete' -s R -l recursive -d 'Delete subvolumes beneath each subvolume recursively'
complete -f -c btrfs -n '__btrfs_command_groups subvolume delete' -s v -l verbose -d 'Verbose output of operations'
# btrfs subvolume list
complete -f -c btrfs -n '__btrfs_command_groups subvolume list' -s o -d 'Print only subvolumes below specified path'
@@ -164,8 +169,8 @@ complete -f -c btrfs -n '__btrfs_command_groups subvolume list' -s s -d 'List on
complete -f -c btrfs -n '__btrfs_command_groups subvolume list' -s r -d 'List readonly subvolumes (including snapshots)'
complete -f -c btrfs -n '__btrfs_command_groups subvolume list' -s d -d 'List deleted subvolumes that are not yet cleaned'
complete -f -c btrfs -n '__btrfs_command_groups subvolume list' -s t -d 'Print the result as a table'
complete -f -c btrfs -n '__btrfs_command_groups subvolume list' -s G -d 'Filter the subvolumes by generation'
complete -f -c btrfs -n '__btrfs_command_groups subvolume list' -s C -d 'Filter the subvolumes by ogeneration'
complete -f -c btrfs -n '__btrfs_command_groups subvolume list' -s G -r -d 'Filter the subvolumes by generation'
complete -f -c btrfs -n '__btrfs_command_groups subvolume list' -s C -r -d 'Filter the subvolumes by ogeneration'
complete -f -c btrfs -n '__btrfs_command_groups subvolume list' -l sort -d 'List the subvolume in order' -a '{gen,ogen,rootid,path}'
# btrfs subvolume snapshot
complete -f -c btrfs -n '__btrfs_command_groups subvolume snapshot' -s r -d 'Create a readonly snapshot'
@@ -194,6 +199,7 @@ complete -f -c btrfs -n $filesystem -a defragment -d 'Defragment a file or a dir
complete -f -c btrfs -n $filesystem -a resize -d 'Resize a filesystem'
complete -f -c btrfs -n $filesystem -a label -d 'Get or change the label of a filesystem'
complete -f -c btrfs -n $filesystem -a usage -d 'Show detailed information about internal filesystem usage.'
complete -f -c btrfs -n $filesystem -a mkswapfile -d 'Create a new swapfile'
# btrfs filesystem df
complete -f -c btrfs -n '__btrfs_command_groups filesystem df' -s b -l raw -d 'Show raw numbers in bytes'
complete -f -c btrfs -n '__btrfs_command_groups filesystem df' -s h -l human-readable -d 'Show human friendly numbers, base 1024'
@@ -230,9 +236,12 @@ complete -f -c btrfs -n '__btrfs_command_groups filesystem defragment' -s v -d '
complete -f -c btrfs -n '__btrfs_command_groups filesystem defragment' -s r -d 'Defragment files recursively'
complete -f -c btrfs -n '__btrfs_command_groups filesystem defragment' -s c -d 'Compress the file while defragmenting' -ra '{zlib,lzo,zstd}'
complete -f -c btrfs -n '__btrfs_command_groups filesystem defragment' -s f -d 'Flush data to disk immediately after defragmenting'
complete -f -c btrfs -n '__btrfs_command_groups filesystem defragment' -s s -d 'Defragment only from NUMBER byte onward'
complete -f -c btrfs -n '__btrfs_command_groups filesystem defragment' -s l -d 'Defragment only up to LEN bytes'
complete -f -c btrfs -n '__btrfs_command_groups filesystem defragment' -s t -d 'Target extent SIZE hint'
complete -f -c btrfs -n '__btrfs_command_groups filesystem defragment' -s s -r -d 'Defragment only from NUMBER byte onward'
complete -f -c btrfs -n '__btrfs_command_groups filesystem defragment' -s l -r -d 'Defragment only up to LEN bytes'
complete -f -c btrfs -n '__btrfs_command_groups filesystem defragment' -s t -r -d 'Target extent SIZE hint'
complete -f -c btrfs -n '__btrfs_command_groups filesystem defragment' -l step -r -d 'Defragment in steps of SIZE'
complete -f -c btrfs -n '__btrfs_command_groups filesystem defragment' -s L -l level -r -d 'Specify compression levels'
# btrfs filesystem usage
complete -f -c btrfs -n '__btrfs_command_groups filesystem usage' -s b -l raw -d 'Show raw numbers in bytes'
complete -f -c btrfs -n '__btrfs_command_groups filesystem usage' -s h -l human-readable -d 'Show human friendly numbers, base 1024'
@@ -244,6 +253,11 @@ complete -f -c btrfs -n '__btrfs_command_groups filesystem usage' -s m -l mbytes
complete -f -c btrfs -n '__btrfs_command_groups filesystem usage' -s g -l gbytes -d 'Show sizes in GiB, or GB with --si'
complete -f -c btrfs -n '__btrfs_command_groups filesystem usage' -s t -l tbytes -d 'Show sizes in TiB, or TB with --si'
complete -f -c btrfs -n '__btrfs_command_groups filesystem usage' -s T -d 'Show data in tabular format'
# btrfs filesystem mkswapfile
complete -f -c btrfs -n '__btrfs_command_groups filesystem mkswapfile' -s s -l size -r -d 'Swapfile size'
complete -f -c btrfs -n '__btrfs_command_groups filesystem mkswapfile' -s U -l uuid -r -d 'UUID for the swapfile'
# btrfs filesystem resize
complete -f -c btrfs -n '__btrfs_command_groups filesystem resize' -l enqueue -d 'Wait for other exclusive operations'
# btrfs balance
complete -f -c btrfs -n $balance -a start -d 'Balance chunks across the devices'
@@ -252,13 +266,23 @@ complete -f -c btrfs -n $balance -a cancel -d 'Cancel running or paused balance'
complete -f -c btrfs -n $balance -a resume -d 'Resume interrupted balance'
complete -f -c btrfs -n $balance -a status -d 'Show status of running or paused balance'
# btrfs balance start
complete -f -c btrfs -n '__btrfs_command_groups balance start' -s d -d 'Act on data chunks with FILTERS'
complete -f -c btrfs -n '__btrfs_command_groups balance start' -s m -d 'Act on metadata chunks with FILTERS'
complete -f -c btrfs -n '__btrfs_command_groups balance start' -s s -d 'Act on system chunks with FILTERS (only under -f)'
function __btrfs_balance_filters
set -l profiles raid{0,1{,c3,c4},10,5,6} dup single
set -l btrfs_balance_filters \
profiles=$profiles\t"Balances only block groups with the given profiles" \
convert=$profiles\t"Convert selected block groups to given profile" \
usage= devid= vrange= limit= strips= soft
set -l prefix (commandline -tc | string replace -r '^-d' -- '' | string match -rg '^(.*?)?[^,]*$' -- $token)
printf "%s\n" "$prefix"$btrfs_balance_filters
end
complete -f -c btrfs -n '__btrfs_command_groups balance start' -s d -ra '(__btrfs_balance_filters)' -d 'Act on data chunks with FILTERS'
complete -f -c btrfs -n '__btrfs_command_groups balance start' -s m -ra '(__btrfs_balance_filters)' -d 'Act on metadata chunks with FILTERS'
complete -f -c btrfs -n '__btrfs_command_groups balance start' -s s -ra '(__btrfs_balance_filters)' -d 'Act on system chunks with FILTERS (only under -f)'
complete -f -c btrfs -n '__btrfs_command_groups balance start' -s v -d 'Be verbose'
complete -f -c btrfs -n '__btrfs_command_groups balance start' -s f -d 'Force a reduction of metadata integrity'
complete -f -c btrfs -n '__btrfs_command_groups balance start' -l full-balance -d 'Do not print warning and do not delay start'
complete -f -c btrfs -n '__btrfs_command_groups balance start' -l background -l bg -d 'Run the balance as a background process'
complete -f -c btrfs -n '__btrfs_command_groups balance start' -l enqueue -d 'Wait for other exclusive operations'
# btrfs balance status
complete -f -c btrfs -n '__btrfs_command_groups balance status' -s v -d 'Be verbose'
@@ -279,6 +303,10 @@ complete -f -c btrfs -n '__btrfs_command_groups device scan' -s u -l forget -d '
# btrfs device stats
complete -f -c btrfs -n '__btrfs_command_groups device stats' -s c -l check -d 'Return non-zero if any stat counter is not zero'
complete -f -c btrfs -n '__btrfs_command_groups device stats' -s z -l reset -d 'Show current stats and reset values to zero'
complete -f -c btrfs -n '__btrfs_command_groups device stats' -s T -d "Print stats in a tabular form"
# btrfs device remove
complete -f -c btrfs -n '__btrfs_command_groups device remove' -l enqueue -d 'Wait for other exclusive operations'
complete -f -c btrfs -n '__btrfs_command_groups device remove' -l force -d 'Skip the safety timeout for removing multiple devices'
# btrfs device usage
complete -f -c btrfs -n '__btrfs_command_groups device usage' -s b -l raw -d 'Show raw numbers in bytes'
complete -f -c btrfs -n '__btrfs_command_groups device usage' -s h -l human-readable -d 'Show human friendly numbers, base 1024'
@@ -295,12 +323,18 @@ complete -f -c btrfs -n $scrub -a start -d 'Start a new scrub. If a scrub is alr
complete -f -c btrfs -n $scrub -a cancel -d 'Cancel a running scrub'
complete -f -c btrfs -n $scrub -a resume -d 'Resume previously canceled or interrupted scrub'
complete -f -c btrfs -n $scrub -a status -d 'Show status of running or finished scrub'
complete -f -c btrfs -n $scrub -a limit -d 'Show or set scrub limits on devices of the given filesystem'
# btrfs scrub limit
complete -f -c btrfs -n '__btrfs_command_groups scrub limit' -s d -l devid -d 'Select the device by DEVID to apply the limit'
complete -f -c btrfs -n '__btrfs_command_groups scrub limit' -s l -l limit -d 'Set the limit of the device'
complete -f -c btrfs -n '__btrfs_command_groups scrub limit' -s a -l all -d 'Apply the limit to all devices'
# btrfs scrub start
complete -f -c btrfs -n '__btrfs_command_groups scrub start' -s B -d 'Do not background'
complete -f -c btrfs -n '__btrfs_command_groups scrub start' -s d -d 'Stats per device (-B only)'
complete -f -c btrfs -n '__btrfs_command_groups scrub start' -s q -d 'Be quiet'
complete -f -c btrfs -n '__btrfs_command_groups scrub start' -s r -d 'Read only mode'
complete -f -c btrfs -n '__btrfs_command_groups scrub start' -s R -d 'Raw print mode, print full data instead of summary'
complete -f -c btrfs -n '__btrfs_command_groups scrub start' -l limit -d 'Set the scrub throughput limit'
complete -f -c btrfs -n '__btrfs_command_groups scrub start' -s c -d 'Set ioprio class (see ionice(1) manpage)'
complete -f -c btrfs -n '__btrfs_command_groups scrub start' -s n -d 'Set ioprio classdata (see ionice(1) manpage)'
complete -f -c btrfs -n '__btrfs_command_groups scrub start' -s f -d 'Force starting new scrub'
@@ -321,6 +355,9 @@ complete -f -c btrfs -n $rescue -a chunk-recover -d 'Recover the chunk tree by s
complete -f -c btrfs -n $rescue -a super-recover -d 'Recover bad superblocks from good copies'
complete -f -c btrfs -n $rescue -a zero-log -d 'Clear the tree log. Usable if it\'s corrupted and prevents mount.'
complete -f -c btrfs -n $rescue -a fix-device-size -d 'Re-align device and super block sizes'
complete -f -c btrfs -n $rescue -a clear-ino-cache -d 'Remove leftover items pertaining to the deprecated inode cache feature'
complete -f -c btrfs -n $rescue -a clear-space-cache -d 'Completely remove the on-disk data of free space cache of given version'
complete -f -c btrfs -n $rescue -a clear-uuid-tree -d 'Clear the UUID tree'
# btrfs rescue chunk-recover
complete -f -c btrfs -n '__btrfs_command_groups rescue chunk-recover' -s y -d 'Assume an answer of YES to all questions'
complete -f -c btrfs -n '__btrfs_command_groups rescue chunk-recover' -s v -d 'Verbose mode'
@@ -337,6 +374,8 @@ complete -f -c btrfs -n $inspect_internal -a min-dev-size -d 'Get the minimum si
complete -f -c btrfs -n $inspect_internal -a dump-tree -d 'Dump tree structures from a given device'
complete -f -c btrfs -n $inspect_internal -a dump-super -d 'Dump superblock from a device in a textual form'
complete -f -c btrfs -n $inspect_internal -a tree-stats -d 'Print various stats for trees'
complete -f -c btrfs -n $inspect_internal -a list-chunks -d 'Enumerate chunks on all devices'
complete -f -c btrfs -n $inspect_internal -a map-swapfile -d 'Find device-specific physical offset of file that can be used for hibernation'
# btrfs inspect-internal inode-resolve
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal inode-resolve' -s v -d 'Verbose mode'
# btrfs inspect-internal logical-resolve
@@ -351,20 +390,50 @@ complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-tree' -s d
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-tree' -s r -l roots -d 'Print only short root node info'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-tree' -s R -l backups -d 'Print short root node info and backup root info'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-tree' -s u -l uuid -d 'Print only the uuid tree'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-tree' -s b -l block -d 'Print info from the specified BLOCK only'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-tree' -s t -l tree -d 'Print only tree with the given ID'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-tree' -s b -l block -r -d 'Print info from the specified BLOCK only'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-tree' -s t -l tree -r -d 'Print only tree with the given ID'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-tree' -l follow -d 'Use with -b, to show all children tree blocks of <block_num>'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-tree' -l noscan -d 'Do not scan the devices from the filesystem'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-tree' -l bfs -d 'Breadth-first traversal of the trees, print nodes, then leaves'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-tree' -l dfs -d 'Depth-first traversal of the trees'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-tree' -l hide-names -d 'Print placeholder instead of names'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-tree' -l csum-headers -d 'Print b-tree node checksums in headers'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-tree' -l csum-items -d 'Print checksums stored in checksum items'
# btrfs inspect-internal dump-super
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-super' -s f -l full -d 'Print full superblock information, backup roots etc.'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-super' -s a -l all -d 'Print information about all superblocks'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-super' -s s -l super -d 'Specify which SUPER-BLOCK copy to print out' -ra '{0,1,2}'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-super' -s F -l force -d 'Attempt to dump superblocks with bad magic'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal dump-super' -l bytenr -d 'Specify alternate superblock OFFSET'
# btrfs inspect-internal logical-resolve
complete -f -c btrfs -n '__btrfs_command_groups logical-resolve' -s P -d 'Print inodes instead of resolving paths'
complete -f -c btrfs -n '__btrfs_command_groups logical-resolve' -s o -d 'Ignore offsets, find all references to an extent'
complete -f -c btrfs -n '__btrfs_command_groups logical-resolve' -s s -r -d 'Set internal buffer size for storing file names'
# btrfs inspect-internal tree-stats
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal tree-stats' -s b -d 'Show raw numbers in bytes'
# btrfs inspect-internal list-chunks
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal list-chunks' -l sort -ra 'devid pstart lstart usage length' -d 'Sort by a column (ascending)'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal list-chunks' -l raw -d 'Show raw numbers in bytes'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal list-chunks' -l human-readable -d 'Show human friendly numbers, base 1024'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal list-chunks' -l iec -d 'Use 1024 as a base (KiB, MiB, GiB, TiB)'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal list-chunks' -l si -d 'Use 1000 as a base (kB, MB, GB, TB)'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal list-chunks' -l kbytes -d 'Show sizes in KiB, or kB with --si'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal list-chunks' -l mbytes -d 'Show sizes in MiB, or MB with --si'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal list-chunks' -l gbytes -d 'Show sizes in GiB, or GB with --si'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal list-chunks' -l tbytes -d 'Show sizes in TiB, or TB with --si'
# btrfs inspect-internal map-swapfile
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal map-swapfile' -l resume-offset -s r -d 'Print the value suitable as resume offset for /sys/power/resume_offset.'
# btrfs inspect-internal tree-stats
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal tree-stats' -s t -r -d 'Print stats only for the given treeid'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal tree-stats' -l raw -s b -d 'Show raw numbers in bytes'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal tree-stats' -l human-readable -d 'Show human friendly numbers, base 1024'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal tree-stats' -l iec -d 'Use 1024 as a base (KiB, MiB, GiB, TiB)'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal tree-stats' -l si -d 'Use 1000 as a base (kB, MB, GB, TB)'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal tree-stats' -l kbytes -d 'Show sizes in KiB, or kB with --si'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal tree-stats' -l mbytes -d 'Show sizes in MiB, or MB with --si'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal tree-stats' -l gbytes -d 'Show sizes in GiB, or GB with --si'
complete -f -c btrfs -n '__btrfs_command_groups inspect-internal tree-stats' -l tbytes -d 'Show sizes in TiB, or TB with --si'
# btrfs property
complete -f -c btrfs -n $property -a get -d 'Get a property value of a btrfs object'
@@ -381,9 +450,12 @@ complete -f -c btrfs -n '__btrfs_command_groups property list' -s t -d 'List pro
complete -f -c btrfs -n $quota -a enable -d 'Enable subvolume quota support for a filesystem.'
complete -f -c btrfs -n $quota -a disable -d 'Disable subvolume quota support for a filesystem.'
complete -f -c btrfs -n $quota -a rescan -d 'Trash all qgroup numbers and scan the metadata again with the current config.'
# btrfs quota enable
complete -f -c btrfs -n '__btrfs_command_groups quota enable' -s s -l simple -d 'Use simple quotas'
# btrfs quota rescan
complete -f -c btrfs -n '__btrfs_command_groups quota rescan' -s s -d 'Show status of a running rescan operation'
complete -f -c btrfs -n '__btrfs_command_groups quota rescan' -s w -d 'Wait for rescan operation to finish'
complete -f -c btrfs -n '__btrfs_command_groups quota rescan' -s s -l status -d 'Show status of a running rescan operation'
complete -f -c btrfs -n '__btrfs_command_groups quota rescan' -s w -l wait -d 'Wait for rescan operation to finish'
complete -f -c btrfs -n '__btrfs_command_groups quota rescan' -s W -l wait-norescan -d 'Wait for rescan to finish without starting it'
# btrfs qgroup
complete -f -c btrfs -n $qgroup -a assign -d 'Assign SRC as the child qgroup of DST'
@@ -391,6 +463,7 @@ complete -f -c btrfs -n $qgroup -a remove -d 'Remove a child qgroup SRC from DST
complete -f -c btrfs -n $qgroup -a create -d 'Create a subvolume quota group.'
complete -f -c btrfs -n $qgroup -a destroy -d 'Destroy a quota group.'
complete -f -c btrfs -n $qgroup -a show -d 'Show subvolume quota groups.'
complete -f -c btrfs -n $qgroup -a clear-stale -d 'Clear all stale qgroups whose subvolume does not exist'
complete -f -c btrfs -n $qgroup -a limit -d 'Set the limits a subvolume quota group.'
# btrfs qgroup assign
complete -f -c btrfs -n '__btrfs_command_groups qgroup assign' -l rescan -d 'Schedule qutoa rescan if needed'
@@ -424,5 +497,7 @@ complete -f -c btrfs -n $replace -a cancel -d 'Cancel a running device replace o
complete -f -c btrfs -n '__btrfs_command_groups replace start' -s r -d 'Only read from <srcdev> if no other zero-defect mirror exists'
complete -f -c btrfs -n '__btrfs_command_groups replace start' -s f -d 'Force using and overwriting <targetdev>'
complete -f -c btrfs -n '__btrfs_command_groups replace start' -s B -d 'Do not background'
complete -f -c btrfs -n '__btrfs_command_groups replace start' -l enqueue -d "Wait if there's another exclusive operation running"
complete -f -c btrfs -n '__btrfs_command_groups replace start' -s K -l nodiscard -d 'Do not perform TRIM on DEVICES'
# btrfs replace status
complete -f -c btrfs -n '__btrfs_command_groups replace status' -s 1 -d 'Only print once until the replace operation finishes'

View File

@@ -3,9 +3,6 @@
## --- WRITTEN MANUALLY ---
set -l __fish_cargo_subcommands (cargo --list 2>&1 | string replace -rf '^\s+([^\s]+)\s*(.*)' '$1\t$2' | string escape)
# Append user-installed extensions (e.g. cargo-foo, invokable as `cargo foo`) to the list of subcommands (à la git)
set -la __fish_cargo_subcommands (complete -C'cargo-' | string replace -rf '^cargo-(\w+).*' '$1')
complete -c cargo -f -c cargo -n __fish_use_subcommand -a "$__fish_cargo_subcommands"
complete -c cargo -x -c cargo -n '__fish_seen_subcommand_from help' -a "$__fish_cargo_subcommands"
@@ -53,27 +50,6 @@ end
complete -c cargo -n '__fish_seen_subcommand_from run test build debug check' -l package \
-xa "(__fish_cargo_packages)"
# Look up crates.io crates matching the single argument provided to this function
function __fish_cargo_search
if test (string length -- "$argv[1]") -le 2
# Don't waste time searching for strings with too many results to realistically
# provide a meaningful completion within our results limit.
return
end
# This doesn't do a prefix search, so bump up the limit a tiny bit to try and
# get enough results to show something.
cargo search --color never --quiet --limit 20 -- $argv[1] 2>/dev/null |
# Filter out placeholders and "... and xxx more crates"
string match -rvi '^\.\.\.|= "0.0.0"|# .*(reserved|yanked)' |
# Remove the version number and map the description
string replace -rf '^([^ ]+).*# (.*)' '$1\t$2'
end
# Complete possible crate names by search the crates.io index
complete -c cargo -n '__fish_seen_subcommand_from add install' -n '__fish_is_nth_token 2' \
-a "(__fish_cargo_search (commandline -ct))"
## --- AUTO-GENERATED WITH `cargo complete fish` ---
# Manually massaged to improve some descriptions
complete -c cargo -n __fish_use_subcommand -l explain -d 'Run `rustc --explain CODE`'

View File

@@ -94,3 +94,6 @@ complete -c cryptsetup -l veracrypt-query-pim -d "Query Personal Iteration Multi
complete -c cryptsetup -l verbose -s v -d "Shows more detailed error messages"
complete -c cryptsetup -l verify-passphrase -s y -d "Verifies the passphrase by asking for it twice"
complete -c cryptsetup -l version -s V -d "Print package version"
# subcommands
complete -c cryptsetup -n "__fish_seen_subcommand_from close status resize" -f -r -a "(path basename /dev/mapper/* | string match -v control)"

View File

@@ -53,7 +53,7 @@ complete -f -c diskutil -n '__fish_diskutil_using_not_subcommand umountDisk' -a
# eject
complete -f -c diskutil -n __fish_use_subcommand -a eject -d 'Eject a volume or disk'
complete -f -c diskutil -n '__fish_diskutil_using_not_subcommand eject' -a '(__fish_diskutil_volumes ; __fish_diskutil_devices)'
complete -f -c diskutil -n '__fish_diskutil_using_not_subcommand eject' -a '(__fish_diskutil_mounted_volumes ; __fish_diskutil_devices)'
# mount
complete -f -c diskutil -n __fish_use_subcommand -a mount -d 'Mount a single volume'

View File

@@ -0,0 +1,27 @@
complete -f -c git -a subtree -d 'Manage git subtrees'
# Git subtree common completions
complete -f -c git -n '__fish_git_using_command subtree' -s q -l quiet -d 'Suppress output'
complete -f -c git -n '__fish_git_using_command subtree' -s d -l debug -d 'Debug output'
complete -f -c git -n '__fish_git_using_command subtree' -s P -l path -d 'Path to the subtree'
# Git subtree subcommands
complete -f -c git -n '__fish_git_using_command subtree' -a add -d "Add a new subtree to the repository"
complete -f -c git -n '__fish_git_using_command subtree' -a merge -d "Merge changes from a subtree into the repository"
complete -f -c git -n '__fish_git_using_command subtree' -a split -d "Extract a subtree from the repository"
complete -f -c git -n '__fish_git_using_command subtree' -a pull -d "Fetch and integrate changes from a remote subtree"
complete -f -c git -n '__fish_git_using_command subtree' -a push -d "Push changes to a remote subtree"
# Completions for push and split subcommands
complete -f -c git -n '__fish_git_using_command subtree; and __fish_seen_subcommand_from push split' -l annotate -d 'Annotate the commit'
complete -f -c git -n '__fish_git_using_command subtree; and __fish_seen_subcommand_from push split' -s b -l branch -d 'Branch to split'
complete -f -c git -n '__fish_git_using_command subtree; and __fish_seen_subcommand_from push split' -l ignore-joins -d 'Ignore joins during history reconstruction'
complete -f -c git -n '__fish_git_using_command subtree; and __fish_seen_subcommand_from push split' -l onto -d 'Specify the commit ID to start history reconstruction'
complete -f -c git -n '__fish_git_using_command subtree; and __fish_seen_subcommand_from push split' -l rejoin -d 'Merge the synthetic history back into the main project'
complete -f -c git -n '__fish_git_using_command subtree; and __fish_seen_subcommand_from push split; and __fish_contains_opt rejoin' -l squash -d 'Merge subtree changes as a single commit'
complete -f -c git -n '__fish_git_using_command subtree; and __fish_seen_subcommand_from push split; and __fish_contains_opt rejoin' -l no-squash -d 'Do not merge subtree changes as a single commit'
complete -f -c git -n '__fish_git_using_command subtree; and __fish_seen_subcommand_from push split; and __fish_contains_opt rejoin' -s m -l message -d 'Use the given message as the commit message for the merge commit'
# Completion for add and merge subcommands
complete -f -c git -n '__fish_git_using_command subtree; and __fish_seen_subcommand_from add merge' -l squash -d 'Merge subtree changes as a single commit'
complete -f -c git -n '__fish_git_using_command subtree; and __fish_seen_subcommand_from add merge' -l no-squash -d 'Do not merge subtree changes as a single commit'
complete -f -c git -n '__fish_git_using_command subtree; and __fish_seen_subcommand_from add merge' -s m -l message -d 'Use the given message as the commit message for the merge commit'

View File

@@ -899,6 +899,15 @@ function __fish_git_is_rebasing
test -e (__fish_git rev-parse --absolute-git-dir)/rebase-merge
end
function __fish_git_filters
printf "%s\n" \
blob:none\t"omits all blobs" \
blob:limit=\t"omits blobs by size" \
object:type={tag,commit,tree,blob}\t"omit object which are not of the requested type" \
sparse:oid=\t"omit blobs not required for a sparse checkout" \
tree:\t"omits all blobs and trees"
end
# general options
complete git -f -l help -s h -d 'Display manual of a Git command'
complete git -f -n __fish_git_needs_command -l version -s v -d 'display git version'
@@ -1033,6 +1042,7 @@ complete -f -c git -n '__fish_git_using_command fetch' -l unshallow -d 'Convert
complete -f -c git -n '__fish_git_using_command fetch' -l refetch -d 'Re-fetch without negotiating common commits'
complete -f -c git -n '__fish_git_using_command fetch' -l negotiation-tip -d 'Only report commits reachable from these tips' -kxa '(__fish_git_commits; __fish_git_branches)'
complete -f -c git -n '__fish_git_using_command fetch' -l negotiate-only -d "Don't fetch, only show commits in common with the server"
complete -f -c git -n '__fish_git_using_command fetch' -l filter -ra '(__fish_git_filters)' -d 'Request a subset of objects from server'
# TODO other options
@@ -1347,6 +1357,7 @@ complete -f -c git -n '__fish_git_using_command clone' -s o -l origin -d 'Use a
complete -f -c git -n '__fish_git_using_command clone' -s b -l branch -d 'Use a specific branch instead of the one used by the cloned repository'
complete -f -c git -n '__fish_git_using_command clone' -l depth -d 'Truncate the history to a specified number of revisions'
complete -f -c git -n '__fish_git_using_command clone' -l recursive -d 'Initialize all submodules within the cloned repository'
complete -f -c git -n '__fish_git_using_command clone' -l filter -ra '(__fish_git_filters)' -d 'Partial clone by requesting a subset of objects from server'
### commit
complete -c git -n __fish_git_needs_command -a commit -d 'Record changes to the repository'
@@ -1595,6 +1606,7 @@ complete -c git -n '__fish_git_using_command log rev-list' -l bisect
complete -c git -n '__fish_git_using_command log rev-list' -l stdin -d 'Read commits from stdin'
complete -c git -n '__fish_git_using_command log rev-list' -l cherry-mark -d 'Mark equivalent commits with = and inequivalent with +'
complete -c git -n '__fish_git_using_command log rev-list' -l cherry-pick -d 'Omit equivalent commits'
complete -f -c git -n '__fish_git_using_command rev-list' -l filter -ra '(__fish_git_filters)' -d 'Omits objects from the list of printed objects'
complete -c git -n '__fish_git_using_command log' -l left-only
complete -c git -n '__fish_git_using_command log' -l right-only
complete -c git -n '__fish_git_using_command log' -l cherry
@@ -1798,6 +1810,8 @@ complete -f -c git -n '__fish_git_using_command merge' -l rerere-autoupdate -d '
complete -f -c git -n '__fish_git_using_command merge' -l no-rerere-autoupdate -d 'Do not use previous conflict resolutions'
complete -f -c git -n '__fish_git_using_command merge' -l abort -d 'Abort the current conflict resolution process'
complete -f -c git -n '__fish_git_using_command merge' -l continue -d 'Conclude current conflict resolution process'
complete -f -c git -n '__fish_git_using_command merge' -l autostash -d 'Before starting merge, stash local changes, and apply stash when done'
complete -f -c git -n '__fish_git_using_command merge' -l no-autostash -d 'Do not stash local changes before starting merge'
### merge-base
complete -f -c git -n __fish_git_needs_command -a merge-base -d 'Find a common ancestor for a merge'
@@ -2278,6 +2292,7 @@ complete -f -c git -n '__fish_git_using_command submodule' -n '__fish_seen_subco
complete -f -c git -n '__fish_git_using_command submodule' -n '__fish_seen_subcommand_from update' -s N -l no-fetch -d "Don't fetch new objects from the remote"
complete -f -c git -n '__fish_git_using_command submodule' -n '__fish_seen_subcommand_from update' -l remote -d "Instead of using superproject's SHA-1, use the state of the submodule's remote-tracking branch"
complete -f -c git -n '__fish_git_using_command submodule' -n '__fish_seen_subcommand_from update' -l force -d "Discard local changes when switching to a different commit & always run checkout"
complete -f -c git -n '__fish_git_using_command submodule' -n '__fish_seen_subcommand_from update' -l filter -ra '(__fish_git_filters)' -d 'Request a subset of objects from server'
complete -f -c git -n '__fish_git_using_command submodule' -n '__fish_seen_subcommand_from add' -l force -d "Also add ignored submodule path"
complete -f -c git -n '__fish_git_using_command submodule' -n '__fish_seen_subcommand_from deinit' -l force -d "Remove even with local changes"
complete -f -c git -n '__fish_git_using_command submodule' -n '__fish_seen_subcommand_from deinit' -l all -d "Remove all submodules"
@@ -2569,11 +2584,11 @@ complete -c git -n __fish_git_needs_command -a '(__fish_git_custom_commands)' -d
function __fish_git_complete_custom_command -a subcommand
set -l cmd (commandline -xpc)
set -e cmd[1] # Drop "git".
set -lx subcommand_args
set -l subcommand_args
if argparse -s (__fish_git_global_optspecs) -- $cmd
set subcommand_args $argv[2..] # Drop the subcommand.
set subcommand_args (string escape -- $argv[2..]) # Drop the subcommand.
end
complete -C "git-$subcommand \$subcommand_args "(commandline -ct)
complete -C "git-$subcommand $subcommand_args "(commandline -ct)
end
# source git-* commands' autocompletion file if exists

View File

@@ -1 +1,10 @@
jj util completion fish | source
# The reason for `__this-command-does-not-exist` is that, if dynamic completion
# is not implemented, we'd like to get an error reliably. However, the
# behavior of `jj` without arguments depends on the value of a config, see
# https://jj-vcs.github.io/jj/latest/config/#default-command
if set -l completion (COMPLETE=fish jj __this-command-does-not-exist 2>/dev/null)
# jj is new enough for dynamic completions to be implemented
printf %s\n $completion | source
else
jj util completion fish | source
end

View File

@@ -1,5 +1,31 @@
# Note that when a completion file is sourced a new block scope is created so `set -l` works.
set -l __fish_status_all_commands basename current-command current-commandline current-filename current-function current-line-number dirname features filename fish-path function is-block is-breakpoint is-command-substitution is-full-job-control is-interactive is-interactive-job-control is-login is-no-job-control job-control line-number print-stack-trace stack-trace test-feature
set -l __fish_status_all_commands \
basename \
buildinfo \
current-command \
current-commandline \
current-filename \
current-function \
current-line-number \
dirname \
features \
filename \
fish-path \
function \
is-block \
is-breakpoint \
is-command-substitution \
is-full-job-control \
is-interactive \
is-interactive-job-control \
is-interactive-read \
is-login \
is-no-job-control \
job-control \
line-number \
print-stack-trace \
stack-trace \
test-feature
# These are the recognized flags.
complete -c status -s h -l help -d "Display help and exit"
@@ -7,6 +33,7 @@ complete -c status -s h -l help -d "Display help and exit"
# The "is-something" subcommands.
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-login -d "Test if this is a login shell"
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-interactive -d "Test if this is an interactive shell"
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-interactive-read -d "Test if inside an interactive read builtin"
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-command-substitution -d "Test if a command substitution is currently evaluated"
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-block -d "Test if a code block is currently evaluated"
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-breakpoint -d "Test if a breakpoint is currently in effect"

View File

@@ -16,9 +16,18 @@ complete -c systemd-analyze -l to-pattern -d 'dot: show relationships matching r
complete -c systemd-analyze -l fuzz -x -d 'critical-chain: also show units which finished timespan earlier than last unit in same level'
complete -c systemd-analyze -l man -xa no -d 'Do not invoke man to verify the existence of man pages'
complete -c systemd-analyze -l generators -d 'Invoke unit generators'
complete -c systemd-analyze -l instance -r -d 'Fallback instance name for template units'
complete -c systemd-analyze -l root -xa "(__fish_complete_directories)" -d 'With cat-files, show config files underneath the specified root path'
complete -c systemd-analyze -l image -r -d 'With cat-files, show config files inside the specified image path'
complete -c systemd-analyze -l image-policy -d 'Disk image dissection policy'
complete -c systemd-analyze -l iterations -x -d 'calendar: show number of iterations the calendar expression will elapse next'
complete -c systemd-analyze -l base-time -x -d 'calendar: show next iterations relative to the specified point in time'
complete -c systemd-analyze -l tldr -d 'cat-config: skip comments, empty lines and section headers'
complete -c systemd-analyze -l unit -r -d "condition: evaluate Condition and Assert assignments in unit file"
complete -c systemd-analyze -l table -d 'plot: output raw time data in a table'
complete -c systemd-analyze -l no-legend -d 'plot: exclude legends/hints'
complete -c systemd-analyze -l detailed -d "plot: show activation timestamps details in SVG plot"
complete -c systemd-analyze -l scale-svg -r -d "plot: stretch the x-axis of the plot"
complete -c systemd-analyze -s H -l host -xa "(__fish_complete_user_at_hosts)" -d 'Execute the operation on a remote host'
complete -c systemd-analyze -s M -l machine -xa "(__fish_systemd_machines)" -d 'Execute operation on a VM or container'
complete -c systemd-analyze -s h -l help -d 'Print a short help and exit'
@@ -34,6 +43,7 @@ complete -c systemd-analyze -n __fish_use_subcommand -a critical-chain -d "Print
complete -c systemd-analyze -n "__fish_seen_subcommand_from critical-chain" -a "(__fish_systemd_units)"
complete -c systemd-analyze -n __fish_use_subcommand -a dump -d "Output serialization of server state"
complete -c systemd-analyze -n __fish_use_subcommand -a malloc -d "Output internal memory state of D-Bus service"
complete -c systemd-analyze -n __fish_use_subcommand -a plot -d "Output SVG graphic showing service initialization"
complete -c systemd-analyze -n __fish_use_subcommand -a dot -d "Output dependency graph in dot(1) format"
complete -c systemd-analyze -n __fish_use_subcommand -a unit-paths -d "List all directories from which unit files may be loaded"
@@ -41,15 +51,25 @@ complete -c systemd-analyze -n __fish_use_subcommand -a exit-status -d "List exi
complete -c systemd-analyze -n __fish_use_subcommand -a capability -d "List Linux capabilities along with their numeric IDs"
complete -c systemd-analyze -n __fish_use_subcommand -a condition -d "Evaluate Condition and Assert assignments"
complete -c systemd-analyze -n __fish_use_subcommand -a syscall-filter -d "List system calls contained in the specified system call set"
complete -c systemd-analyze -n __fish_use_subcommand -a filesystems -d "List filesystems"
complete -c systemd-analyze -n __fish_use_subcommand -a calendar -d "Normalize repetitive calendar events and calculate when they elapse next"
complete -c systemd-analyze -n __fish_use_subcommand -a timestamp -d "Parse timestamp and output the normalized form"
complete -c systemd-analyze -n __fish_use_subcommand -a timestamp -d "Parse time span and output the normalized form"
complete -c systemd-analyze -n __fish_use_subcommand -a timespan -d "Parse time span and output the normalized form"
complete -c systemd-analyze -n __fish_use_subcommand -a cat-config -d "Show contents of a config file"
complete -c systemd-analyze -n "__fish_seen_subcommand_from cat-config" -F
complete -c systemd-analyze -n __fish_use_subcommand -a compare-versions -d "Compare two version strings"
complete -c systemd-analyze -n __fish_use_subcommand -a verify -d "Check unit files for correctness"
complete -c systemd-analyze -n "__fish_seen_subcommand_from verify" -F
complete -c systemd-analyze -n __fish_use_subcommand -a security -d "Analyze security settings of specified service units"
complete -c systemd-analyze -n "__fish_seen_subcommand_from security" -a "(__fish_systemctl_services)"
complete -c systemd-analyze -n __fish_use_subcommand -a inspect-elf -d "Parse and print ELF object packaging metadata"
complete -c systemd-analyze -n __fish_use_subcommand -a fdstore -d "List contents of service unit's file descriptor store"
complete -c systemd-analyze -n __fish_use_subcommand -a image-policy -d "Analyze image policy string"
complete -c systemd-analyze -n __fish_use_subcommand -a has-tpm2 -d "Report TPM2 support"
complete -c systemd-analyze -n __fish_use_subcommand -a pcrs -d "Show known TPM2 PCRs"
complete -c systemd-analyze -n __fish_use_subcommand -a srk -d "Read Storage Root Key from TPM2 device"
complete -c systemd-analyze -n __fish_use_subcommand -a architectures -d "List known CPU architectures"
complete -c systemd-analyze -n __fish_use_subcommand -a smbios11 -d "Show SMBIOS Type #11 strings passed to the system"

View File

@@ -325,7 +325,6 @@ function __fish_wine__complete_winepath_subcommand --argument-names command
end
set -l command wine
complete -c $command -f
complete -c $command -l help -d 'Show help'
complete -c $command -l version -d 'Show version'

View File

@@ -0,0 +1,58 @@
# `wlr-randr` completions.
# See: https://gitlab.freedesktop.org/emersion/wlr-randr
function __fish_print_wlr-randr_outputs --argument-names exclude
if command -q jq
wlr-randr --json | jq \
--raw-output \
--arg exclude "$exclude" \
'.[] | select(.name != $exclude) | "\(.name)\t\(.make), \(.model)"'
end
end
function __fish_get_wlr-randr-current_output
set -l last_output
set -l tokens (commandline -xpc)
while set -q tokens[1]
if test "$tokens[1]" = --output
set last_output "$tokens[2]"
set -e tokens[1]
else if string match -qr -- '^--output=' "$tokens[1]"
set last_output (string replace -r -- '--output=(.*)' '$1' "$tokens[1]")
end
set -e tokens[1]
end
printf "%s" $last_output
end
function __fish_complete_wlr-randr_modes
if command -q jq
set -l output (__fish_get_wlr-randr-current_output)
wlr-randr --json | jq \
--raw-output \
--arg output "$output" \
--arg preferred_str Preferred \
--arg empty_str '' \
'.[] | select(.name == $output) | .modes[] | "\(.width)x\(.height)\t\(if .preferred then $preferred_str else $empty_str end)"'
end
end
complete -c wlr-randr -f
complete -c wlr-randr -s h -l help -d 'Show help'
complete -c wlr-randr -l json -d 'Print as JSON'
complete -c wlr-randr -l dryrun -d 'Dry run'
complete -c wlr-randr -l output -x -d Output -a '(__fish_print_wlr-randr_outputs)'
complete -c wlr-randr -l on -d 'Turn on'
complete -c wlr-randr -l off -d 'Turn off'
complete -c wlr-randr -l mode -x -d Mode -a '(__fish_complete_wlr-randr_modes)'
complete -c wlr-randr -l pos -r -d Position
complete -c wlr-randr -l left-of -x -d 'Relative left position' -a '(__fish_print_wlr-randr_outputs (__fish_get_wlr-randr-current_output))'
complete -c wlr-randr -l right-of -x -d 'Relative right position' -a '(__fish_print_wlr-randr_outputs (__fish_get_wlr-randr-current_output))'
complete -c wlr-randr -l above -x -d 'Relative top position' -a '(__fish_print_wlr-randr_outputs (__fish_get_wlr-randr-current_output))'
complete -c wlr-randr -l below -x -d 'Relative bottom position' -a '(__fish_print_wlr-randr_outputs (__fish_get_wlr-randr-current_output))'
complete -c wlr-randr -l transform -x -d Transformation -a 'normal\t 90\t 180\t 270\t flipped\t flipped-90\t flipped-180\t flipped-270\t'
complete -c wlr-randr -l scale -x -d Scale

View File

@@ -166,13 +166,11 @@ if status --is-login
# Populate path according to config files
for path_file in $argv[2] $argv[3]/*
if test -f $path_file
while read -l entry
if not contains -- $entry $result
test -n "$entry"
and set -a result $entry
end
end <$path_file
for entry in (string split : <? $path_file)
if not contains -- $entry $result
test -n "$entry"
and set -a result $entry
end
end
end

View File

@@ -40,8 +40,7 @@ if test $status -eq 0 -a (count $sysver) -eq 3
if test $age -ge $max_age
test -d "$dir" || mkdir -m 700 -p $dir
/usr/libexec/makewhatis -o "$whatis" (/usr/bin/manpath | string split : | xargs realpath) >/dev/null 2>&1 </dev/null &
disown $last_pid
/bin/sh -c '( "$@" ) >/dev/null 2>&1 </dev/null &' -- /usr/libexec/makewhatis -o "$whatis" (/usr/bin/manpath | string split : | xargs realpath)
end
end
else

View File

@@ -99,9 +99,8 @@ end" >$__fish_config_dir/config.fish
set -l update_args -B $__fish_data_dir/tools/create_manpage_completions.py --manpath --cleanup-in $__fish_user_data_dir/generated_completions --cleanup-in $__fish_cache_dir/generated_completions
if set -l python (__fish_anypython)
# Run python directly in the background and swallow all output
$python $update_args >/dev/null 2>&1 &
# Then disown the job so that it continues to run in case of an early exit (#6269)
disown >/dev/null 2>&1
# Orphan the job so that it continues to run in case of an early exit (#6269)
/bin/sh -c '( "$@" ) >/dev/null 2>&1 &' -- $python $update_args
end
end
end
@@ -221,7 +220,11 @@ end" >$__fish_config_dir/config.fish
# Notify terminals when $PWD changes via OSC 7 (issue #906).
function __fish_update_cwd_osc --on-variable PWD --description 'Notify terminals when $PWD changes'
printf \e\]7\;file://%s%s\a $hostname (string escape --style=url -- $PWD)
set -l host $hostname
if set -q KONSOLE_VERSION
set host ''
end
printf \e\]7\;file://%s%s\a $host (string escape --style=url -- $PWD)
end
__fish_update_cwd_osc # Run once because we might have already inherited a PWD from an old tab

View File

@@ -56,9 +56,13 @@ function __fish_shared_key_bindings -d "Bindings shared between emacs and vi mod
bind --preset $argv alt-right nextd-or-forward-word
bind --preset $argv alt-left prevd-or-backward-word
$legacy_bind --preset $argv \e\[1\;9C nextd-or-forward-word # iTerm2 < 3.5.12
$legacy_bind --preset $argv \e\[1\;9D prevd-or-backward-word # iTerm2 < 3.5.12
bind --preset $argv alt-up history-token-search-backward
bind --preset $argv alt-down history-token-search-forward
$legacy_bind --preset $argv \e\[1\;9A history-token-search-backward # iTerm2 < 3.5.12
$legacy_bind --preset $argv \e\[1\;9B history-token-search-forward # iTerm2 < 3.5.12
# Bash compatibility
# https://github.com/fish-shell/fish-shell/issues/89
bind --preset $argv alt-. history-token-search-backward
@@ -116,7 +120,7 @@ function __fish_shared_key_bindings -d "Bindings shared between emacs and vi mod
bind --preset $argv alt-enter "commandline -i \n" expand-abbr
bind --preset $argv ")" self-insert expand-abbr # Closing a command substitution.
bind --preset $argv ctrl-space 'test -n "$(commandline)" && commandline -i " "'
bind --preset $argv -k nul 'test -n "$(commandline)" && commandline -i " "'
$legacy_bind --preset $argv -k nul 'test -n "$(commandline)" && commandline -i " "'
# Shift-space behaves like space because it's easy to mistype.
bind --preset $argv shift-space 'commandline -i " "' expand-abbr

View File

@@ -180,8 +180,7 @@ if string match -q Darwin -- (uname) && string match -q /usr/bin/git -- (command
else
# git is installed, but on the first run it may be very slow as xcrun needs to populate the cache.
# Kick it off in the background to populate the cache.
/bin/sh -c '/usr/bin/git --version; touch /tmp/__fish_git_ready' &>/dev/null &
disown $last_pid &>/dev/null
/bin/sh -c '( /usr/bin/git --version; touch /tmp/__fish_git_ready ) >/dev/null 2>&1 &'
function __fish_git_prompt_ready
path is /tmp/__fish_git_ready || return 1
# git is ready, erase the function.

View File

@@ -7,16 +7,16 @@ function fish_print_hg_root
# Find an hg directory above $PWD
# without calling `hg root` because that's too slow
set -l root
set -l dir (pwd -P 2>/dev/null)
set -l dir "$(pwd -P 2>/dev/null)"
or return 1
while test $dir != /
while not contains -- "$dir" "" / .
if test -f $dir'/.hg/dirstate'
echo $dir/.hg
return 0
end
# Go up one directory
set dir (string replace -r '[^/]*/?$' '' $dir)
set dir (path dirname -- $dir)
end
return 1

View File

@@ -1,13 +1,11 @@
function fish_vi_cursor -d 'Set cursor shape for different vi modes'
# if stdin is not a tty, there is effectively no bind mode.
if not test -t 0
return
end
set -q fish_cursor_unknown
or set -g fish_cursor_unknown block
function __fish_vi_cursor --argument-names varname
if not status is-interactive; and not status is-interactive-read
return
end
if not set -q $varname
switch $varname
case fish_cursor_insert

View File

@@ -109,18 +109,24 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish'
bind -s --preset -M insert ctrl-n accept-autosuggestion
# Vi/Vim doesn't support these keys in insert mode but that seems silly so we do so anyway.
bind -s --preset -M insert -k home beginning-of-line
bind -s --preset -M default -k home beginning-of-line
bind -s --preset -M insert -k end end-of-line
bind -s --preset -M default -k end end-of-line
bind -s --preset -M insert home beginning-of-line
$legacy_bind -s --preset -M insert -k home beginning-of-line
bind -s --preset -M default home beginning-of-line
$legacy_bind -s --preset -M default -k home beginning-of-line
bind -s --preset -M insert end end-of-line
$legacy_bind -s --preset -M insert -k end end-of-line
bind -s --preset -M default end end-of-line
$legacy_bind -s --preset -M default -k end end-of-line
# Vi moves the cursor back if, after deleting, it is at EOL.
# To emulate that, move forward, then backward, which will be a NOP
# if there is something to move forward to.
bind -s --preset -M default x delete-char 'set fish_cursor_end_mode exclusive' forward-single-char backward-char 'set fish_cursor_end_mode inclusive'
bind -s --preset -M default X backward-delete-char
bind -s --preset -M insert -k dc delete-char forward-single-char backward-char
bind -s --preset -M default -k dc delete-char 'set fish_cursor_end_mode exclusive' forward-single-char backward-char 'set fish_cursor_end_mode inclusive'
bind -s --preset -M insert delete delete-char forward-single-char backward-char
$legacy_bind -s --preset -M insert -k dc delete-char forward-single-char backward-char
bind -s --preset -M default delete delete-char 'set fish_cursor_end_mode exclusive' forward-single-char backward-char 'set fish_cursor_end_mode inclusive'
$legacy_bind -s --preset -M default -k dc delete-char 'set fish_cursor_end_mode exclusive' forward-single-char backward-char 'set fish_cursor_end_mode inclusive'
# Backspace deletes a char in insert mode, but not in normal/default mode.
bind -s --preset -M insert backspace backward-delete-char

View File

@@ -239,8 +239,7 @@ function help --description 'Show help for the fish shell'
# The space before the /c is to prevent msys2 from expanding it to a path
$fish_browser " /c" start $page_url
else if contains -- $fish_browser[1] $graphical_browsers
$fish_browser $page_url &
disown $last_pid >/dev/null 2>&1
/bin/sh -c '( "$@" ) &' -- $fish_browser $page_url
else
$fish_browser $page_url
end

View File

@@ -5,18 +5,17 @@ function fish_prompt -d "Write out the prompt"
set -l laststatus $status
set -l git_info
if set -l git_branch (command git branch --format=%\(refname:lstrip=2\) 2> /dev/null)
if git rev-parse 2>/dev/null
set -l git_branch (
command git symbolic-ref HEAD 2>/dev/null | string replace 'refs/heads/' ''
or command git describe HEAD 2>/dev/null
or echo unknown
)
set git_branch (set_color -o blue)"$git_branch"
set -l git_status
if test -n "$git_branch"; and not command git diff-index --quiet HEAD --
if set -l count (command git rev-list --count --left-right $upstream...HEAD 2>/dev/null)
echo $count | read -l ahead behind
if test "$ahead" -gt 0
set git_status "$git_status"(set_color red)
end
if test "$behind" -gt 0
set git_status "$git_status"(set_color red)
end
end
if git rev-parse --quiet --verify HEAD >/dev/null
and not command git diff-index --quiet HEAD --
for i in (git status --porcelain | string sub -l 2 | sort | uniq)
switch $i
case "."
@@ -35,11 +34,8 @@ function fish_prompt -d "Write out the prompt"
end
else
set git_status (set_color green):
if test -z "$git_branch"
set git_branch -
end
end
set git_info "(git$git_status"(set_color -o blue)"$git_branch"(set_color white)")"
set git_info "(git$git_status$git_branch"(set_color white)")"
end
# Disable PWD shortening by default.

View File

@@ -55,6 +55,7 @@ enum TokenMode {
/// \param buff the original command line buffer
/// \param cursor_pos the position of the cursor in the command line
fn replace_part(
parser: &Parser,
range: Range<usize>,
insert: &wstr,
insert_mode: AppendMode,
@@ -86,9 +87,9 @@ fn replace_part(
out.push_utfstr(&buff[range.end..]);
if search_field_mode {
commandline_set_search_field(out, Some(out_pos));
commandline_set_search_field(parser, out, Some(out_pos));
} else {
commandline_set_buffer(Some(out), Some(out_pos));
commandline_set_buffer(parser, Some(out), Some(out_pos));
}
}
@@ -465,7 +466,7 @@ pub fn commandline(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr])
}
line_offset + new_coord
};
commandline_set_buffer(None, Some(new_pos));
commandline_set_buffer(parser, None, Some(new_pos));
} else {
streams.out.append(sprintf!(
"%d\n",
@@ -631,7 +632,7 @@ pub fn commandline(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr])
.saturating_add_signed(isize::try_from(new_pos).unwrap()),
current_buffer.len(),
);
commandline_set_buffer(None, Some(new_pos));
commandline_set_buffer(parser, None, Some(new_pos));
} else {
streams
.out
@@ -652,6 +653,7 @@ pub fn commandline(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr])
);
} else if positional_args == 1 {
replace_part(
parser,
range,
args[w.wopt_index],
append_mode,
@@ -662,6 +664,7 @@ pub fn commandline(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr])
} else {
let sb = join_strings(&w.argv[w.wopt_index..], '\n');
replace_part(
parser,
range,
&sb,
append_mode,

View File

@@ -517,7 +517,8 @@ pub fn complete(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) ->
next.flags,
faux_cmdline,
&mut tmp_cursor,
false,
/*append_only=*/ false,
/*is_unique=*/ false,
);
// completion_apply_to_command_line will append a space unless COMPLETE_NO_SPACE

View File

@@ -92,6 +92,14 @@ fn parse_cmd_opts(
// A positional argument we got because we use RETURN_IN_ORDER.
let woptarg = w.woptarg.unwrap().to_owned();
if handling_named_arguments {
if is_read_only(&woptarg) {
streams.err.append(wgettext_fmt!(
"%ls: variable '%ls' is read-only\n",
cmd,
woptarg
));
return STATUS_INVALID_ARGS;
}
opts.named_arguments.push(woptarg);
} else {
streams.err.append(wgettext_fmt!(

View File

@@ -12,8 +12,9 @@
use crate::env::Environment;
use crate::env::READ_BYTE_LIMIT;
use crate::env::{EnvVar, EnvVarFlags};
use crate::input_common::decode_input_byte;
use crate::input_common::terminal_protocols_disable_ifn;
use crate::libc::MB_CUR_MAX;
use crate::input_common::DecodeState;
use crate::nix::isatty;
use crate::reader::commandline_set_buffer;
use crate::reader::ReaderConfig;
@@ -23,7 +24,6 @@
use crate::wcstringutil::split_about;
use crate::wcstringutil::split_string_tok;
use crate::wutil;
use crate::wutil::encoding::mbrtowc;
use crate::wutil::encoding::zero_mbstate;
use crate::wutil::perror;
use libc::SEEK_CUR;
@@ -234,7 +234,11 @@ fn read_interactive(
// Keep in-memory history only.
reader_push(parser, L!(""), conf);
commandline_set_buffer(Some(commandline.to_owned()), None);
let _modifiable_commandline = scoped_push_replacer(
|new_value| std::mem::replace(&mut parser.libdata_mut().readonly_commandline, new_value),
false,
);
commandline_set_buffer(parser, Some(commandline.to_owned()), None);
let mline = {
let _interactive = scoped_push_replacer(
@@ -337,70 +341,61 @@ fn read_one_char_at_a_time(
split_null: bool,
) -> Option<c_int> {
let mut exit_res = STATUS_CMD_OK;
let mut eof = false;
let mut nbytes = 0;
let mut unconsumed = vec![];
loop {
let mut finished = false;
let mut res = '\x00';
let mut state = zero_mbstate();
while !finished {
let chars_read = buff.len();
let res = loop {
let mut b = [0_u8; 1];
match read_blocked(fd, &mut b) {
Ok(0) | Err(_) => {
eof = true;
break;
break None;
}
_ => {}
}
let b = b[0];
unconsumed.push(b);
nbytes += 1;
if MB_CUR_MAX() == 1 {
res = char::from(b);
finished = true;
} else {
let sz = unsafe {
mbrtowc(
std::ptr::addr_of_mut!(res).cast(),
std::ptr::addr_of!(b).cast(),
1,
&mut state,
)
} as isize;
if sz == -1 {
let mut consumed = 0;
match decode_input_byte(buff, &mut state, &unconsumed, &mut consumed) {
DecodeState::Incomplete => continue,
DecodeState::Complete => {
unconsumed.clear();
break Some(buff.as_char_slice().last().unwrap());
}
DecodeState::Error => {
state = zero_mbstate();
} else if sz != -2 {
finished = true;
unconsumed.clear();
}
}
}
};
if nbytes > READ_BYTE_LIMIT.load(Ordering::Relaxed) {
// Historical behavior: do not include the codepoint that made us overflow.
buff.truncate(chars_read);
exit_res = STATUS_READ_TOO_MUCH;
break;
}
if eof {
let Some(&res) = res else {
// EOF
if buff.is_empty() {
exit_res = STATUS_CMD_ERROR;
}
break;
};
if res == if split_null { '\0' } else { '\n' } {
buff.pop();
break;
}
if !split_null && res == '\n' {
break;
}
if split_null && res == '\0' {
break;
}
buff.push(res);
if nchars > 0 && nchars <= buff.len() {
break;
}
}
if buff.is_empty() && eof {
exit_res = STATUS_CMD_ERROR;
}
exit_res
}

View File

@@ -6,6 +6,7 @@
use crate::proc::{
get_job_control_mode, get_login, is_interactive_session, set_job_control_mode, JobControl,
};
use crate::reader::reader_in_interactive_read;
use crate::wutil::{waccess, wbasename, wdirname, wrealpath, Error};
use libc::F_OK;
use nix::errno::Errno;
@@ -50,6 +51,7 @@ enum StatusCmd {
STATUS_IS_FULL_JOB_CTRL,
STATUS_IS_INTERACTIVE,
STATUS_IS_INTERACTIVE_JOB_CTRL,
STATUS_IS_INTERACTIVE_READ,
STATUS_IS_LOGIN,
STATUS_IS_NO_JOB_CTRL,
STATUS_LINE_NUMBER,
@@ -82,6 +84,7 @@ enum StatusCmd {
(STATUS_IS_FULL_JOB_CTRL, "is-full-job-control"),
(STATUS_IS_INTERACTIVE, "is-interactive"),
(STATUS_IS_INTERACTIVE_JOB_CTRL, "is-interactive-job-control"),
(STATUS_IS_INTERACTIVE_READ, "is-interactive-read"),
(STATUS_IS_LOGIN, "is-login"),
(STATUS_IS_NO_JOB_CTRL, "is-no-job-control"),
(STATUS_SET_JOB_CONTROL, "job-control"),
@@ -141,6 +144,7 @@ fn default() -> Self {
const IS_FULL_JOB_CTRL_SHORT: char = '\x02';
const IS_INTERACTIVE_JOB_CTRL_SHORT: char = '\x03';
const IS_NO_JOB_CTRL_SHORT: char = '\x04';
const IS_INTERACTIVE_READ_SHORT: char = '\x05';
const SHORT_OPTIONS: &wstr = L!(":L:cbilfnhj:t");
const LONG_OPTIONS: &[WOption] = &[
@@ -162,6 +166,11 @@ fn default() -> Self {
NoArgument,
IS_INTERACTIVE_JOB_CTRL_SHORT,
),
wopt(
L!("is-interactive-read"),
NoArgument,
IS_INTERACTIVE_READ_SHORT,
),
wopt(L!("is-login"), NoArgument, 'l'),
wopt(L!("is-no-job-control"), NoArgument, IS_NO_JOB_CTRL_SHORT),
wopt(L!("job-control"), RequiredArgument, 'j'),
@@ -271,6 +280,11 @@ fn parse_cmd_opts(
return STATUS_CMD_ERROR;
}
}
IS_INTERACTIVE_READ_SHORT => {
if !opts.try_set_status_cmd(STATUS_IS_INTERACTIVE_READ, streams) {
return STATUS_CMD_ERROR;
}
}
IS_NO_JOB_CTRL_SHORT => {
if !opts.try_set_status_cmd(STATUS_IS_NO_JOB_CTRL, streams) {
return STATUS_CMD_ERROR;
@@ -548,6 +562,13 @@ pub fn status(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> O
return STATUS_CMD_ERROR;
}
}
STATUS_IS_INTERACTIVE_READ => {
if reader_in_interactive_read() {
return STATUS_CMD_OK;
} else {
return STATUS_CMD_ERROR;
}
}
STATUS_IS_NO_JOB_CTRL => {
if get_job_control_mode() == JobControl::none {
return STATUS_CMD_OK;

View File

@@ -684,10 +684,11 @@ fn parse_4_arg_expression(
if let Token::UnaryBoolean(token) = first_token {
let subject = self.parse_3_arg_expression(start + 1, end)?;
let range = start..subject.range().end;
UnaryOperator {
subject,
token,
range: start..end,
range,
}
.into_some_box()
} else if first_token == Token::ParenOpen {

View File

@@ -103,6 +103,12 @@ fn test_test() {
assert!(run_test_test(1, &["!", "15", "-ge", "10"]));
assert!(run_test_test(0, &["!", "!", "15", "-ge", "10"]));
assert!(run_test_test(0, &[
"(", "-d", "/", ")",
"-o",
"(", "!", "-d", "/", ")",
]));
assert!(run_test_test(0, &["0", "-ne", "1", "-a", "0", "-eq", "0"]));
assert!(run_test_test(0, &["0", "-ne", "1", "-a", "-n", "5"]));
assert!(run_test_test(0, &["-n", "5", "-a", "10", "-gt", "5"]));

View File

@@ -554,19 +554,16 @@ fn init_curses(vars: &EnvStack) {
if curses::setup(None, |term| apply_term_hacks(vars, term)).is_none() {
if is_interactive_session() {
let term = vars.get_unless_empty(L!("TERM")).map(|v| v.as_string());
// We do not warn for xterm-256color at all, we know that one.
if term != Some("xterm-256color".into()) {
if let Some(term) = term {
FLOG!(
warning,
wgettext_fmt!("Could not set up terminal for $TERM '%ls'. Falling back to hardcoded xterm-256color values", term)
);
} else {
FLOG!(
warning,
wgettext!("Could not set up terminal because $TERM is unset. Falling back to hardcoded xterm-256color values")
);
}
if let Some(term) = term {
FLOG!(
term_support,
wgettext_fmt!("Could not set up terminal for $TERM '%ls'. Falling back to hardcoded xterm-256color values", term)
);
} else {
FLOG!(
term_support,
wgettext!("Could not set up terminal because $TERM is unset. Falling back to hardcoded xterm-256color values")
);
}
}

View File

@@ -369,7 +369,9 @@ fn extract_prefix_and_unescape_yaml(line: &[u8]) -> Option<(Cow<[u8]>, Cow<[u8]>
fn decode_item_fish_2_0(mut data: &[u8]) -> Option<HistoryItem> {
let (advance, line) = read_line(data);
let line = trim_start(line);
assert!(line.starts_with(b"- cmd"));
if !line.starts_with(b"- cmd") {
return None;
}
let (_key, value) = extract_prefix_and_unescape_yaml(line)?;

View File

@@ -21,7 +21,6 @@
use crate::wutil::encoding::{mbrtowc, mbstate_t, zero_mbstate};
use crate::wutil::fish_wcstol;
use std::collections::VecDeque;
use std::ops::ControlFlow;
use std::os::fd::RawFd;
use std::os::unix::ffi::OsStrExt;
use std::ptr;
@@ -332,7 +331,7 @@ fn readb(in_fd: RawFd, blocking: bool) -> ReadbResult {
let select_res = fdset.check_readable(if blocking {
FdReadableSet::kNoTimeout
} else {
0
1000
});
if select_res < 0 {
let err = errno::errno().0;
@@ -437,6 +436,7 @@ pub fn update_wait_on_sequence_key_ms(vars: &EnvStack) {
static IN_ITERM_PRE_CSI_U: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
static IN_JETBRAINS: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
static IN_KITTY: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
static IN_WEZTERM: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
pub fn terminal_protocol_hacks() {
use std::env::var_os;
@@ -457,6 +457,10 @@ pub fn terminal_protocol_hacks() {
);
IN_KITTY
.store(var_os("TERM").is_some_and(|term| term.as_os_str().as_bytes() == b"xterm-kitty"));
IN_WEZTERM.store(
var_os("TERM_PROGRAM")
.is_some_and(|term_program| term_program.as_os_str().as_bytes() == b"WezTerm"),
);
}
fn parse_version(version: &wstr) -> Option<(i64, i64, i64)> {
@@ -487,12 +491,11 @@ pub fn terminal_protocols_enable_ifn() {
|| IN_MIDNIGHT_COMMANDER_PRE_CSI_U.load()
{
"\x1b[?2004h"
} else if IN_ITERM_PRE_CSI_U.load() {
concat!("\x1b[?2004h", "\x1b[>4;1m", "\x1b[>5u", "\x1b=",)
} else if IN_JETBRAINS.load() {
} else if IN_JETBRAINS.load() || IN_ITERM_PRE_CSI_U.load() {
// Jetbrains IDE terminals vomit CSI u
// iTerm fails to option-modify keys
concat!("\x1b[?2004h", "\x1b[>4;1m", "\x1b=",)
} else if IN_KITTY.load() {
} else if IN_KITTY.load() || IN_WEZTERM.load() {
// Kitty spams the log for modifyotherkeys
concat!(
"\x1b[?2004h", // Bracketed paste
@@ -521,11 +524,11 @@ pub(crate) fn terminal_protocols_disable_ifn() {
}
let sequences = if !feature_test(FeatureFlag::keyboard_protocols) {
"\x1b[?2004l"
} else if IN_ITERM_PRE_CSI_U.load() {
concat!("\x1b[?2004l", "\x1b[>4;0m", "\x1b[<1u", "\x1b>",)
} else if IN_JETBRAINS.load() || IN_ITERM_PRE_CSI_U.load() {
concat!("\x1b[?2004l", "\x1b[>4;0m", "\x1b>",)
} else if IN_JETBRAINS.load() {
concat!("\x1b[?2004l", "\x1b[>4;0m", "\x1b>",)
} else if IN_KITTY.load() {
} else if IN_KITTY.load() || IN_WEZTERM.load() {
// Kitty spams the log for modifyotherkeys
concat!(
"\x1b[?2004l", // Bracketed paste
@@ -559,6 +562,7 @@ fn parse_mask(mask: u32) -> Modifiers {
ctrl: (mask & 4) != 0,
alt: (mask & 2) != 0,
shift: (mask & 1) != 0,
sup: (mask & 8) != 0,
}
}
@@ -697,21 +701,25 @@ fn try_readch(&mut self, blocking: bool) -> Option<CharEvent> {
_ => 0,
});
}
match self.parse_codepoint(
&mut state,
&mut key,
match decode_input_byte(
&mut seq,
&buffer,
i,
&mut state,
&buffer[..i + 1],
&mut consumed,
&mut have_escape_prefix,
) {
ControlFlow::Continue(codepoint_complete) => {
if codepoint_complete && i + 1 == buffer.len() {
DecodeState::Incomplete => (),
DecodeState::Complete => {
if have_escape_prefix && i != 0 {
have_escape_prefix = false;
let c = seq.as_char_slice().last().unwrap();
key = Some(Key::from(alt(*c)));
}
if i + 1 == buffer.len() {
break true;
}
}
ControlFlow::Break(()) => {
DecodeState::Error => {
self.push_front(CharEvent::from_check_exit());
break false;
}
}
@@ -785,73 +793,6 @@ fn parse_escape_sequence(
}
}
fn parse_codepoint(
&mut self,
state: &mut mbstate_t,
out_key: &mut Option<Key>,
out_seq: &mut WString,
buffer: &[u8],
i: usize,
consumed: &mut usize,
have_escape_prefix: &mut bool,
) -> ControlFlow<(), bool> {
let mut res: char = '\0';
let read_byte = buffer[i];
if crate::libc::MB_CUR_MAX() == 1 {
// single-byte locale, all values are legal
// FIXME: this looks wrong, this falsely assumes that
// the single-byte locale is compatible with Unicode upper-ASCII.
res = read_byte.into();
out_seq.push(res);
return ControlFlow::Continue(true);
}
let mut codepoint = u32::from(res);
let sz = unsafe {
mbrtowc(
std::ptr::addr_of_mut!(codepoint).cast(),
std::ptr::addr_of!(read_byte).cast(),
1,
state,
)
} as isize;
match sz {
-1 => {
FLOG!(reader, "Illegal input");
*consumed += 1;
self.push_front(CharEvent::from_check_exit());
return ControlFlow::Break(());
}
-2 => {
// Sequence not yet complete.
return ControlFlow::Continue(false);
}
0 => {
// Actual nul char.
*consumed += 1;
out_seq.push('\0');
return ControlFlow::Continue(true);
}
_ => (),
}
if let Some(res) = char::from_u32(codepoint) {
// Sequence complete.
if !fish_reserved_codepoint(res) {
if *have_escape_prefix && i != 0 {
*have_escape_prefix = false;
*out_key = Some(alt(res));
}
*consumed += 1;
out_seq.push(res);
return ControlFlow::Continue(true);
}
}
for &b in &buffer[*consumed..i] {
out_seq.push(encode_byte_to_char(b));
*consumed += 1;
}
ControlFlow::Continue(true)
}
fn parse_csi(&mut self, buffer: &mut Vec<u8>) -> Option<Key> {
let mut next_char = |zelf: &mut Self| zelf.try_readb(buffer).unwrap_or(0xff);
// The maximum number of CSI parameters is defined by NPAR, nominally 16.
@@ -1321,6 +1262,65 @@ fn has_lookahead(&self) -> bool {
}
}
pub(crate) enum DecodeState {
Incomplete,
Complete,
Error,
}
pub(crate) fn decode_input_byte(
out_seq: &mut WString,
state: &mut mbstate_t,
buffer: &[u8],
consumed: &mut usize,
) -> DecodeState {
use DecodeState::*;
let mut res: char = '\0';
let read_byte = *buffer.last().unwrap();
if crate::libc::MB_CUR_MAX() == 1 {
// single-byte locale, all values are legal
// FIXME: this looks wrong, this falsely assumes that
// the single-byte locale is compatible with Unicode upper-ASCII.
res = read_byte.into();
out_seq.push(res);
return Complete;
}
let mut codepoint = u32::from(res);
match unsafe {
mbrtowc(
std::ptr::addr_of_mut!(codepoint).cast(),
std::ptr::addr_of!(read_byte).cast(),
1,
state,
)
} as isize
{
-1 => {
FLOG!(reader, "Illegal input");
*consumed += 1;
return Error;
}
-2 => {
// Sequence not yet complete.
return Incomplete;
}
_ => (),
}
if let Some(res) = char::from_u32(codepoint) {
// Sequence complete.
if !fish_reserved_codepoint(res) {
*consumed += 1;
out_seq.push(res);
return Complete;
}
}
for &b in &buffer[*consumed..] {
out_seq.push(encode_byte_to_char(b));
*consumed += 1;
}
Complete
}
/// A simple, concrete implementation of InputEventQueuer.
pub struct InputEventQueue {
data: InputData,

View File

@@ -54,6 +54,7 @@ pub struct Modifiers {
pub ctrl: bool,
pub alt: bool,
pub shift: bool,
pub sup: bool,
}
impl Modifiers {
@@ -62,6 +63,7 @@ const fn new() -> Self {
ctrl: false,
alt: false,
shift: false,
sup: false,
}
}
pub(crate) const ALT: Self = {
@@ -70,10 +72,10 @@ const fn new() -> Self {
m
};
pub(crate) fn is_some(&self) -> bool {
self.ctrl || self.alt || self.shift
*self != Self::new()
}
pub(crate) fn is_none(&self) -> bool {
!self.is_some()
*self == Self::new()
}
}
@@ -271,6 +273,7 @@ pub(crate) fn parse_keys(value: &wstr) -> Result<Vec<Key>, WString> {
_ if modifier == "ctrl" => modifiers.ctrl = true,
_ if modifier == "alt" => modifiers.alt = true,
_ if modifier == "shift" => modifiers.shift = true,
_ if modifier == "super" => modifiers.sup = true,
_ => {
return Err(wgettext_fmt!(
"unknown modifier '%s' in '%s'",
@@ -407,6 +410,9 @@ fn from(key: Key) -> Self {
if key.modifiers.ctrl {
res.insert_utfstr(0, L!("ctrl-"));
}
if key.modifiers.sup {
res.insert_utfstr(0, L!("super-"));
}
res
}

View File

@@ -1,5 +1,5 @@
// Generic output functions.
use crate::color::RgbColor;
use crate::color::{self, RgbColor};
use crate::common::{self, wcs2string_appending};
use crate::curses::{self, tparm1, Term};
use crate::env::EnvVar;
@@ -456,6 +456,35 @@ pub fn stdoutput() -> &'static RefCell<Outputter> {
}
}
pub struct BufferedOuputter<'a>(&'a mut Outputter);
impl<'a> BufferedOuputter<'a> {
pub fn new(outputter: &'a mut Outputter) -> Self {
outputter.begin_buffering();
Self(outputter)
}
}
impl<'a> Drop for BufferedOuputter<'a> {
fn drop(&mut self) {
self.0.end_buffering();
}
}
impl<'a> Write for BufferedOuputter<'a> {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.0
.write(buf)
.expect("Writing to in-memory buffer should never fail");
Ok(buf.len())
}
fn flush(&mut self) -> Result<()> {
self.0.flush().unwrap();
Ok(())
}
}
/// Given a list of RgbColor, pick the "best" one, as determined by the color support. Returns
/// RgbColor::NONE if empty.
pub fn best_color(candidates: &[RgbColor], support: ColorSupport) -> RgbColor {
@@ -493,6 +522,14 @@ pub fn best_color(candidates: &[RgbColor], support: ColorSupport) -> RgbColor {
/// In particular, the argument parsing still isn't fully capable.
#[allow(clippy::collapsible_else_if)]
pub fn parse_color(var: &EnvVar, is_background: bool) -> RgbColor {
let mut result = parse_color_maybe_none(var, is_background);
if result.is_none() {
result.typ = color::Type::Normal;
}
result
}
pub fn parse_color_maybe_none(var: &EnvVar, is_background: bool) -> RgbColor {
let mut is_bold = false;
let mut is_underline = false;
let mut is_italics = false;
@@ -551,9 +588,6 @@ pub fn parse_color(var: &EnvVar, is_background: bool) -> RgbColor {
}
let mut result = best_color(&candidates, get_color_support());
if result.is_none() {
result = RgbColor::NORMAL;
}
result.set_bold(is_bold);
result.set_underline(is_underline);
result.set_italics(is_italics);

View File

@@ -276,6 +276,9 @@ pub struct LibraryData {
/// Whether we are currently interactive.
pub is_interactive: bool,
/// Whether the command line is closed for modification from fish script.
pub readonly_commandline: bool,
/// Whether to suppress fish_trace output. This occurs in the prompt, event handlers, and key
/// bindings.
pub suppress_fish_trace: bool,

View File

@@ -183,7 +183,7 @@ fn maybe_issue_path_warning(
)
);
}
printf!("\n");
eprintf!("\n");
}
/// Finds the path of an executable named `cmd`, by looking in $PATH taken from `vars`.
@@ -707,7 +707,7 @@ fn path_remoteness(path: &wstr) -> DirRemoteness {
// these are in varying headers. Simply hard code them.
// Note that we treat FUSE filesystems as remote, which means we lock less on such filesystems.
// NOTE: The cast is necessary for 32-bit systems because of the 4-byte CIFS_MAGIC_NUMBER
match usize::try_from(buf.f_type).unwrap() {
match buf.f_type as usize {
0x5346414F | // AFS_SUPER_MAGIC - Andrew File System
0x6B414653 | // AFS_FS_MAGIC - Kernel AFS and AuriStorFS
0x73757245 | // CODA_SUPER_MAGIC - Coda File System

View File

@@ -88,6 +88,8 @@
use crate::nix::isatty;
use crate::operation_context::{get_bg_context, OperationContext};
use crate::output::parse_color;
use crate::output::parse_color_maybe_none;
use crate::output::BufferedOuputter;
use crate::output::Outputter;
use crate::pager::{PageRendering, Pager, SelectionMotion};
use crate::panic::AT_EXIT;
@@ -221,6 +223,13 @@ unsafe impl Sync for ReaderDataStack {}
unsafe { &mut *READER_DATA_STACK.0.get() }
}
pub fn reader_in_interactive_read() -> bool {
reader_data_stack()
.iter()
.rev()
.any(|reader| reader.conf.exit_on_interrupt)
}
/// Access the top level reader data.
pub fn current_data() -> Option<&'static mut ReaderData> {
reader_data_stack()
@@ -650,8 +659,13 @@ fn read_i(parser: &Parser) -> i32 {
data.command_line.clear();
data.update_buff_pos(EditableLineTag::Commandline, None);
data.command_line_changed(EditableLineTag::Commandline);
// OSC 133 End of command
data.screen.write_bytes(b"\x1b]133;C\x07");
// OSC 133 "Command start"
write!(
BufferedOuputter::new(&mut Outputter::stdoutput().borrow_mut()),
"\x1b]133;C;cmdline_url={}\x07",
escape_string(&command, EscapeStringStyle::Url),
)
.unwrap();
event::fire_generic(parser, L!("fish_preexec").to_owned(), vec![command.clone()]);
let eval_res = reader_run_command(parser, &command);
signal_clear_cancel();
@@ -664,11 +678,12 @@ fn read_i(parser: &Parser) -> i32 {
parser.libdata_mut().exit_current_script = false;
// OSC 133 "Command finished"
let _ = write!(
Outputter::stdoutput().borrow_mut(),
write!(
BufferedOuputter::new(&mut Outputter::stdoutput().borrow_mut()),
"\x1b]133;D;{}\x07",
parser.get_last_status()
);
)
.unwrap();
event::fire_generic(parser, L!("fish_postexec").to_owned(), vec![command]);
// Allow any pending history items to be returned in the history array.
data.history.resolve_pending();
@@ -940,6 +955,9 @@ pub fn reader_schedule_prompt_repaint() {
}
pub fn reader_execute_readline_cmd(parser: &Parser, ch: CharEvent) {
if parser.libdata().readonly_commandline {
return;
}
if let Some(data) = current_data() {
let mut data = Reader { parser, data };
let CharEvent::Readline(readline_cmd_evt) = &ch else {
@@ -1018,7 +1036,10 @@ pub fn commandline_get_state(sync: bool) -> CommandlineState {
/// Set the command line text and position. This may be called on a background thread; the reader
/// will pick it up when it is done executing.
pub fn commandline_set_buffer(text: Option<WString>, cursor_pos: Option<usize>) {
pub fn commandline_set_buffer(parser: &Parser, text: Option<WString>, cursor_pos: Option<usize>) {
if parser.libdata().readonly_commandline {
return;
}
{
let mut state = commandline_state_snapshot();
if let Some(text) = text {
@@ -1029,7 +1050,10 @@ pub fn commandline_set_buffer(text: Option<WString>, cursor_pos: Option<usize>)
current_data().map(|data| data.apply_commandline_state_changes());
}
pub fn commandline_set_search_field(text: WString, cursor_pos: Option<usize>) {
pub fn commandline_set_search_field(parser: &Parser, text: WString, cursor_pos: Option<usize>) {
if parser.libdata().readonly_commandline {
return;
}
{
let mut state = commandline_state_snapshot();
assert!(state.search_field.is_some());
@@ -1499,8 +1523,15 @@ fn paint_layout(&mut self, reason: &wstr, is_final_rendering: bool) {
range.end = colors.len();
}
let explicit_foreground = self
.vars()
.get_unless_empty(L!("fish_color_search_match"))
.is_some_and(|var| !parse_color_maybe_none(&var, false).is_none());
for color in &mut colors[range] {
color.foreground = HighlightRole::search_match;
if explicit_foreground {
color.foreground = HighlightRole::search_match;
}
color.background = HighlightRole::search_match;
}
}
@@ -2325,7 +2356,12 @@ fn handle_readline_command(&mut self, c: ReadlineCmd) {
if c == rl::CancelCommandline {
// Move cursor to the end of the line.
let end = self.command_line.len();
self.update_buff_pos(EditableLineTag::Commandline, Some(end));
{
let tmp =
std::mem::replace(&mut self.cursor_end_mode, CursorEndMode::Exclusive);
self.update_buff_pos(EditableLineTag::Commandline, Some(end));
self.cursor_end_mode = tmp;
}
self.autosuggestion.clear();
// Repaint also changes the actual cursor position
@@ -2570,7 +2606,7 @@ fn handle_readline_command(&mut self, c: ReadlineCmd) {
self.data
.insert_string(self.active_edit_line_tag(), &yank_str);
self.rls_mut().yank_len = yank_str.len();
if self.cursor_end_mode == CursorEndMode::Inclusive {
if !yank_str.is_empty() && self.cursor_end_mode == CursorEndMode::Inclusive {
let (_elt, el) = self.active_edit_line();
self.update_buff_pos(self.active_edit_line_tag(), Some(el.position() - 1));
}
@@ -3669,8 +3705,11 @@ fn clear_pager(&mut self) {
fn get_selection(&self) -> Option<Range<usize>> {
let selection = self.selection?;
let start = selection.start;
let start = std::cmp::min(selection.start, self.command_line.len());
let end = std::cmp::min(selection.stop, self.command_line.len());
if start == end {
return None;
}
Some(start..end)
}
@@ -3750,6 +3789,7 @@ fn pager_selection_changed(&mut self) {
&self.cycle_command_line,
&mut cursor_pos,
false,
/*is_unique=*/ false, // don't care
),
};
@@ -4065,7 +4105,10 @@ fn reader_interactive_init(parser: &Parser) {
terminal_protocol_hacks();
IN_MIDNIGHT_COMMANDER_PRE_CSI_U.store(
parser.vars().get_unless_empty(L!("MC_TMPDIR")).is_some()
&& parser.vars().get_unless_empty(L!("__mc_csi_u")).is_none(),
&& parser
.vars()
.get_unless_empty(L!("__mc_kitty_keyboard"))
.is_none(),
);
}
@@ -4384,6 +4427,7 @@ fn get_autosuggestion_performer(
&search_string,
&mut cursor,
/*append_only=*/ true,
/*is_unique=*/ false,
);
}
result
@@ -4790,7 +4834,9 @@ fn fill_history_pager(
if search_term != zelf.pager.search_field_line.text() {
return; // Stale request.
}
let history_pager = zelf.history_pager.as_mut().unwrap();
let Some(history_pager) = zelf.history_pager.as_mut() else {
return; // Pager has been closed.
};
history_pager.direction = direction;
match direction {
SearchDirection::Forward => {
@@ -4859,6 +4905,10 @@ fn expand_replacer(
|new_value| std::mem::replace(&mut parser.libdata_mut().is_interactive, new_value),
false,
);
let _readonly_commandline = scoped_push_replacer(
|new_value| std::mem::replace(&mut parser.libdata_mut().readonly_commandline, new_value),
true,
);
let mut outputs = vec![];
let ret = exec_subshell(
@@ -5567,6 +5617,7 @@ pub fn completion_apply_to_command_line(
command_line: &wstr,
inout_cursor_pos: &mut usize,
append_only: bool,
is_unique: bool,
) -> WString {
let add_space = !flags.contains(CompleteFlags::NO_SPACE);
let do_replace_token = flags.contains(CompleteFlags::REPLACES_TOKEN);
@@ -5591,7 +5642,7 @@ pub fn completion_apply_to_command_line(
}
let mut escape_flags = EscapeFlags::empty();
if append_only || !add_space {
if append_only || !is_unique || !add_space {
escape_flags.insert(EscapeFlags::NO_QUOTED);
}
if no_tilde {
@@ -5839,7 +5890,12 @@ fn try_insert(&mut self, c: Completion, tok: &wstr, token_range: Range<usize>) {
// If this is a replacement completion, check that we know how to replace it, e.g. that
// the token doesn't contain evil operators like {}.
if !c.flags.contains(CompleteFlags::REPLACES_TOKEN) || reader_can_replace(tok, c.flags) {
self.completion_insert(&c.completion, token_range.end, c.flags);
self.completion_insert(
&c.completion,
token_range.end,
c.flags,
/*is_unique=*/ true,
);
}
}
@@ -5975,7 +6031,12 @@ fn handle_completions(&mut self, token_range: Range<usize>) -> bool {
if prefix_is_partial_completion {
flags |= CompleteFlags::NO_SPACE;
}
self.completion_insert(&common_prefix, token_range.end, flags);
self.completion_insert(
&common_prefix,
token_range.end,
flags,
/*is_unique=*/ false,
);
self.cycle_command_line = self.command_line.text().to_owned();
self.cycle_cursor_pos = self.command_line.position();
}
@@ -6019,7 +6080,13 @@ fn handle_completions(&mut self, token_range: Range<usize>) -> bool {
/// \param token_end the position after the token to complete
/// \param flags A union of all flags describing the completion to insert. See the completion_t
/// struct for more information on possible values.
fn completion_insert(&mut self, val: &wstr, token_end: usize, flags: CompleteFlags) {
fn completion_insert(
&mut self,
val: &wstr,
token_end: usize,
flags: CompleteFlags,
is_unique: bool,
) {
let (elt, el) = self.active_edit_line();
// Move the cursor to the end of the token.
@@ -6035,6 +6102,7 @@ fn completion_insert(&mut self, val: &wstr, token_end: usize, flags: CompleteFla
el.text(),
&mut cursor,
/*append_only=*/ false,
is_unique,
);
self.set_buffer_maintaining_pager(&new_command_line, cursor, false);
}

View File

@@ -35,7 +35,7 @@
use crate::output::Outputter;
use crate::termsize::{termsize_last, Termsize};
use crate::wchar::prelude::*;
use crate::wcstringutil::string_prefixes_string;
use crate::wcstringutil::{fish_wcwidth_visible, string_prefixes_string};
use crate::wutil::fstat;
#[derive(Clone, Default)]
@@ -1636,7 +1636,11 @@ fn measure_run_from(
width = next_tab_stop(width);
} else {
// Ordinary char. Add its width with care to ignore control chars which have width -1.
width += wcwidth_rendered_min_0(input.char_at(idx));
if let Ok(ww) = usize::try_from(fish_wcwidth_visible(input.char_at(idx))) {
width += ww;
} else {
width = width.saturating_sub(1);
}
}
idx += 1;
}
@@ -1682,7 +1686,8 @@ fn truncate_run(
curr_width = measure_run_from(run, 0, None, cache);
idx = 0;
} else {
let char_width = wcwidth_rendered_min_0(c);
// FIXME: In case of backspace, this would remove the last width.
let char_width = usize::try_from(fish_wcwidth_visible(c)).unwrap_or(0);
curr_width -= std::cmp::min(curr_width, char_width);
run.remove(idx);
}

View File

@@ -160,7 +160,8 @@ macro_rules! unique_completion_applies_as {
completions[0].flags,
cmdline,
&mut cursor,
false,
/*append_only=*/ false,
/*is_unique=*/ true,
);
assert_eq!(newcmdline, L!($applied), "apply result mismatch");
};
@@ -224,6 +225,7 @@ macro_rules! unique_completion_applies_as {
L!("mv debug debug"),
&mut cursor_pos,
true,
/*is_unique=*/ false,
);
assert_eq!(newcmdline, L!("mv debug Debug/"));

View File

@@ -57,6 +57,7 @@ macro_rules! validate {
&line,
&mut cursor_pos,
$append_only,
/*is_unique=*/ false,
);
assert_eq!(result, expected);
assert_eq!(cursor_pos, out_cursor_pos);

View File

@@ -1,3 +1,5 @@
use std::sync::MutexGuard;
use crate::common::{
escape_string, str2wcstring, unescape_string, wcs2string, EscapeFlags, EscapeStringStyle,
UnescapeStringStyle, ENCODE_DIRECT_BASE, ENCODE_DIRECT_END,
@@ -10,21 +12,21 @@
/// wcs2string is locale-dependent, so ensure we have a multibyte locale
/// before using it in a test.
fn setlocale() {
let _guard = LOCALE_LOCK.lock().unwrap();
fn setlocale() -> MutexGuard<'static, ()> {
let guard = LOCALE_LOCK.lock().unwrap();
#[rustfmt::skip]
const UTF8_LOCALES: &[&str] = &[
"C.UTF-8", "en_US.UTF-8", "en_GB.UTF-8", "de_DE.UTF-8", "C.utf8", "UTF-8",
];
if crate::libc::MB_CUR_MAX() > 1 {
return;
return guard;
}
for locale in UTF8_LOCALES {
let locale = std::ffi::CString::new(locale.to_owned()).unwrap();
unsafe { libc::setlocale(libc::LC_CTYPE, locale.as_ptr()) };
if crate::libc::MB_CUR_MAX() > 1 {
return;
return guard;
}
}
panic!("No UTF-8 locale found");
@@ -100,7 +102,7 @@ fn test_escape_var() {
}
fn escape_test(escape_style: EscapeStringStyle, unescape_style: UnescapeStringStyle) {
setlocale();
let _locale_guard = setlocale();
let seed: u128 = 92348567983274852905629743984572;
let mut rng = get_seeded_rng(seed);
@@ -174,7 +176,7 @@ fn str2hex(input: &[u8]) -> String {
/// string comes back through double conversion.
#[test]
fn test_convert() {
setlocale();
let _locale_guard = setlocale();
let seed = get_rng_seed();
let mut rng = get_seeded_rng(seed);
let mut origin = Vec::new();

View File

@@ -1,5 +1,5 @@
use super::wopendir;
use crate::common::{cstr2wcstring, wcs2zstring};
use crate::common::{str2wcstring, wcs2zstring};
use crate::wchar::{wstr, WString};
use crate::wutil::DevInode;
use libc::{
@@ -8,11 +8,10 @@
S_IFSOCK,
};
use std::cell::Cell;
use std::io::{self};
use std::io;
use std::os::fd::RawFd;
use std::ptr::NonNull;
use std::ptr::{addr_of, NonNull};
use std::rc::Rc;
use std::slice;
/// Types of files that may be in a directory.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -267,19 +266,23 @@ pub fn next(&mut self) -> Option<io::Result<&DirEntry>> {
// dent.d_name is c_char; pretend it's u8.
assert!(std::mem::size_of::<libc::c_char>() == std::mem::size_of::<u8>());
let d_name_cchar = &dent.d_name;
let d_name = unsafe {
slice::from_raw_parts(d_name_cchar.as_ptr() as *const u8, d_name_cchar.len())
};
// Do not rely on `libc::dirent::d_name.len()` as dirent names may exceed
// the nominal buffer size; instead use the terminating nul byte.
// TODO: This should use &raw from Rust 1.82 on
// https://github.com/rust-lang/libc/issues/2669
// https://github.com/fish-shell/fish-shell/issues/11221
let d_name_ptr = addr_of!((*dent).d_name);
let d_name = unsafe { std::ffi::CStr::from_ptr(d_name_ptr.cast()) }.to_bytes();
// Skip . and ..,
// unless we've been told not to.
if !self.withdot && (d_name.starts_with(b".\0") || d_name.starts_with(b"..\0")) {
if !self.withdot && (d_name == b"." || d_name == b"..") {
return self.next();
}
self.entry.reset();
self.entry.name = cstr2wcstring(d_name);
self.entry.name = str2wcstring(d_name);
#[cfg(any(target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
{
self.entry.inode = dent.d_fileno;

View File

@@ -10,7 +10,7 @@ complete -c complete_test_alpha3 --no-files -w 'complete_test_alpha2 extra2'
complete -C'complete_test_alpha1 arg1 '
# CHECK: complete_test_alpha1 arg1
complete --escape -C'complete_test_alpha1 arg1 '
# CHECK: 'complete_test_alpha1 arg1 '
# CHECK: complete_test_alpha1\ arg1\{{ }}
complete -C'complete_test_alpha2 arg2 '
# CHECK: complete_test_alpha1 extra1 arg2
complete -C'complete_test_alpha3 arg3 '

View File

@@ -183,6 +183,11 @@ function foo --argument-names status; end
echo status $status
# CHECK: status 2
function foo --argument-names foo status; end
# CHECKERR: {{.*}}function.fish (line {{\d+}}): function: variable 'status' is read-only
# CHECKERR: function foo --argument-names foo status; end
# CHECKERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
functions -q foo
echo exists $status
# CHECK: exists 1

View File

@@ -40,12 +40,21 @@ echo "echo foo" > git-frobnicate
chmod +x git-frobnicate
complete -c git-frobnicate -xa 'foo bar baz'
complete -c git-frobnicate -l onto -xa 'onto1 onto2'
complete -C'git frobnicate '
#CHECK: bar
#CHECK: baz
#CHECK: foo
complete -C'git frobnicate --onto '
#CHECK: onto1
#CHECK: onto2
complete -C'git frobnicate graft --onto '
#CHECK: onto1
#CHECK: onto2
complete -C'git ' | grep '^add'\t
# (note: actual tab character in the check here)
#CHECK: add Add file contents to the staging area

View File

@@ -400,3 +400,8 @@ echo foo | read -n -1
# CHECKERR: echo foo | read -n -1
# CHECKERR: ^
# CHECKERR: (Type 'help read' for related documentation)
printf \xf9\x98\xb1\x83\x8b | read -z out_of_range_codepoint
set -S out_of_range_codepoint
# CHECK: $out_of_range_codepoint: set in global scope, unexported, with 1 elements
# CHECK: $out_of_range_codepoint[1]: |\Xf9\X98\Xb1\X83\X8b|

View File

@@ -1,2 +1,2 @@
#RUN: %fish -v
# CHECK: fish, version {{[-.gabcdeflphat0-9]*(irty)?}}
# CHECK: fish, version {{[0-9].*}}

View File

@@ -28,6 +28,21 @@ expect_prompt(increment=False)
send("\f")
expect_prompt(increment=False)
# Test that kill-selection after selection is cleared doesn't crash
sendline("bind ctrl-space begin-selection")
expect_prompt()
sendline("bind ctrl-w kill-selection end-selection")
expect_prompt()
send("echo 123")
# Send Ctrl-Space using CSI u encoding
send("\x1b[32;5u")
# Send Ctrl-C to clear the command line
send("\x1b[99;5u")
# Send Ctrl-W which used to crash
send("\x1b[119;5u")
sendline("bind --erase ctrl-space ctrl-w")
expect_prompt()
# Fish should start in default-mode (i.e., emacs) bindings. The default escape
# timeout is 30ms.
#
@@ -345,7 +360,7 @@ send("\x1b")
expect_str("foo")
send("\x1b[A")
expect_str("bind escape 'echo foo'")
sendline("")
sendline("bind --erase escape")
expect_prompt()
send(" a b c d\x01") # ctrl-a, move back to the beginning of the line
@@ -394,6 +409,11 @@ expect_prompt()
sendline("commandline -f and")
expect_prompt()
sendline("bind ctrl-g 'sleep 1' history-pager")
expect_prompt()
send("\x07") # ctrl-g
send("\x1b[27u") # escape, to close pager
# Check that the builtin version of `exit` works
# (for obvious reasons this MUST BE LAST)
sendline("function myexit; echo exit; exit; end; bind ctrl-z myexit")