mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-28 01:11:15 -03:00
Compare commits
186 Commits
4.0b1
...
test-drive
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc63404c96 | ||
|
|
5507bcc425 | ||
|
|
c3442602ef | ||
|
|
3437d63507 | ||
|
|
695ae02aa5 | ||
|
|
e1059b5e43 | ||
|
|
f1cf64fba0 | ||
|
|
8304fd0fd0 | ||
|
|
f4f786633d | ||
|
|
ec3b3fe321 | ||
|
|
d3762f11b5 | ||
|
|
6db0f39676 | ||
|
|
7970ca55af | ||
|
|
ccbbae95ef | ||
|
|
6d551b4459 | ||
|
|
cc9083e220 | ||
|
|
14df28382d | ||
|
|
e6d57f2fb2 | ||
|
|
4def0ac616 | ||
|
|
b574a5e4f6 | ||
|
|
9b67b2ae07 | ||
|
|
ea4e4a4279 | ||
|
|
3405621dee | ||
|
|
834001087d | ||
|
|
e697add5b5 | ||
|
|
704b911168 | ||
|
|
af137e5e96 | ||
|
|
75832b3c5d | ||
|
|
dda4371679 | ||
|
|
10f1f21a4f | ||
|
|
109ef88831 | ||
|
|
f9b79926f1 | ||
|
|
6c3150aa05 | ||
|
|
07dd088d76 | ||
|
|
93e0a33d41 | ||
|
|
dcddffd222 | ||
|
|
d842a6560e | ||
|
|
b4e8cc8b79 | ||
|
|
83eb25d45f | ||
|
|
7eb254f2ba | ||
|
|
2e12a2b6c4 | ||
|
|
a780e4da15 | ||
|
|
33dd823f45 | ||
|
|
e11e62674f | ||
|
|
e49dde87cc | ||
|
|
edfdf210c4 | ||
|
|
996fec87f4 | ||
|
|
870a8f77a0 | ||
|
|
d823444c6e | ||
|
|
abaeb4af2a | ||
|
|
670541eec8 | ||
|
|
0debddc9e5 | ||
|
|
837c32f150 | ||
|
|
9b26fff278 | ||
|
|
2b46d97c68 | ||
|
|
65ced4e2bb | ||
|
|
3710142d1d | ||
|
|
0c9c5e3a34 | ||
|
|
53912777af | ||
|
|
70bd49f612 | ||
|
|
6714818e5d | ||
|
|
7e9b35be48 | ||
|
|
7af9844de0 | ||
|
|
3129c9e939 | ||
|
|
967c4b2272 | ||
|
|
1c4e5cadf2 | ||
|
|
532abaddae | ||
|
|
7049352e61 | ||
|
|
a4f4ae76cb | ||
|
|
c3de539d46 | ||
|
|
7bb38355e8 | ||
|
|
5520ee3c65 | ||
|
|
e66f6878b5 | ||
|
|
e9b9ee8d63 | ||
|
|
17d57b70d0 | ||
|
|
cb3d004a5a | ||
|
|
5e10d75a19 | ||
|
|
050fe09af1 | ||
|
|
b531cc8b43 | ||
|
|
63e705a778 | ||
|
|
1df8de06c1 | ||
|
|
943adf4dd0 | ||
|
|
53dc7772eb | ||
|
|
64ed47bf4e | ||
|
|
6848e70e87 | ||
|
|
d5efef1cc5 | ||
|
|
e715c3e3ff | ||
|
|
13763fa318 | ||
|
|
8910390602 | ||
|
|
b6c2a4c5db | ||
|
|
a88de9d345 | ||
|
|
e8801d2ced | ||
|
|
1d620356f8 | ||
|
|
8bb6597b9b | ||
|
|
8ae12973df | ||
|
|
459fc3c887 | ||
|
|
a719f9d537 | ||
|
|
da0a93b24b | ||
|
|
8bb442f135 | ||
|
|
3fcc6482cb | ||
|
|
83b0294fc9 | ||
|
|
84f19a931d | ||
|
|
3201cb9f01 | ||
|
|
e1e963ae66 | ||
|
|
ca9c5f4cec | ||
|
|
48ae19b4b1 | ||
|
|
7ec1487016 | ||
|
|
bc26481558 | ||
|
|
41e82c8c9e | ||
|
|
376bf3a982 | ||
|
|
1e384900fa | ||
|
|
cde503b0a8 | ||
|
|
69f0d960cf | ||
|
|
ca28d0a78f | ||
|
|
6043644f52 | ||
|
|
1227b6765c | ||
|
|
905c7310c6 | ||
|
|
b1064ac3a0 | ||
|
|
1bda6043c8 | ||
|
|
d8d5913159 | ||
|
|
2ac1523e54 | ||
|
|
9cea5e0732 | ||
|
|
6f9ca42a30 | ||
|
|
b8df9648f2 | ||
|
|
66b80041cc | ||
|
|
a579abb81b | ||
|
|
b97598fa6c | ||
|
|
64cb86ac26 | ||
|
|
a14906f52f | ||
|
|
36d7049749 | ||
|
|
4b9767ce83 | ||
|
|
f6d76d2057 | ||
|
|
659c926dbd | ||
|
|
56da15d11f | ||
|
|
5e59762117 | ||
|
|
69fdbc89d6 | ||
|
|
244c55f9ce | ||
|
|
b7ae159824 | ||
|
|
6dad396498 | ||
|
|
f5a02e590d | ||
|
|
36c632889b | ||
|
|
c473aa60a7 | ||
|
|
6515862095 | ||
|
|
94dfe1b053 | ||
|
|
0b52b72ebc | ||
|
|
eade6a5672 | ||
|
|
044cea1bf3 | ||
|
|
74b1247461 | ||
|
|
9b8793a2df | ||
|
|
6c63139d23 | ||
|
|
f3dd4ee022 | ||
|
|
7bafb0d1ae | ||
|
|
46072e0fd6 | ||
|
|
c09a9246a1 | ||
|
|
e2596d13cd | ||
|
|
0153579a4c | ||
|
|
c1b460525c | ||
|
|
5de6f4bb3d | ||
|
|
54cc932215 | ||
|
|
e3864c752a | ||
|
|
03a9f4a775 | ||
|
|
7e5af914be | ||
|
|
ab4606430e | ||
|
|
774b7c7b5b | ||
|
|
6b1a9ef7ce | ||
|
|
c74afd4198 | ||
|
|
3dc49d9d93 | ||
|
|
b19a467ea6 | ||
|
|
381b38af0a | ||
|
|
965bc78d33 | ||
|
|
610338cc70 | ||
|
|
f9fb026085 | ||
|
|
1e7de063bd | ||
|
|
541f8b47bf | ||
|
|
6eec2db292 | ||
|
|
039011bc81 | ||
|
|
9abec243a4 | ||
|
|
f89e26b06e | ||
|
|
80d53b129f | ||
|
|
7162822486 | ||
|
|
7c2a379674 | ||
|
|
25534bf657 | ||
|
|
687001f8b7 | ||
|
|
e6fea730e2 | ||
|
|
b56bb80a14 | ||
|
|
5fc47f37a6 |
@@ -24,4 +24,4 @@ tasks:
|
|||||||
ninja
|
ninja
|
||||||
- test: |
|
- test: |
|
||||||
cd fish-shell/build
|
cd fish-shell/build
|
||||||
env ninja test
|
ninja test
|
||||||
|
|||||||
@@ -20,4 +20,4 @@ tasks:
|
|||||||
ninja
|
ninja
|
||||||
- test: |
|
- test: |
|
||||||
cd fish/build
|
cd fish/build
|
||||||
env ninja test
|
ninja test
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ linux_task:
|
|||||||
# container:
|
# container:
|
||||||
# <<: *step
|
# <<: *step
|
||||||
# image: ghcr.io/krobelus/fish-ci/focal-32bit:latest
|
# image: ghcr.io/krobelus/fish-ci/focal-32bit:latest
|
||||||
|
|
||||||
tests_script:
|
tests_script:
|
||||||
# cirrus at times gives us 32 procs and 2 GB of RAM
|
# cirrus at times gives us 32 procs and 2 GB of RAM
|
||||||
# Unrestriced parallelism results in OOM
|
# Unrestriced parallelism results in OOM
|
||||||
@@ -30,7 +29,6 @@ linux_task:
|
|||||||
- cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCTEST_PARALLEL_LEVEL=6 ..
|
- cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCTEST_PARALLEL_LEVEL=6 ..
|
||||||
- ninja -j 6 fish
|
- ninja -j 6 fish
|
||||||
- ninja fish_run_tests
|
- ninja fish_run_tests
|
||||||
|
|
||||||
only_if: $CIRRUS_REPO_OWNER == 'fish-shell'
|
only_if: $CIRRUS_REPO_OWNER == 'fish-shell'
|
||||||
|
|
||||||
linux_arm_task:
|
linux_arm_task:
|
||||||
@@ -41,7 +39,6 @@ linux_arm_task:
|
|||||||
- name: jammy-armv7-32bit
|
- name: jammy-armv7-32bit
|
||||||
arm_container:
|
arm_container:
|
||||||
image: ghcr.io/fish-shell/fish-ci/jammy-armv7-32bit
|
image: ghcr.io/fish-shell/fish-ci/jammy-armv7-32bit
|
||||||
|
|
||||||
tests_script:
|
tests_script:
|
||||||
# cirrus at times gives us 32 procs and 2 GB of RAM
|
# cirrus at times gives us 32 procs and 2 GB of RAM
|
||||||
# Unrestriced parallelism results in OOM
|
# Unrestriced parallelism results in OOM
|
||||||
@@ -52,7 +49,6 @@ linux_arm_task:
|
|||||||
- ninja -j 6 fish
|
- ninja -j 6 fish
|
||||||
- file ./fish
|
- file ./fish
|
||||||
- ninja fish_run_tests
|
- ninja fish_run_tests
|
||||||
|
|
||||||
# CI task disabled during RIIR transition
|
# CI task disabled during RIIR transition
|
||||||
only_if: false && $CIRRUS_REPO_OWNER == 'fish-shell'
|
only_if: false && $CIRRUS_REPO_OWNER == 'fish-shell'
|
||||||
|
|
||||||
@@ -92,5 +88,4 @@ freebsd_task:
|
|||||||
- sudo -u fish-user -s cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCTEST_PARALLEL_LEVEL=1 ..
|
- sudo -u fish-user -s cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCTEST_PARALLEL_LEVEL=1 ..
|
||||||
- sudo -u fish-user sh -c '. $HOME/.cargo/env; ninja -j 6 fish'
|
- sudo -u fish-user sh -c '. $HOME/.cargo/env; ninja -j 6 fish'
|
||||||
- sudo -u fish-user sh -c '. $HOME/.cargo/env; ninja fish_run_tests'
|
- sudo -u fish-user sh -c '. $HOME/.cargo/env; ninja fish_run_tests'
|
||||||
|
|
||||||
only_if: $CIRRUS_REPO_OWNER == 'fish-shell'
|
only_if: $CIRRUS_REPO_OWNER == 'fish-shell'
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ indent_size = 2
|
|||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
[share/{completions,functions}/**.fish]
|
[share/{completions,functions}/**.fish]
|
||||||
max_line_length = off
|
max_line_length = unset
|
||||||
|
|
||||||
[{COMMIT_EDITMSG,git-revise-todo}]
|
[{COMMIT_EDITMSG,git-revise-todo}]
|
||||||
max_line_length = 80
|
max_line_length = 80
|
||||||
|
|||||||
4
.github/workflows/mac_codesign.yml
vendored
4
.github/workflows/mac_codesign.yml
vendored
@@ -13,8 +13,8 @@ jobs:
|
|||||||
uses: dtolnay/rust-toolchain@1.73.0
|
uses: dtolnay/rust-toolchain@1.73.0
|
||||||
with:
|
with:
|
||||||
targets: x86_64-apple-darwin
|
targets: x86_64-apple-darwin
|
||||||
- name: Install Rust 1.79
|
- name: Install Rust Stable
|
||||||
uses: dtolnay/rust-toolchain@1.79
|
uses: dtolnay/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
targets: aarch64-apple-darwin
|
targets: aarch64-apple-darwin
|
||||||
- name: build-and-codesign
|
- name: build-and-codesign
|
||||||
|
|||||||
42
.github/workflows/staticbuild.yml
vendored
42
.github/workflows/staticbuild.yml
vendored
@@ -12,7 +12,7 @@ env:
|
|||||||
CMAKE_BUILD_PARALLEL_LEVEL: "4"
|
CMAKE_BUILD_PARALLEL_LEVEL: "4"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
staticbuilds:
|
staticbuilds-linux:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
@@ -29,19 +29,55 @@ jobs:
|
|||||||
sudo apt install python3-sphinx
|
sudo apt install python3-sphinx
|
||||||
rustup target add x86_64-unknown-linux-musl
|
rustup target add x86_64-unknown-linux-musl
|
||||||
rustup target add aarch64-unknown-linux-musl
|
rustup target add aarch64-unknown-linux-musl
|
||||||
sudo apt install musl-tools crossbuild-essential-arm64 -y
|
sudo apt install musl-tools crossbuild-essential-arm64 python3-pexpect tmux -y
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" CMAKE_WITH_GETTEXT=0 CC=aarch64-linux-gnu-gcc RUSTFLAGS="-C linker=aarch64-linux-gnu-gcc -C link-arg=-lgcc -C link-arg=-D_FORTIFY_SOURCE=0" cargo build --release --target aarch64-unknown-linux-musl
|
CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" CMAKE_WITH_GETTEXT=0 CC=aarch64-linux-gnu-gcc RUSTFLAGS="-C linker=aarch64-linux-gnu-gcc -C link-arg=-lgcc -C link-arg=-D_FORTIFY_SOURCE=0" cargo build --release --target aarch64-unknown-linux-musl
|
||||||
cargo build --release --target x86_64-unknown-linux-musl
|
cargo build --release --target x86_64-unknown-linux-musl
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
FISHDIR=target/x86_64-unknown-linux-musl/release/ tests/test_driver.sh tests/test.fish
|
||||||
|
FISHDIR=target/x86_64-unknown-linux-musl/release/ tests/test_driver.sh tests/interactive.fish
|
||||||
- name: Compress
|
- name: Compress
|
||||||
run: |
|
run: |
|
||||||
tar -cazf fish-amd64.tar.xz -C target/x86_64-unknown-linux-musl/release/ fish{,_indent,_key_reader}
|
tar -cazf fish-amd64.tar.xz -C target/x86_64-unknown-linux-musl/release/ fish{,_indent,_key_reader}
|
||||||
tar -cazf fish-aarch64.tar.xz -C target/aarch64-unknown-linux-musl/release/ fish{,_indent,_key_reader}
|
tar -cazf fish-aarch64.tar.xz -C target/aarch64-unknown-linux-musl/release/ fish{,_indent,_key_reader}
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: fish
|
name: fish-static-linux
|
||||||
path: |
|
path: |
|
||||||
fish-amd64.tar.xz
|
fish-amd64.tar.xz
|
||||||
fish-aarch64.tar.xz
|
fish-aarch64.tar.xz
|
||||||
retention-days: 14
|
retention-days: 14
|
||||||
|
staticbuilds-macos:
|
||||||
|
|
||||||
|
runs-on: macos-latest
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: dtolnay/rust-toolchain@1.70
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
sudo pip3 install --break-system-packages sphinx
|
||||||
|
rustup target add x86_64-apple-darwin
|
||||||
|
rustup target add aarch64-apple-darwin
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
RUSTFLAGS='-C target-feature=+crt-static' cargo build --release --target aarch64-apple-darwin
|
||||||
|
RUSTFLAGS='-C target-feature=+crt-static' cargo build --release --target x86_64-apple-darwin
|
||||||
|
- name: Compress
|
||||||
|
run: |
|
||||||
|
tar -cazf fish-macos-aarch64.tar.xz -C target/aarch64-apple-darwin/release/ fish{,_indent,_key_reader}
|
||||||
|
tar -cazf fish-macos-amd64.tar.xz -C target/x86_64-apple-darwin/release/ fish{,_indent,_key_reader}
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: fish-static-macos
|
||||||
|
path: |
|
||||||
|
fish-macos-amd64.tar.xz
|
||||||
|
fish-macos-aarch64.tar.xz
|
||||||
|
retention-days: 14
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -102,3 +102,6 @@ target/
|
|||||||
|
|
||||||
# Generated by clangd
|
# Generated by clangd
|
||||||
/.cache
|
/.cache
|
||||||
|
|
||||||
|
# JetBrains editors.
|
||||||
|
.idea/
|
||||||
|
|||||||
@@ -1,3 +1,44 @@
|
|||||||
|
fish 4.1.0 (released ???)
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Notable improvements and fixes
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Deprecations and removed features
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
Scripting improvements
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Interactive improvements
|
||||||
|
------------------------
|
||||||
|
- Autosuggestions are now also provided in multi-line command lines. Like `ctrl-r`, autosuggestions operate only on the current line.
|
||||||
|
- New feature flag ``buffered-enter-noexec`` with the following effect:
|
||||||
|
when typing a command and :kbd:`enter` while the previous one is still running, the new one will no longer execute immediately. Similarly, keys that are bound to shell commands will be ignored.
|
||||||
|
This mitigates a security issue where a command like ``cat malicious-file.txt`` could write terminal escape codes prompting the terminal to write arbitrary text to fish's standard input.
|
||||||
|
Such a malicious file can still potentially insert arbitrary text into the command line but can no longer execute it directly (:issue:`10987`).
|
||||||
|
|
||||||
|
New or improved bindings
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
- :kbd:`ctrl-z` (undo) after executing a command will restore the previous cursor position instead of placing the cursor at the end of the command line.
|
||||||
|
- The OSC 133 prompt marking feature has learned about kitty's ``click_events=1`` flag, which allows moving fish's cursor by clicking.
|
||||||
|
- :kbd:`ctrl-l` no longer clears the screen but only pushes to the terminal's scrollback all text above the prompt (via a new special input function ``scrollback-push``).
|
||||||
|
This feature depends on the terminal advertising via XTGETTCAP support for the ``indn`` and ``cuu`` terminfo capabilities,
|
||||||
|
and on the terminal supporting Synchronized Output (which is used by fish to detect features).
|
||||||
|
If any is missing, the binding falls back to ``clear-screen``.
|
||||||
|
|
||||||
|
Completions
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
|
Improved terminal support
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Other improvements
|
||||||
|
------------------
|
||||||
|
|
||||||
|
For distributors
|
||||||
|
----------------
|
||||||
|
|
||||||
fish 4.0b1 (released December 17, 2024)
|
fish 4.0b1 (released December 17, 2024)
|
||||||
=======================================
|
=======================================
|
||||||
|
|
||||||
@@ -18,7 +59,7 @@ Notable backwards-incompatible changes
|
|||||||
- Terminals that fail to ignore unrecognized OSC or CSI sequences may display garbage. We know cool-retro-term and emacs' ansi-term are affected,
|
- Terminals that fail to ignore unrecognized OSC or CSI sequences may display garbage. We know cool-retro-term and emacs' ansi-term are affected,
|
||||||
most mainstream terminals are not.
|
most mainstream terminals are not.
|
||||||
- :kbd:`alt-left` and :kbd:`alt-right` will now move by one argument (which may contain quoted spaces), not just one word like :kbd:`ctrl-left` and :kbd:`ctrl-right` do.
|
- :kbd:`alt-left` and :kbd:`alt-right` will now move by one argument (which may contain quoted spaces), not just one word like :kbd:`ctrl-left` and :kbd:`ctrl-right` do.
|
||||||
- :kbd:`alt-backspace` will delete an entire argument, not just one word (which is :kbd:`ctrl-backspace` now).
|
- :kbd:`alt-backspace` will delete an entire argument, not just one word. The old word behavior has been moved to :kbd:`ctrl-backspace`. If your terminal doesn't support `ctrl-backspace`, consider using :kbd:`ctrl-w`, or :kbd:`alt-b` + :kbd:`alt-d`.
|
||||||
- ``random`` will produce different values from previous versions of fish when used with the same seed, and will work more sensibly with small seed numbers.
|
- ``random`` will produce different values from previous versions of fish when used with the same seed, and will work more sensibly with small seed numbers.
|
||||||
The seed was never guaranteed to give the same result across systems,
|
The seed was never guaranteed to give the same result across systems,
|
||||||
so we do not expect this to have a large impact (:issue:`9593`).
|
so we do not expect this to have a large impact (:issue:`9593`).
|
||||||
@@ -61,7 +102,7 @@ Notable improvements and fixes
|
|||||||
|
|
||||||
This build system is experimental; the main build system, using ``cmake``, remains the recommended approach for packaging and installation to a prefix.
|
This build system is experimental; the main build system, using ``cmake``, remains the recommended approach for packaging and installation to a prefix.
|
||||||
- A new function ``fish_should_add_to_history`` can be overridden to decide whether a command should be added to the history (:issue:`10302`).
|
- A new function ``fish_should_add_to_history`` can be overridden to decide whether a command should be added to the history (:issue:`10302`).
|
||||||
- :kbd:`ctrl-c` during command input no longer prints ``^C`` and a new prompt, but merely clears the command line. This restores the behavior from version 2.2. To revert to the old behavior, use ``bind ctrl-c __fish_cancel_commandline`` (:issue:`10213`).
|
- :kbd:`ctrl-c` during command input no longer prints ``^C`` and a new prompt, but merely clears the command line. This restores the behavior from version 2.2. To revert to the old behavior, use ``for mode in (bind --list-modes); bind -M $mode ctrl-c cancel-commandline-traditional; end`` (:issue:`10213`).
|
||||||
- Bindings can now mix special input functions and shell commands, so ``bind ctrl-g expand-abbr "commandline -i \n"`` works as expected (:issue:`8186`).
|
- Bindings can now mix special input functions and shell commands, so ``bind ctrl-g expand-abbr "commandline -i \n"`` works as expected (:issue:`8186`).
|
||||||
- Special input functions run from bindings via ``commandline -f`` are now applied immediately, instead of after the currently executing binding (:issue:`3031`).
|
- Special input functions run from bindings via ``commandline -f`` are now applied immediately, instead of after the currently executing binding (:issue:`3031`).
|
||||||
For example, ``commandline -i foo; commandline | grep foo`` succeeds now.
|
For example, ``commandline -i foo; commandline | grep foo`` succeeds now.
|
||||||
@@ -161,7 +202,6 @@ New or improved bindings
|
|||||||
- Multiline commands are indented before being sent to the editor, which matches how they are displayed in fish.
|
- Multiline commands are indented before being sent to the editor, which matches how they are displayed in fish.
|
||||||
- The ``...-path-component`` bindings, like ``backward-kill-path-component``, now treat ``#`` as part of a path component (:issue:`10271`).
|
- The ``...-path-component`` bindings, like ``backward-kill-path-component``, now treat ``#`` as part of a path component (:issue:`10271`).
|
||||||
- Bindings like :kbd:`alt-l` that print output in between prompts now work correctly with multiline commandlines.
|
- Bindings like :kbd:`alt-l` that print output in between prompts now work correctly with multiline commandlines.
|
||||||
- :kbd:`ctrl-c` no longer cancels builtin ``read``.
|
|
||||||
- :kbd:`alt-d` on an empty command line lists the directory history again. This restores the behavior of version 2.1.
|
- :kbd:`alt-d` on an empty command line lists the directory history again. This restores the behavior of version 2.1.
|
||||||
- ``history-prefix-search-backward`` and ``-forward`` now maintain the cursor position, instead of moving the cursor to the end of the command line (:issue:`10430`).
|
- ``history-prefix-search-backward`` and ``-forward`` now maintain the cursor position, instead of moving the cursor to the end of the command line (:issue:`10430`).
|
||||||
- The following keys have refined behavior if the terminal supports :ref:`the new keyboard encodings <changelog-new-bindings>`:
|
- The following keys have refined behavior if the terminal supports :ref:`the new keyboard encodings <changelog-new-bindings>`:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ function(CREATE_TARGET target)
|
|||||||
${Rust_CARGO}
|
${Rust_CARGO}
|
||||||
build --bin ${target}
|
build --bin ${target}
|
||||||
$<$<CONFIG:Release>:--release>
|
$<$<CONFIG:Release>:--release>
|
||||||
$<$<CONFIG:RelWithDebInfo>:--release>
|
$<$<CONFIG:RelWithDebInfo>:--profile=release-with-debug>
|
||||||
--target ${Rust_CARGO_TARGET}
|
--target ${Rust_CARGO_TARGET}
|
||||||
--no-default-features
|
--no-default-features
|
||||||
${CARGO_FLAGS}
|
${CARGO_FLAGS}
|
||||||
@@ -81,8 +81,6 @@ create_target(fish_key_reader)
|
|||||||
# Set up the docs.
|
# Set up the docs.
|
||||||
include(cmake/Docs.cmake)
|
include(cmake/Docs.cmake)
|
||||||
|
|
||||||
# A helper for running tests.
|
|
||||||
add_executable(fish_test_helper src/fish_test_helper.c)
|
|
||||||
# Set up tests.
|
# Set up tests.
|
||||||
include(cmake/Tests.cmake)
|
include(cmake/Tests.cmake)
|
||||||
|
|
||||||
|
|||||||
@@ -126,4 +126,3 @@ enforcement ladder](https://github.com/mozilla/diversity).
|
|||||||
For answers to common questions about this code of conduct, see the FAQ at
|
For answers to common questions about this code of conduct, see the FAQ at
|
||||||
https://www.contributor-covenant.org/faq. Translations are available at
|
https://www.contributor-covenant.org/faq. Translations are available at
|
||||||
https://www.contributor-covenant.org/translations.
|
https://www.contributor-covenant.org/translations.
|
||||||
|
|
||||||
|
|||||||
@@ -196,8 +196,13 @@ The tests can be found in three places:
|
|||||||
- tests/pexpects for interactive tests using `pexpect <https://pexpect.readthedocs.io/en/stable/>`__
|
- tests/pexpects for interactive tests using `pexpect <https://pexpect.readthedocs.io/en/stable/>`__
|
||||||
|
|
||||||
When in doubt, the bulk of the tests should be added as a littlecheck test in tests/checks, as they are the easiest to modify and run, and much faster and more dependable than pexpect tests. The syntax is fairly self-explanatory. It's a fish script with the expected output in ``# CHECK:`` or ``# CHECKERR:`` (for stderr) comments.
|
When in doubt, the bulk of the tests should be added as a littlecheck test in tests/checks, as they are the easiest to modify and run, and much faster and more dependable than pexpect tests. The syntax is fairly self-explanatory. It's a fish script with the expected output in ``# CHECK:`` or ``# CHECKERR:`` (for stderr) comments.
|
||||||
|
If your littlecheck test has a specific dependency, use ``# REQUIRE: ...`` with a posix sh script.
|
||||||
|
|
||||||
The pexpects are written in python and can simulate input and output to/from a terminal, so they are needed for anything that needs actual interactivity. The runner is in build_tools/pexpect_helper.py, in case you need to modify something there.
|
Tests are run in a temporary $HOME, but that is shared among the tests by default. If you need a temporary directory for your test, you should create one (e.g. with ``mktemp``).
|
||||||
|
|
||||||
|
The pexpects are written in python and can simulate input and output to/from a terminal, so they are needed for anything that needs actual interactivity. The runner is in tests/pexpect_helper.py, in case you need to modify something there.
|
||||||
|
|
||||||
|
If you need a command to do something weird to test something, maybe add it to the ``fish_test_helper`` binary (in tests/fish_test_helper.c), or see if it can already do it.
|
||||||
|
|
||||||
Local testing
|
Local testing
|
||||||
-------------
|
-------------
|
||||||
@@ -209,6 +214,15 @@ The tests can be run on your local computer on all operating systems.
|
|||||||
cmake path/to/fish-shell
|
cmake path/to/fish-shell
|
||||||
make test
|
make test
|
||||||
|
|
||||||
|
Or you can run them on a fish, without involving cmake::
|
||||||
|
|
||||||
|
cargo build
|
||||||
|
FISHDIR=target/debug tests/test_driver.sh tests/test.fish # script tests, the checks
|
||||||
|
FISHDIR=target/debug tests/test_driver.sh tests/interactive.fish # interactive tests, the pexpects
|
||||||
|
|
||||||
|
Here, ``FISHDIR`` refers to a directory with ``fish``, ``fish_indent`` and ``fish_key_reader`` in it.
|
||||||
|
In this example we're in the root of the git repo and have run ``cargo build`` without ``--release``, so it's a debug build.
|
||||||
|
|
||||||
Git hooks
|
Git hooks
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
|||||||
2
COPYING
2
COPYING
@@ -1,7 +1,7 @@
|
|||||||
Fish is a smart and user-friendly command line shell.
|
Fish is a smart and user-friendly command line shell.
|
||||||
|
|
||||||
Copyright (C) 2005-2009 Axel Liljencrantz
|
Copyright (C) 2005-2009 Axel Liljencrantz
|
||||||
Copyright (C) 2009-2024 fish-shell contributors
|
Copyright (C) 2009- fish-shell contributors
|
||||||
|
|
||||||
fish is free software.
|
fish is free software.
|
||||||
|
|
||||||
|
|||||||
139
Cargo.lock
generated
139
Cargo.lock
generated
@@ -4,9 +4,9 @@ version = 3
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "allocator-api2"
|
name = "allocator-api2"
|
||||||
version = "0.2.18"
|
version = "0.2.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
|
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
@@ -31,9 +31,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.1.30"
|
version = "1.2.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945"
|
checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -54,9 +54,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.14"
|
version = "0.2.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
|
checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@@ -71,19 +71,6 @@ dependencies = [
|
|||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dashmap"
|
|
||||||
version = "5.5.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"hashbrown 0.14.5",
|
|
||||||
"lock_api",
|
|
||||||
"once_cell",
|
|
||||||
"parking_lot_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.10.7"
|
version = "0.10.7"
|
||||||
@@ -102,23 +89,22 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.9"
|
version = "0.3.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fish"
|
name = "fish"
|
||||||
version = "4.0.0-alpha1"
|
version = "4.0.0-beta.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"cc",
|
"cc",
|
||||||
"errno",
|
"errno",
|
||||||
"fish-printf",
|
"fish-printf",
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
"libc",
|
||||||
"lru",
|
"lru",
|
||||||
"nix",
|
"nix",
|
||||||
@@ -150,9 +136,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foldhash"
|
name = "foldhash"
|
||||||
version = "0.1.3"
|
version = "0.1.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
|
checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "generic-array"
|
||||||
@@ -166,15 +152,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.5"
|
version = "0.15.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hashbrown"
|
|
||||||
version = "0.15.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"allocator-api2",
|
"allocator-api2",
|
||||||
"equivalent",
|
"equivalent",
|
||||||
@@ -190,17 +170,11 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lazy_static"
|
|
||||||
version = "1.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.159"
|
version = "0.2.169"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
|
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
@@ -224,7 +198,7 @@ version = "0.12.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
|
checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hashbrown 0.15.0",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -365,24 +339,24 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "portable-atomic"
|
name = "portable-atomic"
|
||||||
version = "1.9.0"
|
version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
|
checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.87"
|
version = "1.0.92"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a"
|
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.37"
|
version = "1.0.38"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
@@ -404,9 +378,9 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.7"
|
version = "0.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
|
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
@@ -440,7 +414,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rust-embed-utils",
|
"rust-embed-utils",
|
||||||
"syn 2.0.79",
|
"syn",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -463,6 +437,15 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scc"
|
||||||
|
version = "2.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28e1c91382686d21b5ac7959341fcb9780fa7c03773646995a87c950fa7be640"
|
||||||
|
dependencies = [
|
||||||
|
"sdd",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
@@ -470,26 +453,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serial_test"
|
name = "sdd"
|
||||||
version = "1.0.0"
|
version = "3.0.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "538c30747ae860d6fb88330addbbd3e0ddbe46d662d032855596d8a8ca260611"
|
checksum = "478f121bb72bbf63c52c93011ea1791dca40140dfe13f8336c4c5ac952c33aa9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serial_test"
|
||||||
|
version = "3.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dashmap",
|
"once_cell",
|
||||||
"lazy_static",
|
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
|
"scc",
|
||||||
"serial_test_derive",
|
"serial_test_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serial_test_derive"
|
name = "serial_test_derive"
|
||||||
version = "1.0.0"
|
version = "3.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "079a83df15f85d89a68d64ae1238f142f172b1fa915d0d76b26a7cba1b659a69"
|
checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.109",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -523,20 +512,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.109"
|
version = "2.0.94"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
checksum = "987bc0be1cdea8b10216bd06e2ca407d40b9543468fafd3ddfb02f36e77f71f3"
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "2.0.79"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -563,9 +541,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.13"
|
version = "1.0.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
@@ -595,16 +573,7 @@ version = "0.1.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
10
Cargo.toml
10
Cargo.toml
@@ -3,6 +3,7 @@ resolver = "2"
|
|||||||
members = ["printf"]
|
members = ["printf"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
|
# To build revisions that use Corrosion (those before 2024-01), CMake 3.19 and Rustc 1.78 seem to work.
|
||||||
rust-version = "1.70"
|
rust-version = "1.70"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
@@ -10,6 +11,10 @@ edition = "2021"
|
|||||||
overflow-checks = true
|
overflow-checks = true
|
||||||
lto = true
|
lto = true
|
||||||
|
|
||||||
|
[profile.release-with-debug]
|
||||||
|
inherits = "release"
|
||||||
|
debug = true
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "fish"
|
name = "fish"
|
||||||
version = "4.0.0-beta.1"
|
version = "4.0.0-beta.1"
|
||||||
@@ -30,8 +35,7 @@ pcre2 = { git = "https://github.com/fish-shell/rust-pcre2", tag = "0.2.9-utf32",
|
|||||||
|
|
||||||
bitflags = "2.5.0"
|
bitflags = "2.5.0"
|
||||||
errno = "0.3.0"
|
errno = "0.3.0"
|
||||||
lazy_static = "1.4.0"
|
libc = "0.2"
|
||||||
libc = "0.2.155"
|
|
||||||
# lru pulls in hashbrown by default, which uses a faster (though less DoS resistant) hashing algo.
|
# lru pulls in hashbrown by default, which uses a faster (though less DoS resistant) hashing algo.
|
||||||
# disabling default features uses the stdlib instead, but it doubles the time to rewrite the history
|
# disabling default features uses the stdlib instead, but it doubles the time to rewrite the history
|
||||||
# files as of 22 April 2024.
|
# files as of 22 April 2024.
|
||||||
@@ -61,7 +65,7 @@ portable-atomic = { version = "1", default-features = false, features = [
|
|||||||
] }
|
] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serial_test = { version = "1.0.0", default-features = false }
|
serial_test = { version = "3", default-features = false }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
cc = "1.0.94"
|
cc = "1.0.94"
|
||||||
|
|||||||
@@ -16,4 +16,3 @@ WORKDIR /src
|
|||||||
RUN cmake3 . &&\
|
RUN cmake3 . &&\
|
||||||
make &&\
|
make &&\
|
||||||
make install
|
make install
|
||||||
|
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ Dependencies
|
|||||||
Compiling fish requires:
|
Compiling fish requires:
|
||||||
|
|
||||||
- Rust (version 1.70 or later)
|
- Rust (version 1.70 or later)
|
||||||
- CMake (version 3.5 or later)
|
- CMake (version 3.15 or later)
|
||||||
- a C compiler (for system feature detection and the test helper binary)
|
- a C compiler (for system feature detection and the test helper binary)
|
||||||
- PCRE2 (headers and libraries) - optional, this will be downloaded if missing
|
- PCRE2 (headers and libraries) - optional, this will be downloaded if missing
|
||||||
- gettext (headers and libraries) - optional, for translation support
|
- gettext (headers and libraries) - optional, for translation support
|
||||||
|
|||||||
@@ -8,5 +8,4 @@ for file in *.fish
|
|||||||
echo FAILING FILE $file
|
echo FAILING FILE $file
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
44
build.rs
44
build.rs
@@ -29,6 +29,11 @@ fn main() {
|
|||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Some build info
|
||||||
|
rsconf::set_env_value("BUILD_TARGET_TRIPLE", &env::var("TARGET").unwrap());
|
||||||
|
rsconf::set_env_value("BUILD_HOST_TRIPLE", &env::var("HOST").unwrap());
|
||||||
|
rsconf::set_env_value("BUILD_PROFILE", &env::var("PROFILE").unwrap());
|
||||||
|
|
||||||
let version = &get_version(&env::current_dir().unwrap());
|
let version = &get_version(&env::current_dir().unwrap());
|
||||||
// Per https://doc.rust-lang.org/cargo/reference/build-scripts.html#inputs-to-the-build-script,
|
// Per https://doc.rust-lang.org/cargo/reference/build-scripts.html#inputs-to-the-build-script,
|
||||||
// the source directory is the current working directory of the build script
|
// the source directory is the current working directory of the build script
|
||||||
@@ -222,7 +227,7 @@ fn has_small_stack(_: &Target) -> Result<bool, Box<dyn Error>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn setup_paths() {
|
fn setup_paths() {
|
||||||
fn get_path(name: &str, default: &str, onvar: PathBuf) -> PathBuf {
|
fn get_path(name: &str, default: &str, onvar: &Path) -> PathBuf {
|
||||||
let mut var = PathBuf::from(env::var(name).unwrap_or(default.to_string()));
|
let mut var = PathBuf::from(env::var(name).unwrap_or(default.to_string()));
|
||||||
if var.is_relative() {
|
if var.is_relative() {
|
||||||
var = onvar.join(var);
|
var = onvar.join(var);
|
||||||
@@ -245,7 +250,7 @@ fn get_path(name: &str, default: &str, onvar: PathBuf) -> PathBuf {
|
|||||||
rsconf::rebuild_if_env_changed("PREFIX");
|
rsconf::rebuild_if_env_changed("PREFIX");
|
||||||
rsconf::set_env_value("PREFIX", prefix.to_str().unwrap());
|
rsconf::set_env_value("PREFIX", prefix.to_str().unwrap());
|
||||||
|
|
||||||
let datadir = get_path("DATADIR", "share/", prefix.clone());
|
let datadir = get_path("DATADIR", "share/", &prefix);
|
||||||
rsconf::set_env_value("DATADIR", datadir.to_str().unwrap());
|
rsconf::set_env_value("DATADIR", datadir.to_str().unwrap());
|
||||||
rsconf::rebuild_if_env_changed("DATADIR");
|
rsconf::rebuild_if_env_changed("DATADIR");
|
||||||
|
|
||||||
@@ -256,7 +261,7 @@ fn get_path(name: &str, default: &str, onvar: PathBuf) -> PathBuf {
|
|||||||
};
|
};
|
||||||
rsconf::set_env_value("DATADIR_SUBDIR", datadir_subdir);
|
rsconf::set_env_value("DATADIR_SUBDIR", datadir_subdir);
|
||||||
|
|
||||||
let bindir = get_path("BINDIR", "bin/", prefix.clone());
|
let bindir = get_path("BINDIR", "bin/", &prefix);
|
||||||
rsconf::set_env_value("BINDIR", bindir.to_str().unwrap());
|
rsconf::set_env_value("BINDIR", bindir.to_str().unwrap());
|
||||||
rsconf::rebuild_if_env_changed("BINDIR");
|
rsconf::rebuild_if_env_changed("BINDIR");
|
||||||
|
|
||||||
@@ -265,16 +270,16 @@ fn get_path(name: &str, default: &str, onvar: PathBuf) -> PathBuf {
|
|||||||
// If we get our prefix from $HOME, we should use the system's /etc/
|
// If we get our prefix from $HOME, we should use the system's /etc/
|
||||||
// ~/.local/share/etc/ makes no sense
|
// ~/.local/share/etc/ makes no sense
|
||||||
if prefix_from_home { "/etc/" } else { "etc/" },
|
if prefix_from_home { "/etc/" } else { "etc/" },
|
||||||
datadir.clone(),
|
&datadir,
|
||||||
);
|
);
|
||||||
rsconf::set_env_value("SYSCONFDIR", sysconfdir.to_str().unwrap());
|
rsconf::set_env_value("SYSCONFDIR", sysconfdir.to_str().unwrap());
|
||||||
rsconf::rebuild_if_env_changed("SYSCONFDIR");
|
rsconf::rebuild_if_env_changed("SYSCONFDIR");
|
||||||
|
|
||||||
let localedir = get_path("LOCALEDIR", "locale/", datadir.clone());
|
let localedir = get_path("LOCALEDIR", "locale/", &datadir);
|
||||||
rsconf::set_env_value("LOCALEDIR", localedir.to_str().unwrap());
|
rsconf::set_env_value("LOCALEDIR", localedir.to_str().unwrap());
|
||||||
rsconf::rebuild_if_env_changed("LOCALEDIR");
|
rsconf::rebuild_if_env_changed("LOCALEDIR");
|
||||||
|
|
||||||
let docdir = get_path("DOCDIR", "doc/fish", datadir.clone());
|
let docdir = get_path("DOCDIR", "doc/fish", &datadir);
|
||||||
rsconf::set_env_value("DOCDIR", docdir.to_str().unwrap());
|
rsconf::set_env_value("DOCDIR", docdir.to_str().unwrap());
|
||||||
rsconf::rebuild_if_env_changed("DOCDIR");
|
rsconf::rebuild_if_env_changed("DOCDIR");
|
||||||
}
|
}
|
||||||
@@ -287,7 +292,7 @@ fn get_version(src_dir: &Path) -> String {
|
|||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = PathBuf::from(src_dir).join("version");
|
let path = src_dir.join("version");
|
||||||
if let Ok(strver) = read_to_string(path) {
|
if let Ok(strver) = read_to_string(path) {
|
||||||
return strver.to_string();
|
return strver.to_string();
|
||||||
}
|
}
|
||||||
@@ -316,8 +321,9 @@ fn get_version(src_dir: &Path) -> String {
|
|||||||
// or because it refused (safe.directory applies to `git describe`!)
|
// or because it refused (safe.directory applies to `git describe`!)
|
||||||
// So we read the SHA ourselves.
|
// So we read the SHA ourselves.
|
||||||
fn get_git_hash() -> Result<String, Box<dyn std::error::Error>> {
|
fn get_git_hash() -> Result<String, Box<dyn std::error::Error>> {
|
||||||
let gitdir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(".git");
|
let gitdir = Path::new(env!("CARGO_MANIFEST_DIR")).join(".git");
|
||||||
|
let jjdir = Path::new(env!("CARGO_MANIFEST_DIR")).join(".jj");
|
||||||
|
let commit_id = if gitdir.exists() {
|
||||||
// .git/HEAD contains ref: refs/heads/branch
|
// .git/HEAD contains ref: refs/heads/branch
|
||||||
let headpath = gitdir.join("HEAD");
|
let headpath = gitdir.join("HEAD");
|
||||||
let headstr = read_to_string(headpath)?;
|
let headstr = read_to_string(headpath)?;
|
||||||
@@ -326,7 +332,25 @@ fn get_git_hash() -> Result<String, Box<dyn std::error::Error>> {
|
|||||||
// .git/refs/heads/branch contains the SHA
|
// .git/refs/heads/branch contains the SHA
|
||||||
let refpath = gitdir.join(headref);
|
let refpath = gitdir.join(headref);
|
||||||
// Shorten to 9 characters (what git describe does currently)
|
// Shorten to 9 characters (what git describe does currently)
|
||||||
let refstr = &read_to_string(refpath)?[0..9];
|
read_to_string(refpath)?
|
||||||
|
} else if jjdir.exists() {
|
||||||
|
let output = Command::new("jj")
|
||||||
|
.args([
|
||||||
|
"log",
|
||||||
|
"--revisions",
|
||||||
|
"@",
|
||||||
|
"--no-graph",
|
||||||
|
"--ignore-working-copy",
|
||||||
|
"--template",
|
||||||
|
"commit_id",
|
||||||
|
])
|
||||||
|
.output()
|
||||||
|
.unwrap();
|
||||||
|
String::from_utf8_lossy(&output.stdout).to_string()
|
||||||
|
} else {
|
||||||
|
return Err("did not find either of .git or .jj".into());
|
||||||
|
};
|
||||||
|
let refstr = &commit_id[0..9];
|
||||||
let refstr = refstr.trim();
|
let refstr = refstr.trim();
|
||||||
|
|
||||||
let version = env!("CARGO_PKG_VERSION").to_owned();
|
let version = env!("CARGO_PKG_VERSION").to_owned();
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
code, tt {
|
code, tt {
|
||||||
font-family: ui-monospace, Menlo, monospace;
|
font-family: ui-monospace, Menlo, monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ add_custom_target(sphinx-docs
|
|||||||
|
|
||||||
# sphinx-manpages needs the fish_indent binary for the version number
|
# sphinx-manpages needs the fish_indent binary for the version number
|
||||||
add_custom_target(sphinx-manpages
|
add_custom_target(sphinx-manpages
|
||||||
env FISH_BUILD_VERSION_FILE="${CMAKE_CURRENT_BINARY_DIR}/${FBVF}"
|
env FISH_BUILD_VERSION_FILE=${CMAKE_CURRENT_BINARY_DIR}/${FBVF}
|
||||||
${SPHINX_EXECUTABLE}
|
${SPHINX_EXECUTABLE}
|
||||||
-j auto
|
-j auto
|
||||||
-q -b man
|
-q -b man
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ else()
|
|||||||
set(rust_target_dir "${FISH_RUST_BUILD_DIR}/${Rust_CARGO_HOST_TARGET}")
|
set(rust_target_dir "${FISH_RUST_BUILD_DIR}/${Rust_CARGO_HOST_TARGET}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(rust_profile $<IF:$<CONFIG:Debug>,debug,release>)
|
set(rust_profile $<IF:$<CONFIG:Debug>,debug,$<IF:$<CONFIG:RelWithDebInfo>,release-with-debug,release>>)
|
||||||
set(rust_debugflags "$<$<CONFIG:Debug>:-g>$<$<CONFIG:RelWithDebInfo>:-g>")
|
set(rust_debugflags "$<$<CONFIG:Debug>:-g>$<$<CONFIG:RelWithDebInfo>:-g>")
|
||||||
|
|
||||||
|
|
||||||
@@ -49,6 +49,8 @@ set(VARS_FOR_CARGO
|
|||||||
"PREFIX=${CMAKE_INSTALL_PREFIX}"
|
"PREFIX=${CMAKE_INSTALL_PREFIX}"
|
||||||
# Temporary hack to propogate CMake flags/options to build.rs.
|
# Temporary hack to propogate CMake flags/options to build.rs.
|
||||||
"CMAKE_WITH_GETTEXT=${CMAKE_WITH_GETTEXT}"
|
"CMAKE_WITH_GETTEXT=${CMAKE_WITH_GETTEXT}"
|
||||||
|
# Cheesy so we can tell cmake was used to build
|
||||||
|
"CMAKE=1"
|
||||||
"DOCDIR=${CMAKE_INSTALL_FULL_DOCDIR}"
|
"DOCDIR=${CMAKE_INSTALL_FULL_DOCDIR}"
|
||||||
"DATADIR=${CMAKE_INSTALL_FULL_DATADIR}"
|
"DATADIR=${CMAKE_INSTALL_FULL_DATADIR}"
|
||||||
"SYSCONFDIR=${CMAKE_INSTALL_FULL_SYSCONFDIR}"
|
"SYSCONFDIR=${CMAKE_INSTALL_FULL_SYSCONFDIR}"
|
||||||
|
|||||||
@@ -71,12 +71,6 @@ if(NOT FISH_IN_TREE_BUILD)
|
|||||||
VERBATIM)
|
VERBATIM)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Copy littlecheck.py
|
|
||||||
configure_file(build_tools/littlecheck.py littlecheck.py COPYONLY)
|
|
||||||
|
|
||||||
# Copy pexpect_helper.py
|
|
||||||
configure_file(build_tools/pexpect_helper.py pexpect_helper.py COPYONLY)
|
|
||||||
|
|
||||||
# Suppress generating Xcode schemes for all tests, there's too many.
|
# Suppress generating Xcode schemes for all tests, there's too many.
|
||||||
set(CMAKE_XCODE_GENERATE_SCHEME 0)
|
set(CMAKE_XCODE_GENERATE_SCHEME 0)
|
||||||
|
|
||||||
@@ -95,22 +89,19 @@ add_custom_target(tests_buildroot_target
|
|||||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${TEST_INSTALL_DIR}
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${TEST_INSTALL_DIR}
|
||||||
COMMAND env DESTDIR=${TEST_INSTALL_DIR} ${CMAKE_COMMAND}
|
COMMAND env DESTDIR=${TEST_INSTALL_DIR} ${CMAKE_COMMAND}
|
||||||
--build ${CMAKE_CURRENT_BINARY_DIR} --target install
|
--build ${CMAKE_CURRENT_BINARY_DIR} --target install
|
||||||
# Put fish_test_helper there too:
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/fish_test_helper
|
|
||||||
${TEST_INSTALL_DIR}/${CMAKE_INSTALL_PREFIX}/bin
|
|
||||||
# Also symlink fish to where the tests expect it to be:
|
# Also symlink fish to where the tests expect it to be:
|
||||||
COMMAND ${CMAKE_COMMAND} -E create_symlink
|
COMMAND ${CMAKE_COMMAND} -E create_symlink
|
||||||
${TEST_INSTALL_DIR}/${CMAKE_INSTALL_PREFIX}
|
${TEST_INSTALL_DIR}/${CMAKE_INSTALL_PREFIX}
|
||||||
${TEST_ROOT_DIR}
|
${TEST_ROOT_DIR}
|
||||||
DEPENDS fish fish_test_helper)
|
DEPENDS fish)
|
||||||
|
|
||||||
FILE(GLOB FISH_CHECKS CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/tests/checks/*.fish)
|
FILE(GLOB FISH_CHECKS CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/tests/checks/*.fish)
|
||||||
foreach(CHECK ${FISH_CHECKS})
|
foreach(CHECK ${FISH_CHECKS})
|
||||||
get_filename_component(CHECK_NAME ${CHECK} NAME)
|
get_filename_component(CHECK_NAME ${CHECK} NAME)
|
||||||
get_filename_component(CHECK ${CHECK} NAME_WE)
|
get_filename_component(CHECK ${CHECK} NAME_WE)
|
||||||
add_test(NAME ${CHECK_NAME}
|
add_test(NAME ${CHECK_NAME}
|
||||||
COMMAND sh ${CMAKE_CURRENT_BINARY_DIR}/tests/test_driver.sh
|
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/tests/test_driver.py ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/tests/test.fish ${CHECK}
|
checks/${CHECK}.fish
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests
|
||||||
)
|
)
|
||||||
set_tests_properties(${CHECK_NAME} PROPERTIES SKIP_RETURN_CODE ${SKIP_RETURN_CODE})
|
set_tests_properties(${CHECK_NAME} PROPERTIES SKIP_RETURN_CODE ${SKIP_RETURN_CODE})
|
||||||
@@ -122,8 +113,8 @@ FILE(GLOB PEXPECTS CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/tests/pexpects/*.py)
|
|||||||
foreach(PEXPECT ${PEXPECTS})
|
foreach(PEXPECT ${PEXPECTS})
|
||||||
get_filename_component(PEXPECT ${PEXPECT} NAME)
|
get_filename_component(PEXPECT ${PEXPECT} NAME)
|
||||||
add_test(NAME ${PEXPECT}
|
add_test(NAME ${PEXPECT}
|
||||||
COMMAND sh ${CMAKE_CURRENT_BINARY_DIR}/tests/test_driver.sh
|
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/tests/test_driver.py ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/tests/interactive.fish ${PEXPECT}
|
pexpects/${PEXPECT}
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests
|
||||||
)
|
)
|
||||||
set_tests_properties(${PEXPECT} PROPERTIES SKIP_RETURN_CODE ${SKIP_RETURN_CODE})
|
set_tests_properties(${PEXPECT} PROPERTIES SKIP_RETURN_CODE ${SKIP_RETURN_CODE})
|
||||||
|
|||||||
29
debian/control
vendored
29
debian/control
vendored
@@ -3,10 +3,16 @@ Section: shells
|
|||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: ridiculous_fish <corydoras@ridiculousfish.com>
|
Maintainer: ridiculous_fish <corydoras@ridiculousfish.com>
|
||||||
Uploaders: David Adam <zanchey@ucc.gu.uwa.edu.au>
|
Uploaders: David Adam <zanchey@ucc.gu.uwa.edu.au>
|
||||||
Build-Depends: debhelper (>= 12), cmake (>= 3.19.0) | cmake-mozilla (>= 3.19.0), gettext,
|
Build-Depends: debhelper (>= 12),
|
||||||
rustc (>= 1.70), cargo (>= 0.66) | cargo-mozilla (>= 0.66), libpcre2-dev,
|
cargo (>= 0.66) | cargo-mozilla (>= 0.66),
|
||||||
|
cmake (>= 3.15.0) | cmake-mozilla (>= 3.15.0),
|
||||||
|
gettext,
|
||||||
|
libpcre2-dev,
|
||||||
|
rustc (>= 1.70),
|
||||||
# Test dependencies
|
# Test dependencies
|
||||||
locales-all, ncurses-base, python3
|
locales-all,
|
||||||
|
ncurses-base,
|
||||||
|
python3
|
||||||
Standards-Version: 4.1.5
|
Standards-Version: 4.1.5
|
||||||
Homepage: https://fishshell.com/
|
Homepage: https://fishshell.com/
|
||||||
Vcs-Git: https://github.com/fish-shell/fish-shell.git
|
Vcs-Git: https://github.com/fish-shell/fish-shell.git
|
||||||
@@ -14,8 +20,21 @@ Vcs-Browser: https://github.com/fish-shell/fish-shell
|
|||||||
|
|
||||||
Package: fish
|
Package: fish
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, gettext-base, man-db, ncurses-base, procps,
|
# for col and lock
|
||||||
python3 (>=3.5)
|
Depends: bsdextrautils,
|
||||||
|
file,
|
||||||
|
# for the gettext command
|
||||||
|
gettext-base,
|
||||||
|
# for nroff and preconv
|
||||||
|
groff-base,
|
||||||
|
man-db,
|
||||||
|
# for terminal definitions
|
||||||
|
ncurses-base,
|
||||||
|
# for kill
|
||||||
|
procps,
|
||||||
|
python3 (>=3.5),
|
||||||
|
${misc:Depends},
|
||||||
|
${shlibs:Depends}
|
||||||
Conflicts: fish-common
|
Conflicts: fish-common
|
||||||
Recommends: xsel (>=1.2.0)
|
Recommends: xsel (>=1.2.0)
|
||||||
Suggests: xdg-utils
|
Suggests: xdg-utils
|
||||||
|
|||||||
4
debian/copyright
vendored
4
debian/copyright
vendored
@@ -5,12 +5,12 @@ Source: https://fishshell.com/
|
|||||||
|
|
||||||
Files: *
|
Files: *
|
||||||
Copyright: 2005-2009 Axel Liljencrantz <axel@liljencrantz.se>
|
Copyright: 2005-2009 Axel Liljencrantz <axel@liljencrantz.se>
|
||||||
2009-2024 fish-shell contributors
|
2009- fish-shell contributors
|
||||||
License: GPL-2
|
License: GPL-2
|
||||||
|
|
||||||
Files: doc_src/python_docs_theme/*
|
Files: doc_src/python_docs_theme/*
|
||||||
Copyright: 2001-2017 Python Software Foundation
|
Copyright: 2001-2017 Python Software Foundation
|
||||||
2020-2024 fish-shell contributors
|
2020- fish-shell contributors
|
||||||
License: Python
|
License: Python
|
||||||
|
|
||||||
Files: share/tools/web_config/js/alpine.js
|
Files: share/tools/web_config/js/alpine.js
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ Combining these features, it is possible to create custom syntaxes, where a regu
|
|||||||
|
|
||||||
> abbr > ~/.config/fish/conf.d/myabbrs.fish
|
> abbr > ~/.config/fish/conf.d/myabbrs.fish
|
||||||
|
|
||||||
This will save all your abbrevations in "myabbrs.fish", overwriting the whole file so it doesn't leave any duplicates,
|
This will save all your abbreviations in "myabbrs.fish", overwriting the whole file so it doesn't leave any duplicates,
|
||||||
or restore abbreviations you had erased.
|
or restore abbreviations you had erased.
|
||||||
Of course any functions will have to be saved separately, see :doc:`funcsave <funcsave>`.
|
Of course any functions will have to be saved separately, see :doc:`funcsave <funcsave>`.
|
||||||
|
|
||||||
|
|||||||
@@ -171,7 +171,10 @@ The following special input functions are available:
|
|||||||
make the current word begin with a capital letter
|
make the current word begin with a capital letter
|
||||||
|
|
||||||
``clear-screen``
|
``clear-screen``
|
||||||
clears the screen and redraws the prompt. if the terminal doesn't support clearing the screen it is the same as ``repaint``.
|
clears the screen and redraws the prompt.
|
||||||
|
|
||||||
|
``scrollback-push``
|
||||||
|
pushes earlier output to the terminal scrollback, positioning the prompt at the top.
|
||||||
|
|
||||||
``complete``
|
``complete``
|
||||||
guess the remainder of the current token
|
guess the remainder of the current token
|
||||||
@@ -259,7 +262,7 @@ The following special input functions are available:
|
|||||||
search the history for the next matching argument
|
search the history for the next matching argument
|
||||||
|
|
||||||
``forward-jump`` and ``backward-jump``
|
``forward-jump`` and ``backward-jump``
|
||||||
read another character and jump to its next occurence after/before the cursor
|
read another character and jump to its next occurrence after/before the cursor
|
||||||
|
|
||||||
``forward-jump-till`` and ``backward-jump-till``
|
``forward-jump-till`` and ``backward-jump-till``
|
||||||
jump to right *before* the next occurrence
|
jump to right *before* the next occurrence
|
||||||
@@ -269,7 +272,7 @@ The following special input functions are available:
|
|||||||
|
|
||||||
``jump-to-matching-bracket``
|
``jump-to-matching-bracket``
|
||||||
jump to matching bracket if the character under the cursor is bracket;
|
jump to matching bracket if the character under the cursor is bracket;
|
||||||
otherwise, jump to the next occurence of *any right* bracket after the cursor.
|
otherwise, jump to the next occurrence of *any right* bracket after the cursor.
|
||||||
The following brackets are considered: ``([{}])``
|
The following brackets are considered: ``([{}])``
|
||||||
|
|
||||||
``jump-till-matching-bracket``
|
``jump-till-matching-bracket``
|
||||||
@@ -292,7 +295,7 @@ The following special input functions are available:
|
|||||||
move the selected text to the killring
|
move the selected text to the killring
|
||||||
|
|
||||||
``kill-whole-line``
|
``kill-whole-line``
|
||||||
move the line (including the following newline) to the killring. If the line is the last line, its preceeding newline is also removed
|
move the line (including the following newline) to the killring. If the line is the last line, its preceding newline is also removed
|
||||||
|
|
||||||
``kill-inner-line``
|
``kill-inner-line``
|
||||||
move the line (without the following newline) to the killring
|
move the line (without the following newline) to the killring
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ The following options output metadata about the commandline state:
|
|||||||
**--is-valid**
|
**--is-valid**
|
||||||
Returns true when the commandline is syntactically valid and complete.
|
Returns true when the commandline is syntactically valid and complete.
|
||||||
If it is, it would be executed when the ``execute`` bind function is called.
|
If it is, it would be executed when the ``execute`` bind function is called.
|
||||||
If the commandline is incomplete, return 2, if erroneus, return 1.
|
If the commandline is incomplete, return 2, if erroneous, return 1.
|
||||||
|
|
||||||
**--showing-suggestion**
|
**--showing-suggestion**
|
||||||
Evaluates to true (i.e. returns 0) when the shell is currently showing an automatic history completion/suggestion, available to be consumed via one of the `forward-` bindings.
|
Evaluates to true (i.e. returns 0) when the shell is currently showing an automatic history completion/suggestion, available to be consumed via one of the `forward-` bindings.
|
||||||
|
|||||||
@@ -40,9 +40,11 @@ The following options are available:
|
|||||||
**-i** or **--interactive**
|
**-i** or **--interactive**
|
||||||
The shell is interactive.
|
The shell is interactive.
|
||||||
|
|
||||||
**--install**
|
**--install[=PATH]**
|
||||||
When built as self-installable (via cargo), this will unpack fish's datafiles and place them in ~/.local/share/fish/install/.
|
When built as self-installable (via cargo), this will unpack fish's datafiles and place them in ~/.local/share/fish/install/.
|
||||||
Fish will also ask to do this automatically when run interactively.
|
Fish will also ask to do this automatically when run interactively.
|
||||||
|
If PATH is given, fish will install itself into a relocatable directory tree rooted at that path.
|
||||||
|
That means it will install the datafiles to PATH/share/fish and copy itself to PATH/bin/fish.
|
||||||
|
|
||||||
**-l** or **--login**
|
**-l** or **--login**
|
||||||
Act as if invoked as a login shell.
|
Act as if invoked as a login shell.
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ Synopsis
|
|||||||
status job-control CONTROL_TYPE
|
status job-control CONTROL_TYPE
|
||||||
status features
|
status features
|
||||||
status test-feature FEATURE
|
status test-feature FEATURE
|
||||||
|
status buildinfo
|
||||||
|
|
||||||
Description
|
Description
|
||||||
-----------
|
-----------
|
||||||
@@ -97,6 +98,10 @@ The following operations (subcommands) are available:
|
|||||||
**test-feature** *FEATURE*
|
**test-feature** *FEATURE*
|
||||||
Returns 0 when FEATURE is enabled, 1 if it is disabled, and 2 if it is not recognized.
|
Returns 0 when FEATURE is enabled, 1 if it is disabled, and 2 if it is not recognized.
|
||||||
|
|
||||||
|
**buildinfo**
|
||||||
|
This prints information on how fish was build - which architecture, which build system or profile was used, etc.
|
||||||
|
This is mainly useful for debugging.
|
||||||
|
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ Description
|
|||||||
|
|
||||||
.. BEGIN DESCRIPTION
|
.. BEGIN DESCRIPTION
|
||||||
|
|
||||||
``string escape`` escapes each *STRING* in one of three ways. The first is **--style=script**. This is the default. It alters the string such that it can be passed back to ``eval`` to produce the original argument again. By default, all special characters are escaped, and quotes are used to simplify the output when possible. If **-n** or **--no-quoted** is given, the simplifying quoted format is not used. Exit status: 0 if at least one string was escaped, or 1 otherwise.
|
``string escape`` escapes each *STRING* in one of several ways.
|
||||||
|
|
||||||
|
**--style=script** (default) alters the string such that it can be passed back to ``eval`` to produce the original argument again. By default, all special characters are escaped, and quotes are used to simplify the output when possible. If **-n** or **--no-quoted** is given, the simplifying quoted format is not used. Exit status: 0 if at least one string was escaped, or 1 otherwise.
|
||||||
|
|
||||||
**--style=var** ensures the string can be used as a variable name by hex encoding any non-alphanumeric characters. The string is first converted to UTF-8 before being encoded.
|
**--style=var** ensures the string can be used as a variable name by hex encoding any non-alphanumeric characters. The string is first converted to UTF-8 before being encoded.
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ Description
|
|||||||
|
|
||||||
.. BEGIN DESCRIPTION
|
.. BEGIN DESCRIPTION
|
||||||
|
|
||||||
``string repeat`` repeats the *STRING* **-n** or **--count** times. The **-m** or **--max** option will limit the number of outputted characters (excluding the newline). This option can be used by itself or in conjunction with **--count**. If both **--count** and **--max** are present, max char will be outputed unless the final repeated string size is less than max, in that case, the string will repeat until count has been reached. Both **--count** and **--max** will accept a number greater than or equal to zero, in the case of zero, nothing will be outputed. The first argument is interpreted as *COUNT* if **--count** or **--max** are not explicilty specified. If **-N** or **--no-newline** is given, the output won't contain a newline character at the end. Exit status: 0 if yielded string is not empty, 1 otherwise.
|
``string repeat`` repeats the *STRING* **-n** or **--count** times. The **-m** or **--max** option will limit the number of outputted characters (excluding the newline). This option can be used by itself or in conjunction with **--count**. If both **--count** and **--max** are present, max char will be outputted unless the final repeated string size is less than max, in that case, the string will repeat until count has been reached. Both **--count** and **--max** will accept a number greater than or equal to zero, in the case of zero, nothing will be outputted. The first argument is interpreted as *COUNT* if **--count** or **--max** are not explicitly specified. If **-N** or **--no-newline** is given, the output won't contain a newline character at the end. Exit status: 0 if yielded string is not empty, 1 otherwise.
|
||||||
|
|
||||||
.. END DESCRIPTION
|
.. END DESCRIPTION
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ If **-q** or **--quiet** is given, ``string shorten`` only runs for the return v
|
|||||||
|
|
||||||
The default ellipsis is ``…``. If fish thinks your system is incapable because of your locale, it will use ``...`` instead.
|
The default ellipsis is ``…``. If fish thinks your system is incapable because of your locale, it will use ``...`` instead.
|
||||||
|
|
||||||
The return value is 0 if any shortening occured, 1 otherwise.
|
The return value is 0 if any shortening occurred, 1 otherwise.
|
||||||
|
|
||||||
.. END DESCRIPTION
|
.. END DESCRIPTION
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ highlight_language = "fish-docs-samples"
|
|||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
project = "fish-shell"
|
project = "fish-shell"
|
||||||
copyright = "2024, fish-shell developers"
|
copyright = "fish-shell developers"
|
||||||
author = "fish-shell developers"
|
author = "fish-shell developers"
|
||||||
issue_url = "https://github.com/fish-shell/fish-shell/issues"
|
issue_url = "https://github.com/fish-shell/fish-shell/issues"
|
||||||
|
|
||||||
|
|||||||
@@ -327,8 +327,12 @@ Some bindings are common across Emacs and vi mode, because they aren't text edit
|
|||||||
|
|
||||||
- :kbd:`alt-d` or :kbd:`ctrl-delete` moves the next word to the :ref:`killring`.
|
- :kbd:`alt-d` or :kbd:`ctrl-delete` moves the next word to the :ref:`killring`.
|
||||||
|
|
||||||
|
- :kbd:`alt-d` lists the directory history if the command line is empty.
|
||||||
|
|
||||||
- :kbd:`alt-delete` moves the next argument to the :ref:`killring`.
|
- :kbd:`alt-delete` moves the next argument to the :ref:`killring`.
|
||||||
|
|
||||||
|
- :kbd:`shift-delete` removes the current history item or autosuggestion from the command history.
|
||||||
|
|
||||||
- :kbd:`alt-h` (or :kbd:`f1`) shows the manual page for the current command, if one exists.
|
- :kbd:`alt-h` (or :kbd:`f1`) shows the manual page for the current command, if one exists.
|
||||||
|
|
||||||
- :kbd:`alt-l` lists the contents of the current directory, unless the cursor is over a directory argument, in which case the contents of that directory will be listed.
|
- :kbd:`alt-l` lists the contents of the current directory, unless the cursor is over a directory argument, in which case the contents of that directory will be listed.
|
||||||
@@ -382,7 +386,7 @@ To enable emacs mode, use :doc:`fish_default_key_bindings <cmds/fish_default_key
|
|||||||
|
|
||||||
- :kbd:`ctrl-z`, :kbd:`ctrl-_` (:kbd:`ctrl-/` on some terminals) undo the most recent edit of the line.
|
- :kbd:`ctrl-z`, :kbd:`ctrl-_` (:kbd:`ctrl-/` on some terminals) undo the most recent edit of the line.
|
||||||
|
|
||||||
- :kbd:`alt-/` reverts the most recent undo.
|
- :kbd:`alt-/` or :kbd:`ctrl-shift-z` reverts the most recent undo.
|
||||||
|
|
||||||
- :kbd:`ctrl-r` opens the history in a pager. This will show history entries matching the search, a few at a time. Pressing :kbd:`ctrl-r` again will search older entries, pressing :kbd:`ctrl-s` (that otherwise toggles pager search) will go to newer entries. The search bar will always be selected.
|
- :kbd:`ctrl-r` opens the history in a pager. This will show history entries matching the search, a few at a time. Pressing :kbd:`ctrl-r` again will search older entries, pressing :kbd:`ctrl-s` (that otherwise toggles pager search) will go to newer entries. The search bar will always be selected.
|
||||||
|
|
||||||
|
|||||||
@@ -870,7 +870,7 @@ but if you need multiple or the command doesn't read from standard input, "proce
|
|||||||
|
|
||||||
This creates a temporary file, stores the output of the command in that file and prints the filename, so it is given to the outer command.
|
This creates a temporary file, stores the output of the command in that file and prints the filename, so it is given to the outer command.
|
||||||
|
|
||||||
Fish has a default limit of 100 MiB on the data it will read in a command sustitution. If that limit is reached the command (all of it, not just the command substitution - the outer command won't be executed at all) fails and ``$status`` is set to 122. This is so command substitutions can't cause the system to go out of memory, because typically your operating system has a much lower limit, so reading more than that would be useless and harmful. This limit can be adjusted with the ``fish_read_limit`` variable (`0` meaning no limit). This limit also affects the :doc:`read <cmds/read>` command.
|
Fish has a default limit of 100 MiB on the data it will read in a command substitution. If that limit is reached the command (all of it, not just the command substitution - the outer command won't be executed at all) fails and ``$status`` is set to 122. This is so command substitutions can't cause the system to go out of memory, because typically your operating system has a much lower limit, so reading more than that would be useless and harmful. This limit can be adjusted with the ``fish_read_limit`` variable (`0` meaning no limit). This limit also affects the :doc:`read <cmds/read>` command.
|
||||||
|
|
||||||
.. [#] One exception: Setting ``$IFS`` to empty will disable line splitting. This is deprecated, use :doc:`string split <cmds/string-split>` instead.
|
.. [#] One exception: Setting ``$IFS`` to empty will disable line splitting. This is deprecated, use :doc:`string split <cmds/string-split>` instead.
|
||||||
|
|
||||||
@@ -1845,7 +1845,7 @@ The "locale" of a program is its set of language and regional settings that depe
|
|||||||
|
|
||||||
.. envvar:: LC_MONETARY
|
.. envvar:: LC_MONETARY
|
||||||
|
|
||||||
Determines currency, how it is formated, and the symbols used.
|
Determines currency, how it is formatted, and the symbols used.
|
||||||
|
|
||||||
.. envvar:: LC_NUMERIC
|
.. envvar:: LC_NUMERIC
|
||||||
|
|
||||||
@@ -2024,6 +2024,7 @@ You can see the current list of features via ``status features``::
|
|||||||
ampersand-nobg-in-token on 3.4 & only backgrounds if followed by a separating character
|
ampersand-nobg-in-token on 3.4 & only backgrounds if followed by a separating character
|
||||||
remove-percent-self off 3.8 %self is no longer expanded (use $fish_pid)
|
remove-percent-self off 3.8 %self is no longer expanded (use $fish_pid)
|
||||||
test-require-arg off 3.8 builtin test requires an argument
|
test-require-arg off 3.8 builtin test requires an argument
|
||||||
|
buffered-enter-noexec off 4.1 enter typed while executing will not execute
|
||||||
|
|
||||||
Here is what they mean:
|
Here is what they mean:
|
||||||
|
|
||||||
@@ -2033,6 +2034,7 @@ Here is what they mean:
|
|||||||
- ``ampersand-nobg-in-token`` was introduced in fish 3.4. It makes it so a ``&`` i no longer interpreted as the backgrounding operator in the middle of a token, so dealing with URLs becomes easier. Either put spaces or a semicolon after the ``&``. This is recommended formatting anyway, and ``fish_indent`` will have done it for you already.
|
- ``ampersand-nobg-in-token`` was introduced in fish 3.4. It makes it so a ``&`` i no longer interpreted as the backgrounding operator in the middle of a token, so dealing with URLs becomes easier. Either put spaces or a semicolon after the ``&``. This is recommended formatting anyway, and ``fish_indent`` will have done it for you already.
|
||||||
- ``remove-percent-self`` turns off the special ``%self`` expansion. It was introduced in 3.8. To get fish's pid, you can use the :envvar:`fish_pid` variable.
|
- ``remove-percent-self`` turns off the special ``%self`` expansion. It was introduced in 3.8. To get fish's pid, you can use the :envvar:`fish_pid` variable.
|
||||||
- ``test-require-arg`` removes :doc:`builtin test <cmds/test>`'s one-argument form (``test "string"``. It was introduced in 3.8. To test if a string is non-empty, use ``test -n "string"``. If disabled, any call to ``test`` that would change sends a :ref:`debug message <debugging-fish>` of category "deprecated-test", so starting fish with ``fish --debug=deprecated-test`` can be used to find offending calls.
|
- ``test-require-arg`` removes :doc:`builtin test <cmds/test>`'s one-argument form (``test "string"``. It was introduced in 3.8. To test if a string is non-empty, use ``test -n "string"``. If disabled, any call to ``test`` that would change sends a :ref:`debug message <debugging-fish>` of category "deprecated-test", so starting fish with ``fish --debug=deprecated-test`` can be used to find offending calls.
|
||||||
|
- ``buffered-enter-noexec`` typing enter during command execution will insert a newline into the next commandline instead of executing it.
|
||||||
|
|
||||||
|
|
||||||
These changes are introduced off by default. They can be enabled on a per session basis::
|
These changes are introduced off by default. They can be enabled on a per session basis::
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ License
|
|||||||
License for fish
|
License for fish
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
``fish`` Copyright © 2005-2009 Axel Liljencrantz, 2009-2024 fish-shell contributors. ``fish`` is released under the GNU General Public License, version 2.
|
``fish`` Copyright © 2005-2009 Axel Liljencrantz, 2009- fish-shell contributors. ``fish`` is released under the GNU General Public License, version 2.
|
||||||
|
|
||||||
``fish`` includes other code licensed under the GNU General Public License, version 2, including GNU ``printf``.
|
``fish`` includes other code licensed under the GNU General Public License, version 2, including GNU ``printf``.
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ body {
|
|||||||
div.related ul {
|
div.related ul {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0 0 0 10px;
|
padding: 0 0 0 10px;
|
||||||
list-style: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
div.related {
|
div.related {
|
||||||
@@ -71,12 +70,10 @@ div.related h3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
div.related li.right {
|
div.related li.right {
|
||||||
float: right;
|
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.sphinxsidebar {
|
div.sphinxsidebar {
|
||||||
width: 230px;
|
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +110,6 @@ div.sphinxsidebar ul {
|
|||||||
margin: 10px;
|
margin: 10px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
color: var(--secondary-link-color);
|
color: var(--secondary-link-color);
|
||||||
margin: 10px;
|
|
||||||
list-style: none;
|
list-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,10 +544,6 @@ div.sphinxsidebar ul {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
div.bodywrapper {
|
|
||||||
margin-left: 230px;
|
|
||||||
}
|
|
||||||
|
|
||||||
aside.footnote > .label {
|
aside.footnote > .label {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
@@ -565,19 +557,36 @@ div.documentwrapper {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.document {
|
||||||
|
display: grid;
|
||||||
|
grid-template: 1fr min-content / 12rem minmax(0,1fr);
|
||||||
|
}
|
||||||
|
|
||||||
/* On screens that are less than 700px wide remove anything non-essential
|
/* On screens that are less than 700px wide remove anything non-essential
|
||||||
- the sidebar, the gradient background, ... */
|
- the sidebar, the gradient background, ... */
|
||||||
@media screen and (max-width: 700px) {
|
@media screen and (max-width: 700px) {
|
||||||
|
div.document {
|
||||||
|
display: grid;
|
||||||
|
grid-template: 30vh min-content / 100%;
|
||||||
|
}
|
||||||
div.sphinxsidebar {
|
div.sphinxsidebar {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
/* To separate the "side"bar from the content below */
|
||||||
|
border-bottom: 1px solid;
|
||||||
|
border-color: var(--sidebar-border-color);
|
||||||
}
|
}
|
||||||
div.bodywrapper {
|
|
||||||
|
/* Reduce margins to save space */
|
||||||
|
div.sphinxsidebar ul ul, div.bodywrapper, div.content {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar h3, div.sphinxsidebar h4 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
div.sphinxsidebar ul {
|
div.sphinxsidebar ul {
|
||||||
flex-basis: content;
|
flex-basis: content;
|
||||||
@@ -585,14 +594,15 @@ div.documentwrapper {
|
|||||||
}
|
}
|
||||||
div.sphinxsidebarwrapper {
|
div.sphinxsidebarwrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
gap: 1em;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
div.sphinxsidebarwrapper > h3:nth-child(5) {
|
div.sphinxsidebarwrapper > h3:nth-child(5) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
div#searchbox {
|
#searchbox {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
div.content {margin-left: 0;}
|
|
||||||
div.body {
|
div.body {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
@@ -613,6 +623,9 @@ div.documentwrapper {
|
|||||||
|
|
||||||
/* On print media remove anything non-essential. */
|
/* On print media remove anything non-essential. */
|
||||||
@media print {
|
@media print {
|
||||||
|
div.document {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
.inline-search {
|
.inline-search {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,5 +36,4 @@ WORKDIR /home/fishuser
|
|||||||
|
|
||||||
COPY fish_run_tests.sh /
|
COPY fish_run_tests.sh /
|
||||||
|
|
||||||
|
|
||||||
CMD /fish_run_tests.sh
|
CMD /fish_run_tests.sh
|
||||||
|
|||||||
@@ -38,5 +38,4 @@ WORKDIR /home/fishuser
|
|||||||
|
|
||||||
COPY fish_run_tests.sh /
|
COPY fish_run_tests.sh /
|
||||||
|
|
||||||
|
|
||||||
CMD /fish_run_tests.sh
|
CMD /fish_run_tests.sh
|
||||||
|
|||||||
@@ -35,5 +35,4 @@ WORKDIR /home/fishuser
|
|||||||
|
|
||||||
COPY fish_run_tests.sh /
|
COPY fish_run_tests.sh /
|
||||||
|
|
||||||
|
|
||||||
CMD /fish_run_tests.sh
|
CMD /fish_run_tests.sh
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ BuildRequires: cargo gettext gcc xz pcre2-devel
|
|||||||
BuildRequires: rust >= 1.70
|
BuildRequires: rust >= 1.70
|
||||||
# Packaging guidelines say to use a BuildRequires: rust-packaging, but it adds no value for our package
|
# Packaging guidelines say to use a BuildRequires: rust-packaging, but it adds no value for our package
|
||||||
|
|
||||||
BuildRequires: cmake >= 3.19
|
BuildRequires: cmake >= 3.15
|
||||||
|
|
||||||
%if 0%{?suse_version}
|
%if 0%{?suse_version}
|
||||||
BuildRequires: update-desktop-files
|
BuildRequires: update-desktop-files
|
||||||
@@ -31,9 +31,14 @@ BuildRequires: glibc-langpack-en
|
|||||||
%endif
|
%endif
|
||||||
BuildRequires: python3 procps
|
BuildRequires: python3 procps
|
||||||
|
|
||||||
|
%if 0%{?suse_version}
|
||||||
|
Requires: terminfo-base
|
||||||
|
%else
|
||||||
|
Requires: ncurses-base
|
||||||
|
%endif
|
||||||
|
Requires: file
|
||||||
Requires: python3
|
Requires: python3
|
||||||
Requires: man
|
Requires: man
|
||||||
Requires: ncurses-base
|
|
||||||
Requires: procps
|
Requires: procps
|
||||||
|
|
||||||
# Although the build scripts mangle the version number to be RPM compatible
|
# Although the build scripts mangle the version number to be RPM compatible
|
||||||
|
|||||||
@@ -6,4 +6,3 @@
|
|||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ fn smoke() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_format_string_str() {
|
fn test_format_string_str() {
|
||||||
let mut s: &str = "hello%world%%%%%";
|
let mut s: &str = "hello%world%%%%%";
|
||||||
assert_eq!(s.is_empty(), false);
|
assert!(!s.is_empty());
|
||||||
for (idx, c) in s.char_indices() {
|
for (idx, c) in s.char_indices() {
|
||||||
assert_eq!(s.at(idx), Some(c));
|
assert_eq!(s.at(idx), Some(c));
|
||||||
}
|
}
|
||||||
@@ -98,7 +98,7 @@ fn test_format_string_str() {
|
|||||||
assert_eq!(s.take_literal(&mut buffer), "world%%");
|
assert_eq!(s.take_literal(&mut buffer), "world%%");
|
||||||
|
|
||||||
s.advance_by(1); // advancing over one more %
|
s.advance_by(1); // advancing over one more %
|
||||||
assert_eq!(s.is_empty(), true); // remaining content is empty
|
assert!(s.is_empty()); // remaining content is empty
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "widestring")]
|
#[cfg(feature = "widestring")]
|
||||||
@@ -122,7 +122,7 @@ fn test_format_string_wstr() {
|
|||||||
assert_eq!(s.take_literal(&mut buffer), "world%%");
|
assert_eq!(s.take_literal(&mut buffer), "world%%");
|
||||||
|
|
||||||
s.advance_by(1); // advancing over one more %
|
s.advance_by(1); // advancing over one more %
|
||||||
assert_eq!(s.is_empty(), true); // remaining content is empty
|
assert!(s.is_empty()); // remaining content is empty
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
1
share/completions/!.fish
Normal file
1
share/completions/!.fish
Normal file
@@ -0,0 +1 @@
|
|||||||
|
complete ! --wraps not
|
||||||
1
share/completions/[.fish
Normal file
1
share/completions/[.fish
Normal file
@@ -0,0 +1 @@
|
|||||||
|
complete [ --wraps test
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
complete -c apt-build -l help -d "Display help and exit"
|
complete -c apt-build -l help -d "Display help and exit"
|
||||||
complete -f -c apt-build -a update -d "Update list of packages"
|
complete -f -c apt-build -a update -d "Update list of packages"
|
||||||
complete -f -c apt-build -a upgrade -d "Upgrade packages"
|
complete -f -c apt-build -a upgrade -d "Upgrade packages"
|
||||||
complete -f -c apt-bulid -a world -d "Rebuild your system"
|
complete -f -c apt-build -a world -d "Rebuild your system"
|
||||||
complete -x -c apt-build -a install -d "Build and install a new package"
|
complete -x -c apt-build -a install -d "Build and install a new package"
|
||||||
complete -x -c apt-build -a source -d "Download and extract a source"
|
complete -x -c apt-build -a source -d "Download and extract a source"
|
||||||
complete -x -c apt-build -a info -d "Info on a package"
|
complete -x -c apt-build -a info -d "Info on a package"
|
||||||
|
|||||||
12
share/completions/batsh.fish
Normal file
12
share/completions/batsh.fish
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
set -l command batsh
|
||||||
|
|
||||||
|
complete -c $command -f
|
||||||
|
|
||||||
|
complete -c $command -s h -l help \
|
||||||
|
-a 'pager\tdefault plain groff' \
|
||||||
|
-d 'Show help'
|
||||||
|
|
||||||
|
complete -c $command -s v -l version -d 'Show version'
|
||||||
|
|
||||||
|
complete -c $command \
|
||||||
|
-a 'bash\t"Compile to Bash" batsh\t"Format file" winbat\t"Compile to Batch"'
|
||||||
@@ -72,7 +72,7 @@ function __fish_bind_complete
|
|||||||
printf '%sshift-\tShift modifier…\n' $prefix
|
printf '%sshift-\tShift modifier…\n' $prefix
|
||||||
set -l key_names minus comma backspace delete escape \
|
set -l key_names minus comma backspace delete escape \
|
||||||
enter up down left right pageup pagedown home end insert tab \
|
enter up down left right pageup pagedown home end insert tab \
|
||||||
space f(seq 12)
|
space menu printscreen f(seq 12)
|
||||||
printf '%s\tNamed key\n' $prefix$key_names
|
printf '%s\tNamed key\n' $prefix$key_names
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
set -l commands status install update remove is-installed random-seed systemd-efi-options reboot-to-firmware list set-default set-oneshot
|
set -l commands status install update remove is-installed random-seed systemd-efi-options reboot-to-firmware list set-default set-oneshot set-timeout set-timeout-oneshot
|
||||||
|
|
||||||
complete -c bootctl -f
|
complete -c bootctl -f
|
||||||
complete -c bootctl -n "not __fish_seen_subcommand_from $commands" -a status -d 'Show status of EFI variables'
|
complete -c bootctl -n "not __fish_seen_subcommand_from $commands" -a status -d 'Show status of EFI variables'
|
||||||
@@ -13,6 +13,8 @@ complete -c bootctl -n "__fish_seen_subcommand_from reboot-to-firmware" -a 'true
|
|||||||
complete -c bootctl -n "not __fish_seen_subcommand_from $commands" -a list -d 'List boot loader entries'
|
complete -c bootctl -n "not __fish_seen_subcommand_from $commands" -a list -d 'List boot loader entries'
|
||||||
complete -c bootctl -n "not __fish_seen_subcommand_from $commands" -a set-default -d 'Set default boot loader entry'
|
complete -c bootctl -n "not __fish_seen_subcommand_from $commands" -a set-default -d 'Set default boot loader entry'
|
||||||
complete -c bootctl -n "not __fish_seen_subcommand_from $commands" -a set-oneshot -d 'Set default boot loader entry (Once)'
|
complete -c bootctl -n "not __fish_seen_subcommand_from $commands" -a set-oneshot -d 'Set default boot loader entry (Once)'
|
||||||
|
complete -c bootctl -n "not __fish_seen_subcommand_from $commands" -a set-timeout -d 'Set default boot loader timeout'
|
||||||
|
complete -c bootctl -n "not __fish_seen_subcommand_from $commands" -a set-timeout-oneshot -d 'Set default boot loader timeout (Once)'
|
||||||
|
|
||||||
complete -c bootctl -s h -l help -d 'Show this help'
|
complete -c bootctl -s h -l help -d 'Show this help'
|
||||||
complete -c bootctl -l version -d 'Print version'
|
complete -c bootctl -l version -d 'Print version'
|
||||||
|
|||||||
62
share/completions/btrbk.fish
Normal file
62
share/completions/btrbk.fish
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# Filter Completion
|
||||||
|
function __fish_btrbk_complete_filter
|
||||||
|
btrbk list config --format col:h:snapshot_name,source_subvolume,target_url | string replace -r '([^ ]+)\s+([^ ]+)\s+([^ ]*)' '$1\t$2 -> $3'
|
||||||
|
end
|
||||||
|
|
||||||
|
# options with arguments
|
||||||
|
complete -c btrbk -l format -x -d 'Change output format' -a "table long raw"
|
||||||
|
complete -c btrbk -l loglevel -s l -x -d 'Set logging level' -a "error warn info debug trace"
|
||||||
|
complete -c btrbk -l exclude -x -d 'Exclude configured sections' -a "(__fish_btrbk_complete_filter)"
|
||||||
|
complete -c btrbk -l override -x -d 'Globally override a configuration option'
|
||||||
|
|
||||||
|
# options with file completion
|
||||||
|
complete -c btrbk -l config -r -s c -d 'Specify configuration file'
|
||||||
|
complete -c btrbk -l lockfile -r -d 'Create and check lockfile'
|
||||||
|
|
||||||
|
# options without arguments
|
||||||
|
complete -c btrbk -l help -s h -d 'Display this help message'
|
||||||
|
complete -c btrbk -l version -d 'Display version information'
|
||||||
|
complete -c btrbk -l dry-run -s n -d 'Perform a trial run with no changes made'
|
||||||
|
complete -c btrbk -l preserve -s p -d 'Preserve all (do not delete anything)'
|
||||||
|
complete -c btrbk -l preserve-snapshots -d 'Preserve snapshots (do not delete snapshots)'
|
||||||
|
complete -c btrbk -l preserve-backups -d 'Preserve backups (do not delete backups)'
|
||||||
|
complete -c btrbk -l wipe -d 'Delete all but latest snapshots'
|
||||||
|
complete -c btrbk -l verbose -s v -d 'Be more verbose (increase logging level)'
|
||||||
|
complete -c btrbk -l quiet -s q -d 'Be quiet (do not print backup summary)'
|
||||||
|
complete -c btrbk -l table -s t -d 'Change output to table format'
|
||||||
|
complete -c btrbk -l long -s L -d 'Change output to long format'
|
||||||
|
complete -c btrbk -l print-schedule -s S -d 'Print scheduler details (for the "run" command)'
|
||||||
|
complete -c btrbk -l progress -d 'Show progress bar on send-receive operation'
|
||||||
|
|
||||||
|
# uncommon options from manpage
|
||||||
|
complete -c btrbk -l single-column -s 1 -d 'Print output as a single column'
|
||||||
|
complete -c btrbk -l pretty -d 'Print pretty table output with lowercase and underlined column headings'
|
||||||
|
complete -c btrbk -l raw -d 'Create raw targets for archive command'
|
||||||
|
|
||||||
|
# subcommands
|
||||||
|
complete -c btrbk -f -n __fish_use_subcommand -a run -d 'Run snapshot and backup operations'
|
||||||
|
complete -c btrbk -f -n __fish_use_subcommand -a dryrun -d 'Show what would be executed without running btrfs commands'
|
||||||
|
complete -c btrbk -f -n __fish_use_subcommand -a snapshot -d 'Run snapshot operations only'
|
||||||
|
complete -c btrbk -f -n __fish_use_subcommand -a resume -d 'Run backup operations and delete snapshots'
|
||||||
|
complete -c btrbk -f -n __fish_use_subcommand -a prune -d 'Only delete snapshots and backups'
|
||||||
|
complete -c btrbk -f -n __fish_use_subcommand -a archive -d 'Recursively copy all subvolumes (src -> dst)'
|
||||||
|
complete -c btrbk -f -n __fish_use_subcommand -a clean -d 'Delete incomplete (garbled) backups'
|
||||||
|
complete -c btrbk -f -n __fish_use_subcommand -a stats -d 'Print snapshot/backup statistics'
|
||||||
|
complete -c btrbk -f -n __fish_use_subcommand -a usage -d 'Print filesystem usage'
|
||||||
|
complete -c btrbk -f -n __fish_use_subcommand -a ls -d 'List all btrfs subvolumes below a given path'
|
||||||
|
complete -c btrbk -f -n __fish_use_subcommand -a origin -d 'Print origin information for a subvolume'
|
||||||
|
complete -c btrbk -f -n __fish_use_subcommand -a diff -d 'List file changes between related subvolumes'
|
||||||
|
complete -c btrbk -f -n __fish_use_subcommand -a extents -d 'Calculate accurate disk space usage for a path'
|
||||||
|
complete -c btrbk -f -n __fish_use_subcommand -a list -d 'List snapshots and backups'
|
||||||
|
|
||||||
|
# subsubcommands for "list"
|
||||||
|
complete -c btrbk -n '__fish_seen_subcommand_from list' -f -a all -d 'List all snapshots and backups'
|
||||||
|
complete -c btrbk -n '__fish_seen_subcommand_from list' -f -a snapshots -d 'List snapshots only'
|
||||||
|
complete -c btrbk -n '__fish_seen_subcommand_from list' -f -a backups -d 'List backups and correlated snapshots'
|
||||||
|
complete -c btrbk -n '__fish_seen_subcommand_from list' -f -a latest -d 'List most recent snapshots and backups'
|
||||||
|
complete -c btrbk -n '__fish_seen_subcommand_from list' -f -a config -d 'List configured source/snapshot/target relations'
|
||||||
|
complete -c btrbk -n '__fish_seen_subcommand_from list' -f -a source -d 'List configured source/snapshot relations'
|
||||||
|
complete -c btrbk -n '__fish_seen_subcommand_from list' -f -a volume -d 'List configured volume sections'
|
||||||
|
complete -c btrbk -n '__fish_seen_subcommand_from list' -f -a target -d 'List configured targets'
|
||||||
|
|
||||||
|
complete -c btrbk -n '__fish_seen_subcommand_from run dryrun snapshot resume prune clean' -x -a '(__fish_btrbk_complete_filter)'
|
||||||
@@ -16,14 +16,12 @@ complete -c code -l user-data-dir -ra "(__fish_complete_directories)" -d 'Specif
|
|||||||
complete -c code -l profile -d 'Opens the provided folder or workspace with the given profile'
|
complete -c code -l profile -d 'Opens the provided folder or workspace with the given profile'
|
||||||
complete -c code -s v -l version -d 'Print version'
|
complete -c code -s v -l version -d 'Print version'
|
||||||
complete -c code -s h -l help -d 'Print usage'
|
complete -c code -s h -l help -d 'Print usage'
|
||||||
complete -c code -l folder-uri -d 'Opens a window with given folder uri(s)'
|
|
||||||
complete -c code -l file-uri -d 'Opens a window with given file uri(s)'
|
|
||||||
|
|
||||||
# Extensions management
|
# Extensions management
|
||||||
complete -c code -l extensions-dir -d 'Set the root path for extensions'
|
complete -c code -l extensions-dir -r -d 'Set the root path for extensions'
|
||||||
complete -c code -l list-extensions -d 'List the installed extensions'
|
complete -c code -l list-extensions -d 'List the installed extensions'
|
||||||
complete -c code -l show-versions -d 'Show versions of installed extensions' -n '__fish_seen_argument -l list-extensions'
|
complete -c code -l show-versions -d 'Show versions of installed extensions' -n '__fish_seen_argument -l list-extensions'
|
||||||
complete -c code -l category -d 'Filters installed extensions by provided category' -n '__fish_seen_argument -l list-extensions'
|
complete -c code -l category -x -d 'Filters installed extensions by provided category' -n '__fish_seen_argument -l list-extensions'
|
||||||
complete -c code -l install-extension -ra "(__fish_complete_vscode_extensions)" -d 'Installs or updates the extension'
|
complete -c code -l install-extension -ra "(__fish_complete_vscode_extensions)" -d 'Installs or updates the extension'
|
||||||
complete -c code -l force -n '__fish_seen_argument -l install-extension' -d 'Updates to the latest version'
|
complete -c code -l force -n '__fish_seen_argument -l install-extension' -d 'Updates to the latest version'
|
||||||
complete -c code -l pre-release -n '__fish_seen_argument -l install-extension' -d 'Installs the pre-release version'
|
complete -c code -l pre-release -n '__fish_seen_argument -l install-extension' -d 'Installs the pre-release version'
|
||||||
@@ -35,12 +33,13 @@ complete -c code -l disable-extensions -d 'Disable all installed extensions'
|
|||||||
|
|
||||||
# Troubleshooting
|
# Troubleshooting
|
||||||
complete -c code -l verbose -d 'Print verbose output (implies --wait)'
|
complete -c code -l verbose -d 'Print verbose output (implies --wait)'
|
||||||
complete -c code -l log -a 'critical error warn info debug trace off' -d 'Log level to use (default: info)'
|
complete -c code -l log -xa 'critical error warn info debug trace off' -d 'Log level to use (default: info)'
|
||||||
complete -c code -s s -l status -d 'Print process usage and diagnostics information'
|
complete -c code -s s -l status -d 'Print process usage and diagnostics information'
|
||||||
complete -c code -l prof-startup -d 'Run CPU profiler during startup'
|
complete -c code -l prof-startup -d 'Run CPU profiler during startup'
|
||||||
complete -c code -l sync -d 'Turn sync on or off'
|
complete -c code -l sync -xa 'on off' -d 'Turn sync on or off'
|
||||||
complete -c code -l inspect-extensions -d 'Allow debugging and profiling of extensions'
|
complete -c code -l inspect-extensions -x -d 'Allow debugging and profiling of extensions'
|
||||||
complete -c code -l inspect-brk-extensions -x -d 'Allow debugging and profiling of extensions'
|
complete -c code -l inspect-brk-extensions -x -d 'Allow debugging and profiling of extensions'
|
||||||
|
complete -c code -l disable-lcd-text -d 'Disable LCD font rendering'
|
||||||
complete -c code -l disable-gpu -d 'Disable GPU hardware acceleration'
|
complete -c code -l disable-gpu -d 'Disable GPU hardware acceleration'
|
||||||
complete -c code -l disable-chromium-sandbox -d 'Disable the Chromium sandbox environment'
|
complete -c code -l disable-chromium-sandbox -d 'Disable the Chromium sandbox environment'
|
||||||
complete -c code -l telemetry -d 'Shows all telemetry events which VS code collects'
|
complete -c code -l telemetry -d 'Shows all telemetry events which VS code collects'
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
function __dnf_list_installed_packages
|
function __dnf_list_installed_packages
|
||||||
dnf repoquery --cacheonly "$cur*" --qf "%{name}" --installed </dev/null
|
dnf repoquery --cacheonly "$cur*" --qf "%{name}\n" --installed </dev/null
|
||||||
end
|
end
|
||||||
|
|
||||||
function __dnf_list_available_packages
|
function __dnf_list_available_packages
|
||||||
@@ -26,7 +26,7 @@ function __dnf_list_available_packages
|
|||||||
else
|
else
|
||||||
# In some cases dnf will ask for input (e.g. to accept gpg keys).
|
# In some cases dnf will ask for input (e.g. to accept gpg keys).
|
||||||
# Connect it to /dev/null to try to stop it.
|
# Connect it to /dev/null to try to stop it.
|
||||||
set results (dnf repoquery --cacheonly "$tok*" --qf "%{name}" --available </dev/null 2>/dev/null)
|
set results (dnf repoquery --cacheonly "$tok*" --qf "%{name}\n" --available </dev/null 2>/dev/null)
|
||||||
end
|
end
|
||||||
if set -q results[1]
|
if set -q results[1]
|
||||||
set results (string match -r -- '.*\\.rpm$' $files) $results
|
set results (string match -r -- '.*\\.rpm$' $files) $results
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
complete -c dust -s d -l depth -d "Depth to show"
|
|
||||||
complete -c dust -s n -l number-of-lines -d "Number of lines of output to show"
|
|
||||||
complete -c dust -s p -l full-paths -d "Subdirectories will not have their path shortened"
|
|
||||||
complete -c dust -s X -l ignore-directory -d "Exclude any file or directory with this name"
|
|
||||||
complete -c dust -s I -l ignore-all-in-file -d "Exclude any file or directory with a regex"
|
|
||||||
complete -c dust -s L -l dereference-links -d "dereference sym links - Treat sym links as directories and go into them"
|
|
||||||
complete -c dust -s x -l limit-filesystem -d "Only count the files and directories on the same filesystem as the supplied directory"
|
|
||||||
complete -c dust -s s -l apparent-size -d "Use file length instead of blocks"
|
|
||||||
complete -c dust -s r -l reverse -d "Print tree upside down (biggest highest)"
|
|
||||||
complete -c dust -s c -l no-colors -d "No colors will be printed"
|
|
||||||
complete -c dust -s C -l force-colors -d "Force colors print"
|
|
||||||
complete -c dust -s b -l no-percent-bars -d "No percent bars or percentages will be displayed"
|
|
||||||
complete -c dust -s B -l bars-on-right -d "percent bars moved to right side of screen"
|
|
||||||
complete -c dust -s z -l min-size -d "Minimum size file to include in output"
|
|
||||||
complete -c dust -s R -l screen-reader -d "For screen readers"
|
|
||||||
complete -c dust -l skip-total -d "No total row will be displayed"
|
|
||||||
complete -c dust -s f -l filecount -d "Directory 'size' is number of child files instead of disk size"
|
|
||||||
complete -c dust -s i -l ignore_hidden -d "Do not display hidden files"
|
|
||||||
complete -c dust -s v -l invert-filter -d "Exclude filepaths matching this regex"
|
|
||||||
complete -c dust -s e -l filter -d "Only include filepaths matching this regex"
|
|
||||||
complete -c dust -s t -l file_types -d "show only these file types"
|
|
||||||
complete -c dust -s w -l terminal_width -d "Specify width of output"
|
|
||||||
complete -c dust -s P -l no-progress -d "Disable the progress indication"
|
|
||||||
complete -c dust -s D -l only-dir -d "Only directories will be displayed"
|
|
||||||
complete -c dust -s F -l only-file -d "Only files will be displayed (finds your largest files)"
|
|
||||||
complete -c dust -s o -l output-format -d "Changes output display size"
|
|
||||||
complete -c dust -s S -l stack-size -d "Specify memory to use as stack size"
|
|
||||||
complete -c dust -s h -l help -d "Print help"
|
|
||||||
complete -c dust -s V -l version -d "Print version"
|
|
||||||
@@ -1,26 +1 @@
|
|||||||
function __fish_exercism_no_subcommand -d 'Test if exercism has yet to be given the subcommand'
|
exercism completion fish | source
|
||||||
for i in (commandline -xpc)
|
|
||||||
if contains -- $i demo debug configure fetch restore submit unsubmit tracks download help
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
complete -c exercism -s c -l config -d 'path to config file [$EXERCISM_CONFIG_FILE, $XDG_CONFIG_HOME]'
|
|
||||||
complete -c exercism -s v -l verbose -d "turn on verbose logging"
|
|
||||||
complete -c exercism -s h -l help -d "show help"
|
|
||||||
complete -c exercism -s v -l version -d "print the version"
|
|
||||||
complete -f -n __fish_exercism_no_subcommand -c exercism -a configure -d "Writes config values to a JSON file"
|
|
||||||
complete -f -n __fish_exercism_no_subcommand -c exercism -a debug -d "Outputs useful debug information"
|
|
||||||
complete -f -n __fish_exercism_no_subcommand -c exercism -a download -d "Downloads a solution given the ID of the latest iteration"
|
|
||||||
complete -f -n __fish_exercism_no_subcommand -c exercism -a fetch -d "Fetches the next unsubmitted problem in each track"
|
|
||||||
complete -f -n __fish_exercism_no_subcommand -c exercism -a list -d "Lists the available problems for a language track, given its ID"
|
|
||||||
complete -f -n __fish_exercism_no_subcommand -c exercism -a open -d "Opens exercism.io on given problem"
|
|
||||||
complete -f -n __fish_exercism_no_subcommand -c exercism -a restore -d "Downloads the most recent iteration for each of your solutions on exercism.io"
|
|
||||||
complete -f -n __fish_exercism_no_subcommand -c exercism -a skip -d "Skips a problem given a track ID and problem slug"
|
|
||||||
complete -f -n __fish_exercism_no_subcommand -c exercism -a status -d "Fetches information about your progress with a given language track"
|
|
||||||
complete -f -n __fish_exercism_no_subcommand -c exercism -a submit -d "Submits a new iteration to a problem on exercism.io"
|
|
||||||
complete -f -n __fish_exercism_no_subcommand -c exercism -a tracks -d "Lists the available language tracks"
|
|
||||||
complete -f -n __fish_exercism_no_subcommand -c exercism -a upgrade -d "Upgrades the CLI to the latest released version"
|
|
||||||
complete -f -n __fish_exercism_no_subcommand -c exercism -a help -d "show help"
|
|
||||||
|
|||||||
2
share/completions/fish-lsp.fish
Normal file
2
share/completions/fish-lsp.fish
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
__fish_cache_sourced_completions fish-lsp complete
|
||||||
|
or fish-lsp complete | source
|
||||||
1
share/completions/folderify.fish
Normal file
1
share/completions/folderify.fish
Normal file
@@ -0,0 +1 @@
|
|||||||
|
folderify --completions fish | source
|
||||||
1
share/completions/gcloud.fish
Normal file
1
share/completions/gcloud.fish
Normal file
@@ -0,0 +1 @@
|
|||||||
|
complete -c gcloud -f -a '(__fish_argcomplete_complete gcloud)'
|
||||||
@@ -16,6 +16,7 @@ complete -c gem -n __fish_use_subcommand -xa cleanup -d "Cleanup old versions of
|
|||||||
complete -c gem -n __fish_use_subcommand -xa contents -d "Display the contents of the installed gems"
|
complete -c gem -n __fish_use_subcommand -xa contents -d "Display the contents of the installed gems"
|
||||||
complete -c gem -n __fish_use_subcommand -xa dependency -d "Show the dependencies of an installed gem"
|
complete -c gem -n __fish_use_subcommand -xa dependency -d "Show the dependencies of an installed gem"
|
||||||
complete -c gem -n __fish_use_subcommand -xa environment -d "Display RubyGems environmental information"
|
complete -c gem -n __fish_use_subcommand -xa environment -d "Display RubyGems environmental information"
|
||||||
|
complete -c gem -n __fish_use_subcommand -xa fetch -d "Download a gem into current directory"
|
||||||
complete -c gem -n __fish_use_subcommand -xa help -d "Provide help on the 'gem' command"
|
complete -c gem -n __fish_use_subcommand -xa help -d "Provide help on the 'gem' command"
|
||||||
complete -c gem -n __fish_use_subcommand -xa install -d "Install a gem into the local repository"
|
complete -c gem -n __fish_use_subcommand -xa install -d "Install a gem into the local repository"
|
||||||
complete -c gem -n __fish_use_subcommand -xa list -d "Display all gems whose name starts with STRING"
|
complete -c gem -n __fish_use_subcommand -xa list -d "Display all gems whose name starts with STRING"
|
||||||
@@ -86,6 +87,9 @@ complete $dep_opt -s p -l pipe -d "Pipe Format (name --version ver)"
|
|||||||
set -l env_opt -c gem -n 'contains environment (commandline -pxc)'
|
set -l env_opt -c gem -n 'contains environment (commandline -pxc)'
|
||||||
complete $env_opt -xa "packageversion\t'display the package version' gemdir\t'display the path where gems are installed' gempath\t'display path used to search for gems' version\t'display the gem format version' remotesources\t'display the remote gem servers'"
|
complete $env_opt -xa "packageversion\t'display the package version' gemdir\t'display the path where gems are installed' gempath\t'display path used to search for gems' version\t'display the gem format version' remotesources\t'display the remote gem servers'"
|
||||||
|
|
||||||
|
set -l fetch_opt -c gem -n 'contains fetch (commandline -pxc)'
|
||||||
|
complete $fetch_opt -s v -l version -d "Specify version of gem to download" -x
|
||||||
|
|
||||||
##
|
##
|
||||||
# help
|
# help
|
||||||
set -l help_opt -c gem -n 'contains help (commandline -pxc)'
|
set -l help_opt -c gem -n 'contains help (commandline -pxc)'
|
||||||
|
|||||||
1
share/completions/gsutil.fish
Normal file
1
share/completions/gsutil.fish
Normal file
@@ -0,0 +1 @@
|
|||||||
|
complete -c gsutil -f -a '(__fish_argcomplete_complete gsutil)'
|
||||||
@@ -15,7 +15,7 @@ complete -c htop -l readonly -d 'Disable all system and process changing feature
|
|||||||
complete -c htop -l version -s V -d 'Show version and exit'
|
complete -c htop -l version -s V -d 'Show version and exit'
|
||||||
complete -c htop -l tree -s t -d 'Show processes in tree view'
|
complete -c htop -l tree -s t -d 'Show processes in tree view'
|
||||||
complete -c htop -l highlight-changes -s H -d 'Highlight new and old processes' -x
|
complete -c htop -l highlight-changes -s H -d 'Highlight new and old processes' -x
|
||||||
complete -c htop -l drop-capabilites -d 'Drop unneeded Linux capabilites (Requires libpcap support)' -xka "
|
complete -c htop -l drop-capabilities -d 'Drop unneeded Linux capabilities (Requires libpcap support)' -xka "
|
||||||
off
|
off
|
||||||
basic
|
basic
|
||||||
strict
|
strict
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
# Basic completions for simonw/llm
|
# Completions for simonw/llm
|
||||||
# A complete implementation for `llm [prompt]` but other subcommands
|
|
||||||
# can be further fleshed out.
|
|
||||||
|
|
||||||
set -l subcmds prompt aliases chat collections embed embed-models embed-multi install keys logs models openai plugins similar templates uninstall
|
set -l subcmds prompt aliases chat collections embed embed-models embed-multi install keys logs models openai plugins similar templates uninstall
|
||||||
function __fish_llm_subcmds
|
function __fish_llm_subcmds
|
||||||
@@ -10,7 +8,7 @@ function __fish_llm_subcmds
|
|||||||
"collections" "View/manage embedding collections" \
|
"collections" "View/manage embedding collections" \
|
||||||
"embed" "Embed text and get/store result" \
|
"embed" "Embed text and get/store result" \
|
||||||
"embed-models" "Manage available embedding models" \
|
"embed-models" "Manage available embedding models" \
|
||||||
"embed-multi\Store embeddings for multiple strings" \
|
"embed-multi" "Store embeddings for multiple strings" \
|
||||||
"install" "Install PyPI packages into llm env" \
|
"install" "Install PyPI packages into llm env" \
|
||||||
"keys" "Manage stored API keys" \
|
"keys" "Manage stored API keys" \
|
||||||
"logs" "Explore logged prompts/responses" \
|
"logs" "Explore logged prompts/responses" \
|
||||||
@@ -27,24 +25,117 @@ complete -c llm -n __fish_is_first_token -xa "(__fish_llm_subcmds)"
|
|||||||
# This applies to the base command only
|
# This applies to the base command only
|
||||||
complete -c llm -n "not __fish_seen_subcommand_from $subcmds" -l version -d "Show version info"
|
complete -c llm -n "not __fish_seen_subcommand_from $subcmds" -l version -d "Show version info"
|
||||||
# This applies to the base command or any subcommands
|
# This applies to the base command or any subcommands
|
||||||
complete -c llm -l help -d "Show usage info"
|
complete -c llm -l help -d "Show command usage info" -x
|
||||||
|
|
||||||
function __fish_llm_models
|
function __fish_llm_models
|
||||||
llm models |
|
llm models |
|
||||||
string replace -r '^[^:]+: ([^ ]+)(?: \\(aliases: )?([^),]+,?)?+.*$' '$1 $2' |
|
string replace -r '^[^:\\n]+: (\\S+)(?: \\(aliases: )?((?:[^),\\s]+,?)?+.*?)\\)?$' '$1 $2' |
|
||||||
|
string split ' ' -n |
|
||||||
|
string trim -c ','
|
||||||
|
end
|
||||||
|
|
||||||
|
function __fish_embedding_models
|
||||||
|
llm models |
|
||||||
|
string replace -r '^[^:\\n]+: (\\S+)(?: \\(aliases: )?((?:[^),\\s]+,?)?+.*?)\\)?$' '$1 $2' |
|
||||||
string split ' ' -n |
|
string split ' ' -n |
|
||||||
string trim -c ','
|
string trim -c ','
|
||||||
end
|
end
|
||||||
|
|
||||||
# The default subcommand is 'prompt'
|
# The default subcommand is 'prompt'
|
||||||
set -l is_prompt "not __fish_seen_subcommand_from $subcmds || __fish_seen_subcommand_from prompt"
|
set -l condition "not __fish_seen_subcommand_from $subcmds || __fish_seen_subcommand_from prompt"
|
||||||
complete -c llm -n $is_prompt -s s -l system -d "System prompt to use"
|
complete -c llm -n $condition -s s -l system -d "System prompt to use" -r
|
||||||
complete -c llm -n $is_prompt -s m -l model -d "Model to use" -xa "(__fish_llm_models)"
|
complete -c llm -n $condition -s m -l model -d "Model to use" -xa "(__fish_llm_models)"
|
||||||
complete -c llm -n $is_prompt -s a -l attachment -d "Attachment to use" -r -a'-'
|
complete -c llm -n $condition -s a -l attachment -d "Attachment to use" -ra'-'
|
||||||
complete -c llm -n $is_prompt -l at -d "Attachment type" -r
|
complete -c llm -n $condition -l at -d "Attachment type" -r
|
||||||
complete -c llm -n $is_prompt -l attachment-type -d "Attachment type" -r
|
complete -c llm -n $condition -l attachment-type -d "Attachment type" -r
|
||||||
complete -c llm -n $is_prompt -s n -l no-log -d "Don't log to db"
|
complete -c llm -n $condition -s n -l no-log -d "Don't log to db" -x
|
||||||
complete -c llm -n $is_prompt -s l -l log -d "Log prompt/reply to db"
|
complete -c llm -n $condition -s l -l log -d "Log prompt/reply to db" -x
|
||||||
complete -c llm -n $is_prompt -s c -l continue -d "Continue most recent conversation"
|
complete -c llm -n $condition -s c -l continue -d "Continue most recent conversation" -x
|
||||||
complete -c llm -n $is_prompt -l key -d "API key to use"
|
complete -c llm -n $condition -l key -d "API key to use" -r
|
||||||
complete -c llm -n $is_prompt -l save -d "Save prompt as template with name" -r
|
complete -c llm -n $condition -l save -d "Save prompt as template with name" -x
|
||||||
|
|
||||||
|
# llm aliases
|
||||||
|
set -l condition "__fish_seen_subcommand_from aliases"
|
||||||
|
complete -c llm -n $condition -xa list -d "List current aliases" -x
|
||||||
|
complete -c llm -n $condition -xa path -d "Print path of llm's aliases.json" -x
|
||||||
|
complete -c llm -n $condition -xa remove -d "Remove an llm alias" -r
|
||||||
|
complete -c llm -n $condition -xa set -d "Set an alias for a model" -r
|
||||||
|
|
||||||
|
# llm aliases
|
||||||
|
set -l condition "__fish_seen_subcommand_from chat"
|
||||||
|
complete -c llm -n $condition -s s -l system -d "System prompt to use" -r
|
||||||
|
complete -c llm -n $condition -s m -l model -d "Model to use" -xa "(__fish_llm_models)"
|
||||||
|
complete -c llm -n $condition -l cid -d "Continue conversation with given id" -x
|
||||||
|
complete -c llm -n $condition -l conversation -d "Continue conversation with given id" -x
|
||||||
|
complete -c llm -n $condition -s t -l template -d "Template to use" -x
|
||||||
|
complete -c llm -n $condition -s p -l param -d "Set template parameter to value" -x
|
||||||
|
complete -c llm -n $condition -s o -l option -d "Set key/value option for model" -x
|
||||||
|
complete -c llm -n $condition -l no-stream -d "Do not stream output" -x
|
||||||
|
complete -c llm -n $condition -l key -d "API key to use" -x
|
||||||
|
|
||||||
|
# llm collections
|
||||||
|
set -l condition "__fish_seen_subcommand_from collections"
|
||||||
|
complete -c llm -n $condition -xa list -d "List collections" -x
|
||||||
|
complete -c llm -n $condition -xa delete -d "Delete specified collection" -x
|
||||||
|
complete -c llm -n $condition -xa path -d "Print path to embeddings database" -x
|
||||||
|
|
||||||
|
# llm embed
|
||||||
|
set -l condition "__fish_seen_subcommand_from embed"
|
||||||
|
complete -c llm -n $condition -s i -l input -d "File to embed" -r
|
||||||
|
complete -c llm -n $condition -s m -l model -d "Model to use" -xa "(__fish_embedding_models)"
|
||||||
|
complete -c llm -n $condition -l store -d "Store the text itself in the db" -x
|
||||||
|
complete -c llm -n $condition -s d -l database -d "Path to db to use" -r
|
||||||
|
complete -c llm -n $condition -s c -l content -d "Text content to embed" -x
|
||||||
|
complete -c llm -n $condition -l binary -d "Treat input as binary" -x
|
||||||
|
complete -c llm -n $condition -l metadata -d "JSON object metadata to store" -x
|
||||||
|
complete -c llm -n $condition -s f -l format -d "Output format" -xa "json blob base64 hex"
|
||||||
|
|
||||||
|
# llm embed-models
|
||||||
|
set -l condition "__fish_seen_subcommand_from embed-models"
|
||||||
|
complete -c llm -n $condition -xa list -d "List available embedding models" -x
|
||||||
|
complete -c llm -n $condition -xa default -d "Show or set default embedding model" -x
|
||||||
|
|
||||||
|
# llm embed-multi
|
||||||
|
set -l condition "__fish_seen_subcommand_from embed-multi"
|
||||||
|
complete -c llm -n $condition -l format -xa "json csv tsv nl" -d "Format of input (default: auto-detected)"
|
||||||
|
complete -c llm -n $condition -l files -r -d "Embed files in DIR matching GLOB"
|
||||||
|
complete -c llm -n $condition -l encoding -r -d "Encoding to use when reading input"
|
||||||
|
complete -c llm -n $condition -l binary -d "Treat input as binary"
|
||||||
|
complete -c llm -n $condition -l sql -x -d "Read input using this SQL query"
|
||||||
|
complete -c llm -n $condition -l attach -x -d "Attach db ALIAS from PATH"
|
||||||
|
complete -c llm -n $condition -l batch-size -x -d "Batch size to use for embeddings"
|
||||||
|
complete -c llm -n $condition -l prefix -x -d "Prefix to add to the IDs"
|
||||||
|
complete -c llm -n $condition -s m -l model -d "Embedding model to use" -xa "(__fish_embedding_models)"
|
||||||
|
complete -c llm -n $condition -l store -d "Store the text itself in the db"
|
||||||
|
complete -c llm -n $condition -s d -l database -d "Path to db to use"
|
||||||
|
|
||||||
|
# llm install
|
||||||
|
set -l condition "__fish_seen_subcommand_from install"
|
||||||
|
complete -c llm -n $condition -s U -l upgrade -d "Upgrade packages to latest version" -x
|
||||||
|
complete -c llm -n $condition -s e -l editable -d "Install project in editable mode from PATH" -r
|
||||||
|
complete -c llm -n $condition -l force-reinstall -d "Reinstall all packages, even if up-to-date" -x
|
||||||
|
complete -c llm -n $condition -l no-cache-dir -d "Disable cache" -x
|
||||||
|
|
||||||
|
# llm keys
|
||||||
|
set -l condition "__fish_seen_subcommand_from keys"
|
||||||
|
complete -c llm -n $condition -xa list -d "List names of all stored keys"
|
||||||
|
complete -c llm -n $condition -xa get -d "Print saved key"
|
||||||
|
complete -c llm -n $condition -xa path -d "Print path of llm's keys.json"
|
||||||
|
complete -c llm -n $condition -xa set -d "Save a key in llm's keys.json"
|
||||||
|
|
||||||
|
# llm logs
|
||||||
|
set -l condition "__fish_seen_subcommand_from logs"
|
||||||
|
complete -c llm -n $condition -xa list -d "List recent prompts and responses"
|
||||||
|
complete -c llm -n $condition -xa off -d "Turn off logging"
|
||||||
|
complete -c llm -n $condition -xa on -d "Turn on logging"
|
||||||
|
complete -c llm -n $condition -xa path -d "Print path to llm's logs.db"
|
||||||
|
complete -c llm -n $condition -xa status -d "Show current status of db logging"
|
||||||
|
|
||||||
|
# llm models
|
||||||
|
set -l condition "__fish_seen_subcommand_from models"
|
||||||
|
complete -c llm -n $condition -xa list -d "List available models" -x
|
||||||
|
complete -c llm -n $condition -xa default -d "Show or set default model" -x
|
||||||
|
|
||||||
|
# llm plugins
|
||||||
|
set -l condition "__fish_seen_subcommand_from plugins"
|
||||||
|
complete -c llm -n $condition -l all -d "Include built-in/default plugins" -x
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
complete -c md5sum -d "Compute and check message digest" -r
|
complete -c md5sum -d "Compute and check message digest" -r
|
||||||
complete -c md5sum -s b -l binary -d 'Read in binary mode'
|
complete -c md5sum -s b -l binary -d 'Read in binary mode'
|
||||||
complete -c md5sum -s c -l check -d "Read sums from files and check them"
|
complete -c md5sum -s c -l check -d "Read sums from files and check them"
|
||||||
complete -c md5sum -s t -l text -d 'Read in text mode'
|
complete -c md5sum -l tag -d 'Create a BSD-style checksum'
|
||||||
complete -c md5sum -l quiet -d 'Don''t print OK for each successfully verified file'
|
complete -c md5sum -s t -l text -d 'Read in text mode (default)'
|
||||||
complete -c md5sum -l status -d 'Don''t output anything, status code shows success'
|
complete -c md5sum -s z -l zero -d 'End each output line with NUL, not newline, and disable file name escaping'
|
||||||
complete -c md5sum -s w -l warn -d 'Warn about improperly formatted checksum lines'
|
complete -c md5sum -l ignore-missing -d 'Don\'t fail or report status for missing files'
|
||||||
|
complete -c md5sum -l quiet -d 'Don\'t print OK for each successfully verified file'
|
||||||
|
complete -c md5sum -l status -d 'Don\'t output anything, status code shows success'
|
||||||
complete -c md5sum -l strict -d 'With --check, exit non-zero for any invalid input'
|
complete -c md5sum -l strict -d 'With --check, exit non-zero for any invalid input'
|
||||||
|
complete -c md5sum -s w -l warn -d 'Warn about improperly formatted checksum lines'
|
||||||
complete -c md5sum -l help -d 'Display help text'
|
complete -c md5sum -l help -d 'Display help text'
|
||||||
complete -c md5sum -l version -d 'Output version information and exit'
|
complete -c md5sum -l version -d 'Output version information and exit'
|
||||||
|
|||||||
94
share/completions/mksquashfs.fish
Normal file
94
share/completions/mksquashfs.fish
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
complete -c mksquashfs -o b -d 'Data block size'
|
||||||
|
complete -c mksquashfs -o comp -d 'Selects the compression scheme' -xa 'gzip lzo lz4 xz zstd lzma'
|
||||||
|
complete -c mksquashfs -o noI -o noInodeCompression -d 'Do not compress inode table'
|
||||||
|
complete -c mksquashfs -o noId -o noIdTableCompression -d 'Do not compress the uid/gid table'
|
||||||
|
complete -c mksquashfs -o noD -o noDataCompression -d 'Do not compress data blocks'
|
||||||
|
complete -c mksquashfs -o noF -o noFragmentCompression -d 'Do not compress fragment blocks'
|
||||||
|
complete -c mksquashfs -o noX -o noXattrCompression -d 'Do not compress extended attributes'
|
||||||
|
complete -c mksquashfs -o no-compression -d 'Do not compress any of the data or metadata'
|
||||||
|
complete -c mksquashfs -o tar -d 'Read uncompressed tar file from standard in (stdin)'
|
||||||
|
complete -c mksquashfs -o no-strip -o tarstyle -d 'Act like tar, and do not strip leading directories from source files'
|
||||||
|
complete -c mksquashfs -o cpiostyle -d 'Act like cpio, and read file pathnames from standard in (stdin)'
|
||||||
|
complete -c mksquashfs -o cpiostyle0 -d 'Like -cpiostyle, but filenames are null terminated'
|
||||||
|
complete -c mksquashfs -o reproducible -d 'Build filesystems that are reproducible'
|
||||||
|
complete -c mksquashfs -o not-reproducible -d 'Build filesystems that are not reproducible'
|
||||||
|
complete -c mksquashfs -o mkfs-time -o fstime -xd 'Set filesystem creation timestamp'
|
||||||
|
complete -c mksquashfs -o all-time -xd 'Set all file timestamps'
|
||||||
|
complete -c mksquashfs -o root-time -xd 'Set root directory time'
|
||||||
|
complete -c mksquashfs -o root-mode -xd 'Set root directory permissions to octal <mode>'
|
||||||
|
complete -c mksquashfs -o root-uid -xa '(__fish_complete_user_ids)' -d 'Set root directory owner'
|
||||||
|
complete -c mksquashfs -o root-gid -xa '(__fish_complete_group_ids)' -d 'Set root directory group'
|
||||||
|
complete -c mksquashfs -o all-root -o root-owned -d 'Make all files owned by root'
|
||||||
|
complete -c mksquashfs -o force-uid -xa '(__fish_complete_user_ids)' -d 'Set all file uids'
|
||||||
|
complete -c mksquashfs -o force-gid -xa '(__fish_complete_group_ids)' -d 'Set all file gids'
|
||||||
|
complete -c mksquashfs -o pseudo-override -d 'Make pseudo file uids and gids override -all-root, -force-uid and -force-gid options'
|
||||||
|
complete -c mksquashfs -o no-exports -d 'Do not make filesystem exportable via NFS'
|
||||||
|
complete -c mksquashfs -o exports -d 'Make filesystem exportable via NFS'
|
||||||
|
complete -c mksquashfs -o no-sparse -d 'Do not detect sparse files'
|
||||||
|
complete -c mksquashfs -o no-tailends -d 'Do not pack tail ends into fragments'
|
||||||
|
complete -c mksquashfs -o tailends -o always-use-fragments -d 'Pack tail ends into fragments'
|
||||||
|
complete -c mksquashfs -o no-fragments -d 'Do not use fragments'
|
||||||
|
complete -c mksquashfs -o no-duplicates -d 'Do not perform duplicate checking'
|
||||||
|
complete -c mksquashfs -o no-hardlinks -d 'Do not hardlink files, instead store duplicates'
|
||||||
|
complete -c mksquashfs -o keep-as-directory -d 'If one source directory is specified, create a root directory containing that directory, rather than the contents of the directory'
|
||||||
|
complete -c mksquashfs -o p -xd 'Add pseudo file definition'
|
||||||
|
complete -c mksquashfs -o pf -rd 'Add list of pseudo file definitions from <pseudo-file>'
|
||||||
|
complete -c mksquashfs -o sort -rd 'Sort files according to priorities in <sort_file>'
|
||||||
|
complete -c mksquashfs -o ef -rd 'List of exclude dirs/files'
|
||||||
|
complete -c mksquashfs -o wildcards -d 'Allow extended shell wildcards (globbing) to be used in exclude dirs/files'
|
||||||
|
complete -c mksquashfs -o regex -d 'Allow POSIX regular expressions to be used in exclude dirs/files'
|
||||||
|
complete -c mksquashfs -o max-depth -xd 'Descend at most <levels> of directories when scanning filesystem'
|
||||||
|
complete -c mksquashfs -o one-file-system -d 'Do not cross filesystem boundaries'
|
||||||
|
complete -c mksquashfs -o one-file-system-x -d 'Do not cross filesystem boundaries'
|
||||||
|
complete -c mksquashfs -o no-xattrs -d 'Do not store extended attributes'
|
||||||
|
complete -c mksquashfs -o xattrs -d 'Store extended attributes'
|
||||||
|
complete -c mksquashfs -o xattrs-exclude -xd 'Exclude any xattr names matching <regex>'
|
||||||
|
complete -c mksquashfs -o xattrs-include -xd 'Include any xattr names matching <regex>'
|
||||||
|
complete -c mksquashfs -o xattrs-add -xd 'Add the xattr <name> with <val> to files'
|
||||||
|
complete -c mksquashfs -o version -d 'Print version, licence and copyright message'
|
||||||
|
complete -c mksquashfs -o exit-on-error -d 'Treat normally ignored errors as fatal'
|
||||||
|
complete -c mksquashfs -o quiet -d 'No verbose output'
|
||||||
|
complete -c mksquashfs -o info -d 'Print files written to filesystem'
|
||||||
|
complete -c mksquashfs -o no-progress -d 'Do not display the progress bar'
|
||||||
|
complete -c mksquashfs -o progress -d 'Display progress bar when using the -info option'
|
||||||
|
complete -c mksquashfs -o percentage -d 'Display a percentage rather than the full progress bar'
|
||||||
|
complete -c mksquashfs -o throttle -xd 'Throttle the I/O input rate by the given percentage'
|
||||||
|
complete -c mksquashfs -o limit -xd 'Limit the I/O input rate to the given percentage'
|
||||||
|
complete -c mksquashfs -o processors -xd 'Use <number> processors'
|
||||||
|
complete -c mksquashfs -o mem -xd 'Use <size> physical memory for caches'
|
||||||
|
complete -c mksquashfs -o mem-percent -xd 'Use <percent> physical memory for caches'
|
||||||
|
complete -c mksquashfs -o mem-default -d 'Print default memory usage in Mbytes'
|
||||||
|
complete -c mksquashfs -o noappend -d 'Do not append to existing filesystem'
|
||||||
|
complete -c mksquashfs -o root-becomes -xd 'When appending source files/directories, make the original root become a subdirectory in the new root called <name>, rather than adding the new source items to the original root'
|
||||||
|
complete -c mksquashfs -o no-recovery -d 'Do not generate a recovery file'
|
||||||
|
complete -c mksquashfs -o recovery-path -rd 'Use <name> as the directory to store the recovery file'
|
||||||
|
complete -c mksquashfs -o recover -rd 'Recover filesystem data using recovery file'
|
||||||
|
complete -c mksquashfs -o action -xd 'Evaluate <expr> on every file, and execute <action> if it returns TRUE'
|
||||||
|
complete -c mksquashfs -o log-action -xd 'As -action, but log expression evaluation results and actions performed'
|
||||||
|
complete -c mksquashfs -o true-action -xd 'As -action, but only log expressions which return TRUE'
|
||||||
|
complete -c mksquashfs -o false-action -xd 'As -action, but only log expressions which return FALSE'
|
||||||
|
complete -c mksquashfs -o action-file -rd 'As -action, but read actions from <file>'
|
||||||
|
complete -c mksquashfs -o log-action-file -rd 'As -log-action, but read actions from <file>'
|
||||||
|
complete -c mksquashfs -o true-action-file -rd 'As -true-action, but read actions from <f>'
|
||||||
|
complete -c mksquashfs -o false-action-file -rd 'As -false-action, but read actions from <f>'
|
||||||
|
complete -c mksquashfs -o default-mode -xd 'Sets the default directory permissions to octal <mode>'
|
||||||
|
complete -c mksquashfs -o default-uid -xa '(__fish_complete_user_ids)' -d 'Sets the default directory user'
|
||||||
|
complete -c mksquashfs -o default-gid -xa '(__fish_complete_group_ids)' -d 'Sets the default directory group'
|
||||||
|
complete -c mksquashfs -o ignore-zeros -d 'Allow tar files to be concatenated together and fed to Mksquashfs'
|
||||||
|
complete -c mksquashfs -o nopad -d 'Do not pad filesystem to a multiple of 4K'
|
||||||
|
complete -c mksquashfs -o o -o offset -xd 'Skip <offset> bytes at the beginning of FILESYSTEM'
|
||||||
|
complete -c mksquashfs -o h -o help -d 'Print help and exit'
|
||||||
|
|
||||||
|
complete -c mksquashfs -o Xhelp -d 'Print compressor options for selected compressor'
|
||||||
|
complete -c mksquashfs -o Xwindow-size -xd 'Window size in range 8 .. 15 (gzip only)'
|
||||||
|
complete -c mksquashfs -o Xstrategy -xa 'default filtered huffman_only run_length_encoded fixed' -d 'Strategy to use (gzip only)'
|
||||||
|
complete -c mksquashfs -o Xalgorithm -xa 'lzo1x_1 lzo1x_1_11 lzo1x_1_12 lzo1x_1_15 lzo1x_999' -d 'Algorithm to use (lzo only)'
|
||||||
|
complete -c mksquashfs -o Xhc -d 'Compress using LZ4 High Compression (lz4 only)'
|
||||||
|
complete -c mksquashfs -o Xbcj -xa 'x86 arm armthumb powerpc sparc ia64' -d 'Compress using filters in turn and choose the best compression (xz only)'
|
||||||
|
complete -c mksquashfs -o Xdict-size -xd 'Set xz dictionary size (xz only)'
|
||||||
|
|
||||||
|
# Specialize description if compressor name appears in argv. Misdetection is possible.
|
||||||
|
complete -c mksquashfs -o Xcompression-level -xd 'Compression level setting (lzo, gzip, zstd)'
|
||||||
|
complete -c mksquashfs -n '__fish_seen_argument lzo' -o Xcompression-level -xd 'Sets compression level for lzo1x_999 algorithm in range 1 .. 9'
|
||||||
|
complete -c mksquashfs -n '__fish_seen_argument gzip' -o Xcompression-level -xd 'Sets gzip compression level in range 1 .. 9'
|
||||||
|
complete -c mksquashfs -n '__fish_seen_argument zstd' -o Xcompression-level -xd 'Sets zstd compression level in range 1 .. 22'
|
||||||
@@ -141,7 +141,8 @@ complete -f -c npm -n '__fish_npm_using_command cache' -s h -l help -d 'Display
|
|||||||
# install-ci-test
|
# install-ci-test
|
||||||
complete -f -c npm -n __fish_npm_needs_command -a 'ci clean-install' -d 'Clean install a project'
|
complete -f -c npm -n __fish_npm_needs_command -a 'ci clean-install' -d 'Clean install a project'
|
||||||
complete -f -c npm -n __fish_npm_needs_command -a 'install-ci-test cit' -d 'Install a project with a clean slate and run tests'
|
complete -f -c npm -n __fish_npm_needs_command -a 'install-ci-test cit' -d 'Install a project with a clean slate and run tests'
|
||||||
for c in ci clean-install ic install-clean install-clean install-ci-test cit clean-install-test sit
|
# typos are intentional
|
||||||
|
for c in ci clean-install ic install-clean isntall-clean install-ci-test cit clean-install-test sit
|
||||||
complete -x -c npm -n "__fish_npm_using_command $c" -l install-strategy -a 'hoisted nested shallow linked' -d 'Install strategy'
|
complete -x -c npm -n "__fish_npm_using_command $c" -l install-strategy -a 'hoisted nested shallow linked' -d 'Install strategy'
|
||||||
complete -x -c npm -n "__fish_npm_using_command $c" -l omit -a 'dev optional peer' -d 'Omit dependency type'
|
complete -x -c npm -n "__fish_npm_using_command $c" -l omit -a 'dev optional peer' -d 'Omit dependency type'
|
||||||
complete -x -c npm -n "__fish_npm_using_command $c" -l strict-peer-deps -d 'Treat conflicting peerDependencies as failure'
|
complete -x -c npm -n "__fish_npm_using_command $c" -l strict-peer-deps -d 'Treat conflicting peerDependencies as failure'
|
||||||
@@ -406,7 +407,8 @@ end
|
|||||||
complete -c npm -n __fish_npm_needs_command -a 'install add i' -d 'Install a package'
|
complete -c npm -n __fish_npm_needs_command -a 'install add i' -d 'Install a package'
|
||||||
complete -f -c npm -n __fish_npm_needs_command -a 'install-test it' -d 'Install package(s) and run tests'
|
complete -f -c npm -n __fish_npm_needs_command -a 'install-test it' -d 'Install package(s) and run tests'
|
||||||
complete -f -c npm -n __fish_npm_needs_command -a 'link ln' -d 'Symlink a package folder'
|
complete -f -c npm -n __fish_npm_needs_command -a 'link ln' -d 'Symlink a package folder'
|
||||||
for c in install add i in ins inst insta instal isnt isnta isntal install install-test it link ln
|
# typos are intentional
|
||||||
|
for c in install add i in ins inst insta instal isnt isnta isntal isntall install-test it link ln
|
||||||
complete -f -c npm -n "__fish_npm_using_command $c" -s S -l save -d 'Save to dependencies'
|
complete -f -c npm -n "__fish_npm_using_command $c" -s S -l save -d 'Save to dependencies'
|
||||||
complete -f -c npm -n "__fish_npm_using_command $c" -l no-save -d 'Prevents saving to dependencies'
|
complete -f -c npm -n "__fish_npm_using_command $c" -l no-save -d 'Prevents saving to dependencies'
|
||||||
complete -f -c npm -n "__fish_npm_using_command $c" -s P -l save-prod -d 'Save to dependencies'
|
complete -f -c npm -n "__fish_npm_using_command $c" -s P -l save-prod -d 'Save to dependencies'
|
||||||
@@ -726,4 +728,4 @@ complete -f -c npm -n '__fish_npm_using_command whoami' -a registry -d 'Check re
|
|||||||
complete -f -c npm -n '__fish_npm_using_command whoami' -s h -l help -d 'Display help'
|
complete -f -c npm -n '__fish_npm_using_command whoami' -s h -l help -d 'Display help'
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
complete -f -c npm -n '__fish_seen_subcommand_from add i in ins inst insta instal isnt isnta isntal install; and not __fish_is_switch' -a "(__npm_filtered_list_packages \"$npm_install\")"
|
complete -f -c npm -n '__fish_seen_subcommand_from add i in ins inst insta instal isnt isnta isntal isntall; and not __fish_is_switch' -a "(__npm_filtered_list_packages \"$npm_install\")"
|
||||||
|
|||||||
@@ -1,23 +1,42 @@
|
|||||||
complete -c python -s B -d 'Don\'t write .py[co] files on import'
|
# This function adjusts for options with arguments (-X, -W, etc.), ensures completions stop when a script/module is set (-c, -m, file, -)
|
||||||
complete -c python -s c -x -d "Execute argument as command"
|
function __fish_python_no_arg
|
||||||
complete -c python -l check-hash-based-pycs -a "default always never" -d "Control validation behaviour of pyc files"
|
set -l num 1
|
||||||
complete -c python -s d -d "Debug on"
|
set -l tokens (commandline -pxc)
|
||||||
complete -c python -s E -d "Ignore all PYTHON* env vars"
|
set -l has_arg_list -X -W --check-hash-based-pycs
|
||||||
complete -c python -s h -s '?' -l help -d "Display help and exit"
|
if contains -- - $tokens
|
||||||
complete -c python -s i -d "Interactive mode after executing commands"
|
set num (math $num - 1)
|
||||||
complete -c python -s m -d 'Run library module as a script (terminates option list)' -xa '(python -c "import pkgutil; print(\'\n\'.join([p[1] for p in pkgutil.iter_modules()]))")'
|
end
|
||||||
complete -c python -s O -d "Enable optimizations"
|
for has_arg in $has_arg_list
|
||||||
complete -c python -o OO -d "Remove doc-strings in addition to the -O optimizations"
|
if contains -- $has_arg $tokens
|
||||||
complete -c python -s s -d 'Don\'t add user site directory to sys.path'
|
set num (math $num + 1)
|
||||||
complete -c python -s S -d "Disable import of site module"
|
end
|
||||||
complete -c python -s u -d "Unbuffered input and output"
|
end
|
||||||
complete -c python -s v -d "Verbose mode"
|
if test (__fish_number_of_cmd_args_wo_opts) -gt $num
|
||||||
complete -c python -o vv -d "Even more verbose mode"
|
return 1
|
||||||
complete -c python -s V -l version -d "Display version and exit"
|
end
|
||||||
complete -c python -s W -x -d "Warning control" -a "ignore default all module once error"
|
return 0
|
||||||
complete -c python -s x -d 'Skip first line of source, allowing use of non-Unix forms of #!cmd'
|
end
|
||||||
complete -c python -f -n "__fish_is_nth_token 1" -k -a "(__fish_complete_suffix .py)"
|
|
||||||
complete -c python -f -n "__fish_is_nth_token 1" -a - -d 'Read program from stdin'
|
complete -c python -n __fish_python_no_arg -s B -d 'Don\'t write .py[co] files on import'
|
||||||
|
complete -c python -n __fish_python_no_arg -s c -x -d "Execute argument as command"
|
||||||
|
complete -c python -n __fish_python_no_arg -l check-hash-based-pycs -a "default always never" -d "Control validation behaviour of pyc files"
|
||||||
|
complete -c python -n __fish_python_no_arg -s d -d "Debug on"
|
||||||
|
complete -c python -n __fish_python_no_arg -s E -d "Ignore all PYTHON* env vars"
|
||||||
|
complete -c python -n __fish_python_no_arg -s h -s '?' -l help -d "Display help and exit"
|
||||||
|
complete -c python -n __fish_python_no_arg -s i -d "Interactive mode after executing commands"
|
||||||
|
complete -c python -n __fish_python_no_arg -s m -d 'Run library module as a script (terminates option list)' -xa '(python -c "import pkgutil; print(\'\n\'.join([p[1] for p in pkgutil.iter_modules()]))")'
|
||||||
|
complete -c python -n __fish_python_no_arg -s O -d "Enable optimizations"
|
||||||
|
complete -c python -n __fish_python_no_arg -o OO -d "Remove doc-strings in addition to the -O optimizations"
|
||||||
|
complete -c python -n __fish_python_no_arg -s s -d 'Don\'t add user site directory to sys.path'
|
||||||
|
complete -c python -n __fish_python_no_arg -s S -d "Disable import of site module"
|
||||||
|
complete -c python -n __fish_python_no_arg -s u -d "Unbuffered input and output"
|
||||||
|
complete -c python -n __fish_python_no_arg -s v -d "Verbose mode"
|
||||||
|
complete -c python -n __fish_python_no_arg -o vv -d "Even more verbose mode"
|
||||||
|
complete -c python -n __fish_python_no_arg -s V -l version -d "Display version and exit"
|
||||||
|
complete -c python -n __fish_python_no_arg -s W -x -d "Warning control" -a "ignore default all module once error"
|
||||||
|
complete -c python -n __fish_python_no_arg -s x -d 'Skip first line of source, allowing use of non-Unix forms of #!cmd'
|
||||||
|
complete -c python -n __fish_python_no_arg -f -k -a "(__fish_complete_suffix .py)"
|
||||||
|
complete -c python -n __fish_python_no_arg -f -a - -d 'Read program from stdin'
|
||||||
|
|
||||||
# Version-specific completions
|
# Version-specific completions
|
||||||
# We have to detect this at runtime because pyenv etc can change
|
# We have to detect this at runtime because pyenv etc can change
|
||||||
@@ -25,10 +44,10 @@ complete -c python -f -n "__fish_is_nth_token 1" -a - -d 'Read program from stdi
|
|||||||
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s2"' -s 3 -d 'Warn about Python 3.x incompatibilities that 2to3 cannot trivially fix'
|
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s2"' -s 3 -d 'Warn about Python 3.x incompatibilities that 2to3 cannot trivially fix'
|
||||||
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s2"' -s t -d "Warn on mixed tabs and spaces"
|
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s2"' -s t -d "Warn on mixed tabs and spaces"
|
||||||
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s2"' -s Q -x -a "old new warn warnall" -d "Division control"
|
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s2"' -s Q -x -a "old new warn warnall" -d "Division control"
|
||||||
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s3"' -s q -d 'Don\'t print version and copyright messages on interactive startup'
|
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s3" && __fish_python_no_arg' -s q -d 'Don\'t print version and copyright messages on interactive startup'
|
||||||
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s3"' -s X -x -d 'Set implementation-specific option'
|
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s3" && __fish_python_no_arg' -s X -x -d 'Set implementation-specific option'
|
||||||
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s3"' -s b -d 'Warn when comparing bytes with str or int'
|
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s3" && __fish_python_no_arg' -s b -d 'Warn when comparing bytes with str or int'
|
||||||
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s3"' -o bb -d 'Error when comparing bytes with str or int'
|
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s3" && __fish_python_no_arg' -o bb -d 'Error when comparing bytes with str or int'
|
||||||
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s3"' -s R -d 'Turn on hash randomization'
|
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s3" && __fish_python_no_arg' -s R -d 'Turn on hash randomization'
|
||||||
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s3"' -s I -d 'Run in isolated mode'
|
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s3" && __fish_python_no_arg' -s I -d 'Run in isolated mode'
|
||||||
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s3"' -o VV -d 'Print further version info'
|
complete -c python -n 'python -V 2>&1 | string match -rq "^.*\s3" && __fish_python_no_arg' -o VV -d 'Print further version info'
|
||||||
|
|||||||
@@ -1,24 +1,43 @@
|
|||||||
complete -c python3 -s B -d 'Don\'t write .py[co] files on import'
|
# This function adjusts for options with arguments (-X, -W, etc.), ensures completions stop when a script/module is set (-c, -m, file, -)
|
||||||
complete -c python3 -s c -x -d "Execute argument as command"
|
function __fish_python_no_arg
|
||||||
complete -c python3 -s d -d "Debug on"
|
set -l num 1
|
||||||
complete -c python3 -s E -d "Ignore environment variables"
|
set -l tokens (commandline -pxc)
|
||||||
complete -c python3 -s h -s '?' -l help -d "Display help and exit"
|
set -l has_arg_list -X -W --check-hash-based-pycs
|
||||||
complete -c python3 -s i -d "Interactive mode after executing commands"
|
if contains -- - $tokens
|
||||||
complete -c python3 -s O -d "Enable optimizations"
|
set num (math $num - 1)
|
||||||
complete -c python3 -o OO -d "Remove doc-strings in addition to the -O optimizations"
|
end
|
||||||
complete -c python3 -s s -d 'Don\'t add user site directory to sys.path'
|
for has_arg in $has_arg_list
|
||||||
complete -c python3 -s S -d "Disable import of site module"
|
if contains -- $has_arg $tokens
|
||||||
complete -c python3 -s u -d "Unbuffered input and output"
|
set num (math $num + 1)
|
||||||
complete -c python3 -s v -d "Verbose mode"
|
end
|
||||||
complete -c python3 -s V -l version -d "Display version and exit"
|
end
|
||||||
complete -c python3 -s W -x -d "Warning control" -a "ignore default all module once error"
|
if test (__fish_number_of_cmd_args_wo_opts) -gt $num
|
||||||
complete -c python3 -s x -d 'Skip first line of source, allowing use of non-Unix forms of #!cmd'
|
return 1
|
||||||
complete -c python3 -n "__fish_is_nth_token 1" -k -fa "(__fish_complete_suffix .py)"
|
end
|
||||||
complete -c python3 -f -n "__fish_is_nth_token 1" -a - -d 'Read program from stdin'
|
return 0
|
||||||
complete -c python3 -s q -d 'Don\'t print version and copyright messages on interactive startup'
|
end
|
||||||
complete -c python3 -s X -x -d 'Set implementation-specific option' -a 'faulthandler showrefcount tracemalloc showalloccount importtime dev utf8 pycache_prefex=PATH:'
|
|
||||||
complete -c python3 -s b -d 'Issue warnings for possible misuse of `bytes` with `str`'
|
complete -c python3 -n __fish_python_no_arg -s B -d 'Don\'t write .py[co] files on import'
|
||||||
complete -c python3 -o bb -d 'Issue errors for possible misuse of `bytes` with `str`'
|
complete -c python3 -n __fish_python_no_arg -s c -x -d "Execute argument as command"
|
||||||
complete -c python3 -s m -d 'Run library module as a script (terminates option list)' -xa '(python3 -c "import pkgutil; print(\'\n\'.join([p[1] for p in pkgutil.iter_modules()]))")'
|
complete -c python3 -n __fish_python_no_arg -s d -d "Debug on"
|
||||||
complete -c python3 -l check-hash-based-pycs -d 'Set pyc hash check mode' -xa "default always never"
|
complete -c python3 -n __fish_python_no_arg -s E -d "Ignore environment variables"
|
||||||
complete -c python3 -s I -d 'Run in isolated mode'
|
complete -c python3 -n __fish_python_no_arg -s h -s '?' -l help -d "Display help and exit"
|
||||||
|
complete -c python3 -n __fish_python_no_arg -s i -d "Interactive mode after executing commands"
|
||||||
|
complete -c python3 -n __fish_python_no_arg -s O -d "Enable optimizations"
|
||||||
|
complete -c python3 -n __fish_python_no_arg -o OO -d "Remove doc-strings in addition to the -O optimizations"
|
||||||
|
complete -c python3 -n __fish_python_no_arg -s s -d 'Don\'t add user site directory to sys.path'
|
||||||
|
complete -c python3 -n __fish_python_no_arg -s S -d "Disable import of site module"
|
||||||
|
complete -c python3 -n __fish_python_no_arg -s u -d "Unbuffered input and output"
|
||||||
|
complete -c python3 -n __fish_python_no_arg -s v -d "Verbose mode"
|
||||||
|
complete -c python3 -n __fish_python_no_arg -s V -l version -d "Display version and exit"
|
||||||
|
complete -c python3 -n __fish_python_no_arg -s W -x -d "Warning control" -a "ignore default all module once error"
|
||||||
|
complete -c python3 -n __fish_python_no_arg -s x -d 'Skip first line of source, allowing use of non-Unix forms of #!cmd'
|
||||||
|
complete -c python3 -n __fish_python_no_arg -k -fa "(__fish_complete_suffix .py)"
|
||||||
|
complete -c python3 -n __fish_python_no_arg -fa - -d 'Read program from stdin'
|
||||||
|
complete -c python3 -n __fish_python_no_arg -s q -d 'Don\'t print version and copyright messages on interactive startup'
|
||||||
|
complete -c python3 -n __fish_python_no_arg -s X -x -d 'Set implementation-specific option' -a 'faulthandler showrefcount tracemalloc showalloccount importtime dev utf8 pycache_prefex=PATH:'
|
||||||
|
complete -c python3 -n __fish_python_no_arg -s b -d 'Issue warnings for possible misuse of `bytes` with `str`'
|
||||||
|
complete -c python3 -n __fish_python_no_arg -o bb -d 'Issue errors for possible misuse of `bytes` with `str`'
|
||||||
|
complete -c python3 -n __fish_python_no_arg -s m -d 'Run library module as a script (terminates option list)' -xa '(python3 -c "import pkgutil; print(\'\n\'.join([p[1] for p in pkgutil.iter_modules()]))")'
|
||||||
|
complete -c python3 -n __fish_python_no_arg -l check-hash-based-pycs -d 'Set pyc hash check mode' -xa "default always never"
|
||||||
|
complete -c python3 -n __fish_python_no_arg -s I -d 'Run in isolated mode'
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
set -l rclone_version (rclone version | string match -rg 'rclone v?(.*)' | string split .)
|
if set -l rclone_version (rclone version | string match -rg 'rclone v?(.*)' | string split .) &&
|
||||||
or return
|
test "$rclone_version[1]" -lt 1 ||
|
||||||
|
test "$rclone_version[1]" -eq 1 &&
|
||||||
# Yes, rclone's parsing here has changed, now they *require* a `-` argument
|
test "$rclone_version[2]" -le 62
|
||||||
# where previously they required *not* having it.
|
# version is definitely <= 1.62, adding a `-` would be an error
|
||||||
if test "$rclone_version[1]" -gt 1; or test "$rclone_version[2]" -gt 62
|
rclone completion fish
|
||||||
rclone completion fish - 2>/dev/null | source
|
|
||||||
else
|
else
|
||||||
rclone completion fish 2>/dev/null | source
|
# For newer versions, this requires an `-`. Without a `-`, it would
|
||||||
end
|
# try to write to /etc/completions/fish.
|
||||||
|
# If we can't determine the version, assume a recent one. An error
|
||||||
|
# is better than trying to write to /etc unexpectedly.
|
||||||
|
rclone completion fish -
|
||||||
|
end 2>/dev/null | source
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ end
|
|||||||
|
|
||||||
function __resolvectl_commands
|
function __resolvectl_commands
|
||||||
printf "%b\n" "query\tResolve domain names or IP addresses" \
|
printf "%b\n" "query\tResolve domain names or IP addresses" \
|
||||||
|
"query\tResolve domain names, IPv4 and IPv6 addresses" \
|
||||||
"service\tResolve service records" \
|
"service\tResolve service records" \
|
||||||
"openpgp\tQuery PGP keys for email" \
|
"openpgp\tQuery PGP keys for email" \
|
||||||
"tlsa\tQuery TLS public keys" \
|
"tlsa\tQuery TLS public keys" \
|
||||||
@@ -26,6 +27,9 @@ function __resolvectl_commands
|
|||||||
"reset-statistics\tReset statistics counters" \
|
"reset-statistics\tReset statistics counters" \
|
||||||
"flush-caches\tFlush DNS RR caches" \
|
"flush-caches\tFlush DNS RR caches" \
|
||||||
"reset-server-features\tFlushe all feature level information" \
|
"reset-server-features\tFlushe all feature level information" \
|
||||||
|
"monitor\tMonitor DNS queries" \
|
||||||
|
"show-cache\tShow cache contents" \
|
||||||
|
"show-server-state\tShow server state" \
|
||||||
"dns\tSet per-interface DNS servers" \
|
"dns\tSet per-interface DNS servers" \
|
||||||
"domain\tSet per-interface search or routing domains" \
|
"domain\tSet per-interface search or routing domains" \
|
||||||
"default-route\tSet per-interface default route flag" \
|
"default-route\tSet per-interface default route flag" \
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ __fish_complete_ssh scp
|
|||||||
function __scp2ssh_port_number
|
function __scp2ssh_port_number
|
||||||
# There is a silly inconsistency between the ssh and scp commands regarding the short flag name
|
# There is a silly inconsistency between the ssh and scp commands regarding the short flag name
|
||||||
# for specifying the TCP port number. This function deals with that by extracting the port
|
# for specifying the TCP port number. This function deals with that by extracting the port
|
||||||
# number if present and emitting it as a flag appropriate for ssh.
|
# number if present.
|
||||||
set -l port (commandline -c | string match -r -- ' -P ?(\d+)\b')
|
set -l port (commandline -c | string match -r -- ' -P ?(\d+)\b')
|
||||||
and echo -p\n$port[2]
|
and echo $port[2]
|
||||||
end
|
end
|
||||||
|
|
||||||
function __scp_remote_target
|
function __scp_remote_target
|
||||||
@@ -44,20 +44,25 @@ complete -c scp -d "Local Path" -n "not string match @ -- (commandline -ct)"
|
|||||||
|
|
||||||
# Remote path
|
# Remote path
|
||||||
# Get the list of remote files from the scp target.
|
# Get the list of remote files from the scp target.
|
||||||
if string match -rq 'OpenSSH(_for_Windows)?_(?<major>\d+)\.*' -- (ssh -V 2>&1) && test "$major" -ge 9
|
complete -c scp -d "Remote Path" -f -n "commandline -ct | string match -e ':'" -a '
|
||||||
complete -c scp -d "Remote Path" -f -n "commandline -ct | string match -e ':'" -a "
|
(__scp_remote_target):(
|
||||||
(__scp_remote_target):( \
|
if not set -q __fish_scp_sftp
|
||||||
command ssh (__scp2ssh_port_number) -o 'BatchMode yes' (__scp_remote_target) command\ ls\ -dp\ (__scp_remote_path_prefix)\* 2>/dev/null
|
set -l tmp (mktemp)
|
||||||
)
|
if scp -P(__scp2ssh_port_number) -o "BatchMode yes" -q -O $tmp (__scp_remote_target):/dev/null
|
||||||
"
|
set -g __fish_scp_sftp true
|
||||||
else
|
else
|
||||||
complete -c scp -d "Remote Path" -f -n "commandline -ct | string match -e ':'" -a "
|
set -g __fish_scp_sftp false
|
||||||
(__scp_remote_target):( \
|
|
||||||
command ssh (__scp2ssh_port_number) -o 'BatchMode yes' (__scp_remote_target) command\ ls\ -dp\ (__scp_remote_path_prefix | string unescape)\* 2>/dev/null |
|
|
||||||
string escape -n
|
|
||||||
)
|
|
||||||
"
|
|
||||||
end
|
end
|
||||||
|
rm $tmp
|
||||||
|
end
|
||||||
|
if $__fish_scp_sftp
|
||||||
|
command ssh -p(__scp2ssh_port_number) -o "BatchMode yes" (__scp_remote_target) command\ ls\ -dp\ (__scp_remote_path_prefix)\* 2>/dev/null
|
||||||
|
else
|
||||||
|
command ssh -p(__scp2ssh_port_number) -o "BatchMode yes" (__scp_remote_target) command\ ls\ -dp\ (__scp_remote_path_prefix | string unescape)\* 2>/dev/null |
|
||||||
|
string escape -n
|
||||||
|
end
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
complete -c scp -s 3 -d "Copies between two remote hosts are transferred through the local host"
|
complete -c scp -s 3 -d "Copies between two remote hosts are transferred through the local host"
|
||||||
complete -c scp -s B -d "Batch mode"
|
complete -c scp -s B -d "Batch mode"
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_com
|
|||||||
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-full-job-control -d "Test if all new jobs are put under job control"
|
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a is-full-job-control -d "Test if all new jobs are put under job control"
|
||||||
|
|
||||||
# The subcommands that are not "is-something" which don't change the fish state.
|
# The subcommands that are not "is-something" which don't change the fish state.
|
||||||
|
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a buildinfo -d "Print information on how this version fish was built"
|
||||||
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a current-command -d "Print the name of the currently running command or function"
|
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a current-command -d "Print the name of the currently running command or function"
|
||||||
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a current-commandline -d "Print the currently running command with its arguments"
|
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a current-commandline -d "Print the currently running command with its arguments"
|
||||||
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a current-filename -d "Print the filename of the currently running script"
|
complete -f -c status -n "not __fish_seen_subcommand_from $__fish_status_all_commands" -a current-filename -d "Print the filename of the currently running script"
|
||||||
|
|||||||
1
share/completions/tex-fmt.fish
Normal file
1
share/completions/tex-fmt.fish
Normal file
@@ -0,0 +1 @@
|
|||||||
|
tex-fmt --completion fish | source
|
||||||
@@ -94,6 +94,8 @@ complete -c tmux -n __fish_use_subcommand -a $rename -d 'rename session'
|
|||||||
complete -c tmux -n __fish_use_subcommand -a $showmsgs -d 'save msgs in status bar in per-client msg log'
|
complete -c tmux -n __fish_use_subcommand -a $showmsgs -d 'save msgs in status bar in per-client msg log'
|
||||||
|
|
||||||
complete -c tmux -n __fish_use_subcommand -a $source -d 'execute commands from path'
|
complete -c tmux -n __fish_use_subcommand -a $source -d 'execute commands from path'
|
||||||
|
complete -c tmux -n "__fish_seen_subcommand_from $source" -F
|
||||||
|
|
||||||
complete -c tmux -n __fish_use_subcommand -a $start -d 'start tmux server if not running; do not create a session'
|
complete -c tmux -n __fish_use_subcommand -a $start -d 'start tmux server if not running; do not create a session'
|
||||||
|
|
||||||
complete -c tmux -n __fish_use_subcommand -a $suspendc -d 'send SIGTSTP signal to client (tty stop)'
|
complete -c tmux -n __fish_use_subcommand -a $suspendc -d 'send SIGTSTP signal to client (tty stop)'
|
||||||
@@ -113,14 +115,114 @@ complete -c tmux -xs t -n "__fish_seen_subcommand_from $detach $lockc $refresh $
|
|||||||
complete -c tmux -xs c -n "__fish_seen_subcommand_from $switchc" -a '(__fish_tmux_clients)' -d target-client
|
complete -c tmux -xs c -n "__fish_seen_subcommand_from $switchc" -a '(__fish_tmux_clients)' -d target-client
|
||||||
|
|
||||||
#commands with the -F format flag
|
#commands with the -F format flag
|
||||||
complete -c tmux -n "__fish_seen_subcommand_from $lsc $ls" -rs F -d 'format string'
|
complete -c tmux -n "__fish_seen_subcommand_from $lsc $ls" -xs F -d 'format string'
|
||||||
|
|
||||||
############### End: Clients and Sessions ###############
|
############### End: Clients and Sessions ###############
|
||||||
|
|
||||||
############### Begin: Windows and Panes ###############
|
############### Begin: Windows and Panes ###############
|
||||||
#TODO - these commands are not currently implemented.
|
|
||||||
#there is a section in the tmux man page that has the same title as this section
|
set -l breakp "break-pane breakp"
|
||||||
#use the "Clients and Sessions" code as an example when implementing this
|
set -l capturep "capture-pane capturep"
|
||||||
|
set -l chooseclient choose-client
|
||||||
|
set -l choosetree choose-tree
|
||||||
|
set -l customizemode customize-mode
|
||||||
|
set -l displayp "display-panes displayp"
|
||||||
|
set -l findw "find-window findw"
|
||||||
|
set -l joinp "join-pane joinp move-pane movep"
|
||||||
|
set -l killp "kill-pane killp"
|
||||||
|
set -l killw "kill-window killw"
|
||||||
|
set -l lastp "last-pane lastp"
|
||||||
|
set -l lastw "last-window lastw"
|
||||||
|
set -l linkw "link-window linkw"
|
||||||
|
set -l lsp "list-panes lsp"
|
||||||
|
set -l lsw "list-windows lsw"
|
||||||
|
set -l movew "move-window movew"
|
||||||
|
set -l neww "new-window neww"
|
||||||
|
set -l nextl "next-layout nextl"
|
||||||
|
set -l next "next-window next"
|
||||||
|
set -l pipep "pipe-pane pipep"
|
||||||
|
set -l prevl "previous-layout prevl"
|
||||||
|
set -l prev "previous-window prev"
|
||||||
|
set -l renamew "rename-window renamew"
|
||||||
|
set -l resizep "resize-pane resizep"
|
||||||
|
set -l resizew "resize-window resizew"
|
||||||
|
set -l respawnp "respawn-pane respawnp"
|
||||||
|
set -l respawnw "respawn-window respawnw"
|
||||||
|
set -l rotatew "rotate-window rotatew"
|
||||||
|
set -l selectl "select-layout selectl"
|
||||||
|
set -l selectp "select-pane selectp"
|
||||||
|
set -l selectw "select-window selectw"
|
||||||
|
set -l splitw "split-window splitw"
|
||||||
|
set -l swapp "swap-pane swapp"
|
||||||
|
set -l swapw "swap-window swapw"
|
||||||
|
set -l unlinkw "unlink-window unlinkw"
|
||||||
|
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $breakp -d 'break pane off into a new window'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $capturep -d 'capture contents of a pane into a buffer'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $chooseclient -d 'interactively choose client'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $choosetree -d 'interactively choose session/window/pane'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $customizemode -d 'interactively customize settings'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $displayp -d 'display a visible indicator for each pane'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $findw -d 'interactively choose window matching pattern'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $joinp -d 'split destination pane and move source pane into one of the halves'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $killp -d 'destroy a pane'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $killw -d 'destroy a window'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $lastp -d 'select the previusly selected pane'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $lastw -d 'select the previusly selected window'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $linkw -d 'link source window to destination window'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $lsp -d 'list panes'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $lsw -d 'list windows'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $movew -d 'move window'
|
||||||
|
# TODO: Should accept shell command
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $neww -d 'create a new window'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $nextl -d 'rearrange panes in a window according to the next layout'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $next -d 'move to the next window in the session'
|
||||||
|
# TODO: Should accept shell command
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $pipep -d 'pipe output from pane to a shell command'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $prevl -d 'rearrange panes in a window according to the previous layout'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $prev -d 'move to the previous window in the session'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $renamew -d 'rename a window'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $resizep -d 'resize a pane'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $resizew -d 'resize a window'
|
||||||
|
# TODO: Should accept shell command
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $respawnp -d 'reactivate a pane where a command exited'
|
||||||
|
# TODO: Should accept shell command
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $respawnw -d 'reactivate a window where a command exited'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $rotatew -d 'rotate panes within a window'
|
||||||
|
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $selectl -d 'rearrange panes according to a given layout'
|
||||||
|
set -l layouts 'even-horizontal even-vertical main-horizontal main-horizontal-mirrored main-vertical main-vertical-mirrored tiled'
|
||||||
|
complete -c tmux -n "__fish_seen_subcommand_from $selectl" -x -a "$layouts" -d 'predefined layout'
|
||||||
|
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $selectp -d 'activate specific pane'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $selectw -d 'activate specific window'
|
||||||
|
# TODO: Should accept shell command
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $splitw -d 'create a new pane by splitting target-pane'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $swapp -d 'swap two panes'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $swapw -d 'swap two windows'
|
||||||
|
complete -c tmux -n __fish_use_subcommand -a $unlinkw -d 'unlink target-window'
|
||||||
|
|
||||||
|
## commands with pane flag
|
||||||
|
complete -c tmux -n "__fish_seen_subcommand_from $breakp $joinp $swapp" -xs s -a '(__fish_tmux_panes)' -d 'source pane'
|
||||||
|
complete -c tmux -n "__fish_seen_subcommand_from $capturep $chooseclient $choosetree $customizemode $findw" -xs t -a '(__fish_tmux_panes)' -d 'target pane'
|
||||||
|
complete -c tmux -n "__fish_seen_subcommand_from $killp $pipep $resizep $respawnp $selectl $selectp $splitw" -xs t -a '(__fish_tmux_panes)' -d 'target pane'
|
||||||
|
# Unclear if there's a meaningful difference between "target pane" and "destination pane", but tmux makes the distinction
|
||||||
|
complete -c tmux -n "__fish_seen_subcommand_from $joinp $swapp" -xs t -a '(__fish_tmux_panes)' -d 'destination pane'
|
||||||
|
|
||||||
|
## commands with session flag
|
||||||
|
complete -c tmux -n "__fish_seen_subcommand_from $lastw $lsw $next $prev" -xs t -a '(__fish_tmux_sessions)' -d 'target session'
|
||||||
|
|
||||||
|
## commands with the -F format flag
|
||||||
|
complete -c tmux -n "__fish_seen_subcommand_from $breakp $lsp $lsw $neww $chooseclient $choosetree" -xs F -d 'format string'
|
||||||
|
|
||||||
|
## commands with -s/-t flags that are not panes/sessions (nice completion not yet implemented)
|
||||||
|
complete -c tmux -n "__fish_seen_subcommand_from $linkw $movew $swapw" -xs s -d 'source window'
|
||||||
|
complete -c tmux -n "__fish_seen_subcommand_from $breakp $linkw $movew $neww $swapw" -xs t -d 'destination window'
|
||||||
|
complete -c tmux -n "__fish_seen_subcommand_from $killw $lastp $nextl $prevl $renamew" -xs t -d 'target window'
|
||||||
|
complete -c tmux -n "__fish_seen_subcommand_from $resizew $reswpawnw $rotatew $selectw $unlinkw" -xs t -d 'target window'
|
||||||
|
complete -c tmux -n "__fish_seen_subcommand_from $displayp" -xs t -d 'target client'
|
||||||
|
complete -c tmux -n "__fish_seen_subcommand_from $lsp" -xs t -d 'target'
|
||||||
|
|
||||||
############### End: Windows and Panes ###############
|
############### End: Windows and Panes ###############
|
||||||
|
|
||||||
############### Begin: Key Bindings ###############
|
############### Begin: Key Bindings ###############
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ complete -c wget -o nd -d "Do not create a hierarchy of directories"
|
|||||||
complete -c wget -s x -l force-directories -d "Force creation of a hierarchy of directories"
|
complete -c wget -s x -l force-directories -d "Force creation of a hierarchy of directories"
|
||||||
complete -c wget -l no-host-directories -d "Disable generation of host-prefixed directories"
|
complete -c wget -l no-host-directories -d "Disable generation of host-prefixed directories"
|
||||||
complete -c wget -o nH -d "Disable generation of host-prefixed directories"
|
complete -c wget -o nH -d "Disable generation of host-prefixed directories"
|
||||||
complete -c wget -l protocal-directories -d "Use the protocol name as a directory component"
|
complete -c wget -l protocol-directories -d "Use the protocol name as a directory component"
|
||||||
complete -c wget -l cut-dirs -d "Ignore specified number of directory components" -xa "1 2 3 4 5"
|
complete -c wget -l cut-dirs -d "Ignore specified number of directory components" -xa "1 2 3 4 5"
|
||||||
complete -c wget -s P -l directory-prefix -d "Set directory prefix" -r
|
complete -c wget -s P -l directory-prefix -d "Set directory prefix" -r
|
||||||
complete -c wget -s E -l html-extension -d "Force html files to have html extension"
|
complete -c wget -s E -l html-extension -d "Force html files to have html extension"
|
||||||
|
|||||||
@@ -1,30 +1,4 @@
|
|||||||
function __fish_setup_cancel_text -v fish_color_cancel -v fish_color_normal
|
# This is meant to be bound to something like ctrl-c
|
||||||
set -g __fish_cancel_text "^C"
|
|
||||||
if set -q fish_color_cancel
|
|
||||||
set __fish_cancel_text (echo -sn (set_color $fish_color_cancel) $__fish_cancel_text (set_color normal))
|
|
||||||
end
|
|
||||||
if command -sq tput
|
|
||||||
# Clear to EOL (to erase any autosuggestions)
|
|
||||||
set __fish_cancel_text (echo -sn $__fish_cancel_text (tput el; or tput ce))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
__fish_setup_cancel_text
|
|
||||||
|
|
||||||
# This is meant to be bound to something like \cC.
|
|
||||||
function __fish_cancel_commandline
|
function __fish_cancel_commandline
|
||||||
set -l cmd (commandline)
|
commandline -f cancel-commandline-traditional
|
||||||
if test -n "$cmd"
|
|
||||||
echo -sn $__fish_cancel_text
|
|
||||||
# `commandline -L` prints the line the cursor is on (starting from the prompt), so move the cursor
|
|
||||||
# "to the end" then call `commandline -L` to get the total number of lines typed in at the prompt.
|
|
||||||
commandline -C 10000000
|
|
||||||
printf (string repeat -n (commandline -L) "\n")
|
|
||||||
commandline ""
|
|
||||||
emit fish_cancel
|
|
||||||
end
|
|
||||||
|
|
||||||
# cancel: Close the pager if it's open (#4298)
|
|
||||||
# repaint: Repaint even if we haven't cancelled anything so the prompt refreshes
|
|
||||||
# and the terminal scrolls to it.
|
|
||||||
commandline -f cancel -f repaint
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -10,14 +10,12 @@ function __fish_complete_subcommand -d "Complete subcommand" --no-scope-shadowin
|
|||||||
case '--fcs-skip=*'
|
case '--fcs-skip=*'
|
||||||
set skip_next (string split = -- $arg)[2]
|
set skip_next (string split = -- $arg)[2]
|
||||||
case --commandline # --commandline means to use our arguments instead of the commandline.
|
case --commandline # --commandline means to use our arguments instead of the commandline.
|
||||||
set subcommand $argv
|
complete -C "$argv"
|
||||||
set -e argv
|
return
|
||||||
break
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
set -l options_with_param $argv
|
set -l options_with_param $argv
|
||||||
|
|
||||||
if not string length -q -- $subcommand
|
|
||||||
set -l cmd (commandline -cxp | string escape) (commandline -ct)
|
set -l cmd (commandline -cxp | string escape) (commandline -ct)
|
||||||
while set -q cmd[1]
|
while set -q cmd[1]
|
||||||
set -l token $cmd[1]
|
set -l token $cmd[1]
|
||||||
@@ -39,7 +37,6 @@ function __fish_complete_subcommand -d "Complete subcommand" --no-scope-shadowin
|
|||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
printf "%s\n" (complete -C "$subcommand")
|
printf "%s\n" (complete -C "$subcommand")
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -128,14 +128,6 @@ end" >$__fish_config_dir/config.fish
|
|||||||
complete -x -p "/etc/init.d/*" -a reload --description 'Reload service configuration'
|
complete -x -p "/etc/init.d/*" -a reload --description 'Reload service configuration'
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
|
||||||
# We want to show our completions for the [ (test) builtin, but
|
|
||||||
# we don't want to create a [.fish. test.fish will not be loaded until
|
|
||||||
# the user tries [ interactively.
|
|
||||||
#
|
|
||||||
complete -c [ --wraps test
|
|
||||||
complete -c ! --wraps not
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Only a few builtins take filenames; initialize the rest with no file completions
|
# Only a few builtins take filenames; initialize the rest with no file completions
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -66,9 +66,10 @@ function __fish_shared_key_bindings -d "Bindings shared between emacs and vi mod
|
|||||||
bind --preset $argv alt-l __fish_list_current_token
|
bind --preset $argv alt-l __fish_list_current_token
|
||||||
bind --preset $argv alt-o __fish_preview_current_file
|
bind --preset $argv alt-o __fish_preview_current_file
|
||||||
bind --preset $argv alt-w __fish_whatis_current_token
|
bind --preset $argv alt-w __fish_whatis_current_token
|
||||||
bind --preset $argv ctrl-l clear-screen
|
bind --preset $argv ctrl-l scrollback-push repaint
|
||||||
bind --preset $argv ctrl-c cancel-commandline
|
bind --preset $argv ctrl-c cancel-commandline
|
||||||
bind --preset $argv ctrl-u backward-kill-line
|
bind --preset $argv ctrl-u backward-kill-line
|
||||||
|
bind --preset $argv ctrl-k kill-line
|
||||||
bind --preset $argv ctrl-w backward-kill-path-component
|
bind --preset $argv ctrl-w backward-kill-path-component
|
||||||
bind --preset $argv end end-of-line
|
bind --preset $argv end end-of-line
|
||||||
bind --preset $argv home beginning-of-line
|
bind --preset $argv home beginning-of-line
|
||||||
|
|||||||
@@ -54,10 +54,7 @@ function edit_command_buffer --description 'Edit the command buffer in an extern
|
|||||||
end
|
end
|
||||||
set cursor_from_editor (mktemp)
|
set cursor_from_editor (mktemp)
|
||||||
set -a editor +$line "+norm! $col|" $f \
|
set -a editor +$line "+norm! $col|" $f \
|
||||||
'+autocmd VimLeave * ++once call writefile(
|
'+au VimLeave * ++once call writefile([printf("%s %s %s", shellescape(bufname()), line("."), col("."))], "'$cursor_from_editor'")'
|
||||||
[printf("%s %s %s", shellescape(bufname()), line("."), col("."))],
|
|
||||||
"'$cursor_from_editor'"
|
|
||||||
)'
|
|
||||||
case emacs emacsclient gedit
|
case emacs emacsclient gedit
|
||||||
set -a editor +$line:$col $f
|
set -a editor +$line:$col $f
|
||||||
case kak
|
case kak
|
||||||
|
|||||||
19
share/functions/fish_jj_prompt.fish
Normal file
19
share/functions/fish_jj_prompt.fish
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
function fish_jj_prompt
|
||||||
|
# If jj isn't installed, there's nothing we can do
|
||||||
|
# Return 1 so the calling prompt can deal with it
|
||||||
|
if not command -sq jj
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
jj log 2>/dev/null --no-graph --ignore-working-copy --color=always --revisions @ \
|
||||||
|
--template '
|
||||||
|
concat(
|
||||||
|
" ",
|
||||||
|
separate(" ",
|
||||||
|
format_short_change_id_with_hidden_and_divergent_info(self),
|
||||||
|
bookmarks,
|
||||||
|
tags,
|
||||||
|
if(conflict, label("conflict", "×")),
|
||||||
|
if(empty, label("empty", "(empty)"))
|
||||||
|
),
|
||||||
|
)'
|
||||||
|
end
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
function fish_vcs_prompt --description "Print all vcs prompts"
|
function fish_vcs_prompt --description "Print all vcs prompts"
|
||||||
# If a prompt succeeded, we assume that it's printed the correct info.
|
# If a prompt succeeded, we assume that it's printed the correct info.
|
||||||
# This is so we don't try svn if git already worked.
|
# This is so we don't try svn if git already worked.
|
||||||
fish_git_prompt $argv
|
fish_jj_prompt $argv
|
||||||
|
or fish_git_prompt $argv
|
||||||
or fish_hg_prompt $argv
|
or fish_hg_prompt $argv
|
||||||
or fish_fossil_prompt $argv
|
or fish_fossil_prompt $argv
|
||||||
# The svn prompt is disabled by default because it's quite slow on common svn repositories.
|
# The svn prompt is disabled by default because it's quite slow on common svn repositories.
|
||||||
|
|||||||
@@ -312,6 +312,9 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish'
|
|||||||
bind -s --preset -M visual $key beginning-of-line
|
bind -s --preset -M visual $key beginning-of-line
|
||||||
end
|
end
|
||||||
|
|
||||||
|
bind -s --preset -M visual -m default v end-selection repaint-mode
|
||||||
|
bind -s --preset -M visual -m insert i end-selection repaint-mode
|
||||||
|
bind -s --preset -M visual -m insert I end-selection beginning-of-line repaint-mode
|
||||||
bind -s --preset -M visual -m insert c kill-selection end-selection repaint-mode
|
bind -s --preset -M visual -m insert c kill-selection end-selection repaint-mode
|
||||||
bind -s --preset -M visual -m insert s kill-selection end-selection repaint-mode
|
bind -s --preset -M visual -m insert s kill-selection end-selection repaint-mode
|
||||||
bind -s --preset -M visual -m default d kill-selection end-selection backward-char repaint-mode
|
bind -s --preset -M visual -m default d kill-selection end-selection backward-char repaint-mode
|
||||||
@@ -321,6 +324,7 @@ function fish_vi_key_bindings --description 'vi-like key bindings for fish'
|
|||||||
bind -s --preset -M visual -m default '",*,y' "fish_clipboard_copy; commandline -f end-selection repaint-mode"
|
bind -s --preset -M visual -m default '",*,y' "fish_clipboard_copy; commandline -f end-selection repaint-mode"
|
||||||
bind -s --preset -M visual -m default '",+,y' "fish_clipboard_copy; commandline -f end-selection repaint-mode"
|
bind -s --preset -M visual -m default '",+,y' "fish_clipboard_copy; commandline -f end-selection repaint-mode"
|
||||||
bind -s --preset -M visual -m default '~' togglecase-selection end-selection repaint-mode
|
bind -s --preset -M visual -m default '~' togglecase-selection end-selection repaint-mode
|
||||||
|
bind -s --preset -M visual -m default g,U togglecase-selection end-selection repaint-mode
|
||||||
|
|
||||||
bind -s --preset -M visual -m default ctrl-c end-selection repaint-mode
|
bind -s --preset -M visual -m default ctrl-c end-selection repaint-mode
|
||||||
bind -s --preset -M visual -m default escape end-selection repaint-mode
|
bind -s --preset -M visual -m default escape end-selection repaint-mode
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ function help --description 'Show help for the fish shell'
|
|||||||
if set -q BROWSER
|
if set -q BROWSER
|
||||||
# User has manually set a preferred browser, so we respect that
|
# User has manually set a preferred browser, so we respect that
|
||||||
echo $BROWSER | read -at fish_browser
|
echo $BROWSER | read -at fish_browser
|
||||||
|
if not type -q $fish_browser[1]
|
||||||
|
printf (_ 'help: %s is not a valid command: %s\n') '$fish_browser' "$fish_browser"
|
||||||
|
return 2
|
||||||
|
end
|
||||||
else
|
else
|
||||||
# No browser set up, inferring.
|
# No browser set up, inferring.
|
||||||
# We check a bunch and use the last we find.
|
# We check a bunch and use the last we find.
|
||||||
@@ -93,6 +97,11 @@ function help --description 'Show help for the fish shell'
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
if not type -q $fish_browser[1]
|
||||||
|
printf (_ 'help: %s is not a valid command: %s\n') '$fish_help_browser' "$fish_browser"
|
||||||
|
return 2
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# In Cygwin, start the user-specified browser using cygstart,
|
# In Cygwin, start the user-specified browser using cygstart,
|
||||||
|
|||||||
18
src/ast.rs
18
src/ast.rs
@@ -1255,7 +1255,7 @@ fn can_be_parsed(pop: &mut Populator<'_>) -> bool {
|
|||||||
token.typ == ParseTokenType::string
|
token.typ == ParseTokenType::string
|
||||||
&& !matches!(
|
&& !matches!(
|
||||||
token.keyword,
|
token.keyword,
|
||||||
ParseKeyword::kw_end | ParseKeyword::kw_else | ParseKeyword::kw_case
|
ParseKeyword::kw_case | ParseKeyword::kw_end | ParseKeyword::kw_else
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3337,6 +3337,14 @@ fn consume_excess_token_generating_error(&mut self) {
|
|||||||
ParseTokenType::string => {
|
ParseTokenType::string => {
|
||||||
// There are three keywords which end a job list.
|
// There are three keywords which end a job list.
|
||||||
match tok.keyword {
|
match tok.keyword {
|
||||||
|
ParseKeyword::kw_case => {
|
||||||
|
parse_error!(
|
||||||
|
self,
|
||||||
|
tok,
|
||||||
|
ParseErrorCode::unbalancing_case,
|
||||||
|
"'case' builtin not inside of switch block"
|
||||||
|
);
|
||||||
|
}
|
||||||
ParseKeyword::kw_end => {
|
ParseKeyword::kw_end => {
|
||||||
parse_error!(
|
parse_error!(
|
||||||
self,
|
self,
|
||||||
@@ -3353,14 +3361,6 @@ fn consume_excess_token_generating_error(&mut self) {
|
|||||||
"'else' builtin not inside of if block"
|
"'else' builtin not inside of if block"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ParseKeyword::kw_case => {
|
|
||||||
parse_error!(
|
|
||||||
self,
|
|
||||||
tok,
|
|
||||||
ParseErrorCode::unbalancing_case,
|
|
||||||
"'case' builtin not inside of switch block"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
internal_error!(
|
internal_error!(
|
||||||
self,
|
self,
|
||||||
|
|||||||
130
src/bin/fish.rs
130
src/bin/fish.rs
@@ -21,6 +21,8 @@
|
|||||||
#![allow(unstable_name_collisions)]
|
#![allow(unstable_name_collisions)]
|
||||||
#![allow(clippy::uninlined_format_args)]
|
#![allow(clippy::uninlined_format_args)]
|
||||||
|
|
||||||
|
#[cfg(feature = "installable")]
|
||||||
|
use fish::common::wcs2osstring;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use fish::future::IsSomeAnd;
|
use fish::future::IsSomeAnd;
|
||||||
use fish::{
|
use fish::{
|
||||||
@@ -42,7 +44,7 @@
|
|||||||
fprintf, function, future_feature_flags as features,
|
fprintf, function, future_feature_flags as features,
|
||||||
history::{self, start_private_mode},
|
history::{self, start_private_mode},
|
||||||
io::IoChain,
|
io::IoChain,
|
||||||
nix::{getpid, isatty},
|
nix::{getpid, getrusage, isatty, RUsage},
|
||||||
panic::panic_handler,
|
panic::panic_handler,
|
||||||
parse_constants::{ParseErrorList, ParseTreeFlags},
|
parse_constants::{ParseErrorList, ParseTreeFlags},
|
||||||
parse_tree::ParsedSource,
|
parse_tree::ParsedSource,
|
||||||
@@ -63,7 +65,6 @@
|
|||||||
};
|
};
|
||||||
use std::ffi::{CString, OsStr, OsString};
|
use std::ffi::{CString, OsStr, OsString};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::mem::MaybeUninit;
|
|
||||||
use std::os::unix::prelude::*;
|
use std::os::unix::prelude::*;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@@ -80,7 +81,7 @@
|
|||||||
#[cfg(feature = "installable")]
|
#[cfg(feature = "installable")]
|
||||||
// Disable for clippy because otherwise it would require sphinx
|
// Disable for clippy because otherwise it would require sphinx
|
||||||
#[cfg(not(clippy))]
|
#[cfg(not(clippy))]
|
||||||
fn install(confirm: bool) -> bool {
|
fn install(confirm: bool, dir: PathBuf) -> bool {
|
||||||
use rust_embed::RustEmbed;
|
use rust_embed::RustEmbed;
|
||||||
|
|
||||||
#[derive(RustEmbed)]
|
#[derive(RustEmbed)]
|
||||||
@@ -96,11 +97,6 @@ fn install(confirm: bool) -> bool {
|
|||||||
use std::io::ErrorKind;
|
use std::io::ErrorKind;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::io::{stderr, stdin};
|
use std::io::{stderr, stdin};
|
||||||
let Some(home) = fish::env::get_home() else {
|
|
||||||
eprintln!("Can't find $HOME",);
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
let dir = PathBuf::from(home).join(DATA_DIR).join(DATA_DIR_SUBDIR);
|
|
||||||
|
|
||||||
// TODO: Translation,
|
// TODO: Translation,
|
||||||
// FLOG?
|
// FLOG?
|
||||||
@@ -196,10 +192,9 @@ fn install(confirm: bool) -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(clippy, not(feature = "installable")))]
|
#[cfg(clippy)]
|
||||||
fn install(_confirm: bool) -> bool {
|
fn install(_confirm: bool, _dir: PathBuf) -> bool {
|
||||||
eprintln!("Fish was built without support for self-installation");
|
unreachable!()
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// container to hold the options specified within the command line
|
/// container to hold the options specified within the command line
|
||||||
@@ -241,13 +236,7 @@ fn tv_to_msec(tv: &libc::timeval) -> i64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn print_rusage_self() {
|
fn print_rusage_self() {
|
||||||
let mut rs = MaybeUninit::uninit();
|
let rs = getrusage(RUsage::RSelf);
|
||||||
if unsafe { libc::getrusage(libc::RUSAGE_SELF, rs.as_mut_ptr()) } != 0 {
|
|
||||||
let s = CString::new("getrusage").unwrap();
|
|
||||||
unsafe { libc::perror(s.as_ptr()) }
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let rs: libc::rusage = unsafe { rs.assume_init() };
|
|
||||||
let rss_kb = if cfg!(target_os = "macos") {
|
let rss_kb = if cfg!(target_os = "macos") {
|
||||||
// mac use bytes.
|
// mac use bytes.
|
||||||
rs.ru_maxrss / 1024
|
rs.ru_maxrss / 1024
|
||||||
@@ -284,7 +273,7 @@ fn determine_config_directory_paths(argv0: impl AsRef<Path>) -> ConfigPaths {
|
|||||||
|
|
||||||
// Detect if we're running right out of the CMAKE build directory
|
// Detect if we're running right out of the CMAKE build directory
|
||||||
if exec_path.starts_with(env!("CARGO_MANIFEST_DIR")) {
|
if exec_path.starts_with(env!("CARGO_MANIFEST_DIR")) {
|
||||||
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
|
||||||
FLOG!(
|
FLOG!(
|
||||||
config,
|
config,
|
||||||
"Running out of target directory, using paths relative to CARGO_MANIFEST_DIR:\n",
|
"Running out of target directory, using paths relative to CARGO_MANIFEST_DIR:\n",
|
||||||
@@ -300,10 +289,17 @@ fn determine_config_directory_paths(argv0: impl AsRef<Path>) -> ConfigPaths {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !done {
|
if !done {
|
||||||
// The next check is that we are in a reloctable directory tree
|
// The next check is that we are in a relocatable directory tree
|
||||||
if exec_path.ends_with("bin/fish") {
|
if exec_path.ends_with("bin/fish") {
|
||||||
let base_path = exec_path.parent().unwrap().parent().unwrap();
|
let base_path = exec_path.parent().unwrap().parent().unwrap();
|
||||||
paths = ConfigPaths {
|
paths = ConfigPaths {
|
||||||
|
// One obvious path is ~/.local (with fish in ~/.local/bin/).
|
||||||
|
// If we picked ~/.local/share/fish as our data path,
|
||||||
|
// we would install there and erase history.
|
||||||
|
// So let's isolate us a bit more.
|
||||||
|
#[cfg(feature = "installable")]
|
||||||
|
data: base_path.join("share/fish/install"),
|
||||||
|
#[cfg(not(feature = "installable"))]
|
||||||
data: base_path.join("share/fish"),
|
data: base_path.join("share/fish"),
|
||||||
sysconf: base_path.join("etc/fish"),
|
sysconf: base_path.join("etc/fish"),
|
||||||
doc: base_path.join("share/doc/fish"),
|
doc: base_path.join("share/doc/fish"),
|
||||||
@@ -316,6 +312,9 @@ fn determine_config_directory_paths(argv0: impl AsRef<Path>) -> ConfigPaths {
|
|||||||
);
|
);
|
||||||
let base_path = exec_path.parent().unwrap();
|
let base_path = exec_path.parent().unwrap();
|
||||||
paths = ConfigPaths {
|
paths = ConfigPaths {
|
||||||
|
#[cfg(feature = "installable")]
|
||||||
|
data: base_path.join("share/install"),
|
||||||
|
#[cfg(not(feature = "installable"))]
|
||||||
data: base_path.join("share"),
|
data: base_path.join("share"),
|
||||||
sysconf: base_path.join("etc"),
|
sysconf: base_path.join("etc"),
|
||||||
doc: base_path.join("user_doc/html"),
|
doc: base_path.join("user_doc/html"),
|
||||||
@@ -339,14 +338,15 @@ fn determine_config_directory_paths(argv0: impl AsRef<Path>) -> ConfigPaths {
|
|||||||
let Some(home) = fish::env::get_home() else {
|
let Some(home) = fish::env::get_home() else {
|
||||||
FLOG!(
|
FLOG!(
|
||||||
error,
|
error,
|
||||||
"Cannot find home directory and will refuse to read configuration"
|
"Cannot find home directory and will refuse to read configuration.\n",
|
||||||
|
"Consider installing into a directory tree with `fish --install=PATH`."
|
||||||
);
|
);
|
||||||
return paths;
|
return paths;
|
||||||
};
|
};
|
||||||
|
|
||||||
PathBuf::from(home).join(DATA_DIR).join(DATA_DIR_SUBDIR)
|
PathBuf::from(home).join(DATA_DIR).join(DATA_DIR_SUBDIR)
|
||||||
} else {
|
} else {
|
||||||
PathBuf::from(DATA_DIR).join(DATA_DIR_SUBDIR)
|
Path::new(DATA_DIR).join(DATA_DIR_SUBDIR)
|
||||||
};
|
};
|
||||||
let bin = if cfg!(feature = "installable") {
|
let bin = if cfg!(feature = "installable") {
|
||||||
exec_path.parent().map(|x| x.to_path_buf())
|
exec_path.parent().map(|x| x.to_path_buf())
|
||||||
@@ -357,7 +357,7 @@ fn determine_config_directory_paths(argv0: impl AsRef<Path>) -> ConfigPaths {
|
|||||||
FLOG!(config, "Using compiled in paths:");
|
FLOG!(config, "Using compiled in paths:");
|
||||||
paths = ConfigPaths {
|
paths = ConfigPaths {
|
||||||
data,
|
data,
|
||||||
sysconf: PathBuf::from(SYSCONF_DIR).join("fish"),
|
sysconf: Path::new(SYSCONF_DIR).join("fish"),
|
||||||
doc: DOC_DIR.into(),
|
doc: DOC_DIR.into(),
|
||||||
bin,
|
bin,
|
||||||
}
|
}
|
||||||
@@ -421,8 +421,7 @@ fn check_version_file(paths: &ConfigPaths, datapath: &wstr) -> Option<bool> {
|
|||||||
{
|
{
|
||||||
// When fish is installable, we write the version to a file,
|
// When fish is installable, we write the version to a file,
|
||||||
// now we check it.
|
// now we check it.
|
||||||
let verfile =
|
let verfile = PathBuf::from(wcs2osstring(datapath)).join("fish-install-version");
|
||||||
PathBuf::from(fish::common::wcs2osstring(datapath)).join("fish-install-version");
|
|
||||||
let version = std::fs::read_to_string(verfile).ok()?;
|
let version = std::fs::read_to_string(verfile).ok()?;
|
||||||
|
|
||||||
return Some(version == fish::BUILD_VERSION);
|
return Some(version == fish::BUILD_VERSION);
|
||||||
@@ -458,7 +457,7 @@ fn read_init(parser: &Parser, paths: &ConfigPaths) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
install(true);
|
install(true, PathBuf::from(wcs2osstring(&datapath)));
|
||||||
// We try to go on if installation failed (or was rejected) here
|
// We try to go on if installation failed (or was rejected) here
|
||||||
// If the assets are missing, we will trigger a later error,
|
// If the assets are missing, we will trigger a later error,
|
||||||
// if they are outdated, things will probably (tm) work somewhat.
|
// if they are outdated, things will probably (tm) work somewhat.
|
||||||
@@ -540,7 +539,7 @@ fn fish_parse_opt(args: &mut [WString], opts: &mut FishCmdOpts) -> ControlFlow<i
|
|||||||
wopt(L!("no-config"), NoArgument, 'N'),
|
wopt(L!("no-config"), NoArgument, 'N'),
|
||||||
wopt(L!("no-execute"), NoArgument, 'n'),
|
wopt(L!("no-execute"), NoArgument, 'n'),
|
||||||
wopt(L!("print-rusage-self"), NoArgument, RUSAGE_ARG),
|
wopt(L!("print-rusage-self"), NoArgument, RUSAGE_ARG),
|
||||||
wopt(L!("install"), NoArgument, 'I'),
|
wopt(L!("install"), OptionalArgument, 'I'),
|
||||||
wopt(
|
wopt(
|
||||||
L!("print-debug-categories"),
|
L!("print-debug-categories"),
|
||||||
NoArgument,
|
NoArgument,
|
||||||
@@ -576,7 +575,60 @@ fn fish_parse_opt(args: &mut [WString], opts: &mut FishCmdOpts) -> ControlFlow<i
|
|||||||
'h' => opts.batch_cmds.push("__fish_print_help fish".into()),
|
'h' => opts.batch_cmds.push("__fish_print_help fish".into()),
|
||||||
'i' => opts.is_interactive_session = true,
|
'i' => opts.is_interactive_session = true,
|
||||||
'I' => {
|
'I' => {
|
||||||
install(false);
|
#[cfg(not(feature = "installable"))]
|
||||||
|
eprintln!("Fish was built without support for self-installation");
|
||||||
|
#[cfg(feature = "installable")]
|
||||||
|
if let Some(path) = w.woptarg {
|
||||||
|
// We were given an explicit path.
|
||||||
|
// Install us there as a relocatable install.
|
||||||
|
// That means:
|
||||||
|
// path/bin/fish is the fish binary
|
||||||
|
// path/share/fish/ is the data directory
|
||||||
|
// path/etc/fish is sysconf????
|
||||||
|
use std::fs;
|
||||||
|
let dir = PathBuf::from(wcs2osstring(path));
|
||||||
|
if install(true, dir.join("share/fish/install")) {
|
||||||
|
for sub in &["share/fish/install", "etc/fish", "bin"] {
|
||||||
|
let p = dir.join(sub);
|
||||||
|
let Ok(_) = fs::create_dir_all(p.clone()) else {
|
||||||
|
eprintln!("Creating directory '{}' failed", p.display());
|
||||||
|
std::process::exit(1);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy ourselves there.
|
||||||
|
let argv0 = OsString::from_vec(wcs2string(&args[0]));
|
||||||
|
let exec_path =
|
||||||
|
get_executable_path(<OsString as AsRef<Path>>::as_ref(&argv0));
|
||||||
|
let binpath = dir.join("bin/fish");
|
||||||
|
if let Ok(exec_path) = exec_path.canonicalize() {
|
||||||
|
if exec_path != binpath {
|
||||||
|
if let Err(err) = std::fs::copy(exec_path, binpath.clone()) {
|
||||||
|
FLOG!(error, "Cannot copy fish to", binpath.display());
|
||||||
|
FLOG!(error, err);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
println!(
|
||||||
|
"Fish installed in '{}'. Start that from now on.",
|
||||||
|
binpath.display()
|
||||||
|
);
|
||||||
|
// TODO: Reexec fish?
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FLOG!(error, "Cannot copy fish to '%ls'. Please copy the fish binary there manually", binpath.display());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let paths = Some(determine_config_directory_paths(OsString::from_vec(
|
||||||
|
wcs2string(&args[0]),
|
||||||
|
)));
|
||||||
|
let Some(paths) = paths else {
|
||||||
|
FLOG!(error, "Cannot find config paths");
|
||||||
|
std::process::exit(1);
|
||||||
|
};
|
||||||
|
install(true, paths.data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
'l' => opts.is_login = true,
|
'l' => opts.is_login = true,
|
||||||
'N' => {
|
'N' => {
|
||||||
@@ -714,7 +766,7 @@ fn throwing_main() -> i32 {
|
|||||||
.write(true)
|
.write(true)
|
||||||
.truncate(true)
|
.truncate(true)
|
||||||
.create(true)
|
.create(true)
|
||||||
.open(debug_path.clone())
|
.open(&debug_path)
|
||||||
{
|
{
|
||||||
Ok(dbg_file) => {
|
Ok(dbg_file) => {
|
||||||
// Rust sets O_CLOEXEC by default
|
// Rust sets O_CLOEXEC by default
|
||||||
@@ -759,10 +811,9 @@ fn throwing_main() -> i32 {
|
|||||||
save_term_foreground_process_group();
|
save_term_foreground_process_group();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut paths: Option<ConfigPaths> = None;
|
|
||||||
// If we're not executing, there's no need to find the config.
|
// If we're not executing, there's no need to find the config.
|
||||||
if !opts.no_exec {
|
let paths: Option<ConfigPaths> = if !opts.no_exec {
|
||||||
paths = Some(determine_config_directory_paths(OsString::from_vec(
|
let paths = Some(determine_config_directory_paths(OsString::from_vec(
|
||||||
wcs2string(&args[0]),
|
wcs2string(&args[0]),
|
||||||
)));
|
)));
|
||||||
env_init(
|
env_init(
|
||||||
@@ -770,7 +821,10 @@ fn throwing_main() -> i32 {
|
|||||||
/* do uvars */ !opts.no_config,
|
/* do uvars */ !opts.no_config,
|
||||||
/* default paths */ opts.no_config,
|
/* default paths */ opts.no_config,
|
||||||
);
|
);
|
||||||
}
|
paths
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// Set features early in case other initialization depends on them.
|
// Set features early in case other initialization depends on them.
|
||||||
// Start with the ones set in the environment, then those set on the command line (so the
|
// Start with the ones set in the environment, then those set on the command line (so the
|
||||||
@@ -787,7 +841,7 @@ fn throwing_main() -> i32 {
|
|||||||
|
|
||||||
// Construct the root parser!
|
// Construct the root parser!
|
||||||
let env = Rc::new(EnvStack::globals().create_child(true /* dispatches_var_changes */));
|
let env = Rc::new(EnvStack::globals().create_child(true /* dispatches_var_changes */));
|
||||||
let parser: &Parser = &Parser::new(env, CancelBehavior::Clear);
|
let parser = &Parser::new(env, CancelBehavior::Clear);
|
||||||
parser.set_syncs_uvars(!opts.no_config);
|
parser.set_syncs_uvars(!opts.no_config);
|
||||||
|
|
||||||
if !opts.no_exec && !opts.no_config {
|
if !opts.no_exec && !opts.no_config {
|
||||||
@@ -950,7 +1004,6 @@ fn fish_xdm_login_hack_hack_hack_hack(cmds: &mut [OsString], args: &[WString]) -
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut result = false;
|
|
||||||
let cmd = &cmds[0];
|
let cmd = &cmds[0];
|
||||||
if cmd == "exec \"${@}\"" || cmd == "exec \"$@\"" {
|
if cmd == "exec \"${@}\"" || cmd == "exec \"$@\"" {
|
||||||
// We're going to construct a new command that starts with exec, and then has the
|
// We're going to construct a new command that starts with exec, and then has the
|
||||||
@@ -962,7 +1015,8 @@ fn fish_xdm_login_hack_hack_hack_hack(cmds: &mut [OsString], args: &[WString]) -
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmds[0] = new_cmd;
|
cmds[0] = new_cmd;
|
||||||
result = true;
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,21 +9,21 @@
|
|||||||
|
|
||||||
use std::{ops::ControlFlow, os::unix::prelude::OsStrExt};
|
use std::{ops::ControlFlow, os::unix::prelude::OsStrExt};
|
||||||
|
|
||||||
use libc::{STDIN_FILENO, TCSANOW, VEOF, VINTR};
|
use libc::{STDIN_FILENO, STDOUT_FILENO, TCSANOW, VEOF, VINTR};
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use fish::future::IsSomeAnd;
|
use fish::future::IsSomeAnd;
|
||||||
use fish::{
|
use fish::{
|
||||||
builtins::shared::BUILTIN_ERR_UNKNOWN,
|
builtins::shared::BUILTIN_ERR_UNKNOWN,
|
||||||
common::{shell_modes, str2wcstring, PROGRAM_NAME},
|
common::{shell_modes, str2wcstring, write_loop, PROGRAM_NAME},
|
||||||
env::env_init,
|
env::env_init,
|
||||||
eprintf, fprintf,
|
eprintf, fprintf,
|
||||||
input::input_terminfo_get_name,
|
input::input_terminfo_get_name,
|
||||||
input_common::{
|
input_common::{
|
||||||
terminal_protocol_hacks, terminal_protocols_enable_ifn, CharEvent, InputEventQueue,
|
terminal_protocol_hacks, terminal_protocols_enable_ifn, CharEvent, InputEventQueue,
|
||||||
InputEventQueuer,
|
InputEventQueuer, KITTY_PROGRESSIVE_ENHANCEMENTS_QUERY,
|
||||||
},
|
},
|
||||||
key::{self, char_to_symbol, Key},
|
key::{char_to_symbol, Key},
|
||||||
panic::panic_handler,
|
panic::panic_handler,
|
||||||
print_help::print_help,
|
print_help::print_help,
|
||||||
printf,
|
printf,
|
||||||
@@ -101,9 +101,6 @@ fn process_input(continuous_mode: bool, verbose: bool) -> i32 {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let c = kevt.key.codepoint;
|
let c = kevt.key.codepoint;
|
||||||
if c == key::Invalid {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if verbose {
|
if verbose {
|
||||||
printf!("# decoded from: ");
|
printf!("# decoded from: ");
|
||||||
for byte in kevt.seq.chars() {
|
for byte in kevt.seq.chars() {
|
||||||
@@ -140,6 +137,7 @@ fn setup_and_process_keys(continuous_mode: bool, verbose: bool) -> i32 {
|
|||||||
unsafe { libc::tcsetattr(STDIN_FILENO, TCSANOW, &*shell_modes()) };
|
unsafe { libc::tcsetattr(STDIN_FILENO, TCSANOW, &*shell_modes()) };
|
||||||
|
|
||||||
terminal_protocol_hacks();
|
terminal_protocol_hacks();
|
||||||
|
let _ = write_loop(&STDOUT_FILENO, KITTY_PROGRESSIVE_ENHANCEMENTS_QUERY);
|
||||||
|
|
||||||
if continuous_mode {
|
if continuous_mode {
|
||||||
eprintf!("\n");
|
eprintf!("\n");
|
||||||
|
|||||||
@@ -686,15 +686,15 @@ pub fn read(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo!("don't clone")
|
let mut ifs_delimiter = WString::new();
|
||||||
let delimiter = opts
|
let delimiter: &wstr = opts.delimiter.as_deref().unwrap_or_else(|| {
|
||||||
.delimiter
|
ifs_delimiter = parser
|
||||||
.clone()
|
.vars()
|
||||||
.or_else(|| {
|
.get_unless_empty(L!("IFS"))
|
||||||
let ifs = parser.vars().get_unless_empty(L!("IFS"));
|
.map(|var| var.as_string())
|
||||||
ifs.map(|ifs| ifs.as_string())
|
|
||||||
})
|
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
&ifs_delimiter
|
||||||
|
});
|
||||||
|
|
||||||
if delimiter.is_empty() {
|
if delimiter.is_empty() {
|
||||||
// Every character is a separate token with one wrinkle involving non-array mode where
|
// Every character is a separate token with one wrinkle involving non-array mode where
|
||||||
@@ -735,7 +735,7 @@ pub fn read(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt
|
|||||||
if opts.delimiter.is_none() {
|
if opts.delimiter.is_none() {
|
||||||
// We're using IFS, so tokenize the buffer using each IFS char. This is for backward
|
// We're using IFS, so tokenize the buffer using each IFS char. This is for backward
|
||||||
// compatibility with old versions of fish.
|
// compatibility with old versions of fish.
|
||||||
let tokens = split_string_tok(&buff, &delimiter, None)
|
let tokens = split_string_tok(&buff, delimiter, None)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|s| s.to_owned())
|
.map(|s| s.to_owned())
|
||||||
.collect();
|
.collect();
|
||||||
@@ -743,7 +743,7 @@ pub fn read(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt
|
|||||||
var_ptr += 1;
|
var_ptr += 1;
|
||||||
} else {
|
} else {
|
||||||
// We're using a delimiter provided by the user so use the `string split` behavior.
|
// We're using a delimiter provided by the user so use the `string split` behavior.
|
||||||
let splits = split_about(&buff, &delimiter, usize::MAX, false)
|
let splits = split_about(&buff, delimiter, usize::MAX, false)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|s| s.to_owned())
|
.map(|s| s.to_owned())
|
||||||
.collect();
|
.collect();
|
||||||
@@ -757,7 +757,7 @@ pub fn read(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt
|
|||||||
// compatibility with old versions of fish.
|
// compatibility with old versions of fish.
|
||||||
// Note the final variable gets any remaining text.
|
// Note the final variable gets any remaining text.
|
||||||
let mut var_vals: Vec<WString> =
|
let mut var_vals: Vec<WString> =
|
||||||
split_string_tok(&buff, &delimiter, Some(vars_left(var_ptr)))
|
split_string_tok(&buff, delimiter, Some(vars_left(var_ptr)))
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|s| s.to_owned())
|
.map(|s| s.to_owned())
|
||||||
.collect();
|
.collect();
|
||||||
@@ -775,7 +775,7 @@ pub fn read(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Opt
|
|||||||
// We're using a delimiter provided by the user so use the `string split` behavior.
|
// We're using a delimiter provided by the user so use the `string split` behavior.
|
||||||
// We're making at most argc - 1 splits so the last variable
|
// We're making at most argc - 1 splits so the last variable
|
||||||
// is set to the remaining string.
|
// is set to the remaining string.
|
||||||
let splits = split_about(&buff, &delimiter, argc - 1, false);
|
let splits = split_about(&buff, delimiter, argc - 1, false);
|
||||||
assert!(splits.len() <= vars_left(var_ptr));
|
assert!(splits.len() <= vars_left(var_ptr));
|
||||||
for split in splits {
|
for split in splits {
|
||||||
parser.set_var_and_fire(argv[var_ptr], opts.place, vec![split.to_owned()]);
|
parser.set_var_and_fire(argv[var_ptr], opts.place, vec![split.to_owned()]);
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ pub fn r#return(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) ->
|
|||||||
Err(e) => return e,
|
Err(e) => return e,
|
||||||
};
|
};
|
||||||
|
|
||||||
let has_function_block = parser.blocks().iter().any(|b| b.is_function_call());
|
let has_function_block = parser.blocks_iter_rev().any(|b| b.is_function_call());
|
||||||
|
|
||||||
// *nix does not support negative return values, but our `return` builtin happily accepts being
|
// *nix does not support negative return values, but our `return` builtin happily accepts being
|
||||||
// called with negative literals (e.g. `return -1`).
|
// called with negative literals (e.g. `return -1`).
|
||||||
|
|||||||
@@ -873,7 +873,7 @@ fn builtin_break_continue(
|
|||||||
// Paranoia: ensure we have a real loop.
|
// Paranoia: ensure we have a real loop.
|
||||||
// This is checked in the AST but we may be invoked dynamically, e.g. just via "eval break".
|
// This is checked in the AST but we may be invoked dynamically, e.g. just via "eval break".
|
||||||
let mut has_loop = false;
|
let mut has_loop = false;
|
||||||
for b in parser.blocks().iter().rev() {
|
for b in parser.blocks_iter_rev() {
|
||||||
if [BlockType::while_block, BlockType::for_block].contains(&b.typ()) {
|
if [BlockType::while_block, BlockType::for_block].contains(&b.typ()) {
|
||||||
has_loop = true;
|
has_loop = true;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -57,12 +57,14 @@ enum StatusCmd {
|
|||||||
STATUS_STACK_TRACE,
|
STATUS_STACK_TRACE,
|
||||||
STATUS_TEST_FEATURE,
|
STATUS_TEST_FEATURE,
|
||||||
STATUS_CURRENT_COMMANDLINE,
|
STATUS_CURRENT_COMMANDLINE,
|
||||||
|
STATUS_BUILDINFO,
|
||||||
}
|
}
|
||||||
|
|
||||||
str_enum!(
|
str_enum!(
|
||||||
StatusCmd,
|
StatusCmd,
|
||||||
(STATUS_BASENAME, "basename"),
|
(STATUS_BASENAME, "basename"),
|
||||||
(STATUS_BASENAME, "current-basename"),
|
(STATUS_BASENAME, "current-basename"),
|
||||||
|
(STATUS_BUILDINFO, "buildinfo"),
|
||||||
(STATUS_CURRENT_CMD, "current-command"),
|
(STATUS_CURRENT_CMD, "current-command"),
|
||||||
(STATUS_CURRENT_COMMANDLINE, "current-commandline"),
|
(STATUS_CURRENT_COMMANDLINE, "current-commandline"),
|
||||||
(STATUS_DIRNAME, "current-dirname"),
|
(STATUS_DIRNAME, "current-dirname"),
|
||||||
@@ -432,6 +434,45 @@ pub fn status(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> O
|
|||||||
return STATUS_INVALID_ARGS;
|
return STATUS_INVALID_ARGS;
|
||||||
}
|
}
|
||||||
match s {
|
match s {
|
||||||
|
STATUS_BUILDINFO => {
|
||||||
|
let version = str2wcstring(crate::BUILD_VERSION.as_bytes());
|
||||||
|
let target = str2wcstring(env!("BUILD_TARGET_TRIPLE").as_bytes());
|
||||||
|
let host = str2wcstring(env!("BUILD_HOST_TRIPLE").as_bytes());
|
||||||
|
let profile = str2wcstring(env!("BUILD_PROFILE").as_bytes());
|
||||||
|
streams.out.append(L!("Build system: "));
|
||||||
|
let buildsystem = match option_env!("CMAKE") {
|
||||||
|
Some("1") => "CMake",
|
||||||
|
_ => "Cargo",
|
||||||
|
};
|
||||||
|
streams.out.appendln(str2wcstring(buildsystem.as_bytes()));
|
||||||
|
streams.out.append(L!("Version: "));
|
||||||
|
streams.out.appendln(version);
|
||||||
|
if target == host {
|
||||||
|
streams.out.append(L!("Target (and host): "));
|
||||||
|
streams.out.appendln(target);
|
||||||
|
} else {
|
||||||
|
streams.out.append(L!("Target: "));
|
||||||
|
streams.out.appendln(target);
|
||||||
|
streams.out.append(L!("Host: "));
|
||||||
|
streams.out.appendln(host);
|
||||||
|
}
|
||||||
|
streams.out.append(L!("Profile: "));
|
||||||
|
streams.out.appendln(profile);
|
||||||
|
streams.out.append(L!("Features: "));
|
||||||
|
let features: &[&str] = &[
|
||||||
|
#[cfg(gettext)]
|
||||||
|
"gettext",
|
||||||
|
#[cfg(feature = "installable")]
|
||||||
|
"installable",
|
||||||
|
#[cfg(target_feature = "crt-static")]
|
||||||
|
"crt-static",
|
||||||
|
];
|
||||||
|
streams
|
||||||
|
.out
|
||||||
|
.appendln(str2wcstring(features.join(" ").as_bytes()));
|
||||||
|
streams.out.appendln("");
|
||||||
|
return STATUS_CMD_OK;
|
||||||
|
}
|
||||||
STATUS_BASENAME | STATUS_DIRNAME | STATUS_FILENAME => {
|
STATUS_BASENAME | STATUS_DIRNAME | STATUS_FILENAME => {
|
||||||
let res = parser.current_filename();
|
let res = parser.current_filename();
|
||||||
let function = res.unwrap_or_default();
|
let function = res.unwrap_or_default();
|
||||||
|
|||||||
@@ -852,10 +852,10 @@ fn parse_number(arg: &wstr, number: &mut Number, errors: &mut Vec<WString>) -> b
|
|||||||
} else {
|
} else {
|
||||||
errors.push(wgettext_fmt!("Argument is not a number: '%ls'", arg));
|
errors.push(wgettext_fmt!("Argument is not a number: '%ls'", arg));
|
||||||
}
|
}
|
||||||
} else if floating.map_or(false, |x| x.is_nan()) {
|
} else if floating.is_ok_and(|x| x.is_nan()) {
|
||||||
// NaN is an error as far as we're concerned.
|
// NaN is an error as far as we're concerned.
|
||||||
errors.push(wgettext!("Not a number").to_owned());
|
errors.push(wgettext!("Not a number").to_owned());
|
||||||
} else if floating.map_or(false, |x| x.is_infinite()) {
|
} else if floating.is_ok_and(|x| x.is_infinite()) {
|
||||||
errors.push(wgettext!("Number is infinite").to_owned());
|
errors.push(wgettext!("Number is infinite").to_owned());
|
||||||
} else if integral == Err(Error::Overflow) {
|
} else if integral == Err(Error::Overflow) {
|
||||||
errors.push(wgettext_fmt!("Result too large: %ls", arg));
|
errors.push(wgettext_fmt!("Result too large: %ls", arg));
|
||||||
|
|||||||
@@ -36,15 +36,24 @@ fn find_wait_handles(
|
|||||||
handles: &mut Vec<WaitHandleRef>,
|
handles: &mut Vec<WaitHandleRef>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// Has a job already completed?
|
// Has a job already completed?
|
||||||
// TODO: we can avoid traversing this list if searching by pid.
|
|
||||||
let mut matched = false;
|
let mut matched = false;
|
||||||
let wait_handles: &mut WaitHandleStore = &mut parser.mut_wait_handles();
|
let wait_handles: &mut WaitHandleStore = &mut parser.mut_wait_handles();
|
||||||
|
match query {
|
||||||
|
WaitHandleQuery::Pid(pid) => {
|
||||||
|
if let Some(wh) = wait_handles.get_by_pid(pid) {
|
||||||
|
handles.push(wh);
|
||||||
|
matched = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
for wh in wait_handles.iter() {
|
for wh in wait_handles.iter() {
|
||||||
if wait_handle_matches(query, wh) {
|
if wait_handle_matches(query, wh) {
|
||||||
handles.push(wh.clone());
|
handles.push(wh.clone());
|
||||||
matched = true;
|
matched = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Is there a running job match?
|
// Is there a running job match?
|
||||||
for j in &*parser.jobs() {
|
for j in &*parser.jobs() {
|
||||||
|
|||||||
@@ -1369,9 +1369,7 @@ pub fn valid_func_name(name: &wstr) -> bool {
|
|||||||
|
|
||||||
/// A rusty port of the C++ `write_loop()` function from `common.cpp`. This should be deprecated in
|
/// A rusty port of the C++ `write_loop()` function from `common.cpp`. This should be deprecated in
|
||||||
/// favor of native rust read/write methods at some point.
|
/// favor of native rust read/write methods at some point.
|
||||||
///
|
pub fn write_loop<Fd: AsRawFd>(fd: &Fd, buf: &[u8]) -> std::io::Result<()> {
|
||||||
/// Returns the number of bytes written or an IO error.
|
|
||||||
pub fn write_loop<Fd: AsRawFd>(fd: &Fd, buf: &[u8]) -> std::io::Result<usize> {
|
|
||||||
let fd = fd.as_raw_fd();
|
let fd = fd.as_raw_fd();
|
||||||
let mut total = 0;
|
let mut total = 0;
|
||||||
while total < buf.len() {
|
while total < buf.len() {
|
||||||
@@ -1387,7 +1385,7 @@ pub fn write_loop<Fd: AsRawFd>(fd: &Fd, buf: &[u8]) -> std::io::Result<usize> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(total)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A rusty port of the C++ `read_loop()` function from `common.cpp`. This should be deprecated in
|
/// A rusty port of the C++ `read_loop()` function from `common.cpp`. This should be deprecated in
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::future::IsSomeAnd;
|
use crate::future::IsSomeAnd;
|
||||||
use crate::highlight::HighlightSpec;
|
use crate::highlight::HighlightSpec;
|
||||||
@@ -142,31 +144,8 @@ pub fn at(&self, idx: usize) -> char {
|
|||||||
self.text.char_at(idx)
|
self.text.char_at(idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn line_at_cursor(&self) -> &wstr {
|
pub fn offset_to_line(&self, offset: usize) -> usize {
|
||||||
let start = self.text[0..self.position()]
|
self.text[0..offset].chars().filter(|&c| c == '\n').count()
|
||||||
.as_char_slice()
|
|
||||||
.iter()
|
|
||||||
.rposition(|&c| c == '\n')
|
|
||||||
.map(|newline| newline + 1)
|
|
||||||
.unwrap_or(0);
|
|
||||||
let end = self.text[self.position()..]
|
|
||||||
.as_char_slice()
|
|
||||||
.iter()
|
|
||||||
.position(|&c| c == '\n')
|
|
||||||
.map(|pos| self.position() + pos)
|
|
||||||
.unwrap_or(self.len());
|
|
||||||
// Remove any traililng newline
|
|
||||||
self.text[start..end].trim_matches('\n')
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
if self.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.push_edit(
|
|
||||||
Edit::new(0..self.len(), L!("").to_owned()),
|
|
||||||
/*allow_coalesce=*/ false,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Modify the commandline according to @edit. Most modifications to the
|
/// Modify the commandline according to @edit. Most modifications to the
|
||||||
@@ -186,15 +165,15 @@ pub fn push_edit(&mut self, mut edit: Edit, allow_coalesce: bool) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if range.is_empty() && edit.replacement.is_empty() {
|
||||||
|
return; // nop
|
||||||
|
}
|
||||||
|
|
||||||
// Assign a new group id or propagate the old one if we're in a logical grouping of edits
|
// Assign a new group id or propagate the old one if we're in a logical grouping of edits
|
||||||
if self.edit_group_level.is_some() {
|
if self.edit_group_level.is_some() {
|
||||||
edit.group_id = Some(self.edit_group_id);
|
edit.group_id = Some(self.edit_group_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let edit_does_nothing = range.is_empty() && edit.replacement.is_empty();
|
|
||||||
if edit_does_nothing {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if self.undo_history.edits_applied != self.undo_history.edits.len() {
|
if self.undo_history.edits_applied != self.undo_history.edits.len() {
|
||||||
// After undoing some edits, the user is making a new edit;
|
// After undoing some edits, the user is making a new edit;
|
||||||
// we are about to create a new edit branch.
|
// we are about to create a new edit branch.
|
||||||
@@ -362,3 +341,27 @@ fn cursor_position_after_edit(edit: &Edit) -> usize {
|
|||||||
let removed = chars_deleted_left_of_cursor(edit);
|
let removed = chars_deleted_left_of_cursor(edit);
|
||||||
cursor.saturating_sub(removed)
|
cursor.saturating_sub(removed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn range_of_line_at_cursor(buffer: &wstr, cursor: usize) -> Range<usize> {
|
||||||
|
let start = buffer[0..cursor]
|
||||||
|
.as_char_slice()
|
||||||
|
.iter()
|
||||||
|
.rposition(|&c| c == '\n')
|
||||||
|
.map(|newline| newline + 1)
|
||||||
|
.unwrap_or(0);
|
||||||
|
let mut end = buffer[cursor..]
|
||||||
|
.as_char_slice()
|
||||||
|
.iter()
|
||||||
|
.position(|&c| c == '\n')
|
||||||
|
.map(|pos| cursor + pos)
|
||||||
|
.unwrap_or(buffer.len());
|
||||||
|
// Remove any trailing newline
|
||||||
|
if end != start && buffer.char_at(end - 1) == '\n' {
|
||||||
|
end -= 1;
|
||||||
|
}
|
||||||
|
start..end
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn line_at_cursor(buffer: &wstr, cursor: usize) -> &wstr {
|
||||||
|
&buffer[range_of_line_at_cursor(buffer, cursor)]
|
||||||
|
}
|
||||||
|
|||||||
4
src/env/environment.rs
vendored
4
src/env/environment.rs
vendored
@@ -27,7 +27,7 @@
|
|||||||
use crate::wutil::{fish_wcstol, wgetcwd, wgettext};
|
use crate::wutil::{fish_wcstol, wgetcwd, wgettext};
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
use libc::{c_int, uid_t, STDOUT_FILENO, _IONBF};
|
use libc::{c_int, confstr, uid_t, STDOUT_FILENO, _IONBF};
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
@@ -568,7 +568,7 @@ fn setup_user(vars: &EnvStack) {
|
|||||||
|
|
||||||
/// Make sure the PATH variable contains something.
|
/// Make sure the PATH variable contains something.
|
||||||
fn setup_path() {
|
fn setup_path() {
|
||||||
use crate::libc::{confstr, _CS_PATH};
|
use crate::libc::_CS_PATH;
|
||||||
|
|
||||||
let vars = EnvStack::globals();
|
let vars = EnvStack::globals();
|
||||||
let path = vars.get_unless_empty(L!("PATH"));
|
let path = vars.get_unless_empty(L!("PATH"));
|
||||||
|
|||||||
32
src/env/environment_impl.rs
vendored
32
src/env/environment_impl.rs
vendored
@@ -14,7 +14,7 @@
|
|||||||
use crate::wchar::prelude::*;
|
use crate::wchar::prelude::*;
|
||||||
use crate::wutil::fish_wcstol_radix;
|
use crate::wutil::fish_wcstol_radix;
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use once_cell::sync::Lazy;
|
||||||
use std::cell::{RefCell, UnsafeCell};
|
use std::cell::{RefCell, UnsafeCell};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
@@ -201,16 +201,28 @@ fn changed_exported(&mut self) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RefCell except we promise it can be used as Sync.
|
||||||
|
// Safety: in order to do anything with this, the caller must be holding ENV_LOCK.
|
||||||
|
struct EnvNodeSyncCell(RefCell<EnvNode>);
|
||||||
|
|
||||||
|
impl EnvNodeSyncCell {
|
||||||
|
fn new(node: EnvNode) -> Self {
|
||||||
|
Self(RefCell::new(node))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for EnvNodeSyncCell {}
|
||||||
|
|
||||||
/// EnvNodeRef is a reference to an EnvNode. It may be shared between different environments.
|
/// EnvNodeRef is a reference to an EnvNode. It may be shared between different environments.
|
||||||
/// The type Arc<RefCell<...>> may look suspicious, but all accesses to the EnvNode are protected by a global lock.
|
/// All accesses to the EnvNode are protected by a global lock.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct EnvNodeRef(Arc<RefCell<EnvNode>>);
|
struct EnvNodeRef(Arc<EnvNodeSyncCell>);
|
||||||
|
|
||||||
impl Deref for EnvNodeRef {
|
impl Deref for EnvNodeRef {
|
||||||
type Target = RefCell<EnvNode>;
|
type Target = RefCell<EnvNode>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0 .0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +231,7 @@ fn new(is_new_scope: bool, next: Option<EnvNodeRef>) -> EnvNodeRef {
|
|||||||
// Accesses are protected by the global lock.
|
// Accesses are protected by the global lock.
|
||||||
#[allow(unknown_lints)]
|
#[allow(unknown_lints)]
|
||||||
#[allow(clippy::arc_with_non_send_sync)]
|
#[allow(clippy::arc_with_non_send_sync)]
|
||||||
EnvNodeRef(Arc::new(RefCell::new(EnvNode {
|
EnvNodeRef(Arc::new(EnvNodeSyncCell::new(EnvNode {
|
||||||
env: VarTable::new(),
|
env: VarTable::new(),
|
||||||
new_scope: is_new_scope,
|
new_scope: is_new_scope,
|
||||||
export_gen: 0,
|
export_gen: 0,
|
||||||
@@ -248,9 +260,6 @@ fn iter(&self) -> EnvNodeIter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safety: in order to do anything with an EnvNodeRef, the caller must be holding ENV_LOCK.
|
|
||||||
unsafe impl Sync for EnvNodeRef {}
|
|
||||||
|
|
||||||
/// Helper to iterate over a chain of EnvNodeRefs.
|
/// Helper to iterate over a chain of EnvNodeRefs.
|
||||||
struct EnvNodeIter {
|
struct EnvNodeIter {
|
||||||
current: Option<EnvNodeRef>,
|
current: Option<EnvNodeRef>,
|
||||||
@@ -276,10 +285,7 @@ fn next(&mut self) -> Option<EnvNodeRef> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
static GLOBAL_NODE: Lazy<EnvNodeRef> = Lazy::new(|| EnvNodeRef::new(false, None));
|
||||||
// All accesses to the EnvNode are protected by a global lock.
|
|
||||||
static ref GLOBAL_NODE: EnvNodeRef = EnvNodeRef::new(false, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Recursive helper to snapshot a series of nodes.
|
/// Recursive helper to snapshot a series of nodes.
|
||||||
fn copy_node_chain(node: &EnvNodeRef) -> EnvNodeRef {
|
fn copy_node_chain(node: &EnvNodeRef) -> EnvNodeRef {
|
||||||
@@ -293,7 +299,7 @@ fn copy_node_chain(node: &EnvNodeRef) -> EnvNodeRef {
|
|||||||
};
|
};
|
||||||
#[allow(unknown_lints)]
|
#[allow(unknown_lints)]
|
||||||
#[allow(clippy::arc_with_non_send_sync)]
|
#[allow(clippy::arc_with_non_send_sync)]
|
||||||
EnvNodeRef(Arc::new(RefCell::new(new_node)))
|
EnvNodeRef(Arc::new(EnvNodeSyncCell::new(new_node)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A struct wrapping up parser-local variables. These are conceptually variables that differ in
|
/// A struct wrapping up parser-local variables. These are conceptually variables that differ in
|
||||||
|
|||||||
16
src/env/var.rs
vendored
16
src/env/var.rs
vendored
@@ -102,7 +102,7 @@ pub struct EnvVarFlags: u8 {
|
|||||||
pub struct EnvVar {
|
pub struct EnvVar {
|
||||||
/// The list of values in this variable.
|
/// The list of values in this variable.
|
||||||
/// Arc allows for cheap copying
|
/// Arc allows for cheap copying
|
||||||
values: Arc<Box<[WString]>>,
|
values: Arc<[WString]>,
|
||||||
/// The variable's flags.
|
/// The variable's flags.
|
||||||
flags: EnvVarFlags,
|
flags: EnvVarFlags,
|
||||||
}
|
}
|
||||||
@@ -111,8 +111,8 @@ impl Default for EnvVar {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
/// A shared read-only empty list.
|
/// A shared read-only empty list.
|
||||||
static EMPTY_LIST: OnceLock<Arc<Box<[WString]>>> = OnceLock::new();
|
static EMPTY_LIST: OnceLock<Arc<[WString]>> = OnceLock::new();
|
||||||
let empty_list = EMPTY_LIST.get_or_init(|| Arc::new(Box::new([])));
|
let empty_list = EMPTY_LIST.get_or_init(|| Arc::new([]));
|
||||||
|
|
||||||
EnvVar {
|
EnvVar {
|
||||||
values: Arc::clone(empty_list),
|
values: Arc::clone(empty_list),
|
||||||
@@ -130,7 +130,7 @@ pub fn new(value: WString, flags: EnvVarFlags) -> Self {
|
|||||||
/// Creates a new `EnvVar`.
|
/// Creates a new `EnvVar`.
|
||||||
pub fn new_vec(values: Vec<WString>, flags: EnvVarFlags) -> Self {
|
pub fn new_vec(values: Vec<WString>, flags: EnvVarFlags) -> Self {
|
||||||
EnvVar {
|
EnvVar {
|
||||||
values: Arc::new(values.into_boxed_slice()),
|
values: values.into(),
|
||||||
flags,
|
flags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -199,15 +199,15 @@ pub fn get_delimiter(&self) -> char {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a copy of the variable with new values.
|
/// Returns a copy of the variable with new values.
|
||||||
pub fn setting_vals(&mut self, values: Vec<WString>) -> Self {
|
pub fn setting_vals(&self, values: Vec<WString>) -> Self {
|
||||||
EnvVar {
|
EnvVar {
|
||||||
values: Arc::new(values.into_boxed_slice()),
|
values: values.into(),
|
||||||
flags: self.flags,
|
flags: self.flags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a copy of the variable with the export flag changed.
|
/// Returns a copy of the variable with the export flag changed.
|
||||||
pub fn setting_exports(&mut self, export: bool) -> Self {
|
pub fn setting_exports(&self, export: bool) -> Self {
|
||||||
let mut flags = self.flags;
|
let mut flags = self.flags;
|
||||||
flags.set(EnvVarFlags::EXPORT, export);
|
flags.set(EnvVarFlags::EXPORT, export);
|
||||||
EnvVar {
|
EnvVar {
|
||||||
@@ -217,7 +217,7 @@ pub fn setting_exports(&mut self, export: bool) -> Self {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a copy of the variable with the path variable flag changed.
|
/// Returns a copy of the variable with the path variable flag changed.
|
||||||
pub fn setting_pathvar(&mut self, pathvar: bool) -> Self {
|
pub fn setting_pathvar(&self, pathvar: bool) -> Self {
|
||||||
let mut flags = self.flags;
|
let mut flags = self.flags;
|
||||||
flags.set(EnvVarFlags::PATHVAR, pathvar);
|
flags.set(EnvVarFlags::PATHVAR, pathvar);
|
||||||
EnvVar {
|
EnvVar {
|
||||||
|
|||||||
@@ -522,13 +522,13 @@ fn open_temporary_file(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Writes our state to the fd. path is provided only for error reporting.
|
/// Writes our state to the fd. path is provided only for error reporting.
|
||||||
fn write_to_fd(&mut self, fd: impl AsFd, path: &wstr) -> std::io::Result<usize> {
|
fn write_to_fd(&mut self, fd: impl AsFd, path: &wstr) -> std::io::Result<()> {
|
||||||
let fd = fd.as_fd();
|
let fd = fd.as_fd();
|
||||||
let contents = Self::serialize_with_vars(&self.vars);
|
let contents = Self::serialize_with_vars(&self.vars);
|
||||||
|
|
||||||
let res = write_loop(&fd, &contents);
|
let res = write_loop(&fd, &contents);
|
||||||
match res.as_ref() {
|
match res.as_ref() {
|
||||||
Ok(_) => {
|
Ok(()) => {
|
||||||
// Since we just wrote out this file, it matches our internal state; pretend we read from it.
|
// Since we just wrote out this file, it matches our internal state; pretend we read from it.
|
||||||
self.last_read_file = file_id_for_fd(fd);
|
self.last_read_file = file_id_for_fd(fd);
|
||||||
}
|
}
|
||||||
@@ -602,9 +602,9 @@ fn generate_callbacks_and_update_exports(
|
|||||||
let existing = self.vars.get(key);
|
let existing = self.vars.get(key);
|
||||||
|
|
||||||
// See if the value has changed.
|
// See if the value has changed.
|
||||||
let old_exports = existing.map_or(false, |v| v.exports());
|
let old_exports = existing.is_some_and(|v| v.exports());
|
||||||
let export_changed = old_exports != new_entry.exports();
|
let export_changed = old_exports != new_entry.exports();
|
||||||
let value_changed = existing.map_or(false, |v| v != new_entry);
|
let value_changed = existing.is_some_and(|v| v != new_entry);
|
||||||
if export_changed || value_changed {
|
if export_changed || value_changed {
|
||||||
self.export_generation += 1;
|
self.export_generation += 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ pub fn caller_exit(internal_job_id: u64, job_id: MaybeJobId) -> Self {
|
|||||||
|
|
||||||
/// Test if specified event is blocked.
|
/// Test if specified event is blocked.
|
||||||
fn is_blocked(&self, parser: &Parser) -> bool {
|
fn is_blocked(&self, parser: &Parser) -> bool {
|
||||||
for block in parser.blocks().iter().rev() {
|
for block in parser.blocks_iter_rev() {
|
||||||
if block.event_blocks {
|
if block.event_blocks {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -371,7 +371,7 @@ pub fn is_signal_observed(sig: libc::c_int) -> bool {
|
|||||||
// We are in a signal handler!
|
// We are in a signal handler!
|
||||||
OBSERVED_SIGNALS
|
OBSERVED_SIGNALS
|
||||||
.get(usize::try_from(sig).unwrap())
|
.get(usize::try_from(sig).unwrap())
|
||||||
.map_or(false, |s| s.load(Ordering::Relaxed) > 0)
|
.is_some_and(|s| s.load(Ordering::Relaxed) > 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_desc(parser: &Parser, evt: &Event) -> WString {
|
pub fn get_desc(parser: &Parser, evt: &Event) -> WString {
|
||||||
|
|||||||
@@ -766,7 +766,7 @@ fn create_output_stream_for_builtin(
|
|||||||
IoMode::bufferfill => {
|
IoMode::bufferfill => {
|
||||||
// Our IO redirection is to an internal buffer, e.g. a command substitution.
|
// Our IO redirection is to an internal buffer, e.g. a command substitution.
|
||||||
// We will write directly to it.
|
// We will write directly to it.
|
||||||
let buffer = io.as_bufferfill().unwrap().buffer_ref();
|
let buffer = io.as_bufferfill().unwrap().buffer();
|
||||||
OutputStream::Buffered(BufferedOutputStream::new(buffer.clone()))
|
OutputStream::Buffered(BufferedOutputStream::new(buffer.clone()))
|
||||||
}
|
}
|
||||||
IoMode::close => {
|
IoMode::close => {
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
#[cfg(not(target_has_atomic = "64"))]
|
#[cfg(not(target_has_atomic = "64"))]
|
||||||
use portable_atomic::AtomicU64;
|
use portable_atomic::AtomicU64;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::os::unix::prelude::*;
|
use std::os::unix::prelude::*;
|
||||||
#[cfg(target_has_atomic = "64")]
|
#[cfg(target_has_atomic = "64")]
|
||||||
use std::sync::atomic::AtomicU64;
|
use std::sync::atomic::AtomicU64;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
use std::sync::{Arc, Mutex, Weak};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::common::exit_without_destructors;
|
use crate::common::exit_without_destructors;
|
||||||
use crate::fd_readable_set::FdReadableSet;
|
use crate::fd_readable_set::{FdReadableSet, Timeout};
|
||||||
use crate::fds::AutoCloseFd;
|
use crate::fds::AutoCloseFd;
|
||||||
use crate::flog::FLOG;
|
use crate::flog::FLOG;
|
||||||
use crate::threads::assert_is_background_thread;
|
use crate::threads::assert_is_background_thread;
|
||||||
@@ -21,17 +22,6 @@
|
|||||||
#[cfg(HAVE_EVENTFD)]
|
#[cfg(HAVE_EVENTFD)]
|
||||||
use libc::{EFD_CLOEXEC, EFD_NONBLOCK};
|
use libc::{EFD_CLOEXEC, EFD_NONBLOCK};
|
||||||
|
|
||||||
/// Reason for waking an item
|
|
||||||
#[derive(PartialEq, Eq)]
|
|
||||||
pub enum ItemWakeReason {
|
|
||||||
/// The fd became readable (or was HUP'd)
|
|
||||||
Readable,
|
|
||||||
/// The requested timeout was hit
|
|
||||||
Timeout,
|
|
||||||
/// The item was "poked" (woken up explicitly)
|
|
||||||
Poke,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An event signaller implemented using a file descriptor, so it can plug into
|
/// An event signaller implemented using a file descriptor, so it can plug into
|
||||||
/// [`select()`](libc::select).
|
/// [`select()`](libc::select).
|
||||||
///
|
///
|
||||||
@@ -146,27 +136,12 @@ pub fn post(&self) {
|
|||||||
/// but guarantees that the next call to wait() will not block.
|
/// but guarantees that the next call to wait() will not block.
|
||||||
/// Return true if readable, false if not readable, or not interrupted by a signal.
|
/// Return true if readable, false if not readable, or not interrupted by a signal.
|
||||||
pub fn poll(&self, wait: bool /* = false */) -> bool {
|
pub fn poll(&self, wait: bool /* = false */) -> bool {
|
||||||
let mut timeout = libc::timeval {
|
let timeout = if wait {
|
||||||
tv_sec: 0,
|
Timeout::Forever
|
||||||
tv_usec: 0,
|
|
||||||
};
|
|
||||||
let mut fds: libc::fd_set = unsafe { std::mem::zeroed() };
|
|
||||||
unsafe { libc::FD_ZERO(&mut fds) };
|
|
||||||
unsafe { libc::FD_SET(self.read_fd(), &mut fds) };
|
|
||||||
let res = unsafe {
|
|
||||||
libc::select(
|
|
||||||
self.read_fd() + 1,
|
|
||||||
&mut fds,
|
|
||||||
std::ptr::null_mut(),
|
|
||||||
std::ptr::null_mut(),
|
|
||||||
if wait {
|
|
||||||
std::ptr::null_mut()
|
|
||||||
} else {
|
} else {
|
||||||
&mut timeout
|
Timeout::ZERO
|
||||||
},
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
res > 0
|
FdReadableSet::is_fd_readable(self.read_fd(), timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the fd to write to.
|
/// Return the fd to write to.
|
||||||
@@ -178,9 +153,9 @@ fn write_fd(&self) -> RawFd {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Each item added to fd_monitor_t is assigned a unique ID, which is not recycled. Items may have
|
/// Each item added to FdMonitor is assigned a unique ID, which is not recycled. Items may have
|
||||||
/// their callback triggered immediately by passing the ID. Zero is a sentinel.
|
/// their callback triggered immediately by passing the ID. Zero is a sentinel.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct FdMonitorItemId(u64);
|
pub struct FdMonitorItemId(u64);
|
||||||
|
|
||||||
impl From<FdMonitorItemId> for u64 {
|
impl From<FdMonitorItemId> for u64 {
|
||||||
@@ -196,10 +171,9 @@ fn from(value: u64) -> Self {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The callback type used by [`FdMonitorItem`]. It is passed a mutable reference to the
|
/// The callback type used by [`FdMonitorItem`]. It is passed a mutable reference to the
|
||||||
/// `FdMonitorItem`'s [`FdMonitorItem::fd`] and [the reason](ItemWakeupReason) for the wakeup.
|
/// `FdMonitorItem`'s [`FdMonitorItem::fd`]. If the fd is closed, the callback will not
|
||||||
/// It should return an [`ItemAction`] to indicate whether the item should be removed from the
|
/// be invoked again.
|
||||||
/// [`FdMonitor`] set.
|
pub type Callback = Box<dyn Fn(&mut AutoCloseFd) + Send + Sync>;
|
||||||
pub type Callback = Box<dyn Fn(&mut AutoCloseFd, ItemWakeReason) -> ItemAction + Send + Sync>;
|
|
||||||
|
|
||||||
/// An item containing an fd and callback, which can be monitored to watch when it becomes readable
|
/// An item containing an fd and callback, which can be monitored to watch when it becomes readable
|
||||||
/// and invoke the callback.
|
/// and invoke the callback.
|
||||||
@@ -209,82 +183,20 @@ pub struct FdMonitorItem {
|
|||||||
/// A callback to be invoked when the fd is readable, or for another reason given by the wake reason.
|
/// A callback to be invoked when the fd is readable, or for another reason given by the wake reason.
|
||||||
/// If the fd is invalid on return from the function, then the item is removed from the [`FdMonitor`] set.
|
/// If the fd is invalid on return from the function, then the item is removed from the [`FdMonitor`] set.
|
||||||
callback: Callback,
|
callback: Callback,
|
||||||
/// The timeout associated with waiting on this item or `None` to wait indefinitely. A timeout
|
|
||||||
/// of `0` is not supported.
|
|
||||||
timeout: Option<Duration>,
|
|
||||||
/// The last time we were called or the time of initialization.
|
|
||||||
last_time: Option<Instant>,
|
|
||||||
/// The id for this item, assigned by [`FdMonitor`].
|
|
||||||
item_id: FdMonitorItemId,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A value returned by the callback to indicate what to do with the item.
|
|
||||||
#[derive(PartialEq, Eq)]
|
|
||||||
pub enum ItemAction {
|
|
||||||
Remove,
|
|
||||||
Retain,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FdMonitorItem {
|
impl FdMonitorItem {
|
||||||
/// Return the duration until the timeout should trigger or `None`. A return of `0` means we are
|
/// Invoke this item's callback because the fd is readable.
|
||||||
/// at or past the timeout.
|
/// Returns the [`ItemAction`] to indicate whether the item should be removed from the [`FdMonitor`] set.
|
||||||
fn remaining_time(&self, now: &Instant) -> Option<Duration> {
|
fn service(&mut self) {
|
||||||
let last_time = self.last_time.expect("Should always have a last_time!");
|
(self.callback)(&mut self.fd)
|
||||||
let timeout = self.timeout?;
|
|
||||||
assert!(now >= &last_time, "Steady clock went backwards or bug!");
|
|
||||||
let since = *now - last_time;
|
|
||||||
Some(if since >= timeout {
|
|
||||||
Duration::ZERO
|
|
||||||
} else {
|
|
||||||
timeout - since
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Invoke this item's callback if its value (when its value is set in the fd or has timed out).
|
|
||||||
/// Returns `true` if the item should be retained or `false` if it should be removed from the
|
|
||||||
/// set.
|
|
||||||
fn service_item(&mut self, fds: &FdReadableSet, now: &Instant) -> ItemAction {
|
|
||||||
let mut result = ItemAction::Retain;
|
|
||||||
let readable = fds.test(self.fd.as_raw_fd());
|
|
||||||
let timed_out = !readable && self.remaining_time(now) == Some(Duration::ZERO);
|
|
||||||
if readable || timed_out {
|
|
||||||
self.last_time = Some(*now);
|
|
||||||
let reason = if readable {
|
|
||||||
ItemWakeReason::Readable
|
|
||||||
} else {
|
|
||||||
ItemWakeReason::Timeout
|
|
||||||
};
|
|
||||||
result = (self.callback)(&mut self.fd, reason);
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Invoke this item's callback with a poke, if its id is present in the sorted poke list.
|
|
||||||
fn maybe_poke_item(&mut self, pokelist: &[FdMonitorItemId]) -> ItemAction {
|
|
||||||
if self.item_id.0 == 0 || pokelist.binary_search(&self.item_id).is_err() {
|
|
||||||
// Not pokeable or not in the poke list.
|
|
||||||
return ItemAction::Retain;
|
|
||||||
}
|
|
||||||
|
|
||||||
(self.callback)(&mut self.fd, ItemWakeReason::Poke)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(fd: AutoCloseFd, timeout: Option<Duration>, callback: Callback) -> Self {
|
|
||||||
FdMonitorItem {
|
|
||||||
fd,
|
|
||||||
timeout,
|
|
||||||
callback,
|
|
||||||
item_id: FdMonitorItemId(0),
|
|
||||||
last_time: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A thread-safe class which can monitor a set of fds, invoking a callback when any becomes
|
/// A thread-safe class which can monitor a set of fds, invoking a callback when any becomes
|
||||||
/// readable (or has been HUP'd) or when per-item-configurable timeouts are reached.
|
/// readable (or has been HUP'd).
|
||||||
pub struct FdMonitor {
|
pub struct FdMonitor {
|
||||||
/// Our self-signaller. When this is written to, it means there are new items pending, new items
|
/// Our self-signaller, used to wake up the background thread out of select().
|
||||||
/// in the poke list, or terminate has been set.
|
|
||||||
change_signaller: Arc<FdEventSignaller>,
|
change_signaller: Arc<FdEventSignaller>,
|
||||||
/// The data shared between the background thread and the `FdMonitor` instance.
|
/// The data shared between the background thread and the `FdMonitor` instance.
|
||||||
data: Arc<Mutex<SharedData>>,
|
data: Arc<Mutex<SharedData>>,
|
||||||
@@ -303,11 +215,8 @@ fn assert_sync<T: Sync>() {}
|
|||||||
|
|
||||||
/// Data shared between the `FdMonitor` instance and its associated `BackgroundFdMonitor`.
|
/// Data shared between the `FdMonitor` instance and its associated `BackgroundFdMonitor`.
|
||||||
struct SharedData {
|
struct SharedData {
|
||||||
/// Pending items. This is set by the main thread with the mutex locked, then the background
|
/// The map of items. This may be modified by the main thread with the mutex locked.
|
||||||
/// thread grabs them.
|
items: HashMap<FdMonitorItemId, FdMonitorItem>,
|
||||||
pending: Vec<FdMonitorItem>,
|
|
||||||
/// List of IDs for items that need to be poked (explicitly woken up).
|
|
||||||
pokelist: Vec<FdMonitorItemId>,
|
|
||||||
/// Whether the background thread is running.
|
/// Whether the background thread is running.
|
||||||
running: bool,
|
running: bool,
|
||||||
/// Used to signal that the background thread should terminate.
|
/// Used to signal that the background thread should terminate.
|
||||||
@@ -316,35 +225,31 @@ struct SharedData {
|
|||||||
|
|
||||||
/// The background half of the fd monitor, running on its own thread.
|
/// The background half of the fd monitor, running on its own thread.
|
||||||
struct BackgroundFdMonitor {
|
struct BackgroundFdMonitor {
|
||||||
/// The list of items to monitor. This is only accessed from the background thread.
|
|
||||||
/// This doesn't need to be in any particular order.
|
|
||||||
items: Vec<FdMonitorItem>,
|
|
||||||
/// Our self-signaller. When this is written to, it means there are new items pending, new items
|
/// Our self-signaller. When this is written to, it means there are new items pending, new items
|
||||||
/// in the poke list, or terminate has been set.
|
/// in the poke list, or terminate has been set.
|
||||||
change_signaller: Weak<FdEventSignaller>,
|
change_signaller: Arc<FdEventSignaller>,
|
||||||
/// The data shared between the background thread and the `FdMonitor` instance.
|
/// The data shared between the background thread and the `FdMonitor` instance.
|
||||||
|
/// Note the locking here is very coarse and the lock is held while servicing items.
|
||||||
|
/// This means that an item which reads a lot of data may prevent adding other items.
|
||||||
|
/// When we do true multithreaded execution, we may want to make the locking more fine-grained (per-item).
|
||||||
data: Arc<Mutex<SharedData>>,
|
data: Arc<Mutex<SharedData>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FdMonitor {
|
impl FdMonitor {
|
||||||
/// Add an item to the monitor. Returns the [`FdMonitorItemId`] assigned to the item.
|
/// Add an item to the monitor. Returns the [`FdMonitorItemId`] assigned to the item.
|
||||||
pub fn add(&self, mut item: FdMonitorItem) -> FdMonitorItemId {
|
pub fn add(&self, fd: AutoCloseFd, callback: Callback) -> FdMonitorItemId {
|
||||||
assert!(item.fd.is_valid());
|
assert!(fd.is_valid());
|
||||||
assert!(item.timeout != Some(Duration::ZERO), "Invalid timeout!");
|
|
||||||
assert!(
|
|
||||||
item.item_id == FdMonitorItemId(0),
|
|
||||||
"Item should not already have an id!"
|
|
||||||
);
|
|
||||||
|
|
||||||
let item_id = self.last_id.fetch_add(1, Ordering::Relaxed) + 1;
|
let item_id = self.last_id.fetch_add(1, Ordering::Relaxed) + 1;
|
||||||
let item_id = FdMonitorItemId(item_id);
|
let item_id = FdMonitorItemId(item_id);
|
||||||
|
let item: FdMonitorItem = FdMonitorItem { fd, callback };
|
||||||
let start_thread = {
|
let start_thread = {
|
||||||
// Lock around a local region
|
// Lock around a local region
|
||||||
let mut data = self.data.lock().expect("Mutex poisoned!");
|
let mut data = self.data.lock().expect("Mutex poisoned!");
|
||||||
|
|
||||||
// Assign an id and add the item to pending
|
// Assign an id and add the item.
|
||||||
item.item_id = item_id;
|
let old_value = data.items.insert(item_id, item);
|
||||||
data.pending.push(item);
|
assert!(old_value.is_none(), "Item ID {} already exists!", item_id.0);
|
||||||
|
|
||||||
// Start the thread if it hasn't already been started
|
// Start the thread if it hasn't already been started
|
||||||
let already_started = data.running;
|
let already_started = data.running;
|
||||||
@@ -356,8 +261,7 @@ pub fn add(&self, mut item: FdMonitorItem) -> FdMonitorItemId {
|
|||||||
FLOG!(fd_monitor, "Thread starting");
|
FLOG!(fd_monitor, "Thread starting");
|
||||||
let background_monitor = BackgroundFdMonitor {
|
let background_monitor = BackgroundFdMonitor {
|
||||||
data: Arc::clone(&self.data),
|
data: Arc::clone(&self.data),
|
||||||
change_signaller: Arc::downgrade(&self.change_signaller),
|
change_signaller: Arc::clone(&self.change_signaller),
|
||||||
items: Vec::new(),
|
|
||||||
};
|
};
|
||||||
crate::threads::spawn(move || {
|
crate::threads::spawn(move || {
|
||||||
background_monitor.run();
|
background_monitor.run();
|
||||||
@@ -370,29 +274,24 @@ pub fn add(&self, mut item: FdMonitorItem) -> FdMonitorItemId {
|
|||||||
item_id
|
item_id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mark that the item with the given ID needs to be woken up explicitly.
|
/// Remove an item from the monitor and return its file descriptor.
|
||||||
pub fn poke_item(&self, item_id: FdMonitorItemId) {
|
/// Note we may remove an item whose fd is currently being waited on in select(); this is
|
||||||
|
/// considered benign because the underlying item will no longer be present and so its
|
||||||
|
/// callback will not be invoked.
|
||||||
|
pub fn remove_item(&self, item_id: FdMonitorItemId) -> AutoCloseFd {
|
||||||
assert!(item_id.0 > 0, "Invalid item id!");
|
assert!(item_id.0 > 0, "Invalid item id!");
|
||||||
let needs_notification = {
|
|
||||||
let mut data = self.data.lock().expect("Mutex poisoned!");
|
let mut data = self.data.lock().expect("Mutex poisoned!");
|
||||||
let needs_notification = data.pokelist.is_empty();
|
let removed = data.items.remove(&item_id).expect("Item ID not found");
|
||||||
// Insert it, sorted. But not if it already exists.
|
drop(data);
|
||||||
if let Err(pos) = data.pokelist.binary_search(&item_id) {
|
// Allow it to recompute the wait set.
|
||||||
data.pokelist.insert(pos, item_id);
|
|
||||||
};
|
|
||||||
needs_notification
|
|
||||||
};
|
|
||||||
|
|
||||||
if needs_notification {
|
|
||||||
self.change_signaller.post();
|
self.change_signaller.post();
|
||||||
}
|
removed.fd
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
data: Arc::new(Mutex::new(SharedData {
|
data: Arc::new(Mutex::new(SharedData {
|
||||||
pending: Vec::new(),
|
items: HashMap::new(),
|
||||||
pokelist: Vec::new(),
|
|
||||||
running: false,
|
running: false,
|
||||||
terminate: false,
|
terminate: false,
|
||||||
})),
|
})),
|
||||||
@@ -405,110 +304,121 @@ pub fn new() -> Self {
|
|||||||
impl BackgroundFdMonitor {
|
impl BackgroundFdMonitor {
|
||||||
/// Starts monitoring the fd set and listening for new fds to add to the set. Takes ownership
|
/// Starts monitoring the fd set and listening for new fds to add to the set. Takes ownership
|
||||||
/// over its instance so that this method cannot be called again.
|
/// over its instance so that this method cannot be called again.
|
||||||
fn run(mut self) {
|
fn run(self) {
|
||||||
assert_is_background_thread();
|
assert_is_background_thread();
|
||||||
|
|
||||||
let mut pokelist: Vec<FdMonitorItemId> = Vec::new();
|
|
||||||
let mut fds = FdReadableSet::new();
|
let mut fds = FdReadableSet::new();
|
||||||
|
let mut item_ids: Vec<FdMonitorItemId> = Vec::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Poke any items that need it
|
// Our general flow is that a client thread adds an item for us to monitor,
|
||||||
if !pokelist.is_empty() {
|
// and we use select() or poll() to wait on it. However, the client thread
|
||||||
self.poke(&pokelist);
|
// may then reclaim the item. We are currently blocked in select():
|
||||||
pokelist.clear();
|
// how then do we stop waiting on it?
|
||||||
}
|
//
|
||||||
fds.clear();
|
// The safest, slowest approach is:
|
||||||
|
// - The background thread waits on select() for the set of active file descriptors.
|
||||||
|
// - The client thread records a request to remove an item.
|
||||||
|
// - The client thread wakes up the background thread via change_signaller.
|
||||||
|
// - The background thread check for any pending removals, and removes and returns them.
|
||||||
|
// - The client thread accepts the removed item and continues on.
|
||||||
|
// However this means a round-trip from the client thread to this background thread,
|
||||||
|
// plus additional blocking system calls. This slows down the client thread.
|
||||||
|
//
|
||||||
|
// A second possibility is that:
|
||||||
|
// - The background thread waits on select() for the set of active file descriptors.
|
||||||
|
// - The client thread directly removes an item (protected by the mutex).
|
||||||
|
// - After select() returns the set of active file descriptors, we only invoke callbacks
|
||||||
|
// for items whose file descriptors are still in the set.
|
||||||
|
// However this risks the ABA problem: if the client thread reclaims an item, closes its
|
||||||
|
// fd, and then adds a new item which happens to get the same fd, we might falsely
|
||||||
|
// trigger the callback of the new item even though its fd is not readable.
|
||||||
|
//
|
||||||
|
// So we use the following approach:
|
||||||
|
// - The background thread creates a snapshotted list of active ItemIDs.
|
||||||
|
// - The background thread waits in select() on the set of active file descriptors,
|
||||||
|
// without holding the lock.
|
||||||
|
// - The client thread directly removes an item (protected by the mutex).
|
||||||
|
// - After select() returns the set of active file descriptors, we only invoke callbacks
|
||||||
|
// for items whose file descriptors are marked active, and whose ItemID was snapshotted.
|
||||||
|
//
|
||||||
|
// This avoids the ABA problem because ItemIDs are never recycled. It does have a race where
|
||||||
|
// we might select() on a file descriptor that has been closed or recycled. Thus we must be
|
||||||
|
// prepared to handle EBADF. This race is otherwise considered benign.
|
||||||
|
|
||||||
// Our change_signaller is special-cased
|
// Construct the set of fds to monitor.
|
||||||
let change_signal_fd = self.change_signaller.upgrade().unwrap().read_fd();
|
// Our change_signaller is special-cased.
|
||||||
|
fds.clear();
|
||||||
|
let change_signal_fd = self.change_signaller.read_fd();
|
||||||
fds.add(change_signal_fd);
|
fds.add(change_signal_fd);
|
||||||
|
|
||||||
let mut now = Instant::now();
|
// Grab the lock and snapshot the item_ids. Skip items with invalid fds.
|
||||||
// Use Duration::MAX to represent no timeout for comparison purposes.
|
let mut data = self.data.lock().expect("Mutex poisoned!");
|
||||||
let mut timeout = Duration::MAX;
|
item_ids.clear();
|
||||||
|
item_ids.reserve(data.items.len());
|
||||||
|
for (item_id, item) in &data.items {
|
||||||
|
let fd = item.fd.as_raw_fd();
|
||||||
|
if fd >= 0 {
|
||||||
|
fds.add(fd);
|
||||||
|
item_ids.push(*item_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for item in &mut self.items {
|
// Sort it to avoid the non-determinism of the hash table.
|
||||||
fds.add(item.fd.as_raw_fd());
|
item_ids.sort_unstable();
|
||||||
if item.last_time.is_none() {
|
|
||||||
item.last_time = Some(now);
|
|
||||||
}
|
|
||||||
timeout = timeout.min(item.timeout.unwrap_or(Duration::MAX));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have no items, then we wish to allow the thread to exit, but after a time, so
|
// If we have no items, then we wish to allow the thread to exit, but after a time, so
|
||||||
// we aren't spinning up and tearing down the thread repeatedly. Set a timeout of 256
|
// we aren't spinning up and tearing down the thread repeatedly. Set a timeout of 256
|
||||||
// msec; if nothing becomes readable by then we will exit. We refer to this as the
|
// msec; if nothing becomes readable by then we will exit. We refer to this as the
|
||||||
// wait-lap.
|
// wait-lap.
|
||||||
let is_wait_lap = self.items.is_empty();
|
let is_wait_lap = item_ids.is_empty();
|
||||||
if is_wait_lap {
|
let timeout = if is_wait_lap {
|
||||||
assert!(
|
Some(Duration::from_millis(256))
|
||||||
timeout == Duration::MAX,
|
} else {
|
||||||
"Should not have a timeout on wait lap!"
|
None
|
||||||
);
|
|
||||||
timeout = Duration::from_millis(256);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't leave Duration::MAX as an actual timeout value
|
|
||||||
let timeout = match timeout {
|
|
||||||
Duration::MAX => None,
|
|
||||||
timeout => Some(timeout),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Call select()
|
// Call select().
|
||||||
|
// We must release and then re-acquire the lock around select() to avoid deadlock.
|
||||||
|
// Note that while we are waiting in select(), the client thread may add or remove items;
|
||||||
|
// in particular it may even close file descriptors that we are waiting on. That is why
|
||||||
|
// we handle EBADF. Note that even if the file descriptor is recycled, we don't invoke
|
||||||
|
// a callback for it unless its ItemID is still present.
|
||||||
|
drop(data);
|
||||||
let ret = fds.check_readable(
|
let ret = fds.check_readable(
|
||||||
timeout
|
timeout
|
||||||
.map(|duration| duration.as_micros() as u64)
|
.map(|d| Timeout::Duration(d))
|
||||||
.unwrap_or(FdReadableSet::kNoTimeout),
|
.unwrap_or(Timeout::Forever),
|
||||||
);
|
);
|
||||||
if ret < 0 && errno::errno().0 != libc::EINTR {
|
if ret < 0 && !matches!(errno().0, libc::EINTR | libc::EBADF) {
|
||||||
// Surprising error
|
// Surprising error
|
||||||
perror("select");
|
perror("select");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the value of `now` after waiting on `fds.check_readable()`; it's used in the
|
// Re-acquire the lock.
|
||||||
// servicer closure.
|
data = self.data.lock().expect("Mutex poisoned!");
|
||||||
now = Instant::now();
|
|
||||||
|
|
||||||
// A predicate which services each item in turn, returning true if it should be removed
|
// For each item id that we snapshotted, if the corresponding item is still in our
|
||||||
let servicer = |item: &mut FdMonitorItem| {
|
// set of active items and its fd was readable, then service it.
|
||||||
let fd = item.fd.as_raw_fd();
|
for item_id in &item_ids {
|
||||||
let action = item.service_item(&fds, &now);
|
let Some(item) = data.items.get_mut(item_id) else {
|
||||||
if action == ItemAction::Remove {
|
// Item was removed while we were waiting.
|
||||||
FLOG!(fd_monitor, "Removing fd", fd);
|
// Note there is no risk of an ABA problem because ItemIDs are never recycled.
|
||||||
}
|
continue;
|
||||||
action
|
|
||||||
};
|
};
|
||||||
|
if fds.test(item.fd.as_raw_fd()) {
|
||||||
// Service all items that are either readable or have timed out, and remove any which
|
item.service();
|
||||||
// say to do so.
|
}
|
||||||
|
}
|
||||||
self.items
|
|
||||||
.retain_mut(|item| servicer(item) == ItemAction::Retain);
|
|
||||||
|
|
||||||
// Handle any changes if the change signaller was set. Alternatively, this may be the
|
// Handle any changes if the change signaller was set. Alternatively, this may be the
|
||||||
// wait lap, in which case we might want to commit to exiting.
|
// wait lap, in which case we might want to commit to exiting.
|
||||||
let change_signalled = fds.test(change_signal_fd);
|
let change_signalled = fds.test(change_signal_fd);
|
||||||
if change_signalled || is_wait_lap {
|
if change_signalled || is_wait_lap {
|
||||||
// Clear the change signaller before processing incoming changes
|
// Clear the change signaller before processing incoming changes
|
||||||
self.change_signaller.upgrade().unwrap().try_consume();
|
self.change_signaller.try_consume();
|
||||||
let mut data = self.data.lock().expect("Mutex poisoned!");
|
|
||||||
|
|
||||||
// Move from `pending` to the end of `items`
|
if data.terminate || (is_wait_lap && data.items.is_empty() && !change_signalled) {
|
||||||
self.items.extend(&mut data.pending.drain(..));
|
|
||||||
|
|
||||||
// Grab any poke list
|
|
||||||
assert!(
|
|
||||||
pokelist.is_empty(),
|
|
||||||
"poke list should be empty or else we're dropping pokes!"
|
|
||||||
);
|
|
||||||
std::mem::swap(&mut pokelist, &mut data.pokelist);
|
|
||||||
|
|
||||||
if data.terminate
|
|
||||||
|| (is_wait_lap
|
|
||||||
&& self.items.is_empty()
|
|
||||||
&& pokelist.is_empty()
|
|
||||||
&& !change_signalled)
|
|
||||||
{
|
|
||||||
// Maybe terminate is set. Alternatively, maybe we had no items, waited a bit,
|
// Maybe terminate is set. Alternatively, maybe we had no items, waited a bit,
|
||||||
// and still have no items. It's important to do this while holding the lock,
|
// and still have no items. It's important to do this while holding the lock,
|
||||||
// otherwise we race with new items being added.
|
// otherwise we race with new items being added.
|
||||||
@@ -523,27 +433,12 @@ fn run(mut self) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Poke items in the poke list, removing any items that close their fd in their callback. The
|
|
||||||
/// poke list is consumed after this. This is only called from the background thread.
|
|
||||||
fn poke(&mut self, pokelist: &[FdMonitorItemId]) {
|
|
||||||
self.items.retain_mut(|item| {
|
|
||||||
let action = item.maybe_poke_item(pokelist);
|
|
||||||
if action == ItemAction::Remove {
|
|
||||||
FLOG!(fd_monitor, "Removing fd", item.fd.as_raw_fd());
|
|
||||||
}
|
|
||||||
return action == ItemAction::Retain;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// In ordinary usage, we never invoke the destructor. This is used in the tests to not leave stale
|
/// In ordinary usage, we never invoke the destructor. This is used in the tests to not leave stale
|
||||||
/// fds arounds; this is why it's very hacky!
|
/// fds arounds; this is why it's very hacky!
|
||||||
impl Drop for FdMonitor {
|
impl Drop for FdMonitor {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// Safety: this is a port of the C++ code and we are running in the destructor. The C++ code
|
|
||||||
// had no way to bubble back any errors encountered here, and the pthread mutex the C++ code
|
|
||||||
// uses does not have a concept of mutex poisoning.
|
|
||||||
self.data.lock().expect("Mutex poisoned!").terminate = true;
|
self.data.lock().expect("Mutex poisoned!").terminate = true;
|
||||||
self.change_signaller.post();
|
self.change_signaller.post();
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user