Compare commits

..

32 Commits
4.0.1 ... 4.0.2

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
37 changed files with 538 additions and 225 deletions

View File

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

2
Cargo.lock generated
View File

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

View File

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

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

@@ -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

@@ -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"
@@ -2571,9 +2586,9 @@ function __fish_git_complete_custom_command -a subcommand
set -e cmd[1] # Drop "git".
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 $(string escape -- $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

@@ -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

@@ -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

@@ -120,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

@@ -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

@@ -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

@@ -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

@@ -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

@@ -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;
@@ -563,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,
}
}
@@ -701,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;
}
}
@@ -789,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.
@@ -1325,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

@@ -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

@@ -955,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 {
@@ -1033,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 {
@@ -1044,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());
@@ -3696,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)
}
@@ -3777,6 +3789,7 @@ fn pager_selection_changed(&mut self) {
&self.cycle_command_line,
&mut cursor_pos,
false,
/*is_unique=*/ false, // don't care
),
};
@@ -4414,6 +4427,7 @@ fn get_autosuggestion_performer(
&search_string,
&mut cursor,
/*append_only=*/ true,
/*is_unique=*/ false,
);
}
result
@@ -4820,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 => {
@@ -4889,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(
@@ -5597,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);
@@ -5621,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 {
@@ -5869,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,
);
}
}
@@ -6005,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();
}
@@ -6049,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.
@@ -6065,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

@@ -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 += usize::try_from(fish_wcwidth_visible(input.char_at(idx))).unwrap();
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 = usize::try_from(fish_wcwidth_visible(c)).unwrap();
// 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

@@ -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

@@ -51,6 +51,10 @@ 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")