I sometimes want to run this script in multiple docker containers concurrently,
and possibly modify it while another instance is already running. The behavior
after modification is unpredictable; let's change it to read the whole script
up-front (like Python/fish do).
My
$ sudo docker/docker_run_tests.sh --shell-after docker/jammy-asan.Dockerfile
shows a lot of complaints about
Direct leak of 60 byte(s) in 1 object(s) allocated from:
because some unit tests call reader_init() and reader_deinit(). Work around
this by initializing this value only once. AFAICT, OnceCell is async-signal
safe (unlike Mutex), although I don't think documentation promises that.
It doesn't feel great to change implementation code to accomodate tests but
I think for this specific issue that's what we usually do. Alternatively,
we could add to lsan_suppressions.txt.
If cargo ever wants to write to "target/man", it would collide with our
use of this path. Let's make this less likely by prefixing the name with
"fish-". This also makes it more obvious that this is fish's invention.
(Note: this commit should technically have preceded the "Fix config paths
for disjoint build-dirs and in-tree installs" one, to make that one easier
to follow, but I wasn't 100% sure if this commit is right.)
From https://doc.rust-lang.org/cargo/reference/environment-variables.html
> OUT_DIR — If the package has a build script, this is set to the folder
> where the build script should place its output. See below for more
> information. (Only set during compilation.)
so OUT_DIR is something like "target/debug/build/fish-41da27d587f48978".
Whenever build.rs is re-run, we get a new one.
I don't think we need this flexibility anywhere. It wouldn't protect
concurrent "cargo test" from interfering with each other - that's handled
by a file lock taken by Cargo.
Use "target/" instead (or CMAKE_BINARY_DIR if set).
Namespace the files better, so we don't create weird paths like
target/test/complete_test/...
target/fish_root/
With the upcoming tests/checks/gettext.fish test from #11583, my
sudo docker/docker_run_tests.sh --shell-after docker/focal.Dockerfile
fails writing to "po/template.po" because "/fish-source" is mounted as
read-only. (There should be no need for tests to write to the source tree.)
Since commit 6239cba1e4 (Add dry-run mode to update_translations.fish,
2025-05-30), "build_tools/update_translations.fish" always removes that
template file when done, even without "--dry-run".
I'm not sure if we still have a need for keeping around "po/template.po".
To add a new translation, you can run "build_tools/update_translations
po/xy.po". It could serve as a cache but that would only work if we integrated
it into a build system.
Move it to /tmp, fixing the docker tests.
Use test_driver directly instead of CMake in the docker tests.
Deal with the read-only "/fish-source" by exporting
"CARGO_TARGET_DIR=$HOME/fish-build". It seems correct to also inject this
environment variable into the interactive debugging shells. Add some logging
to make this override more obvious to the user.
Adopt "build_tools/check.sh", because that defines the full set of checks
that we (eventually) want to run in CI.
In particular, this will also run "tests/checks/po-files-up-to-date.fish"
which "cargo b && cargo t && tests/test_driver.py" does not, due to the
REQUIRES clause.
Since most docker images have some lints/warnings today, disable those for
now. Use "docker_run_tests.sh --lint" to override. The default may be changed
in future.
Commit 89282fd9bc (Use CARGO_MANIFEST_DIR to see if we're running from
build dir, 2024-01-20) did
-if exec_path.starts_with(OUT_DIR)
+if exec_path.starts_with(CARGO_MANIFEST_DIR)
where OUT_DIR is the cmake build directory ("./build")
and CARGO_MANIFEST_DIR is our top level source tree.
This allowed "target/debug/fish" to work, but it broke
1. CMake build directories outside the source tree, e.g. "docker/docker_run_tests.sh".
Those incorrectly fall back to the compiled-in-path (/usr/local/share etc)
2. Installations iside the source tree, e.g.
"mkdir build && cd build && cmake .. -DCMAKE_INSTALL_PREFIX=$PWD/../install".
These installations incorrectly use "share/" etc. from the source tree.
Fix this by
1. respecting the CMake-specific FISH_BUILD_DIR, ad
2. if that's not set, use $CARGO_MANIFEST_DIR/target
We have a mixture of 2 and 4 space indent.
4 benchmarks/driver.sh
2 build_tools/check.sh
4 build_tools/git_version_gen.sh
4 build_tools/mac_notarize.sh
2 build_tools/make_pkg.sh
2 build_tools/make_tarball.sh
2 build_tools/make_vendor_tarball.sh
4 docker/docker_run_tests.sh
4 osx/install.sh
2 tests/test_functions/sphinx-shared.sh
Our editorconfig file specifies 2, with no explicit reason.
Our fish and Python scripts use 4, so let's use that.
Commit 5c0fddae70 (Refactor history flushing, 2025-03-28) made three changes:
1. call fsync() when we are finished writing the history file.
2. when appending to (as opposed to vacuuming) history, call write(2)
(followed by flush() and sync()) for each item. Previously, we'd only
call write(2) if our 64k buffer was full, or after processing the last
history item.
3. actually check the return value of flush() (which would retry when flushing
fails -- but std::fs::File::flush() never fails!).
The motivation was to potentially fix#10300 which didn't succeed (see
https://github.com/fish-shell/fish-shell/issues/10300#issuecomment-2876718382).
As for 1 and 2, I don't think the way we use fsync really helps, and flushing
eagerly should not make a difference.
As for 3, there are some explanations in comments, commit message and a [PR
comment](https://github.com/fish-shell/fish-shell/pull/11330#discussion_r2020171339).
To summarize, 5c0fddae70 wants to address the scenario where file.flush()
fails. Prior to that commit we would ostensibly carry on with a corrupted
"first_unwritten_new_item_index" (corrupted because it doesn't match what's
written to disk), which can cause various issues. However this doesn't
ever happen because std::fs::File::flush() never fails because it doesn't
do anything -- std::fs::File::write() does not buffer writes, it always
delegates to write(2).
There can definitely be scenarios like the one described in
https://github.com/fish-shell/fish-shell/pull/11330#discussion_r2020171339
where the disk is full. In that case, either write(2) fails, which we
already check. Or close(3p) fails with EIO, which we have never checked. We
should probably check that.
Undo all three changes for now.
Closes#11495
Remove dependency on CTest. Parallel execution is handled by `test_driver.py`
internally now, so CTest is no longer relevant for performance.
This also removes CMake targets for single tests. As a replacement,
`test_driver.py` can be called directly with the path to the build directory as
the first argument and the path to the desired test as the second argument.
Ensuring that the executables in the build directory are up to date needs to be
done separately.
For a pure cargo build, an example of running a single test would be:
`cargo b && tests/test_driver.py target/debug tests/checks/abbr.fish`
The recommended way of running tests is `build_tools/check.sh`, which runs more
extensive tests and does not depend on CMake. That script does not work in CI
yet, so CMake testing is retained for now.
Update CI config to use the new `FISH_TEST_MAX_CONCURRENCY`.
Also update the FreeBSD version, since the previous one is outdated and does not
support the semaphore logic in `test_driver.py`.
`mmap` should fail when the length argument is 0. Checking this in advance
allows returning early, without performing unnecessary syscalls.
This also fixes an issue observed on FreeBSD 13.2 where `mmap` does not always
fail when the length is 0, resulting in the `assert!(len > 0)` in
`MmapRegion::new` failing.
https://github.com/fish-shell/fish-shell/issues/11595
Commit cd3da62d24 (fix(completion): unescape strings for __fish_complete_list,
2024-09-17) bravely addressed an issue that exists in a lot of completions.
It did so only for __fish_complete_list. Fair enough.
Unfortunately it unescaped more than just "$(commandline -t)".
This causes the problem described at
https://github.com/fish-shell/fish-shell/issues/11508#issuecomment-2889088934
where completion descriptions containing a backslash followed by "n" are
interpreted as newlines, breaking the completion parser. Fix that.
Given a command line like
foo --foo=bar=baz=qux\=argument
(the behavior is the same if '=' is substituted with ':').
fish completes arguments starting from the last unescaped separator, i.e.
foo --foo=bar=baz=qux\=argument
^
__fish_complete_list provides completions like
printf %s\n (commandline -t)(printf %s\n choice1 choice2 ...)
This means that completions include the "--foo=bar=baz=" prefix.
This is wrong. This wasn't a problem until commit f9febba (Fix replacing
completions with a -foo prefix, 2024-12-14), because prior to that, replacing
completions would replace the entire token.
This made it too hard to writ ecompletions like
complete -c foo -s s -l long -xa "hello-world goodbye-friend"
that would work with "foo --long fri" as well as "foo --long=frie".
Replacing the entire token would only work if the completion included that
prefix, but the above command is supposed to just work.
So f9febba made us replace only the part after the separator.
Unfortunately that caused the earlier problem. Work around this. The change
is not pretty, but it's a compromise until we have a better way of telling
which character fish considers to be the separator.
Fixes#11508
The main purpose of this is avoiding timeouts in CI.
Passing `--max-concurrency=n` to `test_driver.py` will result in at most `n`
tests running concurrently, where `n` is a positive integer.
Not specifying the argument preserves the old behavior of running all tests
concurrently without a limit.
This was missed in the Rust port - C++ had statfs for MNT_LOCAL and not statvfs.
The effect of this is that fish never thought its filesystem was local on macOS
or BSDs (Linux was OK). This caused history race tests to fail, and also could
in rare cases result in history items being dropped with multiple concurrent
sessions.
This fixes the history race tests under macOS and FreeBSD - we weren't locking
because we thought the history was a remote file.
Within a linked worktree, `$GIT_DIR` and `$GIT_COMMON_DIR` have different
values (see [git-worktree docs](https://git-scm.com/docs/git-worktree#_details)).
The two serve different purposes, in case of stashes `$GIT_COMMON_DIR`
should be used, this way stash detection in the git prompt works also
when inside a `git worktree`.
Closes#11591
Systems like NixOS might not have "git-receive-pack" or any other "git-*"
executable in in $PATH -- instead they patch git to use absolute paths.
This is weird. But no reason for us to fail. Silence the error.
Fixes#11590
Eliminates some code duplication between the two different saving
implementations. These changes are based on
https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2149438316.
One extra change is included here, namely the early return on an empty file
name, indicating private mode. Without this, `history_path.unwrap()` fails in
some tests. Returning early is probably what we want in such situations anyway.
The cached information might become outdated. It is important that all fish
processes use the same mutual exclusion logic (either `flock`-based or the
fallback), because the two methods do not provide mutual exclusion from one
another.
Avoiding caching makes the behavior independent on previous system states,
resulting in fish instances performing file operations at the same time to use
the same locking logic.
More detailed discussion in
https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2134543447
If arguments always have the same value they do not need to be arguments.
For `HistoryImpl::add`, the comments are incorrect (assuming they should
indicate the value of the argument), since both arguments can be true or false
independently.
`History::add` is only called at one location in a test with a constant value of
`false` for `pending`. This might mean that the parameter could be deleted, or
maybe even the entire function, if testing can work without it.
Both history files and universal variables files are accessed by multiple
processes, which need a way to synchronize their accesses.
This synchronization logic is mixed in with the logic for reading and updating
the files' contents, which results in messy code, duplicated locking
implementations, and inconsistencies.
Moreover, the existing implementations are flawed which has resulted in file
corruption (e.g. https://github.com/fish-shell/fish-shell/issues/10300).
The new approach separates the synchronization logic from the rest.
There are two approaches to synchronization.
- The primary one is using `flock(2)` to lock the directory containing the file
which requires synchronized access. We do not lock the file holding the data
directly because this file might be replaced, which can result in locking
succeeding when it should block. Locking the directory solves this problem.
To avoid inconsistent file states, changes are first written to a temporary
file, which is then renamed into place while still holding the lock.
- In some situations `flock` locks are unavailable or take a long time. This
mostly applies to remote file systems. If we think that a directory is located
on a remote file system, we do not attempt to use `flock`.
As a fallback, we have a lockless approach, which uses file metadata (device,
inode, size, ctime, mtime) to identify file versions.
We then read from the file, write the updated data to a temporary file,
check if the file id for the path is the same as before we started reading,
and if so we rename the temporary file such that it replaces the old file.
Note that races are possible between the file id check and the rename syscall.
If we detect a file id mismatch, we retry, up to a predetermined number of
attempts.
The operations which should be performed are passed to the functions handling
synchronization as `Fn`s. Because we might have to run these operations
repeatedly when retrying, they should be executable arbitrarily often without
causing side-effects relevant to the program. This requires some changes to
functions accessing these files. In many cases, they have to work with
non-mutable references, which requires that they return the data which should be
updated in the program state, instead of directly assigning to the appropriate
location.
Locking via `O_EXLOCK`, which was used for the universal variable file, is no
longer supported. That version of locking locks the file operated on directly,
instead of its directory. According to the man pages of {Open,Free,Net}BSD
and macOS, these locks have flock semantics. So if flock is available, we can
use it, and if it is not, the `O_EXLOCK` flag does not help.
This is preparatory work for refactoring the file synchronization approach.
`read_exact` will fail if the file length does not match the expected one, which
means zero padding is useless. (On any reasonable OS it was also useless before,
because anonymous memory mapping would be zero-pages.)
Use `std::io::Result` instead of `Option` as the return type where appropriate,
to allow for better-informed error handling.
Remove explicit checks about the length to be mapped being 0.
From `mmap(3)`:
> If len is zero, mmap() shall fail and no mapping shall be established.
This allows for more informative error handling.
In some cases, the `?` operator can now be applied sensibly instead of more
verbose local error handling.
There is no need for separate implementations for history and uvar file
handling. Having a shared implementation ensures that creating temporary files
is handled consistently and removes clutter from the source files which want to
create temporary files.
This is another step towards making the `load_from_file` function callable
without modifying internal data of `self`. Instead, the required updates for
a successful load should be returned.
For now, `self.last_read_file_id` is still modified
within `load_from_file`, which means it still needs a mutable reference to
`self`.
This is done as a step towards enabling loading from the variables file without
affecting internal variables, such that retrying becomes possible without
issues.
Callbacks are generated by
`src/env_universal_common.rs:generate_callbacks_and_update_exports`.
This function only pushes to the `Vec`, so the content of the `Vec` passed to it
does not matter within this function.
The generated callbacks are used in `src/env/environment.rs:universal_sync`,
which calls `generate_callbacks_and_update_exports` via
`EnvUniversal::sync`,
(optionally `EnvUniversal::load_from_path_narrow`),
`EnvUniversal::load_from_file`.
The only other code making use of these callbacks is in tests.
Because the only real use passes an empty `Vec`, there is no need to to pass the
`Vec` as a mutable reference to the function at all. Instead, we create the `Vec`
in `generate_callbacks_and_update_exports` and return it from there, which is
what the new code does.
This change is made because we want loading from a file to be performed without
mutating data which does not come directly from the file.
Then, we can safely retry loading from the file as many times as we want,
without worrying about side-effects on our data structures.
We want to be able to do this in the case where we cannot properly lock the file
and fall back to lockless reading, where we check file metadata before and after
reading to detect modifications, and retry if modifications are detected.
This fallback logic is not in place yet, and further changes are required for
side-effect free loading.
This allows converting non-UTF-8-conforming bytes from their PUA encoding back
to the original bytes before outputting.
Due to the way Rust handles trait implementations, we cannot use
`impl<T: std::fmt::Display> FloggableDisplay for T`
anymore, as that would result in a conflicting implementation for the types
which get a custom implementation.
Instead, explicitly implement the trait for all types which need it.
The changes to enable terminal protocols (CSI-U, etc) also attempts to
re-disable these when fish exits. In particular it attempts to disable these
from a SIGTERM handler.
Unfortunately none of that machinery is async-signal safe. Indeed our SIGTERM
handler has gotten rather sketchy, with taking a mutex and some other stuff.
Remove the async-signal-unsafe stuff and make SIGTERM manifestly safe.
Unfortunately this means that terminal protocols will remain set after SIGTERM
but that's probably unavoidable.
Calls to redirect_tty_output were added in many places when certain tty-syscalls
returned EIO. See commit 396bf1235d
This was intended to work around a glibc bug in wide character output, but it
was never really justifiable or tested, and we no longer use glibc wide
character output.
Bravely remove these, except in the case where we got SIGHUP and we don't want
to trigger SIGTTIN or SIGTTOU.
Definitions of localizable strings should not be guarded by `cfg`, because then
they might not end up being exported, depending on the compilation config.
The PO file updates can now run in a normal test, eliminating the need for
special handling.
Rename the `check-translations.fish` script, to clarify which part of the checks
happens in it.
This is intended to allow translation updates in contexts where building within
the `fish_xgettext.fish` script is undesirable.
Specifically, this allows checking for PO file updates in the tests run by
`test_driver.py`. Because these use a tmpdir for `$HOME`, building within such a
test requires installing the entire Rust toolchain and doing a clean build,
which is a waste of resources.
With this argument, it is possible to build the template before running the
tests and passing the file path into the script.
When including the tests in the build, string literals passed to `wgettext!`
would be included in the gettext template file, which we do not want here,
because the strings should not be localized for this test.
This function does not need to run when the pager is not focused. Calling it
lazily eliminates the overhead of calling it when it is not needed.
This code runs on each keypress when entering a command, so it makes sense to
keep it as lean as possible. (At the very least it avoids spam when trying to
debug/analyze gettext behavior.)
This test is the one with the longest runtime. Splitting the two targets into
separate tests allows them to run in parallel, which can speed up the tests.
This concerns edge cases when executing a function. Historically, when we parse
fish script, we identify early whether or not it's a function; but only record
the function's name and not its properties (i.e. not its source).
This means that the function can change between parsing and execution. Example:
function foo; echo alpha; end
foo (function foo; echo beta; end)
This has historically output "beta" because the function is replaced as part of
its own arguments.
Worse is if the function is deleted:
function foo; echo alpha; end
foo (functions --erase foo)
This outputs an error but in an awkward place; that's OK since it's very rare.
Let's codify this behavior since someone might be depending on it.
Previously, for Processes which were BlockNodes, we stored the node separately
in the Process via an Option; just promote this to a real field of the
ProcessType::BlockNode.
No user visible changes expected.
Our docker tests are currently broken since we no longer seem to install
"build_root". When I sidestep this issue for now and run
sudo docker/docker_run_tests.sh --shell-before docker/focal.Dockerfile
cd /fish-source
CARGO_TARGET_DIR=$HOME/out
tests/test_driver.py ~/out/debug
the test driver fails in various ways.
This is because Ubuntu Focal provides Python 3.8.
Fix some of the typing incompatibilities. Fix a hang in tests like
"tests/checks/init-command.fish"; apparently fish believes it's interactive
because Python 3.8's create_subprocess_shell() makes the fish child believe
that stdin is a TTY, so it's implicitly interactive.
Our docker/docker_run_tests.sh script runs tests in a container with the fish
source tree mounted as read-only. We have a hack to speed up repeated runs
of the check-all-fish-files test that assumes the source tree is writable.
Paper over this by silencing the error for now.
There were no remaining checks left to match stderr:1:
touch: cannot touch '/fish-source/tests/.last-check-all-files': Read-only file system
Commit bf65b9e3a7 (Change `gettext` paths to be relocatable (#11195),
2025-03-30) is difficult to follow because it combines code movement with
two behavior changes. Our parent commit fixed the first behavior change.
The second behavior change made us tolerate trailing NUL bytes in LOCALEDIR.
This was motivated because conda wants to use binary patching to change
the effective prefix at runtime, presumably so the user can move around the
"fish" executable program arbitraily.
This turned out to be unnecessary because fish is already "relocatable"
(see our parent commit).
Let's remove the special case for LOCALEDIR. Treat it like other paths.
Closes#11574Closes#11474
Fish uses this logic to find paths to functions etc.:
1. if $(status fish-path) starts with $CARGO_MANIFEST_DIR,
we use $CARGO_MANIFEST_DIR/share etc.
Aside: this also has the unintended effect that "cmake
-DCMAKE_INSTALL_PREFIX=$PWD/prefix" will not use "$PWD/prefix/share" but
"$PWD/share", at least since eacbd6156d (Port and adopt main written in
Rust, 2023-08-18).
2. Else if $(status fish-path) ends with "bin/fish",
and $(status fish-path)/../share/fish exists, we use that, since 4912967eab
(Large set of changes related to making fish relocatable, and improving
the build and install story, 2012-07-08)
3. Else if $(status fish-path) ends in "fish" (which is very likely),
and $(status fish-path)/share exists, we use that, since
c2a8de4873 (Make fish find config directories in source tree, 2016-09-23).
I think this is for running (without installing) in-tree builds ("cmake .");
this is not recommended but it is used, see
https://github.com/fish-shell/fish-shell/pull/10330
4. If none of the above worked, either because the fish binary has been
moved into a weird directory, or if we fail to get $(status fish-path)
(e.g. on OpenBSD, where "argv[0]" is not available),
then we fall back to reasonable default paths determined at compiled
time.
These paths include data_dir=$PREFIX/share.
We recently added locale_dir too in bf65b9e3a7 (Change `gettext` paths
to be relocatable (#11195), 2025-03-30).
In case 1, we use locale: manifest_dir.join("share/locale"),
In case 2 and 3, we use locale: data_dir.join("locale"),
In case 4, we use locale: data_dir.join("share"),
The last one seems wrong (there is not "/usr/share/share"). Fix that.
Alternatively, we could revert bf65b9e3a7 (and redo the parts we want to keep).
This uses Python's `asyncio` to run tests in parallel, which speeds up test
execution significantly.
The timeout is removed. It would be possible to add a timeout to
`asyncio.as_completed()` if we want that.
This was only used to cache `fish_test_driver`, which can be built in a few tens
of milliseconds on most systems.
This avoids using outdated binaries for testing and simplifies the code and its
usage.
If no `--cachedir` is specifed for `test_driver.py`, it would build
`fish_test_helper` once per test it runs. This is unnecessary. Instead, build it
once in the beginning before running any tests and then use the binary in all
tests.
When the informative status is disabled, the stashstate variable was
set to 1 if the $git_dir/logs/refs/stash file existed and was readable,
even if the file itself was empty (i.e., no stashes). Now the stashstate
variable is set only if the file is NOT empty.
Commit 22c0054c1e (Add check to test all fish files with -n, 2020-02-17)
added a test that runs "fish --no-execute" on all fish files in share/**.fish
Commit 329cd7d429 (Make functions, completions and tests resilient to
running on an embed-data fish, 2025-03-25) change this to run it on **.fish.
Evidently "the tests are exempt because they contain syntax errors" is no
longer true - this is because we have since changed those files to recursively
run 'fish -c "syntax-error"', which makes it easier to test for multiple
syntax-errors in a single test file. Remove the comment.
Globbing everything seems a bit crass, and there's no explicit
motivation.
$ time find -name '*.fish' >/dev/null
Executed in 431.93 millis
$ time find * -name '*.fish' >/dev/null
Executed in 39.98 millis
Let's go back to testing only directories where we currently have Git-tracked
fish files. This makes uncached "check-all-fish-files.fish" go from 26
seconds to 5 seconds.
According to commit 8a07db8e8f (Revert "Revert "Speed up check-all-fish-files
when executed locally"", 2021-03-06), we can assume "find -newer" is supported.
check-all-fish-files takes a long time (>20 seconds here); which is why we
have a (hacky) optimization to avoid checking files we already checked.
This optimization hasn't worked since commit e96b6e157c (Remove TMPDIR
dependency from tests/, 2021-07-30) which started each test invocation in
a private tmpdir. Fix that.
The optimization is useful because this test is, by far, the bottleneck
for parallel test execution (#11561):
$ cargo b && time tests/test_driver.py target/debug
...
checks/tmux-complete.fish PASSED 8465 ms
checks/check-completions.fish PASSED 10948 ms
checks/check-sphinx.fish PASSED 12949 ms
checks/check-all-fish-files.fish PASSED 29828 ms
200 / 200 passed (0 skipped)
________________________________________________________
Executed in 31.00 secs fish external
usr time 81.02 secs 462.00 micros 81.02 secs
sys time 26.41 secs 272.00 micros 26.41 secs
A cache miss for check-all-fish-files.fish takes 24 seconds (though the
grandchild commit will speed this up), a cache hit 0.5 seconds.
Most Git commands take arbitrary revisions. AFAICT, we usually want the same
order, e.g. list local branches before remote branches before commit IDs etc.
I think there is no particular reason why this order is inconsistent between
various subcommands.
Let's extract a function. This standardizes the order and adds various
revision-types that were missing for some subcommands.
This variable is never defined. It was copied from Git's
contrib/completion/git-completion.bash where $match is probably equivalent
to $(commandline -t). I could not measure a significant speedup from passing
this filter to "git for-each-ref", so let's remove it for now.
This is done to prepare for running the tests in parallel.
With this approach the root tmpdir can be created before any test starts, each
test can create its home dir under the root tmpdir,
and when all tests are done the root tmpdir can be deleted.
Deletion of per-test dirs is more difficult in an async context.
This is intended as a way to run all available checks with a single command.
The script can be used locally and in CI. It is intended to replace
`cmake/Tests.cmake` (but this script also runs checks not present there).
At the moment, `ctest` is not used, which could be added to speed up tests.
Address and thread sanitizers are not run by this script.
Add flags to control behavior.
- `--check` to fail if changes would be made by formatters
- `--force` to skip the prompt about uncommitted changes
Fix behavior when `--all` is not specified. It used to operate on `$files`,
which did not get set in that case.
Not all fish files are considered, mainly because some tests might test how fish
behaves on weirdly formatted files.
For Rust files, `cargo fmt` is used when `--all` is specified.
The `--check` flag for `cargo fmt` is used when appropriate.
Do not try to build `fish_indent`. `make fish_indent` does not work anymore. Let
the user handle building and installing/setting `$PATH`.
This is intended to provide information to programmers where localizations might
be coming from, and potentially help with analyzing issues with localizations.
This new wrapper type can be constructed via macros which invoke the
`gettext_extract` proc macro to extract the string literals for PO file
generation.
The type checking enabled by this wrapper should prevent trying to obtain
translations for a string for which none exist.
Because some strings (e.g. for completions) are not defined in Rust, but rather
in fish scripts, the `LocalizableString` type can also be constructed from
non-literals, in which case no extraction happens.
In such cases, it is the programmer's responsibility to only construct the type
for strings which are available for localization.
This approach is a replacement for the `cargo-expand`-based extraction.
When building with the `FISH_GETTEXT_EXTRACTION_FILE` environment variable set,
the `gettext_extract` proc macro will write the messages marked for extraction
to a file in the directory specified by the variable.
Updates to the po files:
- This is the result of running the `update_translations.fish` script using the
new proc_macro extraction. It finds additional messages compared to the
`cargo-expand` based approach.
- Messages IDs corresponding to paths are removed. The do not have localizations
in any language and localizing paths would not make sense. I have not
investigated how they made it into the po files in the first place.
- Some messages are reordered due to `msguniq` sorting differing from `sort`.
Remove docs about installing `cargo-expand`
These are no longer needed due to the switch to our extraction macro.
This is done in preparation for a proc macro which extracts strings which are
passed to `gettext`. Because the `concat!` macro would get expanded after the
proc macro, the proc macro would still see the `concat!`, which it cannot
handle.
This mode is intended for testing if the PO files are up-to-date and
well-formed.
At the moment, we only check translations in CI, where this is not particularly
relevant. Once we no longer need `cargo-expand`
(e.g. via https://github.com/fish-shell/fish-shell/pull/11536)
we can extend the `check_translations.fish` test to run
`update_translations.fish --dry-run` and fail if the exit status is nonzero.
On terminals that do not implement the kitty keyboard protocol "ctrl-ц" on
a Russian keyboard layout generally sends the same byte as "ctrl-w". This
is because historically there was no standard way to encode "ctrl-ц",
and the "ц" letter happens to be in the same position as "w" on the PC-101
keyboard layout.
Users have gotten used to this, probably because many of them are switching
between a Russian (or Greek etc.) and an English layout.
Vim/Emacs allow opting in to this behavior by setting the "input method"
(which probably means "keyboard layout").
Match key events that have the base layout key set against bindings for
that key.
Closes#11520
---
Alternatively, we could add the relevant preset bindings (for "ctrl-ц" etc.)
but
1. this will be wrong if there is a disagreement on the placement of "ц" between two layouts
2. there are a lot of them
3. it won't work for user bindings (for better or worse)
As explained in the parent commit, "alt-+" is usually preferred over
"alt-shift-=" but both have their moments. We communicate this via a comment
saying "# recommended notation". This is not always true and not super helpful,
especially as we add a third variant for #11520 (physical key), which is
the recommended one for users who switch between English and Cyrillic layouts.
Only explain what each variant does. Based on this the user may figure out
which one to use.
As of the parent commit, "ctrl-shift-x" bindings will take precedence over
"ctrl-X". Have fish_key_reader imply this via the ordering The next commit
will make this more explicit.
The new key notation canonicalizes aggressively, e.g. these two bindings
clash:
bind ctrl-shift-a something
bind shift-ctrl-a something else
This means that key events generally match at most one active binding that
uses the new syntax.
The exception -- two coexisting new-syntax binds that match the same key
event -- was added by commit 50a6e486a5 (Allow explicit shift modifier for
non-ASCII letters, fix capslock behavior, 2025-03-30):
bind ctrl-A 'echo A'
bind ctrl-shift-a 'echo shift-a'
The precedence was determined by definition order.
This doesn't seem very useful.
A following patch wants to resolve#11520 by matching "ctrl-ц" events against
"ctrl-w" bindings. It would be surprising if a "ctrl-w" binding shadowed a
"ctrl-ц" one based on something as subtle as definition order. Additionally,
definition order semantics (which is an unintended cause of the implementation)
is not really obvious. Reverse definition order would make more sense.
Remove the ambiguity by always giving precedence to bindings that use
explicit shift.
Unrelated to this, as established in 50a6e486a5, explicit shift is still
recommended for bicameral letters but not typically for others -- e.g. alt-+
is typically preferred over alt-shift-= because the former also works on a
German keyboard.
See #11520
Interactive fish with output redirected ("fish >/dev/null")
is not a common use case but it is valid.
Perhaps surprisingly, "fish >some-file" *does* print terminal escape codes
(colors, cursor movement etc.) even if terminal output is not a TTY.
This is typically harmless, and potentially useful for debugging.
We also send blocking terminal queries but those are not harmless in this case.
Since no terminal will receive the queries, we hang; indefinitely as of today,
but we should give up after a timeout and print an error. Either way that
seems needlessly surprising. Suppress queries in this case.
In future, we should probably do something similar if stdin is not a terminal;
though in that case we're even less likely to be interactive (only "-i"
I think).
When "self.paste_is_buffering()" is true, "parse_escape_sequence()" explicitly
returns "None" instead of "Some(Escape)". This is irrelevant because this
return value is never read, as long as "self.paste_is_buffering()" remains
true until "parse_escape_sequence()" returns, because the caller will return
early in that case. Paste buffering only ends if we actually read a complete
escape sequence (for ending bracketed paste).
Remove this extra branch.
On startup, we block until the terminal responds to our primary device
attribute query.
As an escape hatch, ctrl-c makes us stop waiting.
No keys are discarded; even ctrl-c is still enqueued. Usually this isn't
noticed because typing "echo<ctrl-c>" will insert a "echo" only to immediately
clear it.
The double interpretation of ctrl-c seems odd.
Additionally, the queuing seems unsafe considering that when typing something
like "echo hello<enter><ctrl-c>" the command will be executed.
Clear the queue instead, including ctrl-c.
This matches other programs like gdb, Kakoune and possibly others.
As mentioned in the previous few commits and in #11535, running
"set fish_complete_path ..." and "complete -C 'git ...'" may result in
"share/completions/git.fish" being loaded multiple times.
This is usually fine because fish internally erases all cached completions
whenever fish_complete_path changes.
Unfortunately there is at least global variable that grows each time git.fish
is sourced. This doesn't make a functional difference but it does slow
down completions. Fix that by resetting the variable at load time.
Commit 5918bca1eb (Make "complete -e" prevent completion autoloading,
2024-08-24) has a weird "!removed" check; it was added because "complete
-e" only needs to create the tombstone if we removed nothing. Otherwise the
autoloader will usually take care of not loading the removed completions again.
We should probably get rid of "!removed".. for now add a test to demonstrate
this behavior.
Commit 5918bca1eb (Make "complete -e" prevent completion autoloading,
2024-08-24) makes "complete -e foo" add a tombstone for "foo", meaning we
will never again load completions for "foo".
Due to an oversight, the same tombstone is added when we clear cached
completions after changing "fish_complete_path", preventing completions from
being loaded in that case. Fix this by restoring the old behavior unless
the user actually used "complete -e".
As reported in https://github.com/fish-shell/fish-shell/issues/11535#issuecomment-2915440295,
a command like "complete -C'git '" gets progressively slower every time.
A diff of "fish_trace=1" output shows that each completion invocation added
more stuff to the global "__fish_git_aliases", resulting in output like:
--> for s db
...
--> for s db s db
...
--> for s db s db s db
Reproducer:
$ touch ~/.local/share/fish/generated_completions/foo.fish
$ cargo install --path . --debug
$ ~/.cargo/bin/fish -d autoload -c 'function foo; end; for i in 1 2; complete -C"foo "; end'
We redundantly autoload the embedded file, which, by definition doesn't change.
This happens when
1. the "embed-data" feature is enabled (default for "cargo install")
2. there is a completion file in generated_completions
which triggers a hack to give precedence to "embedded:completions/git.fish"
over "generated_completions/git.fish".
Since we always load all file-based files first, we clobber the autoload cache
("self.autoloaded_files") with the mtime of the generated completion file, even
if we're never gonna return it. This makes the embed-data logic think that
the asset has changed (which is impossible! But of course it is possible that
"fish_complete_path" changes and causes a need to load "embedded:git.fish").
Fix that by treating embedded files more like normal files. This is closer
to historical behavior where $__fish_data_dir/{functions,completions}
are normal directories. Seems like this should fix a false negative in
"has_attempted_autoload" which feels useful.
Add a dead test, I guess. It's not run with feature="embed-data" yet. In
future we should test this in CI.
This documents an invariant established by 532abaddae (Invalidate stale
autosuggestions eagerly, 2024-12-25). It was initially broken but fixed in
ba4ead6ead (Stop saving autosuggestions that we can't restore, 2025-01-17).
When two fish processes rewrite the uvar file concurrent, they rely on the
uvar file's mtime (queried after taking a lock, if locking is supported) to
tell us whether their view of the uvar file is still up-to-date. If it is,
they proceed to move it into place atomically via rename().
Since the observable mtime only updates on every OS clock tick, we call
futimens() manually to force-update that, to make sure that -- unless both
fish conincide on the same *nanosecond* -- other fish will notice that the
file changed.
Unfortunately, commit 77aeb6a2a8 (Port execution, 2023-10-08) accidentally
made us call futimens() only if clock_gettime() failed, instead of when
it succeeded. This means that we need to wait for the next clock tick to
observe a change in mtime.
Any resulting false negatives might have caused us to drop universal variable updates.
Reported in https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2098948362
See #10300
When locking the uvar file, we retry whenever flock() fails with EINTR
(e.g. due to ctrl-c).
But not when locking the history file. This seems wrong; all other libc
functions in the "history_file" code path do retry.
Fix that. In future we should extract a function.
Note that there are other inconsistencies; flock_uvar_file() does not
shy away from remote file systems and does not respect ABANDONED_LOCKING.
This means that empirically probably neither are necessary; let's make things
consistent in future.
See https://github.com/fish-shell/fish-shell/pull/11492#discussion_r2095096200
Might help #10300
clang --version here outputs "clang version 19.1.7"
but it looks like that changed on GHA's Ubuntu runner:
++ clang --version
++ awk 'NR==1 { split($NF, version, "."); print version[1] }'
+ llvm_version='(1ubuntu1)'
which leads to
The CHECK on line 7 wants:
abbr -a -- cuckoo somevalue # imported from a universal variable, see `help abbr`
but there was no remaining output to match.
additional output on stderr:1:111:
=================================================================
==4680==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7bc287a5d402 at pc 0x55e597fa96b6 bp 0x7ffd2bc00700 sp 0x7ffd2bbffea8
READ of size 18 at 0x7bc287a5d402 thread T0
==4680==WARNING: invalid path to external symbolizer!
==4680==WARNING: Failed to use and restart external symbolizer!
Fix that, assuming that "clang --version" always matches the latest symbolizer
that is installed. While at it, leave a "set -x" (which should be the
default for CI), and install llvm explicitly.
WHen "status current-command" is called outside a function it always returns
"fish". An extra newline crept in, fix that.
Fixes 77aeb6a2a8 (Port execution, 2023-10-08).
Fixes#11503
* Remove `strlen_safe` & `null_terminated_array_length` and use the provided method of `OwningNullTerminatedArray`.
* Remove unneeded traits and make `NullTerminatedArray` private.
2719ae4 adds a special cfg for cygwin to avoid annoying warnings. As cygwin target is usually cross-compiled, cfg! is not enough to detect the correct target. This PR uses CARGO_CFG_TARGET_OS env var instead.
There is no reason to have this file clutter the repo root.
Move it into the `po` directory, and give it a more descriptive name.
Inspired by this discussion:
https://github.com/fish-shell/fish-shell/pull/11463#discussion_r2083453275
I use `template.po` instead of `message.po-template` to be more compatible with
automatic filetype detection. (e.g. vim/nvim detect the former as a po file, but
the latter as a conf file)
This allows msgfmt to detect issues with translations of format strings.
The detection used here is very simple. It just checks if a string contains '%',
and if it does, the entry in the po file is preceded by '#, c-format'.
Any entries with this marker are checked by msgfmt in our tests, so if an issue
arises, we will notice before it is merged.
The old version just prints the entire command being profiled as-is.
If such a command consists of more than one line, these lines do not have any
padding, and thus visually interfere with the timings.
This commit adds padding, such that all lines but the first one have padding
prepended, such that the original line content starts at the column in which the
first line starts.
This does not work perfectly for subcommands (in the profiling sense,
where the command starts with (regex) '-+>' instead of just '>').
In such cases, even if the command string is indented in the source, the command
will not start with whitespace. However, subsequent lines are not trimmed, so
the might be indented farther than they should be relative to the first line of
the command.
Another regression from d51f669647 (Vi mode: avoid placing cursor beyond last
character, 2024-02-14) "Unfortunately Vi mode sometimes needs to temporarily
select past end". So do the replace_one mode bindings which were forgotten.
Fix this.
This surfaces a tricky problem: when we use something like
bind '' self-insert some-command
When key event "x" matches this generic binding, we insert both "self-insert"
and "some-command" at the front of the queue, and do *not* consume "x",
since the binding is empty.
Since there is a command (that might call "exit"), we insert a check-exit
event too, after "self-insert some-command" but _before_ "x".
The check-exit event makes "self-insert" do nothing. I don't think there's a
good reason for this; self-insert can only be triggered by a key event that
maps to self-insert; so there must always be a real key available for it to
consume. A "commandline -f self-insert" is a nop. Skip check-exit here.
Fixes#11484
The purpose of this script is to simplify the translation-related workflow for
both developers and translators. It runs the xgettext, msgmerge, msgfmt pipeline
(or only parts of it, depending on the arguments), either for all languages, or
for one specific one.
Developers can use the script with the `--no-mo` flag to update the PO files for
all languages after changes to the Rust/fish sources, to keep the translations
up to date. Ideally, this would run automatically for all changes, such that
translations are always up to date, but for now, it would already be an
improvement to run this script before releasing a new version of fish.
Translators can use the script in the same way as developers, to get up to date
PO files. To see their translations in action, the script can be called with
`--only-mo`, which takes the current version of the PO files and generates MO
files from them, which get placed in a location which fish (built with `cargo
build`) can detect.
Translators might also find it useful to specify the language they want to work
on as a non-option argument. This argument should be the path to the po file
they want to work on. Specifying non-existing files to work on a new language is
allowed, but the files must be in the po directory and follow the naming
convention.
This simplifies the logic a bit and performs a better.
Performance improvements for extract_fish_script_messages (time in
microseconds):
- explicit regex: from 128241 to 83471 (speedup 1.5)
- implicit regex: from 682203 to 463635 (speedup 1.5)
The replaces the `strs` list by a corresponding file, which eliminates the need
for looping over the list.
Use sed to transform strings into gettext po format entries.
Format the file with fish_indent and use more expressive variable name for the
file cargo expand writes to.
Performance improvements (in microseconds):
- sort+format rust strings: from 21750 to 11096 (speedup 2.0)
The fish builtin string functions are significantly slower than grep + sed.
The final replacement of \' to ' also does not make any sense here, because
single quotes appear unescaped in Rust strings.
Performance improvement: from 404880 to 44843 (speedup 9.0)
Profiling details (from separate runs):
Time (μs) Sum (μs) Command
174 404880 > set -a strs (string match -rv 'BUILD_VERSION:|PACKAGE_NAME' <$tmpfile |
string match -rg 'const [A-Z_]*: &str = "(.*)"' | string replace -a "\'" "'")
404706 404706 -> string match -rv 'BUILD_VERSION:|PACKAGE_NAME' <$tmpfile |
string match -rg 'const [A-Z_]*: &str = "(.*)"' | string replace -a "\'" "'"
202 44843 > set -a strs (grep -Ev 'BUILD_VERSION:|PACKAGE_NAME' <$tmpfile |
grep -E 'const [A-Z_]*: &str = "(.*)"' |
sed -E -e 's/^.*const [A-Z_]*: &str = "(.*)".*$/\1/' -e "s_\\\'_'_g")
4952 44641 -> grep -Ev 'BUILD_VERSION:|PACKAGE_NAME' <$tmpfile |
grep -E 'const [A-Z_]*: &str = "(.*)"' |
sed -E -e 's/^.*const [A-Z_]*: &str = "(.*)".*$/\1/' -e "s_\\\'_'_g"
28716 28716 --> command grep --color=auto $argv
10973 10973 --> command grep --color=auto $argv
Using a file is significantly faster.
Profiling overview (times in microseconds):
- cargo expand: from 4959320 to 4503409 (speedup 1.1)
- gettext call pipeline: from 436996 to 13536 (speedup 32.3)
- static string pipeline: from 477429 to 404880 (speedup 1.18)
My phone uses dotted underline to indicate errors; that seems nice, a bit
less aggressive than curly. Unfortunately dotted underlines are not as well
supported in terminal emulators; sometimes they are barely visible. So it's
unlikely that we want to use --underline=dotted for an important theme.
Add double and dashed too I guess, even though I don't have a concrete
use case..
Commit f4503af037 (Make alt-{b,f} move in directory history if commandline is
empty, 2025-01-06) had the intentional side effect of making alt-{left,right}
(move in directory history) work in Terminal.app and Ghostty without other,
less reliable workarounds.
That commit says "that [workaround] alone should not be the reason for
this change."; maybe this was wrong.
Extend the workaround to Vi mode. The intention here is to provide
alt-{left,right} in Vi mode. This also adds alt-{b,f} which is odd but
mostly harmless (?) because those don't do anything else in Vi mode.
It might be confusing when studying "bind" output but that one already has
almost 400 lines for Vi mode.
Closes#11479
For backwards compatibility, fish does not treat "{echo,hello}" as a compound
statement but as brace expansion (effectively "echo hello"). We interpret
"{X...}" as compound statement only if X is whitespace or ';' (which is an
interesting solution).
A brace expansion at the very start of a command
is usually pointless (space separation is shorter).
The exception are cases where the command name and the first few arguments
share a suffix.
$ {,1,2,3,4}echo
1echo 2echo 3echo 4echo
Not sure if anyone uses anything like that. Perhaps we want to trade
compatibility for simplicity. I don't have a strong opinion on this.
Always parse the opening brace as first character of a command token as
compound statement.
Brace expansion can still be used with a trick like: «''{echo,foo}»
Closes#11477
Source locations (file name and line number) where a string originates is not
required by gettext tooling. It can help translators to identify context,
but the value of this is reduced by our lack of context support, meaning that
all occurrences of a string will receive the same translation.
Translators can use `rg` or similar tools to find the source locations.
For further details see this thread:
https://github.com/fish-shell/fish-shell/pull/11463#discussion_r2079378627
The main advantage is that updates to the PO files are now only necessary when
the source strings change, which greatly reduces the diff noise.
A secondary benefit is that the string extraction logic is simplified.
We can now directly extract the strings from fish scripts,
and several issues are fixed alongside, mostly related to quoting.
The regex for extracting implicit messages from fish scripts has been tweaked to
ignore commented-out lines, and properly support lines starting with `and`/`or`.
The old regex has the problem that it does not handle lines containing any
non-space characters in front of ` complete` (or ` function`), which results in
`string replace` leaving this part in the resulting string.
For example,
`and complete -d "foo"`
would turn into
`andN_ foo`
if passed to
`string replace --regex $regex 'N_ $1'` (where `$regex` is the `$implicit_regex`) variable.
Another issue are commented-out lines.
This was added without a use case. Now there is a use case (#11084) that
needs it to include all tokens which the sister option "--tokens-expanded"
should not do. The inconsistency is probably not worth it, given that this
"--tokens-raw" use case can be served by a future "read -zal --tokenize-raw".
completions frequently use
argparse ... -- (commandline -xpc)
The "commandline -xpc" output
contains only string tokens.
A syntactically-valid process ("-p") consistes of only string tokens
and redirection tokens. We skip all non-string tokens, but we do include
redirection targets, which are always strings. This is weird, and confuses
completion scripts such as the one above. Leave out redirection targets too.
Part of #11084
Squashed commit of the following:
commit 23163d40bed2d97c72050990cf15db3944ce2ff0
Author: DaiLu Cao <caodailu@foxmail.com>
Date: Thu Apr 24 10:11:04 2025 +0800
Manually review up to line 1055 and modify all Chinese colons ':' to English ':' to prevent potential unknown errors.
commit dca5fb8182b94bffab5034dc5626b2b98d026b6f
Author: DaiLu Cao <caodailu@foxmail.com>
Date: Thu Apr 17 10:50:13 2025 +0800
Manually proofread up to 340 lines
commit 4b2d91c1138f3c8dec15b68aeb0510f02e15a776
Author: DaiLu Cao <caodailu@foxmail.com>
Date: Thu Apr 17 09:50:21 2025 +0800
use msgfmt check and fix all error
commit e2470d81c01ab7bf46d3d6ffd0291a05d4b38e13
Author: DaiLu Cao <caodailu@foxmail.com>
Date: Wed Apr 16 11:10:54 2025 +0800
Fix translation error converting '\\n' to '\\ n' error
commit 7ff970d06ce950aee35e1fb0ec70338f7bd42c1d
Author: DaiLu Cao <caodailu@foxmail.com>
Date: Wed Apr 16 10:53:38 2025 +0800
Fix make error, local cargo test completed
commit 018dfa225530a85486903ef58d47f4c358956b0b
Author: DaiLu Cao <caodailu@foxmail.com>
Date: Fri Apr 11 16:46:36 2025 +0800
modification of make errors
commit cbebd506a500aecc0669dce7f08422fcfed5615f
Author: DaiLu Cao <caodailu@foxmail.com>
Date: Fri Apr 11 15:45:01 2025 +0800
The second modification of make errors are all symbol problems
commit f75c3f7a2a84ffaea4eb642532b5a24da1c9154f
Author: DaiLu Cao <caodailu@foxmail.com>
Date: Fri Apr 11 15:27:01 2025 +0800
Re-add Chinese translation, try to solve the problem of make failing
commit 58551be20d261e3466a9e4ede290675f633e94a3
Author: DaiLu Cao <caodailu@foxmail.com>
Date: Fri Apr 11 15:06:01 2025 +0800
Supplement Chinese translation
This greatly reduces the number of changes necessary to the PO files when the
Rust/fish source files are updated. (Changes to the line number can be applied
automatically, but this adds a lot of noise to the git history.)
Due to the way we have been extracting Rust strings, differentiation between
the same source string in different contexts has not been possible regardless
of the change.
It seems that duplicate msgid entries are not permitted in PO files, so since we
do not use context to distinguish the strings we extract, there is no way to
have context-/location-dependent translations, so we might as well reduce the
git noise by eliminating line numbers.
Including source locations helps translators with understanding context.
Because we do not distinguish between contexts for a given source string,
this is of limited utility, but keeping file names at least allows to open the
relevant files and search them for the string. This might also be helpful to
identify translations which do not make sense in all context in which they are
used. (Although without adding context support, the only remedy would be to
remove the translation altogether, as far as I can tell.)
For extraction from Rust, additional issues are fixed:
- File name extraction from the grep results now works properly. Previously,
lines not starting with whitespace resulted in missing or corrupted matches.
(missing if the source line contains no colon followed by a whitespace,
corrupted if it does, then the match included the part of the line in front of
the colon, instead of just the location)
- Only a single source location per string was supported (`head -n1`). The new
approach using sed does not have this limitation.
Commit daa692a20b (Remove unnecessary escaping for # and ~ inside key name
tokens, 2025-04-01) stopped escaping ? in fish_key_reader output. This is
generally correct but not if the "qmark-noglob" feature flag is turned off.
Add that back, to be safe.
While at it, pass an environment variable more explicitly in a test.
After nix updated to 0.30, all functions related to file descriptor accepts impl AsFd, e.g., BorrowedFd. This PR is a minimal update. It tries to use impl AsFd as long as possible, but uses BorrowedFd in some places. Yes it introduces unsafe, but doesn't introduce new unsafe code.
This merges a large set of changes to the fish AST, with the intention of
making the code simpler.
There's no expected user-visible changes here, except for some minor
changes in the output of `fish_indent --dump-parse-tree`.
Ast parsing is about 50% faster measured via
`cargo +nightly bench --features=benchmark bench_ast_construction`
and also uses less memory due to some size optimization.
The biggest change is removing the `Type` notion from `Node`. Previously
each Node had an integer type identified with it, like Type::Argument. This
was a relic from C++: types were natural in C++ and we could use LLVM-style
RTTI to identify Nodes, leveraging the fact that C++ has inheritance and so
Type could be at the same location in each Node.
This proved quite awkward in Rust which does not have inheritance. So
instead we switch to a new notion, Kind:
pub enum Kind<'a> {
Redirection(&'a Redirection),
Token(&'a dyn Token),
Keyword(&'a dyn Keyword),
VariableAssignment(&'a VariableAssignment),
...
and a `&dyn Node` can now return its Kind. Basically leveraging Rust's enum
types.
Interesting lesson about the optimal way to construct ASTs in both
languages.
This eliminates a bunch of the different functions from NodeVisitorMut.
It also removes the runtime polymorphism - now it's a generic instead of
using &dyn. The reason is that there's only one implementation of
NodeVisitorMut so there's no size savings from polymorphism.
We can parse two different things via Ast:
1. A regular job list
2. A freestanding argument list, as used in `complete --arguments ...`
This second case is specific to one use.
Prior to this commit, we parsed the Ast and then "forgot" what we parsed,
storing a &dyn Node. Then we had to cast it to the right type, and assert,
and etc.
Make Ast generic over the Node type it parsed, and default the Node type to
JobList. This simplifies call sites.
This begins the process of replacing the underlying Node "type" notion with
Kind. A Kind is an Enum of all of the possible node types, except with
Token and Keyword collapsed into one.
The idea is, rather than this:
if node.type() == Type::Argument {
let arg = node.as_argument().unwrap();
...
}
we can instead do this:
if let Kind::Argument(arg) = node.kind() {
// we already have arg
}
There is also a cast() function:
let arg: Option<Argument> = node.cast()
which may be convenient in some places.
The big thing we lose is the ability to talk about a Node's type without
actually having a Node. But this turns out to not be an issue in practice.
Future commits will begin adopting Kind.
Prior to this commit, each Node in the ast could accept a visitor and visit
children either in order or in reverse order. This reverse feature added a lot
of complexity and the only client is Traversal.
Switch Traversal to reverse the nodes itself and remove the reverse bool
elsewhere, leading to some code simplifications.
In the fish AST, each node falls into one of three "categories":
1. A branch: contains child nodes
2. A leaf: no child nodes, contains a source range
3. A list: a sequence of child nodes and nothing more
Prior to this commit the category was explicit in the code for each Node type;
make it instead derived from the node's type. This continues to shrink our
macros.
No functional change expected.
Commit f38646593c (Allow `export` to set colon-separated `PATH`, `CDPATH`
and `MANPATH`., 2017-02-10)
did something very weird for «export PATH=foo».
It essentially does
set -gx PATH (string replace -- "$PATH" (string join ":" -- $PATH) foo)
which makes no sense. It should set PATH to "foo", no need to involve the
existing value of $PATH.
Additionally, the string split / string join dance is unnecessary. Nowadays,
builtin set already handles path variables as is needed here, so get rid of
this special case.
Fixes#11434
Specifically, the width and precision format specifiers are interpreted as
referring to the width of the grapheme clusters rather than the byte count of
the string. Note that grapheme clusters can differ in width.
If a precision is specified for a string, meaning its "maximum number of
characters", we consider this to limit the width displayed.
If there is a grapheme cluster whose width is greater than 1,
it might not be possible to get precisely the desired width.
In such cases, this last grapheme cluster is excluded from the output.
Note that the definitions used here are not consistent with the `string length`
builtin at the moment, but this has already been the case.
This should prevent occurrences of the search string from being found in other
locations (e.g. in a comment).
The whole approach of string extraction from Rust sources is sketchy,
but this at least prevents producing garbage when the content of a string
appears somewhere else unquoted.
The previous version generates files which do not preserve the line number from
the original fish script file, resulting in translation not working.
The new approach is quite ugly, and might have some issues,
but at least it seems to work in some cases.
Extracting explicit and implicit messages works essentially the same way, which
is also reflected in the code being identical, except for the regex.
Extract the duplicated code into a function.
- Apply lint config to entire workspace
- Inherit workspace config for fish-printf
- Allow stdlib printing in fish-printf tests
The current problem which is addressed by this is that warnings about C-String
literals are generated by clippy for code in fish-printf. These literals are not
available with the current MSRV 1.70, but previously the MSRV setting was not
inherited by fish-printf, causing the warning to appear.
Commit b00899179f (Don't indent multi-line quoted strings; do indent inside
(), 2024-04-28) changed how we compute indents for string tokens with command
substitutions:
echo "begin
not indented
end $(
begin
indented
end)"(
begin
indented
end
)
For the leading quoted part of the string, we compute indentation only for
the first character (the opening quote), see 4c43819d32 (Fix crash indenting
quoted suffix after command substitution, 2024-09-28).
The command substitutions, we do indent as usual.
To implement the above, we need to separate quoted from non-quoted
parts. This logic crashes when indent_string_part() is wrongly passed
is_double_quoted=true.
This is because, given the string "$()"$(), parse_util_locate_cmdsub calls
quote_end() at index 4 (the second quote). This is wrong because that function
should only be called at opening quotes; this is a closing quote. The opening
quote is virtual here. Hack around this.
Fixes#11444
As reported in
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$n20_uqiMqatEQcPG79Ca0c2_YvHBHTr-yCVXTEuze_Y
commit f5fac096c0 (Don't move cursor in delete-char, 2017-04-19) fixed the
behavior of Vi mode keys "delete" and "x" when the cursor is at the end of
the buffer, and commit d51f669647 (Vi mode: avoid placing cursor beyond
last character, 2024-02-14) generalized this fix.
This means that the delete-specific fix is no longer necessary. Remove it.
Note that if the cursor is at end of a line but not the last line, the
behavior of "delete" in Vi mode is still wrong. It should stay on the line.
This is a weird confusion between the "end" and "terminate" token
types.
"end" is the end of the "line" - a newline or ";".
"terminate" is the end of the "file" - like pressing newline
interactively or having the file end.
So this would count things like `if` and `switch` as a "help"
invocation even if followed by a newline, e.g.
```fish
if; echo foo
```
and
```fish
switch
case foo
```
The result of that was that a naked "if" in a script file isn't an
error, but doesn't start a block either, so if you complete the block
it would count the "end" as superfluous, which sends you on a bit of a
hunt to figure out where the block start is missing.
This script was broken by the changes to profiling output in
9d904e1113.
The new version works with both the old and new profiling output, even when
mixed. The script output has been adjusted to match the new profiling style
better.
This also adds basic error handling for situations where the script is invoked
incorrectly and makes the file executable.
The first two attempts skip over empty variables and the last one doesn't.
This is fine but since we need the default case anyway, might as well reuse
it here too. (An empty color variable is treated the same way a missing
color variable is.)
I don't have a runnable test case but this does seem to have bitrotted.
Originally, we only cared about keys and the EOF and check-exit events.
Returning one of the other new events here seems totally wrong.
Try to fix this, and move the logic closer to where it's needed, so we no
longer need to update its name and we're less likely to forget to update it,
and it cannot.
DCS commands stop at ST ("\e\\"). Make sure we don't stop at just "\e". I
don't know of any command that will actually include the escape byte in its
payload but better safe than sorry.
The input queue doesn't want to be blocked, so let's decide later what to
do with a mouse click. This fixes the potential problem where a mouse click
is ignored if it is received while we're waiting for the terminal to repond
to a query.
While we are waiting for a query response from the terminal, we defer any
input processing until we receive our query response
Then that response is promoted to the front of the input queue, and
remaining inputs are processed in order.
We accidentally process focus events, which may run arbitrary code. We can't
do this; it breaks a lot of invariants (for example the it can invalidate
the cursor positions for CursorPositionQuery, or it can cause fish to exit
before fully consumeing a query response).
Make sure we only process known-safe events. We definitely need to process
CheckExit (in case we received SIGHUP). I guess we should also process Eof,
in case the terminal is buggy.
These code paths have a tiny bit of logic in common, share that.
Maybe this should be nested in ImplicitEvent, and maybe Eof and CheckExit
shouldn't be..
This object is initialized once just before we start reading from the terminal.
Once seems to be the appropriate type for this. This gets rid of an awkward
enum variant.
We never need to access this from other threads, so a Mutex is overkill.
Leave behind stale variable names like "wait_guard" to be cleaned up by the
next commit.
Since TestInputEventQueuer is used concurrently in tests,
give it its own private object, to avoid borrowing conflicts.
Same for fish_key_reader; this fixes the issue that fish_key_reader potentially
reads keyboard input before a query is finished.
Whenever config.fish runs (interactive) builtin read, we push and pop a
top-level, before the main shell's reader.
The terminal state outlives all readers, so its scope should reflect that
to avoid redundant initialization. Move it into the parser.
This is also used by a following commit that wants to access the query state
from a builtin. This should work even if no reader is active.
Note that Mutex doesn't really make sense here - the next commit will fix that.
The differences between color variables and set_color implementation have
gotten somewhat small so make them explicit by getting rid of this code clone.
Outputter::set_text_face() has clever caching logic that is not always needed
by builtin set_color -- in fact, it even needs to explicitly disable the
cache for foreground and background colros -- but this might still be worth it.
As reported in https://github.com/fish-shell/fish-shell/issues/11325, we have logic that
implicitly activates bold mode.
Even worse: the test case from https://github.com/fish-shell/fish-shell/issues/11426 shows that
we're not even consistent about that.
To reproduce, use
set -g fish_pager_color_background --background=fff
set -g fish_pager_color_prefix --underline --bold 000
set -g fish_pager_color_completion
set -g fish_pager_color_description
complete : -s a -l all -d asdf
and type ": -" <TAB>
The second prefix is underlined but not bold,
because the implicit bold mode has a subtle bug.
Now if we were to fix this, using
diff --git a/src/terminal.rs b/src/terminal.rs
index b86a7d85fe..7791d34936 100644
--- a/src/terminal.rs
+++ b/src/terminal.rs
@@ -589,7 +589,7 @@
// Lastly, we set bold, underline, italics, dim, and reverse modes correctly.
if style.is_bold()
&& !self.last.style.is_bold()
- && !bg_set
+ && !(bg_set && !last_bg_set)
&& self.write_command(EnterBoldMode)
{
self.last.style.bold = true;
that would make the description bold as well, which would probably cause chaos.
Either way, it seems wrong to expand this hack.
Let's remove it.
For better or worse, we can't safely update the default theme yet on
an existing user's machine, because we have set universal variables.
This means that fish_color_search_match and fish_pager_color_progress on
existing installations are no longer bold. That's probably acceptable.
The former was hard to read for the longest time, until 9af6a64fd2 (Fix
bad contrast in search match highlighting, 2024-04-15). The progress info
is probably not a big deal.
Attentive users may run "fish_config theme choose 'fish default'". Perhaps
we should tell them on upgrade?
Closes#11325
(As suggested in 84e7fbd466 (Make default .theme file consistent with uvars,
2022-02-03))
Historical behavior in default fish is that
1. fish_color_keyword and fish_color_option are unset, meaning they
default to their fallbacks, fish_color_command and fish_color_param.
2. colors not mentioned in the default them, such as
fish_pager_color_secondary_background, are unset
"fish_config theme save fish\ default"
- sets group 1 to a non-empty value (deactivating the fallbacks)
- sets group 2 to an empty value (which has no function change except it
changes completions for builtin set)
Both are probably fine. I guess the historical behavior is a bit nicer.
But the new behavior is simpler. We can definitely optimize it later,
for example by never redundantly setting universal color variables to an
empty value.
The foreground component of fish_color_search_match was first used in commit
9af6a64fd2 (Fix bad contrast in search match highlighting, 2024-04-15)
which also changed it from bryellow to white. Unfortunately it forgot to
update the themes. Probably all of them want to the default, so let's do that.
We only query for the cursor position if either
1. if the terminal sends an XTGETTCAP response indicating it supports scroll
forward (terminfo code indn)
2. if the terminal sends a mouse click event
In practice, the terminals that do either are also capable of reporting the
cursor position, so let's require that for now.
We could definitely make this optional, and degrade gracefully -- that's
what I originally intended.
But maybe we don't need it? Keeps things simpler. In future, we can add a
timeout, and print an error, to help debugging terminals.
Old versions of ConHost and Putty can't parse DCS sequences.
For this reason, we briefly switch to the alternate screen buffer while sending
DCS-format (e.g. XTGETTCAP) queries. For extra paranoia, we wrapped this
procedure in a synchronized update. This doesn't seem to be needed; neither
ConHost nor Putty show glitches when the synchronized update is omitted.
As of today, every terminal that implements XTGETTCAP also implements
synchronized updates but that might change.
Let's remove it, to reduce surprise for users and terminal developers.
As a bonus, this also fixes a glitch on Terminal.app which fails to parse
the synchronized-update query (`printf '\x1b[?2026$p'`) and echoes the "p"
(bug report ID FB17141059). Else we could work around this with another
alternate screen buffer.
Unfortunately, this change surfaces two issues with GNU screen. For one,
they don't allow apps to use the alternate screen features (the user may
allow it with "altscreen on"). Second, screen unconditionally echoes
the payload of DCS commands. A possible fix has been suggested at
https://lists.gnu.org/archive/html/screen-devel/2025-04/msg00010.html
I think this combination of behaviors is unique among terminals. I'm sure
there are more terminals that don't parse DCS commands yet, but I think almost
all terminals implement alternate screen buffer. Probably only terminal
multiplexers are prone to this issue. AFAICT very few multiplexers exists,
so we can work around those until they are fixed.
Disable XTGETTCAP queries for GNU screen specifically. Unfortunately screen
does not implement XTVERSION, so I don't know how to reliably identify
it. Instead, check STY and some commonly-used values TERM values.
This has false negatives in some edge cases.
But the worst thing that happens is that "+q696e646e" will be echoed once
at startup, which is easy to ignore, or work around with something like
function workaround --on-event fish_prompt
commandline -f repaint
functions --erase workaround
end
which I don't think we should apply by default, because it can mask other
issues.
We should give screen more time to respond. I guess I'll open an issue so
we don't forget. In doubt, we can always go back to the previous approach
(but implement it in fish script).
Alternative workaround: instead of the alternative screen buffer, we could
try something like clr_eol/clr_bol to erase the spuriously echoed text. I
tried to do this in various ways but (surprisingly) failed.
"set_color --background=normal" resets all attributes. I don't expect anyone
relied on this behavior. Let's remove it, to reduce surprise. This also
improves consistency with "set_color --underline-color=normal".
As suggested in
https://github.com/fish-shell/fish-shell/issues/11417#issuecomment-2825023522
For backwards compatibility reasons, "set_color normal" still resets
everything though. In future we could make "set_color --foreground=normal"
reset only foreground.
Closes#11418
Some changes fix actual problems, e.g. missing spaces in square bracket tests,
and backticks unintentionally causing code execution when intended as formatting.
Others, such as conservative quoting probably work fine in the old version in
most situations, but it's nice to have some additional safety.
Using `{ ..; }` instead of `(..)` is just a small performance enhancement.
Many of these issues were identified by shellcheck, which might be useful in CI
as well.
Given
set -g fish_color_error --background=red --background=blue
set_color --background=red --background=blue
Historically, the former would use the first color (red) while the equivalent
set_color command uses the second one (blue).
This changed in 037c1896d4 (Reuse wgetopt parsing for set_color for internal
colors, 2025-04-13) which gave set_color semantics to the former.
This seems like the wrong choice set_color is less important.
For foreground colors we already pick the best color in a way that's consistent
across both. Let's extend this approach to background and underline colors
(even though I'd not really recommend using this feature).
Fixes#11420Closes#11421
Consolidate best_color() calls because the following commit
wants to use this for background and underline colors too.
Switch to Result so we can use the "?" syntax.
Commit 6fcb418ae3 (Enable 24-bit RGB colors by default, 2025-04-11)
invalidated some documentation about fallback colors; by default we prefer
RGB unless the user has explicitly set fish_term256=0.
Note that this made fallback colors much less useful, because they are only
active if the user sets fish_term256=0. Note that setting fish_term24bit=0
is *not* enough; in that case we use the 256 color palette (and assume that
it is a subset of the 24-bit colors).
We do have some themes that use fallback colors:
fish_pager_color_description B3A06D yellow
By default, those will be less useful now.
See also https://github.com/fish-shell/fish-shell/issues/11393
Commit df3b0bd89f (Fix commandline state for custom completions with variable
overrides, 2022-01-26) made us push a transient command line for custom
completions based on a tautological null-pointer check ("var_assignments").
Commit 77aeb6a2a8 (Port execution, 2023-10-08) turned the null pointer into
a reference and replaced the check with "!ad.var_assignments.is_empty()".
This broke scenarios that relied on the transient commandline. In particular
the attached test cases rely on the transient commandline implicitly placing
the cursor at the end, irrespective of the cursor in the actual commandline.
I'm not sure if there is an easy way to identify these scenarios.
Let's restore historical behavior by always pushing the transient command line.
Fixes#11423
Commit cebc05f6c1 (Reset is not a color, 2025-04-15) tried to simpilfy
this behavior but forgot about cases like "set_color --background=normal
red --bold" where we do want to continue after resetting background.
Closes#11417
Add a new underline-color option to set_color (instead of adding an optional
color argument to --underline); this allows to set the underline color
independently of underline style (line, curly, etc.). I don't think this
flexibility is very important but this approach is probably the least hacky.
Note that there are two variants:
1. \e[58:5:1m
2. \e[58;5;1m
Variant 1 breaks:
breakage from colon-variant for colored underlines
- cool-retro-term makes text blink
- GNU screen (goes into bold mode)
- terminology (goes into bold mode)
Variant 2 would break:
- mintty (Cygwin terminal) -- it enables bold font instead.
- Windows Terminal (where it paints the foreground yellow)
- JetBrains terminals echo the colons instead of consuming them
- putty
- GNU screen (goes into bold mode)
- st
- urxvt
- xterm
- etc.
So choose variant 1.
Closes#11388Closes#7619
set_color --underline=curly outputs \e[4:3m which breaks the following
terminals:
- Terminal.app interprets it as yellow background
- abduco and dvtm interpret it as green foreground
- JetBrains terminals interprets it as yellow background
- urxvt interprets it as yellow background
terminals that interpret curly as single underline:
- tmux [1]
- emacs ansi-term [2]
- emacs vterm
- GNU screen (also wrongly turns on italic mode)
- terminology (also wrongly turns on italic mode)
- Vim's :terminal
[1]: https://github.com/orgs/tmux/discussions/4477
[2]: https://lists.gnu.org/archive/html/bug-gnu-emacs/2025-04/msg01093.htmlCloses#10957
This workaround was added in commit d66700a0e4 (Color work, 2012-02-11).
I don't understand why it would be necessary, it seems redundant. Bravely
remove it. Would be interesting to know which terminal caused the motivating
problem. Terminal.app and others seem to be unaffected by this change.
This command does not work
set_color --background=reset
These seem to work
set fish_color_normal reset
set fish_color_normal --background=reset
but I don't understand why anyone would do that, since an empty color option
gives the same behavior.
Also "reset" is totally undocumented, since "normal" is our canonical spelling.
Let's simplify things by removing support for reset everywhere except if it's
a foreground color (since there are some uses of "set_color reset" out there).
Also, simplify the set_color logic accordingly.
Our highlighting module allows different highlight roles for foreground
and background.
Other users of our color-parsing logic have no need for this.
Historically we have passed an "is_background" bool and only parsed what we're
interested in. This sort of makes sense because it's exactly what we need,
but it meant that the special behavior spread quite far.
There is no real need for spreading it; a function with the behavior "parse
a text face but honor is_background" is strictly more complex than "parse a
text face". Additionally, any performance optimization is only relevant if
the user specifies faces that won't be used, which is a very unusual case.
Let's isolate this logic in the highlighting module.
The parent commit got rid of the is_background parameter that determined
the meaning of the return value (fg/bg); since we always return both now,
give them names.
A following commit wants to add other underline styles. At most one underline
style can be active at one time. This can't be modelled well by a flat
bitset, so let's use a composable type here.
When the text face changes from bold to non-bold, we need to reset
all attributes since there is no exit_bold_mode.
The same holds for various dim and reverse mode, and future attributes.
A following commit wants to make this logic more robust to addition of future
attributes. Prepare for that by using the new type.
Not sure if this is 100% a good idea but it does remove some duplication.
While at it, change parse_color_maybe_none to actually return Option::None
and not Color::None which means something else (see a following commit).
Our "Color" type also includes text styling (bold, italics, ...). This doesn't
seem like the perfect way to model this, because the background text styles
are always unused (this is noticeable with some fish_color_* variables).
Introduce a type that represents attributes to apply to text, and nothing
else. Prefer to pass this instead of two Color values with redundant text
style is redundant.
We have a a workaround with a comment saying
> We don't know if exit_attribute_mode resets colors, so we set it to
> something known.
I'm pretty sure fish (and other software) makes this assumption.
I'd be very surprised if a relevant terminal behaves differently.
Let's remove our attempt to work around around this.
While at it, extract a function to be used in two other places
(but don't change their behavior yet).
A "None" type color means "don't change it, use the last color. So it makes
no sense to ever set "self.last_fg = NONE". The background-color code path
only sets it in the other cases. Let's copy that for the foreground one.
Also, extract this assignment to simplify both code paths.
fish -c 'set_color --print-colors --background blue' |xxd
does not print color enabling sequences but does print *disabling* sequences.
There's no need for that.
RgbColor can also be a named color, so this name is surprising to readers
who don't have the implicit assumption that named colors are the default
and that RGB support is something novel.
tl;dr reduce memory usage and ast complexity. No functional change expected.
This concerns how our ast is represented. Prior to this commit, and ever
since the new ast was introduced, each Node had a reference to its parent -
the so-called "parent pointer". This made it convenient to "walk around"
the AST - for example we could get a command and then walk up the AST to
determine if that command had a decoration (`time`, etc).
This parent pointer concept was natural in C++ for a few reasons:
1. Pointers are idiomatic in C++.
2. Parent pointers were "thin": just regular pointer-sized, e.g.
8 bytes in x86-64.
3. C++'s inheritance means that the pointer can just be stored as a field
in the base Node class. Super easy and efficient.
But these proved to have significant drawbacks when expressed in Rust:
1. Parent pointers form a cyclic data structure which is very awkward in
Rust. We had to use raw pointers and unsafe code.
2. Parent pointers were a `&dyn Node` which is necessarily "fat" (base
pointer + vtable pointer), taking up 16 bytes on a 64 bit machine. This
greatly bloated the size of the AST because our AST is quite fine (many
detailed node types).
3. The lack of inheritance means that parent pointers had to be repeated
for every node and exposed through the Node trait, which was awkward and
verbose.
In fact storing parent pointers is rather uncommon among AST
implementations. For example, LLVM does not do this; instead it dynamically
constructs a map of parent pointers on demand (see `ParentMapContext`).
fish could do this or something like it, but in fact we can do better: we
can tweak Traversal to provide parent pointers.
As a reminder, Traversal is a way of naturally iterating over all AST nodes
in a for loop:
for node in ast.walk() {...}
This is in-order ("top-down"). A parent node is yielded before its children.
Prior to this commit, this worked as follows: the Traversal maintained a
stack of next-to-be-yielded nodes. The `next()` function would pop off the
next node, push all of its children onto the stack, and then yield that
popped node.
We can easily make Traversal remember the sequence of parents of a given
Node by tweaking the Traversal to remember each Node after popping it. That
is, mark each Node in the stack as "NeedsVisit" or "Visited". Within
`next()`, check the status of the top node:
- NeedsVisit => mark it as Visited, push its children, and return that Node
- Visited => pop it, discard it, and try again
This means that, for any Node returned by `next()`, we can get the sequence
of parents as those Nodes that are marked as Visited on the stack.
The net effect of all of this is a large decrease in ast complexity and
memory usage. For example, __fish_complete_gpg.fish goes from 508 KB to 198 KB,
as measured by `fish_indent --dump-parse-tree`.
There's somewhat higher memory usage for Traversal, but these are transient
allocations, not permanent.
This removes parent back-pointers from ast nodes. Nodes no longer store
references to their parents, resulting in memory size reductions for the ast
(__fish_complete_gpg.fish goes from 508 KB to 198 KB in memory usage).
These depths are used in calculating indents for ast pretty-printing.
This moves away from parent back-pointers, so that we can ultimately remove
them.
Prior to this commit, Traversal was a convenient way to walk the nodes of
an ast in pre-order. This worked simply: it kept a stack of Nodes, and then
when a Node was visited, it was popped off and its children added.
Enhance Traversal to track whether each node on the Stack is `NeedsVisit`
or `Visited`. The idea is that, when a Node is yielded from next(), we can
reconstruct its parents as those Visited nodes on the Traversal stack.
This will allow clients to get the parents of Nodes as they are traversed
without each Node needing to explicitly save its parent.
This function hid a bug! It converted two Nodes to `*const ()` which discards
the vtable pointer, using only the data pointer; but two nodes can and do have
the same data pointer (e.g. if one node is the first item in another).
Add the (statically dispatched) is_same_node function with a warning comment,
and adopt that instead.
Now that we have more confidence in our pointers, we can allocate directly
more often, instead of always through Box. This recovers the performance
lost from the previous commit.
Prior to this commit, lists of items (e.g. an argument list to a command) would
each be Boxed, i.e. we had effectively Vec<Box<Item>>. The rationale here is
that we had raw pointers and pointer stability was important to enforce.
But we have fewer raw pointers now - only the parent pointers - and we can be
confident that the Ast will not change or move after construction. So remove
this intermediate Box, simplifying some logic and reducing ast size by ~5%.
This slows down Ast construction because we're still constructing
the Box and moving things in and out of it - that will be addressed in
subsequent commits.
This saves a decent amount of memory, both because we no longer have excess
capacity sitting around that we'll never use, but also because we no longer need
to store the "capacity" value.
This makes the destinations update dynamically when they are added/removed.
Unquote the echo statement so that it is correctly paresd by the -a options.
Indicate the units of the durations (microseconds).
Right-align the durations for better readability.
Use `format!` instead of `fprintf` for more flexible formatting.
Write to `File` instead of raw fd.
Closes#11396
- Reorganize completions and options so they are easier to read.
- Add destination UUIDs to completetions as well as descriptions
- Add a few missing sub commands
As mentioned in
https://github.com/fish-shell/fish-shell/pull/9688#discussion_r1155089596,
commit b77d1d0e2b (Stop crashing on invalid Unicode input, 2024-02-27), Rust's
char type doesn't support arbitrary 32-bit values. Out-of-range Unicode
codepoints would cause crashes. That commit addressed this by converting
the encoded bytes (e.g. UTF-8) to special private-use-area characters that
fish knows about. It didn't bother to update the code path in builtin read
that relies on mbrtowc as well.
Fix that. Move and rename parse_codepoint() and rename/reorder its input/output
parameters.
Fixes#11383
(cherry picked from commit d9ba27f58f)
This also changes the single-byte locale code path to treat keyboard input
like "\x1ba" as alt-a instead of "escape,a". I can't off-hand reproduce
a problem with "LC_ALL=C fish_key_reader", I guess we always use a UTF-8
locale if available?
(cherry picked from commit b061178606)
Two issues:
1. typing the codepoint 0x123456 into fish_key_reader:
$ fish_key_reader -cV
# decoded from: \xf4\xa3\x91
bind \xf4 'do something'
# decoded from:
bind \xa3 'do something'
# decoded from:
bind \x91 'do something'
The invalid codepoint is represented in its original encoding, which leaks
to the UI. This was more or less intentionally added by b77d1d0e2b (Stop
crashing on invalid Unicode input, 2024-02-27). That commit rendered it
as replacement byte, but that was removed for other reasons in e25a1358e6
(Work around broken rendering of pasted multibyte chars in non-UTF-8-ish
locale, 2024-08-03).
We no longer insert such (PUA) codepoints into the commandline. The "bind"
comes above would work however. I don't think this is something we want
to support. Discard invalid codepoints in the reader, so they can't be
bound and fish_key_reader shows nothing.
2. builtin read silently drops invalid encodings This builtin is not really
suited to read binary data (#11383 is an error scenario), but I guess it can
be bent to do that. Some of its code paths use str2wcstring which passes
through e.g. invalid UTF-8. The read-one-char-at-a-time code path doesn't.
Fix this.
As mentioned in
https://github.com/fish-shell/fish-shell/pull/9688#discussion_r1155089596,
commit b77d1d0e2b (Stop crashing on invalid Unicode input, 2024-02-27), Rust's
char type doesn't support arbitrary 32-bit values. Out-of-range Unicode
codepoints would cause crashes. That commit addressed this by converting
the encoded bytes (e.g. UTF-8) to special private-use-area characters that
fish knows about. It didn't bother to update the code path in builtin read
that relies on mbrtowc as well.
Fix that. Move and rename parse_codepoint() and rename/reorder its input/output
parameters.
Note that the behavior is still wrong if builtin read can't decode the
input; see the next commit.
Fixes#11383
This also changes the single-byte locale code path to treat keyboard input
like "\x1ba" as alt-a instead of "escape,a". I can't off-hand reproduce
a problem with "LC_ALL=C fish_key_reader", I guess we always use a UTF-8
locale if available?
As reported in
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$BDVmBtBgtKCj45dVfS36rP7Y6Fo7E4uBg1vcH9IIIQg
tmux new-session -c "" fish -C 'echo $PWD'
prints
/home/fishuser/
This is because our path canonicalization function only
removes trailing slashes if there were duplicate slashes in the string.
Else (for the case above), we end up with "trailing == len"
which means we ignore trailing slashes.
I don't think this was intended by 24f1da7f30 (Add a fancy new
paths_are_equivalent function to test for equivalent paths instead of merely
equal ones, 2013-08-27). Fix it.
While at it, also document the command to reset the shape to the default,
which we should probably use. See foot commit 49034bb7 (csi: let CSI 0 q mean
"switch to user configured cursor style", 2019-07-22).
As of today, the XTerm documentation is a not clear on this; in
XTerm itself, CSI 0 q may actually change the cursor because they have an
additional default cursor is configured differently..
Things like branch and tag name can take up a lot of space on the screen. The
empty status may be useful but we're still looking for evidence. For now let's
keep only the conflict status, which is fairly familiar from the Git prompt.
See also #11183
* man: redirect stderr to /dev/null when checking for embedded files
This fixes a bug where `man status` results in "status: fish was not
built with embedded files⏎" printed.
* fish_config and status completions: redirect stderr to /dev/null when checking for embedded files
I am less sure about this commit, can get rid of it.
* status get-file/list-files: add \n to error message when not compiled with embedded files
The original only worked in the manifest directory *and* didn't even
list the right packages.
E.g. for fish it listed "printf", when the package is called
"fish-printf". So we're not keeping it because it's wrong.
Instead let's parse the actual json. It's a shame there is no
simple command to just get it line-delimited, of course.
Fixes#11384
CMake has this entire zoo of weird build types including "MinSizeRel".
I've also seen it set to empty, in distro packages no less.
Since we can't really make them all known to cargo, let's warn.
We could also error, but I'm not convinced there isn't some distro
packager out there setting it to "StrawberriesAndKittens" for some
reason,
and they'd be very cross with us if that stopped working.
See #11376
If you use `set t 10; function fish_prompt; seq $t; set t $(math $t - 1); end` and trigger a repaint, you will see 9 residual lines from the previous prompt.
Now, the right prompt will not be executed only if it is undefined `fish_right_prompt`.
This allows the use of `read -p 'echo left' -R 'echo right'`.
Also changes condition for use of `DEFAULT_PROMPT` for consistency.
I think `set_color ff0000` should default to outputting true-color sequences.
Unfortunately there is no good and widely-supported way to query for true-color
support. `COLORTERM=truecolor` doesn't work in some cases such as ssh.
Since many terminals nowadays implement the RGB sequences, let's try using
them by default.
Note that Emacs's ansi-term implements truecolor now.
See also the discussion around
https://github.com/fish-shell/fish-shell/pull/11345#issuecomment-2794920900Closes#11372
We have basically zero system tests for text coloring/formatting. I have
something in the works that will enable this without forcing tests to parse
the output of "tmux capture-pane -pe".
Fixes#11373
Fixes 17b4b39c8b (Stop reading terminfo database, 2025-03-20).
This part of the code could use some love; when we happen to clear the
selected text, we should end the selection.
But that's not how it works today. This is fine for Vi mode, because Vi
mode never deletes in visual mode.
Let's fix the crash for now.
Fixes#11367
(cherry picked from commit af3b49bf9c)
Use function names which explicitly state their flushing behavior.
When writing history items to a new file, flushing is only done at the end.
When appending items to an existing file, flushing is done for each item, in
order to keep the `first_unwritten_new_item_index` counter consistent with the
file system.
These builds do not use it, and setting it makes it possible to use
stale files.
So instead, we set it to empty. All uses I could find are either fine
with that (`set fish_function_path $__fish_data_dir/functions` - which
would also just be empty, which means it reads the embedded
functions),
or would break even if the variable was set but the directory was
empty (`source $__fish_data_dir/completions/git.fish`).
In case a completion needs a function from another script, run
`complete -C"foo "` to load it, so the full autoloading logic is used.
Otherwise these things break if the path is off. E.g. cargo's version
will fail if you override the cargo completion in
~/.config/fish/completions without also overriding the rustup
completions.
In other cases, fix for empty $__fish_data_dir, which will be coming in the next commit
This reflects better what it is - fish doesn't need to "install"
itself anymore, it just includes the data in the binary.
This also means we could include a separate "embed-man" feature that
can be turned off if you want the man pages to be shipped separately.
Also explain that in the README.
Technically the fish_update_completions files could also be piped to
python, but they'd have to be one file.
So for now, if you start a single-file fish, you'll have to run
fish_update_completions manually.
That fits the idea of having a single file that you move somewhere
better, given that it otherwise would run a script in the background
that creates a bunch of files
Because these are embedded in the fish binary,
we need to rebuild fish once they're changed.
This is only for release builds,
because rust-embed only really embeds in those
(debug builds read from the filesystem).
This is no longer useful, given that we read files from in the binary.
In the upcoming commits, this can be done with status list-files/get-file if you need it
This will load the functions and completions from inside of the fish
binary.
That means its no longer necessary to *install* a self-installable
build for basic functionality.
The functions/completions will be loaded *last*, so they are still
overridable via a file on disk (with the exception of
generated_completions, which we only use as a fallback if no
completions exist).
It still needs to extract files that are to be used by other tools,
including the man pages, fish_config.py, the man page completion
generator.
The remaining issues:
- It no longer prompts to install, but if you tried `fish_config`
after this it would fail to open the tool,
and it would be easy to forget to update those files
So: When and how should this remind you that these files need to be extracted?
Do we want e.g. a builtin that checks the version file (`status installed`)?
This could then be run by `fish_config` and `help` and tell you to run `fish --install`.
- `builtin --help` will fail - we could read these things from inside,
but we'd need groff for that.
Do we want to pre-process these and put them in the builtins themselves?
Do we want to print these on demand in `__fish_print_help` to groff?
- What directories need to still be defined? Does $__fish_data_dir need to keep existing?
Technically this *could* be the main distribution method. Maybe we
could let distro packages skip the embedded documentation and external
files,
but keep the functions/completions in the binary.
This gets the reader out of asting the source and is needed for
autoloader to get it to read a source string directly
Also add an "eval_file_wstr" method as a convenience to run a wstr as if it is a *file*, with a block and stuff
Our use of the terminfo database in /usr/share/terminfo/$TERM is both
1. a way for users to configure app behavior in their terminal (by
setting TERM, copying around and modifying terminfo files)
2. a way for terminal emulator developers to advertise support for
backwards-incompatible features that are not otherwise easily observable.
To 1: this is not ideal (it's very easy to break things). There's not many
things that realistically need configuration; let's use shell variables
instead.
To 2: in practice, feature-probing via terminfo is often wrong. There's not
many backwards-incompatible features that need this; for the ones that do
we can still use terminfo capabilities but query the terminal via XTGETTCAP
directly, skipping the file (which may not exist on the same system as
the terminal).
---
Get rid of terminfo. If anyone finds a $TERM where we need different behavior,
we can hardcode that into fish.
* Allow to override this with `fish_features=no-ignore-terminfo fish`
Not sure if we should document this, since it's supposed to be removed soon,
and if someone needs this (which we don't expect), we'd like to know.
* This is supported on a best-effort basis; it doesn't match the previous
behavior exactly. For simplicity of implementation, it will not change
the fact that we now:
* use parm_left_cursor (CSI Ps D) instead of cursor_left (CSI D) if
terminfo claims the former is supported
* no longer support eat_newline_glitch, which seems no longer present
on today's ConEmu and ConHost
* Tested as described in https://github.com/fish-shell/fish-shell/pull/11345#discussion_r2030121580
* add `man fish-terminal-compatibility` to state our assumptions.
This could help terminal emulator developers.
* assume `parm_up_cursor` is supported if the terminal supports XTGETTCAP
* Extract all control sequences to src/terminal_command.rs.
* Remove the "\x1b(B" prefix from EXIT_ATTRIBUTE_MODE. I doubt it's really
needed.
* assume it's generally okay to output 256 colors
Things have improved since commit 3669805627 (Improve compatibility with
0-16 color terminals., 2016-07-21).
Apparently almost every actively developed terminal supports it, including
Terminal.app and GNU screen.
* That is, we default `fish_term256` to true and keep it only as a way to
opt out of the the full 256 palette (e.g. switching to the 16-color
palette).
* `TERM=xterm-16color` has the same opt-out effect.
* `TERM` is generally ignored but add back basic compatiblity by turning
off color for "ansi-m", "linux-m" and "xterm-mono"; these are probably
not set accidentally.
* Since `TERM` is (mostly) ignored, we don't need the magic "xterm" in
tests. Unset it instead.
* Note that our pexpect tests used a dumb terminal because:
1. it makes fish do a full redraw of the commandline everytime, making it
easier to write assertions.
2. it disables all control sequences for colors, etc, which we usually
don't want to test explicitly.
I don't think TERM=dumb has any other use, so it would be better
to print escape sequences unconditionally, and strip them in
the test driver (leaving this for later, since it's a bit more involved).
Closes#11344Closes#11345
I think multi is always shorter unless we're only moving by one cell.
Also, we want to simplify this for a following commit where we no longer
check if it's supported.
This reverts commit 58347d494a (update PROMPT_SP heuristic, 2016-12-23)
If we write the last column of a line:
printf %0"$COLUMNS"d 0; sleep 3
most terminals will *not* move the cursor to the next line.
This behavior is indicated by the terminfo's xenl (AKA xen or
eat_newline_glitch) boolean capability.
We originally added checks for this capability because ConEmu and Windows
ConHost did not implement it, but they do now.
Also, as mentioned in
https://github.com/fish-shell/fish-shell/pull/11342#issuecomment-2769979520,
we're not aware of any present-day terminal that does not have this behavior,
but the value advertised by terminfo is sometimes wrong.
Let's get rid of this for now. A following commit will document that we
require this behavior.
I don't think we want to support terminals that implement XTGETTCAP but for
some reason don't use CSI Ps S for scroll forward; that would be a needless
complication.
Let's make ctrl-l / scrollback-push fail hard if a terminal does this.
Confusingly kitty and foot use different response formats, but happily we
no longer care.
An upcoming commit will document that we require the CSI Ps S style.
scoped_buffer borrows the screen to be able to flush buffers on drop. This is
a bit intrusive (see also 29ae571afa (Make scoped_push nicer, 2024-12-28)).
Not sure what's the best solution -- probably we should always pass the
outputter as parameter, removing the field.
For now let's at least contain the effects of this.
This part of the code could use some love; when we happen to clear the
selected text, we should end the selection.
But that's not how it works today. This is fine for Vi mode, because Vi
mode never deletes in visual mode.
Let's fix the crash for now.
Fixes#11367
`Duration::as_nanos()`
"Returns the total number of nanoseconds contained by this Duration."
https://doc.rust-lang.org/core/time/struct.Duration.html#method.as_nanos
Because we are indicating the time in milliseconds, we cannot use
`Duration::subsec_nanos()` but we need to manually get the whole duration in
nanoseconds and subtract the duration in milliseconds to get the fractional
part.
With
bind ctrl-r 'sleep 1' history-pager
typing ctrl-r,escape crashes fish in the history pager completion callback,
because the history pager has already been closed.
Prior to 55fd43d86c (Port reader, 2023-12-22), the completion callback
would not crash open a pager -- which causes weird races with the
user input.
Apparently this crash as been triggered by running "playwright",
and -- while that's running typing ctrl-r ligh escape.
Those key strokes were received while the kitty keyboard protocol
was active, possibly a race.
Fixes#11355
(cherry picked from commit c94e30293a)
With
bind ctrl-r 'sleep 1' history-pager
typing ctrl-r,escape crashes fish in the history pager completion callback,
because the history pager has already been closed.
Prior to 55fd43d86c (Port reader, 2023-12-22), the completion callback
would not crash open a pager -- which causes weird races with the
user input.
Apparently this crash as been triggered by running "playwright",
and -- while that's running typing ctrl-r ligh escape.
Those key strokes were received while the kitty keyboard protocol
was active, possibly a race.
Fixes#11355
This "SpawnedProc(env=os.environ.copy())" seems redundant but it's not, since
the default argument is initialized (with a copy of env) at module-load time.
Reshuffle the code to make it look less odd.
While at it, fix some invalid escape sequence warnings.
We canonicalize "ctrl-shift-i" to "ctrl-I".
Both when deciphering this notation (as given to builtin bind),
and when receiving it as a key event ("\e[105;73;6u")
This has problems:
A. Our bind notation canonicalization only works for 26 English letters.
For example, "ctrl-shift-ä" is not supported -- only "ctrl-Ä" is.
We could try to fix that but this depends on the keyboard layout.
For example "bind alt-shift-=" and "bind alt-+" are equivalent on a "us"
layout but not on a "de" layout.
B. While capslock is on, the key event won't include a shifted key ("73" here).
This is due a quirk in the kitty keyboard protocol[^1]. This means that
fish_key_reader's canonicalization doesn't work (unless we call toupper()
ourselves).
I think we want to support both notations.
It's recommended to match all of these (in this order) when pressing
"ctrl-shift-i".
1. bind ctrl-shift-i do-something
2. bind ctrl-shift-I do-something
3. bind ctrl-I do-something
4. bind ctrl-i do-something
Support 1 and 3 for now, allowing both bindings to coexist. No priorities
for now. This solves problem A, and -- if we take care to use the explicit
shift notation -- problem B.
For keys that are not affected by capslock, problem B does not apply. In this
case, recommend the shifted notation ("alt-+" instead of "alt-shift-=")
since that seems more intuitive.
Though if we prioritized "alt-shift-=" over "alt-+" as per the recommendation,
that's an argument against the shifted key.
Example output for some key events:
$ fish_key_reader -cV
# decoded from: \e\[61:43\;4u
bind alt-+ 'do something' # recommended notation
bind alt-shift-= 'do something'
# decoded from: \e\[61:43\;68u
bind alt-+ 'do something' # recommended notation
bind alt-shift-= 'do something'
# decoded from: \e\[105:73\;6u
bind ctrl-I 'do something'
bind ctrl-shift-i 'do something' # recommended notation
# decoded from: \e\[105\;70u
bind ctrl-shift-i 'do something'
Due to the capslock quirk, the last one has only one matching representation
since there is no shifted key. We could decide to match ctrl-shift-i events
(that don't have a shifted key) to ctrl-I bindings (for ASCII letters), as
before this patch. But that case is very rare, it should only happen when
capslock is on, so it's probably not even a breaking change.
The other way round is supported -- we do match ctrl-I events (typically
with shifted key) to ctrl-shift-i bindings (but only for ASCII letters).
This is mainly for backwards compatibility.
Also note that, bindings without other modifiers currently need to use the
shifted key (like "Ä", not "shift-ä"), since we still get a legacy encoding,
until we request "Report all keys as escape codes".
[^1]: <https://github.com/kovidgoyal/kitty/issues/8493>
This notation doesn't make sense, use either A or shift-a. We accept it
for ASCII letters only -- things like "bind shift-!" or "bind shift-Ä"
do not work as of today, we don't tolerate extra shift modifiers yet.
So let's remove it for consistency.
Note that the next commit will allow the shift-A notation again, but it will
not match shift-a events.
Our versions look like
4.0.0
4.0b1
4.0.1-535-abfef-dirty
But packagers may want to add more information here, and we don't
really care. Note that we no longer ever set the version to "unknown"
since 5abd0e46f5.
Supersedes #11173
(cherry picked from commit 411a396fa9)
This uses jj's dynamic completions when possible.
This avoids an annoying problem. After 04a4e5c4, jj's dynamic
completions (see the second paragraph of
<https://jj-vcs.github.io/jj/latest/install-and-setup/#command-line-completion>)
do not work very well in fish if the user puts `COMPLETE=fish jj |
source` in their `~/.config/fish/config.fish`. When the user types `jj
<TAB>`, they are instead overridden by fish's built-in non-dynamic
completions.
The difference is subtle. One problem I saw is that `jj new <TAB>` works
as expected (and shows revisions) while `jj new -A <TAB>` becomes broken
(and shows files).
If the user puts `COMPLETE=fish jj | source` in
`~/.config/fish/completions/jj.fish` there is no problem. However, users
might be confused if they run `COMPLETE=fish jj | source` or put it in
their config and it works in a broken fashion. I certainly was.
Meanwhile, I checked that if the user has `jj completion fish | source`
in their `config.fish`, executing `COMPLETE=fish jj
__this_command_does_not_exist | source` afterwards still works
correctly.
Let me know if there's a better approach to this problem.
(cherry picked from commit 932010cd04)
The commands 'close', 'resize', and 'status' each take 'name' as their solo argument.
Signed-off-by: memchr <memchr@proton.me>
(cherry picked from commit 5012bcb976)
This does two things:
- it stops completing cargo- tools because `cargo --list` already
includes them. This speeds up loading especially with a long $PATH
- it stops using `cargo search` for `cargo add` and install.
this removes a network call, which may be unexpected and can take a
long time
Fixes#11347
(cherry picked from commit 18371fbd4e)
This does two things:
- it stops completing cargo- tools because `cargo --list` already
includes them. This speeds up loading especially with a long $PATH
- it stops using `cargo search` for `cargo add` and install.
this removes a network call, which may be unexpected and can take a
long time
Fixes#11347
While at it, don't escape "?", I don't know why 68e167d576 (f-k-r should
use the user's locale, 2016-06-29) did that. Question mark is only special
in combination with redirections.
This parser was pretty nice but it has some issues with the new syntax.
It's not really needed when most bindings use the new syntax.
Let's remove it altogether.
I don't think there's a relevant terminal where the "bind -k" notation is
still needed. The remaining reason to keep it is backwards compatibility.
But "bind -k" is already subtly broken on terminals that implement either
of modifyOtherKeys, application keypad mode or the kitty keyboard protocol,
since those alter the byte sequences (see #11278).
Having it randomly not work might do more harm than good. Remove it.
This is meant go into 4.1, which means that users who switch back and forth
between 4.1 and 4.0 can already use the new notation.
If someone wants to use the bind config for a wider range of versions they
could use "bind -k 2>/dev/null" etc.
While at it, use the new key names in "bind --key-names", and sort it like
we do in "bind --function-names".
Closes#11342
Extract our own cfg value, to avoid noisy warnings like:
warning: unexpected `cfg` condition value: `cygwin`
--> src/fallback.rs:78:23
|
78 | #[cfg(not(target_os = "cygwin"))]
| ^^^^^^^^^^^^^^^^^^^^
|
The cygwin target will be added to Rust 1.86, so we can get rid of this
after some time.
If the kitty protcol is not supported, we still want to request modifyOtherKeys
and application keypad mode. Since 2d234bb676 (Only request keyboard protocols
once we know if kitty kbd is supported, 2025-01-26), fish_key_reader fails
to turn on those modes if the kitty keyboard protocol is not supported.
FindRust is too clever by half. It tries to do rustup's job for it.
See b38551dde9 for how that can break.
So we simplify it, and only let it check three things:
- Where's rustc? Look in $PATH and ~/.cargo/bin
- Where's cargo? Look in $PATH and ~/.cargo/bin
- What is the rust target (because we pass it explicitly)?
If any of these aren't that simple, we'll ask the user to tell us,
by setting Rust_COMPILER, Rust_CARGO or Rust_CARGO_TARGET.
None of the other things are helpful to us - we do not support windows
or whatever a "unikraft" is, and if the rust version doesn't work
it'll print its own error.
We could add a rustc version check, but that will become less and less
useful because rustc versions since 1.56 (released October 2021) will check rust-version in
Cargo.toml. So even at this point it's only pretty old rust versions already.
If anything changes in one of the listed directories or files, trigger a
rebuild.
Rebuilds are needed to update the version info built into the binaries.
The version info includes an abbreviated git commit hash, as well as information
about whether the repo was in a dirty state (uncommitted changes) when building.
Changes to files not explicitly listed will not trigger a rebuild, so to get
accurate version info upon such changes (also when checking out a different
commit which does not differ in any of the listed files), a rebuild needs to be
triggered manually (e.g. via `cargo clean` or `touch build.rs`).
It appears we're getting the correct output, but in the wrong order,
so pexpect doesn't filter it correctly:
> \r\n\x1b]133;C;cmdline_url=echo%20bar\x07bar\r\n\x1b]133;D;0\x07\x1b[?25h⏎ \r⏎ \r\rprompt 39>\x1b[?2004h
That `\x07bar` should be the \a that marks the end of the escape
sequence, followed by the actual "bar", followed by sequences marking
the end of output...
Text like "simply do" or "just press" is patronizing and unnecessary.
The prose is nicer if it's removed, and in some cases other words are
more specific.
Something like "we'll pretend your prompt is just a ``>``" can stay.
From the cargo docs (https://doc.rust-lang.org/cargo/reference/build-scripts.html#change-detection):
> By default, it takes a conservative approach of always re-running the build script if any file within the package is changed (or the list of files controlled by the exclude and include fields). For most cases, this is not a good choice, so it is recommended that every build script emit at least one of the rerun-if instructions (described below). If these are emitted, then Cargo will only re-run the script if the given value has changed
So, since we emit rerun-if-path-changed, we need to emit *all* the paths.
Failing to do this shows up most visibly as an outdated git version.
Fixes#11332
Consider command line modifications triggered from fish script via abbreviation
expansion:
function my-abbr-func
commandline -r ""
echo expanded
end
abbr -a foo --function my-abbr-func
Prior to commit 8386088b3d (Update commandline state changes eagerly as well,
2024-04-11), we'd silently ignore the command line modification.
This is because the abbreviation machinery runs something similar to
if my-abbr-func
commandline -rt expanded
end
except without running "apply_commandline_state_changes()" after
"my-abbr-func", so the «commandline -r ""» update is lost.
Commit 8386088b3d applies the commandline change immediately in the abbrevation
function callback, invalidating abbrevation-expansion state.
The abbreviation design does not tell us what should happen here. Let's ignore
commandline modifications for now. This mostly matches historical behavior.
Unlike historical behavior we also ignore modifications if the callback fails:
function my-abbr-func
commandline -r ""
false
end
Remove the resulting dead code in editable_line.
See #11324
(cherry picked from commit 11c7310f17)
Consider command line modifications triggered from fish script via abbreviation
expansion:
function my-abbr-func
commandline -r ""
echo expanded
end
abbr -a foo --function my-abbr-func
Prior to commit 8386088b3d (Update commandline state changes eagerly as well,
2024-04-11), we'd silently ignore the command line modification.
This is because the abbreviation machinery runs something similar to
if my-abbr-func
commandline -rt expanded
end
except without running "apply_commandline_state_changes()" after
"my-abbr-func", so the «commandline -r ""» update is lost.
Commit 8386088b3d applies the commandline change immediately in the abbrevation
function callback, invalidating abbrevation-expansion state.
The abbreviation design does not tell us what should happen here. Let's ignore
commandline modifications for now. This mostly matches historical behavior.
Unlike historical behavior we also ignore modifications if the callback fails:
function my-abbr-func
commandline -r ""
false
end
Remove the resulting dead code in editable_line.
See #11324
Commit 50e595503e (completions/git: fix completions for third-party git
commands, 2025-03-03) wasn't quite right, as we can see in the linked
reproduction:
$ fish_trace=1 complete -C 'git machete add --onto '
----> complete -C git-machete\ add\n--onto\
The recursive completion invocation contains a spurious newline, which means
that "--onto" is the command name. The newline is produced by "string escape
-- add --onto" inside a command substitution.
Fix this by interpreting newlines as list separators, and then joining
by spaces.
Fixes#11319
(cherry picked from commit 360cfdb7ae)
Commit 50e595503e (completions/git: fix completions for third-party git
commands, 2025-03-03) wasn't quite right, as we can see in the linked
reproduction:
$ fish_trace=1 complete -C 'git machete add --onto '
----> complete -C git-machete\ add\n--onto\
The recursive completion invocation contains a spurious newline, which means
that "--onto" is the command name. The newline is produced by "string escape
-- add --onto" inside a command substitution.
Fix this by interpreting newlines as list separators, and then joining
by spaces.
Fixes#11319
Currently fish errors out with
```fish
fish: Invalid redirection target:
rev <(ls)
^~~~^
```
This isn't very helpful in telling the user what they could be doing instead:
`rev (ls | psub)`.
Closes#11287
We can no longer have a single template that is always inserted. Instead
the web UI shows a menu allowing to select between one of our templates and
a blank one.
Commit f086bc9564 (Maintain ownership when rewriting universal variables
file, 2015-09-26) fixed an issue where "sudo -E fish" would create root-owned
~/.config/fish/fish_variables that break the users's shell.
A simlar issue exists for files in ~/.cache/fish; fix that.
Note that ~/.cache/fish is currently created on first run when we generate
completions from manpages.
See the issue described in #11292
Sometimes, the dirname of a completion is much longer than the basename.
When the dirname is the same for many completions, a long common dirname
prefix makes it hard to see the interesting differences in the basenames.
Fix this by collapsing the dirname prefix to "…/".
In future, we should find a generic way to collapse completions that don't
contain slashes.
Closes#8618Closes#11250
We incorrectly apply highlighting to trailing spaces that follow a command
or argument. This surfaces when the highlighting includes underline, which
is visible even on space characters.
Fix this by and have Claude add a unit test.
Co-Authored-By: Claude <noreply@anthropic.com>
Fixes#11265
In our C++ implementation, these tests were run serially. As pointed out in
https://github.com/fish-shell/fish-shell/issues/11254#issuecomment-2735623229
we run them in parallel now, which means that one test could be changing
the global locale used by another.
In theory this could be fine because all tests are setting setting the
global locale to the same thing but the existence of a lock suggests that
setlocale() is not guaranteed to be atomic, so it's possible that another
thread uses a temporarily-invalid locale.
Fixes#11254
(cherry picked from commit 1d78c8bd42)
In our C++ implementation, these tests were run serially. As pointed out in
https://github.com/fish-shell/fish-shell/issues/11254#issuecomment-2735623229
we run them in parallel now, which means that one test could be changing
the global locale used by another.
In theory this could be fine because all tests are setting setting the
global locale to the same thing but the existence of a lock suggests that
setlocale() is not guaranteed to be atomic, so it's possible that another
thread uses a temporarily-invalid locale.
Fixes#11254
Commit 8bf8b10f68 (Extended & human-friendly keys, 2024-03-30)
add bindings that obsolete the terminfo-based `bind -k` invocations.
The `bind -k` variants were still left around[^*]. Unfortunately it forgot to
add the new syntax for some special keys in Vi mode. This leads to issues if
a terminal that supports the kitty keyboard protocol sends an encoding that
differs from the traditional one. As far as I can tell, this happens when
capslock or numlock is active. Let's add the new key names and consistently
mark `bind -k` invocations as deprecated.
Fixes#11303
[^*]: Support for `bind -k` will probably be removed in a future release -
it leads to issues like https://github.com/fish-shell/fish-shell/issues/11278
where it's better to fail early.
(cherry picked from commit 733f704267)
Commit 8bf8b10f68 (Extended & human-friendly keys, 2024-03-30)
add bindings that obsolete the terminfo-based `bind -k` invocations.
The `bind -k` variants were still left around[^*]. Unfortunately it forgot to
add the new syntax for some special keys in Vi mode. This leads to issues if
a terminal that supports the kitty keyboard protocol sends an encoding that
differs from the traditional one. As far as I can tell, this happens when
capslock or numlock is active. Let's add the new key names and consistently
mark `bind -k` invocations as deprecated.
Fixes#11303
[^*]: Support for `bind -k` will probably be removed in a future release -
it leads to issues like https://github.com/fish-shell/fish-shell/issues/11278
where it's better to fail early.
We have this hack where any positional arguments are taken as argument
names if "--argument-names" is given, and that didn't check for
read-only variables.
Fixes#11295
(cherry picked from commit d203ee4d53)
We have this hack where any positional arguments are taken as argument
names if "--argument-names" is given, and that didn't check for
read-only variables.
Fixes#11295
This uses jj's dynamic completions when possible.
This avoids an annoying problem. After 04a4e5c4, jj's dynamic
completions (see the second paragraph of
<https://jj-vcs.github.io/jj/latest/install-and-setup/#command-line-completion>)
do not work very well in fish if the user puts `COMPLETE=fish jj |
source` in their `~/.config/fish/config.fish`. When the user types `jj
<TAB>`, they are instead overridden by fish's built-in non-dynamic
completions.
The difference is subtle. One problem I saw is that `jj new <TAB>` works
as expected (and shows revisions) while `jj new -A <TAB>` becomes broken
(and shows files).
If the user puts `COMPLETE=fish jj | source` in
`~/.config/fish/completions/jj.fish` there is no problem. However, users
might be confused if they run `COMPLETE=fish jj | source` or put it in
their config and it works in a broken fashion. I certainly was.
Meanwhile, I checked that if the user has `jj completion fish | source`
in their `config.fish`, executing `COMPLETE=fish jj
__this_command_does_not_exist | source` afterwards still works
correctly.
Let me know if there's a better approach to this problem.
The chances that xterm-256color breaks anything are miniscule.
In the features we use, there are basically no differences,
especially when you consider that we decode keys independently.
E.g. tmux-256color has differences, but they are either just taste
questions (xterm's clear_screen will also clear scrollback),
or they're just... not actually different?
Terminfo will claim that it uses a different cursor_up and
exit_attribute_mode, but it also understands the xterm ones,
and it sends a different key_home,
but we decode that even with TERM=xterm-256color.
In some cases, terminfo is also just outright *wrong* and will claim
something does not support italics when it does.
So, since the differences are very likely to simply not matter,
throwing a warning is more confusing than it is helpful.
(cherry picked from commit 642ec399ca)
The chances that xterm-256color breaks anything are miniscule.
In the features we use, there are basically no differences,
especially when you consider that we decode keys independently.
E.g. tmux-256color has differences, but they are either just taste
questions (xterm's clear_screen will also clear scrollback),
or they're just... not actually different?
Terminfo will claim that it uses a different cursor_up and
exit_attribute_mode, but it also understands the xterm ones,
and it sends a different key_home,
but we decode that even with TERM=xterm-256color.
In some cases, terminfo is also just outright *wrong* and will claim
something does not support italics when it does.
So, since the differences are very likely to simply not matter,
throwing a warning is more confusing than it is helpful.
Commit 29dc307111 (Insert some completions with quotes instead of backslashes,
2024-04-13) breaks some workflows. Given
touch '[test] file1'
touch '[test] file2'
ls tes<Tab>
we insert completions quoted, which is inconvenient when using globs.
This implicit quoting feature is somewhat minor. But quotes look nicer,
so let's try to keep them. Either way, users can ask for it by starting a
token with «"».
Use quoting only when we insert unique completions.
Closes#11271
(cherry picked from commit 9f79fe17fc)
Prior to this commit, the WildCardExpander had one scoped variable, leading to
the annoying "zelf" pattern. Factor this into its own object and pass it around
explicitly, to clean this up.
In C++ it's easy to make an RAII-type object like "increment a counter for
the duration of this function." Such an object might accept a pointer or
reference, increment the value, and then restore it in its destructor. We
do this all the time - for example to mark a region of code as
non-interactive, etc.
Rust makes this more awkward, because now the reference is tracked by the
borrow checker: it "owns" the object for the duration of the function. This
leads to approaches like "zelf" where the object that marks the parser as
non-interactive itself becomes the new parser, but we can't call it "self"
and it's just yucky.
In this commit we introduce a notion of the "scoped data" of the Parser,
factored out of the library data. This is data which is typically set in a
scoped fashion: whether we are a subshell, are interactive, emit fish_trace
debugging info, etc. Crucially we set this as Rc: this allow the scope
itself to share data with the Parser and we can get rid of lots of "zelf"s.
Introduce a new function `Parser::push_scope` which creates a new scope and
allows modifying these variables associated with the scope. This ends up as
a nice simplification.
As part of a plan to overhaul the "scoped_set" pattern, introduce two new
"scoped" types:
ScopedCell is a trivial wrapper around Cell which exposes a function
`scoped_mod`. This allows you to modify the contents of the Cell; the
original contents are restored when the guard is dropped.
ScopedRefCell is similar, except it requires the caller to supply an
accessor which returns a &mut field, and also the new value.
These will be used to replace the rather unsightly scoped_push calls
around the fish codebase.
This concerns completions which wrap other completions. For example, if 'tig'
wraps 'git' then for the duration of the git completions, we need to make a fake
("transient") command line which contains "git" and not "tig".
Previously we had a stack of such command lines, but we never inspected anything
except the last element. Make this a single value.
This add two commands history-last-token-search-backward and
history-last-token-search-forward which behaves like bash's yank-last-arg. So
similar to history-token-search-* but only considers the last argument for
each command.
Closes#10756Closes#11258
As seen in GitHub Actions:
132/193 Test #17: check-completions.fish ...................***Failed 16.28 sec
checks/check-completions.fish..Failure:
There were no remaining checks left to match stdout:1:
OUTPUT from /home/runner/work/fish-shell/fish-shell/share/completions/pulumi.fish: warning: A new version of Pulumi is available. To upgrade from version '3.154.0' to '3.156.0', visit https://pulumi.com/docs/install/ for manual instructions and release notes.
This makes several changes:
- All panes in the current session are now show, instead of just the
current window.
- Instead of using window names when referring to panes (e.g.
"fish-dev.1"), we now use either window indicies ("3.1") or absolute
pane ids (%12). This is mainly because several windows often share the
same window name, e.g. many of my panes are automatically named "fish"
if they are currently running the shell and nothing else.
I put the window names in the descriptions. Because fish uses the
descriptions for completions, completing `fish-dev` is still helpful.
- I include the pane name into the description for a similar reason,
truncated to 15 chars.
- The panes are now ordered carefully, with panes in this window listed
first, then panes are ordered by window, and finally panes are listed
by their id (which does not change when panes are moved between windows)
Example output after `tmux selectp -t <TAB>` for a session with a few
windows. Note that windows 0, 1, and 4 are all named
`fish`. A pane in the current window can be accessed in 3 ways: `3`,
`2.3`, or `%57`.
```
0 (%4 [fish-dev] ~/d/fish-shell <active pane>) 3.1 (%58 [fish] man tmux ~/.c/f...)
1 (%8 [fish-dev] hwatch "jj.logs... <active win.>) 4.0 (%1 [sshd] tmux rename-win...)
2 (%15 [fish-dev] /U/i/d/fish-she... <active win.>) %1 (4.0 [sshd] tmux rename-win...)
3 (%57 [fish-dev] ~/d/fish-shell <active win.>) %4 (2.0 [fish-dev] ~/d/fish-shell <active pane>)
0.0 (%100 [fish] ~) %8 (2.1 [fish-dev] hwatch "jj.logs... <active win.>)
1.0 (%11 [fish] ~/d/_/nixpkgs) %11 (1.0 [fish] ~/d/_/nixpkgs)
1.1 (%38 [fish] ~/.c/f/completi...) %15 (2.2 [fish-dev] /U/i/d/fish-she... <active win.>)
2.0 (%4 [fish-dev] ~/d/fish-shell <active pane>) %38 (1.1 [fish] ~/.c/f/completi...)
2.1 (%8 [fish-dev] hwatch "jj.logs... <active win.>) %41 (3.0 [fish] ~/.c/f/conf.d)
2.2 (%15 [fish-dev] /U/i/d/fish-she... <active win.>) %57 (2.3 [fish-dev] ~/d/fish-shell <active win.>)
2.3 (%57 [fish-dev] ~/d/fish-shell <active win.>) %58 (3.1 [fish] man tmux ~/.c/f...)
3.0 (%41 [fish] ~/.c/f/conf.d) %100 (0.0 [fish] ~)
```
Compared to before:
```
0 (pane) 2 (pane) 0:fish-dev.0 (session:window.pane) 0:fish-dev.2 (session:window.pane) fish-dev (window)
1 (pane) 3 (pane) 0:fish-dev.1 (session:window.pane) 0:fish-dev.3 (session:window.pane)
```
Note that the "before" version describes the same 3 panes several times
in a row, and all the entries involving "fish-dev" are suspect since
there could be another "fish-dev" window (or, more likely, this window
and others could all be named "fish").
Closes#11115
There are some minor updates.
Also, the syntax seems to have changed in tmux 2.4 in 2017,
ef68debc8d/CHANGES (L1484)
Notably, many of the key table commands now use `-T` in place of
the correct `-t`, and the list of key binding tables has changed.
Our versions look like
4.0.0
4.0b1
4.0.1-535-abfef-dirty
But packagers may want to add more information here, and we don't
really care. Note that we no longer ever set the version to "unknown"
since 5abd0e46f5.
Supersedes #11173
Commit 29dc307111 (Insert some completions with quotes instead of backslashes,
2024-04-13) breaks some workflows. Given
touch '[test] file1'
touch '[test] file2'
ls tes<Tab>
we insert completions quoted, which is inconvenient when using globs.
This implicit quoting feature is somewhat minor. But quotes look nicer,
so let's try to keep them. Either way, users can ask for it by starting a
token with «"».
Use quoting only when we insert unique completions.
Closes#11271
This effectively disables "--help", replacing it with just a stand-in
string.
The upshot is that it makes the test suite immune to whether or not it
can find the documentation - until now it needed to *not* find it,
which is weird.
(also it saves some useless lines)
Fixes#11270
Looks like the github actions image now has ninja installed.
This causes a failure; we effectively do
$ (
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo
)
$ make VERBOSE=1
[...]
cd build; cmake .. -G "Ninja" \
-DCMAKE_INSTALL_PREFIX="/usr/local" -DCMAKE_EXPORT_COMPILE_COMMANDS=1
Re-run cmake no build system arguments
CMake Error: Error: generator : Ninja
Does not match the generator used previously: Unix Makefiles
Either remove the CMakeCache.txt file and CMakeFiles directory or choose a different binary directory.
"make" fails because it runs from top-level, with GNUMakefile's logic to
use -GNinja if available. This is at odds with the direct cmake invocation,
which defaults to -G'Unix Makefiles'.
We shouldn't mix direct cmake invocation and the top-level Makefiles, so
run make from the build directory instead.
While at it, update some test invocations missed in 8d6fdfd9de
(Remove cmake "test" target, 2025-02-02). This should
help avoid missing test failure output in CI, see
https://github.com/fish-shell/fish-shell/issues/11116#issuecomment-2629406479
(cherry picked from commit b0be53ed6a)
The new cursor-end-mode "inclusive" (which is active in Vi mode) is causing
many issues.
One of them is because cancel-commandline wants to move to the end of the
command line before printing "^C". Since "inclusive" cursor mode prevents
the cursor from moving past the last character, that one will be overwritten
with a "^". Hack around this.
Closes#11261
(cherry picked from commit b08ff33291)
The new cursor-end-mode "inclusive" (which is active in Vi mode) is causing
many issues.
One of them is because cancel-commandline wants to move to the end of the
command line before printing "^C". Since "inclusive" cursor mode prevents
the cursor from moving past the last character, that one will be overwritten
with a "^". Hack around this.
Closes#11261
Running
fish_vi_key_bindings
fish_default_key_bindings
ought to maintain cursor shape, at least in the default configuration,
so let's do that.
Fixes 9ef76860e6 (Default Vi cursor shapes for insert/replace mode, 2024-10-26).
Looks like the github actions image now has ninja installed.
This causes a failure; we effectively do
$ (
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo
)
$ make VERBOSE=1
[...]
cd build; cmake .. -G "Ninja" \
-DCMAKE_INSTALL_PREFIX="/usr/local" -DCMAKE_EXPORT_COMPILE_COMMANDS=1
Re-run cmake no build system arguments
CMake Error: Error: generator : Ninja
Does not match the generator used previously: Unix Makefiles
Either remove the CMakeCache.txt file and CMakeFiles directory or choose a different binary directory.
"make" fails because it runs from top-level, with GNUMakefile's logic to
use -GNinja if available. This is at odds with the direct cmake invocation,
which defaults to -G'Unix Makefiles'.
We shouldn't mix direct cmake invocation and the top-level Makefiles, so
run make from the build directory instead.
While at it, update some test invocations missed in 8d6fdfd9de
(Remove cmake "test" target, 2025-02-02). This should
help avoid missing test failure output in CI, see
https://github.com/fish-shell/fish-shell/issues/11116#issuecomment-2629406479
Since commit 0627c9d9af (Render control characters as Unicode Control Pictures,
2020-08-29), we render control character in the commandline as "␇" etc.
They can be inserted via either history search, or bindings such as
bind ctrl-g "commandline -i \a"
That commit incorrectly assumes that the prompt is rendered the same way as
the command line (which goes through "ScreenData" etc).
This is wrong -- prompt text is written to stdout as-is, and a prompt that
outputs \t (tab) or \a (BEL) is valid. The wrong assumption means that we
overestimate the width of prompts containing control characters.
(For some reason, after switching from Vi insert to Vi normal mode, we seem
to get the width right which means the command line jumps around)
Let's revert to the old width computation for any prompt text.
Closes#11252
(cherry picked from commit 4d81cf8af4)
Since commit 0627c9d9af (Render control characters as Unicode Control Pictures,
2020-08-29), we render control character in the commandline as "␇" etc.
They can be inserted via either history search, or bindings such as
bind ctrl-g "commandline -i \a"
That commit incorrectly assumes that the prompt is rendered the same way as
the command line (which goes through "ScreenData" etc).
This is wrong -- prompt text is written to stdout as-is, and a prompt that
outputs \t (tab) or \a (BEL) is valid. The wrong assumption means that we
overestimate the width of prompts containing control characters.
(For some reason, after switching from Vi insert to Vi normal mode, we seem
to get the width right which means the command line jumps around)
Let's revert to the old width computation for any prompt text.
Closes#11252
For unknown reasons this assertion fails. This means that 1b9b893169 (After
reading corrupted history entry, keep reading older entries, 2024-10-06)
is not fully working. Go back to historical behavior for now.
Closes#11236
(cherry picked from commit 4f80e5cb54)
See f2dde229aa (Revert changes to restore cursor position after undo,
2025-03-05).
I think there are two problems with tmux when doing a final redraw of a
larger-than-screen commandline. One is easy to trigger independent of
f2dde229aa. The other is reproduced by the broken output in the tmux test
removed by that commit. Should root-cause them later.
Use a hack for now; this also happens to fix the broken output in tmux.
For unknown reasons this assertion fails. This means that 1b9b893169 (After
reading corrupted history entry, keep reading older entries, 2024-10-06)
is not fully working. Go back to historical behavior for now.
Closes#11236
Midnight Commander 4.8.33 knows how to read the CSI u encoding of ctrl-o
(which is the only key it reads while the shell is in control). But it fails
to when numlock or capslock is active. Let's disable the kitty keyboard
protocol again until mc indicates that this is fixed.
Closes#10640
The other issue talked about in that issue is an unrelated mc issue, see
https://github.com/MidnightCommander/mc/issues/4597#issuecomment-2705900024
* completions/flatpak: don't ignore packages with uppercase in name
`[^A-Z]+` here seems to trim header section in old version flatpak (avoid one
more `tail -n -2`?) but this can ignore packages have uppercase name like
`org.gtk.Gtk3theme.Adwaita-dark`.
* completions/flatpak: use cached `__fish_print_flatpak_packages` for `flatpak install`
rustup has changed its output for 'rustup toolchain list --verbose`.
Teach FindRust.cmake about it, so that it may shamble on.
Cherry-picked from b38551dde9
rustup has changed its output for 'rustup toolchain list --verbose`.
Teach FindRust.cmake about it, so that it may shamble on.
This was reported against BSD and also affects macOS and ALSO affects Linux; our
CI just doesn't have a new enough rustup. Anyways we can't have nice things.
This feature is nice and desirable, but it was implemented in a intrusive way
by modifying the sequence of bytes we emit when running a command; this in
turn requires changing a bunch of tests.
This sequence hasn't changed in decades and the consequences of changing it
are hard to predict, given that it is likely terminal dependent; we've
already found a regression.
It's fine to reintroduce this but it should be done in a less intrusive way
(conceptually that seems straightforward - we're just remembering the cursor
position).
Revert "Fix spurious blank lines when executing scrolled commandline"
This reverts commit 0e512f8033.
Revert "On undo after execute, restore the cursor position "
This reverts commit 610338cc70.
Most versions of fish don't run any external processes at startup, except
maybe fish_vcs_prompt. This changed recently with a couple additions of uname.
This is probably fine but I guess we can reduce it down to one.
This change feels somewhat wrong. Not sure. I guess we can remove it once
we provide $OSTYPE.
Note that this is also the reason why bindings don't use
bind alt-backspace 'if test "$(uname)" = Darwin ...'
We don't want to expose a private interface in "bind" output.
This fails with:
```
CMake Warning (dev) at cmake/FindRust.cmake:349 (message):
Unexpected output from `rustc --version` for Toolchain
`stable-x86_64-unknown-freebsd`: ``.
Ignoring this toolchain.
Call Stack (most recent call first):
cmake/Rust.cmake:5 (include)
CMakeLists.txt:24 (include)
This warning is for project developers. Use -Wno-dev to suppress it.
-- Rust Toolchain:
CMake Warning at cmake/FindRust.cmake:31 (message):
The rustc executable was not found. Rust not installed or ~/.cargo/bin not
added to path?
Hint: Consider setting `Rust_COMPILER` to the absolute path of `rustc`.
```
For some reason? Disable it for now until someone figures out what's
going on
Commit 6af96a81a8 (Default bindings for token movement commands, 2024-10-05)
has been reverted but not all docs have been.
Key bindings to move by command line argument are quite intuitive, and useful
when moving across URLs or other long arguments.
We have redundant bindings like {alt,ctrl}-left, so let's use one of them
for token movement. We don't want to break the OS-native shortcut for word
movement, so use the other one on the current platform.
Note that Sublime Text does something similar: it uses the native key
binding for word movement, and the vacant one (e.g. `alt-left` on Linux)
for sub-word movement in camel case words.
While there have been 2.5 votes against making this platform dependent,
the majority of feedback was in favor.
This uses uname which seems wrong; we should rather use the OS that the
terminal is running on. I plan to implement this in future, but there's no
consensus yet on whether terminal applications should be allowed to do this.
See #10926
See #11107
Ever since 149594f974 (Initial revision, 2005-09-20), we move the
cursor to the end of the commandline just before executing it.
This is so we can move the cursor to the line below the command line,
so moving the cursor is relevant if one presses enter on say, the
first line of a multi-line commandline.
As mentioned in #10838 and others, it can be useful to restore the
cursor position when recalling commandline from history. Make undo
restore the position where enter was pressed, instead of implicitly
moving the cursor to the end. This allows to quickly correct small
mistakes in large commandlines that failed recently.
This requires a new way of moving the cursor below the command line.
Test changes include unrelated cleanup of history.py.
(cherry picked from commit 610338cc70)
(cherry picked from commit 0e512f8033)
As reported on gitter, fish running inside a qemu console randomly fails to
recognize multi-byte sequences like "\e[D" (right); it sometimes recognizes
the first two bytes as "alt-[" and the last byte as the "D" key.
This because 8bf8b10f68 (Extended & human-friendly keys, 2024-03-30) changed
our approach to reading multi-byte key sequences. Previously, we'd wait
forever (or rather fish_sequence_key_delay_ms) for the "D" byte.
As of 8bf8b10f68, we assume the entire sequence is already present in the
input buffer; and stop parsing the sequence if stdin is not readable.
It would be more technically correct to implement the VT state machine but
then we'd probably want to to figure out a timeout or a reset key, in case
of transport or terminal issues.
Returning early is also what we have historically done for multi-byte code
points. Also, other terminal programs have been using it for many years
without problems.
I don't know why this happens in qemu but it seems we can work around by
setting a 1ms timeout. This timeout should be small enough two keys "escape"
and "[" typed by a human will still be seen separate.
Refs:
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$Cfi9wL8FGLAI6_VAQWG2mG_VxsADUPvdPB46P41Jdbshttps://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$O_-LZ1W7Dk6L_4Rj0MyCry6GtO2JQlEas8fH9PrSYT8
(cherry picked from commit e1be842167)
As reported on gitter, fish running inside a qemu console randomly fails to
recognize multi-byte sequences like "\e[D" (right); it sometimes recognizes
the first two bytes as "alt-[" and the last byte as the "D" key.
This because 8bf8b10f68 (Extended & human-friendly keys, 2024-03-30) changed
our approach to reading multi-byte key sequences. Previously, we'd wait
forever (or rather fish_sequence_key_delay_ms) for the "D" byte.
As of 8bf8b10f68, we assume the entire sequence is already present in the
input buffer; and stop parsing the sequence if stdin is not readable.
It would be more technically correct to implement the VT state machine but
then we'd probably want to to figure out a timeout or a reset key, in case
of transport or terminal issues.
Returning early is also what we have historically done for multi-byte code
points. Also, other terminal programs have been using it for many years
without problems.
I don't know why this happens in qemu but it seems we can work around by
setting a 1ms timeout. This timeout should be small enough two keys "escape"
and "[" typed by a human will still be seen separate.
Refs:
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$Cfi9wL8FGLAI6_VAQWG2mG_VxsADUPvdPB46P41Jdbshttps://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$O_-LZ1W7Dk6L_4Rj0MyCry6GtO2JQlEas8fH9PrSYT8
As reported in
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$yD_Lutaftf6ytk617kjw5vC-k_OgHRQxIiSRv89uBMI
it's weird that command name completions shadow abbreviation name
completions, given that the abbreviation will the one that will be
executed in the typical cases. Let's put abbreviation completions first;
unique_completions_retaining_order() will take care of removing any command
completions we add later.
When a command like "long-running-command &" exits, the resulting SIGCHLD
is queued in the topic monitor. We do not process this signal immediately
but only after e.g. the next command has finished. Only then do we reap the
child process.
Some terminals, such as Terminal.app, refuse to close when there are unreaped
processes associated with the terminal -- as in, having the same session ID,
see setsid(3).
In future, we might want to reap proactively.
For now, apply an isolated workaround: instead of taking care of a child
process, double-fork to create an orphaned process. Since the orphan will
be reaped by PID 1, we can eventually close Terminal.app without it asking
for confirmation.
/bin/sh -c '( "$@" ) >/dev/null 2>&1 &' -- cmd arg1 arg2
This fix confines the problem to the period during which a background process
is running. To complete the fix, we would need to call setsid to detach the
background process from a controlling terminal. That seems to be desirable
however macOS does provide a setsid utility.
setsid cmd arg1 arg2 >/dev/null 2>&1
Fixes#11181
(cherry picked from commit e015956de7)
When a command like "long-running-command &" exits, the resulting SIGCHLD
is queued in the topic monitor. We do not process this signal immediately
but only after e.g. the next command has finished. Only then do we reap the
child process.
Some terminals, such as Terminal.app, refuse to close when there are unreaped
processes associated with the terminal -- as in, having the same session ID,
see setsid(3).
In future, we might want to reap proactively.
For now, apply an isolated workaround: instead of taking care of a child
process, double-fork to create an orphaned process. Since the orphan will
be reaped by PID 1, we can eventually close Terminal.app without it asking
for confirmation.
/bin/sh -c '( "$@" ) >/dev/null 2>&1 &' -- cmd arg1 arg2
This fix confines the problem to the period during which a background process
is running. To complete the fix, we would need to call setsid to detach the
background process from a controlling terminal. That seems to be desirable
however macOS does provide a setsid utility.
setsid cmd arg1 arg2 >/dev/null 2>&1
Fixes#11181
As of 303af07, iTerm2 3.5.11 on two different machines has two different
behaviors. For unknown reasons, when pressing alt-right fish_key_reader
shows "\e\[1\;9C" on one machine and "\e\[1\;3C" on another.
Feels like iTerm2 interprets modifyOtherKeys differently, depending on
configuration.
We don't want to risk asking for the kitty
keyboard protocol until iTerm2 3.5.12 (see
https://github.com/fish-shell/fish-shell/issues/11004#issuecomment-2571494782).
So let's work around around this weirdness by adding back the legacy
bindings removed in c0bcd817ba (Remove obsolete bindings, 2024-04-28) and
plan to remove them in a few years.
Note that fish_key_reader still reports this as "left", which already has
a different binding, but it looks like literal matches of legacy sequences
have precedence.
Fixes the problem described in
https://github.com/fish-shell/fish-shell/issues/11192#issuecomment-2692247060Closes#11192
(cherry picked from commit 44d5abdc05)
Before 798527d79a (completions: fix double evaluation of tokenized commandline, 2024-01-06)
git-foo completions did something like
set -l subcommand_args (commandline -opc)
complete -C "git-foo $subcommand_args "
As mentioned in 368017905e (builtin commandline: -x for expanded tokens,
supplanting -o, 2024-01-06), the "-o" option is bad
because it produces a weird intermediate, half-expanded state.
The immediate goal of 798527d79a was to make sure we do not do any
more expansion on top of this. To that end, it changed the above to
"\$subcommand_args". The meaning is more or less the same[^*] but crucially,
the recursive completion invocation does not see through the variable,
which breaks some completions.
Fix this with the same approach as in 6b5ad163d3 (Fix double expansion of
tokenized command line, 2025-01-19).
[^*]: It wasn't semantically correct before or after -- this was later
corrected by 29f35d6cdf (completion: adopt commandline -x replacing deprecated
-o, 2024-01-22)).
Closes#11205
(cherry picked from commit 50e595503e)
As of 303af07, iTerm2 3.5.11 on two different machines has two different
behaviors. For unknown reasons, when pressing alt-right fish_key_reader
shows "\e\[1\;9C" on one machine and "\e\[1\;3C" on another.
Feels like iTerm2 interprets modifyOtherKeys differently, depending on
configuration.
We don't want to risk asking for the kitty
keyboard protocol until iTerm2 3.5.12 (see
https://github.com/fish-shell/fish-shell/issues/11004#issuecomment-2571494782).
So let's work around around this weirdness by adding back the legacy
bindings removed in c0bcd817ba (Remove obsolete bindings, 2024-04-28) and
plan to remove them in a few years.
Note that fish_key_reader still reports this as "left", which already has
a different binding, but it looks like literal matches of legacy sequences
have precedence.
Fixes the problem described in
https://github.com/fish-shell/fish-shell/issues/11192#issuecomment-2692247060Closes#11192
Before 798527d79a (completions: fix double evaluation of tokenized commandline, 2024-01-06)
git-foo completions did something like
set -l subcommand_args (commandline -opc)
complete -C "git-foo $subcommand_args "
As mentioned in 368017905e (builtin commandline: -x for expanded tokens,
supplanting -o, 2024-01-06), the "-o" option is bad
because it produces a weird intermediate, half-expanded state.
The immediate goal of 798527d79a was to make sure we do not do any
more expansion on top of this. To that end, it changed the above to
"\$subcommand_args". The meaning is more or less the same[^*] but crucially,
the recursive completion invocation does not see through the variable,
which breaks some completions.
Fix this with the same approach as in 6b5ad163d3 (Fix double expansion of
tokenized command line, 2025-01-19).
[^*]: It wasn't semantically correct before or after -- this was later
corrected by 29f35d6cdf (completion: adopt commandline -x replacing deprecated
-o, 2024-01-22)).
Closes#11205
Given
$ cat ~/.config/kitty/kitty.conf
notify_on_cmd_finish unfocused 0.1 command notify-send "job finished with status: %s" %c
kitty will send a notification whenever a long-running (>.1s) foreground
command finishes while kitty is not focused.
The %c placeholder will be replaced by the commandline.
This is passed via the OSC 133 command start marker, kitty's fish shell
integration.
That integration has been disabled for fish 4.0.0 because it's no longer
necessary since fish already prints OSC 133. But we missed the parameter for
the command string. Fix it. (It's debatable whether the shell or the terminal
should provide this feature but I think we should fix this regression?)
Closes#11203
See https://github.com/kovidgoyal/kitty/issues/8385#issuecomment-2692659161
(cherry picked from commit 4378e73fc7)
Something like
write!(f, "foo{}bar", ...)
seems to call f.write_str() thrice.
Splitting a single OSC 133 command into three calls to write(3) might result in
odd situations if one of them fails. Let's try to do it in one in most cases.
Add a new buffered output type that can be used with write!(). This is
somewhat redundant given that we have scoped_buffer(). While at it, remove
the confused error handling. This doesn't fail unless we are OOM (and this
new type makes that more obvious).
(cherry picked from commit e5e932e970)
Given
$ cat ~/.config/kitty/kitty.conf
notify_on_cmd_finish unfocused 0.1 command notify-send "job finished with status: %s" %c
kitty will send a notification whenever a long-running (>.1s) foreground
command finishes while kitty is not focused.
The %c placeholder will be replaced by the commandline.
This is passed via the OSC 133 command start marker, kitty's fish shell
integration.
That integration has been disabled for fish 4.0.0 because it's no longer
necessary since fish already prints OSC 133. But we missed the parameter for
the command string. Fix it. (It's debatable whether the shell or the terminal
should provide this feature but I think we should fix this regression?)
Closes#11203
See https://github.com/kovidgoyal/kitty/issues/8385#issuecomment-2692659161
Something like
write!(f, "foo{}bar", ...)
seems to call f.write_str() thrice.
Splitting a single OSC 133 command into three calls to write(3) might result in
odd situations if one of them fails. Let's try to do it in one in most cases.
Add a new buffered output type that can be used with write!(). This is
somewhat redundant given that we have scoped_buffer(). While at it, remove
the confused error handling. This doesn't fail unless we are OOM (and this
new type makes that more obvious).
modifyOtherKeys with non-English or other non-default keyboard layouts will
cause wrong keys to be sent by WezTerm. Let's try to disable it for now.
Proposed upstream fix: https://github.com/wezterm/wezterm/pull/6748Closes#11204
wine can be used, and is usually used for things like `wine
setup.exe`,
so it should allow for regular file completion.
Fixes#11202
(cherry picked from commit 86e531b848)
This was broken for 4.0 because it used `{}` command grouping.
Instead just do one of the things the fish_git_prompt does.
(the default isn't usable here because it gets the sha from elsewhere)
(cherry picked from commit e925eccad2)
This was broken for 4.0 because it used `{}` command grouping.
Instead just do one of the things the fish_git_prompt does.
(the default isn't usable here because it gets the sha from elsewhere)
Fix the accidental "git branch" output leaking while making sure we support:
1. unborn branch, where HEAD does not exist (`git init`)
2. detached head (`git checkout --detach`)
Notably computing the branch name should be independent of computing
a diff against HEAD.
In scenario 1 there is a branch but no HEAD,
while in scenario 2 it's the other way round.
Hence we need a separate check to see if we're in a git repo.
"git rev-parse" seems to work. Not sure what's best pracitce.
Also remove the ahead/behind logic, it was broken because it misspelled
@{upstream}.
Fixes#11179
(cherry picked from commit 7b7e744353)
Fix the accidental "git branch" output leaking while making sure we support:
1. unborn branch, where HEAD does not exist (`git init`)
2. detached head (`git checkout --detach`)
Notably computing the branch name should be independent of computing
a diff against HEAD.
In scenario 1 there is a branch but no HEAD,
while in scenario 2 it's the other way round.
Hence we need a separate check to see if we're in a git repo.
"git rev-parse" seems to work. Not sure what's best pracitce.
Also remove the ahead/behind logic, it was broken because it misspelled
@{upstream}.
Fixes#11179
As reported in
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$CLuoHTdvcRj_8-HBBq0p-lmGWeix5khEtKEDxN2Ulfo
Running
fish -C '
fzf_key_bindings
echo fish_vi_key_bindings >>~/.config/fish/config.fish
fzf-history-widget
'
and pressing "enter" will add escape sequences like "[2 q" (cursor shape)
to fish's command line.
This is because fzf-history-widget binds "enter" to a filter
that happens to be a fish script:
set -lx FZF_DEFAULT_OPTS \
... \
"--bind='enter:become:string replace -a -- \n\t \n {2..} | string collect'" \
'--with-shell='(status fish-path)\\ -c)
The above ~/.config/fish/config.fish (redundantly) runs "fish_vi_key_bindings"
even in *noninteractive* shells, then "fish_vi_cursor" will print cursor
sequences in its "fish_exit" handler. The sequence is not printed to the
terminal but to fzf which doesn't parse CSI commands.
This is a regression introduced by a5dfa84f73 (fish_vi_cursor: skip if stdin
is not a tty, 2023-11-14). That commit wanted "fish -c read" to be able to
use Vi cursor. This is a noninteractive shell, but inside "read" we are
"effectively interactive". However "status is-interactive" does not tell
us that.
Let's use a more contained fix to make sure that we print escape sequences only
if either fish is interactive, or if we are evaluating an interactive read.
In general, "fish -c read" is prone to configuration errors, since we
recommend gating configuration (for bind etc) on "status is-interactive"
which will not run here.
(cherry picked from commit 495083249b)
As reported in
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$CLuoHTdvcRj_8-HBBq0p-lmGWeix5khEtKEDxN2Ulfo
Running
fish -C '
fzf_key_bindings
echo fish_vi_key_bindings >>~/.config/fish/config.fish
fzf-history-widget
'
and pressing "enter" will add escape sequences like "[2 q" (cursor shape)
to fish's command line.
This is because fzf-history-widget binds "enter" to a filter
that happens to be a fish script:
set -lx FZF_DEFAULT_OPTS \
... \
"--bind='enter:become:string replace -a -- \n\t \n {2..} | string collect'" \
'--with-shell='(status fish-path)\\ -c)
The above ~/.config/fish/config.fish (redundantly) runs "fish_vi_key_bindings"
even in *noninteractive* shells, then "fish_vi_cursor" will print cursor
sequences in its "fish_exit" handler. The sequence is not printed to the
terminal but to fzf which doesn't parse CSI commands.
This is a regression introduced by a5dfa84f73 (fish_vi_cursor: skip if stdin
is not a tty, 2023-11-14). That commit wanted "fish -c read" to be able to
use Vi cursor. This is a noninteractive shell, but inside "read" we are
"effectively interactive". However "status is-interactive" does not tell
us that.
Let's use a more contained fix to make sure that we print escape sequences only
if either fish is interactive, or if we are evaluating an interactive read.
In general, "fish -c read" is prone to configuration errors, since we
recommend gating configuration (for bind etc) on "status is-interactive"
which will not run here.
Historically, up-arrow search matches have been highlighted by
1. using the usual foreground (from syntax highlighting)
2. using the background from $fish_color_search_match
Commit 9af6a64fd2 (Fix bad contrast in search match highlighting, 2024-04-15)
broke this by also applying the foreground from $fish_color_search_match.
As reported on gitter, there is a meaningful scenario where the foreground
from syntax highlighting should not be overwritten:
set fish_color_search_match --reverse
this copies the foreground from syntax highlighting to the background.
Since commit 9af6a64fd2 overwrites the foreground highlight, the resulting
background will be monocolored (black in my case) instead of whatever is
the syntax-colored foreground.
FWIW the reversed foreground will always be monocolored, because we have
always done 2.
Let's unbreak this scenario by using the foreground from
fish_color_search_match only if it's explicitly set (like we do since
9af6a64fd2).
This is hacky because an empty color is normally the same as "normal", but
it gets us closer to historical behavior. In future we should try to come
up with a better approach to color blending/transparency.
(cherry picked from commit b6269438e9)
Historically, up-arrow search matches have been highlighted by
1. using the usual foreground (from syntax highlighting)
2. using the background from $fish_color_search_match
Commit 9af6a64fd2 (Fix bad contrast in search match highlighting, 2024-04-15)
broke this by also applying the foreground from $fish_color_search_match.
As reported on gitter, there is a meaningful scenario where the foreground
from syntax highlighting should not be overwritten:
set fish_color_search_match --reverse
this copies the foreground from syntax highlighting to the background.
Since commit 9af6a64fd2 overwrites the foreground highlight, the resulting
background will be monocolored (black in my case) instead of whatever is
the syntax-colored foreground.
FWIW the reversed foreground will always be monocolored, because we have
always done 2.
Let's unbreak this scenario by using the foreground from
fish_color_search_match only if it's explicitly set (like we do since
9af6a64fd2).
This is hacky because an empty color is normally the same as "normal", but
it gets us closer to historical behavior. In future we should try to come
up with a better approach to color blending/transparency.
(This regressed in version 4 which sends OSC 7 to all terminals)
Konsole has a bug: it does not recognize file:://$hostname/path as directory.
When we send that via OSC 7, that breaks Konsole's "Open Folder With"
context menu entry.
OSC 7 producers are strongly encouraged to set a non-empty hostname, but
it's not clear if consumers are supposed to accept an empty hostname (see
https://gitlab.freedesktop.org/terminal-wg/specifications/-/issues/20).
I think it should be fine; implementations should treat it as local path.
Let's work around the Konsole bug by omitting the hostname for now. This
may not be fully correct when using a remote desktop tool to access a
system running Konsole but I guess that's unlikely and understandable.
We're using KONSOLE_VERSION, so it the workaround should not leak into SSH
sessions where a hostname component is important.
Closes#11198
Proposed upstream fix https://invent.kde.org/frameworks/kio/-/merge_requests/1820
(cherry picked from commit c926a87bdb)
Konsole has a bug: it does not recognize file:://$hostname/path as directory.
When we send that via OSC 7, that breaks Konsole's "Open Folder With"
context menu entry.
OSC 7 producers are strongly encouraged to set a non-empty hostname, but
it's not clear if consumers are supposed to accept an empty hostname (see
https://gitlab.freedesktop.org/terminal-wg/specifications/-/issues/20).
I think it should be fine; implementations should treat it as local path.
Let's work around the Konsole bug by omitting the hostname for now. This
may not be fully correct when using a remote desktop tool to access a
system running Konsole but I guess that's unlikely and understandable.
We're using KONSOLE_VERSION, so it the workaround should not leak into SSH
sessions where a hostname component is important.
Closes#11198
Proposed upstream fix https://invent.kde.org/frameworks/kio/-/merge_requests/1820
As reported in b5736c5535 (Extend iTerm CSI u workaround to < 3.5.12,
2025-02-20), iTerm 3.5.12 has resolved our issues related to the kitty
keyboard protocol. Enable it here too, matching the release branch.
The flag to gate this is set for versions of iTerm that don't have sufficient
support for the kitty keyboard protocol. CSI u is (more or less) the encoding
used by that protocol. Let's name things accordingly. My bad.
Commit 2d234bb676 (Only request keyboard protocols once we know if kitty kbd
is supported, 2025-01-26) queries support for the kitty protocol and acted
upon it after having read next character.
Unfortunately this meant that we don't turn on the kitty protocol until after
we read a character -- since the CSI ? u response does not generate a char
event. Let's query for primary DA additionally, matching what fish does.
In future, we should do a timed wait as well, to avoid terminal responses
leaking when there we exit fish_key_reader too quickly.
Whenever we add logic to print a control sequence that we hadn't printed
before, there is a nonzero risk that a terminal mishandles it.
Terminal-specific workarounds cause pain but are probably better than not
being able to use any new commands provided by terminals.
There is no universal way to identify a terminal. Device attributes (primary
through tertiary) typically get spoofed responses, likely not good enough
for working around bugs in specific versions of a terminal.
The de-facto standard for the terminal name and version is XTVERSION.
It's usually specific to the terminal, except for something like VTE-based
terminals, where we get this (which seems good enough also)
printf '\x1b[>0q'; cat
^[P>|VTE(7803)^[\
Of course querying for XTVERSION can trigger terminal bugs just as well. Let's
start querying for it now -- even without a concrete use case -- to increase
the chance we can use it during crunch time when we don't want to test
anymore. (We typically discover buggy terminals only very late in the release
cycle, most prominently after a release).
When we enable/disable terminal protocols,
we use atomic operations because of issues like
1. halfway through enabling, we might be interrupted by a signal handler.
2. our SIGTERM handler runs the (idempotent) disabling sequences,
so the operations must be async-signal safe.
The flags to keep track of whether things like kitty keyboard protocol are enabled
are "mirrored" between the enabling and disabling logic:
- the enabling logic marks it as enabled *before* enabling anything
- the disabling logic marks it as disabled *after* everything has been disabled
This ensures that we are well-behaved in issue 1; we will always (perhaps
redundantly) disable the kitty keyboard protocol.
We forgot to use the same ordering for bracketed paste.
If we get SIGTERM after this line
BRACKETED_PASTE.store(false, Ordering::Release);
we might exit with bracketed paste still turned on.
Code blocks are often written like
$ echo hello world
hello world
The "$ " is widely understood to introduce a shell command. It's often
easier to copy the whole line than copying everything after "$ ".
This gets more pronounced when there are multiple commands without interleaved
output (either due to omission or the rule of silence). Copying the whole
code block is the most natural first step.
You could argue that this is a presentation issue - the dollar prefix
should be rendered but not copied to clipboard. But in my experience there
are many cases where there is no HTML or Javascript that would allow the
copy-to-clipboard functionality to strip the prefixes.
The "$ " prefix is almost never useful when pasting; strip it automatically.
Privileged commands use "# " as prefix which overlaps with comments, so do
not strip that until we can disambiguate (another potential reason not to
do that would be safety but it's unclear if that really matters).
Add the new logic to the commandline builtin, because we don't know about the
AST in fish script. (Technically, the tokenizer already knows whether a "$
" is in command position and at the beginning of a line, but we don't
have that either (yet).)
Maybe we should move the rest of __fish_paste over as well. I'm not sure what
difference that would make; for one, pasting could no longer be cancelled
by ctrl-c (in theory), which seems like a good direction?
Comments by macOS users have shown that, apparently, on that platform
this isn't wanted.
The functions are there for people to use,
but we need more time to figure out if and how we're going to bind
these by default.
For example, we could change these bindings depending on the OS in future.
This reverts most of commit 6af96a81a8.
Fixes#10926
See #11107
(cherry picked from commit 378f452eaa)
This can happen if your filesystem on macOS has xattrs, so the newly
created dirs will also have them and `ls` will print an "@" indicator.
Fixes#11137
(cherry picked from commit 414293521e)
The majority of users will be going straight from 3.7 to 4.0. The 4.0 notes
should reflect this transition, rather than the changes that were only in 4.0b1.
iTerm has a bug where it'll send Option-Left as Left instead of the
proper Alt-Left. This was reported upstream and fixed in
480f059bce
which is contained in the 3.5.12-beta2 tag, so let's assume that fixes
it.
Fixes#11025
(not necessary in 4.1)
parse_util_lineno() returns 1-based line numbers but
parse_util_get_offset_from_line() expects zero based line offsets.
Fixes#11162
(cherry picked from commit afbdb9f268)
Commit 4f536d6a9b (Update commandline state snapshot lazily,
2024-04-13) add an optimization to update the search field only if
necessary. The optimization accidentally prevents us from resetting
the search field.
Fixes#11161
(cherry picked from commit 72f2433120)
Commit 4f536d6a9b (Update commandline state snapshot lazily,
2024-04-13) add an optimization to update the search field only if
necessary. The optimization accidentally prevents us from resetting
the search field.
Fixes#11161
These are supposed to be small, so we dump the redundant fish_indent
and fish_key_reader - the fish binary can do those jobs too (both as
builtins and if called via symlinks of that name).
We still keep tarballs instead of just compressing so that we have a
file called "fish" and not "fish-amd64-linux"
Custom formats for --pretty/--format option can only be written in [pretty]
section, thus only this section is searched.
[ja: add ? to the regex]
Closes#11065
(cherry picked from commit dfa77e6c19)
Commit 82c4896809 (Fix unnecessary undo when exiting the history
pager with an empty cmd and no matches, 2025-02-02) was a nice fix
but failed to account for the code path where we switch from history
search to completion pager (and maybe also the inverse case). In this
case we don't want to undo the transient edit but commit it instead.
To work around terminal bugs.
The flag "keyboard-protocols" defaults to "on" and enables keyboard protocols,
but can be turned off by setting "no-keyboard-protocols".
This has downsides as a feature flag - if you use multiple terminals and
one of them can't do it you'll have to disable it in all,
but anything else would require us to hook this up to env-dispatch,
and ensure that we turn the protocols *off* when the flag is disabled.
Since this is a temporary inconvenience, this would be okay to ask
zellij and Jetbrains-with-WSL users.
Missed write_to_fd calls
Not in 4.0 because fish_indent isn't a builtin there.
This requires str2wcstring, which is awkward but it's not performance-sensitive.
Fixes#11146
I'm running fish 4.0b1 locally and I tried running `help abbr` and
browsing the docs. I noticed one example which wasn't formatted
correctly.
I'm not too familiar with rst, but based on looking at the file, it
seems that this is how example code should be represented.
(cherry picked from commit d47a4899b4)
I'm running fish 4.0b1 locally and I tried running `help abbr` and
browsing the docs. I noticed one example which wasn't formatted
correctly.
I'm not too familiar with rst, but based on looking at the file, it
seems that this is how example code should be represented.
e697add5b5 (Feature flag to prevent executing off buffered keys, 2025-01-02)
breaks my expectations/habits, and it breaks Midnight Commander.
Additionally, I'm not aware of any case where it actually adds security.
We generally assume that terminal echoback sequences do not contain
control characters except for well-known escape sequences.
This backs out commit e697add5b5.
See #10987, #10991
This can happen if your filesystem on macOS has xattrs, so the newly
created dirs will also have them and `ls` will print an "@" indicator.
Fixes#11137
alt-{left,right} move in the directory history (like in browsers).
Arrow keys can be inconvenient to reach on some keyboards, so
let's alias this to alt-{b,f}, which already have similar behavior.
(historically the behavior was the same; we're considering changing
that back on some platforms).
This happens to fix alt-{left,right} in Terminal.app (where we had
a workaround for some cases), Ghostty, though that alone should not
be the reason for this change.
Cherry-picked from commit f4503af037.
Closes#11105
alt-{left,right} move in the directory history (like in browsers).
Arrow keys can be inconvenient to reach on some keyboards, so
let's alias this to alt-{b,f}, which already have similar behavior.
(historically the behavior was the same; we're considering changing
that back on some platforms).
This happens to fix alt-{left,right} in Terminal.app (where we had
a workaround for some cases), Ghostty, though that alone should not
be the reason for this change.
Closes#11105
Add back the test from 0e512f8033 (Fix spurious blank lines when
executing scrolled commandline, 2025-01-08).
It's flaky in CI (see b8208d72f7 (Remove test for broken tmux output,
2025-01-09)) but that's not a problem for now because we disabled
the entire test CI in 2508cc9de6 (Disable some more tests under CI,
2025-01-14).
Commit c54131c8c5 (Make at least one character of the autosuggestion
always shown, 2025-01-26) draws autosuggetion until exactly the end
of the line, possibly truncated by an ellipsis. The line is "barely"
soft-wrapped; no characters or cursors are on the next line.
This means that the pager can start there (on the next line).
The calculation for available pager height fails to recognize that.
Fix that.
Comments by macOS users have shown that, apparently, on that platform
this isn't wanted.
The functions are there for people to use,
but we need more time to figure out if and how we're going to bind
these by default.
For example, we could change these bindings depending on the OS in future.
This reverts most of commit 6af96a81a8.
Fixes#10926
See #11107
Prior to this change, wcstod_underscores would create a "pruned" string without
underscores, and then parse that. Switch instead to a filtered Iterator, which
can ignore underscores as it traverses the string.
Add a test that completes in a reasonable time only if wcstod_underscores is not
quadratic.
(cherry picked from commit b4577c10e5cf9239bc93c605f431a56d98266a1e)
Currently, when the history pager is selected, fish always one undo away from the original search term. If the search has no matches, the fish replaces the search term with itself (resulting in no visible change, but it is still treated as a transient edit). However, fish ignores undo operations where the replacement is "" by "", leading to an unnecessary undo. For example:
1. Type 'test'.
2. Do ctrl-c.
3. Open the history pager.
4. Make so there are no matches.
5. Exit - you will undo back to 'test'.
This commit also ensures that if you select a pager element that does not change the content of the commandline, it will not be added to the undo history.
Currently, if we return to the present, fish thinks that it still has a transient edit. This results in an unnecessary undo when performing a backward search. For example:
1. Type ': '.
2. Do a backward token search.
3. Do a forward token search.
4. Do another backward token search - this will result in the undo of ': '.
Currently, the search always restarts when moving from the present.
For example:
1. Do a few backward searches.
2. Use PageDown to return to the present.
3. Do another backward search.
4. Now, PageUp does nothing because the search was restarted, even if we maintained search mode.
This can no longer be overridden, which means we have a broken "test"
target now. Instead, you need to call "make fish_run_tests".
Blergh.
Fixes#11116
(cherry picked from commit 8d6fdfd9de)
This adds the ability to complete (and therefore preview) buffer names,
and adds incomplete (aiming to maximize utility/effort, similarly to
b1064ac) bindings to the `tmux` buffer commands.
The main benefit is, IMO, is the tab completion for `tmux paste-buffer
-b` and `tmux show-buffer -b`.
Every reader gets their own wait handle which is wrong and not actually
needed - it's a singleton. We should probaly make it global. Let's
do an intermediate solution for now -- not much time this weekend ;).
Fixes#11110
There is no guarantee that Write::write() will write the entirety of the
provided buffer in one go, regardless of how short it is, because that depends
on the semantics of the underlying write handle (even if it was a
single byte, though in this case that would be because of an interrupt).
The only case I'm aware of that would guarantee a single Write::write() call
would suffice is when writing into a high-level memory-backed buffer, and we
can't make that guarantee (now or in perpetuity).
The current limit can be reached in actual use and still be a usable shell.
E.g. in #11095 someone had `git status` print over 100MiB of file
information.
This isn't propagated correctly:
If $fish_read_limit is set globally, it won't apply to the completion
command substitution, *unless* you set fish_read_limit inside of that
function.
I'm not entirely sure how that happens, but let's work around it for
now by removing that limit.
I'm going to increase the default limit in a future commit, because
it's not something supposed to be reachable in ordinary code.
See #11106
Previously, there were situations where an autosuggestion existed but was not shown at all. This commit guarantees that at least the `ellipsis_char` is shown, regardless of the situation.
This commit ensures that autosuggestions cannot soft wrap. Previous behavior:
- If the first line is not soft wrapped, the autosuggestion will be truncated and not shown on soft-wrapped lines.
- If the first line is soft-wrapped, the autosuggestion will not have any limit.
The right prompt was rendered even if scrolled.
The command line wasn't rendering on the first line, starting from 0 to the left prompt length. Steps to reproduce:
fish -C 'bind ctrl-g \'commandline $(printf %0"$(math $COLUMNS)"d0) $(seq $(math $LINES - 1))\''
# use ctrl-g
# observe that only one '0' is rendered
When drawing a soft wrapped line, the last 2 characters of the previous line are redrawn. If these 2 characters are occupied by the prompt, they are replaced with ' '.
Steps to reproduce:
fish -C 'function fish_prompt; printf %0"$(math $COLUMNS)"d 0; end'
# type anything
# observe that the last two characters of the prompt have been deleted
We need to add a line to the desired screen if the previous line was full or non-existent to prevent the pager from being drawn on empty soft wrapped or new lines.
Steps to reproduce:
fish -C '
function fish_prompt; printf \>; end
bind ctrl-g \'commandline "ls $(printf %0"$(math $COLUMNS - 5)"d 0) "\''
# use ctrl-g and tab
# observe that the pager starts on the line with the cursor
If the prompt occupies the full width of the first line, each new line will soft wrap, leaving empty lines between. This change removes the indentation that matches the start of the line to the end of the prompt if the prompt width equals the terminal width.
Steps to reproduce:
fish -C 'function fish_prompt; printf %0"$COLUMNS"d 0; end'
# type "begin" and Enter
# observe that there was a spurious empty line
To check:
```fish
fish_config theme choose None
set -g fish_pager_color_selected_completion blue
```
Now the selected color will only apply to the parentheses
Missed in 43e2d7b48c (Port pager.cpp)
(cherry picked from commit 6c4d658c15)
To check:
```fish
fish_config theme choose None
set -g fish_pager_color_selected_completion blue
```
Now the selected color will only apply to the parentheses
Missed in 43e2d7b48c (Port pager.cpp)
The version where a feature became the default is now described inline,
to make it a single source of truth. I could have fixed the other
section where this was described, but this seemed easier.
I also removed a few details that seem no longer relevant.
(cherry picked from commit 064d867873)
Commit f36f757fa6 (Never rewrite history file when adding ephemeral
items, 2024-10-06) has a glaring bug: when adding to history ephemeral
items that has potential paths, we fail to re-enable automatic saving,
which effectively disables automatic saving for the entire session.
Only a call to history::save_all() at exit saves us from losing data.
But until exit, other fish will see our history (unless we run history
save/merge or similar).
Fix the imbalanced enable/disable and restructure the code a bit.
Also, extend the change from f36f757fa6 (never vacuum on ephemeral
items) to private mode.
The version where a feature became the default is now described inline,
to make it a single source of truth. I could have fixed the other
section where this was described, but this seemed easier.
I also removed a few details that seem no longer relevant.
This documents some non-argument options for the window and panes
commands. The choice of what to document is somewhat arbitrary,
this commit is biased towards options that I find confusing or
misleading without documentation (is `-a` "all" or "after"?)
and the command that seem more useful to me.
I also didn't cover the options that would be covered by
#10855 (though this PR can be used independently). I'm not
sure how much difference this made, it might not matter at
all.
(cherry picked from commit f241187c4a)
These dynamic completions are exhaustive, but not as well-documented or
as ergonomic as the manual completions. So, any manual completions
should override them.
(cherry picked from commit 183e20cc3a)
For example, `tmux shell<tab>` now completes to `if-shell` and
`run-shell`, though no additional information is provided.
(cherry picked from commit 27e5ed7456)
This documents some non-argument options for the window and panes
commands. The choice of what to document is somewhat arbitrary,
this commit is biased towards options that I find confusing or
misleading without documentation (is `-a` "all" or "after"?)
and the command that seem more useful to me.
I also didn't cover the options that would be covered by
#10855 (though this PR can be used independently). I'm not
sure how much difference this made, it might not matter at
all.
These dynamic completions are exhaustive, but not as well-documented or
as ergonomic as the manual completions. So, any manual completions
should override them.
This used to get all the interfaces and ssids when the completions
were loaded. That's obviously wrong, given that ssids especially can, you know, change
This uses `git ls-files`, which has a simpler format (just the
filenames on separate lines), in order to print the untracked files.
This allows us to skip them in the `git status` call, which reduces
the output a lot and removes two `string match`.
In a repository with over half a million files (my home directory, if
I made it one), this improves time by a third (12s to 8s).
In a smaller repo (fish-shell) it's barely measurable.
This is consistent with what we do for highlighting history search,
see d7354880e3 (Fix regression causing crash in token history search,
2025-01-27). In future, we should try to find a better fix (and a
better test).
Fixes the other problem described in #11096
Determine if untracked files are off via `__fish_git`, so we get the
repo used on the commandline etc,
and if it isn't, at least don't error out. Yes, this *can* print a
hundred megabytes of filenames.
The two terminals Midnight Commander and dvtm are special in that
they filter requests (or perhaps responses) like
printf "\x1b[0c"
and don't implement the response themselves -- so we never get
one. Let's work around that until we can fix it.
Disable the kitty protocol in mc for now (to keep the code simple),
though we could certainly re-enable it.
Fixes 64859fc242 (Blocking wait for responses to startup queries, 2025-01-25).
`git add` may have to go through literal megabytes of file information
because of tons of untracked files.
So, if the repository is set to not show untracked files (because it's
too slow for the prompt), let's fall back on regular file completions.
(the alternative is to go back to `while read`, but that takes much
longer in repositories of a sensible size)
Fixes#11095
This was copied from C++ code but we have overflow checks, which
forces us to actually handle errors.
While at it, add some basic error logging.
Fixes#11092
Today we might
1. enable modifyOtherKeys
2. get a reply indicating the kitty keyboard protocol is supported
3. because of 2, we never turn off modifyOtherKeys again
Let's get rid of this weird issue by enabling either modifyOtherKeys
or the kitty enhancements only after we know whether the kitty protocol
is supported.
This means we need to call terminal_protocols_enable_ifn() before every
call to readch() until the querying is done. Fortunately, this is
already in place in read_normal_chars(); there are other places that
call readch() but none of those is executed until querying has completed.
At startup we query for
- the cursor position (CSI 6 n)
- kitty keyboard protocol support (CSI ? u)
- terminfo capabilities via XTGETTCAP
Since we don't wait for responses, those can leak into child processes.
Some child processes like fzf cannot decode DCS replies. Plug the
leak by ending each round of querying by asking for the Primary Device
Attribute, and resume input processing only after a response has been
received, (or ctrl-c as an escape hatch).
This is a nice simplification. Tested with the lowest common
denominator (putty, Terminal.app and st).
Fixes#11079
The st terminal wrongly parses CSI ? u as DECRC. A fix has been
proposed upstream. Let's also work around it I guess (not to mention
that querying in the first place is also sort of a workaround).
If you don't care about file paths containing '=' or ':', you can
stop reading now.
In tokens like
env var=/some/path
PATH=/bin:/usr/local/b
file completion starts after the last separator (#2178).
Commit db365b5ef8 (Do not treat \: or \= as file completion anchor,
2024-04-19) allowed to override this behavior by escaping separators,
matching Bash.
Commit e97a4fab71 (Escape : and = in file completions, 2024-04-19)
adds this escaping automatically (also matching Bash).
The automatic escaping can be jarring and confusing, because separators
have basically no special meaning in the tokenizer; the escaping is
purely a hint to the completion engine, and often unnecessary.
For "/path/to/some:file", we compute completions for "file" and for
"/path/to/some:file". Usually the former already matches nothing,
meaning that escaping isn't necessary.
e97a4fab71 refers us to f7dac82ed6 (Escape separators (colon and
equals) to improve completion, 2019-08-23) for the original motivation:
$ ls /sys/bus/acpi/devices/d<tab>
$ ls /sys/bus/acpi/devices/device:
device:00/ device:0a/ …
Before automatic escaping, this scenario would suggest all files from
$PWD in addition to the expected completions shown above.
Since this seems to be mainly about the case where the suffix after
the separator is empty,
Let's remove the automatic escaping and add a heuristic to skip suffix
completions if:
1. the suffix is empty, to specifically address the above case.
2. the whole token completes to at least one appending completion.
This makes sure that "git log -- :!:" still gets completions.
(Not sure about the appending requirement)
This heuristic is probably too conservative; we can relax it later
should we hit this again.
Since this reverts most of e97a4fab71, we address the code clone
pointed out in 421ce13be6 (Fix replacing completions spuriously quoting
~, 2024-12-06). Note that e97a4fab71 quietly fixed completions for
variable overrides with brackets.
a=bracket[
But it did so in a pretty intrusive way, forcing a lot of completions
to become replacing. Let's move this logic to a more appropriate place.
---
Additionally, we could sort every whole-token completion before every
suffix-completion. That would probably improve the situation further,
but by itself it wouldn't address the immediate issue.
Closes#11027
(cherry picked from commit b6c249be0c)
Mainly to make the next commit's diff smaller. Not much functional
change: since file completions never have the DONT_SORT flag set,
these results will be sorted, and there are no data dependencies --
unless we're overflowing the max number of completions. But in that
case the whole-token completions seem more important anyway.
(cherry picked from commit 0cfc95993a)
Commit 798527d79a (completions: fix double evaluation of tokenized
commandline, 2024-01-06) fixed some completions such as the "watchexec"
ones by adding "string escape" here:
set argv (commandline -opc | string escape) (commandline -ct)
This fixed double evaluation when we later call `complete -C"$argv"`.
Unfortunately -- searching for "complete -C" and
"__fish_complete_subcommand" -- it seems like that commit missed some
completions such as sudo. Fix them the same way.
Alternatively, we could defer expansion of those arguments (via
--tokens-raw), since the recursive call to completion will expand
them anyway, and we don't really need to know their value.
But there are (contrived) examples where we do want to expand first,
to correctly figure out where the subcommand starts:
sudo {-u,someuser} make ins
By definition, the tokens returned by `commandline -opc` do not
contain the token at cursor (which we're currently completing).
So the expansion should not hurt us. There is an edge case where
cartesian product expansion would produce too many results, and we
pass on the unexpanded input. In that case the extra escaping is very
unlikely to have negative effects.
Fixes # 11041
Closes # 11067
Co-authored-by: kerty <g.kabakov@inbox.ru>
This reverts commit ebdc3a0393.
Not discussed, includes a new thing that queries the terminal for the client OS
when what is really needed is just a `uname` - which would also work on Terminal.app.
Revert "README for this fork"
This reverts commit 97db461e7f.
Revert "Allow foo=bar global variable assignments"
This reverts commit 45a2017580.
Revert "Interpret () in command position as subshell"
This reverts commit 0199583435.
Revert "Allow special variables $?,$$,$@,$#"
This reverts commit 4a71ee1288.
Revert "Allow $() in command position"
This reverts commit 4b99fe2288.
Revert "Turn off full LTO"
This reverts commit b1213f1385.
Revert "Back out "bind: Remove "c-" and "a-" shortcut notation""
This reverts commit f43abc42f9.
Revert "Un-hide documentation of non-fish shell builtins"
This reverts commit 485201ba2e.
Unlike other builtins, "{" is a separate token, not a keyword-string
token.
Allow the left brace token as command string; produce it when parsing
"{ -h"/"{ --help" (and nowhere else). By using a decorated statement,
we reuse logic for redirections etc.
Other syntax elements like "and" are in the builtin list, which
- adds highlighting logic
- adds it to "builtin --names"
- makes it runnable as builtin
(e.g. "builtin '{'" would hypothetically print the man page)
These don't seem very important (highlighting for '{' needs to match
'}' anyway).
Additionally, making it a real builtin would mean that we'd need to
deactivate a few places that unescape "{" to BRACE_BEGIN.
Let's not add it to the built in list. Instead, simply synthesize
builtin_generic in the right spot.
I'm assuming we want "{ -h" to print help, but '"{" -h' to run an
external command, since the latter is historical behavior. This works
naturally with the above fake builtin approach which never tries to
unescape the left brace.
Commit 798527d79a (completions: fix double evaluation of tokenized
commandline, 2024-01-06) fixed some completions such as the "watchexec"
ones by adding "string escape" here:
set argv (commandline -opc | string escape) (commandline -ct)
This fixed double evaluation when we later call `complete -C"$argv"`.
Unfortunately -- searching for "complete -C" and
"__fish_complete_subcommand" -- it seems like that commit missed some
completions such as sudo. Fix them the same way.
Alternatively, we could defer expansion of those arguments (via
--tokens-raw), since the recursive call to completion will expand
them anyway, and we don't really need to know their value.
But there are (contrived) examples where we do want to expand first,
to correctly figure out where the subcommand starts:
sudo {-u,someuser} make ins
By definition, the tokens returned by `commandline -opc` do not
contain the token at cursor (which we're currently completing).
So the expansion should not hurt us. There is an edge case where
cartesian product expansion would produce too many results, and we
pass on the unexpanded input. In that case the extra escaping is very
unlikely to have negative effects.
Fixes # 11041
Closes # 11067
Co-authored-by: kerty <g.kabakov@inbox.ru>
If a child program crashes with some text rendered below the cursor,
we fail to clear that text. For example run vim, "pkill -9 vim" and
observe that scrollback-push fails to clean up the leftover text.
Fix that.
Custom formats for --pretty/--format option can only be written in [pretty]
section, thus only this section is searched.
[ja: add ? to the regex]
Closes#11065
libc::getpid and getpgrp *cannot fail*, so an unsafe declaration here
is just noise.
I mean sure, if your libc is broken and these fail, but at that point
I'm comfortable declaring your computer a platypus that we do not need
to support.
Wgetopt needs a ":" at the beginning to turn on this type of error.
I'm not sure why that is now, and we might want to change it (but tbh
wgetopt could do with a replacement anyway).
Fixes#11049
We capture the process already, and we use argv by reference for the
other cases.
argv can be big, and this reduces allocations and thereby memory usage
and speed.
E.g. `set -l foo **` with 200k matches has 25% reduced memory usage
and ~5% reduced runtime.
Sorry, commit 51adba6ee0 (Restore autosuggestion after corrected
typo, 2025-01-10) was pushed too early. One issue is that it saves
autosuggestions also when we edit in the middle, where we can't
restore it. We'd still restore it in some cases, even though it
doesn't apply. This breaks invariants that may cause various problems
when interacting with the autosuggestion.
Fix it by only saving the autosuggestion when we will be able to
restore it correctly.
Wgetopt needs a ":" at the beginning to turn on this type of error.
I'm not sure why that is now, and we might want to change it (but tbh
wgetopt could do with a replacement anyway).
Fixes#11049
We capture the process already, and we use argv by reference for the
other cases.
argv can be big, and this reduces allocations and thereby memory usage
and speed.
E.g. `set -l foo **` with 200k matches has 25% reduced memory usage
and ~5% reduced runtime.
For compound commands we already have begin/end but
> it is long, which it is not convenient for the command line
> it is different than {} which shell users have been using for >50 years
The difference from {} can break muscle memory and add extra steps
when I'm trying to write simple commands that work in any shell.
Fix that by embracing the traditional style too.
---
Since { and } have always been special syntax in fish, we can also
allow
{ }
{ echo }
which I find intuitive even without having used a shell that supports
this (like zsh. The downside is that this doesn't work in some other
shells. The upside is in aesthetics and convenience (this is for
interactive use). Not completely sure about this.
---
This implementation adds a hack to the tokenizer: '{' is usually a
brace expansion. Make it compound command when in command position
(not something the tokenizer would normally know). We need to disable
this when parsing a freestanding argument lists (in "complete somecmd
-a "{true,false}"). It's not really clear what "read -t" should do.
For now, keep the existing behavior (don't parse compound statements).
Add another hack to increase backwards compatibility: parse something
like "{ foo }" as brace statement only if it has a space after
the opening brace. This style is less likely to be used for brace
expansion. Perhaps we can change this in future (I'll make a PR).
Use separate terminal token types for braces; we could make the
left brace an ordinary string token but since string tokens undergo
unescaping during expansion etc., every such place would need to know
whether it's dealing with a command or an argument. Certainly possible
but it seems simpler (especially for tab-completions) to strip braces
in the parser. We could change this.
---
In future we could allow the following alternative syntax (which is
invalid today).
if true {
}
if true; {
}
Closes#10895Closes#10898
Commit bdfbdaafcc (Forbid subcommand keywords in variables-as-commands
(#10249), 2024-02-06) banned "set x command; $x foo" because the
parser will not recognize "$x" as decorator.
That means that we would execute only the builtin stub,
which usually exist only for the --help argument.
This scenario does not apply for keywords that are quoted or contain
line continuations. We should not treat «"command"» differently
from «command». Fix this inconsistency to reduce confusion.
UnLike other aliases (":.["), ! is special in the grammar but in the
few cases like "! -h" where we parse it as decorated statement they
are equals. Add it to the built in list, so the help argument works.
It can still be overridden, so this should not break anything.
Other sigil-aliases ('[' and '_') are reserved words that cannot be
redefined as function. Only '!' is not.
Whereas several users define "function !!", I
found only one public occurrence of "function !":
5c7f87ed07/fish/functions/!.fish
Note that "function !" only works if invoked as "!", "! -h" or
"! --help" or "foo | !". In most other cases we parse it as negation.
We should probably make it a reserved word to reduce confusion.
If we do that, we should also add it to __fish_print_help, to make
"! -h" work.
For now let's rearrange the code so we can recognize "!" as
super-command. This fixes completion-based autosuggestions on "! ".
The commandline "and fis" rightly gets command autosuggestions whereas
"'and' fis" wrongly gets file autosuggestions. The former works via
a hack. Extend it to quoted keywords.
This file has bitrotted; for example commit bc66921ac9 (Optimize
keyword detection, 2019-04-03) removed use of SKIP_KEYWORDS but
confusingly it's still around (even after 0118eafee1 (Remove unused
functions, members (and a variable), 2022-04-09).
Also some keywords appear in multiple lists; the separate lists are
not really used today; there is a comment stating they may be useful
in future.
It would be great to add an optimization back but either way we should
present the set of reserved words in source code as a contiguous list,
to make it easy for humans to see all relevant information.
StatementVariant needs an indirection because for example NotStatement
may contain another whole statement (error[E0072]: recursive type
has infinite size).
This is dealt with by putting each StatementVariant in a Box.
This Box was also used by the AST walk implementation to implement
tagged dispatched for all variant AST nodes (see "visit_union_field").
Because of this, all other variant AST are boxed the same way, even
though they may not by cyclic themselves.
Reduce confusion by boxing only around the nodes that are actually
recursive types, and use a different tag for static dispatch.
This means that simple nodes like most normal commands and arguments
need one fewer allocation.
For better or worse, backward-token completely skips over operators
like > & |.
forward-token is (accidentally?) inconsistent with that. Fix that.
Skipping over those tokens might be wrong weird. Maybe not for
redirections since they are tighly coupled to their target. Maybe we
can improve this in future.
When pasting and executing a full line, the trailing newline character
will be included in history.
I usually manually delete the newline before executing, but sometimes
I forget. When I recall my (typically single-line) commands, it's
surprising that the cursor is on the blank second line.
The newline doesn't seem useful. Let's remove it automagically.
I wonder if anyone will be thrown off by this smart behavior.
In future, we can make this space trimming configurable, similar to
fish_should_add_to_history.
As mentioned in
https://github.com/fish-shell/fish-shell/pull/11045#discussion_r1915994998,
we need to refresh TTY timestamps to avoid timing-based issues.
For some context see
git log --grep='[Rr]efresh.* TTY'
Make things more consistent again. I don't know if all of these are
absolutely necessary, hoping to find out later (and consolidate this
logic in outputter).
tmux-commandline can fail with
```
prompt 4> commandline -i "echo $(printf %0"$COLUMNS"d)"
```
And I just can't even.
job_summary is annoyingly tight.
Also count cancel_event as a *skip*, not success.
And leave the old behavior under the name "cancel-commandline".
This renames "cancel-commandline-traditional" back to
"cancel-commandline", so the old name triggers the old behavior.
Fixes#10935
And leave the old behavior under the name "cancel-commandline".
This renames "cancel-commandline-traditional" back to
"cancel-commandline", so the old name triggers the old behavior.
Fixes#10935
Saturating all cores easily leads to timeouts.
The system might be doing something else, and it only leaves at most
one core per-test.
E.g. this will cause 90% of runs to fail on a raspberry pi 4.
Note that we set CTEST_PARALLEL_LEVEL on our CI machines anyway, so
this will not affect them.
The issue here is we start some short `sleep`s in the background, wait
for a prompt, and only *then* wait for jobs, and *then* check for the
job end output.
That means if the prompt takes too long, we'll read the job end
messages with the `expect_prompt`.
Instead of increasing the timeouts, just wait on the same line and
remove that prompt.
Bit of a shot in the dark, I've seen this fail and there's no real
need to match the prompt *and* the command you just ran.
(plus wc -l | string trim is unnecessary when we have count)
Commit 4f3d6427ce (Fix regression causing crash in "commandline -j",
2025-01-12) wasn't quite right; it mishandles the edge case where
the current process has no token, fix that.
Zellij 0.41.2 has a bug where it responds to
printf '\x1b[?2026$p'; cat -v
with '^[[2026;2$y' (DECRQM) instead of '^[[?2026;2$y' (DECRPM).
This is fixed by https://github.com/zellij-org/zellij/pull/3884
We fail to parse it, leading to an extra y added to the input queue.
Since it seems easy to work around for us, let's do that, I guess.
Failed on Cirrus Alpine.
The only explanation I can come up with here is that this took over
100ms to start `true | sleep 6`.
The alternative is that it started it and then did not regain control
in 6 seconds to kill that sleep.
Part of #11036
If you don't care about file paths containing '=' or ':', you can
stop reading now.
In tokens like
env var=/some/path
PATH=/bin:/usr/local/b
file completion starts after the last separator (#2178).
Commit db365b5ef8 (Do not treat \: or \= as file completion anchor,
2024-04-19) allowed to override this behavior by escaping separators,
matching Bash.
Commit e97a4fab71 (Escape : and = in file completions, 2024-04-19)
adds this escaping automatically (also matching Bash).
The automatic escaping can be jarring and confusing, because separators
have basically no special meaning in the tokenizer; the escaping is
purely a hint to the completion engine, and often unnecessary.
For "/path/to/some:file", we compute completions for "file" and for
"/path/to/some:file". Usually the former already matches nothing,
meaning that escaping isn't necessary.
e97a4fab71 refers us to f7dac82ed6 (Escape separators (colon and
equals) to improve completion, 2019-08-23) for the original motivation:
$ ls /sys/bus/acpi/devices/d<tab>
$ ls /sys/bus/acpi/devices/device:
device:00/ device:0a/ …
Before automatic escaping, this scenario would suggest all files from
$PWD in addition to the expected completions shown above.
Since this seems to be mainly about the case where the suffix after
the separator is empty,
Let's remove the automatic escaping and add a heuristic to skip suffix
completions if:
1. the suffix is empty, to specifically address the above case.
2. the whole token completes to at least one appending completion.
This makes sure that "git log -- :!:" still gets completions.
(Not sure about the appending requirement)
This heuristic is probably too conservative; we can relax it later
should we hit this again.
Since this reverts most of e97a4fab71, we address the code clone
pointed out in 421ce13be6 (Fix replacing completions spuriously quoting
~, 2024-12-06). Note that e97a4fab71 quietly fixed completions for
variable overrides with brackets.
a=bracket[
But it did so in a pretty intrusive way, forcing a lot of completions
to become replacing. Let's move this logic to a more appropriate place.
---
Additionally, we could sort every whole-token completion before every
suffix-completion. That would probably improve the situation further,
but by itself it wouldn't address the immediate issue.
Closes#11027
Mainly to make the next commit's diff smaller. Not much functional
change: since file completions never have the DONT_SORT flag set,
these results will be sorted, and there are no data dependencies --
unless we're overflowing the max number of completions. But in that
case the whole-token completions seem more important anyway.
Syntax highlighting wants to underline arguments that are files, and in other
cases do disk I/O (such as testing if a command is valid). Factor out this I/O
logic to untangle highlighting, and add some tests. No functional change
expected.
Commit 3fcc6482cb (Fix parse_util_process_extent including too much
on the left, 2024-12-24) changed the process extent based on the
observation that "A\n\n\nB" comprises three tokens with ranges 0..1,
1..2 and 4..5. Prior to that commit, the second process extent was
2..5, which seems a bit weird because it includes newlines.
Weirdness aside, the real reason for changing it was this snippet in
the autosuggestion performer, where we compute the process extent
around cursor, and check if the line at process start matches the
cached search string.
// Search history for a matching item unless this line is not a continuation line or quoted.
if range_of_line_at_cursor(
&command_line,
parse_util_process_extent(&command_line, cursor_pos, None).start,
) == search_string_range
Given "A\n\n\nB" and cursor_pos=1 commit 3fcc6482cb changed the output
from 2..5 to 4..5. This brings problems:
1. leading spaces will not be included (which is probably
inconsequential but still ugly).
2. the specified cursor position is not included in the given range.
We could paper over 2 by computing min(cursor_pos)
but that would leave 1.
For now let's revert and solve the autosuggestion issue in a less
brittle way.
This needs to work both in builtin and command mode.
We should probably clarify how we're passing FDs around, and I suspect
we may close fds in places we don't expect.
Ubuntu Focal calls the package with col "bsdmainutils", which is a
transitional package on newer version of both Debian and Ubuntu.
Closes#11037.
(Adapted from commit 54fef433e9)
Various commits have added bits to .cargo/config.toml. Unfortunately,
this file needs to be changed by the Linux package builds (debuild, RPM,
OBS etc) with the results of `cargo vendor`, to support building in
isolated environments.
These environments - especially Debian's dpkg-buildpackage/debuild - do
not make it easy to alter a file which already exists in the tarball in
an automatic way. dpkg-buildpackage in particular requires all changes
to be made in the form of patches.
Just exclude .cargo/config.toml from the tarballs for now. This means
that the stanzas it includes _will not apply_ to builds made from
tarballs, which includes releases and development builds made using the
OBS/Launchpad PPAs.
This replaces the test_driver.sh/test.fish/interactive.fish system with a test driver written in python that calls into littlecheck directly and runs pexpect in a subprocess.
This means we reduce the reliance on the fish that we're testing, and we remove a posix sh script that is a weird stumbling block (see my recent quest to make it work on directories with spaces).
To run specific tests, e.g. all the tmux tests and bind.py:
tests/test_driver.py target/release/ tests/checks/tmux*.fish tests/pexpects/bind.py
Backspace signals that the user is not happy with the commandline,
and by extension the autosuggestion.
For this reason, backspace suppresses autosuggestions until the next
text insertion.
However if I
1. type something that has an autosuggestion
2. type *one* wrong letter (removing the autosuggestion)
3. type backspace
backspace does not visibly suppress any autosuggestion but rhater
signal that the user wants to go back to the previous state of the
commandline, which does have an autosuggestion.
Enable this scenario by caching the autosuggestion when it's
invalidated. On certain edits that make the cached autosuggestion
valid again, restore it from the cache. Currently, only do this up
to a single backspace. Could extend that in future.
This implementation is really bad.. but it's a start.
Weirdly, it does not restore the cache on undo; but that's
inconsequential because undo doesn't suppress autosuggestion as
of today.
Closes#3549
My history often has erroneous single-line commands followed by
corrected versions. Sometimes the corrected versions only exist within
a multi-line commandline. This means that autosuggestion skips over
the corrected versions and return a false positive.
Fix that by splitting the commandline into lines and suggesting those,
in reverse chronological order.
One other wart: shift-delete won't delete such autosuggestions from
history; instead it will flash the screen.
Line boundaries are not the best heuristic but they are an
improvement for the most part and fits with the current approach
where autosuggestion always operates on the entire line.
In future we should operate on processes and jobs. But it may be
tricky - a backgrounding `&` should probably be included (in both?)
but `&&` or `;` probably not.
See also the discussion in
1c4e5cadf2 (diff-267c9f4da66412a9f439ac08d224356fe24265b5e1cebb6c44c2d55b96414513R59)
If there is no history search or autosuggestion, shift-delete acts
as backspace, matching native macOS behavior.
I'm not sure if we want to keep that amount of overloaded behavior,
but let's assume so for now.
If that assumption holds, it may be confusing that shift-delete
deletes the autosuggestion if the cursor is here
echo some command with autosuggstion
^
So let's only do that if the cursor is actually at the autosuggestion,
I guess.
shift-delete attempts to delete the autosuggestion from history even
if the autosuggestion is not from history.
This is weird. We probably shouldn't do this. Let's flash the
commandline instead to try to reduce confusion.
I think the dynamic detection patch ends up overriding the environment variable
set by CI (if present), because `if(NOT CTEST_PARALLEL_LEVEL)` would define to
false even if an environment variable of that name existed then we end up
explicitly assigning the environment variable by that name upon invocation with
`env`.
This is an experiment to see if it causes any of the tests to flake and/or if it
even appreciably speeds up CI to begin with.
I note that there are tests added in 8bf8b10 that mutate global terminal state
but also note that local tests without CTEST_PARALLEL_LEVEL set at all have been
running to completion just fine without any observed flakiness *and* that our
Cirrus CI tests have this hard-coded to 6.
The new 1.84 release has a new feature that makes `cargo update` MSRV-aware.
This is what it looks like in practice:
Updating crates.io index
Updating git repository `https://github.com/fish-shell/rust-pcre2`
From https://github.com/fish-shell/rust-pcre2
* [new tag] 0.2.9-utf32 -> origin/tags/0.2.9-utf32
Locking 7 packages to latest Rust 1.70 compatible versions
Updating cc v1.2.6 -> v1.2.7
Updating phf v0.11.2 -> v0.11.3
Updating phf_codegen v0.11.2 -> v0.11.3
Updating phf_generator v0.11.2 -> v0.11.3
Updating phf_shared v0.11.2 -> v0.11.3
Updating siphasher v0.3.11 -> v1.0.1
Updating syn v2.0.94 -> v2.0.95
The result of
commandline -i ": '$(seq $LINES)"\n"first scrolled line'"
is a commandline that is scrolled by one line.
Before executing that commandline, we move the cursor down by one
too many line. This is a regression from 610338cc70 (On undo after
execute, restore the cursor position, 2024-12-21). Fix that.
The test also demonstrates an unrelated problem, probably specific
to tmux.
Some terminals such as conhost and putty cannot parse DCS commands,
and will echo them back.
Work around this by making sure that this echoed text will not
be visible.
Do so by temporarily enabling the alternative screen buffer when
sending DCS queries (in this case only XTGETTCAP). The alternative
screen buffer feature seems widely supported, and easier to get right
than trying to clear individual lines etc.
The alternative screen may still be visible for a
short time. Luckily we can use [Synchronized Output](
https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036)
to make sure the screen change is never visible to the user.
Querying support for that is deemed safe since it only requires a
CSI command.
Note that it seems that every terminal that supports Synchronized
Output also parses DCS commands successfully. This means that we
could get away without the alternative screen buffer in practice.
Not sure yet.
The implementation is slightly more complex than necessary in that it
defines a redundant ImplicitEvent. This is for two reasons: 1. I have
a pending change that wants to use it, so this removes diff noise and
2. we historically have sc/input_common.rs not depend on src/output.rs.
I dont' think any are strong reasons though.
This needs to be tested more, it has shown issues in MS conhost,
and potentially others.
Changing strategy after beta isn't the greatest idea.
This reverts commit 4decacb933.
See #10994
I believe this fixes more cases than it breaks. For example
this should fix Termux which seems to be popular among fish
users. Unfortunately I haven't yet managed to test that one.
Cherry-pick of all of
- e49dde87cc (Probe for kitty keyboard protocol support, 2025-01-03)
- 10f1f21a4f (Don't send kitty kbd protocol probe until ECHO is disabled, 2025-01-05)
- dda4371679 (Stop sending CSI 5n when querying for kitty keyboard support, 2025-01-05)
Commit b6d76ae: we now use lines like "# RUN: fish=%fish %fish".
If a test exits with 127 we try to look up the command but use the
wrong name, which leads to unintelligible errors if the test exits
with 127 for other reasons.
If I run "sleep 3", type a command and hit enter, then there is no
obvious way to cancel or edit the imminent command other than ctrl-c
but that also cancels sleep, and doesn't allow editing. (ctrl-z sort
of works, but also doesn't allow editing).
Let's try to limit ourselves to inserting the buffered command
(translating enter to a newline), and only execute once the user
actually presses enter after the previous command is done.
Hide it behind a new feature flag for now.
By making things less scary, this might be more user-friendly, at
the risk of breaking expectations in some cases.
This also fixes a class of security issues where a command like
`cat malicious-file.txt` might output escape sequences, causing
the terminal to echo back a malicious command; such files can still
insert into the command line but at least not execute it directly.
(Since it's only fixed partially I'm not really sure if the security
issue is a good enough motivation for this particular change.)
Note that bracketed paste probably has similar motivation as this feature.
Part of #10987Closes#10991
Some terminals like the Linux console don't support indn (scroll
forward). Let's query for the presence of these features, and fall
back to the traditional behavior if absent.
For now, break with the tradition of using the terminfo database that
we read ourselves. Instead ask the terminal directly via XTGETTCAP.
This is a fairly young feature implemented by terminals like xterm,
foot and kitty, however xterm doesn't expose these capabilities at
this point.
This is a good opportunity to try XTGETTCAP, since these are
capabilities we haven't used before. Advantages of XTGETTCAP are that
it works across SSH and is independent of $TERM (of course ignoring
$TERM may also be breaking to some users). Let's see if it sees
adoption in practice.
Tested to work on foot and kitty, allowing the default ctrl-l binding
to work without erasing any screen content.
See #11003
The new ctrl-l implementation relies on Cursor Position Reporting (CPR)
This may not work on exotic terminals that don't support CSI 6n yet
As a workaround, probe for this feature by sending a CSI 6n (CPR)
on startup. Until the terminal responds, have scrollback-push fall
back to clear-screen.
The theoretical problem here is that we might handle scrollback-push
before we have handled the response to our feature probe. That seems
fairly unlikely; also e49dde87cc has the same characteristics.
This could query a capability instead (via XTGETTCAP or otherwise)
but I haven't found one; and this seems at least as reliable.
While at it, change the naming a bit.
See #11003
After we query kitty keyboard protocol support,
we send CSI 5n, to also receive a response if
the protocol is not supported.
However we don't bother to wait for the response, so this extra
message is not really useful (only to get better logs). Remove it.
With tmux 3.0 (from 2019) inside SSH, the CSI 5n response is echoed.
I guess with all other terminals we were just lucky. Move it to
right after where we disable ECHO I guess.
In general, asynchronous requests create a lot of potential for error,
we should try to get away from them.
These aren't typically used in the terminal but they are present on
many keyboards.
Also reorganize the named key constants a bit. Between F500 and
ENCODE_DIRECT_BASE (F600) we have space for 256 named keys.
To make it more familiar to vi/vim users.
In all mode, ctrl-k is bind to kill-line.
In Vi visual mode:
* press v or i turn into normal or insert mode respectively.
* press I turn to insert mode and move the cursor to beginning of line.
* because fish doesn't have upcase/locase-selection, and most people reach for
g-U rather than g-u, g-U binds to togglecase-selection temporarily.
(cherry picked from commit f9b79926f1)
To make it more familiar to vi/vim users.
In all mode, ctrl-k is bind to kill-line.
In Vi visual mode:
* press v or i turn into normal or insert mode respectively.
* press I turn to insert mode and move the cursor to beginning of line.
* because fish doesn't have upcase/locase-selection, and most people reach for
g-U rather than g-u, g-U binds to togglecase-selection temporarily.
The `gcloud` and `gsutil` Google Cloud commands use argcomplete, so integrating them is easy with the `__fish_argcomplete_complete` function.
(cherry picked from commit d842a6560e)
Testing has revealed some problems on BSD and Windows terminals and
the Linux Console, let's revert to the old implementation until these
are fixed. Leaving the changelog entry for now since it shouldn't
take long.
See #11003
The FdReadableSet api was always intended to be converted to use Duration
instead of usec/msec once the ffi was removed. This lets us be explicit about
forever/infinite timeouts and removes the (small) chance of a collision between
u64::MAX and INFINITE.
I tried this out with `type Timeout = Option<Duration>` (only without the alias)
but was unhappy with easy it is to accidentally use `None` when you meant a
timeout of zero.
cursor_selection_mode=inclusive means the commandline position is
bounded by the last character. Fix a loop that fails to account
for this.
Fixes d51f669647 (Vi mode: avoid placing cursor beyond last character,
2024-02-14).
This change looks very odd because if the commandline is like
echo foo.
it makes us try to uppercase the trailing period even though that's
not part of word range. Hopefully this is harmless.
Note that there seem to be more issues remaining, for example Vi-mode
paste leaves the cursor in an out-of-bounds odd position.
Fixes#10952Closes#10953
Reported-by: Lzu Tao <taolzu@gmail.com>
(cherry picked from commit 69f0d960cf)
Commit 1c4e5cadf2 (Autosuggestions in multi-line
command lines, 2024-12-15) accidentally passed an empty
"commandline_before_suggestion" to compute_layout() when there is
no autosuggestion.
Closes#10996
Fixes#10980.
This would, if a commandline was given, still revert to checking
the *real* commandline if it was empty.
Unfortunately, in those cases, it could have found a command and tried
to complete it.
If a commandline is given, that is what needs to be completed.
(note this means this is basically useless in completions that use it
like `sudo` and could just be replaced with `complete -C"$commandline"`)
(cherry picked from commit d5efef1cc5)
As reported in
https://github.com/fish-shell/fish-shell/issues/10992#issuecomment-2568954940,
the user may reset the terminal and run scrollback-push without
repainting in between. This means that the terminal will report
the cursor position y=0 x=0 which doesn't match what fish renders.
Fortunately, y=0 is a safe fallback value for the scrollback-push
use case.
While at it, fix an off-by-one error in a log.
Before 1c4e5cadf2 (Autosuggestions in multi-line command lines,
2024-12-15), the completion code path in the autosuggestion performer
used to do something weird: it used to request completions for the
entire command line (with the implied cursor at end) but try to apply
the same completion at the actual cursor.
That commit changed this to request completions only up to the cursor
position, which could in theory make us produce valid completions even
if the cursor is not at end of the line. However, that doesn't really
work since autosuggestions can only be rendered at the end of the line.
And the worst of it, that commit tries to compute
line_at_cursor(&full_line, search_string_range.end)
which crashes as out-of-bounds if the completion needs to replace the token
(like a case-correcting completion does).
Let's apply completions to the end, matching how autosuggestions work
in general.
I believe it's possible that the cursor position reported by the
terminal does not match fish's cursor. In that case, overflow. Fix
that since we should not trust the terminal.
Also rename a confusingly named variable.
Mouse-click handling has a similar issue, fix that too.
FWIW, tmux always reports cursor position zero (\x1b[1;1R) when
querying from fish (but not when querying with printf).
Will investigate that next, see the linked issue.
Fixes#10992
jj is often colocated with Git so the Git prompt also works, but
jj is always in a detached HEAD state, which is atypical for Git.
The jj prompt improves things by showing the revision ID which is
usually more useful than the commit ID.
This prompt is mostly adapted from the defaults for "jj log -r @".
Showing conflicting/empty commits seems useful.
Also perhaps bookmarks and tags, not sure.
The main problem with this prompt is that due to --ignore-working-copy,
the information may be stale. That will be rectified after every jj
command, so hopefully this doesn't cause issues.
Added in libc 0.2.163.
The constants for _CS_PATH are not implemented for some of the BSDs yet
(rust-lang/cmake#3612), so we need to keep our linking of this via the C
compiler for now.
These are quite mechanical, but include all the commands (as of tmux
3.5a) in the "Windows and Panes" section of `man tmux`. For these
commands, I included the target-pane/session/client/window flags and the
-F formatstring flags (but not the less generic flags specific to
individual commands).
Nice completion is implemented for those flags where the helper
functions were already implemented previously.
After this, tmux pane<tab> will hopefully be useful.
A few TODOs mention low-hanging fruit for somebody who better
understands fish's `complete` command syntax (or a future me).
Another piece of low-hanging fruit would be completion for all the
target-window flags. This PR merely lists them.
(cherry picked from commit b1064ac3a0)
If I run
$ command A
$ command B
$ command C
and find myself wanting to re-run the same sequence of commands
multiple times, I like to join them into a single command:
$ command A &&
command B &&
command C
When composing this mega-commandline, history search can recall the
first one; the others I usually inserted with a combination of ctrl-k,
ctrl-x or the ctrl-r (since 232483d89a (History pager to only operate
on the line at cursor, 2024-03-22), which is motivated by exactly
this use case).
It's irritating that autosuggestions are missing, so try adding them.
Today, only single-line commands from history are suggested. In
future, we should perhaps also suggest any line from a multi-line
command from history.
If I type something that invalidates the autosuggestion, the
autosuggestion is still kept around in memory. This is used if
1. there is no valid autosuggestion for the new commandline
2. the user types something like "backspace backspace a"
that both makes the cached autosuggestion valid again, and does
not trigger autosuggestion suppression (hence backspace alone is
not anough)
The fact that an autosuggestion might not match the current command
line makes it more difficult to implement autosuggestions on multiline
command lines.
For now let's invalidate autosuggestions eagerly, to enable the
next commit. This heuristic invalidates too much but I don't think
that matters. We'll simply recompute the autosuggestion in those few
cases which.
This is somewhat subtle:
The #RUN line in a littlecheck file will be run by a posix shell,
which means the substitutions will also be mangled by it.
Now, we *have* shell-quoted them, but unfortunately what we need is to
quote them for inside a pre-existing layer of quotes, e.g.
# RUN: fish -C 'set -g fish %fish'
here, %fish can't be replaced with `'path with spaces/fish'`, because
that ends up as
# RUN: fish -C 'set -g fish 'path with spaces/fish''
which is just broken.
So instead, we pass it as a variable to that fish:
# RUN: fish=%fish fish...
In addition, we need to not mangle the arguments in our test_driver.
For that, because we insist on posix shell, which has only one array,
and we source a file, we *need* to stop having that file use
arguments.
Which is okay - test_env.sh could previously be used to start a test,
and now it no longer can because that is test_*driver*.sh's job.
For the interactive tests, it's slightly different:
pexpect.spawn(foo) is sensitive to shell metacharacters like space.
So we shell-quote it.
But if you pass any args to pexpect.spawn, it no longer uses a shell,
and so we cannot shell-quote it.
There could be a better way to fix this?
We:
1. Set up a nice TMPDIR for our tests to use
2. Immediately `cd` to the directory containing the test runner.
So instead we don't do (2), and stay in the temp directory, and
explicitly use all the things from the test runner directory.
I am fairly certain that cmake papered over this by adding a second
layer of temp dir.
The default is still "../test/root/bin/", but we now pass this
through,
so you *can* run
`FISHDIR=$PWD ../tests/test_driver.sh $PWD/../tests/test.fish`
Fixes#10980.
This would, if a commandline was given, still revert to checking
the *real* commandline if it was empty.
Unfortunately, in those cases, it could have found a command and tried
to complete it.
If a commandline is given, that is what needs to be completed.
(note this means this is basically useless in completions that use it
like `sudo` and could just be replaced with `complete -C"$commandline"`)
As soon as we start processing a scrollback-push readline command, we
pause execution of all other readline commands until scrollback-push
retires. This means that we never get into a situation with two
active scrollback-push commands -- unless we are executing readline
commands via a script running "commandline -f":
since the first part of scrollback-push handling returns immediately,
the script will proceed before scrollback-push retires.
A second scrollback-push fails an assertion. Work around that for now.
In future, scrollback-push should block when invoked by such a script,
just like it does when invoked from bindings.
Commit 83b0294fc9 (ctrl-l to scroll content instead of erasing screen,
2024-12-21) broke tests like tests/checks/tmux-autosuggestion.fish
on macOS CI.
I didn't get to the bottom of this but it's probably because terminfo
is broken on that CI system.
A (related?) failure mode can be observed using
TERM=linux-m ssh my-mac tmux
ctrl-l moves the cursor but fails to scroll the text.
The only reason for using terminfo here was to be consistent with
the rest of the code base. Let's use a hardcoded value instead;
I don't see why any terminal would deviate from xterm here.
This fixes macOS CI and the TERM=linux-m "misconfiguration".
It is possible that we should be using a different escape sequence
here; I'm not sure.
On ctrl-l we send `\e[2J` (Erase in Display). Some terminals interpret
this to scroll the screen content instead of clearing it. This happens
on VTE-based terminals like gnome-terminal for example.
The traditional behavior of ctrl-l erasing the screen (but not the
rest of the scrollback) is weird because:
1. `ctrl-l` is the easiest and most portable way to push the prompt
to the top (and repaint after glitches I guess). But it's also a
destructive action, truncating scrollback. I use it for scrolling
and am frequently surprised when my scroll back is missing
information.
2. the amount of lines erased depends on the window size.
It would be more intuitive to erase by prompts, or erase the text
in the terminal selection.
Let's use scrolling behavior on all terminals.
The new command could also be named "push-to-scrollback", for
consistency with others. But if we anticipate a want to add other
scrollback-related commands, "scrollback-push" is better.
This causes tests/checks/tmux-history-search.fish to fail; that test
seems pretty broken; M-d (alt-d) is supposed to delete the current
search match but there is a rogue "echo" that is supposed to invalidate
the search match. I'm not sure how that ever worked.
Also, pexepect doesn't seem to support cursor position reporting,
so work around that.
Ref: https://codeberg.org/dnkl/foot/wiki#how-do-i-make-ctrl-l-scroll-the-content-instead-of-erasing-it
as of wiki commit b57489e298f95d037fdf34da00ea60a5e8eafd6d
Closes#10934
We parse "\e\e[x" as alt-modified "Invalid" key. Due to this extra
modifier, we accidentally add it to the input queue, instead of
dropping this invalid key.
We don't really want to try to extract some valid keys from this
invalid sequence, see also the parent commit.
This allows us to remove misplaced validation that was added by
e8e91c97a6 (fish_key_reader: ignore sentinel key, 2024-04-02) but
later obsoleted by 66c6e89f98 (Don't add collateral sentinel key to
input queue, 2024-04-03).
This situation can be triggered in practice inside a terminal like tmux
3.5 by running
tmux new-session fish -C 'sleep 2' -d reader -o log-file
and typing "alt-escape x"
The log shows that we drop treat this as alt-[ and drop the x on the floor.
reader: Read char alt-\[ -- Key { modifiers: Modifiers { ctrl: false,
alt: true, shift: false }, codepoint: '[' } -- [27, 91, 120]
This input ("\e[x") is ambiguous.
It looks like it could mean "alt-[,x". However that conflicts with a
potential future CSI code, so it makes no sense to try to support this.
Returning "None" from parse_csi() causes this weird behavior of
returning "alt-[" and dropping the rest of the parsed sequence.
This is too easy; it has even crept into a bunch of places
where the input sequence is actually valid like "VT200 button released"
but where we definitely don't want to report any key.
Fix the default: report no key for all unknown sequences and
intentionally-suppressed sequences. Treat it at "alt-[" only when
there is no input byte available, which is more or less unambiguous,
hence a strong enough signal that this is a actually "alt-[".
When the user clicks somewhere in the prompt, kitty asks the shell
to move the cursor there (since there is not much else to do).
This is currently implemented by sending an array of
forward-char-passive commands. This has problems, for example it
is really slow on large command lines (probably because we repaint
everytime).
Implement kitty's `click_events=1` flag to set the
position directly. To convert from terminal-coordinates
to fish-coordinates, query [CSI 6 n Report Cursor
Position](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html)
and use it to compute the left prompt's terminal-coordinates (which
are (0, 0) in fish-coordinates).
Unfortunately this doesn't yet work correctly while the terminal
is scrolled. This is probably because the cursor position is wrong
if off-screen. To fix that we could probably record the cursor
position while not scrolled, but it doesn't seem terribly important
(the existing implementation also doesn't get it right).
We still turn off mouse reporting. If we turned it on, it
would be harder to select text in the terminal itself (not fish).
This would typically mean that mouse-drag will alter fish's
selection and shift+mouse-drag or alt+mouse-drag can be used.
To improve this, we could try to synchronize the selection: if parts
of the fish commandline are selected in the terminal's selection,
copy that to fish's selection and vice versa.
Or maybe there is an intuitive criteria, like: whenever we receive a
mouse event outside fish, turn off mouse reporting, and turn it back on
whenver we receive new keyboard input. One problem is that we lose
one event (though we could send it back to the terminal). Another
problem is we would turn it back on too late in some scenarios.
Closes#10932
Commit 01dbfb0a3f (replace writestr() with fwprintf() in reader.cpp,
2016-12-20) accidentally replaced a retry-on-EINTR write with a
non-retrying version. Commit 7f31acbf9b (Prevent fish_title output
from triggering a bel, 2022-02-02) fixed this for some cases but
not all, fix that.
This has been removed, see kitty commit cd92d50a0 (Keyboard protocol:
Remove CSI R from the allowed encodings of the F3 key as it conflicts
with the *Cursor Position Report* escape code, 2022-12-24).
cursor_selection_mode=inclusive means the commandline position is
bounded by the last character. Fix a loop that fails to account
for this.
Fixes d51f669647 (Vi mode: avoid placing cursor beyond last character,
2024-02-14).
This change looks very odd because if the commandline is like
echo foo.
it makes us try to uppercase the trailing period even though that's
not part of word range. Hopefully this is harmless.
Note that there seem to be more issues remaining, for example Vi-mode
paste leaves the cursor in an out-of-bounds odd position.
Fixes#10952Closes#10953
Reported-by: Lzu Tao <taolzu@gmail.com>
PR #10953 reports missing coverage for the change to update_buff_pos()
in d51f669647 (Vi mode: avoid placing cursor beyond last character,
2024-02-14).
Add a case demonstrating how $ should not move the cursor past the
last character. Goes without saying that it's really ugly that we
update_buff_pos() must be so defensive here, ideally we wouldn't pass
it out-of-bounds positions.
Before, it unnecessarily stated that there are three `--style` options, when
there are actually four.
I also align the default `--style=script` argument to the beginning of the line
to match the other options visually for easier scanning.
Before, it unnecessarily stated that there are three `--style` options, when
there are actually four.
I also align the default `--style=script` argument to the beginning of the line
to match the other options visually for easier scanning.
These are quite mechanical, but include all the commands (as of tmux
3.5a) in the "Windows and Panes" section of `man tmux`. For these
commands, I included the target-pane/session/client/window flags and the
-F formatstring flags (but not the less generic flags specific to
individual commands).
Nice completion is implemented for those flags where the helper
functions were already implemented previously.
After this, tmux pane<tab> will hopefully be useful.
A few TODOs mention low-hanging fruit for somebody who better
understands fish's `complete` command syntax (or a future me).
Another piece of low-hanging fruit would be completion for all the
target-window flags. This PR merely lists them.
This can be used to get some information on how fish was built - the
version, the build system, the operating system and architecture, the
features.
(cherry picked from commit 6f9ca42a30)
If base directories (e.g. $HOME/.config/fish) need to be created,
create them with mode 0700 (i.e. restricted to the owner).
This both keeps the behavior of old fish versions (e.g. 3.7.1) and is
compliant with the XDG Base Directory Specification.
See: https://specifications.freedesktop.org/basedir-spec/0.8/#referencing
If base directories (e.g. $HOME/.config/fish) need to be created,
create them with mode 0700 (i.e. restricted to the owner).
This both keeps the behavior of old fish versions (e.g. 3.7.1) and is
compliant with the XDG Base Directory Specification.
See: https://specifications.freedesktop.org/basedir-spec/0.8/#referencing
[Do NOT cherry-pick to 4.0 - this needs more time to be tested]
fish sometimes needs to capture the output of a command or block of
commands. Examples include fish_prompt or any command substitution
("cmdsubs"). It does this the obvious way: by creating a pipe, using dup2
to replace stdout of the command with the write end of the pipe, and then
reading from the read end into a buffer, until EOF or the command
substitution completes. Importantly, this task also overlaps with waiting
for the process to exit; that is when executing:
set var (some_cmd)
fish needs to both wait on `some_cmd` and ALSO read its output into memory.
This is awkward to do in a portable way in a single thread (though maybe
doable on Linux with pidfd). So we wait and read on different threads.
To make things worse, command substitutions may themselves create
additional command substitutions (recursion, etc). Creating a read thread
for every command substitution would result in excessive threads. So rather
than a thread per cmdsub, we have a single dedicated thread that handles
ALL command substitutions, by multiplexing multiple file descriptors via
select/poll. This is the "fd monitor." You hand it a file descriptor and it
lets you know when it's readable, and then you can read from it (via a
callback). Also, it has a "wakeup" fd: if you write to that then the fd
monitor wakes up, figures out what it has to do, and resumes.
When the command substitution ends, we need to remove the fd from the fd
monitor, because we intend to close it. You might object "the commands in
the cmdsub have all completed so the write end of the pipe has been closed
so the fd monitor can just notice that the pipe is closed" but it's not so:
consider the horrible case of `set var (yes &)` and abandon all hope.
The current mechanism for removing the fd from the monitor is called a
"poke." We tell the fd monitor (through a "control" self-pipe) to
explicitly wake up the item. It then invokes the callback ("pokes") the
item on the dedicated fd monitor thread. The item notices that the command
substitution is complete, and it returns a value meaning "remove me" and
the fd monitor does so. The client thread is stuck waiting for this process
to complete.
So basically removing a fd from the monitor requires a round trip to its
dedicated thread. This is slow and also complicated (Rust doesn't have
futures)!
So let's not do that.
The big idea is to remove this round-trip synchronization. That is, when we
intend to remove the fd from the fd monitor, we _just do it_ and then close
the fd. Use a lock rather than a round-trip to the thread. Crucially that
lock is unlocked while the monitor thread waits in select/poll.
This invites all sorts of races:
1. fish might remove and close the fd right before the monitor polls it. It
will thus attempt to poll a closed fd.
2. fish might remove and close the fd, and then something else opens a file
and receives the same fd. Now the fd monitor will poll an fd that was
never added.
3. fish might remove and close the fd _while the fd monitor is polling it_.
What happens then? (Turns out on macOS we get EBADF, and on Linux the fd is
marked readable).
The Big Idea is that *all of these races are benign*. As long as
poll/select doesn't crash or hang, we don't care *what* it returns, because
the source of truth are the set of items stored in the fd monitor and these
item IDs are never recycled. (This also assumes that it's OK to select/poll
on random file descriptors; there ought to be no side effects).
Not only is this a large simplification since we no longer need that round
trip, it's a substantial performance improvement as well. The
"aliases.fish" benchmark goes from 164 to 154 msec on my Mac, and from 124
to 112 msec on my Linux machine - nearly 10%.
Add some tests to verify our assumptions about the behavior of closing or
replacing a file descriptor during poll. But even if these fail, all we
care about is that poll/select doesn't crash or hang.
FdMonitor is used to monitor a set of file descriptors and invoke a callback
when one becomes readable. Prior to this commit, they coudl also have the
callback invoked on timeout. fish used to use this feature but no longer does;
remove it.
Instead of hardcoded 230px margin.
This also makes the ToC only take up a third of the screen when
narrow, and lets you scroll the rest.
Without, you'd have to scroll past the *entire* ToC, which is awkward
Remaining issue is the search box up top. Since this disables the one
in the sidebar once the window gets too narrow, that one is important,
and it isn't *great*
(cherry picked from commit 9b8793a2df)
Instead of hardcoded 230px margin.
This also makes the ToC only take up a third of the screen when
narrow, and lets you scroll the rest.
Without, you'd have to scroll past the *entire* ToC, which is awkward
Remaining issue is the search box up top. Since this disables the one
in the sidebar once the window gets too narrow, that one is important,
and it isn't *great*
It is, as the name implies, unused - it became SIGSYS, which we
already check.
Since it is entirely undefined on some architectures it causes a build
failure there, see discussion in #10633
It is, as the name implies, unused - it became SIGSYS, which we
already check.
Since it is entirely undefined on some architectures it causes a build
failure there, see discussion in #10633
The libc crate has a bug on BSD where WEXITSTATUS is not an 8-bit
value, causing assertion failures.
Any libc higher than our 0.2.155 would increase our MSRV, see libc
commit 5ddbdc29f (Bump MSRV to 1.71, 2024-01-07), so we want to
woraround this anyway. It's probably not worth using a patched
version of libc since it's just one line.
While at it, tighten some types I guess.
Upstream fix: https://github.com/rust-lang/libc/pull/4213Closes#10919
Cherry-picked from c1b460525c
__fish_cancel_commandline was unused (even before) and has some issues
on multiline commandlines. Make it use the previously active logic.
Closes#10935
Cherry-picked from 5de6f4bb3d
The libc crate has a bug on BSD where WEXITSTATUS is not an 8-bit
value, causing assertion failures.
Any libc higher than our 0.2.155 would increase our MSRV, see libc
commit 5ddbdc29f (Bump MSRV to 1.71, 2024-01-07), so we want to
woraround this anyway. It's probably not worth using a patched
version of libc since it's just one line.
While at it, tighten some types I guess.
Upstream fix: https://github.com/rust-lang/libc/pull/4213Closes#10919
__fish_cancel_commandline was unused (even before) and has some issues
on multiline commandlines. Make it use the previously active logic.
Closes#10935
This seems more logical, especially since these need not be mentioned
in the "final" 4.0. When we merge the integration branch back into
master, we can combine changelog additions, so it won't be lost
from master.
* Pass path to install()
It was dirty that it would re-get $HOME there anyway.
* Import wcs2osstring
* Allow installable builds to use a relocatable tree
If you give a path to `--install`, it will install fish into a
relocatable tree there, so
PATH/share/fish contains the datafiles
PATH/bin/fish contains the fish executable
PATH/etc/fish is sysconf
I am absolutely not sold on that last one - the way I always used
sysconfdir is that it is always /etc. This would be easy to fix but
should probably also be fixed for "regular" relocatable builds (no
idea who uses them).
An attempt at #10916
* Move install path into "install/" subdir
* Disable --install harder if not installable
* Pass path to install()
It was dirty that it would re-get $HOME there anyway.
* Import wcs2osstring
* Allow installable builds to use a relocatable tree
If you give a path to `--install`, it will install fish into a
relocatable tree there, so
PATH/share/fish contains the datafiles
PATH/bin/fish contains the fish executable
PATH/etc/fish is sysconf
I am absolutely not sold on that last one - the way I always used
sysconfdir is that it is always /etc. This would be easy to fix but
should probably also be fixed for "regular" relocatable builds (no
idea who uses them).
An attempt at #10916
* Move install path into "install/" subdir
* Disable --install harder if not installable
I forgot that 610338cc70 (On undo after execute, restore the cursor
position, 2024-12-21) would cause a fallout to tests:
It makes us reuse in another place our usual cursor-movement sequences.
This causes failures like this (linebreaks added for readability):
Testing file pexpects/bind.py:Failed to match pattern: (?:\r\n|\x1b\[2 q)[^\n]*def abc\r\n
bind.py:45: timeout from expect_prompt(TO_END + "def abc\r\n") # emacs transpose words, default timeout: no delay
Escaped buffer:
\x1b[?2004h\x1b[>4;1m\x1b[=5u\x1b=\rprompt 2>echo \rprompt 2>echo abc \rprompt 2>echo def abc\r
prompt 2>echo def abc\x1b[?2004l\x1b[>4;0m\x1b[=0u\x1b>\x1b]133;C\x07def abc\r\n\x1b]133;D;0\x07\x1b[?25h⏎
\r⏎ \r\rprompt 3>\x1b[?2004h\x1b[>4;1m\x1b[=5u\x1b=
It seems that we don't print anything where we should print something
like "\r\n" or "\e[2 q" to move the cursor below the command line.
I haven't gotten to the bottom of this but it might be related to
terminfo. Once we get rid of that, we can unconditionally print
our canonical movement sequences.
This issue seems to only affect tests, since fish operates fine in
a sourcehut CI system. Let's ignore it for now.
Ever since 149594f974 (Initial revision, 2005-09-20), we move the
cursor to the end of the commandline just before executing it.
This is so we can move the cursor to the line below the command line,
so moving the cursor is relevant if one presses enter on say, the
first line of a multi-line commandline.
As mentioned in #10838 and others, it can be useful to restore the
cursor position when recalling commandline from history. Make undo
restore the position where enter was pressed, instead of implicitly
moving the cursor to the end. This allows to quickly correct small
mistakes in large commandlines that failed recently.
This requires a new way of moving the cursor below the command line.
Test changes include unrelated cleanup of history.py.
Commit 8bf8b10f68 (Extended & human-friendly keys, 2024-03-30) stopped
ctrl-c from exiting without a motivation. Unfortunately this was
only noticeable on terminals that speak the kitty keyboard protocol,
which is probably no one had noticed so far.
Closes#10928
This reverts commit 27c7578760.
dust generates its own completions (which are shipped in the wrong spot
in the Debian packages, but which are also more up-to-date).
Closes#10922.
The apple-codesign crate has a fairly aggressive MSRV policy, and the
compiler itself still targets 10.12 which is well below the minimum
version of macOS for aarch64. Just use stable.
The version of rclone is set during compilation and could be any crazy string depending on the packager, whether it's a dev build, etc. If it cannot be parsed, let's assume a recent version.
Follows up on cc8fa0f7
This is allowed
time a=b echo 123
but -- due to an oversight in 3de95038b0 (Make "time" a job prefix,
2019-12-21) -- this is not allowed:
not time a=b echo 123
Instead, this one one works:
not a=b time echo 123
which is weird because without the "not" this would run "/bin/time".
It seems wrong that "not" is not like the others. Swap the order
for consistency.
Note that unlike "not", "time" currently needs to come before variable
assignments, so "a=b time true" is disallowed. This matches zsh. POSIX
shells call "/bin/time" here. Since it's ambiguous, erroring out seems
fine. It's weird that we're inconsistent with not here but I guess
"command not" is not expected to have subtly different behavior.
Closes#10890
This was added accidentally in 971d257e67 (Port AST to Rust,
2023-04-02). It does not seem to be causing an observable effect
(although I didn't try hard).
It's pretty annoying that this panics without sphinx, because the
install itself would be *working*.
So instead we tell the user that they need to clean or set
$FISH_BUILD_DOCS if they want to try again.
We get "undefined reference to `__memmove_chk'" when compiling
pcre2 (via pcre2-sys) on newer Ubuntu.
That one is used with higher fortify_source levels, and Ubuntu 24.04
defaults to 3, while my arch system (where I cannot reproduce)
defaults to 2.
The values we would try are:
xterm-256color, xterm, ansi, dumb
This is a pretty useless list, because systems without
"xterm-256color" but with "ansi" basically don't exist,
and it is very likely that the actual terminal is more
xterm-compatible than it is ansi.
So instead we just use our xterm-256color definition, which has a high
likelihood of being basically correct.
This is fairly subtle.
When installable, and we either can't find the version file or it is
outdated, we ask the user to confirm installation (just like `--install`).
We do that only if we are really truly interactive (with a tty!) to
avoid `fish -c` running into problems.
This check could be tightened even more, because currently:
```fish
fish -ic 'echo foo'
```
asks, while
```fish
fish -ic 'echo foo' < /dev/null
```
does not.
`fish -c` will still error out if it can't find the config, but it
will just run if it is out of date.
Unfortunately it does not appear like #[cfg(test)] works for build.rs?
Investigating a better solution, but this is a good idea anyway (or `make
test` would generate man pages via build.rs!)
This is unfortunately necessary, because otherwise it would not rerun
the build script just because you installed sphinx.
Because we use the man pages for --help output, they're pretty
necessary.
To override it, you can set $FISH_BUILD_DOCS=0, like
```fish
FISH_BUILD_DOCS=0 cargo install --path .
```
fish will print messages for some jobs when they exit abnormally, such as
with SIGABRT. If a job exits abnormally inside the prompt, then (prior to
this commit) fish would print the message and re-trigger the prompt, which
could result in an infinite loop. This has existed for a very long time.
Fix it by reaping jobs after running the prompt, and NOT triggering a
redraw based on that reaping. We still print the message but the prompt is
not executed.
Add a test.
Fixes#9796
This built on my test system, might be version differences.
(it's also not enough to make it *work*, but a necessary step)
This reverts commit 6fded249cd.
Commit 29dc30711 (Insert some completions with quotes instead of
backslashes, 2024-04-13) wrongly copmletes
$ cat ~/space
to
$ cat '~/path with spaces'
Today completions can be either replacing or appending. We never quote
(but backslash-escape) appending completions (unless they "append"
to an empty token). We always quote replacing completions. The
assumption in this part of the code is that replacing completions
can be quoted without changing meaning.
This assumption is wrong for tildes. For the backslash-escaping code
path, we take care of this edge case via a special DONT_ESCAPE_TILDES
flag. However that flag does not take effect when using quotes for
escaping. Fix that.
Unfortunately, e97a4fab7 (Escape : and = in file completions,
2024-04-19) introduced a (hopefully temporary) code clone in
escape_separators, which made added an extra step to debugging here.
For x86_64 and cross-compiled for aarch64, manually triggered
It *seems* to work, but I had to explicitly disable gettext for it (which is AFAICT currently non-functional under musl anyway).
Also it will create one .zip containing two .tar.xzs. It is about 8MB, which should be fine, tbh.
When built with the default "installable" feature, the data files (share/) are
included in the fish binary itself.
Run `fish --install` or `fish --install=noconfirm` (for
non-interactive use) to install fish's data files into ~/.local/share/fish/install
To figure out if the data files are out of date, we write the current version
to a file on install, and read it on start.
CMake disables the default features so nothing changes for that, but this allows installing via `cargo install`,
and even making a static binary that you can then just upload and have extract itself.
We set $__fish_help_dir to empty for installable builds, because we do not have
a way to generate html docs (because we need fish_indent for highlighting).
The man pages are found via $__fish_data_dir/man
This now allows:
- Same argument (`random 5 5`)
- Swapped ends (`random 10 2`)
- One possibility (`random 0 5 4`)
This makes it easier to use with numbers generated elsewhere instead
of hard-coded, so you don't need to check as much before running it.
Fixes#10879
We don't really care if the process has a custom handler installed, we
can just set it to default.
The one we check is SIGHUP, which may be given to us via `nohup`.
This saves ~30 syscalls *per process* we spawn, so:
```fish
for f in (seq 1000)
command true
end
```
has ~30000 fewer rt_sigaction calls. These take up about ~30% of the
total time spent in syscalls according to strace.
We could also compute this set once at startup and then reuse it.
We turned it off, but for some reason (cmake version?) that stopped working on my system.
So instead we just remove all the code that does it.
To be honest I do not know why this exists anyway.
exists_no_autoload() wrongly thinks that tombstoned functions can be
autoloaded; fix that.
While at-it replace the use of get_props() with something simpler.
Co-authored-by: Himadri Bhattacharjee
Closes#10873
The [disambiguate flag](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#disambiguate) means that:
> In particular, ctrl+c will no longer generate the SIGINT signal,
> but instead be delivered as a CSI u escape code.
so cancellation only works while we turn off disambiguation.
Today we turn it off while running external commands that want to
claim the TTY. Also we do it (only as a workaround for this issue)
while expanding wildcards or while running builtin wait.
However there are other cases where we don't have a workaround,
like in trivial infinite loops or when opening a fifo.
Before we run "while true; end", we put the terminal back in ICANON
mode. This means it's line-buffered, so we won't be able to detect
if the user pressed ctrl-c.
Commit 8164855b7 (Disable terminal protocols throughout evaluation,
2024-04-02) had the right solution: simply disable terminal protocols
whenever we do computations that might take a long time.
eval_node() covers most of that; there are a few others.
As pointed out in #10494, the logic was fairly unsophisticated then:
it toggled terminal protocols many times. The fix in 29f2da8d1
(Toggle terminal protocols lazily, 2024-05-16) went to the extreme
other end of only toggling protocols when absolutely necessary.
Back out part of that commit by toggling in eval_node() again,
fixing cancellation. Fortunately, we can keep most of the benefits
of the lazy approach from 29f2da8d1: we toggle only 2 times instead
of 8 times for an empty prompt.
There are only two places left where we call signal_check_cancel()
without necessarily disabling the disambiguate flag
1. open_cloexec() we assume that the files we open outside eval_node()
are never blocking fifos.
2. fire_delayed(). Judging by commit history, this check is not
relevant for interactive sessions; we'll soon end up calling
eval_node() anyway.
In future, we can leave bracketed paste, modifyOtherKeys and
application keypad mode turned on again, until we actually run an
external command. We really only want to turn off the disambiguate
flag.
Since this is approach is overly complex, I plan to go with either
of these two alternatives in future:
- extend the kitty keyboard protocol to optionally support VINTR,
VSTOP and friends. Then we can drop most of these changes.
- poll stdin for ctrl-c. This promises a great simplification,
because it implies that terminal ownership (term_steal/term_donate)
will be perfectly synced with us enabling kitty keyboard protocol.
This is because polling requires us to turn off ICANON.
I started working on this change; I'm convinced it must work,
but it's not finished yet. Note that this will also want to
add stdin polling to builtin wait.
Closes#10864
Moving the "make empty ToLowercase iterator" logic to within the
`unwrap_or_else()` instead of always generating it brings most of the speedup;
unrolling the recursive call brings in the rest.
Using `c.is_uppercase()` instead of getting the iterator and checking if the
first (and only) lowercase letter of the sequence is the same as the original
input is 5-8x faster (measured via criterion against `/usr/share/dict/words`).
(Additional benefit of forcibly inlining the now iterator-based comparison not
taken into account; this necessitated changing from a closure to a local
function as the inline attribute on closures is not yet supported with the
stable compiler toolchain.)
This is still suboptimal because we are allocating a vector of indices to be
removed (but allocation-free in the normal case of no duplicates) but
significantly better than the previous version of the code that duplicated the
strings (which are larger and spread out all over the heap).
The ideal code (similar to what we had in the C++ version, iirc) would look like
this, but it's not allowed because the borrow checker hates you:
```
fn unique_in_place_illegal(comps: &mut Vec<Completion>) {
let mut seen = HashSet::with_capacity(comps.len());
let mut idx = 0;
while idx < comps.len() {
if !seen.insert(&comps[idx].completion) {
comps.remove(idx);
continue;
}
idx += 1;
}
}
```
This was an sh-script that just invoked fish again.
I can see how we could implement it in another language to avoid the
fish under test corrupting the results, but it literally invoked the
fish under test anyway.
Mostly we pass on the options - otherwise they would be ignored.
For `clear`, we do need the full checks, because that will
prompt *before* running the builtin.
But this makes it easier to eventually move that logic into the builtin
If a semicolon-delimited list of CSI parameters contained an (invalid) long
sequence of ascii numeric characters, the original code would keep multiplying
by ten and adding the most recent ones field until the `params[count][subcount]`
u32 value overflowed.
This was found via automated fuzz testing of the `try_readch()` routine against
a corpus of some proper/valid CSI escapes.
This lets us call into the entirety of the prior `readch()` with an exhaustible
input stream without panicking on the `unreachable!()` call. The previous
functionality is kept under the old name by calling `try_readch()` with the
`blocking` parameter set to `true` (100% same behavior as before).
While the `try_readch(false)` entrypoint isn't used directly by the current fish
codebase, it is required in order to automate input reader tests without the
overhead and complexity of running the test harness in a tty emulator emulator
like pexpect or tmux, which moreover necessitates out-of-process testing – which
is incompatible with most perf-guided testing harnesses.
I hope to be able to upstream harness integrations using this entry point in the
near future.
These are pretty basic, but get us roughly up to the level of the
official completions (that are also incomplete and offer disabled
options).
Fixes#10858
`print_help` is a hacky-wacky function used to support the `--help` command
of `fish_key_reader` and others. The Rust version panics on an error; fix
that and make it print more useful help messages.
* feat(function): move cmd completion function to a separate file
* feat(completion): support wine cmd subcommand
* feat(completion): support wine control subcommand
* feat(completion): support wine eject subcommand
* feat(completion): support wine explorer subcommand
* feat(completion): support wine explorer subcommand for desktops
* feat(completion): support wine start subcommand
* feat(completion): support wine winemenubuilder subcommand
* feat(completion): support wine winepath subcommand
* fix(function): rename function for cmd argument completion
* feat(function): implement function to complete registry keys
* feat(completion): support wine regedit subcommand
* feat(function): add top-level key descriptions
* fix(completion): remove redundant comment
* feat(completion): support wine msiexec subcommand
* refactor(completion): group code into functions
* feat(completion): enhance subcommand descriptions
I'm guessing this was missed in the port because there were comments referencing
using a hash set to perform the deduplication but there was no hashset. (The
TODO was added later.)
This caught an incorrect description for process/job exit handlers for ANY_PID
(now removed) which has been replaced with a message stating the handler is for
any process exit event.
The previous approach of "treat this field as an `Option<NonZeroU32>` and
remember to check `p.has_pid()` before accessing it" was a mix of C++ and rust
conventions and led to some bugs or incorrect behaviors.
* `jobs -p` would previously print both the (correct) external pid and the
(incorrect) internal value of `0` if a backgrounded command contained a
fish function (e.g. `function foo; end; cat | foo &; jobs`)
* Updating/calculating job cpu time and usage was incorrectly including all of
fish's cpu usage/time for each function/builtin member of the job pipeline.
Closes#10832
ctrl-r ctrl-s ctrl-s
Attemps to go before the beginning and asserts out. Instead refuse to
do that.
(there's some weirdness where it can reduce the pager to the first
entry if you keep pressing, which I haven't found yet, but that's better than *crashing*)
CMake Warning (dev) at cmake/Tests.cmake:56 (add_custom_command):
Exactly one of PRE_BUILD, PRE_LINK, or POST_BUILD must be given. Assuming
POST_BUILD to preserve backward compatibility.
Policy CMP0175 is not set: add_custom_command() rejects invalid arguments.
Run "cmake --help-policy CMP0175" for policy details. Use the cmake_policy
command to set the policy and suppress this warning.
So we just keep it the same.
These are another way to spell the same thing that doesn't match what
`bind` would print.
They're also not documented and tested thoroughly.
Since they are just small shortcuts and unreleased we can just remove
them.
Fixes#10845
This has the side effect of changing the order of completions for a bare `git
diff` to show modified files before revisions; previously they came at the very
end after all revisions, stashes, local branches, remote branches, and tags.
That seems sensible to me?
As I understand the completions file, it seems to me that the intention was for
`git diff src/` to only show modified files to begin with it
previously/currently shows them all, so we might want to add a `-n 'not ...'`
condition for `git diff` to prevent that.
fish by default shows a git-aware prompt. Recall that on macOS, there are
two hazards we must avoid:
1. The command `/usr/bin/git` is installed by default. This command is not
actually git; instead it's a stub which pops open a dialog proposing to
install Xcode command line tools. Not a good experience.
2. Even after installing these tools, the first run of any `git` or other
command may be quite slow, because it's now a stub which invokes `xcrun`
which needs to populate a cache on a fresh boot. Another bad experience.
We previously attempted to fix this by having `xcrun` print out its cache
path and check if there's a file there. This worked because `xcrun` only
lazily created that file. However, this no longer works: `xcrun` now
eagerly creates the file, and only lazily populates it. Thus we think git
is ready, when it is not.
(This can be reproduced by running `xcrun --kill-cache` and then running
the default fish shell prompt - it will be slow).
Change the fix in the following way: using sh, run `/usr/bin/git --version;
touch /tmp/__fish_git_ready` in the background. Then detect the presence of
/tmp/__fish_git_ready as a mark that git is ready.
Fixes#10535
Given "printf %18446744073709551616s", we parse the number only in
the printf crate, which tells us that we overflowed somwhere (but
not where exactly).
We were previously printing the internal `INVALID_PID` value (since removed),
which was a meaningless `-2` constant, when there was no pgid associated with a
job.
This PR changes that to `-` to indicate no pgid available, which I prefer over
something like `0` or `-1`, but will cause problems for code that is hardcoded
to convert this field to an integral value.
Just like we already fix terminal modes if a command left them broken,
having an invisible cursor makes the terminal hard to use and so we
fix it.
We can't really use cnorm/cursor_normal because that often includes
other gunk like making the cursor blink, but it turns out every
terminfo entry agrees on the sequence to make the cursor visible, so
we hardcode it.
Fixes#10834
This is nicer when you use fish over ssh, and that system does not
have a browser. But the system where your terminal is has one, and so
now you can just click the link.
If we end up using this in more places, we can create a `Pid` newtype.
Note that while the constant is no longer used in code, its previous value of -2
is still printed by `jobs` when no pgid is associated with a job. I will open a
PR to change this to something else, likely either `0` or `-`.
If we try to memory map the history file, and we get back ENODEV meaning that
the underlying device does not support memory mapping, then treat that as a hint
that the filesystem is remote and disable history locking.
As of 04c913427 (Limit command line rendering to $LINES lines,
2024-10-25), we only render a part of the command line. This removes
valuable information from scrollback.
The reasons for the limit were
1. to enable redrawing the commandline (can't do that if part of it
is off-screen).
2. if the cursor is at the beginning of the command-line, we can't
really render the off-screen suffix (unless we can tell the terminal
to scroll back after doing that).
Fortunately these don't matter for the very last rendering of a
command line. Let's render the entire command just before executing,
fixing the scrollback for executed commands.
In future, we should fix it also for pre-execution renderings. This
needs a terminal command to clear part of the scrollback. Can't find
anything on https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
There is "Erase Saved Lines" but that deletes the entire scrollback.
See the discussion in #10827
Since f89909ae3 (Also handle overflown screens if editing pager search
field, 2024-10-27), cursor_arr is never None after the loop.
Assert that by unwrapping.
qa.sh
alt-e restores the cursor position received from the editor, moving by
one character at a time. This can be super slow on large commandlines,
even on release builds. Let's fix that by setting the coordinates
directly.
This happens when using alt-e to edit the command buffer,
adding some lines, leaving the cursor at the end
and quitting the editor without saving.
Let's avoid the noisy error that has sort of bad rendering (would
need __fish_echo).
Our recursive create_dir() first calls stat() to check if the directory
already exists and then mkdir() trying to create it. If another (fish)
process creates the same directory after our stat() but before our
mkdir(), then our mkdir() fails with EEXIST. This error is spurious
if there is already a directory at this path (and permissions are
correct).
Let's switch to the stdlib version, which promises to solve this issue.
They currently do it by running mkdir() first and ask stat() later.
This implies that they will only return success even if we don't have
any of rwx permissions on the directory, but that was already a problem
before this change. We silently don't write history in that case..
Fixes#10813
All-whitespace autocompletions are invisible, no matter the cursor
shape. We do offer such autosuggestions after typing a command name
such as "fish". Since the autosuggestion is invisible it's probably
not useful. It also does no harm except when using a binding like
bind ctrl-g '
if commandline --showing-suggestion
commandline -f accept-autosuggestion
else
up-or-search
end'
where typing "fish<ctrl-g>" surprisingly does not perform a history
search. Fix this by detecting this specific case. In future we
could probably stop showing autosuggestions whenever they only
contain whitespace.
With BSD man, "PAGER=vim man man | cat" hangs because
[man](https://cgit.freebsd.org/src/tree/usr.bin/man/man.sh) wrongly
calls the pager even though stdout is not a terminal.
This hang manifests in places where we call apropos in a subshell,
such as in "complete -Ccar".
Let's work around this I guess. This should really be fixed upstream
because it's a problem in every app that wants to display man pages
but doesn't emulate a complete terminal.
Weirdly, the Apple derivative of man.sh uses WHATISPAGER instead
of MANPAGER.
Closes#10820
A release build is recommended to most users (to avoid occasional slowness)
whereas developers may prefer debug builds for shorter build times and more
accurate debug information.
There are more users of "make install" than developers, so I think the
default should be optimized for users, i.e. an optimized build. I think
that's in line with what most of our peer projects do.
Even if developers don't know about the -DCMAKE_BUILD_TYPE=Debug
trick, they will likely be able to iterate quickly by using "cargo
{build,check,clippy,test}" and rust-analyzer, all of which use a debug
configuration by default, irrespective of cmake. Granted, users will need
to use cmake to run system tests. If a task needs a lot of iterations,
one can always convert the system test to a script that can be run with
target/build/fish. For building & running all system tests, the release
build takes 30% longer, so not that much.
Here are my build/test times and binary sizes; with debug:
$ time ninja -C build-Debug/
________________________________________________________
Executed in 25.30 secs fish external
usr time 68.33 secs 676.00 micros 68.32 secs
sys time 11.34 secs 41.00 micros 11.34 secs
$ du -h build-Debug/fish
43M build-Debug/fish
$ time ninja -C build-Debug/ test
________________________________________________________
Executed in 193.96 secs fish external
usr time 182.84 secs 1.53 millis 182.83 secs
sys time 30.97 secs 0.00 millis 30.97 secs
with release
$ time ninja -C build-RelWithDebInfo/
________________________________________________________
Executed in 106.80 secs fish external
usr time 164.98 secs 631.00 micros 164.98 secs
sys time 11.62 secs 41.00 micros 11.62 secs
$ du -h build-RelWithDebInfo/fish
4.6M build-RelWithDebInfo/fish
$ time ninja -C build-RelWithDebInfo/ test
________________________________________________________
Executed in 249.87 secs fish external
usr time 260.25 secs 1.43 millis 260.25 secs
sys time 29.86 secs 0.00 millis 29.86 secs
Tangentially related, the numbers with "lto = true" deleted. This seems
like a nice compromise for a default but I don't know much about the other
benefits of lto.
$ time ninja -C build-RelWithDebInfo-thin-lto/
________________________________________________________
Executed in 35.50 secs fish external
usr time 196.93 secs 0.00 micros 196.93 secs
sys time 13.00 secs 969.00 micros 13.00 secs
$ du -h build-RelWithDebInfo-thin-lto/fish
5.5M build-RelWithDebInfo-thin-lto/fish
$ time ninja -C build-RelWithDebInfo-thin-lto/ test
________________________________________________________
Executed in 178.62 secs fish external
usr time 287.48 secs 976.00 micros 287.48 secs
sys time 28.75 secs 115.00 micros 28.75 secs
Alternative solution: have no default at all, and error out until the user
chooses a build type.
Currently the only difference between RelWithDebInfo and Release is that
the former adds -g (aka debuginfo=2) though it doesn't seem to make a lot
of difference in my testing.
Since build_tools/make_pkg.sh and debian/rules use RelWithDebInfo, let's be
consistent with those.
Some background: fish has some files which should be updated atomically:
specifically the history file and the universal variables file. If two fish
processes modified these in-place at the same time, then that could result
in interleaved writes and corrupted files.
To prevent this, fish uses the write-to-adjacent-file-then-rename to
atomically swap in a new file (history is slightly more complicated than
this, for performance, but this remains true). This avoids corruption.
However if two fish processes attempt this at the same time, then one
process will win the race and the data from the other process will be lost.
To prevent this, fish attempts to take an (advisory) lock on the target
file before beginning this process. This prevents data loss because only
one fish instance can replace the target file at once. (fish checks to
ensure it's locked the right file).
However some filesystems, particularly remote file systems, may have locks
which hang for a long time, preventing the user from using their shell.
This is far more serious than data loss, which is not catastrophic: losing
a history item or variable is not a major deal. So fish just attempts to
skip locks on remote filesystems.
Unfortunately Linux does not have a good API for checking if a filesystem
is remote: the best you can do is check the file system's magic number
against a hard-coded list. Today, the list is NFS_SUPER_MAGIC,
SMB_SUPER_MAGIC, SMB2_MAGIC_NUMBER, and CIFS_MAGIC_NUMBER.
Expand it to AFS_SUPER_MAGIC, CODA_SUPER_MAGIC, NCP_SUPER_MAGIC,
NFS_SUPER_MAGIC, OCFS2_SUPER_MAGIC, SMB_SUPER_MAGIC, SMB2_MAGIC_NUMBER,
CIFS_MAGIC_NUMBER, V9FS_MAGIC which is believed to be exhaustive.
ALSO include FUSE_SUPER_MAGIC: if the user's home directory is some FUSE
filesystem, that's kind of sus and the fewer tricks we try to pull, the
better.
As mentioned in 04c913427 (Limit command line rendering to $LINES
lines, 2024-10-25) our rendering breaks when the command line overflows
the screen and we have a pager search field.
Let's also apply the overflow logic in this case.
Note that the search field still works, it's just not visible.
In future we should maybe show a small search field (~4 lines) in
this case (removing 4 screen lines worth of command line). But again,
this is not really important.
If the first physical line in the command line overflows the screen,
the cursor will be wrong and we'll fail to clear the prompt without
a manual ctrl-l. Let's fix that, and also don't print the OSC 133
marker in this case.
Currently, when we are scrolled, the first line on the screen still
gets an indentation that would normally be filled by the prompt.
This happens even for soft-wrapped lines, so they might be
torn apart in weird ways here.
In future, we might paint the prompt here. If not, the current
behavior for soft-wrapped lines is debatable but its' not super
important to fix. The main goal is to first get rid of glitches in
these edge cases.
This test does "isolated-tmux send-keys Escape" to exit copy mode. When
EDITOR contains "vi", tmux will use Vi keybindings where Escape does
something else ("q" would exit copy mode).
Tests want to have predictable behavior so let's declare the default
emacs key bindings unconditionally.
Fixes#10812
This added link args to target macOS 10.9, but these arguments are not necessary
when building via the make_pkg.sh script, and this file is causing other
problems.
Let's provide a sensible default here. Use a line for "insert" and an
underline for "replace_one" mode. Neovim does the same, it feels pretty
slick.
As mentioned in #10806
As of the parent commit, __fish_vi_key_bindings_remove_handlers
should be working properly now, so this is no longer necessary That
function also cleans up other stuff like fish_cursor_end_mode, that
fish_default_key_bindings doesn't know anything about.
Also this fixes a spurious exit status of 4 in some scenarios.
fish_key_bindings may be set directly
or via fish_{default,vi}_key_bindings.
The latter use "set --no-event" to simplify their control
flow. This (24836f965 (Use set --no-event in the key binding
functions, 2023-01-10)) broke Vi mode cleanup, since Vi mode
uses a variable hook. Let's update this variable also when using
fish_{default,vi}_key_bindings. Another reason to keep this variable
in sync is to make the fish_key_bindings handlers working as expected.
Render the command line buffer only until the last line we can fit
on the screen.
If the cursor pushes the viewport such that neither the prompt nor
the first line of the command line buffer are visible, then we are
"scrolled". In this case we need to make sure to erase any leftover
prompt, so add a hack to disable the "shared_prefix" optimization
that tries to minimize redraws.
Down-arrow scrolls down only when on the last line, and up-arrow always
scrolls up as much as possible. This is somewhat unconventional;
probably we should change the up-arrow behavior but I guess it's a
good idea to show the prompt whenever possible. In future we could
solve that in a different way: we could keep the prompt visible even
if we're scrolled. This would work well because at least the left
prompt lives in a different column from the command line buffer.
However this assumption breaks when the first line in the command
line buffer is soft-wrapped, so keep this approach for now.
Note that we're still broken when complete-and-search or history-pager
try to draw a pager on top of an overfull screen. Will try to fix
this later.
Closes#7296
It's a 9-char CSI and we've read 3 (`<ESC>[T`), so we need to read six more.
Verified against the previous C++ codebase and couldn't find a reason for the
change to consuming 10 chars in a `git blame` run.
Commit ba67d20b7 (Refresh TTY timestamps after nextd/prevd, 2024-10-13)
wasn't quite right because it also needs to fix it for arbitrary commands.
While at it, do this only when needed:
1. It seems to be only relevant for multiline prompts.
Note that we can wait until after evaluation to check if the prompt is
multiline, because repaint events go through the queue, see 5ba21cd29
(Send repaint requests through the input queue again, 2024-04-19).
2. When the binding doesn't execute any external command, we probably don't
need to fix up whatever the user printed. If they actually wanted to show
output and print another prompt, they should currently use "__fish_echo",
to properly support multiline prompts. Bindings should produce no other
output. What distinguishes external programs is that they can trigger this
issue even if they don't produce any output that remains visible in fish,
namely by using the terminal's alternate screen.
Would be nice if we could get rid of __fish_echo; I'm not yet sure how.
Fixes#10800
A side effect of cd9e50c2c (completions/set: Complete variables of all scopes
when setting, 2024-10-03) is that
HOME=$(mktemp -d) fish
fish_config choose ayu\ Light
set -S fish_color_
gives only completions that have the "Universal variable" description even
though most colors are also defined in the global scope which usually takes
precedence.
Fix this by reordering the completions. (The last-added completion is shown
first which is very surprising, we should change that).
This is not perfect; if the user has already specified `-U`, then we should
probably not show description of the global version. But that's still
worth the trade that this commit makes. Finally, the description could show
something like "Defined in universal and global scope" etc.
The test case shows that the pager rendering is not quite right. It renders
'{\', leaving out the newline. This rendering is ambiguous.
Let's fix it by rendering \n as control picture, like we do for other control
characters in the pager.
Given
$ echo {\
C
where C is the cursor.
Completions have prefix "{\\\n".
Since \n has a wcwidth of -1, this line always fails
let prefix_len = usize::try_from(fish_wcswidth(&self.prefix));
This triggers uncovers a regression in 43e2d7b48 (Port pager.cpp, 2023-12-02),
where we end up computing comp_width=0 for all completions.
Fix this. Test in the next commit.
The C++ version added the prefix width only if the completion had a valid
width. That seems wrong, let's do it always (if the prefix width is valid).
Completion on ": {*," used to work but nowadays our attempt to wildcard-expand
it fails with a syntax error and we do nothing. This behavior probably only
makes sense for the overflow case, so do that.
On a German keyboard, with a German keymap, and this ~/.wezterm.lua
local wezterm = require 'wezterm'
local config = wezterm.config_builder()
config.enable_kitty_keyboard = true
return config
when I press shift+# (which is single quote)
WezTerm sends the CSI u encoding shift-'.
Because of this, we completely disable kitty progressive enhancements and
modifyOtherKeys on WezTerm.
It makes no sense for every single app to work around WezTerm violating the
protocol. All these workarounds just create unnecessary version dependencies.
Also our workaround is brittle; it breaks as soon as you're inside something
like SSH.
Least importantly, the workarond prevents users of English keyboard layouts
to easily use the new features.
Since it seems so easy to work around by settting "enable_kitty_keyboard = false",
and most importantly, since that's the default, it seems better to remove
the workaround to simplify the world.
See #10663
This makes the default colorscheme less colorful for two reasons:
1. It makes it a little less "angry fruit salad"
2. Some terminals (like Microsoft's Windows Terminal) have a terrible
blue default that contrasts badly against a black background
The alternative is to make *parameters* "normal" and give commands the
current parameter color (cyan). But I've seen cyan be quite blue and
quite green depending on the terminal, so I don't want to rely on it.
`cargo build --git` clones a git repo without any tags, so you get a
version like
```
fish, version f3fc743fc
```
which is *just* the commit hash and missing the "3.7.1-NUM-g" part.
So, if we hit that case (detected because it has no ".", under the
assumption that we'll never make a version that's just "4" instead of
"4.0"), we prepend the version from Cargo.toml.
Commit 5db0bd5 (Lock history file before reading it, 2024-10-09)
rewrites the history file in place instead of using rename().
By writing to the same file (with the same inode), it corrupts
our memory-mapped snapshot; mmap(3) says:
> It is unspecified whether modifications to the underlying object done
> after the MAP_PRIVATE mapping is established are visible through the
> MAP_PRIVATE mapping.
Revert it (it was misguided anyway).
Closes#10777Closes#10782
There is no natural default binding for token movements. Add the
alt-{left,right,backspace,delete}, breaking some existing behavior.
For example, backward-delete-word is no longer bound to alt-backspace but
only to ctrl-backspace. Unfortunately some terminals (particularly tmux)
don't support distinguishing ctrl-backspace from ctrl-h yet, so the loss
of alt-backspace may be tragic.
---
I guess we could also add:
bind alt-B backward-token
bind alt-F forward-token
bind ctrl-W backward-kill-token
bind alt-D kill-token
Those might be intercepted by the terminal on Linux, but I don't know where
that happens.
Tested on foot, kitty, alacritty, xterm, tmux, konsole and gnome-terminal.
Closes#10766
Commit a91bf6d88 (builtin.c: builtin_source now checks that its argument is
a file., 2005-12-16) fixed an infinite loop for commands like "source /"
where the argument is a directory.
It did so by erroring out early unless the filename argument is a regular file.
This is too restrictive; it disallows reading from special files like /dev/null
and fifos.
Today we get a sensible error without this check, so remove it.
This fixes a macOS-specific bug. See 390b40e02 (Fix regression not refreshing
TTY timestamps after external command from binding, 2024-05-29) and 8a7c3ceec
(Don't abandon line after writing control sequences, 2024-04-06).
Fixes#10779
OSC 133 was added to tmux 3.4.
Also fix the test on macOS where we do have 3.5a in CI; for some reason we
get copy_cursor_y=6 there. I didn't investigate yet but at least that's
not the same bug this test was made to fix.
For multi-line prompts, we start each leading line with a clr_eol. Immediately
before printing these prompt lines we emit the OSC 133 prompt start marker.
Some terminals such as tmux interpret make clr_eol delete such markers,
hence prompt navigation is broken.
Fix this by printing the marker only after clr_eol.
The scenario where this triggers is quite odd. I haven't looked into why
the problem doesn't exist if I remove the recursive repaint request.
See https://github.com/tmux/tmux/issues/4183Closes#10776
Our panic handler attempts a blocking read from stdin and only exits
after the user presses Enter.
This is unconventional behavior and might cause surprise but there is a
significant upside: crashes become more visible for terminals that don't
already detect crashes (see ecdc9ce1d (Install a panic handler to avoid
dropping crash stacktraces, 2024-03-24)).
As reported in 4d0aa2b5d (Fix panic handler, 2024-08-28), the panic handler
failed to exit fish if the panic happens on background threads. It would
only exit the background thread (like autosuggestion/highlight/history-pager
performer) itself. The fix was to abort the whole process.
Aborting has the additional upside of generating a coredump.
However since abort() skips stack unwinding, 4d0aa2b5d makes us no longer
restore the terminal on panic. In particular, if the terminal supports kitty
progressive enhancements, keys like ctrl-p will no longer work in say,
a Bash parent shell. So it broke 121680147 (Use RAII for restoring term
modes, 2024-03-24).
Fix this while still aborting to create coredumps. This means we can't use
RAII (for better or worse). The bad part is that we have to deal with added
complexity; we need to make sure that we set the AT_EXIT handler only after
all its inputs (like TERMINAL_MODE_ON_STARTUP) are initialized to a safe
value, but also before any damage has been done to the terminal. I guess we
can add a bunch of assertions.
Unfortunately, if a background thread panics, I haven't yet figured out how
to tell the main thread to do the blocking read. So the trick of "Press
Enter to exit", which allows users to attach a debugger doesn't yet work for
panics in background threads. We can probably figure that out later. Maybe
use pthread_kill(3)? Of course we still create coredumps, so that's fine.
As a temporary workaround, let's sleep for a bit so the user can at least
see that there is a crash & stacktrace.
One ugly bit here is that unit tests run AT_EXIT twice but it should be
idempotent.
I don't think I really get why this newline is here. It moves the cursor
from the end of the newline to the beginning of the next line. Maybe it
was added only for panics in background threads? Either way it's fine.
We don't care to check the latest value of these variables;
these should only be read on startup and are not meant to
be overridden by the user ever. Hence we don't need a parser.
If SIGTERM is delivered to a background thread, a function call to sanitize
the reader state would crash in assert_is_main_thread(). In this case we
are about to exit so there's no need to fix the reader state. Skip it on
background threads.
Users may install two versions of fish and configure their terminal to run
the one that is second in $PATH. This is not really what I'd do but it
seems reasonable. We should not need $PATH for this.
Fixes#10770
We use optimistic concurrency when rewriting the history file to
minimize the lock scope. Unfortunately, old.mtime == new.mtime
does not imply that file is unchanged; we don't have guarantees
on the granularity of the modification time timestamp, see
https://stackoverflow.com/questions/14392975/timestamp-accuracy-on-ext4-sub-millsecond
So let's lock before reading any old contents and use the other
"write-to-tempfile-and-rename" code path only when locking fails.
Potentially fixes#10300
(untested) which probably happens because read_zero_padded() attempts to
read bytes that have not been flushed yet.
No functional change, since with the parent commit, we no longer treat
"DirRemoteness::local" different from "DirRemoteness::remote", but we might
do so in future, so make sure we don't give a false positive here.
Non-Linux systems have ST_LOCAL or MNT_LOCAL, so no unknowns there.
See #10434
mmap() fails with ENODEV on remote file systems. This means we always fail
to read any old history on network file systems on Linux (except on the file
systems we recognize which are NFS, SMB and CIFS).
Untested, so I'm not sure if this works.
Fixes#10434
We no longer use RAII for enabling/disabling these, so a full object is
overkill. Additionally this object doesn't allow us to recover from the case
where we receive SIGTERM while inside terminal_protocols_{enable,disable}.
We can simply run disable another time since they're idempotent. Untested.
When I run a command with leading space, it is not added to the on-disk
history. However we still call History::save(). After 25 of such calls,
we rewrite the history file (even though nothing was written by us).
This is annoying when diagnosing #10300 where the history of the current
shell (but not other shells) is broken; because the history rewrite will
make the problem go away. Let's not save in this case, to make it easier to
run commands to inspect the state of the history file.
Commit 4e79ec5f tried to restore the static PCRE2 build after the update to the
pcre2 crate, but it set an environment variable at configure time, not build
time.
Properly set the environment variable at build time.
Given a history like
- cmd: echo OLD
when: 1726157160
\x00\x00\x00- cmd: echo leading NUL bytes
when: 1726157160
- cmd: echo NEW
when: 1726157223
offset_of_next_item() happily records 3 items even though the second item
is corrupted.
decode_item() fails which makes the caller stop loading any older items --
we got knee capped.
Avoid this horrible failure mode by skipping over these items already in
offset computation. For now we still lose the corrupted item itself.
In future we should probably try to delete the NUL bytes or avoid the
corruption in the first place.
See #10300 and others.
This should make the sort have a strict weak ordering, which rust
requires since 1.81 (or it will panic).
Note: This changes the order, but that's *fine* since the current
order is random weirdness anyway.
Fixes#10763
This was overly smart and tried to not show you e.g. global variables
unless you were setting without scope or explicitly global.
That is annoying when you do
`set -g fish_col<TAB>`
and don't get colors because they're universal, but you could
overwrite them.
We *could* elide e.g. local variables if we're setting a global, but I
can see someone wanting to set a universal variable on basis of a
global ("save this"), so I would rather not try to find the very
specific cases where this works.
1. Leave the indentation
2. Leave the "NAME" header - without the first line would be
unindented
3. Leave the "SYNOPSIS" header
We use $MANPAGER here, so it should be formatted like a manpage.
The alternative is to write special docs for this use-case, which
would be shorter and point towards the full man page.
Fixes#10625
They are already presented in normal mode, and I presume were forgotten to be
added in visual mode
I don't add it to ./CHANGELOG.rst because it's a minor change that can be
considered as a bug fix
The recent update to the rust-pcre2 crate lost the property where a static
PCRE2 build could be enabled with a Cargo feature. This means that static
PCRE2 builds can no longer be forced.
Switch to setting the "PCRE2_SYS_STATIC" variable again, which is how the
official rust-pcre2 crate expects to work.
Commit c921c124e (docs: use canonical key names in :kbd: tags, 2024-04-13)
removed the box highlighting from elements like :kbd:`ctrl-c`.
This is because Sphinx for some reason converts this into
<kbd>
<kbd>ctrl</kbd>
-
<kbd>c</kbd>
</kbd>
which results in duplicate boxes.
(See https://github.com/sphinx-doc/sphinx/issues/7530)
Our current style looks a bit ugly (it's
definitely worse than github's rendering at
https://github.com/fish-shell/fish-shell/blob/master/CHANGELOG.rst).
Let's restore the old style but make sure to only apply it only to the
outermost kbd element.
While at it, use the same monospace font as for inline code.
Commit b00899179 (Don't indent multi-line quoted strings; do indent inside
(), 2024-04-28) made parse_util_compute_indents() crash on `echo "$()"'x`.
After recursively indenting the command substitution, we indent the "'x
suffix. We skip the quoted part by setting "done=2". Later we wrongly
index "self.indents[done..range.start+offset+1]" (= "self.indents[2..1]").
Fix this by making sure that "start >= done", thus not setting any indents
for the quoted suffix. There is no need to do so; only the first character
in each line needs an indent.
In particular, this fixes the case
ctrl-r foo ctrl-r
where foo substring-matches no more than one page's worth of results.
The second attempt will fall back to subsequence matching which is wrong.
In case a terminal resize[1] causes us
to repaint a multi-line prompt that changes width like
function fish_prompt
for i in 1 2 3
random choice 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbb'
end
end
we add a clr_eol after each line[2] , to make sure
that a "b" line does not have leftover "a" letters
(80aaae5b7 (Clear to end of each line in left prompt, 2020-10-25)).
Unfortunately, if a prompt line takes up all the columns, clr_eol will
wrongly clear the last column. Reproduce with
function fish_prompt
string repeat $COLUMNS -
echo "$PWD> "
end
and observe that the last "-" is missing.
Previous (reverted) attempt d3ceba107 (Clear to eol before outputting line
in multi-line prompt, 2021-05-17) found the right fix but had an off-by-one
error which reintroduced the leftover "a" letters in the "random choice"
prompt above.
Given prompt string "aa\nbb\ncc", it wrongly printed
clr_eol "aa" clr_eol "\nbb" "\ncc"
Observe that the first line is cleared twice, while the second line is
never cleared. Fix that.
[1]: or an async "commandline -f repaint" triggered by a uvar change /
async prompt update
[2]: except after the last line where we probably already emit clr_eol
elsewhere..
Alternative fix: emit both clr_eol and clr_bol *before* drawing the current
line. However, if fish and the terminal disagree on character width, that
approach might erase too much.
Closes#8164
I guess it's nice to know that these two are the same but that info is not
needed here, it just adds confusion. The user must have pressed ctrl-j if
we get here, so echo that back.
See the parent commit.
This is just too confusing; \b sounds like it would map backspace but it's
actually just ctrl-h. Backspace is a different key ("bind backspace"),
so let's move away from \b.
Reproduce by typing ctrl-h in fish_key_reader, or, for even more confusion,
use a terminal like tmux and type ctrl-backspace which also sends ctrl-h.
I've thought about changing \b (and its aliases like \ch and \x08) to mean
backspace but that seems like unnecessary breakage, since they all already
mean ctrl-h, and can usually be mapped independent of backspace.
See the discussion in #10738
Make fish-printf no longer depend on the widestring crate, as other clients
won't use it; instead this is an optional feature.
Make format strings a generic type, so that both narrow and wide strings can
serve. This removes a lot of the complexity around converting from narrow to
wide.
Add a README.md to this crate.
This gave a weird error when you did e.g. `math Foo / 6`:
"Missing Operator" and only the "F" marked.
Adding an operator here anywhere won't help, so calling this an
"Unknown function" is closer to the truth. We also get nicer markings
because we know the extent of the identifier.
Fix 7308dbc7a (fish_indent: Prevent overwriting file with identical content,
2024-07-21) in a different way by passing O_TRUNC again.
If we don't want regressions we could use code review.
When `manpath` prints a symlink to a directory, `/usr/libexec/makewhatis`
ignores the entire directory:
```
$ /usr/libexec/makewhatis -o /tmp/whatis \
(/usr/bin/manpath | string split :)
makewhatis: /Users/wiggles/.nix-profile/share/man: Not a directory
```
This means that the built-in `man` completions will not index any commands in
these directories.
If we pass the directories to `readlink -f` first, `makewhatis` correctly
indexes the `man` pages.
```
$ /usr/libexec/makewhatis -o /tmp/whatis \
(/usr/bin/manpath | string split : | xargs readlink -f)
```
We used deque in C++ because this vector may be large, and so it avoids
repeated re-allocations. But VecDeque is different in Rust - it's contiguous -
so there's no benefit. Just use Vec.
For implementation reasons, we special-case cd in several ways
1. it gets different completions (handle_as_special_cd)
2. when highlighting, we honor CDPATH
3. we discard autosuggestions from history that don't have valid path arguments
There are some third-party tools like zoxide that redefine cd ("function cd
--wraps ...; ...; end"). We can't support this in general but let's try to
make an effort.
zoxide tries to be a superset of cd, so special case 1 is still
valid but 2 and 3 are not, because zoxide accepts some paths
that cd doesn't accept.
Let's add a hack to detect when "cd" actually means something else by checking
if there is any --wraps argument.
A cleaner solution is definitely possible but more effort.
Closes#10719
fish adds ~/.local/share/fish/man to its MANPATH for builtins etc. But pages
like fish-doc are unambiguous so it seems like they should be accessible
from outside fish by default.
Closes#10711
In some cases we add the wildcard twice.
$ fish -c '../jj; complete -C"ls cli/*/conf/tem"'
cli/*/*/config/templates.toml
Fix that. Test in the next commit.
There seems to be another bug in 3.7.1 where we fail to apply this completion
to the command line. This appears fixed. (FWIW we might want to revert
the quoting change in completion_apply_to_command_line(), maybe that one
accidentally fix this).
Fixes#10703
The HashMap is used to generate the __fish_describe_command integration
completions. Given the nature of the allocations and the numbers that we use, a
BTreeMap would theoretically perform better. Benchmarks show a 2-9%
improvement in completion times consistently in favor of BTreeMap.
Warnings were appearing under GCC 13.2
(void) alone is insufficient under modern compilers, workaround with logical
negation taken from GCC bug tracker.
Worth including because mold is rather popular in the rust world and because the
bug affects mold versions coincident with the development of the fish rust port.
The bug affects all currently released versions of mold from 2.30.0 (Mar 2024)
onwards under at least FreeBSD (though quite likely other platforms as well).
See https://github.com/rui314/mold/issues/1338 for reference.
We keep having to extend these with new terminals, and I can no longer
find a terminal that fails this.
Even emacs' ansi-term can now at least reliably ignore the sequence.
- the __fish_seen_any_argument function did not work
- the xxd_exclusive_args specification was not correct
- longer old-style options were missing
- technically short options are also old-style options in xxd
- some options were missing
Static linking against glibc has crashes depending on the name
resolution setup (I think when it needs to dlopen). It is a fundamental glibc
limitation that we cannot fix on our end.
It will crash when doing `echo ~<TAB>`.
This carves out a specific exception for "gnu", i.e. glibc, targets.
Other targets, including musl and other operating systems, continue to
allow static linking.
The previous control flow logic wasn't sound and would leave the shell in a hung
state when `break` would be encountered.
The behavior is now straightforward, the shell reads until <Enter> or <q> is
pressed, at which point it aborts.
This was based on a misunderstanding.
On musl, 64-bit time_t on 32-bit architectures was introduced in version 1.2.0,
by introducing new symbols. The old symbols still exist, to allow programs compiled against older versions
to keep running on 1.2.0+, preserving ABI-compatibility. (see musl commit 38143339646a4ccce8afe298c34467767c899f51)
Programs compiled against 1.2.0+ will get the new symbols, and will therefore think time_t is 64-bit.
Unfortunately, rust's libc crate uses its own definition of these types, and does not check for musl version.
Currently, it includes the pre-1.2.0 32-bit type.
That means:
- If you run on a 32-bit system like i686
- ... and compile against a C-library other than libc
- ... and pass it a time_t-containing struct like timespec or stat
... you need to arrange for that library to be built against musl <1.2.0.
Or, as https://github.com/ericonr/rust-time64 says:
> Therefore, for "old" 32-bit targets (riscv32 is supposed to default to time64),
> any Rust code that interacts with C code built on musl after 1.2.0,
> using types based on time_t (arguably, the main ones are struct timespec and struct stat) in their interface,
> will be completely miscompiled.
However, while fish runs on i686 and compiles against pcre2, we do not pass pcre2 a time_t.
Our only uses of time_t are confined to interactions with libc, in which case with musl we would simply use the legacy ABI.
I have compiled an i686 fish against musl to confirm and can find no issue.
This reverts commit 55196ee2a0.
This reverts commit 4992f88966.
This reverts commit 46c8ba2c9f.
This reverts commit 3a9b4149da.
This reverts commit 5f9e9cbe74.
This reverts commit 338579b78c.
This reverts commit d19e5508d7.
This reverts commit b64045dc18.
Closes#10634
Add kqueue-based uvar notifier for BSD
Tested under FreeBSD 13.3.
This also works under all versions of macOS, and has some
benefits over the current notifyd choice.
Mutex is used because of the non-mut `notification_fd_became_readable()` `&self`
reference, but contention is not expected.
This restores a hack to trigger a command line repaint when "$fish_color_*" or
"$fish_pager_color_*" changes. These allow the command line to react immediately
to changes in other sessions or web_config.
This was removed in ff62d172e5 but there does not
appear to be a handler which actually redraws these.
Revert of ff62d172e5
The generated assembly is more or less the same and the previously generated
version had been manually verified, but this PR removes the usage of
`MaybeUninit::assume_init()` and replaces it with direct pointer writes.
This should result in no observable change: it continues to pass the functional
tests and benchmarks identically. The safety of the new code has been verified
with Miri.
[0]: https://github.com/mqudsi/fish-yaml-unescape-benchmark
- -q silenced warnings in apk 2.x but not in in 3.x, so redirect stderr
to /dev/null to avoid seeing warnings while completing (-q is still
passed to `apk search` as it strips package versions and releases)
- Drop `-q` from `apk info`, as on apk 3.x it prevents apk info from
outputting anything at all
I've tested these changes on both Chimera Linux (which uses apk 3.x)
and Alpine Linux (which is still using 2.x).
This does not work as-is ("CSI a" is shift-up, not up).
I'm not sure if we want to implement these.
It's not a regression so there is no pressure.
This reverts commit 350598cb99.
byte_to_symbol was broken because it didn't iterate by byte, it
iterated by rust-char, which is a codepoint.
So it failed for everything outside of ascii and, because of a
mistaken bound, ascii chars from 0x21 to 0x2F ("!" to "/" - all the punctuation).
char_to_symbol will print printable codepoints as-is and
others escaped. This is okay - something like `decoded from: +` or
`decoded from: ö` is entirely understandable, there is no need to tell
you that "ö" is \xc3\xb6.
This reverts commit 423e5f6c03.
This except clause was too narrow, so it would fail here even on other
systems just because webbrowser.get() returned nothing usable
Now it will fail *later* with "could not locate runnable browser", but
at least it won't say anything about chromeos on non-chromeos systems.
Array starts at 0, goes up to 27, that's 28 entries... *BUT* we also
need the catch-all entry after, so it's 29.
To be honest there's got to be a better way to write this.
WezTerm supports CSI u but unfortunately, typing single quote on a German
keyboard makes WezTerm send what gets decoded as `shift-'`.
This is bad, so disable it until this is fixed. In future we should maybe
add a runtime option to allow the user to override this decision.
See #10663
The \e\e\[A style is bad but iTerm and putty (alt-left) use it.
The main motivation for this change is to improve fish_key_reader output.
Part of #10663
As of rust 1.78, the Unix stdlib implementation is affected by the same issue:
pub fn sleep(dur: Duration) {
let mut secs = dur.as_secs();
let mut nsecs = dur.subsec_nanos() as _;
// If we're awoken with a signal then the return value will be -1 and
// nanosleep will fill in `ts` with the remaining time.
unsafe {
while secs > 0 || nsecs > 0 {
let mut ts = libc::timespec {
tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t,
tv_nsec: nsecs,
};
secs -= ts.tv_sec as u64;
let ts_ptr = core::ptr::addr_of_mut!(ts);
if libc::nanosleep(ts_ptr, ts_ptr) == -1 {
assert_eq!(os::errno(), libc::EINTR);
secs += ts.tv_sec as u64;
nsecs = ts.tv_nsec;
} else {
nsecs = 0;
}
}
}
}
Note that there is a small behavior change here -- sleep() will continue
after signals; I'm not sure if we want that but it seems harmless?
Part of #10634
iTerm2 deviates from protocol, so back out c3c832761 (Stop using stack for
kitty progressive enhancement, 2024-08-03) in that case.
Note that we use several ways of detecting iTerm2 (ITERM_PROFILE,
TERM_PROGRAM=iTerm.app, ITERM_SESSION_ID).
LC_TERMINAL seems superior because it works over ssh.
This new one should hopefully go away eventually.
- Ubuntu focal is the lowest LTS release that we can support with only
distro packages (e.g. no rustup).
- Remove tsan from Cirrus (it's not working currently, and also not really
important).
- Remove Centos (it passes tests but I'm not sure it's worth adding; there
isn't even an official docker image for CentOS Stream).
Today fish pushes/pops kitty progressive enhancements everytime control is
transfered to/from fish. This constitutes a regression relative to 3.7.1:
$ fish
$ ssh somehost fish
(network disconnect, now we missed our chance to pop from the stack)
$ bash # or some ncurses application etc
(keyboard shortcuts like ctrl-p are broken)
When invoking bash, we pop one entry off the stack but there is another one.
There seems to be a simple solution: don't use the stack but always reset
the current set of flags. Do that since I did not find a strong use case
for using the stack[1] (Note that it was recommended by terminal developers
to use the stack, so I might be wrong).
Note that there is still a regression if the outer shell is bash.
[1]: https://github.com/kovidgoyal/kitty/issues/7603#issuecomment-2256949384Closes#10603
According to the discussion in #2315, we adopt TTY modes for external commands
mainly for "stty". If our child process crashes (or SSH disconnect), we
might get weird modes. Let's ignore the modes in the failure case.
Co-authored-by: Johannes Altmanninger <aclopte@gmail.com>
Part of #10603
Run
printf \Xf6 | wl-copy # ö in ISO-8859-1
LANG=de_DE LC_ALL=$LANG gnome-terminal -- build/fish
and press ctrl-v. The pasted data looks like this:
$ set data (wl-paste -n 2>/dev/null | string collect -N)
$ set -S data
$data: set in local scope, unexported, with 1 elements
$data[1]: |\Xf6|
we pass $data directly to "commandline -i", which is supposed to insert it
into the commandline verbatim. What's actually inserted is "�".
This is because of all of:
1. We never decode "\Xf6 -> ö" in this scenario. Decoding it -- like we do
for non-pasted keyboard input -- would fix the issue.
2. We've switched to using Rust's char, which, for better or worse, disallows
code points that are not valid in Unicode (see b77d1d0e2 (Stop crashing
on invalid Unicode input, 2024-02-27)). This means that we don't simply
store \Xf6 as '\u{00f6}'. Instead we use our PUA encoding trick, making it
\u{f6f6} internally.
3. Finally, b77d1d0e2 renders reserved codepoints (which includes PUA chars)
using the replacement character � (sic). This was deemed more
user-friendly than printing an invalid character (which is probably not
mapped to a glyph). Yet it causes problems here: since we think that
\u{f6f6} is garbage, we try to render the replacement character. Apparently
that one is not defined(?) in ISO-8859-1; we get "�".
Fix this regression by removing the replacement character feature.
In future we should maybe decode pasted input instead. We could do that
lazily in "commandline -i", or eagerly in "set data (wl-paste ...)".
Commit 29f2da8d1 (Toggle terminal protocols lazily, 2024-05-16) made it so
the wildcard expansion in "echo **" (in a large directory tree) can't be
canceled with ctrl-c. Fix this by disabling terminal protocols already at
expansion time (not waiting until execution).
Using
SHELL=$(command -v fish) mc
Midnight Commander will spawn a fish child with
"function fish_prompt;"
"echo \"$PWD\">&%d; fish_prompt_mc; kill -STOP %%self; end\n",
So fish_prompt will SIGSTOP itself using an uncatchable signal.
On ctrl-o, mc will send SIGCONT to give back control to the shell.
Another ctrl-o will be intercepted by mc to put the shell back to sleep.
Since mc wants to intercept at least ctrl-o -- also while fish is in control
-- we can't use the CSI u encoding until mc either understands that, or uses
a different way of passing control between mc and fish.
Let's disable it for now.
Note that mc still uses %self but we've added a feature flag
to disable that. So if you use "set fish_features all"
you'll want to add a " no-remove-percent-self". A patch
to make mc use $fish_pid has been submitted upstream at
https://lists.midnight-commander.org/pipermail/mc-devel/2024-July/011226.html.
Closes#10640
When applying a wildcard, it's important to keep track of the files that have
been visited, to avoid symlink loops. Previously fish used a FileId for the
purpose. However FileId also includes richer information like modification time;
thus if a file is modified during wildcard expansion then fish may believe that
the file is different and visit it twice.
The richer information like modification time is important for atomic file
writes but should be ignored for wildcard expansion; just use the (dev, inode)
pair instead.
This also somewhat reduces our reliance on struct stat, but we still need it for
fstatat which Rust does not expose.
Returns 0 (true) in case an autosuggestion is currently being displayed.
This was first requested in #5000 then again in #10580 after the existing
workaround for this missing functionality was broken as part of a change to the
overall behavior of `commandline` (for the better).
Since we have a mix of both 0-based and 1-based line numbers in the code base,
we can now distinguish between them by type alone. Also stop using 0 as a
placeholder value for "no line number available" except in explicit helper
functions such as `get_lineno_for_display()`.
Both are plenty fast enough, but this way the output of fish_trace isn't
completely taken over by the loops (seems fair since fish_trace probably gets
used rather heavily for completions).
I've often needed a way to get the last bit of performance out of unwieldy
completions that involve a lot of string processing (apt completions come to
mind, and I ran into it just now with parsing man pages for kldload
completions).
Since many times we are looking for just one exact string in the haystack, an
easy optimization here is to introduce a way for `string match` or `string
replace` to early exit after a specific number of matches (typically one) have
been found.
Depending on the size of the input, this can be a huge boon. For example,
parsing the description from FreeBSD kernel module man pages with
zcat /usr/share/man/man4/zfs.4.gz | string match -m1 '.Nd *'
runs 35% faster with -m1 than without, while processing all files under
/usr/share/man/man4/*.4.gz in a loop (so a mix of files ranging from very short
to moderately long) runs about 10% faster overall with -m1.
Preliminary work. Might be important to check version if options I added aren't widely available.
Changed some short options to old-style options since they can't be grouped and don't even need spaces before their arguments, such as `less -ooutputfile` which creates `outputfile`.
The -Dxcolor argument is commented out because its arguments follow complex rules I didn't look into in depth
Part of #1842
The implementation is obviously isn't 100% vi compatible, but works good enough
for major cases
This commit depends on previous commits where jump-{to, till}-matching-bracket
motions were introduces
Part of #1842
It's like jump-to-matching-bracket, but jumps right before the bracket
I will use it to mimic vi 'ab' and 'ib' text objects in the next commit
Given complicated semantics of jump-till-matching-bracket, an alternative name
could be 'jump-inside-matching-brackets'. But that would make names non-symmetrical.
I'm not sure what is worse.
Part of #1842
Split to:
- jump_and_remember_last_jump. What previously was called jump, now called
jump_and_remember_last_jump
- jump. Only jump, don't remember last jump. Now it's also possible to pass
vector of targets
The commit is pure refactoring, no functional changes are introduced.
The refactoring is needed for the next commits
When we changed our default from RelWithDebInfo to Debug, we inadvertently ended
up with all CI building and running in Debug mode. Change at least one of them
back to Release to make sure we don't have any optimizations that cause funky
stuff.
I'm changing the Ubuntu CI image because it's hopefully the fastest (since rust
is relatively dog-slow to compile in release mode).
__fish_apropos is a huge hack under macOS and it seems that it's either broken
or man pages are missing/not indexed under CI. In all cases, hard-code the
results of __fish_describe_command to test the integration machinery
specifically and get the test to pass under macOS CI.
Command completion descriptions were not being generated from `apropos`. Well,
they were being generated but that was not being correctly used by fish core.
Not sure when this was broken, but there's a possibility it was during the rust
port.
In addition to simply not working, it seems the old code tried to avoid
allocations but String::split_at_mut() allocates a new string (since one
allocation from the global allocator can't be split into two allocations to be
freed separately). Use `String::as_mut_utfstr()` before splitting the &wstr
instead of splitting the &str to actually do this alloc-free.
This was vexing me for a while because the extraneous output presented as a
valid (but unwanted) completion, i.e. with RUSTC_WRAPPER exported, `env RUSTC_W`
would offer `RUSTC_W=` and `RUSTC_WRAPPER=` as completions (when only the latter
should have been offered up).
This blames to a40b019, when @floam made some changes to various completions,
but this one seems to not quite fit the pattern and had a copy/paste error
resulting in using an undeclared variable.
Also disable filename completion on port.
__kld_whatis is an order of magnitude faster than calling `whatis` by means of
`__fish_whatis`. (It could be even faster if we could somehow tell `string
replace` to return after the first result, since the .Nd line comes at the start
of the file.)
It still takes some ~3.5 to print descriptions for all available klds (864 under
FreeBSD 13), so we still need to decide when it's prudent to do so and when it's
not.
The "principal" parser is the one and only today; in the future we hope to
have multiple parsers to execute fish script in parallel.
Having a globally accessible "principle" parser is suspicious; now we can
get rid of it.
The "principal" environment stack was the one that was associated with the
"principal" parser and would dispatch changes like to TZ, etc.
This was always very suspicious, as a global; now we can remove it.
Prior to this commit, there was a stack of ReaderDatas, each one has a
reference to a Parser (same Parser in each, for now). However, the current
ReaderData is globally accessible. Because it holds a Parser, effectively
anything can run fish script; this also prevents us from making the Parser
&mut.
Split these up. Create ReaderData, which holds the data portion of the
reader machinery, and then create Reader which holds a ReaderData and a
Parser. Now `reader_current_data()` can only return the data itself; it
cannot execute fish script.
This results in some other nice simplifications.
This is a start on untangling input. Prior to this, a ReaderData and an
Inputter would communicate with each other; this is natural in C++ but
difficult in Rust because the Reader would own an Inputter and therefore
the Inputter could not easily reference the Reader. This was previously
"resolved" via unsafe code.
Fix this by collapsing Inputter into Reader. Now they're the same object!
Migrate Inputter's logic into a trait, so we get some modularity, and then
directly implement the remaining input methods on ReaderData.
* completions/magento: Fixes module aggregation for module related commmands
Previousely when attempting completion for commands `module:enable`,
`mmodule:disable` and `module:uninstall` and error would be disaplyed,
stating that "magento" was not found.
Upon inspection of the issue in the related completion script it became
clear that:
1. The shell command `magento` does not exist as the CLI script of
Magentoresides under `bin/magento`.
2. The module aggregation would not work after referncing the
appropriate CLI command as an undeclared variable was being
introspected.
3. Using Magento's CLI command took too long to respond as it has to
bootstrap the whole Magento stack in order to deliver modules.
Thus the whole aggregation was rewritten to a form that actually works
and reduces the aggregation to reading the appropriate information
directly from the configuration file, provided that the file exists and
PHP is installed.
* completions/magento: Refactors module aggregation for module related commmands to not use PHP script
Executing random scripts from fish completion poses a threat to the
system. While this would indicate that the Magento installation has been
corrupted, it still is better to not run `app/etc/config.php` to get
hold of the modules.
Thus the module aggregation was rewritten to make use of `sed` instead,
which has the additional benefit of being faster than using PHP.
Add round options, but I think can also add floor, ceiling, etc. And
the default mode is trunc.
Closes#9117
Co-authored-by: Mahmoud Al-Qudsi <mqudsi@neosmart.net>
A few specific tests fail under i586 due to its inherent floating point
inaccuracy issues (rust-lang/rust#114479), so ignore these tests if certain
are met.
We have specific integration tests elsewhere in fish to check that even under
i586 we get mostly sane results, so this is OK. I tried to modify the assert
macros to check for a loose string match (up to one character difference) or an
f64 abs diff of less than epsilon, but it was a lot of code with little value
and increased the friction to contributing to the tests. Also, let's just
acknowledge the fact that all of i686, let alone i586 specifically, is a dead
end and not worth investing such time and effort into so long as it more or less
"works".
Closes#10474.
Due to the inherent floating point accuracy issues under i586 described
in #10474 and at https://github.com/rust-lang/rust/issues/114479, we need to add
a workaround to our littlecheck math tests to perform less stringent comparisons
when fish was built for x86 without SSE2 support.
This commit addresses the littlecheck issues that caused #10474 to be re-opened,
but I still have to reproduce the cargo test failures for
`negative_precision_width`, `test_float`, `test_float_g`, and `test_locale`.
The CMake `cargo test` integration was broken if Rust_CARGO_TARGET were used
with `CARGO_FLAGS` set to `-Zbuild-std` (e.g. to target i586 under i686 without
the i586 toolchain installed).
This would fail the FreeBSD tests whenever we merge or push multiple
times in quick succession.
Basically:
- Commits up to ABCDEF are pushed, which triggers a CI run
- Cirrus starts up, but takes a while - it knows to use commit ABCDEF
- More commits are pushed up to 123456
- Cirrus does a shallow clone, only has 123456
- Cirrus tries to check out ABCDEF, but doesn't know it - instant failure
Instead, let's use 100 commits, which should be enough
We require 3.19
This also makes skipped tests visible, which showed that the
print-help test was never run because the REQUIRES line was off.
In sh-mode, bash's `command -v` returns true if *all* commands exist.
The special input functions self-insert, self-insert-not-first, and
and or used to be handled by inputter_t::readch, but they aren't
anymore with `commandline -f`.
I am unsure if these *would* have worked, I can't come up with a use.
So, for now, do nothing instead of panicking.
This would crash if you ran `commandline -f backward-jump`.
The C++ version would read a char (but badly), this doesn't anymore.
So, at least instead of crashing, just do nothing.
One issue with fish_add_path at the moment is that it is sometimes a bit too intransparent.
You'll try to add a path, but it won't appear - was that because it wasn't a directory,
or because it doesn't exist, or because it was already included?
If it isn't usable after, did fish_add_path not add it because of something or did something *else* remove it?
So we give more explanations - "skipping this because it's a file", "not setting anything because no paths are left to add", ...
fish_add_path can be used either interactively, in the commandline,
or in config.fish. That's its greatest strength, it's a very
DWIM-style command.
One of the compromises that entails, however, is that it can't really
be very loud about what it does. If it skips a path, it can't write a
warning because it might be used in config.fish.
But it *can* if it's used interactively. So we try to detect that case
and enable verbose mode automatically.
That means if you do
```fish
fish_add_path /opt/mytool/bin/mytool
```
it may tell you "Skipping path because it is a file instead of a
directory:".
The check isn't perfect, it goes through status current-command and
isatty, but it should be good for most cases (and be false in config.fish).
The prompt regex for pexpect was:
```
return re.compile(
r"""(?:\r\n?|^) # beginning of line
(?:\x1b[\d[KB(m]*)* # optional colors
(?:\x1b[\?2004h) # Bracketed paste
(?:\x1b[>4;1m) # XTerm's modifyOtherKeys
(?:\x1b[>5u) # CSI u with kitty progressive enhancement
(?:\x1b=) # set application keypad mode, so the keypad keys send unique codes
(?:\[.\]\ )? # optional vi mode prompt
"""
+ (r"prompt\ %d>" % counter) # prompt with counter
+ r"""
(?:\x1b[\d\[KB(m]*)* # optional colors
""",
re.VERBOSE,
)
```
This has a terrible bug: an accidentally unescaped bracket here:
(?:\x1b[>4;1m) # XTerm's modifyOtherKeys
^
This bracket then extends throughout the entire regex, and is
accidentally terminated here:
(?:\x1b[\d\[KB(m]*)* # optional colors
^
Thus the whole regex is busted; in particular the prompt counters are
not being tested correctly.
A second issue is that these escape sequences are not emitted before the
first prompt, so correcting the regex will cause every test to fail.
Fix this by ignoring all of the escape sequences and merely look for
the "prompt %d>" portion.
THIS DELIBERATELY CAUSES TEST FAILURES.
The tests were already broken and falsely reported as passing.
These will be fixed in followup commits.
Good news is that the tests should become way more reliable after
this is fixed - hopefully no more introducing random sleep() calls.
This doesn't pull its weight. Block size is not a particularly big
problem,
and this both complicates the code a bit and would arbitrarily cause issues
if a fish script exceeded 65k lines.
This reverts commit edd6533a14.
This doesn't have any effect on the size of the struct (due to alignment
requirements and padding) but reduces the complexity by turning
Block::wants_pop_env into an emergent property dependent on the type rather than
something we have to manually manage.
We only increment it and check if it's non-zero, we never decrement or check the
actual count. As such, change it to a bool and bring the size of `Block` down
from 32 to 24 bytes.
We almost never access any of this and having it stored directly in the `Block`
struct increases its size (reducing how many we can fit in L1 and L2, and
increasing memory copy traffic).
Gets rid of BlockData::None so we can avoid allocating a Box at all when we have
no data (at the cost of yet-another-wrapper-type), which is the usual case.
This has a few advantages,
* We now statically assert that all fields used by a particular block type are
correctly initialized (i.e. you can't assign the function name but forget to
assign its arguments),
* Conversely, we can match directly on `BlockData` and be guaranteed that the
fields we want to access are initialized and present,
* We reduce the number of assertions, effectively "unwrapping" only once based
off the block type instead of each time we try to access a conditional field,
* We reduce the size of the `Block` struct by coalescing fields that cannot
co-exist, bringing it down from 104 bytes to 88 bytes.
It would be nice to make all of `Block` itself an enum, but it currently
requires `Copy` and we take advantage of that to copy it around everywhere.
Putting these fields directly in `Block` directly would mean a lot more memory
traffic just checking block types.
There's no need for two separate block types when one is merely a variant of the
other. This may have been required under C++ but thanks to sum types (rust's
enums) we don't need to do that any more.
The value completions were rendered almost entirely useless due to the forced
inclusion of file completions at all tokens, including in the head/command
position thanks to the use of `__fish_complete_subcommand` which doesn't
understand the semantics of `env` and expects something like `ssh`. But we don't
need it at all.
If the backgrounded/stopped job was using the tty, sending it SIGCONT first
might cause it to immediately wake and try to use the tty (which fish still has
control over), causing it to immediately stop again after receiving a SIGTTOU.
We are supposed to send SIGHUP first so that when the process resumes it sees
the queued SIGHUP and executes its registered handler!
Don't fork/exec an external process, especially one performing IO, if we don't
have to.
This, in turn, speeds up __fish_source_cached_completions which is rather slow
under WSL (and slower than it needs to be on other platforms).
Use "directories" explicitly instead of "components" to make it more
clear that the arguments need to be directories, not files.
Also a bit on intent and variable scope.
There's no guarantee that a condition variable is stateful. The docs for
`Condvar::notify_one()` actually say the opposite:
> If there is a blocked thread on this condition variable, then it will be woken
> up from its call to wait or wait_timeout. Calls to notify_one are not buffered
> in any way.
This test was relying on the main loop obtaining the lock and entering the
condition variable sleep before the thread was scheduled and got around to
notifying the condition variable. If this non-deterministic behavior was not
upheld, the test would time out since it would obtain the lock (either before or
after the variable were updated) then call `condvar.wait()` *after* the variable
had been updated and the condvar signalled, but without (atomically or even at
all) checking to see if the desired wake precondition was fulfilled. As the
child thread had already run and the wake notification was NOT buffered, there
was nothing to wake the running thread.
There really wasn't any way to salvage the test as originally written, since the
write to `ctx.val` was not in any way linked to the acquire/release of the mutex
so regardless of whether or not the main thread obtained the mutex and checked
the value precondition before calling `condvar.wait()`, the child thread's write
could have happened after the check but before the wait() call. As such, the
test has been rewritten to use `wait_while()` but then also updated to bail in
case of a timeout instead of hanging indefinitely (since neither the `ctest`
runner nor the `cargo test` harness was timing out; `cargo test` would only
report that the test had exceeded 60 seconds but as long as it was not executed
with `cargo test -- -Z --ensure-time` (which is only available under nightly),
the test would not halt.
If this test were *intentionally* written to test the scenario that was timing
out, it should be written deterministically in such a way that the main loop
did not run until after it was guaranteed that the variable had been updated
(i.e. by looping until val became 5 or waiting for an AtomicBool indicating the
update had completed to be set), but I'm not sure what the benefit in that would
be since the docs actually guarantee the opposite behavior (the notified state
is explicitly not cached/buffered).
If we have fish code written with the assumption that condvar notifications
prior to *any* call to `Condvar::wait()` *are* buffered, then that code should
of course be revisited in light of this.
Commit 8a7c3ce (Don't abandon line after writing control sequences, 2024-04-06)
was broken by 29f2da8 (Toggle terminal protocols lazily, 2024-05-16), fix that.
Fixes#10529
Reminder that reStructuredText is awkward and you can't make sphinx treat these
as inline code; they'll be formatted as italic text only.
Vim search expression:
\([`:]\)\@<!`[^`:]\+`\(`\)\@!
Followed by
ysi``
does the trick quite nicely.
* feat: improve konsole completion
* Improve konsole profile completion to be dynamic
Directly complete --profile as a long argument
* Dynamically complete konsole -p
This makes `path basename` a more useful replacement for the stock `basename`
command, which can be used with `-s .ext` to trim `.ext` from the base name.
Previously, this would have required the equivalent of
path change-extension "" (path basename $path)
but now it can be just
path basename -E $path
* Properly handle a lot more -Z completion formats as suggested by `rustc -Z
help`
* Don't run any `rustc` commands when sourcing `rustc.fish`; these invocations
are instead deferred until the user attempts to complete the specific switch.
* Support CSV -A/F/D/W values
This adds a crate containing a new implementation of printf, ported from musl.
This has some advantages:
- locale support is direct instead of being "applied after".
- No dependencies on libc printf. No unsafe code at all.
- No more WideWrite - just uses std::fmt::Write.
- Rounding is handled directly in all cases, instead of relying on Rust and/or
libc.
- No essential dependency on WString.
- Supports %n.
- Implementation is more likely to be correct since it's based on a widely used
printf, instead of a low-traffic Rust crate.
- Significantly faster.
Mostly replacing std::<type>::MAX with <type>::MAX.
Surprising here is replacing
.expect(format!(...))
with
.unwrap_or_else(|_| panic!(...))
It explains that this is because the "format!" would always be called.
This enabled the profile in fish_setlocale, which caused startup
profile to always be on, so
```fish
fish --profile file -c 'foo'
```
would show the entire startup as well
Hex float parsing may come about through wcstod, for example:
printf "%f" '0x8p2'
should output 32.0.
Currently we use a not-great fork of hexponent. Hexponent has been dormant for
years, and has some issues: doesn't round properly, allocates unnecessarily,
doesn't handle denormals, is more complicated than necessary.
Just rewrite hex float parsing, fixing those problems and getting us off of this
weird fork.
ThreadId is way slower than it should be for the sense that we use it in; it
doesn't cache the id and allocates an Arc internally.
We don't care about the thread id used in crate::threads correlating with any
other thread id the code uses anywhere (not that it does) because it's only used
for our own bookkeeping. Change to something much simpler instead.
Verified that std::sync::OnceLock<T> compiles to the same assembly at the
*access* site as the Option<T> we were using. The additional overhead upon init
is fine. No need for extra Box<T> indirection for IO_THREAD_POOL.
While obtaining an uncontested mutex from the same thread (without reentrance)
is basically ~free, the use of `MainThread<RefCell<T>>` instead of `Mutex<T>`
makes it clear that there is no actual synchronization taking place, hopefully
making the code easier to understand.
We don't set this variable ourselves, but some might set it in their config out
of habit coming from shells that don't automatically colorize ls output.
This variable overrides stdout tty detection for `ls --color=auto` (but does not
modify the behavior of `ls --color=never` or `ls --color=always` regardless of
its value) under at least the BSD version of `ls`. (Under the GNU version, it
influences colorization only if stdout *is* a tty.)
If we detect CLICOLOR_FORCE *and* we are not writing directly to the tty, we
skip colorization (by clearing-but-not-erasing `$__fish_ls_color_opt`, so that
we don't end up accidentally using its value from another scope).
This automatically assigns the 'completions' label and the 'fish next-3.x'
milestone to completions-only PRs.
A completions-only PR is defined as being one that touches
share/completions/*.fish but does not touch any files outside of share/
The C++ version of this code simply copied the entire uvar table.
Today we take a reference. It's not clear which one is better.
Removal of locale variables like LC_ALL triggers variable change handlers
which call EnvStackImpl::get. This deadlocks because we still hold the lock
to protect the reference to all uvars. Work around this.
Closes#10513
It is short and simple enough to write yourself if you need it and it encourages
bad behavior by a) always returning owned strings, b) always allocating them in
a vector. If/where possible, it is better to a) use &wstr, b) use an iterator.
In rust, it's an anti-pattern to unnecessarily abstract over allocating
operations. Some of the call sites even called split_string(..).into_iter().
This updates is_windows_subsystem_for_linux() to take a WSL version to test for
(any, v1, or v2) and returns the boolean result depending on the system. I've
benchmarked and when running on regular Linux, this is still just as fast as the
previous binary check; it's only when it's WSL that this takes about 20ns
longer to figure out which variant.
Note that older WSLv2 kernels had a `-microsoft-standard` suffix while newer
ones appear to have a `-microsoft-standard-WSL2` suffix, so we make sure to test
for the least common denominator. (It doesn't matter to us, but note that newer
WSLv2 kernels have four dots in the version string!)
WSL workarounds pertaining to the default Windows terminal or executable
behavior of win32 binaries under a WSL shell are extended to WSLv2 while those
specific to oddities in kernel behavior are confined to WSLv1 only. (It
technically wouldn't hurt to extend them to WSLv2 but there's no good reason to
do so, either.)
A common complaint has been the massive amount of directories Windows appends to
$PATH slowing down fish when it attempts to find a non-existent binary (which it
does a lot more often than someone not in the know might think). The typical
workaround suggested is to trim unneeded entries from $PATH, but this a) has
considerable friction, b) breaks resolution of Windows binaries (you can no
longer use `clip.exe`, `cmd.exe`, etc).
This patch introduces a two-PATH workaround. If the cmd we are executing does
not contain a period (i.e. has no extension) it by definition cannot be a
Windows executable. In this case, we skip searching for it in any of the
auto-mounted, auto-PATH-appended directories like `/mnt/c/Windows/` or
`/mnt/c/Program Files`, but we *do* include those directories if what we're
searching for could be a Windows executable. (For now, instead of hard-coding a
list of known Windows executable extensions like .bat, .cmd, .exe, etc, we just
depend on the presence of an extension at all).
e.g. this is what starting up fish prints with logging enabled (that has been
removed):
bypassing 100 dirs for lookup of kill
bypassing 100 dirs for lookup of zoxide
bypassing 100 dirs for lookup of zoxide
bypassing 100 dirs for lookup of fd
not bypassing dirs for lookup of open.exe
not bypassing dirs for lookup of git.exe
This has resulted in a massive speedup of common fish functions, especially
anywhere we internally use or perform the equivalent of `if command -q foo`.
Note that the `is_windows_subsystem_for_linux()` check will need to be patched to
extend this workaround to WSLv2, but I'll do that separately.
Under WSL:
* Benchmark `external_cmds` improves by 10%
* Benchmark `load_completions` improves by an incredible 77%
c0bcd817ba removed some key bindings, including the bindings of
ESC ESC [ C for Alt-Right. the commit claimed that
"Sequences like \e\eOC are Escape followed by an SS3 arrow key which we
can already decode separately." but for whatever reason this doesn't work:
Alt-Right is broken in iTerm2 by default.
Restore the default ESC ESC [ X bindings for iTerm2 compatibility.
On this binding we fail to disable CSI u
bind c-t '
begin
set -lx FZF_DEFAULT_OPTS --height 40% --bind=ctrl-z:ignore
eval fzf | while read -l r; echo read $r; end
end
'
because for "fzf", ParseExecutionContext::setup_group() returns early with the
parent process group (which should be fish's own) , hence "wants_terminal"
is false. This seems questionable, I don't think the eval should make a
difference here.
For now, don't touch it; use the more accurate way of detecting whether
a process may read keyboard input. In many of such cases "wants_terminal"
is false, like
echo (echo 1\n2\n3 | fzf)
Fixes#10504
Don't unconditionally execute the plumbing to get `rustc -C` completions (use it
only when trying to complete `rustc -C`), filter out deprecated options, and use
fewer calls to the `string` builtin to optimize further.
Need to do the same thing for the `-Z` completions next, those hang the shell
for a good 1.5+ seconds.
I've been needing this for some time to generate completions for functions that
we can dynamically generate completions for that take one or more
comma-separated values in any order.
Try not to let `cargo asm` build a large project and hang the terminal (and make
the fans go crazy) if we try to generate a list of functions/paths and the
project is in a dirty state. Also support dynamic completion of --target.
If rustup is installed, use the existing `__rustup_installed_targets` to get a
list of installed targets to compile for. If it's not, print a list of all
targets known to rustc.
It sucks that the completions file is currently architected in a way where we
have to manually specify the arguments for each subcommand. 🤷
This hot function dominates the flamegraphs for the completions thread, and any
optimizations are worthwhile.
A variety of different approaches were tested and benchmarked against real-world
fish-history file inputs and this is the one that won out across all rustc
target-cpu variations tried.
Benchmarks and code at https://github.com/mqudsi/fish-yaml-unescape-benchmark
Fixes the build on Ubuntu distributions with aggressive enabling of LTO
for all builds.
This build profile sets CFLAGS and CXXFLAGS in a way that prevents cargo
tests from linking. This manifests as errors like:
= note: make[5]: *** read jobs pipe: Bad file descriptor. Stop.
make[5]: *** Waiting for unfinished jobs....
lto-wrapper: fatal error: make returned 2 exit status
compilation terminated.
/usr/bin/ld: error: lto-wrapper failed
collect2: error: ld returned 1 exit status
We don't forward this variable for storage in any structs, so there's no reason
to go through an Arc instead of returning the `&'static EnvStack` directly.
NB: This particular change was safe, and passes all tests on its own.
We don't forward this variable for storage in any structs, so there's no reason
to go through an Arc instead of returning the `&'static EnvStack` directly.
These have clearer sync/unsync semantics and now ship with rust itself.
They don't paper over any possible cross-thread issues, and we can specifically
choose which we want for the purpose.
`Parser` is a single-threaded `!Send`, `!Sync` type and does not need to use
`Arc` for anything. We were using it because that's all we had for the parser's
`EnvStack`, but though that is *technically* protected internally by a mutex
(shared with global EnvStack), there's nothing to say that other parsers with a
narrower scope/lifetime on other threads will be necessarily using the same
backing mutex.
We can safely marshal the existing `Arc<EnvStack>` we get from
`environment::principal()` into an `Rc<EnvStack>` since the underlying reference
is always valid. To prove this point, we could have PRINCIPAL_STACK be a static
`EnvStack` and have `environment::principal()` use `Arc::from_raw()` to turn
that into an `Arc<EnvStack>`, but there's no need to factorize this process.
By inverting the order of storage, we can use an `OnceCell`/`unsync::Lazy`
inside the Send/Sync `MainThread<T>` and remove the need for a lock altogether.
It's reasonable since this is only checking to see that the history file
contains the expected format and if it's corrupted but we at least got what we
expect to be the correct key/value pairs, then that's all we can do.
Of course the real motivation is to speed up this very hot function in any way
possible!
On the completions and history thread, the parent function
HistoryFileContents::decode_item() is responsible for ~60% of the CPU time, and
extract_prefix_and_unescape_yaml() alone comprising 14% (of the total).
This change removes allocations in the event that the history item is either
fully or partially plain yaml with no escapes to begin with, and brings down the
execution time of this function to only 7% of the total execution time.
The bulk of the remaining time is spent in wcs2string(), which is called
unconditionally and is naturally alloc-heavy.
- Remove duplicated options - we had `-type` 9 times!
- Remove deprecated options and synonyms
- Make descriptions shorter, even removing some - when they're inscrutable they might as well not be there.
Really, 99.8% of these options are of interest to nobody except possibly (a subset of) gcc developers, so it pays to have *less* on your screen that you don't use anyway.
We ignore typed control characters 33a7172ee (Revert to not inserting control
characters from keyboard input, 2024-03-02).
We used to do the same for bracketed paste but that changed in 8bf8b10f6
(Extended & human-friendly keys, 2024-03-30) which made bracketed paste
behave like fish_clipboard_paste; it inserts the exact input (minus leading
whitespace etc). At that time it wasn't clear to me which behavior was the
right one (because of the inconsistency between terminal and bracketed paste).
As reported in
https://matrix.to/#/!YLTeaulxSDauOOxBoR:matrix.org/$PEEOAoyJY-644amIio0CWmq1TkpEDdSy2QnfJdK-dco
trailing tabs in pasted text can be confusing.
There seems to be not real need to insert raw control characters into the
command line, so let's strip them when pasting.
Now the only way to insert a raw control character into the command line is
to recall it from command history. Not sure what the behavior should be for
that case, we can revisit that later. If we get rid of raw control characters
entirely, then we can also delete the new "control pictures" rendering :)
This allows running `set` without triggering any event handlers.
That is useful, for example, if you want to set a variable in an event
handler for that variable - we could do it, for example, in the
fish_user_path or fish_key_bindings handlers.
This is something the `block` builtin was supposed to be for, but it
never really worked because it only allows suppressing the event for
the duration, they would fire later. See #9030.
Because it is possible to abuse this, we only have a long-option so
that people see what is up.
Commit a583fe723 ("commandline -f foo" to skip queue and execute immediately,
2024-04-08) fixed the execution order of some bindings but was partially
backed out in 5ba21cd29 (Send repaint requests through the input queue again,
2024-04-19) because repainting outside toplevel yields surprising results
(wrong $status etc).
Transient prompts wants to first repaint and then execute some more readline
commands, all within a single binding. This was broken by the second commit
because that one defers the repaint until after the binding has finished.
Work around this problem by deferring input events again while a readline
event was queued. This is closest to the historical behavior.
The implementation feels hacky; we might find odd situations.
For example,
commandline -f repaint end-of-line
set token (commandline -t)
sets the wrong token.
Probably not a very important case. We could throw an error or make it work
by letting "commandline -t" drain the input queue.
That seems too complicated, better change repaints to not use the input queue
(and fake $status etc). Let's try to do that in future.
Closes#10492
[w]open_dir does not pass O_CREAT, so the mode argument to open is never used.
also, O_CREAT | O_DIRECTORY could not be used (portably) to create a directory.
(on POSIX does not specify what should happen, on Linux it is EINVAL.)
This new feature in rsconf 0.2.0 resolves the compile-time warnings we get under
rustc 1.80+ about unrecognized cfg names by informing cargo of all valid cfg
names/values even when the cfg in question isn't enabled.
rustc 1.80 now complains about features not declared in Cargo.toml and cfg
keys/values not declared by build.rs to protect against typos or misuse (you
think you're using the right condition but you're not). See
rust-lang/cargo#10554 and rust-lang/rust#82450.
(We're not actually using TSAN under CI at this time, but I do want to re-enable
it at some point — especially if we get multithreaded execution going — using
the rust-native TSAN configuration.)
I'll be updating the `rsconf` crate and patching `build.rs` accordingly to also
handle the warnings about unknown cfg values, but tsan is a feature and not a
cfg and these can be dealt with in `Cargo.toml` directly.
We were passing a slice (and not a vec) to `CString::new()`, meaning it would
allocate a new Vec internally to hold the bytes.
Also document that the resulting CString will be silently truncated at the first
interior NUL.
The function was repeatedly calling `s.char_at(n)` which is O(1) only for UTF-32
strings (so not a problem at the moment). But it was also calling `hex_digit(n)`
twice for each `n` in the 3-digit case, causing unnecessary repeated parsing of
individual characters into their radix-16 numeric equivalents, which could be
avoided just by reusing the already calculated result.
CARGO_NET_GIT_FETCH_WITH_CLI uses the `git` executable instead of the rust
git2 crate/lib, which speeds things up and is known to resolve some issues
fetching the registry or individual crates.
This is to work around a specific issue with git-resident Cargo.toml
dependencies (e.g. terminfo) that keep randomly failing to download under macOS
CI.
We use this fallback value for FISH_BUILD_DIR when `cargo` is not
invoked from `cmake`, but we already have a cargo-defined build
directory and we shouldn't just decide to use $TARGET_MANIFEST_DIR/build
instead.
Tests pass locally!
We will continue to use the "normal" fish base directory detection when using
the CMake test harness which properly sets up a sandboxed $HOME for fish to use,
but when running source code tests with a bare `cargo test` we don't want to
write to the actual user's profile.
This also works around test failures when running `cargo test` under CI with a
locked-down $HOME directory (see #10474).
Prior to this change, signals.py attempted to generate Ctrl-C (SIGINT) by
sending \x03 to stdin. But with the change to use the CSI U sequence, Ctrl-C no
longer generates SIGINT.
Switch to sending SIGINT directly. Also switch up some of the sleep constants so
that a sleep command can't be confused with another one.
The test_history_formats test was reading from build/tests/ which is an artifact
of the cmake test runner. The source code tests should not depend on the cmake
test harness at all, so this is changed to read from the original test source in
the ./tests/ directory instead.
As documented in #10474, there are issues with 64-bit floating point rounding
under x86 targets without SSE2 extensions, where x87 floating point math causes
imprecise results.
Document the shortcoming and provide some version of the test that passes
regardless of architecture.
FISH_BUILD_DIR (nominally, ./build) is created by cmake. If you only check out
the project via git and then run `cargo build`, this directory won't exist and
many of the tests will fail.
%ld expects a 4-byte parameter on 32-bit architectures and an 8-byte parameter
on 64-bit architectures, but we supplied are trying to supply a 64-bit parameter
that would overflow 32-bit storage.
Use %lld instead which expects a `long long` parameter, which should be 8-bytes
under both architectures.
See #10474
I think given a local terminal running fish on a remote system, we can't
assume that an input sequence like \ea is sent all in one packet. (If we
could that would be perfect.)
Let's readd the default escape delay, to avoid a potential regression, but
make it only apply to raw escape bindings like "bind \e123". Treat sequences
like "bind escape,1,2,3" like regular sequences, so they can be bound on
all terminals.
This partially reverts commit b815319607.
Given "abbr foo something", the input sequence
foo<space><ctrl-z><space>
would re-expand the abbreviation on the second space which is surprising
because the cursor is not at or inside the command token. This looks to be
a regression from 00432df42 (Trigger abbreviations after inserting process
separators, 2024-04-13)
Happily, 69583f303 (Allow restricting abbreviations to specific commands
(#10452), 2024-04-24) made some changes that mean the bad commit seems no
longer necessary. Not sure why it works but I'll take it.
I think we can now call what we have in git better than the last
C++-based release, and you'll still need a C compiler to build it
because we still have some C code (libc.c).
As reported on gitter, commands like "rm (...)" sometimes want a previous
command inside the parentheses. Let's try that. If a user actually wants
to search for a command substitution they can move the cursor outside the
command substitution, or type the search string after pressing ctrl-r?
On a command with multiline quoted string like
begin
echo "line1
line2"
end
we actually indent line2 which seeems misleading because the indentation
changes the behavior when typed into a script.
This has become more prominent since commits
- a37629f86 (fish_clipboard_copy: indent multiline commands, 2024-04-13)
- 611a0572b (builtins type/functions: indent interactively-defined functions, 2024-04-12)
- 222673f33 (edit_command_buffer: send indented commandline to editor, 2024-04-12)
which add indentation to an exported commandline.
Never indent quoted strings, to make sure the rendering matches the semantics.
Note that we do need to indent the opening quote which is fine because
it's on the same line.
While at it, indent command substitutions recursively. That feature should
also be added to fish_indent's formatting mode (which is the default).
Fortunately the formatting mode already works fine with quoted strings;
it does not indent them. Not sure how that's done and whether indentation
can use the same logic.
Given "1(23)4", this function returns an inclusive range, from the opening
to the closing parenthesis. The subcommand is extracted by incrementing
the range start and interpreting the result as an exclusive range.
This is confusing, especially if we want to add multi-character quotes.
Change it to always return the full range (including parentheses) and provide
an easy way to access the command string.
While at it, switch to returning an enum.
This change is perhaps larger and more complex than necessary (sorry)
because it is mainly made with multi-character quotes in mind. Let's see
if that works out.
In addition to the native Emacs undo binding, we also support ctrl-z.
On Linux, ctrl-shift-z alias ctrl-Z is the redo binding according to
https://en.wikipedia.org/wiki/Table_of_keyboard_shortcuts Let's bind allow
that.
Unfortunately ctrl-shift and ctrl-alt modified shortcuts on Linux may be
intercepted by the windowing system or the terminal. Only alt-shift seems to be
available reliably (but the shift bit should mean "extend selection" in Emacs).
This removes IsOkAnd and the is_some_and method.
I cannot actually find is_none_or in the stdlib?
I've kept the trait name to avoid changing it now and then later, maybe this should
be moved elsewhere to avoid claiming it's an stdlib thing?
It appears we can't find a system that ships rustc >= 1.67 and < 1.70,
so keeping it at 1.67 gains nothing.
1.70 is used in Debian 13, so that will be able to build fish out of
the box (12 was on 1.63 which was already too low).
After abandoning a commandline (for example with ctrl-c) it's nice to be
able to restore it. There is little reason to discard the requisite undo
information, so keep it.
git_version_gen fails on Noble Numbat because modern Git refuses
to read repo-local config if owned by another user.
fishuser@a4263f53c93e:~/fish-build$ cd /fish-source/
fishuser@a4263f53c93e:/fish-source$ git describe --always --dirty
fatal: detected dubious ownership in repository at '/fish-source'
To add an exception for this directory, call:
Allow reading it (though that doesn't seem necessary here, it would be better
to ignore it).
vared.fish is installed at
/home/fishuser/fish-build/test/buildroot/usr/local/share/fish/functions/vared.fish
as oppposed to being sourced from share/functions/.
I'm not 100% sure why this happens but it doesn't seem wrong.
iTerm2 supports CSI u so the custom bindings are no longer needed. Sequences
like \e\eOC are Escape followed by an SS3 arrow key which we can already
decode separately.
In ImageMagick 7 or later, legacy commands have been replaced with
magick. Here a new functions, defines these completions and it is
called for `magick` and `magick convert`.
fixes#7172. Closes#10307.
Co-authored-by: Mahmoud Al-Qudsi <mqudsi@neosmart.net>
We were inconsistent about this for no apparent reason.
Also cleaning up in ~/.config/fish/completions is
irrelevant by now since we moved to ~/.local/share/fish 8 years ago.
Now that the parent commit moved it again, cleaning up that one seems
reasonable.
These take over two minutes under ASAN (like ~40 seconds without, so
they aren't quick to begin with), and don't really give any additional
insight.
So we skip them to save time
This allows making something like
```fish
abbr --add gc --position anywhere --command git back 'reset --hard
HEAD^'
```
to expand "gc" to "reset --hard HEAD^", but only if the command is
git (including "command git gc" or "and git gc").
Fixes#9411
I have no idea why this matches the string thrice when it is entered
once and suggestions are disabled.
I've seen this fail even on my local system, I expect it works because
of some terminal integration.
Running
echo foo | vim -
gets us in a weird situation because we put the job in fish's process groups.
It causes us to not set a PGID for this job, so it can't be resumed among
other things.
Stopping the job with ctrl-z and try to exit the shell causes a crash in the
"There are still jobs active" warning because the PID for the job is still 0.
Let's remove the assertion to restore previous behavior, and hopefully fix
this later.
Remove the last non scoped place where we disable protocols (just before
exec(1)); it's not necessary with the current approach because we always
disable inside eval.
There is an edge case where we don't:
fish -ic "exec bash"
leaving bash with CSI u enabled. Disable that also in -ic mode where we
don't have a reader.
In future we should use the same approach for restore_term_mode() but I'm
not sure which one is better.
We enable terminal protocols once at startup, and disable them before exit.
Additionally, we disable them while evaluating commands (see 8164855b7 (Disable
terminal protocols throughout evaluation, 2024-04-02))..
Thirdly, we re-enable protocols inside builtin read (where it's disabled
because we are evaluating something). All of these three are scoped and
statically guaranteed to not leak into each others scopes.
There is another place where we enable protocols non-scoped: when we
receive a notification that a job is stopped. If this is ever hit, things
will be imbalanced and we'll fail to restore the right terminal state,
or (more likely) crash due the assertion in terminal_protocols_enable().
This code path used to be necessary when we disabled protocols only while
actually executing an external command but we changed that in 8164855b7,
so it should no longer be. Remove it.
I haven't been able to find a test case, I'll try to do that later.
The main reason we changed the scope of protocols was focus reporting (#10408).
We have given up on that for now (outside tmux where I can't get it to work)
so we might want to reconsider and go back to the "optimized" approach of
enabling it for as long as possible. But this is simpler, easier to verify.
Try to keep the "backwards-incompatible" section reasonably short so
people can get a quick overview of what they need to handle.
So we split the "bind" part into two.
This tries to open the given file to use as stdin, and if it fails,
for any reason, it uses /dev/null instead.
This is useful in cases where we would otherwise do either of these:
```fish
test -r /path/to/file
and string match foo < /path/to/file
cat /path/to/file 2>/dev/null | string match foo
```
This both makes it nicer and shorter, *and* helps with TOCTTOU - what if the file is removed/changed after the check?
The reason for reading /dev/null instead of a closed fd is that a closed fd will often cause an error.
In case opening /dev/null fails, it still skips the command.
That's really a last resort for when the operating system
has turned out to be a platypus and not a unix.
Fixes#4865
(cherry picked from commit df8b9b7095)
wl-copy is a daemon process that serves its stdin to any wl-paste processes.
On Wayland, we launch it from fish_clipboard_copy. It then lives in the
same process group as fish (see `ps -o pid,pgid,comm`).
For some reason pressing ctrl-c inside the VSCode integrated terminal with
fish as the default shell kills the wl-copy process, thus clearing the
clipboard. On other terminals it works fine.
This is also reproducible by running "echo foo | wl-copy" ctrl-v ctrl-c ctrl-v
(the second ctrl-v does not paste because wl-copy was killed).
Work around this for now by running wl-copy asynchronously, and disowning it.
This seems to fix it though I really don't know why. Alternatively we could
"setsid" but that's technically not available on BSD.
For some reason this works in Bash. We should strace it to figure out why.
This introduces a feature flag, "test-require-arg", that removes builtin test's zero and one argument special modes.
That means:
- `test -n` returns false
- `test -z` returns true
- `test -x` with any other option errors out with "missing argument"
- `test foo` errors out as expecting an option
`test -n` returning true is a frequent source of confusion, and so we are breaking with posix in this regard.
As always the flag defaults to off and can be turned on. In future it will default to on and then eventually be made read-only.
There is a new FLOG category "deprecated-test", run `fish -d deprecated-test` and it will show any test call that would change in future.
This seems a bit better because it's what bind uses. To makes sure that
something like :kbd:`ctrl-x` looks good in HTML, remove the border from the
kbd style. Else both "ctrl" and "x" get small boxes which looks weird.
When writing scripts for other shells, it can be confusing and annoying
that our `man` function shadows other manual pages, for example `exec(1p)`
from [Linux man-pages]. I almost never want to see the fish variant for such
contended cases (which obviuosly don't include fish-specific commands like
`string`, only widely-known shell builtins).
For the contented cases like `exec`, the POSIX documentation is more
substantial and useful, since it describes a (sub)set of languages widely
used for scripting.
Because of this I think we should stop overriding the system's man pages.
Nowadays we offer `exec -h` as intuitive way to show the documentation for
the fish-specific command (note that `help` is not a good replacement because
it uses a web browser).
Looking through the contended commands, it seems like for most of them,
the fish version is not substantially different from the system version.
A notable exception is `read` but I don't think it's a very important one.
So I think we should can sacrifice a bit of the native fish-scripting
experience in exchange for playing nicer with other shells. I think the
latter is more important because scripting is not our focus, the way I see it.
So maybe put our manpath at the end.
In lieu of that, let's at least have `exec.rst` reference the system variant.
[Linux man-pages]: https://www.kernel.org/doc/man-pages/Closes#10376
This is similar to f7dac82ed (Escape separators (colon and equals) to improve
completion, 2019-08-23) except we only escape : and = if they are the result of
file completions. This way we avoid issues with custom completions like dd.
This also means that it won't work for things like __fish_complete_suffix
[*] but that can be fixed later, once we can serialize the DONT_ESCAPE flag.
By moving the escaping step earlier, this causes some unit test changes
which should not result in actual behavior change.
See also #6099
[*]: The new \: and \= does not leak from "complete -C" because that command
unescapes its output -- unless --escape is given.
alt-d used to do that until evil merge[*] 213e90704 (Merge remote-tracking branch
'upstream/master' into bind_mode, 2014-01-15) which changed the order of
the \ed bindings such that the smart dirh version would be shadowed by the
simpler ones.
[*] git blame alone failed to find it because it skips merge commits.
Another consequence of a583fe723 ("commandline -f foo" to skip queue
and execute immediately, 2024-04-08) is that "commandline -f repaint"
will paint the prompt with the current value of $status which might be
set from a shell command in a the currently executing binding, instead of
waiting for the top-level status. This is wrong, at least historically. It
surfaces in bindings like alt-w which always paint a status value of [1]
when on single-lines commandlines.
Another regression is that a redundant repaint in a signal handler outputs
an extra prompt.
Fix both by making repaint commands go over the input queue again. This way,
they are always run with a good commandline state. There is no need to
repaint immediately because I don't think anyone has a data dependency on it
(we currently don't expose the prompt string), it's only for rendering.
We sometimes leak ^[[I and ^[[O focus reporting events when run from VSCode's
"Run python file" button in the top right corner. To reproduce I installed
the ms-python extension set the VSCode default shell to fish and repeatedly
ran a script that does "time.sleep(1)". I believe VSCode synthesizes keys
and triggers a race condition.
We can probably fix this but I'm not sure when I'll get to it (given how
relatively unimportant this feature is).
So let's go back to the old behavior of only enabling focus reporting in tmux.
I believe that tmux is affected by the same VSCode issue (also on 3.7.1 I
think) but I haven't been able to get tmux to emit focus reporting sequences
yet. Still, keep it to not regress cursor shape (#4788). So far this is
the only motivation for focus reporting and I believe it is only relevant
for terminals that can split windows (though there are a bunch that do).
Closes#10448
There seem to be versions of ssh (possibly not from OpenSSH) that don't
print the version number in -V, so make sure not to pass an empty string as
numeric arg to test.
Fixes#10445
While it does need to store the string, we also need to use the string after
storing it, so we aren't getting any advantage from passing by value. Just pass
by reference to simplify the call sites.
This is another problem that has been bothering me for years: as mentioned
in 1dd901e52 (Maintain cursor in history prefix search, 2024-04-12), up-arrow
search highlights search matches but the contrast is really bad, especially in
command position, because the search matches --background=brblack is combined
with whatever foreground syntax highlighting the command has. The history
pager had a similar problem (for the selected history item) but circumented
it by disabling syntax highlighting altogether for the selected item.
fish_color_search_match's foreground component is ignored.
Let's use it instead of syntax highlighting.
This fixes the contrast on some default colorschemes but the bryellow
foreground looks weirdly like an error/warning on some terminals. Change it
to white. This needs a hack because we don't have a canonical way to tell
if a uvar has been set by the user. Fortunately the foreground component
hasn't been used at all so far, so we're not so much changing it as much as
initializing it.
On Konsole with
function my-bindings
bind --preset --erase escape
bind escape,i 'echo escape i'
end
set fish_key_bindings my-bindings
the "escape,i" binding doesn't trigger. This is because of our special
handling of the escape key prefix. Other multi-key bindings like "bind j,k"
wait indefinitely for the second character. But not "escape,i"; that one
has historically had a low timeout (fish_escape_delay_ms). The motivation
is probably that we have a "escape" binding as well that shouldn't wait
indefinitely.
We can distinguish between the case of raw escape sequence binding like "\e123"
and a binding that talks about the actual escape key like "escape,i". For the
latter we don't need the special treatment of having a low timeout, so make it
fall back to "fish_sequence_key_delay_ms" which waits indefinitely by default.
Indented multiline commandlines look ugly in an external editor. Also,
fish doesn't properly handle the case when the editor runs fish_indent.
Fix is by indenting when exporting the commandline and un-indenting when
importing the commandline again.
Unindent only if the file is properly indented (meaning at least by the
amount fish would use). Another complication is that we need to offset
cursor positions by the indentation.
This approach exposes "fish_indent --only-indent" and "--only-unindent"
though I don't imagine they are useful for others so I'm not sure if this
is the right place and whether we should even document it.
One alternative is to add "commandline --indented" to handle indentation
transparently.
So "commandline --indented" would print a indented lines,
and "commandline --indented 'if true' ' echo'" would remove the unecessary
indentation before replacing the commandline.
That would probably simplify the logic for the cursor position offset.
When we read bytes like \xfc that don't produce a Unicode code point,
we encode them in a Unicode private use area.
This encoding should be transparent to the user.
We accidentally add it to uvar files as \uf6fc in this case. When reading
it back, read_unquoted_escape() will fail at the "fish_reserved_codepoint(c)"
check. This check is to avoid external input being misinterpreted
as one of our in-band signalling characters like ANY_CHAR (for *).
For encoded raw bytes, this check probably doesn't really matter in terms of
security because the only thing we do with these bytes is convert them back
to raw. So we could allow unescaping them at this point, thus supporting
old uvar files.
However that seems like the wrong direction. PUA encoding should never leak.
So let's instead make sure to serialize it as \xfc instead of \f6fc going
forward.
Fixes#10313
Popular operating systems support shift-delete to delete the selected item
in an autocompletion widgets. We already support this in the history pager.
Let's do the same for up-arrow history search.
Related discussion: https://github.com/fish-shell/fish-shell/pull/9515
On
a;
we don't expand the abbreviation because the cursor is right of semicolon,
not on the command token. Fix this by making sure that we call expand-abbr
with the cursor on the semicolon which is the end of the command token.
(Now that our bind command execution order is less surprising, this is doable.)
This means that we need to fix the cursor after successfully expanding
an abbreviation. Do this by setting the position explicitly even when no
--set-position is in effect.
An earlier version of this patch used
bind space self-insert backward-char expand-abbr or forward-char
The problem with that (as a failing test shows) was that given "abbr m
myabbr", after typing "m space ctrl-z", the cursor would be after the "m",
not after the space. The second space removes the space, not changing the
cursor position, which is weird. I initially tried to fix this by adding
a hack to the undo group logic, to always restore the cursor position from
when begin-undo-group was used.
bind space self-insert begin-undo-group backward-char expand-abbr end-undo-group or forward-char
However this made test_torn_escapes.py fail for mysterious reasons.
I believe this is because that test registers and triggers a SIGUSR1 handler;
since the signal handler will rearrange char events, that probably messes
with the undo group guards.
I resorted to adding a tailor-made readline cmd. We could probably remove
it and give the new behavior to expand-abbr, not sure.
Fixes#9730
File names that have lots of spaces look quite ugly when inserted as
completions because every space will have a backslash.
Add an initial heuristic to decide when to use quotes instead of
backslash escapes.
Quote when
1. it's not an autosuggestion
2. we replace the token or insert a fresh one
3. we will add a space at the end
In future we could relax some of these requirements.
Requirement 2 means we don't quote when appending to an existing token.
Need to find a natural behavior here.
Re 3, if the completion adds no space, users will probably want to add more
characters, which looks a bit weird if the token has a trailing quote.
We could relax this requirement for directory completions, so «ls so»
completes to «ls 'some dir with spaces'/».
Closes#5433
On Konsole, given
bind escape,i 'echo escape i'
bind alt-i 'echo alt-i'
pressing alt-i triggers the wrong binding. This is because we treat "escape
followed by i" as "alt-i". This is to support raw sequences like "\ei"
which are probably meant as "alt-i" -- we match such inputs to both mappings.
This double matching is not necessary for new-style bindings which
unambiguously describe the key presses, so let's activate this sequence
matching only for bindings specified as raw sequences.
Conversely, we currently fail to match an XTerm raw binding for ctrl-enter:
echo 'XTerm.vt100.formatOtherKeys: 0' | xrdb
xterm -e fish
bind \e\[27\;5\;13~ execute
because we decode this to a single char; we match the leading CSI but not
the entire sequence. So this is a raw binding where we accidentally
match full, modified keys. Fix that too (two birds with one stone).
I think commit 8386088b3 (Update commandline state changes eagerly as well,
2024-04-11) broke the alt-s binding.
This is because we update the commandline state snapshot (which is consumed
by builtin commandline and others) only at key points. This seems like a
dubious optimization. With the new streamlined bind execution semantics,
this doesn't really work anymore; any shell command can run any number of
commands like "commandline -i foo" which should synchronize.
Do the simple thing of calculating the snapshot whenever needed.
The search term highlighting looks looks really bad on the default theme
because the command is highlighted as dark blue and the search term adds
a dark background. If this new feature motivates us to finally fix this,
that would be great.
Closes#10430
Some of these handled multiline prompts but not multiline command lines. We
first need to move the cursor to the end of the commandline, then we can
print a message. Finally, we need to move the cursor back to where it was.
The new reader_execute_readline_cmd() runs apply_commandline_state_changes()
to make sure that given
bind x "commandline --insert foo; commandline -f backward-char"
the backward-char command knows about the insertion of "foo". This
causes problems when running "sleep 1&" and typing some characters -
the commandline will be cleared when the job finishes. This is because
apply_commandline_state_changes() works with stale information in this case.
Let's call it as soon as we know it's needed. This is less messy and fits
better with the new bind function semantics ("execute things in the order
they are written").
This makes them more convenient to use interactively, similar to the existing
\c and \a versions. The resulting bind output keeps using the canonical
ctrl/alt version.
Not sure about s- because that's somewhat ambiguous, it could be "super".
See the parent commit for some context. Turns out that 8bf8b10f6 (Extended &
human-friendly keys, 2024-03-30) broke this for terminals that speak CSI u.
This is pretty complex, probably not worth it.
When a terminal sends \x1ba, that could be either escape,a or alt-a.
Historically we've handled this with an escape delay that defaults to 30
milliseconds. If we read nothing for that time, it's escape. Otherwise it's
an alt modifier (or an escape sequence).
As a side effect of 8bf8b10f6 (Extended & human-friendly keys, 2024-03-30) we
added a new way of disambiguating escape: whenever we read the escape byte,
we immediately try another (nonblocking) read. If it succeeds, we treat it
as modifier, else it's escape. Before that commit, we didn't have a concept
of modifiers.
The new way works fine for disambiguating escape,a from alt-a (as pressed
by the user) because only for alt-a the data is sent in the same packet.
So we no longer need the escape delay to disambiguate the alt from the
escape key. Let's simplify things by not using it by default.
The escape delay as set by fish_escape_delay_ms also serves another purpose;
it allows to disambiguate "escape,a" from "escape (pause) a". For that use
case we want to keep it.
As mentioned in 8a7c3ceec (Don't abandon line after writing control sequences,
2024-04-06) we need to freshed stdout timestamps after writing to stdout
but before we might redraw, in particular when writing control sequences.
Commit a583fe723 ("commandline -f foo" to skip queue and execute immediately,
2024-04-08) made "commandline -f repaint" redraw immediately, while still
executing the bound shell command; at that time we have written "disabling"
sequences but not refreshed timestamps yet, so do that.
This is probably not needed for commands outside the repaint family.
Needless to say that this is messy, maybe we can simplify things in future.
Ref https://github.com/fish-shell/fish-shell/issues/10409#issuecomment-2044863817
A failing test might emit an OSC 133 prompt marking sequence, confusing
the parent terminal to think the test output contains a shell prompt. Let's
remove these.
If a key's codepoint is in the PUA1 range, it could
be either from our own named keys (like key::Space)
or from a CSI u key that we haven't assigned a name yet
https://sw.kovidgoyal.net/kitty/keyboard-protocol/#functional-key-definitions
(The latter can still be bound using the \u1234 or the equivalent \e[4660u
raw CSI u sequence.)
It doesn't make sense to insert a PUA character into the commandline when
the user presses PrintScreen; ignore them silently.
This partially reverts b77d1d0e2 (Stop crashing on invalid Unicode input,
2024-02-27). That commit did:
1. convert input byte sequences that map to a PUA codepoint into several
characters, using our on-char-per-byte PUA encoding.
2. do the same for inputs that are codepoints outside the valid Unicode range.
3. render them as replacement character (one per input byte)
In future, we should probably remove these features altogether, and simply
ignore invalid Unicode code points.
Commit c3cd68dda (Process shell commands from bindings like regular char
events, 2024-03-02) mentions a "weird ordering difference".
The issue is that "commandline -f foo" goes through the input
queue while other commands are executed directly.
For example
bind ctrl-g "commandline -f end-of-line; commandline -i x"
is executed in the wrong order. Fix that.
This doesn't yet work for "commandline -f exit" but that can be fixed easily.
It's hard to imagine anyone would rely on the existing behavior. "commandline
-f" in bindings is mostly used for repainting the commandline.
If a binding was input starting with "\e", it's usually a raw control sequence.
Today we display the canonical version like:
bind --preset alt-\[,1,\;,5,C foo
even if the input is
bind --preset \e\[1\;5C foo
Make it look like the input again. This looks more familiar and less
surprising (especially since we canonicalize CSI to "alt-[").
Except that we use the \x01 representation instead of \ca because the
"control" part can be confusing. We're inside an escape sequence so it seems
highly unlikely that an ASCII control character actually comes from the user
holding the control key.
The downside is that this hides the canonical version; it might be surprising
that a raw-escape-sequence binding can be erased using the new syntax and
vice versa.
We don't yet support all keys from
https://sw.kovidgoyal.net/kitty/keyboard-protocol/#functional-key-definitions
Instead of displaying a private-use character, show the character code;
this can be used to map the key even if we don't know a name for it.
bind \uE011 'echo print screen'
bind ctrl-\uE011 'echo do control + print screen'
Note that it's also possible to mape the raw CSI u sequence, like
bind \e\[57361u 'echo print screen'
but we should not encourage that syntax because it does not allow adding
the modifiers like ctrl.
Of course leaking the PUA character code is not ideal.
As implied by the changelog.
Unfortunately it's not obvious how to access the RefCell value in spite
of a potential (albeit unlikely) present mutable borrow. We need to use a
different type to make it work in such cases, hopefully doing that in future.
In future we could even use panic=abort and use this style of cleanup for
panics (instead of RAII).
For numpad 1 with nulock, Alacritty sends
escape,[,5,7,4,0,0,u
which is codepoint \x31, key "1". We have a terminfo mapping for "sright"
which translates to
escape,[,1,;,2,C
The first two characters, escape and [ match. Then we accidentally match the
"1" from the mapping against the entire sequence, because that sequence is
canonicalized to codepoint "1" . The most blatant problem is that we discard
the rest of the sequence. Fix that.
This allows us to re-enable raw CSI u mappings like "bind \e[1u ..."
which is what kitty uses for shell integration.
This allows terminals like foot and kitty to
* scroll to the previous/next prompt with ctrl-shift-{z,x}
* pipe the last command's output to a pager with ctrl-shift-g
Kitty has existing fish shell integration
shell-integration/fish/vendor_conf.d/kitty-shell-integration.fish which we
can simplify now. They keep a state variable to decide which of prompt start,
command start or command end to output. I think with our implementation
this is no longer necessary, at least I couldn't reproduce any difference.
We also don't need to hook into fish_cancel or fish_posterror like they do;
only in the one place where we actually draw the prompt.
As mentioned in the above shell integration script, kitty disables reflow
when it sees an OSC 133 marker, so we need to do it ourselves,
otherwise the prompt will go blank after a terminal resize.
Closes#10352
If I type
$ echo $SOME_VARIABLE_WIHT_A_TYPO
$ set -S SOME_VARIABLE_WIHT
and press tab, I'm always extremely surprised that this completes to
$ set -S fish_history
which is because $history[1] contains the typo'd variable name. I don't
think anyone intends to filter by that last 3-4 history items, so let's
remove this pitfall.
Note that I usually hit this scenario with undefined variables, not necessarily
typos.. "set -S" is usually redundant but it's still quite nice in this case,
to rule out any weird empty strings/empty lists.
Commit 8164855b7 (Disable terminal protocols throughout evaluation, 2024-04-02)
changed where we output control sequences (to enable bracketed paste and CSI).
Likewise, f285e85b0 (Enable focus reporting only just before reading from
stdin, 2024-04-06) added control sequence output just before we read().
This output causes problems because it invalidates our stdout/stderr
timestamps, which causes us to think that a rogue background process wrote
to the terminal; we react by abandoning the current line and redrawing the
prompt below. Our fix was to refresh the TTY timestamps after we run a bind
command that might add stdout (#3481).
Since commit c3cd68dda (Process shell commands from bindings like regular
char events, 2024-03-02), this timestamp refresh logic is in the wrong place;
shell commands are run later now; we could move it but wait -
... we also need to make sure to refresh timestamps after outputting control
sequences. Since bracketed paste is enabled after CSI u, we can skip the
latter. Additionally, since we currently output control sequences before
every single top-level interactive command, we no longer need to separately
refresh timestamps in between commands.
Fixes#10409
Some terminals send the focus-in sequences ("^[I") whenever focus reporting is
enabled. We enable focus reporting whenever we are finished running a command.
If we run two commands without reading in between, the focus sequences
will show up on the terminal.
Fix this by enabling focus-reporting as late as possible.
This fixes the problem with `^[I` showing up when running "cat" in
gnome-terminal https://github.com/fish-shell/fish-shell/issues/10411.
This begs the question if we should do the same for CSI u and bracketed paste.
It's difficult to answer that; let's hope we find motivating test cases.
If we enable CSI u too late, we might misinterpret key presses, so for now
we still enable those as early as possible.
Also, since we now read immediately after enabling focus events, we can get
rid of the hack where we defer enabling them until after the first prompt.
When I start a fresh terminal, the ^[I no longer shows up.
It's not clear whether builtin read should be able to do everything
that the normal prompt does but I guess we haven't found a problem yet.
Given that read could be used to read a single character at a type,
it's a bit odd to toggle terminal protocols all the time.
But that's not the typical case (at least not for when stdin is a TTY),
and it seems fine.
Teste with
bind ctrl-4 'echo yay'
Regressed in 8164855b7 (Disable terminal protocols throughout evaluation,
2024-04-02).
Apparently VTE terminals send the "focus in" event whenever we re-enable
focus reporting. That's probably a sensible thing to do.
Anyway, our problem is simply that we accidentally end history search on these
focus events which are implemented as anonymous (unmappable) readline cmds.
Perhaps there should be a separate cmd category.
Focus events show up as key::Invalid which is a weird private use code point;
probably we can get rid of this key..
Fixes#10411
Similar to 20bbdb68f (Set terminal title unconditionally, 2024-03-30).
While at it, get rid of a few unnecessary guards (we are never called from
a command substitution, so the check only adds confusion).
I'm not sure if it's worth supporting a terminal that mishandles unknown OSC
and CSI sequences. Better to fix the terminal. Note that there are Emacs
terminals available that don't have this problems; for example "vterm".
See the changelog additions for user-visible changes.
Since we enable/disable terminal protocols whenever we pass terminal ownership,
tests can no longer run in parallel on the same terminal.
For the same reason, readline shortcuts in the gdb REPL will not work anymore.
As a remedy, use gdbserver, or lobby for CSI u support in libreadline.
Add sleep to some tests, otherwise they fall (both in CI and locally).
There are two weird failures on FreeBSD remaining, disable them for now
https://github.com/fish-shell/fish-shell/pull/10359/checks?check_run_id=23330096362
Design and implementation borrows heavily from Kakoune.
In future, we should try to implement more of the kitty progressive
enhancements.
Closes#10359
To do so add an ad-hoc "commandline --search-field" to operate on pager
search field.
This is primarily motivated because a following commit reuses the
fish_clipboard_paste logic for bracketed paste. This avoids a regression.
Terminal titles are set with an OSC 0 sequence. I don't think we want to
support terminals that react badly to unknown OSC (or CSI) sequences.
So let's remove our feature detection.
This will fix future false negatives along the lines of
https://github.com/fish-shell/fish-shell/pull/10037
This binding is akin to ForwardSingleChar but it is "passive" in that is not
intended to affect the meta state of the shell: autocompletions are not accepted
if the cursor is at the end of input and it does not have any effect in the
completions pager.
Currently, we expand command-abbrs (those with `--position command`) after `if`, but not after `command` or `builtin` or `time`:
```fish
abbr --add gc "git checkout"
```
will expand as `if gc` but not as `command gc`.
This was explicitly tested, but I have no idea why it shouldn't be?
The incorrect order of operations was being used since && binds tighter than ||
in rust (as with most sane languages).
Under Linux, EAGAIN == EWOULDBLOCK so this would always succeed in the case of a
non-blocking fd without making the call to make_fd_nonblocking().
Comparing to the 3.7.0 C++ code, it looks like this was an oversight introduced
in the migration to rust.
In particular, this allows restoring the terminal on crashes, which is
feasible now that we have the panic handler. Since std::process::exit() skips
destructors, we need to reshuffle some code. The "exit_without_destructors"
semantics (which std::process::exit() als has) was mostly necessary for C++
since Rust leaks global variables by default.
When fish crashes due to a panic, the terminal window is closed. Some
terminals keep the window around when the crash is due to a fatal signal,
but today we don't exit via fatal signal on panic.
There is the option to set «panic = "abort"» in Cargo.toml, which
would give us coredumps but also worse stacktraces on stderr.
More importantly it means that we don't unwind, so destructors are skipped
I don't think we want that because we should use destructors to
restore the terminal state.
On crash in interactive fish, read one more line before exiting, so the
stack trace is always visible.
In future, we should move this "read one line before exiting" logic to where
we call "panic!", so I can attach a debugger and see the stacktrace.
Looks like "add_custom_command(OUTPUT ...)" assumes the dependencies are
correct which is not always true. We can use "add_custom_target" to always
re-run Cargo.
Unfortunately on Debian "open" is a symlink to "openvt", and there's
no way from outside to tell.
This prevents fish from failing because no browser could be found.
Today fish_cursor_selection_mode controls whether selection mode includes
the cursor. Since it's by default only used for Vi mode, perhaps use it to
also decide whether it should be allowed to select one-past the last character.
Not allowing to select to select one-past the last character is much nicer
in Vi mode. Unfortunately Vi mode sometimes needs to temporarily select
past end (using forward-single-char and such), so reset fish_cursor_selection_mode
for the duration of the binding.
Also fix other things like cursor placement after yank/yank-pop.
Closes#10286Closes#3299
We have
bind --preset -M $mode --sets-mode paste \e\[200~ __fish_start_bracketed_paste
Commit c3cd68dda (Process shell commands from bindings like regular char
events, 2024-03-02) made it so __fish_start_bracketed_paste is no longer
executed before the bind mode is updated.
This is a long-awaited fix but it broke __fish_start_bracketed_paste's
assumption that $fish_bind_mode is the mode before we entered paste mode.
This means we never exit paste mode.
Work around that. I forgot about this issue because I already replaced our
bracketed paste handling on my fork.
This was a misunderstanding, the OBS tumbleweed builds build from a tarball that's pushed manually.
We no longer use corrosion so this dependency is unused.
This reverts commit bdde2b2b35.
Fixes#10391
The current version of serial_test we use (0.4.0)
depends on parking_lot 0.10.2 which in turn
depends on lock_api 0.3.4.
This version of lock_api is vulnerable to [RUSTSEC-2020-0070](https://rustsec.org/advisories/RUSTSEC-2020-0070)
This was patched in lock_api 0.4.2 but we need to update serial_test
to get the update.
Today,
bind foo "commandline -f expand-abbr; commandline -i \n"
does not work because this
1. enqueues an expand-abbr readline event
2. "commandline -i" inserts \n
3. processes the expand-abbr readline event
Since there is no abbreviation on the new line, this doesn't do anything.
PR https://github.com/fish-shell/fish-shell/pull/9398 would fix this
particular instance however it does not fix the issue that "commandline -i"
is run before the expand-abbr is processed by the reader. This is harmless
here but there would be a problem if "commandline" tried to read commandline
state that was created by a preceding command.
It's not super clear to me whether the above binding should work as one
would naively expect. That would imply that "commandline" would need to
drain all input events (at least all synthetic ones) from the input queue,
to ensure it sees the current state.
Fortunately the parent commit makes it so if we separate them
bind foo "commandline -f expand-abbr" "commandline -i \n"
both will be separate events and the commandline state will be synced after
each of them. This fixes abbreviation expansion here.
Also, we can now mix readline cmds and shell commands, which makes it shorter.
A long standing issue is that bindings cannot mix special input functions
and shell commands. For example,
bind x end-of-line "commandline -i x"
silently does nothing. Instead we have to do lift everything to shell commands
bind x "commandline -f end-of-line; commandline -i x"
for no good reason.
Additionally, there is a weird ordering difference between special input
functions and shell commands. Special input functions are pushed into the
the queue whereas shell commands are executed immediately.
This weird ordering means that the above "bind x" still doesn't work as
expected, because "commandline -i" is processed before "end-of-line".
Finally, this is all implemented via weird hack to allow recursive use of
a mutable reference to the reader state.
Fix all of this by processing shell commands the same as both special input
functions and regular chars. Hopefully this doesn't break anything.
Fixes#8186Fixes#10360Closes#9398
Most chat programs I found use Shift+Return to insert a newline while plain
Return sends the message. One user reported having only tried Shift+Return
and not knowing about Alt+Return.
No release notes yet because this only works on a very small number of
terminals. Once we enable CSI u, this should work on most modern terminals.
Multiline search strings are weirdly broken (inserting control characters
in the command line) and probably not very useful anyway.
On the other hand I often want to compose a multi-line command
from single-line commands I ran previously.
Let's support this case by limiting the initial search string to the current
line; and replace only that line.
Alternatively this could operate on jobs (that is, replace a surrounding
"foo | bar") instead of using line boundaries.
This is resistant to misuse by including O_DIRECTORY in the open flags and it is
a separate function from {w,}open_cloexec() in preparation for making that one
return a `File` instead of an `OwnedFd`.
`intersects()` is "any of" while `contains()` is "all of" and while it makes no
difference when testing a single bit, I believe `contains()` is less brittle
for future maintenance and updates as its meaning is clearer.
</pedantic>
More work in prep for having wopen_cloexec() return `File` directly.
This eliminates checking for an invalid fd and makes both ownership and
mutability clear (some more operations that involve changes to the underlying
state of the fd now require `&mut File` instead of just a `RawFd`).
Code that clearly does not use non-blocking IO is ported to use
`Write::write_all()` directly instead of our rusty port of the `write_loop()`
function (which handles EAGAIN/EWOULDBLOCK in addition to EINTR, while
`write_all()` only handles the latter).
Add git as a build requirement. Package name guessed then confirmed by searching
on rpm.pbone.net against openSUSE Tumbleweed.
Log excerpt:
[ 14s] CMake Error at /usr/share/cmake/Modules/ExternalProject.cmake:2910 (message):
[ 14s] error: could not find git for clone of corrosion-populate
The %{_docdir} macro is defined, but due to an oversight is not passed
to CMake in some versions of openSUSE where it should be.
Use doc directives to avoid mucking around with cp.
gpg's --use-embedded-filename is a dangerous option that can cause gpg
to write arbitrary content to arbitrary files.
According to the GnuPG maintainer, this is not an option recommended
for use (https://dev.gnupg.org/T4500). Fish shouldn't encourage users
to supply it.
I've offered https://dev.gnupg.org/T6972 to upstream to make it even
more clear that this option is a bad idea.
While removing it, we might as well also remove
--no-use-embedded-filename, since it is effectively a no-op.
(cherry picked from commit b265152fba)
Some of the completions recently introduced called Blender itself to query some
arguments, and Blender sometimes prints messages to stderr. This output was not
filtered, resulting in the shell printing irrelevant messages during completion.
(cherry picked from commit 4f3e7ddef0)
This is a step towards converting `wopen_cloexec()` to return `File` instead of
`OwnedFd`/`AutocloseFd`.¹
In addition to letting us use native standard library functions instead of
unsafe libc calls, we gain additional semantic safety because `File` operations
that manipulate the state of the fd (e.g. `File::seek()`) require a `&mut`
reference to the `File`, whereas using `RawFd` or `OwnedFd` everywhere leaves us
in a position where it's not clear whether or not other references to the same
fd will manipulate its underlying state.
¹ We actually wouldn't even need `wopen_cloexec()` at all (just a widechar
wrapper) as Rust's native `File::open()`/`File::create()` functionality uses
`FD_CLOEXEC` internally.
I used below script to list all GitHub issues and PRs that are not yet
mentioned in the changelog. It's almost empty now.
While at it, curate the "notable" section and move some entries around,
notably from "interactive improvements" to "bindings".
```shell
ms="fish next-3.x"
{
gh issue list --state closed --milestone "$ms" -L 500
gh pr list --state all --search "milestone:\"$ms\"" -L 500
} | sort -n | while IFS='
' read line; do
set -- $line
grep -qE '\W'$1 CHANGELOG.rst ||
echo https://github.com/fish-shell/fish-shell/issues/$1 "$line"
done
```
* builtin/test: Split Token enum into 2-level hierarchy
* builtin/test: Rearrange the Token enum hierarchy
* builtin/test: Separate Token into Unary and Binary
* builtin/test: import IsOkAnd polyfill
* builtin/test: Rename enum variants one more time
... even if the file hasn't changed. This addresses an oddity in the following
case:
* Shell is started,
* function `foo` is sourced from foo.fish
* foo.fish is *externally* edited and saved
* <Loaded definition of `foo` is now stale, but fish is unaware>
* `funced foo` loads `type -p foo` showing changed definition, user exits
$EDITOR saving no changes (or with $status 0, more generally).
* Stale definition of `foo` remains
(cherry picked from commit 2c2ab0c1fa)
If a hostname starts with a dash `-` character, the prompt_hostname function
fails because the `string` function interprets it as an option instead
of an argument.
(cherry picked from commit 6c9c033126)
I was able to trigger this by flipping around the history pager.
Since the only applicable caller here already stops if it gets None,
just don't assert.
Unless the editor changed to a different file for some reason.
Note that the Kakoune integration uses -always to export the cursor even if
the user temporarily suppressed hooks - possibly a "fish_indent" hook.
I don't think the existing logic is correct, as the comment says, our internal
state is only matched if we *actually* wrote out the file. But if we ran into an
error, it doesn't match, does it?
The incompatible_msrv one is a false positive because we have polyfills for
is_some_and() and is_ok_or() which are Rust 1.74. I'm not yet sure how to
communicate that to Clippy.
Call fish_should_add_to_history to see if a command should be saved
If it returns 0, it will be saved, if it returns anything else, it
will be ephemeral.
It gets the right-trimmed text as the argument.
If it doesn't exist, we do the historical behavior of checking for a
leading space.
That means you can now turn that off by defining a
`fish_should_add_to_history` that just doesn't check it.
documentation based on #9298
This is absolutely disgusting code, but it works out okay-ish.
The problem is xgettext has no rust support (it's stuck in review
limbo). So we use cargo-expand to extract all invocations of
gettext, and massage all that to generate a
messages.pot ourselves.
We also assume any string constant could be translated.
One of the things that keep me from using Vi mode is that it doesn't define an
insert-mode shortcut to accept autosuggestions. Let's use Control-N because
that Vim key is the closest equivalent.
Closes#10339
The existing logic did not work because:
- Path::new("/foo/bar").ends_with("/bar") does not return true.
- PathBuf::shrink_to() only (potentially) reallocates the backing
storage, and won't have an effect on the stored value.
It appears that the shift-delete key escape sequence is not being generated
because there's no mapping for it in screen-256color, causing the test to fail.
Switch to using f1 for the test.
We are no longer C++, we no longer support xcode
Note: This will remove a warning "DO NOT EDIT" comment from __fish_build_paths.fish, but
that's unnecessary. The file is typically in /usr or another
package-manager-owned location, so people don't typically edit it.
And if it did we don't actually *care*, it'll work fine.
As mentioned in the comment the historical behavior is because pressing unknown
control characters like Ctrl+4 inserts confusing characters, so let's back
out that part of b77d1d0e2 (Stop crashing on invalid Unicode input, 2024-02-27).
We still have the code for rendering control characters, for pasted text,
or text recalled from history. It is unclear whether we should strip those.
Some terminals already strip control characters from pasted text -- but not
all of them: see https://codeberg.org/dnkl/foot/pulls/312 for example which
has a follow up called "Don't strip HT when pasting in non-bracketed mode".
Don't force the internal use of `RefCell<T>`, let the caller place that into
`MainThread<>` manually. This lets us remove the reference to `MainThread<>`
from the definition of `Screen` again and reduces the number of
`assert_is_main_thread()` calls.
Fairly straightforward, with the only unfortunate part of this being that
`Screen` isn't as pure and now encodes the facte that we use it with
main-thread-only stdout `Outputter`.
The regex struct is pretty large at 560 bytes, with the entire
Abbreviation being 664 bytes.
If it's an "Option<Regex>", any abbr gets to pay the price. Boxing it
means abbrs without a regex are over 500 bytes smaller.
IfStatement is 680 bytes, much larger than the other
variants (SwitchStatement is next at 232). An enum is as large as its
largest variant, so this saves a bunch, especially since
DecoratedStatement is much more likely than IfStatement.
This will speed up the no-execute benchmark by 1.07x.
Unlike C++, Rust requires "char" to be a valid Unicode code point. As a
workaround, we take the raw (probably UTF-8-encoded) input and convert each
input byte to a char representation from the private use area (see commit
3b15e995e (str2wcs: encode invalid Unicode characters in the private use
area, 2023-04-01)). We convert back whenever we output the string, which
is correct as long as the encoding didn't change since the data was input.
We also need to convert keyboard input; do that.
Quick testing shows that our reader drops PUA characters. Since this patch
converts both invalid Unicode input as well as PUA input into a safe PUA
representation, there's no longer a reason to not add PUA characters to
the commandline, so let's do that to restore traditional behavior.
Render them as � (REPLACEMENT CHARACTER); unfortunately we show one per
input byte instead of one per code point. To fix this we probably need our
own char type.
While at it, remove some special cases that try to prevent insertion of
control characters. I don't think they are necessary. Could be wrong..
This makes it so code like
```fish
echo foo
echo bar
```
is collapsed into
```fish
echo foo
echo bar
```
One empty line is allowed, more is overkill.
We could also allow more than one for e.g. function endings.
We don't need to know that it tried these five before finally getting
one, the list is *right there*.
It is also very unlikely that someone has "xterm" or "ansi" but not "xterm-256color"
For xterm-256color, we don't warn *at all* because we have that one hardcoded.
This allows us to get the terminfo information without linking against curses.
That means we can get by without a bunch of awkward C-API trickery.
There is no global "cur_term" kept by a library for us that we need to invalidate.
Note that it still requires a "unhashed terminfo database", and I don't know how well it handles termcap.
I am not actually sure if there are systems that *can't* have terminfo, everything I looked at
has the ncurses terminfo available to install at least.
... even if the file hasn't changed. This addresses an oddity in the following
case:
* Shell is started,
* function `foo` is sourced from foo.fish
* foo.fish is *externally* edited and saved
* <Loaded definition of `foo` is now stale, but fish is unaware>
* `funced foo` loads `type -p foo` showing changed definition, user exits
$EDITOR saving no changes (or with $status 0, more generally).
* Stale definition of `foo` remains
If a hostname starts with a dash `-` character, the prompt_hostname function
fails because the `string` function interprets it as an option instead
of an argument.
We still don't support tabs but as of the parent commit, there are no more
weird glitches, so it should be fine to recall those lines?
This reverts commit cc0e366037.
Inserting Tab or Backspace characters causes weird glitches. Sometimes it's
useful to paste tabs as part of a code block.
Render tabs as "␉" and so on for other ASCII control characters, see
https://unicode-table.com/en/blocks/control-pictures/. This fixes the
width-related glitches.
You can see it in action by inserting some control characters into the
command line:
set chars
for x in (seq 1 0x1F)
set -a chars (printf "%02x\\\\x%02x" $x $x)
end
eval set chars $chars
commandline -i "echo '" $chars
Fixes#6923Fixes#5274Closes#7295
We could extend this approach to display a fallback symbol for every unknown
nonprintable character, not just ASCII control characters.
In future we might want to support tab properly.
This reserved 64, which is *gigantic*.
Over all of share/**.fish, 75% of lists are empty, 99.97% are 16
elements or fewer.
Reducing this to 16 reduces memory usage for a gigantic example
script (git.fish pasted a bunch of times for a total of almost 100k
lines) by ~10% and speeds up "--no-execute" time by the same amount.
For smaller scripts it's less noticeable simply because parse time
matters less.
There are other options, like creating the vec ::with_capacity, or
using 8 instead of 16, or even letting the vec just grow
naturally (rust's vec currently grows from 0 to 4 and then doubles,
which isn't terrible for this use), but the point is that 64 is
wasteful and never comes out on top, always in the last two places
comparing a bunch of choices.
Makes it possible to use the sanitizers again.
Note that this requires RUSTFLAGS to be set when running CMake, and will not be
updated when running the build system if the environment variable changes.
Fish functions are great for configuring fish but they don't integrate
seamlessly with the rest of the system. For tasks that can run outside fish,
writing scripts is the natural approach.
To edit my scripts I frequently run
$EDITOR (which my-script)
Would be great to reduce the amount typing for this common case (the names
of editor and scripts are usually short, so that's a lot of typing spent on
the boring part).
Our Alt+o binding opens the file at the cursor in a pager. When the cursor
is in command position, it doesn't do anything (unless the command is actually
a valid file path). Let's make it open the resolved file path in an editor.
In future, we should teach this binding to delegate to "funced" upon seeing
a function instead of a script. I didn't do it yet because funced prints
messages, so it will mess with the commandline rendering if used from
a binding. (The fact that funced encourages overwriting functions that
ship with fish is worrysome. Also I'm not sure why funced doesn't open the
function's source file directly (if not sourced from stdin). Persisting the
function should probably be the default.)
Alternative approach: I think other shells expand "=my-script" to
"/path/to/my-script". That is certainly an option -- if we do that we'd want
to teach fish to complete command names after "=". Since I don't remember
scenarios where I care about the full path of a script beyond opening it in
my editor, I didn't look further into this.
Closes#10266
Commit e5b34d5cd (Suppress autosuggesting during backspacing like browsers do,
2012-02-06) disabled autosuggestion when backspacing. Autosuggestions are
re-enabled whenever we insert anything in the command line. Undo uses a
different code path to insert into the command line, which does not re-enable
autosuggestion.
Fix that.
Also re-enable autosuggestion when undo erases from the command line.
This seems like the simplest approach. It's not clear if there's a better
behavior; browsers don't agree on one in any case.
This is the last remnant of the old percent expansion.
It has the downsides of it, in that it is annoying to combine with
anything:
```fish
echo %self/foo
```
prints "%self/foo", not fish's pid.
We have introduced $fish_pid in 3.0, which is much easier to use -
just like a variable, because it is one.
If you need backwards-compatibility for < 3.0, you can use the
following shim:
```fish
set -q fish_pid
or set -g fish_pid %self
```
So we introduce a feature-flag called "remove-percent-self" to turn it
off.
"%self" will simply not be special, e.g. `echo %self` will print
"%self".
This stops you from doing e.g.
```fish
set pager command less
echo foo | $pager
```
Currently, it would run the command *builtin*, which can only do
`--search` and similar, and would most likely end up printing its own
help.
That means it very very likely won't work, and the code is misguided -
it is trying to defeat function resolution in a way that won't do what
the author wants it to.
The alternative would be to make the command *builtin* execute the
command, *but*
1. That would require rearchitecting and rewriting a bunch of it and
the parser
2. It would be a large footgun, in that `set EDITOR command foo` will
only ever work inside fish, but $EDITOR is also used outside.
I don't want to add a feature that we would immediately have to discourage.
Currently, if you enter `echo` and press up-arrow, it might select
e.g. `echo foo`.
You can then enter text, making it `echo foobar` and press up-arrow
again, but the search string is *still* `echo`.
Many *other* input functions will end history search, including e.g.
expand-abbr, so pressing space by default will already end it.
So this ends the history search once you input something.
Incidentally this allows suggestions to work in this case, so it
Fixes#10287
Note that autosuggestions have been disabled while history search is
active since a08450bcb6, I'm not sure
it's actually *needed*, so it would also be possible to enable it in
that case.
But since this is already awkward (history search is *active* but with
the old search string) and I'm not sure if e.g. suggestions during
history search would be too busy, let's do this first.
With LTO, Release builds are now a lot slower.
For development debug builds are much nicer.
We'll ask packagers to pass Release when building a package.
Unfortunately ninja does not want to be tricked.
I tried `touch`ing a file and writing the date to a file,
and even removing that file before cargo runs, it doesn't work.
So instead we'll do the imperfect solution of enumerating sources.
And yes, we use a GLOB because listing source files is terrible.
Any build system that wants you not to glob is a build system made for
build system people who like touching build systems, not me.
The default codegen units is 16 but we set it to 1*. On my system, this
saves 0.1 MB (2%) in the unstripped binary, while adding 10s (20%) to the
build time. This doesn't seem worth, better stick to the defaults.
[*] along enabling fat LTO which is debatable too
gpg's --use-embedded-filename is a dangerous option that can cause gpg
to write arbitrary content to arbitrary files.
According to the GnuPG maintainer, this is not an option recommended
for use (https://dev.gnupg.org/T4500). Fish shouldn't encourage users
to supply it.
I've offered https://dev.gnupg.org/T6972 to upstream to make it even
more clear that this option is a bad idea.
While removing it, we might as well also remove
--no-use-embedded-filename, since it is effectively a no-op.
This reduces the test time by ~33% on my system (23s to 15s)
Given that it takes ~180-240s on Github Actions, if we get a reduction
like that we can save over a minute.
These are dog-slow at building, and the tests themselves are barely
sped up running as release.
Given that we have ~10 minute build and ~3 minute test time on Github
Actions on macOS, let's see if this speeds it up
(we can also do it for the others, but the most important is the
slowest test because that's what stops the checkmark appearing)
We only use this
1. if we have localeconv_l
2. to get the decimal point / thousands separator for numbers
So we can ignore all this and directly create a purely LC_NUMERIC locale.
This *was* more useful when we were in C++ and the printing functions
all relied on locale, but we only use this in printf and that only
extracts the number stuff.
Commit b768b9d3f (Use fuzzy subsequence completion for options names as well,
2024-01-27) allowed completing "oa" to "--foobar", which is a false positive,
especially because it hides other valid completions of non-option arguments.
Let's at least require a leading dash again before completing option names.
The lines of code I commented on in #10254 were meant to serve only as examples
of the changes I was requesting, not the only instances.
Also just use `Mode::from_bits_truncate()` instead of unsafe or unwrapping since
we know the modes are correct.
* Fix build on NetBSD
Notably:
1. A typo in `f_flag` vs `f_flags` - this was probably never tested
2. Some pointless name differences - `st_mtimensec` vs
`st_mtime_nsec`
3. The big one: This said that LC_GLOBAL_LOCALE() was -1 "everywhere".
Well, not on NetBSD.
* ifdef for macos
Instead of skipping for non-interactive shells, skip when stdin is not a tty.
This allows the cursor to be set for scripts that use the `read` command.
We use this so you can run fish from the build directory and it picks
up its data files.
If this wasn't canonicalized, that would break if you're building with
a $PWD through a symlink.
* Update just.fish to handle descriptions for completions
This change updates fish completions to also include descriptions for justfile recipes. It has been tested with descriptions for recipes with arguments as well
* rely on fish only (avoid sed)
Version 2.1.0 introduced subsequence matching for completions but as the
changelog entry mentions, "This feature [...] is not yet implemented for
options (like ``--foobar``)". Add it. Seems like a strict improvement,
pretty much.
.unwrap() is in effect an assert(). If it is applied mistakenly, the
program crashes and there isn't a good error.
I would like it to be used as a last resort. In these cases there are
nicer ways to do it that handle a missing result properly.
Fix cases like
eval my-cmd (commandline -o)
complete -C "my-cmd $(commandline -o)"
In both cases, we spuriously evaluate tokens like "(inside-quoted-string)"
as command substitutions. Fix this by escaping the strings. The momentarily
regresses the intended purpose of "eval" -- to expand variables -- but the
next commit will fix that.
Issue #10194 reports Cobra completions do
set -l args (commandline -opc)
eval $args[1] __complete $args[2..] (commandline -ct | string escape)
The intent behind "eval" is to expand variables and tildes in "$args".
Fair enough. Several of our own completions do the same, see the next commit.
The problem with "commandline -o" + "eval" is that the former already
removes quotes that are relevant for "eval". This becomes a problem if $args
contains quoted () or {}, for example this command will wrongly execute a
command substituion:
git --work-tree='(launch-missiles)' <TAB>
It is possible to escape the string the tokens before running eval, but
then there will be no expansion of variables etc. The problem is that
"commandline -o" only unescapes tokens so they end up in a weird state
somewhere in-between what the user typed and the expanded version.
Remove the need for "eval" by introducing "commandline -x" which expands
things like variables and braces. This enables custom completion scripts to
be aware of shell variables without eval, see the added test for completions
to "make -C $var/some/dir ".
This means that essentially all third party scripts should migrate from
"commandline -o" to "commandline -x". For example
set -l tokens
if commandline -x >/dev/null 2>&1
set tokens (commandline -xpc)
else
set tokens (commandline -opc)
end
Since this is mainly used for completions, the expansion skips command
substitutions. They are passed through as-is (instead of cancelling or
expanding to nothing) to make custom completion scripts work reasonably well
in the common case. Of course there are cases where we would want to expand
command substitutions here, so I'm not sure.
Move all qmark tests to `scoped_test()` sections with explicitly set feature
flags. We already test the default qmark behavior in the functionality tests.
This prefers `-s` to `-v` - we have a *lot* more uses of `command -s`, it's the easier
mnemonic *and* the more compatible-with-fish option.
Also we don't really need the separate section that explains what
these options do *again*.
It seems the logic for calculating the cursor position was not ported correctly,
because the correct place to insert it is at the cursor_pos regardless of
range.start, going by the parameters submitted to the function and the expected
result.
This allows running a fish built from `cargo build` *and* built via
cmake.
In future, we should make this an optional thing that's removed from
installed builds.
This is our traditional behavior; "man" and "git" do the same.
(cherry picked from commit b83f3b0e98)
Proposing this for 3.7.1 because I think see this as regression in 3.7.0 -
a user might have installed bat for syntax highlighting only.
We're already moving them, we can remove the awkward dot that hides
them, and while we're doing that remove the useless $USER as well.
Most systems will have only one of these files - it's rare to run a
second package manager (especially for anything more than
bootstrapping a container).
These take a *lot* of time - `pip3` takes 180ms, `pipenv` takes 320ms
on my system.
Note that this removes a number of obsolete workarounds - pip's was
fixed in 2017 (and pip2 is less and less of a thing), pipenv's change
was in 2019.
Since these are packaging tools with access to the internet they
should really be kept up-to-date, so it is unlikely someone still uses
these old versions.
We have a lot of completions that look like
```fish
pip completion --fish 2>/dev/null | source
```
That's *fine*, upstream gives us some support.
However, the scripts they provide change very rarely, usually not even
every release, and so running them again for every shell is extremely
wasteful.
In particular the python tools are very slow, `pip completion --fish`
takes about 180ms on my system with a hot cache, which is quite
noticeable.
So what we do is we run them once, store them in a file in our cache
directory, and then serve from that.
We store the mtime of the command we ran, and compare against that for
future runs. If the mtime differs - so if the command was up or
downgraded, we run it again.
This will move all current cache uses to e.g. ~/.cache/fish/
That's better anyway because it makes it easier to remove.
Also it allows supplying a subdir so you can do `__fish_make_cache_dir
completions`
to get ~/.cache/fish/completions.
NCurses headers contain this conditional "#define cur_term":
print "#elif @cf_cv_enable_reentrant@"
print "NCURSES_WRAPPED_VAR(TERMINAL *, cur_term);"
print "#define cur_term NCURSES_PUBLIC_VAR(cur_term())"
print "#else"
OpenSUSE Tumbleweed uses this configuration option; For reentrancy, cur_term
is a function. If the NCurses autoconf variable @NCURSES_WRAP_PREFIX@
is not changed from its default, the function is called _nc_cur_term.
I'm not sure if we have a need to support non-default @NCURSES_WRAP_PREFIX@
but if we do there are various ways;
- search for the symbol with the cur_term suffix
- figure out the prefix based on the local curses installation,
for example by looking at the header files.
Fixes#10243
If I alias "e" to "emacsclient" it will probably accept the same options.
Let's dereference the alias so we can detect support for passing the cursor
position in more cases.
This does not solve the problem for recursive cases (e.g. alias of another
alias). If we want to handle that we would need cycle detection.
This is run in the current locale, without resetting to en_US.UTF-8
like our integration tests do.
So if you want to check for a specific message you need to check the
localized version.
This is awkward because some systems really want $SHELL to be
sh-compatible, it's also duplicated with the actual docs and not
really something you have to do in the first five minutes of using
fish.
Supersedes #10229
CMP0066: Honor per-config flags in try_compile() source-file
signature.
CMP0067: Honor language standard in try_compile() source-file signature.
We no longer have any try_compile
This was previously limited to Linux predicated on the existence
of certain headers, but Rust just exposes those functions unconditionally. So
remove the check and just perform the mtime hack on Linux and Android.
Make sure to also look for the error part that occurs after the last format
specifier.
Still not great because it won't fail if there's unexpected output at the
beginning or end of the string.
Commit 5f849d0 changed control-C to print an inverted ^C and then a newline.
The original motivation was
> In bash if you type something and press ctrl-c then the content of the line
> is preserved and the cursor is moved to a new line. In fish the ctrl-c just
> clears the line. For me the behaviour of bash is a bit better, because it
> allows me to type something then press ctrl-c and I have the typed string
> in the log for further reference.
This sounds like a valid use case in some scenarios but I think that most
abandoned commands are noise. After all, the user erased them. Also, now that
we have undo that can be used to get back a limited set of canceled commands.
I believe the original motivation for existing behavior (in other shells) was
that TERM=dumb does not support erasing characters. Similarly, other shells
like to leave behind other artifacts, for example when using tab-completion
or in their interactive menus but we generally don't.
Control-C is the obvious way to quickly clear a multi-line commandline.
IPython does the same. For the other behavior we have Alt-# although that's
probably not very well-known.
Restore the old Control-C behavior of simply clearing the command line.
Our unused __fish_cancel_commandline still prints the ^C. For folks who
have explicitly bound ^C to that, it's probably better to keep the existing
behavior, so let's leave this one.
Previous attempt at #4713 fizzled.
Closes#10213
This function is a hotspot, but it has inefficient codegen:
1. For whatever reason, the chars() iterator of wstr is slower
than that of a slice. Use the slice.
2. Unnecessary overflow checks were preventing vectorization.
Switch to a more optimized implementation.
This improves aliases benchmark time by about 9%.
This was used in CMake to detect invalid mbrtowc implementations. The only known
case was on SnowLeopard, which is no longer supported. Remove this file.
Since none of the compiles(xxx) calls are to particularly complex code, we can
just use `rsconf` directly to test for the presence of the symbols or headers as
needed.
Note that it seems at least some of the previous detection was not working
correctly; in particular HAVE_PIPE2 was evaluating to false on my WSL install
where pipe2(2) was available (caught because it revealed some compilation errors
in that conditional compilation path after porting).
I kept the cfg names and the tests themselves mostly as-is, though we might want
to change that to conform with the rust convention of lowercase cfg names and
decide whether we want to prefix all these with have_, fish_, or nothing at all.
Also the posix_spawn() test should probably check for the symbol `posix_spawn()`
rather than the header `spawn.h` since we don't use it via the header but rather
via the symbol (but in reality they're almost certainly going to give the same
result).
NB: I only encountered this when rewriting the cfg detection, which means that
the previous detection wasn't correct since I have pipe2 on Linux but didn't run
into this build error before.
I had originally created a safe `set_locale()` wrapper and clippy-disallowed
`libc::setlocale()` but almost all our uses of `libc::setlocale()` are in a loop
where it makes much more sense to just obtain the lock outright then call
`setlocale()` repeatedly rather than lock it in the wrapper function each time.
No need to use cfg_attr and have to worry about syncing the preconditions for
the cfg_attr with the preconditions for where `slice_contains_slice()` is used
in the codebase, just mark it as `allow(unused)` with a comment.
pcre2-sys includes a vendored copy of PCRE2, which allows for
statically-linked PCRE2. Hook this up to the CMake build variable, and
remove the C++ integration for PCRE2.
They are probably not terribly useful for us but let's see what happens.
Unfortunately cargo does not properly forward the combination of "RUSTFLAGS"
and "--target" that is currently required to build with ASan [1]. Hence doctests
will fail to link on ASan builds. Let's disable doctests when ASan is active.
[1]: https://github.com/rust-lang/cargo/issues/10666 et al
Use Rust for executables
Drops the C++ entry points and restructures the Rust package into a
library and three binary crates.
Renames the fish-rust package to fish.
At least on Ubuntu, "fish_indent" is built before "fish".
Make sure export CURSES_LIBRARY_LIST to all binaries to make sure
that "cached-curses-libnames" is populated.
Closes#10198
With the next commit, if I run
docker/docker_run_tests.sh --shell-after docker/jammy-asan-clang.Dockerfile
I get this in test_string.fish and test_git.fish:
=================================================================
==8339==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 72 byte(s) in 1 object(s) allocated from:
#0 0x55a8a637eb45 in realloc /rustc/llvm/src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:85:3
#1 0x7facb841b6cc in _nc_doalloc (/lib/x86_64-linux-gnu/libtinfo.so.6+0x106cc) (BuildId: e22ba7829a55a0dec2201a0b6dac7ba236118561)
SUMMARY: AddressSanitizer: 72 byte(s) leaked in 1 allocation(s).
Strangely there is no tparm in the call stack. It does not seem to happen
in CI.
This makes "ninja test" write only to the build directory, not to the source
tree. This enables our docker script which mounts the source as read-only.
Some tests create files like "./test/test-home". Traditionally the did so
in the first parent directory that contained tests/test.fish; so either a
build directory or the root.
The new rust version always changes directory to the root. This blows up
when running with our docker/ files, which mount the source as read-only.
Fix this by always changing directory to the build directory.
In future we could extend this to not chdir if FISH_BUILD_DIR was not
specified, to match traditional behavior. No strong opinions here.
Update the pydoctheme.css file to add support for print media.
The code was adapted from the existing support for screens that are less than
700px wide, with the following changes:
- Remove the documents and sections index
- Remove the quick search
- Remove dead CSS code
Additionally, add section numbers and ensure that code blocks are never split
across multiple pages.
GNUInstallDirs is what defines CMAKE_INSTALL_FULL_BINDIR and such, so
the setting in Rust.cmake didn't work.
This also makes build.rs error out if any of these aren't defined
This would highlight `$var["foo"]` as an error because
parse_util_slice_length didn't advance the iterator.
There's got to be a nicer way to write this.
The C++ code implicitly relied on wrapping behavior.
There are probably more cases like this. Maybe we should disable
"overflow-checks" in release mode.
This would crash from the highlighter for something like
`PATH={$PATH[echo " "`
The underlying cause is that we use "char_at" which panics on
overread.
So instead this implements try_char_at and then just returns None.
The function `stat` as defined in `include/x86_64-linux-gnu/sys/stat.h`
marks its arguments as nonnull as in below. This UB causes crash in
release builds with variable `interpreter` assumed to be nonnull. Along
with failing stat returning nonzero value, this ultimately causes
`strlen` to be called with NULL as argument.
Definition of `stat`:
```
extern int stat (const char *__restrict __file,
struct stat *__restrict __buf) __THROW __nonnull ((1, 2));
```
Reproduce:
```
> # interp.c is any vaild single file C source
> gcc ./interp.c -Wl,--dynamic-linker=/bad -o interp
> echo './interp' > in.txt
> ./fish < in.txt
'./fish < in.txt' terminated by signal SIGSEGV (Address boundary error)
```
Co-authored-by: Moody Liu <mooodyhunter@outlook.com>
This is more correct - we don't want to change how we encode this
string in the middle of encoding it, and also happens to be a bit
faster in my benchmarks because this is actually a function call
according to valgrind.
We assume that you use something like hyperfine to run warmups, like
our driver script does.
This allows the script to be run e.g. in valgrind without being too
much of a pain in the gluteus.
Iterator::last() consumes the entire iterator, even for DoubleEndedIterator,
see https://github.com/rust-lang/rust/pull/28125#issuecomment-145070161
Because of this, "at_line_start()" took 90% of
fish_indent share/completions/git.fish
making it take 1000ms instead of 30 ms. Fix that.
Keep running tests serially to avoid breaking assumptions.
I think many of these tests can run in parallel and/or don't need test_init().
Use the safe variant everywhere, to get it done faster.
Here are the differences to the C++ version in fish_tests:
1. we don't need to chdir to repo root, cargo test already does.
2. we don't need srandom because we already use deterministic RNGs for tests.
3. we don't yet call asan_before_exit(). Not yet sure how to hook into
"cargo test" before exit.
This will allow to use "cargo test" for unit tests that depend on our
curses.rs.
This means that Rust.cmake depends on ConfigureChecks, so move that one to
the front.
Today, debounce-style work items are only created from the main thread.
The work to compute the result is done in a background thread but the
completion callback is called on the main thread again.
The completion callbacks used by the reader capture a shared reference to
ReaderData, which includes a Parser. Neither of those types needs to be
sent across threads.
The debounce machinery moves the completion callback into a function object
that is moved to the background thread and back again. Because of this
there is a Send requirement on the completion callback.
Since we already synchronize on MAIN_THREAD_QUEUE, we don't need Send from
the function object. Lift the requirement.
This removes an awkward hack from ParseError::describe_with_prefix,
where it added errors for two error codes.
andor_in_pipeline was already there, so we just need bare_variable_assignment.
Some of the completions recently introduced called Blender itself to query some
arguments, and Blender sometimes prints messages to stderr. This output was not
filtered, resulting in the shell printing irrelevant messages during completion.
This would misname `\e\x7F` as "backspace":
bind -k backspace 'do something'
bind \e\x7F 'do something'
because it would check if there was any key *in there*.
This was probably meant for continuous mode, but it simply doesn't
work right. It's preferable to not give a key when one would work over
giving one when it's not correct.
This file uses the questionable "self.somemethod(self.somefield)" pattern.
We should either set the functions free or stop passing redundant parameters.
Not sure.
For now fix one of them to avoid a string clone.
This implements input and input_common FFI pieces in input_ffi.rs, and
simultaneously ports bind.rs. This was done as a single commit because
builtin_bind would have required a substantial amount of work to use the input
ffi.
This will support rewriting the input machinery in Rust.
Note that while there are a lot of keys here, in practice this is very fast -
taking on the order of microseconds to populate.
We run __fish_enable_bracketed_paste on every shell prompt, and inside
edit_command_buffer. This protects from accidents when pasting control
characters, and makes sure the paste results in a single undo group.
Let's do the same for builtin read.
Found while doing the research for #10101
- Replace short options with old-style options: even though they are
single-letter, Blender's options cannot be combined.
- Add comments to separate blocks of options, mirroring Blender's help message.
- Add missing options: render-frame, python-use-system-env, register-allusers,
unregister, unregister-allusers.
- Remove options: debug-gpu-disable-ssbo, debug-gpu-renderdoc, -R.
- Fix typos:
- debug-depsgraph-eval (was -evel)
- debug-depsgraph-pretty (was -time)
- app-template (was open-last)
- Update output formats:
- Add descriptions.
- Add HDR, TIFF, OpenEXR, OpenEXR Multilayer, FFmpeg, Cineon, DPX, JPEG 2000,
and WebP, which are optional but generally available.
- Remove IRIZ, which is no longer available.
- Fix arguments for --use-extension: they should be 0 or 1, not true or false.
- Make env-system-* options require a parameter.
- Improve --add-ons by querying the list of add-ons inside Blender rather than a
hardcoded path. This is because Blender's add-on modules may come from many
different paths which depend on platform.
- Fix __blender_echo_input_file_name, by relying on extension.
- Fix listing of scene datablocks inside Blend file.
- Add listing of Python text datablocks to execute inside Blend file.
Closes#10150
Adhere as best as possible to the style guidelines at
https://www.nordtheme.com/docs/colors-and-palettes. Some adaptations were made
so that `functions <function>` is also syntax highlighted per the upstream
recommendations.
Additionally, the theme file has been reordered to follow the order of variables
defined in interactive syntax-highlighting-variables documentation.
This was an issue with "--no-execute", which has no variables and
therefore no $HOME:
```fish
fish --no-execute /path/to/file
```
would say the error is in `~/path/to/file`.
Instead, since this is just for a message, we simply return the
filename without doing the replacement.
Fixes#10171
The existing subsequence search commonly returns false positives.
Support globs, to allow searching for disconnected substrings in a better way.
Closes#10143Closes#10131
When working on a C or C++ projects, it is often handy to compile a
single file (e.g. large refactoring where many files fail to compile so
compiling a single file results in less compiler errors making the compiler
output significantly easier to read and navigate). Current completion offers
only ninja targets which are usually just top level binaries. This commit makes
object files and library files to be offered in the ninja completion.
The change is inspired by the zsh ninja completion [1], but aims to reduce noise
by only matching for entries ending in ".o", ".so" or ".a".
[1] c828f06e08/src/zsh/_ninja (L30)
The "#[bench]" attribute is not allowed in stable Rust, so keep it behind
a new feature flag. Run on nightly Rust with
$ cargo bench --features=bechmark
test tests::encoding::bench::bench_convert_ascii ... bench: 125,988 ns/iter (+/- 1,128) = 1040 MB/s
Repeated
CARGO_LOG=cargo::core::compiler::fingerprint=trace cargo b
show that we always rebuild because of "compat.c". Not sure why.
Let's disable this for now so we can use the cache (for test targets etc.).
We rarely attach trait methods to stdlib types so this warning is unlikely to
be a true positive It is a false positive for the methods defined in future.rs.
It's not always obvious which method is selected when it's available in the
stdlib but I haven't seen a build failure yet. So let's disable the warning.
In future we might be able suppress it per method, see Rust issue 48919.
We often want to format and print a string to a fd, usually stdout/stderr.
In general we can't use "format!", "print!", "eprint!" etc. because they don't
know about our use of WString where we encode of invalid Unicode characters
in the private use area.
Instead we use "wwrite_to_fd()".
Since we unfortunately don't have a "wformat!()" yet, we use "sprintf!()"
to create a formatted wstring to pass to "wwrite_to_fd()".
Add "printf!" and "eprintf!" to stand in for "print!" and "eprint!".
For printing to files other than stdout and stderr, keep "fwprintf!" but
drop the "w" since our "sprintf!" always produces wide strings.
Replace "fputws" with "fprintf" though we could also use "wwrite_to_fd"
if performance matters.
Unlike std::io::stdout(), we don't use locking yet.
Remaining work:
- There are more places where we use \be?print(ln)?!
Usually we print strings that are guaranteed to be valid UTF-8, but not
always. We should probably make all of them respect our WString semantics
but preferrably keep using the native Rust format strings (#9948).
- I think flog.rs currently uses String so it won't handle invalid Unicode
characters. We should probably fix this as well.
These compile checks are expected to produce compiler errors on some systems.
The errors show up when there is an unrelated error, this is probably quite
confusing so fix that. Should revisit this later.
Like FLOGF!, this now needs at least one argument to format.
This avoids some issues with missing variables and broken format
strings - it is how I found 13ba5bd405 -
where disown had a format string, with two placeholders, but no
arguments to fill them with.
For use in e.g. macros, where it's otherwise hard to tell if we have
something to format or not, this adds a wgettext_maybe_fmt! version to
"maybe" format, if necessary.
In LastC++11, an empty history item means we either reached the end of history,
or the item is actually empty. The second meaning is still true. We never
append empty history items but the history file might have been modified.
Fixes#10129
Recall that universal notifiers are used to report changes to universal
variables to other shell instances. This adds a new strategy based on using
inotify to directly monitor the universal variables
file.
We have tried this in the past and abandoned it because it doesn't properly
work on some CI systems - let's try again.
This
1. Skips access() if we only have "special" permissions like the owner
that need stat
2. Does the geteuid()/getegid() *once* outside of filter_path, if we
need it
In the extreme case of `path filter --perm user,group` it will remove
3 syscalls per file.
This makes it easier to get *any pager* in the number of places we do.
Unfortunately:
1. It can't just execute the pager because that might block
2. We can't really set the necessary options for less here
so they still need to be set outside.
This
Fixes#10074
by falling back to `cat` in that case. We could also decide to abort
instead of using a non-pager, but for history that's probably fine.
Drop support for history file version 1.
ParseExecutionContext no longer contains an OperationContext because in my
first implementation, ParseExecutionContext didn't have interior mutability.
We should probably try to add it back.
Add a few to-do style comments. Search for "todo!" and "PORTING".
Co-authored-by: Xiretza <xiretza@xiretza.xyz>
(complete, wildcard, expand, history, history/file)
Co-authored-by: Henrik Hørlück Berg <36937807+henrikhorluck@users.noreply.github.com>
(builtins/set)
This reduces noise in the upcoming "Port execution" commit.
I accidentally made IoStreams a "class" instead of a "struct". Would be
easy to correct that but this will be deleted soon, so I don't think we care.
These printed "Unknown error while evaluating command substitution".
Now they print something like
```
fish: for: status: cannot overwrite read-only variable
for status in foo; end
^~~~~^
in command substitution
fish: Invalid arguments
echo (for status in foo; end)
^~~~~~~~~~~~~~~~~~~~~~~^
```
for `echo (for status in foo; end)`
This is, of course, still not *great*. Mostly the `fish: Invalid
arguments` is basically entirely redundant.
An alternative is to simply skip the error message, but that requires some
more scaffolding (describe_with_prefix adds some error messages on its
own, so we can't simply say "don't add the prefix if we don't have a
message")
(cherry picked from commit 1b5eec2af6)
Refresh some stale CSS, improve some rendering, and fix some bugs.
Some of the CSS no longer applied. Remove the bright red X in history
and use a tamer color. Fix the prev/next paginator buttons from moving
for large paginations. Fix the calculation about disabling prev/next.
* wildcard: Remove file size from the description
We no longer add descriptions for normal file completions, so this was
only ever reached if this was a command completion, and then it was
only added if the file wasn't a regular file... in which case it can't
be an executable.
So this was dead.
* Make possible_link() a maybe
This gives us the full information, not just "no" or "maybe"
* wildcard: Rationalize file/command completions
This keeps the entry_t as long as possible, and asks it, so especially
on systems with working d_type we can get by without a single stat in
most cases.
Then it guts file_get_desc, because that is only used for command
completions - we have been disabling file descriptions for *years*,
and so this is never called there.
That means we have no need to print descriptions about e.g. broken symlinks, because those are not executable.
Put together, what this means is that we, in most cases, only do
an *access(2)* call instead of a stat, because that might be checking
more permissions.
So we have the following constellations:
- If we have d_type:
- We need a stat() for every _symlink_ to get the type (e.g. dir or regular)
(this is for most symlinks, if we want to know if it's a dir or executable)
- We need an access() for every file for executables
- If we do not have d_type:
- We need a stat() for every file
- We need an lstat() for every file if we do descriptions
(i.e. just for command completion)
- We need an access() for every file for executables
As opposed to the current way, where every file gets one lstat whether
with d_type or not, and an additional stat() for links, *and* an
access.
So we go from two syscalls to one for executables.
* Some more comments
* rust link option
* rust remove size
* rust accessovaganza
* Check for .dll first for WSL
This saves quite a few checks if e.g. System32 is in $PATH (which it
is if you inherit windows paths, IIRC).
Note: Our WSL check currently fails for WSL2, where this would
be *more* important because of how abysmal the filesystem performance
on that is.
This is off by one from the C++ version.
It wasn't super obvious why this worked in the first place.
Looks like args[0] is "-" because we are invoked like
fish -c 'exec "${@}"' - "${@}"
and it looks like "-" is treated like "--" by bash, so we emulate that.
See https://github.com/fish-shell/fish-shell/issues/367#issuecomment-11740812
This function only ever returns true if target_os=linux, so we need to invert
the OS check.
In the first invocation, this function may allocate heap memory.
Clarify that this is safe.
[ja: I don't have the original commit handy so I made up the log message]
The following "Port execution" commit will use RefCell for the wait handle
store. If we hold a borrow while we are running an event (which may run
script code) there will be a borrowing conflict. Avoid this by returning
the borrow earlier.
Given an env like
foo
bar=baz
we would set "foo" to empty due to a typo.
The typo is pointed out by a PORTING comment.
Luckily I don't think we ever hit this case because that would mean our
parent process has a serious bug. Rust's std::env::vars_os() skips env
lines that don't contain a "=" char. This seems like a reasonable behavior
for us too. Do that.
This makes it so expand_intermediate_segment knows about the case
where it's last, only followed by a "/".
When it is, it can do without the file_id for finding links (we don't
resolve the files we get here), which allows us to remove a stat()
call.
This speeds up the case of `...*/` by quite a bit.
If that last component was a directory with 1000 subdirectories we
could skip 1000 stat calls!
One slight weirdness: We refuse to add links to directories that we already visited, even if they are the last component and we don't actually follow them. That means we can't do the fast path here either, but we do know if something is a link (if we get d_type), so it still works in common cases.
This can be bound like `bind \cl clear-screen`, and is, by default
In contrast to the current way it doesn't need the external `clear`
command that was always awkward.
Also it will clear the screen and first draw the old prompt to remove
flicker.
Then it will immediately trigger a repaint, so the prompt will be overwritten.
This fixes the following deadlock. The C++ functions path_get_config and
path_get_data lazily determine paths and then cache those in a C++ static
variable. The path determination requires inspecting the environment stack.
If these functions are first called while the environment stack is locked
(in this case, when fetching the $history variable) we can get a deadlock.
The fix is to call them eagerly during env_init. This can be removed once
the corresponding C++ functions are removed.
This issue caused fish_config to fail to report colors and themes.
Add a test.
This was pretty annoying on rust release day, because it introduced
new warnings.
Specifically 1.73 introduced a spurious one about PartialOrd and Ord
disagreeing when both were in fact #derive-d.
Unlike our C++ tests, our Rust tests fail as soon as an assertion fails.
Whether this is desired is debatable; it seems fine for
most cases and is easier to implement.
This means that Rust tests usually don't need to print anything besides
what assert!/assert_eq! already provide.
One exception is the history merge test. Let's add a simple err!() macro to
support this. Unlike the C++ err() it does not yet print colors.
Currently all of our macros live in common.rs, to keep the import graph simple.
Notably this exposes config.h to Rust (for UVAR_FILE_SET_MTIME_HACK).
In future we should move the CMake checks into build.rs so we can potentially
get rid of CMake.
On the following "Port execution" commit, ASan will complain if we read
beyond a terminating null byte in get_autosuggestion_performer(). This is
actually working as intended but we need to appease ASan somehow..
get_pwd_slash() uses "if var.is_empty()" but it should be "if !var.is_empty()".
This wasn't a problem so far because in practice most code paths use the
get_pwd_slash() override from EnvStackImpl. The generic one is used in the
upcoming unit tests.
This uses "screen.reset_line" to move the cursor without informing the
reader's machinery (because that deals with positions *in the
commandline*), but then only repainted "if needed" - meaning if the
reader thought anything changed.
That could lead to a situation where the cursor stays at column 0
until you do something, e.g. in
```fish
bind -m insert u undo
```
when you press alt+u - because the *escape* calls repaint-mode, which
puts the cursor in column 0, and then the undo doesn't, which keeps it
there.
Of course this binding should also `repaint-mode`, because it changes
the mode.
Some changes might be ergonomic:
1. Make repaint-mode the default if the mode changed (we would need to
skip it for bracketed-paste)
2. Make triggering the repaint easier - do we need to set
force_exec_prompt_and_repaint to false here as well?
Anyway, this
Fixes#7910
This strips the newline from "code_context" (which is really just the
called function), and from the unescaped output.
Rather, in case the output doesn't end with a newline it'll mark it
with an explicit message "(no trailing newline)".
This was introduced as a workaround to #7215 - xdg-open's generic path
wouldn't background graphical apps.
This has been fixed a month ago in xdg-open, so we can stop doing it.
The good news is this also allows terminal apps to be used again, so
it
Fixes#10045
This is a sensible thing to do, and fixes some cases where we're
state-dependent.
E.g. this fixes the case in the pager where some things are bold and
some aren't, because that bolding is (rather awkwardly) implicitly
triggered when we have a background, and so we don't notice we need to
re-do that bolding after we moved to the next line because we think we
still have the same color.
Fixes#9617
This adopts the Rust postfork code, bridging it from C++ exec module.
We use direct function calls for the bridge, rather than cxx/autocxx, so that we
can be sure that no memory allocations or other shenanigans are happening.
This implements the "postfork" code in Rust, including calling fork(),
exec(), and all the bits that have to happen in between. postfork lives
in the fork_exec module.
It is not yet adopted.
This introduces a new module called fork_exec, which will be for posix_spawn,
postfork, and flog_safe - stuff concerned with actually executing binaries,
and error reporting.
Add a FLOG_SAFE! macro which writes errors to the flog fd in an
async-signal-safe way. This implementation differs from the C++ in that we
allow printing integers directly - no requiring them to be converted to a
buffer first.
This makes it so
```fish
if -e foo
# do something
end
```
complains about `-e` not being a command instead of `end` being used
outside of an if-block.
That means both that `-e` could now be used as a command name (it
already can outside of `if`!) *and* that we get a better error!
The only way to get `if` to be a decorated statement now is to use `if
-h` or `if --help` specifically (with a literal option).
The same goes for switch, while and begin.
It would be possible, alternatively, to disallow `if -e` and point
towards using `test` instead, but the "unknown command" message should
already point towards using `test` more than pointing at the
"end" (that might be quite far away).
- This is untested and unused, string ownership is very much subject to change
- Ports the minimally necessary parts of complete.rs as well
- This should fix an infinite loop in `create_directory` in `path.rs`, the first
`wstat` loop only breaks if it fails with an error that's different from
EAGAIN
- wildcard_match is now closer to the original that is linked in a comment, as
pointer-arithmetic translates very poorly. The act of calling wildcard
patterns wc or wildcard is kinda confusing when wc elsewhere is widechar.
This was already supposed to handle `--foo=bar<TAB>` cases, except it
printed the `--foo=` again, causing fish to take that as part of the
token.
See #9538 for a similar thing with __fish_complete_directories.
Fixes#10011
This is the most common and sensible env var, we check it outside,
so we can skip loading the function at all if we already know it's not
gonna do anything.
This is done on every startup of every single fish, and it saves ~0.2ms.
I sometimes find myself doing something like this:
- Look for a commandline that includes "echo" (as an example)
- Type echo, press up a few times
- I can't immediately find what I'm looking for
- Press ctrl-r to open up the history pager
- It uses the current commandline as the search string,
so now I'm looking for "echo foobar"
This makes it so if the search string already is in use, that's what
the history-pager picks as the initial search string.
This was the remaining immediately actionable part of #7375.
It's not definitely the last word, but a change here would require a
bigger plan.
Fixes#7375
Apparently this is actually a point of confusion.
Unfortunately we can't use `which` here because 1. it might not be
installed, 2. it might be trash.
So we give instructions from inside fish, and explain that they
should *typically* work.
See #10002
Without this, a recipe containing a trailing backslash followed by a line not
beginning with tab (like any non-continued recipe lines would) would result in
the continuation showing up in completions.
Whenever a line ends in a backslash, consider the next line invalid as a target.
Regex explanation:
^([^#]*[^#\\])? -- optional prefix not containing comment character and not
ending in backslash
(\\\\)*\\$ -- 2n+1 backslashes at end of line (handles escaped backslashes)
This is in regards to a comment on 290d07a833, which resulted in 46c967903d.
Those commits handled the default path when it is unset on startup.
DEFAULT_PATH is used when PATH is unset at runtime as far as I can tell.
As far as I can tell this has had the non-overidding ordering behavior since inception
(or at least 17 years ago ea998b03f2).
We don't change anything about compilation-setup, we just immediately jump to
Rust, making the eventual final swap to a Rust entrypoint very easy.
There are some string-usage and format-string differences that are generally
quite messy.
In CMake this used a `version` file in the CARGO_MANIFEST_DIR, but
relying on that is problematic due to change-detection, as if we add
`cargo-rerun-if-changed:version`, cargo would rerun every time if the file does
not exist, since cargo would expect the file to be generated by the
build-script. We could generate it, but that relies on the output of `git
describe`, whose dependencies we can only limit to anything in the
`.git`-folder, again causing unnecessary build-script runs.
Instead, this reads the `FISH_BUILD_VERSION`-env-variable at compile time
instead of the `version`-file, and falls back to calling git-describe through
the `git_version`-proc-macro. We thus do not need to deal with extraneous
build-script running.
- `libc::setlinebuf` is not available through Rust's libc it appears.
- autocxx fails to generate bindings using `*mut FILE`, instead go through
`void*`
- rust_main needs `parse_util_detect_errors_in_ast`, which is _partially_
ported, instead add FFI interop for C++.
- We need to set the filename if we are sourcing a file
C++ main used getopt (no w!), which appears to internally print
error-messages. The Rust version will use `wgetopter_t`, and therefore needs to
print this itself.
- It is currently never set, but will be set once `main` is ported
- `should_suppress_stderr_for_tests` used to be PROGRAM_NAME !=
TESTS_PROGRAM_NAME, but the equivalent C++ code was
`!std::wcscmp(program_name, TESTS_PROGRAM_NAME)`, and `wcsmp` returns
zero if they are equal, thus is equivalent to `==` in Rust
- https://github.com/ATiltedTree/setup-rust has not been committed to since May
2022, I am uncertain about how widely used it is.
- It appears to have a bug with restoring its internal cache whenever there
comes a new stable version (immediate guess would be the cache-key does not
resolve `stable` to a specific version, which somehow breaks rustup, but I have not investigated)
- https://github.com/dtolnay/rust-toolchain is a more sensible take of https://github.com/actions-rs/toolchain,
where the original repo appears to be unmaintained.
It is implemented in one file of yaml/bash
https://github.com/dtolnay/rust-toolchain/blob/master/action.yml, we could
easily fork it if it becomes unmainted, unlike the other actions which uses
unnecessary javascript
* Some temporary change until compose - commit
* First draft
* Fix an error that prints double completion
* Fix completion errors. Add rpm-ostree alias.
Fix cimpletion where it trigger by multiple commands.
Add update and remove, which are aliases for upgrade and uninstall.
* Remove -r when it is unnecessary
Some command need path completion for arguments no matter what,
which makes -r flag useless
* Remove -x for compose image
-x does not block the path anyway
* Add missing short otpion in compose image
Revert the last change to block -l completion
* Fix description
Fix multiple description.
This used to be assigned to the job, but that was removed in
f30ce21aaa.
Since then this was vestigial. It could have technically errored out,
but we should be catching that where we use the actual modes, not here.
Similar to `time`, except that one is more common as a command.
Note that this will also allow `builtin and`, which is somewhat
useless, but then it is also useless outside of a pipeline.
Addition to #9985
This used to print all codepoints outside of the ASCII range (i.e.
above 0x80) in \uXXXX or \UYYYYYYYY notation.
That's quite awkward, considering that this is about keys that are
being pressed, and many keyboards have actual symbols for these on
them - I have an "ö" key, so I would like to use `bind ö` and not
`bind \u00F6`. So we go by iswgraph.
On a slightly different note, `\e` was written as `\c[ (or \e)`. I do
not believe anyone really uses `\c[` (the `[` would need to
be escaped!), and it's confusing and unnecessary to even mention that.
This allows e.g. `foo | command time`, while still rejecting `foo | time`.
(this should really be done in the ast itself, but tbh most of
parse_util kinda should)
Fixes#9985
This cleans up the CSS, reduces the number of different colors and special settings we use.
It increases contrast so we now pass WCAG AAA (according to chromium), and switches to css variables for colors to make dark mode simpler to implement.
- "1.6.0" now supports formatting let-else statements which we use liberally,
and appears to have some fixes in regards to long-indented-lines with macros
like `wgettext_ft!`
- This commit updates the formatting so that devs with the latest stable don't
see random format-fixes upon running `cargo fmt`
During development, for a while `path change-extension` would return 0
when it found an extension to change.
This was later changed to returning 0 if there are any path arguments.
Neither of which is *super* useful, I admit, but we've picked one and
the docs shouldn't contradict it.
Unfortunately, /var/lib/dpkg/status on recent-ish Debian versions at
least only contains the *installed* packages, rendering this solution
broken.
What we do instead is:
1. Remove a useless newline from each package, so our limit would now
let more full package data sets through
2. Increase the limit by 5x
This yields a completion that runs in ~800ms instead of ~700ms on a
raspberry pi, but gives ~10x the candidates, compared to the old
apt-cache version.
This partially reverts 96deaae7d8
This was accidentally changed in 3.2.0, when type was made a builtin.
Since it's been 4 releases and nobody has noticed, rather than
breaking things again let's leave it as it is, especially because the
option is named "--no-functions", not "--no-functions-or-builtins".
Note: This *requires* an argument after the format string:
```rust
FLOGF!(debug, "foo");
```
won't compile. I think that's okay, because in that case you should
just use FLOG.
An alternative is to make it skip the sprintf.
"FLOGF!" is supposed to treat its first argument as a format
string (but doesn't because that part isn't implemented currently).
That means running something like
```rust
FLOGF!(term_support, "curses var", var_name, "=", value);
```
That would rightly just print "curses var", ignoring the other
arguments.
By contrast, FLOG! is the literal "just join these as a string"
version.
- Make CMake use the correct target-path
- Make build.rs use the correct target dir
Workspaces place it in the project root by default, the alternative to making
this change is to add a `.cargo/config.toml` file with
```toml
[build]
target-dir = "fish-rust/target"
```
Which I think is unnecessary, as we likely want to use the new location anyways.
- This allows running `cargo fmt/clippy/test/etc` from root
- Ideally the root should be the fish-rust package instead of being virtual, but
that requires changed to CMake/Corrosion. This change should instead be
completely compatible with our existing setup.
- This also means we will only have on `Cargo.lock` for all current and future
crates.
This was "function", needs to be "function*s*".
It was only an issue in the option parsing because we set cmd there
again instead of passing it. Maybe these should just be file-level constants?
This is an alternative to the very common pattern of
```rust
streams.err.append(output);
streams.err.append1('\n');
```
Which has negative performance implications, see https://github.com/fish-shell/fish-shell/pull/9229
It takes `Into<WString>` to hopefully avoid allocating anew when the argument is
a WString with leftover capacity
This used expect_re with a regex ending in `.*`, followed by an
`expect_prompt`.
This meant that, depending on the timing, the regex could swallow the
prompt marker, which caused extremely confusing output like
>Testing file pexpects/generic.py:Failed to match pattern: prompt 14
> ...
> OUTPUT +1.33 ms (Line 70): \rprompt 13>functions\r\nN_, abbr,
> alias, bg, cd, [SNIP], up-or-search, vared, wait\r\n⏎
> \r⏎ \r\rprompt 14>
Yeah - it shows that "prompt 14" was in the output and it can't find
"prompt 14".
I could reproduce the failure locally when running the tests
repeatedly. I got one after 17 attempts and so far haven't been able
to reproduce it with this change applied.
This removes some spurious unsafe and some imports.
Note: We don't use it in `test`, because that can be asked to check
arbitrary file descriptors, while this only checks stdout specifically.
Turns out doing `==` on Enums with values will do a deep comparison,
including the values.
So EventDescription::Signal(SIGTERM) is !=
EventDescription::Signal(SIGWINCH).
That's not what we want here, so this does a bit of a roundabout thing.
* Simplify and fix `__fish_is_zfs_feature_enabled`
Previously `__fish_is_zfs_feature_enabled` was doing
`<whitespace>$queried_feature<whitespace>` pattern matching which
was skipping the state part expected in the follow-up checking code.
Passing the dataset/snapshot in a `target` argument is pointless. As
none of the existing code attempts to do this plus it is also a
private function (`__` prefix), rename of the argument and removal
of extra text replacement should not be considered a breaking change.
* Changed the `&& \` into `|| return`
* Run `fish_indent`
The `impl<T> Hash for &T` hashes the string itself[^1].
It is unclear if that is actually faster than just calling `keyfunc` multiple times (they should all be linear).
For context, Rust by default uses SipHash 1-3 db1b1919ba
An alternative would be to store it as raw pointers aka `*const T`, which have a cheaper hash impl.
That has a more complicated implementation + removes lifetimes.
This commit rather removes the premature optimization.
[^1]: Source: https://doc.rust-lang.org/std/ptr/fn.hash.html
- The Err-variants will be used by e.g. wildcard, so might as well change it
now.
- `create_directory` should now not infinitely loop until it fails with an
error message that isn't `EAGAIN`
These are both clearly behind early returns, there is no need to check it again.
This isn't a case where we're doing logic gymnastics to see that it
can't be run without no_exec() being handled, this is
```c++
if (no_exec()) return;
// ..
// ..
// ..
if (no_exec()) foo;
```
We have already run waccess with X_OK. We already *know* the file is
executable.
There is no reason to check again.
Restores some of the speedup from the fast_waccess hack that was
removed to fix#9699.
Corrosion does not forward the `CMAKE_OSX_DEPLOYMENT_TARGET` to cargo.
As a result we end up building the Rust-libraries for the default target,
which is usually current macOS-version. But CMake links using the set
target, so we link for a version older than we built for.
To properly build for older macOS versions, the env variable
`MACOSX_DEPLOYMENT_TARGET` should instead be set, which cargo,
cmake and friends read by default. This can then lead to
warnings if you have libraries (e.g. PCRE2) built for newer
than our minimum version. Therefore we do not set a min-target
by default.
Padding with an unprintable character is now disallowed, like it was for other
zero-length characters.
`string shorten` now ignores escape sequences and non-printable characters
when calculating the visible width of the ellipsis used (except for `\b`,
which is treated as a width of -1).
Previously `fish_wcswidth` returned a length of -1 when the ellipsis-str
contained any non-printable character, causing the command to poentially
print a larger width than expected.
This also fixes an integer overflows in `string shorten`'s
`max` and `max2`, when the cumulative sum of character widths turned negative
(e.g. with any non-printable characters, or `\b` after the changes above).
The overflow potentially caused strings containing non-printable characters
to be truncated.
This adds test that verify the fixed behaviour.
- Add test to verify piped string replace exit code
Ensure fields parsing error messages are the same.
Note: C++ relied upon the value of the parsed value even when `errno` was set,
that is defined behaviour we should not rely on, and cannot easilt be replicated from Rust.
Therefore the Rust version will change the following error behaviour from:
```shell
> string split --fields=a "" abc
string split: Invalid fields value 'a'
> string split --fields=1a "" abc
string split: 1a: invalid integer
```
To:
```shell
> string split --fields=a "" abc
string split: a: invalid integer
> string split --fields=1a "" abc
string split: 1a: invalid integer
```
* feat(completions): support Krita
* feat(completions): support summary options for Krita
* feat(completions): support remaining options for Krita
* feat(completions): remove debug instructions
* feat(completions): hide completions for sizes for Krita
* feat(completions): fix Krita
* feat(changelog): mention new completion
* fix(completions): refactor Krita
* fix(completion): reformat
* feat(completion): dynamically generate workspace list
* fix(completion): refactor
* fix(completion): krita
* fix(completions): use printf
This gives us the biggest chance that these are *visible* in the
terminal, which allows people to choose something nicer.
It changes two colors - the autosuggestion and the pager
description (i.e. the completion descriptions in the pager).
In a bunch of terminals I've tested these are pretty similar - for the
most part brblack for the suggestions is a bit brighter than 555, and
yellow for the descriptions is less blue
than the original.
We could also make the descriptions brblack, but that's for later.
Technically we are a bit naughty in having a few foreground and
background pairs that might not be visible,
but there's nothing we can do if someone makes white invisible on brblack.
Fixes#9913Fixes#3443
Empty hash maps muck around with TLS. Per code review, use a boxed slice
of a tuple instead. This has the nice benefit of printing inherited vars
in sorted order.
This adopts the new function store, replacing the C++ version.
It also reimplements builtin_function in Rust, as these was too coupled to
the function store to handle in a separate commit.
This didn't work for something like `pactl set-card-profile foo
<TAB>`,
because it didn't allow for the card name, as it would just print the
index again and again.
We could end up overflowing if we print out something that's a multiple of the
chunk size, which would then finish printing in the chunk-printing, but not
break out early.
DirIter had a serious bug where it would crash on an invalid path. Make it more
robust and rationalize its error handling. Move it into its own module and add
tests.
Prior to this change, we had a silly wrapper type EventDescription which wrapped
EventType, which actually described the event.
Remove this wrapper and rename EventType to EventDescription (since it describes
more than just the type of event).
The RETURN_IN_ORDER argparse mode (enabled via leading '-') causes non-options
(i.e. positionals) to be returned intermixed with options in the original order,
instead of being permuted to the end. Such positionals are identified via the
option sentinel of char code 1. Use a real named constant for this return,
rather than weird stuff like '\u{1}'
This had a weird, unnecessary and terrible backwards-incompatibility
in how you get the completions out.
I do not like it but I am in a good enough mood to work around it.
See #9878.
This confirmed that a file existed via access(file, F_OK).
But we already *know* that it does because this is the expansion for
the "trailing slash" - by definition all wildcard components up to
here have already been checked.
And it's not checking for directoryness either because it does F_OK.
This will remove one `access()` per result, which will cut the number
of syscalls needed for a glob that ends in a "/" in half.
This brings us on-par with e.g. `ls` (which uses statx while we use
newfstatat, but that should have about the same results)
Fixes#9891.
Remove the following C++ functions/methods, which have no callers:
fallback.cpp:
- wcstod_l
proc.cpp:
- job_t::get_processes
wutil.cpp:
- fish_wcstoll
- fish_wcstoull
Also drop unused configure checks/defines:
- HAVE_WCSTOD_L
- HAVE_USELOCALE
Remove the following C++ functions/methods, which have all been ported to Rust and no longer have any callers in C++:
common.cpp:
- assert_is_locked/ASSERT_IS_LOCKED
path.cpp:
- path_make_canonical
wutil.cpp:
- wreadlink
- fish_iswgraph
- file_id_t::older_than
It's super easy to get a lot of these and they'll otherwise slow down
the completions a lot.
This makes `git add <TAB>` ~5-6x faster with about 4000 untracked
files (a copy of the fish build directory). It goes from 1.5 seconds to
250ms.
This is just for the git >= 2.11 path, but the other one would require
more checking and since git 2.11 is almost 7 years old now that's not
worth it.
This makes `fish -c begin` fail with a status of 127 - it already
printed a syntax error so that was weird. (127 was the status for
syntax errors when piping to fish, so we stay consistent with that)
We allow multiple `-c` commands, and this will return the regular
status if the last `-c` succeeded.
This is fundamentally an extremely weird situation but this is the
simple targeted fix - we did nothing, unsuccessfully, so we should
fail.
Things to consider in future:
1. Return something better than 127 - that's the status for "unknown
command"!
2. Fail after a `-c` failed, potentially even checking all of them
before executing the first?
Fixes#9888
This also allows scoped feature tests that makes testing feature flags thread-safe.
As in you can guarantee that the test actually has the correct feature flag
value, regardless of which other tests are running in parallell.
This also cleans up and removes unnecessary usage of FFI-oriented `feature_metadata_t`,
which is only used from Rust code after `builtins/status` was ported.
This ran two `test`s a `count` and one `echo`, which is a bit wasteful.
So instead, for the common case where you pass one argument, this will
run one `set -q`.
This can save off ~160 microseconds for each ordinary `cd`, which
speeds it up by a factor of ~2 (so 1000 runs of cd might take 260ms
instead of 550ms).
Ideally the cd function would just be incorporated into the builtin,
but that's a bigger change.
Note this is slightly incomplete - the FD is not moved into the parser, and so
will be freed at the end of each directory change. The FD saved in the parser is
never actually used in existing code, so this doesn't break anything, but will
need to be corrected once the parser is ported.
This shaves about 9 seconds off of the runtime, and makes the test
deterministic.
We do not touch the test_convert test because there is a known failure and we
need to track it down before making it deterministic.
Get some stuff out of the common module, which is growing large.
Also migrate the tests into "native" Rust tests so they will run in parallel.
We have to use an explicit setlocale() call to get a multibyte locale, for the
"crazy" tests.
Prior to this commit, FLOG used the ffi bridge to get the output fd. Invert
this: have fish set the output fd within main. This allows FLOG to be used in
pure Rust tests.
After accidentally running a command that includes a pasted password, I want
to delete command from history. Today we need to recall or type (part of)
that command and type "history delete". Let's maybe add a shortcut to do
this from the history pager.
The current shortcut is Shift+Delete. I don't think that's very discoverable,
maybe we should use Delete instead (but only if the cursor is at the end of
the commandline, otherwise delete a char).
Closes#9454
The tentative binding for the upcoming "history-pager-delete" is
bind -k sdc history-pager-delete or backward-delete-char
When Shift+Delete is pressed while the history pager is active,
"history-pager-delete" succeeds. In this case, the "or" needs to kick the
"backward-delete-char" out of the input queue.
After doing so, it continues reading, but interprets the input as
single-char binding. This breaks when the next key emits a multi-char sequence,
like the arrow keys.
Fix this by reading a full sequence, which means we need to run "read_char()"
instead of "read_ch()" (confusing, right?).
I'm still working on writing a test. Somehow this only reproduces in the
history pager where Shift+Delete followed by down arrow emits "[B" (since
we swallowed the leading escape char). Confusingly, it doesn't do that in
the commandline or the completion search field.
Two small fixes:
1. ParsedSourceRef, if present, should not be None; express that in the type.
2. ParsedSourceRef is intended to be shareable across threads; make it so.
Use as_wstr() instead of from_ffi() in a few places to avoid an allocation,
and make job_control_t work in &wstr instead of &str to reduce complexity at
the call sites.
- Using an option makes it much clearer that the check for empty args is
redundant.
- Also prefer implementing TryFrom only for &str, to not hide the string
conversion and allocation happening.
This was present in the C++ version for command, though never for type.
Checking over all elements of PATH can be slow on some platforms eg
WSL2, so only do that when used with `--all`.
Based on discussion in
https://github.com/fish-shell/fish-shell/pull/9856
This restores the status quo where builtins are like external commands
in that they can't see anything after a 0x00, because that's the c-style
string terminator.
* Make NULs work for builtins
This switches from passing a c-string to output_stream_t::append to
passing a proper string.
That means a builtin that prints a NUL no longer crashes with "thread '' panicked
at 'String contained intermediate NUL character: ".
Instead, it will actually handle the NUL, even as an argument.
That means something like
`echo foo\x00bar` will now actually print a NUL instead of truncating
after the `foo` because we passed c-strings around everywhere.
The former is *necessary* for e.g. `string`, the latter is a change
that on the whole makes dealing with NULs easier, but it is a
behavioral change.
To restore the c-string behavior we would have to truncate arguments
at NUL.
See #9739.
* Use AsRef instead of trait bound
* docs: Add "Writing your own prompt" doc
* Remove a space from the "output"
* some teensy adjustments
* Address feedback
* envvar one more PWD
* More html warning
Prior to this change, parser_t exposed an environment_t, and Rust had to go
through that. But because we have implemented Environment in Rust, it is
better to just expose the native Environment from parser_t. Make that
change and update call sites.
The writembs macro was ported from C++, which attempted to detect when a NULL
termcap was used. However we have never gotten a bug report from this. Bravely
remove it.
The outputter code has a lot of checks that string capabilities are non-empty;
just enforce that at the curses layer so we can remove those checks.
Also remove some types and traits, replacing them with simple functions.
Per code review, we think that tparm does nothing when there are no parameters,
and it is safe to remove it, even though this is a break from C++. This
simplifies some code.
This commit introduces a fishconfig_print.css that contains special CSS styles that only apply when printing the fishconfig page. This is especially useful when the user wants to print out the key bindings.
This makes some simplifications to scoped_push and ScopeGuard:
1. ScopeGuard no longer uses ManuallyDrop; the memory management is now
trivial and no longer requires `unsafe`.
2. The functions `cancel` and `rollback` have been removed, as
these were unused. They can be added back later if needed.
3. `scoped_push` has been simplified in both signature and implementation.
4. `Projection` is no longer required and has been removed.
Also add some tests.
This should include the important info from the wiki.
We should try to find some recommendation for tools, or even an online
platform where people can submit translations without having to go
through all this setup
Mostly this tries to give logical header levels, so the "Fish Style
Guide" section is in the "Code Style" section
Also remove a few unimportant C++-centric sections - I'm not sure iwyu
even runs anymore, and cppcheck isn't great in my experience.
We can't just call the Rust version of `fish_setlocale()` without also either
calling the C++ version of `fish_setlocale()` or removing all `src/complete.cpp`
variables that are initialized and aliasing them to their new rust counterparts.
Since we're not interested in keeping the C++ code around, just call the C++
version of the function via ffi until we don't have *any* C++ code referencing
`src/common.h` at all.
Note that *not* doing this and then calling the rust version of
`fish_setlocale()` instead of the C++ version will cause errant behavior and
random segfaults as the C++ code will try to read and use uninitialized values
(including uninitialized pointers) that have only had their rust counterparts
init.
This is not yet used but will take eventually take the place of all (n)curses
access. The curses C library does a lot of header file magic with macro voodoo
to make it easier to perform certain tasks (such as access or override string
capabilities) but this functionality isn't actually directly exposed by the
library's ABI.
The rust wrapper eschews all of that for a more straight-forward implementation,
directly wrapping only the basic curses library calls that are required to
perform the tasks we care about. This should let us avoid the subtle
cross-platform differences between the various curses implementations that
plagued the previous C++ implementation.
All functionality in this module that requires an initialized curses TERMINAL
pointer (`cur_term`, traditionally) has been subsumed by the `Term` instance,
which once initialized with `curses::setup()` can be obtained at any time with
`curses::Term()` (which returns an Option that evaluates to `None` if `cur_term`
hasn't yet been initialized).
Either add rust wrappers for C++ functions called via ffi or port some pure code
from C++ to rust to provide support for the upcoming `env_dispatch` rewrite.
The global variables are moved (not copied) from C++ to rust and exported as
extern C integers. On the rust side they are accessed only with atomic semantics
but regular int access is preserved from the C++ side (until that code is also
ported).
It's not clear whether or not `system_wcwidth()` was picked solely because of
the namespace conflict (which is easily remedied) but using the most obvious
name for this function should be the way to go.
We already have our own overload of `wcwidth()` (`fish_wcwidth()`) so it should
be more obvious which is the bare system call and which isn't.
(I do want to move this w/ some of the other standalone extern C wrappers to the
unix module later.)
Pull in the correct descriptions merged from across the various C++ header and
source files and get rid of the getter function that's only used in one place
but causes us to split the documentation for FISH_EMOJI_WIDTH across multiple
declarations.
This can be used for functions that accept non-Unicode content (i.e. &CStr or
CString) but are often used in our code base with a UTF-8 or UTF-32 string
on-hand.
When such a function is passed a CString, it's passed through as-is and
allocation-free. But when, as is often the case, we have a static string we can
now pass it in directly with all the nice ergonomics thereof instead of having
to manually create and unwrap a CString at the call location.
There's an upstream request to add this functionality to the standard library:
https://github.com/rust-lang/rust/issues/71448
This is more complicated than it needs to be thanks to the presence of CMake and
the C++ ffi in the picture. rsconf can correctly detect the required libraries
and instruct rustc to link against them, but since we generate a static rust
library and have CMake link it against the C++ binaries, we are still at the
mercy of CMake picking up the symbols we want.
Unfortunately, we could detect the gettext symbols but discover at runtime that
they weren't linked in because CMake was compiled with `-DWITH_GETTEXT=0` or
similar (as the macOS CI runner does). This means we also need to pass state
between CMake and our build script to communicate which CMake options were
enabled.
Delegate the `view` and `view_mut` to the newly added `Projection<T>`, which
makes everything oh so much clearer and cleaner. Add comments to clarify what is
happening.
This can be used when you primarily want to return a reference but in order for
that reference to live long enough it must be returned with an object.
i.e. given `Mutex<Foo { bar }>` you want a function to lock the mutex and return
a reference to `bar` but you can't return that reference since it has a lifetime
dependency on `MutexGuard` (which only derefs to all of `Foo` and not just
`bar`). You can return a `Projection` owning the `MutexGuard<Foo>` and set it up
to deref to `&bar`.
This was always extremely weasel-wordy and I have no idea which one
here is a good choice.
OMF is basically inactive at this point, so we might be doing people a
disservice by linking to it.
This wasn't providing a lot of value, and the license compatibility is iffy.
There's a bit of weirdness in that this now uses a `Box<dyn Error>`,
but since currently nothing actually errors out let's punt that for
later.
This is a terrible way of going about things,
and means we're currently broken on any unix that isn't specifically listed.
But at least it'll build and allow us to keep the FreeBSD CI running.
Historically fish has used the functions `fish_wcstol`, `fish_wcstoi`, and
`fish_wcstoul` (and some long long variants) for most integer conversions.
These have semantics that are deliberately different from the libc
functions, such as consuming trailing whitespace, and disallowing `-` in
unsigned versions.
fish has started to drift away from these semantics; some divergence from
C++ has crept in.
Rename the existing `fish_wcs*` functions in Rust to remove the fish
prefix, to express that they attempt to mirror libc semantics; then
introduce `fish_` wrappers which are ported from C++. Also fix some
miscellaneous bugs which have crept in, such as missing range checks.
This also skips the 192 git- and 64 npm- pages that
1. have better completions already (for the most part)
2. don't have the same name as a command typically in $PATH
In doing so it reduces the runtime on my system from 9s to 7s. Granted
I have all of these, so that's the best case.
This implements the primary environment stack, and other environments such
as the null and snapshot environments, in Rust. These are used to implement
the push and pop from block scoped commands such as `for` and `begin`, and
also function calls.
owning_null_terminated_array is used for environment variables, where we need to
provide envp for child processes. This switches the implementation from C++ to
Rust.
We retain the C++ owning_null_terminated_array_t; it simply wraps the Rust
version now.
The `u64::from(buf.f_flag)` was needed in two places. The existing handled macOS
which always has a 32-bit statfs::f_flag, but statvfs::f_flag is an `unsigned
long` which means it needs to be coerced to 64-bits on 32-bit targets.
It completes identical to `fg` and `bg` w/ this change. I'm not aware of any
reason why it shouldn't, but feel free to enlighten me if I've missed something.
[ci skip]
There's no reason to inject prefix into our newly allocated str after storing
pattern in there. Just allocate with the needed capacity up front and then
insert in the correct order.
There's no reason to inject prefix into our newly allocated str after storing
pattern in there. Just allocate with the needed capacity up front and then
insert in the correct order.
Suppress TLS variable leaks caused by outstanding background threads by
suppressing the ASAN interposer functions. This is possible because because
we're now using use_tls=1.
-----------------------
Direct leak of 64 byte(s) in 2 object(s) allocated from:
#0 0x5627a1f0cc86 in __interceptor_realloc (/home/runner/work/fish-shell/fish-shell/build/fish_tests+0xb9fc86) (BuildId: da87d16730727369ad5fa46052d10337d6941fa9)
#1 0x7f04d8800f79 in pthread_getattr_np (/lib/x86_64-linux-gnu/libc.so.6+0x95f79) (BuildId: 69389d485a9793dbe873f0ea2c93e02efaa9aa3d)
#2 0x5627a1f2f664 in __sanitizer::GetThreadStackTopAndBottom(bool, unsigned long*, unsigned long*) (/home/runner/work/fish-shell/fish-shell/build/fish_tests+0xbc2664) (BuildId: da87d16730727369ad5fa46052d10337d6941fa9)
#3 0x5627a1f2fb83 in __sanitizer::GetThreadStackAndTls(bool, unsigned long*, unsigned long*, unsigned long*, unsigned long*) (/home/runner/work/fish-shell/fish-shell/build/fish_tests+0xbc2b83) (BuildId: da87d16730727369ad5fa46052d10337d6941fa9)
#4 0x5627a1f19a0d in __asan::AsanThread::SetThreadStackAndTls(__asan::AsanThread::InitOptions const*) (/home/runner/work/fish-shell/fish-shell/build/fish_tests+0xbaca0d) (BuildId: da87d16730727369ad5fa46052d10337d6941fa9)
#5 0x5627a1f19615 in __asan::AsanThread::Init(__asan::AsanThread::InitOptions const*) (/home/runner/work/fish-shell/fish-shell/build/fish_tests+0xbac615) (BuildId: da87d16730727369ad5fa46052d10337d6941fa9)
#6 0x5627a1f19b01 in __asan::AsanThread::ThreadStart(unsigned long long) (/home/runner/work/fish-shell/fish-shell/build/fish_tests+0xbacb01) (BuildId: da87d16730727369ad5fa46052d10337d6941fa9)
#7 0x7f04d87ffb42 (/lib/x86_64-linux-gnu/libc.so.6+0x94b42) (BuildId: 69389d485a9793dbe873f0ea2c93e02efaa9aa3d)
#8 0x7f04d88919ff (/lib/x86_64-linux-gnu/libc.so.6+0x1269ff) (BuildId: 69389d485a9793dbe873f0ea2c93e02efaa9aa3d)
init_curses() is/can be called more than once, in which case the previous
ncurses terminal state is leaked and a new one is allocated.
`del_curterm(cur_term)` is supposed to be called prior to calling `setupterm()`
if `setupterm()` is being used to reinit the default `TERMINAL *cur_term`.
The new asan exit handlers are called to get proper ASAN leak reports (as
calling _exit(0) skips the LSAN reporting stage and exits with success every
time).
They are no-ops when not compiled for ASAN.
Set use_tls back to its default of 1.
This is required to work around an ASAN/LSAN virtualization bug but seems to be
behind the random __cxa_thread_atexit_impl() leaks?
This ports some signal setup and handling bits to Rust.
The signal handling machinery requires walking over the list of known signals;
that's not supported by the Signal type. Rather than duplicate the list of
signals yet again, switch back to a table, as we had in C++.
This also adds two further pieces which were neglected by the Signal struct:
1. Localize signal descriptions
2. Support for integers as the signal name
This allows the rust code to free up C++ resources allocated for a callback even
when the callback isn't executed (as opposed to requiring the callback to run
and at the end of the callback cleaning up all allocated resources).
Also add type-erased destructor registration to callback_t. This allows for
freeing variables allocated by the callback for debounce_t's
perform_with_callback() that don't end up having their completion called due to
a timeout.
Largely routine but for the trampolines in iothread.h and iothread.cpp which
were a real PITA to get correct w/ all their variants.
Integration is complete with all old code ripped out and the tests using the
rust version of the code.
Like the WSL check, this was incorrectly assuming WSL implies
cfg(windows) when it's actually picked up as Linux.
Also, improve over the C++ code by not relying on the build-time WSL
status to determine if we are running on WSL at runtime since it's often
the case that the fish binaries are built on a non-WSL host (for
packaging) then executed on a WSL only at runtime.
(But it's ok to assume if fish has been built for Windows or not Linux
that it will either be run or not run on top of a Win32 character device
system.)
Also, port of the comment and relevant WSL and fish issue links over
from the CPP codebase for posterity.
* Since we already have an allocation of length wstr.len(), it's
probably better to allocate the result (which is strictly less than or
equal to the input length) up-front rather than risk thrashing the Vec
allocation,
* There's no need to compare c2 against '\0' since that will just cause
to_digit(16) to return None anyway,
* Our convert_hex() specialization of to_digit(16) that only checks
capital letters A-F without also checking lowercase a-f isn't
significantly faster than just use to_digit(16), and we already assert
that the input *wasn't* a lowercase a-f before making the call, so
there's no point in using a special function to handle that.
Prior to this change, wstr::split had two weird behaviors:
1. Splitting an empty string would yield nothing, rather than an empty
string.
2. Splitting a string with the separator character as last character
would not yield an empty string.
For example L!("x:y:").split(':') would return ["x", "y"] instead of
what it does in C++, which is ["x", "y", ""].
Fix these.
This reverts commit 76dc849fca.
The warning added in that commit is incorrect. The functions
unescape_string_url and unescape_string_var will not panic, because
char_at() return 0 if the index is equal to its length.
This reverts commit f9c92753c4.
This commit attempted to replace exit_without_destructors() with
std::process::exit; however this is wrong for two reasons:
1. std::process::exit() runs Rust runtime cleanup stuff we don't want
2. std::process::exit() invokes destructors, meaning atexit handlers,
which we don't want.
The type system no longer guarantees that the input string is nul-terminated,
meaning accessing beyond the range-checked `i` a char-at-a-time is no longer
safe. (In C++, we would either be using a plain C string which is always
nul-terminated or we would be using (w)string::cstr() which similarly grants
access to its nul-terminated buffer.)
Aside from that, there's no need to explicitly check `if c2 == '\0'` because
'\0' is not a valid hex digit so the `?` tacked on to `convert_hex_digit(c2)?`
will abort and return `None` anyway.
convert_hex_digit() is not appreciably faster than char::to_digit(16) and makes
the code less maintainable since it encodes certain assumptions; since it's also
not used consistently just drop it in favor of the std fn.
Since the output string (per the decode logic) is always shorter than or equal
to the input string, just reserve the input string size upfront to prevent vec
reallocations.
* Add rpm-ostree completion
Add basic command completion for rpm-ostree. This should improve the
user experience for fish users using rpm-ostree.
* Shorten rpm-ostree descriptions
---------
Co-authored-by: Mahmoud Al-Qudsi <mqudsi@neosmart.net>
* completions: updated jq completions
* completions: added completions for gojq
* Shorten jq completion descriptions
* Update gojq.fish
Capitalize first letter of descriptions to match other completions.
---------
Co-authored-by: Mahmoud Al-Qudsi <mqudsi@neosmart.net>
Somewhat counter-intuitively, this code is active when compiling under *Linux*
and is always false when compiling under Windows. The logic was incorrectly
reversed before (it's easier to reason about when you realize that fish doesn't
even compile under Windows because it uses tons of libc functions).
As the code was actually never compiled, it wasn't actually tested for validity
either and there were some issues that prevented it from compiling that have
since been fixed. The logic has also been adjusted a bit to make it possible to
use the rust-native int parsing instead of `libc::strtod()`.
The code has been changed to use `once_cell::race::OnceBool` instead of
`once_cell::sync::Lazy<T>` which imposes a greater runtime burden with locking
and other overhead. We don't care if the code runs more than once on init (if
calls were to race, though they probably don't) - just that the code isn't
subsequently executed on each call. The `once_cell::race` module is a better fit
here, though it doesn't expose the ergonomic `Lazy<T>` façade around its types.
is_main_thread() and co were previously ported to threads.rs, so remove the
duplicate code and move everything else related to threads there as well. No
need for common.rs to be as long as our old common.cpp!
I left #[deprecated] stubs in common.rs to help redirect anyone porting code
over that we can remove after the port has finished.
Additionally, the fork guards had previously been left as a todo!() item but I
ported that over. They're all called from the now-central threads::init()
function so there isn't a need to call each individual thread-management-fn
manually.
The decision was made a while back to try and embrace/use the native rust thread
functionality and utilities so the manual thread management code has been ripped
out and was replaced with code that marshals the native rust values instead. The
values won't line up with what the C++ code sees, but it never lined up anyway
since each was using a separate counter to keep track of the values.
There are many places where we want to treat a missing variable the same as
a variable with an empty value.
In C++ we handle this by branching on maybe_t<env_var_t>::missing_or_empty().
If it returns false, we go on to access maybe_t<env_var_t>::value() aka
operator*.
In Rust, Environment::get() will return an Option<EnvVar>.
We could define a MissingOrEmpty trait and implement it for Option<EnvVar>.
However that will still leave us with ugly calls to Option::unwrap()
(by convention Rust does use shorthands like *).
Let's add a variable getter that returns none for empty variables.
This isn't the same as "join"/"join0", where one is just a special
case of the other.
These are two different, if basically opposite commands.
But more importantly this was a huge mess and the formatting was broken.
Except for the indent visitor bits.
Tests for parse_util_detect_errors* are not ported yet because they depend
on expand.h (and operation_context.h which depends on env.h).
This caused math to assert out because it never wrote into the buffer.
Now, presumably it wrote somewhere but I don't know where, so fixing
this seems like a good idea.
Fixes#9735.
The translation is fairly direct though it adds some duplication, for example
there are multiple "match" statements that mimic function overloading.
Rust has no overloading, and we cannot have generic methods in the Node trait
(due to a Rust limitation, the error is like "cannot be made into an object")
so we include the type name in method names.
Give clients like "indent_visitor_t" a Rust companion ("IndentVisitor")
that takes care of the AST traversal while the AST consumption remains
in C++ for now. In future, "IndentVisitor" should absorb the entirety of
"indent_visitor_t". This pattern requires that "fish_indent" be exposed
includable header to the CXX bridge.
Alternatively, we could define FFI wrappers for recursive AST traversal.
Rust requires we separate the AST visitors for "mut" and "const"
scenarios. Take this opportunity to concretize both visitors:
The only client that requires mutable access is the populator. To match the
structure of the C++ populator which makes heavy use of function overloading,
we need to add a bunch of functions to the trait. Since there is no other
mutable visit, this seems acceptable.
The "const" visitors never use "will_visit_fields_of()" or
"did_visit_fields_of()", so remove them (though this is debatable).
Like in the C++ implementation, the AST nodes themselves are largely defined
via macros. Union fields like "Statement" and "ArgumentOrRedirection"
do currently not use macros but may in future.
This commit also introduces a precedent for a type that is defined in one
CXX bridge and used in another one - "ParseErrorList". To make this work
we need to manually define "ExternType".
There is one annoyance with CXX: functions that take explicit lifetime
parameters require to be marked as unsafe. This makes little sense
because functions that return `&Foo` with implicit lifetime can be
misused the same way on the C++ side.
One notable change is that we cannot directly port "find_block_open_keyword()"
(which is used to compute an error) because it relies on the stack of visited
nodes. We cannot modify a stack of node references while we do the "mut"
walk. Happily, an idiomatic solution is easy: we can tell the AST visitor
to backtrack to the parent node and create the error there.
Since "node_t::accept_base" is no longer a template we don't need the
"node_visitation_t" trampoline anymore.
The added copying at the FFI boundary makes things slower (memcpy dominates
the profile) but it's not unusable, which is good news:
$ hyperfine ./fish.{old,new}" -c 'source ../share/completions/git.fish'"
Benchmark 1: ./fish.old -c 'source ../share/completions/git.fish'
Time (mean ± σ): 195.5 ms ± 2.9 ms [User: 190.1 ms, System: 4.4 ms]
Range (min … max): 193.2 ms … 205.1 ms 15 runs
Benchmark 2: ./fish.new -c 'source ../share/completions/git.fish'
Time (mean ± σ): 677.5 ms ± 62.0 ms [User: 665.4 ms, System: 10.0 ms]
Range (min … max): 611.7 ms … 805.5 ms 10 runs
Summary
'./fish.old -c 'source ../share/completions/git.fish'' ran
3.47 ± 0.32 times faster than './fish.new -c 'source ../share/completions/git.fish''
Leftovers:
- Enum variants are still snakecase; I didn't get around to changing this yet.
- "ast_type_to_string()" still returns a snakecase name. This could be
changed since it's not user visible.
A JobId is not supposed to convert to other types.
Since this type is defined as NonZeroU32 (which cannot be -1), we need to
add some conversion functions to match the C++ behavior.
Overall, it would have been better to keep using the C++ type.
The conversion to usize is used for array accesses, so negative values
would cause crashes either way. Let's do it earlier so we can get rid of
the suspect C-style cast.
This allows us to use the scoped push in more scenarios by appeasing the
borrow checker.
Use it in a couple of places instead of ScopeGuard. Hopefully this is makes
porting easier.
Even though we generally dont' want to use this type (because it's immutable),
it can be advantageous when working with the std::fs API. This is because
it implements "AsRef<Path>" which neither of CString and Vec<u8> do.
This is basically a subset of type, so we might as well.
To be clear this is `command -s` and friends, if you do `command grep` that's
handled as a keyword.
One issue here is that we can't get "one path or not" because I don't
know how to translate a maybe_t? Do we need to make it a shared_ptr instead?
While it is true that `git switch <remote-branch>` errors to disallow a detached
head without the `-d` option, it is valid to use any starting point (commit or
reference) in conjunction with the `-c` option. Additionally, the starting point
can occur before any option.
This enables the following completions:
* `git switch -c <local-name> <any-branch>`
* `git switch <any-branch> -c <local-name>`
* `git switch -d <any-starting-point>`
* `git switch <any-branch> -d`
The trade-off is this does allow for `git switch <remote-branch>` to be
completed with an error.
Note that this logically reverts 7e3d3cc30f.
Vi visual mode selection highlighting behaves unexpectedly when the selection
foreground and background in the highlight spec don't match. The following
unexpected behaviors are:
* The foreground color is not being applied when defined by the
`fish_color_selection` variable.
* `set_color` options (e.g., `--bold`) would not be applied under the cursor
when selection begins in the middle of the command line or when the cursor
moves forward after visually selecting text backward.
With this change, visual selection respects the foreground color and any
`set_color` options are applied consistently regardless of where visual
selection begins and the position of the cursor during selection.
Most of it is duplicated, hence untested.
Functions like mbrtowc are not exposed by the libc crate, so declare them
ourselves.
Since we don't know the definition of C macros, add two big hacks to make
this work:
1. Replace MB_LEN_MAX and mbstate_t with values (resp types) that should
be large enough for any implementation.
2. Detect the definition of MB_CUR_MAX in the build script. This requires
more changes for each new libc. We could also use this approach for 1.
Additionally, this commit brings a small behavior change to
read_unquoted_escape(): we cannot decode surrogate code points like \UDE01
into a Rust char, so use � (\UFFFD, replacement character) instead.
Previously, we added such code points to a wcstring; looks like they were
ignored when printed.
wcs2string converts a wide string to a narrow one. The result is
null-terminated and may also contain interior null-characters.
std::string allows this.
Rust's null-terminated string, CString, does not like interior null-characters.
This means we will need to use Vec<u8> or OsString for the places where we
use interior null-characters.
On the other hand, we want to use CString for places that require a
null-terminator, because other Rust types don't guarantee the null-terminator.
Turns out there is basically no overlap between the two use cases, so make
it two functions. Their equivalents in Rust will have the same name, so
we'll only need to adjust the type when porting.
Existing C++ code didn't use a function for this but simply added
ENCODE_DIRECT_BASE. In Rust that's more verbose because char won't do
arithmetics, hence the function.
We'll add a dual function for decoding, so let's rename this.
BTW we should get rid of the "wchar" naming, it's just "char" in Rust.
This prevents leaking the escape sequence by printing nonsense, and it
also allows disabling cursor setting by just setting the variable to
e.g. empty.
And if we ever added any shapes, it would allow them to be used on new
fish and ignored on old
Fixes#9698
Use a "cmake-vendored" directory if it exists, to avoid accessing the
network if it's available, and a target to create an appropriate tarball
to create that directory.
Otherwise this would complete
`git --exec-path=foo`, by running `complete -C"'' --exec-path=foo"`,
which would print "--exec-path=foo", and so it would end as
`git --exec-path=--exec-path=foo` because the "replaces token" bit was
lost.
I'm not sure how to solve it cleanly - maybe an additional option to
`complete`?
Anyway, for now this
Fixes#9538.
Prior to this change, wcstoi("0x") would fail with missing digits.
However strtoul will "backtrack" to return just the 0 and leave the x as
the remainder. Implement this behavior.
Prior to this change, wcstoi() would return an error if the requested
type were unsigned, and the input had a leading minus sign. However this
causes problems for printf, which expects strtoul behavior.
Add "modulo base" behavior which wraps the negative value to positive.
Factor this into an option; the default is False (but code which
previously used strtoull directly should set it to true).
fish_wcstoi_partial is like fish_wcstoi: it converts from a string to an
int optionally inferring the radix. fish_wcstoi_partial also returns the
number of characters consumed.
Unfortunately we cannot use wide string literals in match statements
(not sure if there's an easy fix).
Because of this, I converted the input to UTF-8 so we could use the match
statement. This conversion is confusing, let's skip it.
This can be triggered on linux with:
```js
import { spawn } from 'child_process';
const shell = spawn('/home/alfa/dev/fish-shell/build-c++/fish', []);
```
Under node 19.8.1.
*No clue* how that happens, but since this is a workaround we shall
skip it.
Everything but signal handlers has been changed to use `Signal` instead of
`c_int` or `i32` signal values.
Event handlers are using `usize` to match C++, at least for now.
Signal is a newtype around NonZeroI32. We could use NonZeroU8 since all signal
values comfortably fit, but using i32 lets us avoid a fallible attempt at
narrowing values returned from the system as integers to the narrower u8 type.
Known signals are explicitly defined as constants and can be matched against
with equality or with pattern matching in a `match` block. Unknown signal values
are passed-through without causing any issues.
We're using per-OS targeting to enable certain libc SIGXXX values - we could
change this to dynamically detecting what's available in build.rs but then it
might not match what libc exposes, still giving us build failures.
This should be used in lieu of manually targeting individual operating systems
when using features shared by all BSD families.
e.g. instead of
#[cfg(any(target_os = "freebsd", target_os = "dragonflybsd", ...))]
fn foo() { }
you would use
#[cfg(feature = "bsd")]
fn foo() { }
This feature is automatically detected at build-time (see build.rs changes) and
should *not* be enabled manually. Additionally, this feature may not be used to
conditionally require any other dependency, as that isn't supported for
auto-enabled features.
Another from the "why are we asserting instead of doing something
sensible" department.
The alternative is to make exit() and return() compute their own exit
code, but tbh I don't want any *other* builtin to hit this either?
Fixes#9659
Just address two clippy lints that are fallout from changing the signal type.
There's no longer any need to convert these (which gets rid of an unwrap).
Due to limitations imposed by the borrow checker, there are very few places
where we will be able to use the `ScopedPush` class ported over from the C++
codebase (once you capture the value w/ a `ScopedPush` you can't access the
value - or the mutable reference you used to reach it! - until the `ScopedPush`
object goes out of scope).
This alternative requires binding the previous values to a variable and manually
restoring them in the callback passed to the `ScopeGuard` constructor, but will
work with rust's borrow and `&mut` paradigm.
Currently the `autocxx` generated code does not produce any code intelligence
because `rust-analyzer` can't find the generated code since it's not in the
workspace. Here, we detect `rust-analyzer` by checking for a `RUSTC_WRAPPER`
environment variable containing `rust-analyzer` and changing (or avoid changing)
the output directory accordingly.
Closes#9654.
This was added to support signals; however we are unlikely to use this
for anything else. Remove it; just use a u64 to report signals that have
been set.
The test passes but only if executed on its own. It's not the most perfect test,
but I can basically never get `make test` to pass under WSL while that's not the
case on all my other machines.
This optimizes over both the rust rewrite and the original C++ code. The rust
rewrite saw `std::bitset` replaced with `[bool; 65]` which could result in a
lot of memory copy bandwidth each time we checked for and received no signals.
The original C++ code would iterate over all signal slots to see if any were
set. The code now returns a single u64 and only checks slots that are known to
have signals via an intelligent `Iterator` impl.
You can now use a reference to CxxWString or an allocated UniquePtr<CxxWString>
to get an &wstr temporary to use without having to allocate again (e.g. via
`from_ffi()`).
Rust has multiple sanitizers available (with llvm integration).
-Zsanitizer=address catches the most likely culprits but we may want to set up a
separate job w/ -Zsanitizer=memory to catch uninitialized reads.
It might be necessary to execute `cargo build` as `cargo build -Zbuild-std` to
get full coverage.
When we're linking against the hybrid C++ codebase, the sanitizer library is
injected into the binary by also include `-fsanitize=address` in CXXFLAGS - we
do *not* want to manually opt-into `-lasan`. We also need to manually specify
the desired target triple as a CMake variable and then explicitly pass it to all
`cargo` invocations if building with ASAN.
Corrosion has been patched to make sure it follows these rules.
The `cargo-test` target is failing to link under ASAN. For some reason it has
autocxx/ffi dependencies even though only rust-native, ffi-free code should be
tested (and one would think the situation wouldn't change depending on the
presence of the sanitizer flag). It's been disabled under ASAN for now.
wchar.rs should not import let alone reexport FFI strings.
Stop re-exporting utf32str! because we use L! instead.
In wchar_ffi.rs, stop re-exporting cxx::CxxWString because that hasn't
seen adoption.
I think we should use re-exports only for aliases like "wstr" or for aliases
into internal modules.
So I'd probably remove `pub use wchar_ffi::wcharz_t = crate::ffi::wcharz_t`
as well.
bool_assert_comparison is stupid, the reason they give is "it's shorter". Well,
`assert!(!foo)` is nowhere near as readable as `assert_eq!(foo, false)` because
of the ! noise from the macro.
Uninlined format args is a stupid lint that Rust actually walked back when they
made it an official warning because you still have to use a mix of inlined and
un-inlined format args (the latter of which won't complain) since only idents
can be inlined.
This shows some of the ugliness of the rust borrow checker when it comes to
safely implementing any sort of recursive access and the need to be overly
explicit about which types are actually used across threads and which aren't.
We're forced to use an `Arc` for `ItemMaker` (née `item_maker_t`) because
there's no other way to make it clear that its lifetime will last longer than
the FdMonitor's. But once we've created an `Arc<T>` we can't call
`Arc::get_mut()` to get an `&mut T` once we've created even a single weak
reference to the Arc (because that weak ref could be upgraded to a strong ref at
any time). This means we need to finish configuring any non-atomic properties
(such as `ItemMaker::always_exit`) before we initialize the callback (which
needs an `Arc<ItemMaker>` to do its thing).
Because rust doesn't like self-referential types and because of the fact that we
now need to create both the `ItemMaker` and the `FdMonitorItem` separately
before we set the callback (at which point it becomes impossible to get a
mutable reference to the `ItemMaker`), `ItemMaker::item` is dropped from the
struct and we instead have the "constructor" for `ItemMaker` take a reference to
an `FdMonitor` instance and directly add itself to the monitor's set, meaning we
don't need to move the item out of the `ItemMaker` in order to add it to the
`FdMonitor` set later.
We were only using their ffi implementations which are automatically
exported/public, but the actual functions we would need if we were to use
FdMonitor and co. in native rust code were either private or missing convenient
wrappers.
The existing code is kept, but a rusty version of these functions is added for
code that needs them.
These should only be temporarily used when porting 1-to-1 from C++; we should
use the std library's `read()` and `write_all()` methods instead in the future.
By extracting the equivalent of i32::cmp() into its own const function,
it becomes a lot easier to see what is happening and the logic can be
more direct.
These will be used in the parser.
Maybe this type should be a struct with boolean fields. The current way has
the upside that the usage is exactly the same as in C++.
CXX does not allow generic types like maybe_t. When porting a C++ function
that returns maybe_t to Rust, we return std::unique_ptr instead. Let's make
the transition more seamless by allowing to convert back to maybe_t implicitly.
For some reason this error is triggered by tests after the Rust port of
ast.cpp. Might want to get to the bottom of this but moving it back
to match the original C++ logic fixes it.
This is one of the few warnings we disable due to false positives. Let's also
disable it in the preprocessing steps needed for the Rust build.
Other warnings we ignore are -Wno-address -Wunused-local-typedefs and
-Wunused-macros. I didn't add them here because I don't expect that they
will be triggered by the headers we give to cxx.
After deleting a history item with
history delete --exact --case-sensitive the-item
it is still reachable by history search until the shell is restarted.
Let's fix this by saving history after each deletion. The non-exact variants
of "history delete" already do this. I think this was just an oversight
owed to the fact that hardly anyone uses "--exact" (else we would surely
have changed it to not require an explicit "--case-sensitive").
Prior to this fix, the Rust FLOG output was regressed from C++, because
it put quotes around strings. However if we used Display, we would fail
to FLOG non-display types like ThreadIDs.
There is apparently no way in Rust to write a function which formats a
value preferentially using Display, falling back to Debug.
Fix this by introducing two new traits, FloggableDisplay and
FloggableDebug. FloggableDisplay is implemented for all Display types,
and FloggableDebug can be "opted into" for any Debug type:
impl FloggableDebug for MyType {}
Both traits have a 'to_flog_str' function. FLOG brings them both into
scope, and Rust figures out which 'to_flog_str' gets called.
`xbps-query` actually parses `-Rsl` as `-Rs l`, which means that packages
without the letter "l" in their names or descriptions are not included in
`__fish_print_xbps_packages`'s output.
* wutil: Rewrite `wrealpath` in Rust
* Reduce use of FFI types in `wrealpath`
* Addressed PR comments regarding allocation
* Replace let binding assignment with regular comparison
More ugliness with types that cxx bridge can't recognize as being POD. Using
pointers to get/set `termios` values with an assert to make sure we're using
identical definitions on both sides (in cpp from the system headers and in rust
from the libc crate as exported).
I don't know why cxx bridge doesn't allow `SharedPtr<OpaqueRustType>` but we can
work around it in C++ by converting a `Box<T>` to a `shared_ptr<T>` then convert
it back when it needs to be destructed. I can't find a clean way of doing it
from the cxx bridge wrapper so for now it needs to be done manually in the C++
code.
Types/values that are drop-in ready over ffi are renamed to match the old cpp
names but for types that now differ due to ffi difficulties I've left the `_ffi`
in the function names to indicate that this isn't the "correct" way of using the
types/methods.
We want to keep the cast because tv_sec is not always 64 bits, see b5ff175b4
(Fix timer.rs cross-platform compilation, 2023-02-14).
It would be nice to avoid the clippy exemption, perhaps using something like
#[cfg(target_pointer_width = "32")]
let seconds = val.tv_sec as i64;
#[cfg(not(target_pointer_width = "32"))]
let seconds = val.tv_sec;
but I'm not sure if "target_pointer_width" is the right criteria.
The FISH_RUST_TARGET_DIR is not set for Tests.cmake, the target_dir will set to
$CARGO_MANIFEST_DIR/target. But if build.target-dir or CARGO_TARGET_DIR is set,
the real target_dir doesn't at the $CARGO_MANIFEST_DIR/target. It causes failure
in cargo test. Then, set --target-dir for cargo test.
Closes#9600
Upsizing to `usize` from `i32` doesn't work if `usize` is only 32-bits.
I changed the code to use the `FromStr` impl on `i32`, but we could have also
just used `u64` instead of `i32`.
Also, we should get in the habit of using the appropriate type aliases where
possible (`i32` should be `RawFd`).
We want to try and catch as much unexpected/non-deterministic behavior as we
can. We could run the CI explicitly in debug mode, but I think it makes sense to
always have overflow checks on in both debug/release modes everywhere, at least
for the duration of the codebase transition.
The mutex was being locked from the very start, before it was needed and
possibly before it would be needed.
Also rename the static global to stick to rust naming conventions.
Note that `once_cell::sync::Lazy<T>` actually internally uses its own lock
around the value, but in this case it's insufficient because `SmallRng` doesn't
implement `SeedableRng` so we can't reseed it with only an `&mut` reference and
must instead replace its value.
We probably *could* still use `Lazy<SmallRng>` directly and then rely on
`std::mem::swap()` to replace the contents of the shared global static without
reassigning the variable directly with a new `SmallRng` instance, but I'm not
sure that's a great idea. This is just a built-in, there's no real harm in
locking twice (especially while fish remains essentially single-threaded).
The old comments about using i128 logic were still there even though we are no
longer using that approach and the output type was very much misleadingly a u64
printed to the console (but via `%d` so it was ultimately shown as an i64). Be
explicit about the resulting being a valid i64 value before passing it to the
sprintf!() macro.
Also add comments about the safety of the final `unwrap()` operation.
Rust doesn't have __FUNCTION__ or __func__ (though you can hack around it with a
proc macro, but that will require a separate crate and slowing down compilation
times with heavy proc macro dependencies), so these are just regular functions
(at least for now). Rust's default stack trace on panic (even in release mode)
should be enough (and the functions themselves are inlined so the calling
function should be the second frame from the top, after the #[cold] panic
functions).
This is to allow us to verify some implementation details that aren't explicitly
documented in the rust standard library's documentation.
std::thread uses `pthread_create()` underneath the hood on *nix platforms, so
this *should* merely be a formality.
The way cxx bridge works, it doesn't recognize any types from another module as
being shared cxx bridge types with generations native to both C++ and Rust,
meaning every module that was going to use function pointers would have to
define its own `c_void` type (because cxx bridge doesn't recognize any of
libc::c_void, std::ffi::c_void, or autocxx::c_void).
FFI on other platforms has long used the equivalent of `uint8_t *` as an
alternative to `void *` for code where `void` was not available or was
undesirable for some reason. We can join the club - this way we can always use
`* {const|mut} u8` in our rust code and `uint8_t *` in our C++ code to pass
around parameters or values over the C abi.
I needed to rename some types already ported to rust so they don't clash with
their still-extant cpp counterparts. Helper ffi functions added to avoid needing
to dynamically allocate an FdMonitorItem for every fd (we use dozens per basic
prompt).
I ported some functions from cpp to rust that are used only in the backend but
without removing their existing cpp counterparts so cpp code can continue to use
their version of them (`wperror` and `make_detached_pthread`).
I ran into issues porting line-by-line logic because rust inverts the behavior
of `std::remove_if(..)` by making it (basically) `Vec::retain_if(..)` so I
replaced bools with an explict enum to make everything clearer.
I'll port the cpp tests for this separately, for now they're using ffi.
Porting closures was ugly. It's nothing hard, but it's very ugly as now each
capturing lambda has been changed into an explicit struct that contains its
parameters (that needs to be dynamically allocated), a standalone callback
(member) function to replace the lambda contents, and a separate trampoline
function to call it from rust over the shared C abi (not really relevant to
x86_64 w/ its single calling convention but probably needed on other platforms).
I don't like that `fd_monitor.rs` has its own `c_void`. I couldn't find a way to
move that to `ffi.rs` but still get cxx bridge to consider it a shared POD.
Every time I moved it to a different module, it would consider it to be an
opaque rust type instead. I worry this means we're going to have multiple
`c_void1`, `c_void2`, etc. types as we continue to port code to use function
pointers.
Also, rust treats raw pointers as foreign so you can't do `impl Send for * const
Foo` even if `Foo` is from the same module. That necessitated a wrapper type
(`void_ptr`) that implements `Send` and `Sync` so we can move stuff between
threads.
The code in fd_monitor_t has been split into two objects, one that is used by
the caller and a separate one associated with the background thread (this is
made nice and clean by rust's ownership model). Objects not needed under the
lock (i.e. accessed by the background thread exclusively) were moved to the
separate `BackgroundFdMonitor` type.
* Improve prompt execution time
* Change status to changes
* Remove grep/awk/sort
* Remove calls to grep/awk/sort
* Don't overwrite user defined colors
* Make look more consistent with git
This removes a weird `ls` call (that just decorates directories), and
makes it behave like normal path completion.
(really, this should be a proper option to complete)
Fixes#9285
Add completions for trash-cli commands:
trash, trash-empty, trash-list, trash-put and trash-restore.
``trash --help`` are used to identify the executable in trash cli completion.
Keeps the location of original function definition, and also stores
where it was copied. `functions` and `type` show both locations,
instead of none. It also retains the line numbers in the stack trace.
Rewrite completions for meson to expose meson commands with their
options and subcommands. New completions are based on the meson 1.0.
Subcommands were introduced in meson 0.42.0 (August 2017), so new
completions will only work for versions after 0.42.0. At this moment,
even oldstable Debian (buster) has meson 0.49.2 -- which means it is
unlikely someone will be affected.
---------
Co-authored-by: Mahmoud Al-Qudsi <mqudsi@neosmart.net>
By default, fish does not complete files that have leading dots, unless the
wildcard itself has a leading dot. However this also affected completions;
for example `git add` would not offer `.gitlab-ci.yml` because it has a
leading dot.
Relax this for custom completions. Default file expansion still
suppresses leading dots, but now custom completions can create
leading-dot completions and they will be offered.
Fixes#3707.
When we draw the prompt, we move the cursor to the actual
position *we* think it is by issuing a carriage return (via
`move(0,0)`), and then going forward until we hit the spot.
This helps when the terminal and fish disagree on the width of the
prompt, because we are now definitely in the correct place, so we can
only overwrite a bit of the prompt (if it renders longer than we
expected) or leave space after the prompt. Both of these are benign in
comparison to staircase effects we would otherwise get.
Unfortunately, midnight commander ("mc") tries to extract the last
line of the prompt, and does so in a way that is overly naive - it
resets everything to 0 when it sees a `\r`, and doesn't account for
cursor movement. In effect it's playing a terminal, but not committing
to the bit.
Since this has been an open request in mc for quite a while, we hack
around it, by checking the $MC_SID environment variable.
If we see it, we skip the clearing. We end up most likely doing
relative movement from where we think we are, and in most cases it
should be *fine*.
This removes a possibility of an infinite loop where something in
__fish_config_interactive triggers a fish_prompt or fish_read event,
which calls __fish_on_interactive which calls
__fish_config_interactive again, ...
Fixes#9564
This wanted to get the default priority, and it ran a thing *at source
time*.
This can lead to a variety of errors and I don't believe it's all that
useful, so we remove it.
This is an additional tool, and this function is executed on source
time so we'd spew errors.
(also remove an ineffective line - it's probably *nicer* with the
read, but that's not what's currently effectively doing anything)
We should fix this warning eventually. Silence it for now to make Clippy
pass without warnings, which makes it much more useful.
Compiling fish-rust v0.1.0 (/home/johannes/git/fish-riir/fish-rust)
error: mutable borrow from immutable input(s)
--> src/ffi.rs:79:32
|
79 | pub fn get_procs(&self) -> &mut [UniquePtr<process_t>] {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: immutable borrow here
--> src/ffi.rs:79:22
|
79 | pub fn get_procs(&self) -> &mut [UniquePtr<process_t>] {
| ^^^^^
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#mut_from_ref
= note: `#[deny(clippy::mut_from_ref)]` on by default
error: could not compile `fish-rust` due to previous error
A following commit will pass global string constants to the gettext macro.
This is not ideal because we might accidentally use the constants without
gettext (which we should never do). To fix that we might need to define a
macro per constant, or use a proc macro which is maybe not worth it.
warning: deref which would be done by auto-deref
--> src/wchar_ffi.rs:81:5
|
81 | &*EMPTY_WSTRING
| ^^^^^^^^^^^^^^^ help: try this: `&EMPTY_WSTRING`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#explicit_auto_deref
= note: `#[warn(clippy::explicit_auto_deref)]` on by default
Separate the neovim completions from the vim ones, as their supported
options have diverged considerably.
Some documented options are not yet implemented, these are added but
commented out.
Closes#9535.
---------
Co-authored-by: Mahmoud Al-Qudsi <mqudsi@neosmart.net>
This is an easy win for `git add ` completion time if we have multiple descriptions.
What happened was we did things once per description string, but the
things included a bunch of computation (including multiple `string`
calls and even a `realpath`!). Because these don't change, we can
simply do them once.
And it turns out we can just use a cartesian product:
for d in $desc
printf '%s\t%s\n' $file $d
end
becomes
printf '%s\n' $file\t$desc
lazy_static has better ergonomics at the call/access sites (it returns a
reference to the type directly, whereas with once_cell we get a static Lazy<T>
that we must dereference instead) but the once_cell api is slated for
integration into the standard library [0] and has been the "preferred" way to
declare static global variables w/ deferred initialization. It's also less
opaque and easier to comprehend how it works, I guess?
(Both `once_cell` and `lazy_static` are already in our dependency tree, so this
should have no detrimental effect on build times. It actually negligibly
*improves* build times by not using macros, reducing the amount of expansion the
compiler has to do by a miniscule amount.)
[0]: https://github.com/rust-lang/rust/issues/74465
I have no idea why `apt-cache --no-generate show` is so slow since it basically
dumps the contents of the cache file located at `/var/lib/dpkg/status`. We are
technically bypassing any waits on the cache lock file so this may produce
incorrect results if the cache is being regenerated in the moment, but that's a
small price to pay and the results are likely confined to simply not generating
comprehensive results.
With this change, we no longer need to truncate results to the first n matches
and we no longer only print packages beginning with the commandline argument
enabling fish's partial completions logic to offer less-perfect suggestions when
no better options are available.
Even though we are generating more usable completions, we still trounce the old
performance by leaps and bounds:
```
Benchmark #1: fish -c "complete -C\"apt install ac\""
Time (mean ± σ): 2.165 s ± 0.033 s [User: 267.0 ms, System: 1932.2 ms]
Range (min … max): 2.136 s … 2.256 s 10 runs
Benchmark #2: build/fish -c "complete -C\"apt install ac\""
Time (mean ± σ): 111.1 ms ± 1.8 ms [User: 38.9 ms, System: 72.9 ms]
Range (min … max): 108.2 ms … 114.9 ms 26 runs
Summary
'build/fish -c "complete -C\"apt install ac\""' ran
19.49 ± 0.44 times faster than 'fish -c "complete -C\"apt install ac\""'
```
I think this should be preferred for all subcommand completions because it
handles typos or subcommands we don't recognize better (`apt foo <TAB>` no
longer suggests subcommands since the subcommand position has been taken).
It's debatable whether is_ascii_digit() is better than (0..=9).contains().
(Probably we want to go with the mainstream Rust choice eventually.)
Let's disable the warning for now since it's not terribly important.
We should only be dealing with wcharz_t at the language boundary.
Rust callers should prefer the equivalent &wstr.
Since wcsfilecmp() is no longer exposed directly it can take &wstr only.
- Added phx completions. These are very common completions for the Elixir Phoenix Framework.
Documentation can be found here: https://hexdocs.pm/phoenix/1.7.0-rc.2/Mix.Tasks.Local.Phx.html#content
- Added argument completions
- Made all descriptions start with an uppercase for better consistency
- Update CHANGELOG.rst
This is early work but I guess there's no harm in pushing it?
Some thoughts on the conventions:
Types that live only inside Rust follow Rust naming convention
("FeatureMetadata").
Types that live on both sides of the language boundary follow the existing
naming ("feature_flag_t").
The alternative is to define a type alias ("using feature_flag_t =
rust::FeatureFlag") but that doesn't seem to be supported in "[cxx::bridge]"
blocks. We could put it in a header ("future_feature_flags.h").
"feature_metadata_t" is a variant of "FeatureMetadata" that can cross
the language boundary. This has the advantage that we can avoid tainting
"FeatureMetadata" with "CxxString" and such. This is an experimental approach,
probably not what we should do in general.
The initial port of feature flags requires a global initialization. Since
fish_indent accesses feature flags, let's make sure to initialize them here.
In future, we can stop initializing things fish_indent doesn't need (like
the topic monitor) but that's no big deal. Global initialization should
always be a benign addition.
The original implementation without the test took me 3 hours (first time
seriously looking into this)
The functions take "wcharz_t" for smooth integration with existing C++ callers.
This is at the expense of Rust callers, which would prefer "&wstr". Would be
nice to declare a function parameter that accepts both but I don't think
that really works since "wcharz_t" drops the lifetime annotation.
rustfmt removes the "::" prefix from qualifiers. This breaks the build because
I think a later "pub use ffi::*" results in "std" being an ambiguous reference.
We can re-enable these once we're nearing a RIIR release (or if someone thinks
it's a good use of their time to fix them before then). Otherwise we're just
going to have GitHub reporting CI failure for all commits instead of just the
ones that actually broke something.
(I'm mainly trying to get the branch in a good state to merge into master.)
Use rustup to install the latest version of rust. The latest version of rust
available from pkg is 1.66.0 while the code currently needs 1.67.0 or later.
The nix crate had all its default features enabled, which included features that
are not present under BSD. We should only enable the select subset of crate
features that we know are available cross-platform (or else use conditional
targeting in Cargo.toml to only enable Linux-only features when compiling for
Linux targets).
For now, it seems we can just use the nix crate with all features disabled as it
still builds under Linux and FreeBSD in this state.
The `cmake` meta package pulls in `cmake-core`, `cmake-docs`, and `cmake-man` -
we don't need the latter two.
(It seems to be available on all the versions/architectures we target.)
The git-lite flavor, being significantly smaller and downloading/installing much
faster with fewer dependencies, is much better suited for CI environments (at
the cost of not supporting interactive git commands).
By default /etc/pkg/FreeBSD.conf uses either the /quarterly or /latest pkg
builds, which are built against the latest minor release of FreeBSD for the
given ${ABI} string at the time they were last updated.
The nature of the shared binary packages means everyone (across all minor
versions of the same major version on the same architecture, all of which share
the same stable ABI) gets the same binary build.
There are however packages which depend on symbols exported by system-provided
libraries (rather than by other packages, which are always going to be in sync)
that *aren't* stable across minor releases, leaving packages like llvm
broken if you install the latest llvm from pkg's binary repos built against,
say, FreeBSD 13.1 while running FreeBSD 13.0.
The other option is to use the "snapshots" of the binary packages available upon
the release of each minor version, by using /release_0, /release_1, etc instead
of /quarterly or /latest, but then you're limited to the ports that were
available at that specific date and those old versions.
tl;dr just make sure we're always using the latest minor release for each major
version of FreeBSD we intend to support.
This works around an autocxx limitations where different types cannot
have the same name even if they live in different namespace.
ast::job_t conflicts with job_t.
This adds an implementation of fish_wcstoi in Rust, mirroring the one in
fish. As Rust does not have a string to number which infers the radix
(i.e. looks for leading 0x or 0), we add that manually.
In v3 several input parameters where renamed and since v4 it requires Node.js 16.
This resolves warnings about Node.js 12 and `set-output` being deprecated and
slated for removal in the `Lock threads` workflow.
This addresses the node v12 deprecation warning in the GitHub CI, caused by the
dependency on actions/checkout@v2.
While actions/checkout@v3 introduces some new features and changes some
defaults, the subset of features that we use should not be affected by this
migration.
The "breaking change" from v2 to v3 can be seen at [0]. Since we are tracking
only v2 without a dot release specified, we are already opting into any breakage
across minor versions, so really the only change of note is the node version
upgrade.
[0]: https://github.com/actions/checkout/compare/v2.4.2...v3.0.0
This translated ctrl-k to "\v", which is a "vertical tab", and ctrl-l
to "\f" and ctrl-g to "\a".
There is no "vertical tab" or "alarm" or "\f" *key*, so these
shouldn't be translated. Just drop these and call them `\ck` and such.
(vertical tab specifically is utterly useless and I would be okay with
dropping it entirely, I have never seen it used anywhere)
That commit did way too many things, making it hard to see the 5 regressions
it introduced. Let's revert it and its stragglers. In future, we could redo
some of the changes.
Reverts changes to share/completions/git.fish from
- 3548aae55 (completions/git: Don't leak submodule subcommands, 2023-01-23)
- 905f788b3 (completions/git: Remove awkward newline symbol, 2023-01-10)
- 2da1a4ae7 (completions/git: Fix git-foo commands, 2023-01-09)
- e9bf8b9a4 (Run fish_indent on share/completions/*.fish, 2022-12-08)
- d31847b1d (Fix apparent dyslexia, 2022-11-12)
- 054d0ac0e (git completions: undo mistaken `set -f` usage, 2022-10-28)
- f5711ad5e (git.fish: collapse repeat complete cmds, set -f, rm unneeded funcs, 2022-10-27)
Bracketed paste adds one undo entry unless the pasted text contains a '
or \. This is because the "paste" bind-mode has bindings for those keys,
so they effectively start a new undo entry.
Let's fix this by adding an explicit undo group (our first use of this
feature!).
Please tell us which fish version you are using by executing the following:
fish --version
echo $version
Please tell us which operating system and terminal you are using. The output of `uname -a` and `echo $TERM` may be helpful in this regard although other commands might be relevant in your specific situation.
Please tell us which operating system (output of `uname`) and terminal you are using.
Please tell us if you tried fish without third-party customizations by executing this command and whether it affected the behavior you are reporting:
sh -c 'env HOME=$(mktemp -d) fish'
sh -c 'env HOME=$(mktemp -d) XDG_CONFIG_HOME= XDG_DATA_DIRS= fish'
Tell us how to reproduce the problem. Including an asciinema.org recording is useful for problems that involve the visual display of fish output such as its prompt.
git --no-pager diff --exit-code || { echo 'There are uncommitted changes after regenerating the gettext PO files. Make sure to update them via `build_tools/update_translations.fish --no-mo` after changing source files.'; exit 1; }
ubuntu-32bit-fetched-pcre2:
ubuntu-32bit-static-pcre2:
runs-on:ubuntu-latest
steps:
- uses:actions/checkout@v2
- uses:actions/checkout@v4
- uses:dtolnay/rust-toolchain@1.70
with:
targets:"i586-unknown-linux-gnu"# rust-toolchain wants this comma-separated
- Compound commands (``begin; echo 1; echo 2; end``) can now be now be abbreviated using braces (``{ echo1; echo 2 }``), like in other shells.
- Fish now supports transient prompts: if :envvar:`fish_transient_prompt` is set to 1, fish will reexecute prompt functions with the ``--final-rendering`` argument before running a commandline (:issue:`11153`).
- When tab completion results are truncated, any common directory name is omitted. E.g. if you complete "share/functions", and it includes the files "foo.fish" and "bar.fish",
the completion pager will now show "…/foo.fish" and "…/bar.fish". This will make the candidates shorter and allow for more to be shown at once (:issue:`11250`).
- The self-installing configuration introduced in fish 4.0 has been changed.
Now fish built with embedded data will just read the data straight from its own binary or write it out when necessary, instead of requiring an installation step on start.
That means it is now possible to build fish as a single file and copy it to a compatible system, including as a different user, without extracting any files.
As before this is the default when building via `cargo`, and disabled when building via `cmake`, and for packagers we continue to recommend cmake.
Note: When fish is built like this, the `$__fish_data_dir` variable will be empty because that directory no longer has meaning. If you need to load files from there,
use `status get-file` or find alternatives (like loading completions for "foo" via `complete -C"foo "`).
We're considering making data embedding mandatory in future releases because it has a few advantages even for installation from a package (like making file conflicts with other packages impossible). (:issue:`11143`)
Deprecations and removed features
---------------------------------
- Tokens like ``{echo,echo}`` or ``{ echo, echo }`` in command position are no longer interpreted as brace expansion but as compound command.
- Terminfo-style key names (``bind -k``) are no longer supported. They had been superseded by the native notation since 4.0,
and currently they would map back to information from terminfo, which does not match what terminals would send with the kitty keyboard protocol (:issue:`11342`).
- fish no longer reads the terminfo database, so its behavior is no longer affected by the :envvar:`TERM` environment variable (:issue:`11344`).
For the time being, this can be turned off via the "ignore-terminfo" feature flag::
set -Ua fish_features no-ignore-terminfo
- The ``--install`` option when fish is built as self-installable was removed. If you need to write out fish's data you can use the new ``status list-files`` and ``status get-file`` subcommands, but it should no longer be necessary. (:issue:`11143`)
- RGB colors (``set_color ff0000``) now default to using 24-bit RGB true-color commands, even if $COLORTERM is unset, because that is often lost e.g. over ssh (:issue:`11372`)
- To go back to using the nearest match from the 256-color palette, use ``set fish_term24bit 0`` or set $COLORTERM to a value that is not "24bit" or "truecolor".
To make the nearest-match logic use the 16 color palette instead, use ``set fish_term256 0``.
- Inside macOS Terminal.app, fish makes an attempt to still use the palette colors.
If that doesn't work, use ``set fish_term24bit 0``.
-``set_color --background=COLOR`` no longer implicitly activates bold mode.
To mitigate this change on existing installations that use a default theme, update your theme with ``fish_config theme choose`` or ``fish_config theme save``.
Scripting improvements
----------------------
Interactive improvements
------------------------
- Autosuggestions are now also provided in multi-line command lines. Like `ctrl-r`, autosuggestions operate only on the current line.
- Autosuggestions used to not suggest multi-line commandlines from history; now autosuggestions include individual lines from multi-line command lines.
- The history search now preserves ordering between :kbd:`ctrl-s` forward and :kbd:`ctrl-r` backward searches.
- Left mouse click (as requested by `click_events <terminal-compatibility.html#click-events>`__) can now select pager items (:issue:`10932`).
- Instead of flashing all the text to the left of the cursor, fish now flashes the matched token during history token search, the completed token during completion (:issue:`11050`), the autosuggestion when deleting it, and the full command line in all other cases.
- Pasted commands are now stripped of any ``$`` prefix.
- The :kbd:`alt-s` binding will now also use ``run0`` if available.
New or improved bindings
^^^^^^^^^^^^^^^^^^^^^^^^
- On non-macOS systems, :kbd:`alt-left`, :kbd:`alt-right`, :kbd:`alt-backspace`, :kbd:`alt-delete` no longer operate on punctuation-delimited words but on whole arguments, possibly including special characters like ``/`` and quoted spaces.
On macOS, the corresponding :kbd:`ctrl-` prefixed keys operate on whole arguments.
Word operations are still available via the other respective modifier, same as in the browser.
-: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` now pushes all text located above the prompt to the terminal's scrollback, before clearing and redrawing the screen (via a new special input function ``scrollback-push``).
For compatibility with terminals that do not provide the scroll-forward command,
this is only enabled by default if the terminal advertises support for the ``indn`` capability via XTGETTCAP.
- Bindings using shift with non-ASCII letters (such as :kbd:`ctrl-shift-ä`) are now supported.
If there is any modifier other than shift, this is the recommended notation (as opposed to :kbd:`ctrl-Ä`).
Completions
^^^^^^^^^^^
-``git`` completions now show the remote url as a description when completing remotes.
-``systemctl`` completions no longer print escape codes if ``SYSTEMD_COLORS`` is set (:issue:`11465`).
Improved terminal support
^^^^^^^^^^^^^^^^^^^^^^^^^
- Support for double, curly, dotted and dashed underlines in `fish_color_*` variables and :doc:`set_color <cmds/set_color>` (:issue:`10957`).
- Underlines can now be colored independent of text (:issue:`7619`).
- New documentation page `Terminal Compatibility <terminal-compatibility.html>`_ (also accessible via ``man fish-terminal-compatibility``) lists required and optional terminal control sequences used by fish.
Other improvements
------------------
-``fish_indent`` and ``fish_key_reader`` are now available as builtins, and if fish is called with that name it will act like the given tool (as a multi-call binary).
This allows truly distributing fish as a single file. (:issue:`10876`)
-``fish_indent --dump-parse-tree`` now emits simple metrics about the tree including its memory consumption.
For distributors
----------------
-``fish_indent`` and ``fish_key_reader`` are still built as separate binaries for now, but can also be replaced with a symlink if you want to save disk space (:issue:`10876`).
- The CMake system was simplified and no longer second-guesses rustup. It will run rustc and cargo via $PATH or in ~/.cargo/bin/.
If that doesn't match your setup, set the Rust_COMPILER and Rust_CARGO cmake variables (:issue:`11328`).
- Cygwin support has been reintroduced, since rust gained a Cygwin target (https://github.com/rust-lang/rust/pull/134999, :issue:`11238`).
--------------
fish 4.0.2 (released April 20, 2025)
====================================
This release of fish fixes a number of issues identified in fish 4.0.1:
- Completions are quoted, rather than backslash-escaped, only if the completion is unambiguous. Continuing to edit the token is therefore easier (:issue:`11271`). This changes the behavior introduced in 4.0.0 where all completions were quoted.
- The warning when the terminfo database can't be found has been downgraded to a log message. fish will act as if the terminal behaves like xterm-256color, which is correct for the vast majority of cases (:issue:`11277`, :issue:`11290`).
- Key combinations using the super (Windows/command) key can now (actually) be bound using the :kbd:`super-` prefix (:issue:`11217`). This was listed in the release notes for 4.0.1 but did not work correctly.
-:doc:`function <cmds/function>` is stricter about argument parsing, rather than allowing additional parameters to be silently ignored (:issue:`11295`).
- Using parentheses in the :doc:`test <cmds/test>` builtin works correctly, following a regression in 4.0.0 where they were not recognized (:issue:`11387`).
-:kbd:`delete` in Vi mode when Num Lock is active will work correctly (:issue:`11303`).
- Abbreviations cannot alter the command-line contents, preventing a crash (:issue:`11324`).
- Improvements to various completions, including new completions for ``wl-randr`` (:issue:`11301`), performance improvements for ``cargo`` completions by avoiding network requests (:issue:`11347`), and other improvements for ``btrfs`` (:issue:`11320`), ``cryptsetup`` (:issue:`11315`), ``git`` (:issue:`11319`, :issue:`11322`, :issue:`11323`), ``jj`` (:issue:`11046`), and ``systemd-analyze`` (:issue:`11314`).
- The Mercurial (``hg``) prompt can handle working directories that contain an embedded newline, rather than producing errors (:issue:`11348`).
- A number of crashes have been fixed. Triggers include prompts containing backspace characters (:issue:`11280`), history pager search (:issue:`11355`), invalid UTF-8 in :doc:`read <cmds/read>` (:issue:`11383`), and the ``kill-selection`` binding (:issue:`11367`).
- A race condition in the test suite has been fixed (:issue:`11254`), and a test for fish versioning relaxed to support downstream distributors' modifications (:issue:`11173`).
- Small improvements to the documentation (:issue:`11264`, :issue:`11329`, :issue:`11361`).
--------------
fish 4.0.1 (released March 12, 2025)
====================================
This release of fish includes the following improvements compared to fish 4.0.0:
- Key combinations using the super (Windows/command) key can be bound using the :kbd:`super-` prefix (:issue:`11217`).
- Konsole's menu shows the "Open folder with" option again (:issue:`11198`).
-``$fish_color_search_match`` will now only be applied to the foreground color if it has an explicit foreground. For example, this allows setting::
set -g fish_color_search_match --reverse
- Cursor shape commands (``\e[2 q``) are no longer sent in non-interactive shells or in redirections (:issue:`11255`).
-:doc:`status <cmds/status>` gained a ``is-interactive-read`` subcommand, to check whether the script is being called from an interactive :doc:`read <cmds/read>` invocation.
- fish's background tasks are now started in a way that avoids an error on macOS Terminal.app (:issue:`11181`).
- Using key combinations within qemu should work correctly.
- Prompts containing control characters no longer cause incorrect display of command lines (:issue:`11252`).
- Cancelling the command-line in Vi mode displays correctly again (:issue:`11261`).
- The acidhub prompt properly displays the git branch again (:issue:`11179`).
- Completions for ``wine`` correctly include files again (:issue:`11202`).
- On macOS, paths from ``/etc/paths`` and ``/etc/manpaths`` containing colons are handled correctly (:issue:`10684`). This functionality was included in the 4.0.0 release notes but was missing from the source code.
- The XTerm ``modifyOtherKeys`` keyboard encoding is no longer used under WezTerm, as it does not work correctly in all layouts (:issue:`11204`).
-:kbd:`option-left` and other similar keys should now work in iTerm versions before 3.5.12; the kitty keyboard protocol is now disabled on these versions (:issue:`11192`).
- The kitty keyboard protocol is no longer used under Midnight Commander, as it does not work correctly (:issue:`10640`).
- fish now sends the commandline along with the OSC 133 semantic prompt command start sequence. This fixes a test in the kitty terminal (:issue:`11203`).
- Git completions for third-party commands like "git-absorb" are completed correctly again (:issue:`11205`).
- Completions for ``diskutil`` no longer produce an error (:issue:`11201`).
- The output of certain error messages no longer prints newlines to standard output (:issue:`11248`).
- A number of crashes have been fixed, including file names longer than 255 bytes (:issue:`11221`), using fish on a btrfs filesystem (:issue:`11219`), history files that do not have the expected format (:issue:`11236`), and pasting into an empty command line (:issue:`11256`).
--------------
fish 4.0.0 (released February 27, 2025)
=======================================
fish's core code has been ported from C++ to Rust (:issue:`9512`). This means a large change in dependencies and how to build fish. However, there should be no direct impact on users. Packagers should see the :ref:`For Distributors <rust-packaging>` section at the end.
Notable backwards-incompatible changes
--------------------------------------
- As part of a larger binding rework, ``bind`` gained a new key notation.
In most cases the old notation should keep working, but in rare cases you may have to change a ``bind`` invocation to use the new notation.
See :ref:`below <changelog-new-bindings>` for details.
-:kbd:`ctrl-c` now calls a new bind function called ``clear-commandline``. The old behavior, which leaves a "^C" marker, is available as ``cancel-commandline`` (:issue:`10935`)
-``random`` will produce different values from previous versions of fish when used with the same seed, and will work more sensibly with small seed numbers.
The seed was never guaranteed to give the same result across systems,
so we do not expect this to have a large impact (:issue:`9593`).
- Variables in command position that expand to a subcommand keyword are now forbidden to fix a likely user error.
For example, ``set editor command emacs; $editor`` is no longer allowed (:issue:`10249`).
-``functions --handlers`` will now list handlers in a different order.
Now it is definition order, first to last, where before it was last to first.
This was never specifically defined, and we recommend not relying on a specific order (:issue:`9944`).
- The ``qmark-noglob`` feature, introduced in fish 3.0, is enabled by default. That means ``?`` will no longer act as a single-character glob.
You can, for the time being, turn it back on by adding ``no-qmark-noglob`` to :envvar:`fish_features` and restarting fish::
set -Ua fish_features no-qmark-noglob
The flag will eventually be made read-only, making it impossible to turn off.
- Terminals that fail to ignore unrecognized OSC or CSI sequences may display garbage. We know cool-retro-term and emacs' ansi-term are affected, but most mainstream terminals are not.
- fish no longer searches directories from the Windows system/user ``$PATH`` environment variable for Linux executables. To execute Linux binaries by name (i.e. not with a relative or absolute path) from a Windows folder, make sure the ``/mnt/c/...`` path is explicitly added to ``$fish_user_paths`` and not just automatically appended to ``$PATH`` by ``wsl.exe`` (:issue:`10506`).
- Under Microsoft Windows Subsystem for Linux 1 (not WSL 2), backgrounded jobs that have not been disowned and do not terminate on their own after a ``SIGHUP`` + ``SIGCONT`` sequence will be explicitly killed by fish on exit (after the usual prompt to close or disown them) to work around a WSL 1 deficiency that sees backgrounded processes that run into ``SIGTTOU`` remain in a suspended state indefinitely (:issue:`5263`). The workaround is to explicitly ``disown`` processes you wish to outlive the shell session.
Notable improvements and fixes
------------------------------
.._changelog-new-bindings:
- fish now requests XTerm's ``modifyOtherKeys`` keyboard encoding and `kitty keyboard protocol's <https://sw.kovidgoyal.net/kitty/keyboard-protocol/>`_ progressive enhancements (:issue:`10359`).
Depending on terminal support, this allows to binding more key combinations, including arbitrary combinations of modifiers :kbd:`ctrl`, :kbd:`alt` and :kbd:`shift`, and distinguishing (for example) :kbd:`ctrl-i` from :kbd:`tab`.
Additionally, ``bind`` now supports a human-readable syntax in addition to byte sequences.
This includes modifier names, and names for keys like :kbd:`enter` and :kbd:`backspace`.
For example
-``bind up 'do something'`` binds the up-arrow key instead of a two-key sequence ("u" and then "p")
-``bind ctrl-x,alt-c 'do something'`` binds a sequence of two keys.
Any key argument that starts with an ASCII control character (like ``\e`` or ``\cX``) or is up to 3 characters long, not a named key, and does not contain ``,`` or ``-`` will be interpreted in the old syntax to keep compatibility for the majority of bindings.
Keyboard protocols can be turned off by disabling the "keyboard-protocols" feature flag::
set -Ua fish_features no-keyboard-protocols
This is a temporary measure to work around buggy terminals (:issue:`11056`), which appear to be relatively rare.
Use this if something like "=0" or "=5u" appears in your commandline mysteriously.
- fish can now be built as a self-installing binary (:issue:`10367`). That means it can be easily built on one system and copied to another, where it can extract supporting files.
To do this, run::
cargo install --path . # in a clone of the fish repository
# or `cargo build --release` and copy target/release/fish{,_indent,_key_reader} wherever you want
The first time it runs interactively, it will extract all the data files to ``~/.local/share/fish/install/``. A specific path can be used for the data files with ``fish --install=PATH`` To uninstall, remove the fish binaries and that directory.
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`).
- 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`, :issue:`10126`).
For example, ``commandline -i foo; commandline | grep foo`` succeeds now.
- Undo history is no longer truncated after every command, but kept for the lifetime of the shell process.
- The :kbd:`ctrl-r` history search now uses glob syntax (:issue:`10131`).
- The :kbd:`ctrl-r` history search now operates only on the line or command substitution at cursor, making it easier to combine commands from history (:issue:`9751`).
- Abbreviations can now be restricted to specific commands. For instance::
abbr --add --command git back 'reset --hard HEAD^'
will expand "back" to ``reset --hard HEAD^``, but only when the command is ``git`` (:issue:`9411`).
Deprecations and removed features
---------------------------------
-``commandline --tokenize`` (short option ``-o``) has been deprecated in favor of ``commandline --tokens-expanded`` (short option ``-x``) which expands variables and other shell syntax, removing the need to use :doc:`eval <cmds/eval>` in completion scripts (:issue:`10212`).
- Two new feature flags:
-``remove-percent-self`` (see ``status features``) disables PID expansion of ``%self``, which has been supplanted by ``$fish_pid`` (:issue:`10262`).
-``test-require-arg`` disables ``test``'s one-argument mode. That means ``test -n`` without an additional argument will return false, ``test -z`` will keep returning true. Any other option without an argument, anything that is not an option and no argument will be an error. This also goes for ``[``, test's alternate name.
This is a frequent source of confusion and so we are breaking with POSIX explicitly in this regard.
In addition to the feature flag, there is a debug category "deprecated-test". Running fish with ``fish -d deprecated-test`` will show warnings whenever a ``test`` invocation that would change is used. (:issue:`10365`).
These can be enabled with::
set -Ua fish_features remove-percent-self test-require-arg
We intend to enable them by default in future, and after that eventually make them read-only.
- Specifying key names as terminfo names (using the ``bind -k`` syntax) is deprecated and may be removed in a future version.
- When a terminal pastes text into fish using bracketed paste, fish used to switch to a special ``paste`` bind mode.
This bind mode has been removed. The behavior on paste is no longer configurable.
- When an interactive fish is stopped or terminated by a signal that cannot be caught (SIGSTOP or SIGKILL), it may leave the terminal in a state where keypresses with modifiers are sent as CSI u sequences, instead of traditional control characters or escape sequences that are recognized by Readline and compatible programs, such as bash and python.
If this happens, you can use the ``reset`` command from ``ncurses`` to restore the terminal state.
-``fish_key_reader --verbose`` no longer shows timing information.
- Terminal information is no longer read from hashed terminfo databases, or termcap databases (:issue:`10269`). The vast majority of systems use a non-hashed terminfo database, which is still supported.
-``source`` returns an error if used without a filename or pipe/redirection (:issue:`10774`).
Scripting improvements
----------------------
-``for`` loops will no longer remember local variables from the previous iteration (:issue:`10525`).
- A new ``history append`` subcommand appends a command to the history, without executing it (:issue:`4506`).
- A new redirection: ``<? /path/to/file`` will try opening the file as input, and if it doesn't succeed silently uses ``/dev/null`` instead.
This can help with checks like ``test -f /path/to/file; and string replace foo bar < /path/to/file``. (:issue:`10387`)
- A new option ``commandline --tokens-raw`` prints a list of tokens without any unescaping (:issue:`10212`).
- A new option ``commandline --showing-suggestion`` tests whether an autosuggestion is currently displayed (:issue:`10586`).
-``functions`` and ``type`` now show that a function was copied and its source, rather than solely ``Defined interactively`` (:issue:`6575`).
- Stack trace now shows line numbers for copied functions (:issue:`6575`).
-``foo & && bar`` is now a syntax error, like in other shells (:issue:`9911`).
-``if -e foo; end`` now prints a more accurate error (:issue:`10000`).
-``cd`` into a directory that is not readable but accessible (permissions ``--x``) is now possible (:issue:`10432`).
- An integer overflow in ``string repeat`` leading to a near-infinite loop has been fixed (:issue:`9899`).
-``string shorten`` behaves better in the presence of non-printable characters, including fixing an integer overflow that shortened strings more than intended (:issue:`9854`).
-``string pad`` no longer allows non-printable characters as padding (:issue:`9854`).
-``string repeat`` now allows omission of ``-n`` when the first argument is an integer (:issue:`10282`).
-``string match`` and ``replace`` have a new ``--max-matches`` option to return as soon as the specified number of matches have been identified, which can improve performance in scripts (:issue:`10587`).
-``functions --handlers-type caller-exit`` once again lists functions defined as ``function --on-job-exit caller``, rather than them being listed by ``functions --handlers-type process-exit``.
- A new ``set --no-event`` option sets or erases variables without triggering a variable event. This can be useful to change a variable in an event handler (:issue:`10480`).
- Commas in command substitution output are no longer used as separators in brace expansion, preventing a surprising expansion in some cases (:issue:`5048`).
- Universal variables can now store strings containing invalid UTF-8 (:issue:`10313`).
- A new ``path basename -E`` option that causes it to return the basename ("filename" with the directory prefix removed) with the final extension (if any) also removed. This is a shorter version of ``path change-extension "" (path basename $foo)`` (:issue:`10521`).
- A new ``math --scale-mode`` option to select ``truncate``, ``round``, ``floor``, ``ceiling`` as you wish; the default value is ``truncate``. (:issue:`9117`).
-``random`` is now less strict about its arguments, allowing a start larger or equal to the end. (:issue:`10879`)
-``function --argument-names`` now produces an error if a read-only variable name is used, rather than simply ignoring it (:issue:`10842`).
- Tilde expansion in braces (that is, ``{~,}``) works correctly (:issue:`10610`).
Interactive improvements
------------------------
- Autosuggestions were sometimes not shown after recalling a line from history, which has been fixed (:issue:`10287`).
- Up-arrow search matches -- which are highlighted in reverse colors -- are no longer syntax-highlighted, to fix bad contrast with the search match highlighting.
- Command abbreviations (those with ``--position command`` or without a ``--position``) now also expand after decorators like ``command`` (:issue:`10396`).
- Abbreviations now expand after process separators like ``;`` and ``|``. This fixes a regression in version 3.6 (:issue:`9730`).
- When exporting interactively defined functions (using ``type``, ``functions`` or ``funcsave``) the function body is now indented, to match the interactive command line editor (:issue:`8603`).
-:kbd:`ctrl-x` (``fish_clipboard_copy``) on multiline commands now includes indentation (:issue:`10437`).
-:kbd:`ctrl-v` (``fish_clipboard_paste``) now strips ASCII control characters from the pasted text.
This is consistent with normal keyboard input (:issue:`5274`).
- When a command like ``fg %2`` fails to find the given job, it no longer behaves as if no job spec was given (:issue:`9835`).
- Redirection in command position like ``>echo`` is now highlighted as error (:issue:`8877`).
-``fish_vi_cursor`` now works properly inside the prompt created by builtin ``read`` (:issue:`10088`).
- fish no longer fails to open a FIFO if interrupted by a terminal resize signal (:issue:`10250`).
-``read --help`` and friends no longer ignore redirections. This fixes a regression in version 3.1 (:issue:`10274`).
- Measuring a command with ``time`` now considers the time taken for command substitution (:issue:`9100`).
-``fish_add_path`` now automatically enables verbose mode when used interactively (in the command line), in an effort to be clearer about what it does (:issue:`10532`).
- fish no longer adopts TTY modes of failed commands (:issue:`10603`).
-``complete -e cmd`` now prevents autoloading completions for ``cmd`` (:issue:`6716`).
- fish's default color scheme no longer uses the color "blue", as it has bad contrast against the background in a few terminal's default palettes (:issue:`10758`, :issue:`10786`)
The color scheme will not be upgraded for existing installs. If you want, you should select it again via ``fish_config``.
- Command lines which are larger than the terminal are now displayed correctly, instead of multiple blank lines being displayed (:issue:`7296`).
- Prompts that use external commands will no longer produce an infinite loop if the command crashes (:issue:`9796`).
- The output of ``jobs`` shows "-" for jobs that have the same process group ID as the fish process, rather than "-2" (:issue:`10833`).
- Job expansion (``%1`` syntax) works properly for jobs that are a mixture of external commands and functions (:issue:`10832`).
- Command lines which have more lines than the terminal can be displayed and edited correctly (:issue:`10827`).
- Functions that have been erased are no longer highlighted as valid commands (:issue:`10866`).
-``not``, ``time``, and variable assignments (that is ``not time a=b env``) is correctly recognized as valid syntax (:issue:`10890`).
- The Web-based configuration removes old right-hand-side prompts again, fixing a regression in fish 3.4.0 (:issue:`10675`).
- Further protection against programs which crash and leave the terminal in an inconsistent state (:issue:`10834`, :issue:`11038`).
- A workaround for git being very slow on macOS has been applied, improving performance after a fresh boot (:issue:`10535`).
New or improved bindings
^^^^^^^^^^^^^^^^^^^^^^^^
- When the cursor is on a command that resolves to an executable script, :kbd:`alt-o` will now open that script in your editor (:issue:`10266`).
- During up-arrow history search, :kbd:`shift-delete` will delete the current search item and move to the next older item. Previously this was only supported in the history pager.
-:kbd:`shift-delete` will also remove the currently-displayed autosuggestion from history, and remove it as a suggestion.
-:kbd:`ctrl-Z` (also known as :kbd:`ctrl-shift-z`) is now bound to redo.
- Some improvements to the :kbd:`alt-e` binding which edits the command line in an external editor:
- The editor's cursor position is copied back to fish. This is currently supported for Vim and Kakoune.
- Cursor position synchronization is only supported for a set of known editors, which are now also detected in aliases which use ``complete --wraps``. For example, use ``complete --wraps my-vim vim`` to synchronize cursors when ``EDITOR=my-vim``.
- Multiline commands are indented before being sent to the editor, which matches how they are displayed in fish.
- 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.
-:kbd:`alt-d` on an empty command line lists the directory history again. This restores the behavior of version 2.1.
-``history-prefix-search-backward`` and ``-forward`` now maintain the cursor position, instead of moving the cursor to the end of the command line (:issue:`10430`).
- The following keys have refined behavior if the terminal supports :ref:`the new keyboard encodings <changelog-new-bindings>`:
-:kbd:`shift-enter` now inserts a newline instead of executing the command line.
-:kbd:`ctrl-backspace` now deletes the last word instead of only one character (:issue:`10741`).
-:kbd:`ctrl-delete` deletes the next word (same as :kbd:`alt-d`).
- New special input functions:
-``forward-char-passive`` and ``backward-char-passive`` are like their non-passive variants but do not accept autosuggestions or move focus in the completion pager (:issue:`10398`).
-``forward-token``, ``backward-token``, ``kill-token``, and ``backward-kill-token`` are similar to the ``*-bigword`` variants but for the whole argument token (which includes escaped spaces) (:issue:`2014`).
-``clear-commandline``, which merely clears the command line, as an alternative to ``cancel-commandline`` which prints ``^C`` and a new prompt (:issue:`10213`).
- The ``accept-autosuggestion`` special input function now returns false when there was nothing to accept (:issue:`10608`).
- Vi mode has seen some improvements but continues to suffer from the lack of people working on it.
- New default cursor shapes for insert and replace mode.
-:kbd:`ctrl-n` in insert mode accepts autosuggestions (:issue:`10339`).
- Outside insert mode, the cursor will no longer be placed beyond the last character on the commandline.
- When the cursor is at the end of the commandline, a single :kbd:`l` will accept an autosuggestion (:issue:`10286`).
- The cursor position after pasting (:kbd:`p`) has been corrected.
- Added an additional binding, :kbd:`_`, for moving to the beginning of the line (:issue:`10720`).
- When the cursor is at the start of a line, escaping from insert mode no longer moves the cursor to the previous line.
- Added bindings for clipboard interaction, like :kbd:`",+,p` and :kbd:`",+,y,y`.
- Deleting in visual mode now moves the cursor back, matching vi (:issue:`10394`).
- The :kbd:`;`, :kbd:`,`, :kbd:`v`, :kbd:`V`, :kbd:`I`, and :kbd:`gU` bindings work in visual mode (:issue:`10601`, :issue:`10648`).
- Support :kbd:`%` motion (:issue:`10593`).
-:kbd:`ctrl-k` to remove the contents of the line beyond the cursor in all modes (:issue:`10648`).
- Support `ab` and `ib` vi text objects. New input functions are introduced ``jump-{to,till}-matching-bracket`` (:issue:`1842`).
- The :kbd:`E` binding now correctly handles the last character of the word, by jumping to the next word (:issue:`9700`).
Completions
^^^^^^^^^^^
- Command-specific tab completions may now offer results whose first character is a period. For example, it is now possible to tab-complete ``git add`` for files with leading periods. The default file completions hide these files, unless the token itself has a leading period (:issue:`3707`).
- Option completion now uses fuzzy subsequence filtering, just like non-option completion (:issue:`830`).
This means that ``--fb`` may be completed to ``--foobar`` if there is no better match.
- Completions that insert an entire token now use quotes instead of backslashes to escape special characters (:issue:`5433`).
- Normally, file name completions start after the last ``:`` or ``=`` in a token.
This helps commands like ``rsync --files-from=``.
This special meaning can now disabled by escaping these separators as ``\:`` and ``\=``.
This matches Bash's behavior.
Note that this escaping is usually not necessary since the completion engine already tries
to guess whether the separator is actually part of a file name.
- Various new completion scripts and numerous updates to existing ones.
- Completions could hang if the ``PAGER`` environment variable was sent to certain editors on macOS, FreeBSD and some other platforms. This has been fixed (:issue:`10820`).
- Generated completions are now stored in ``$XDG_CACHE_HOME/fish`` or ``~/.cache/fish`` by default (:issue:`10369`)
- A regression in fish 3.1, where completing a command line could change it completely, has been fixed (:issue:`10904`).
Improved terminal support
^^^^^^^^^^^^^^^^^^^^^^^^^
- fish now marks the prompt and command-output regions (via OSC 133) to enable terminal shell integration (:issue:`10352`).
Shell integration shortcuts can scroll to the next/previous prompt or show the last command output in a pager.
- fish now reports the working directory (via OSC 7) unconditionally instead of only for some terminals (:issue:`9955`).
- fish now sets the terminal window title (via OSC 0) unconditionally instead of only for some terminals (:issue:`10037`).
- Focus reporting in tmux is no longer disabled on the first prompt.
- Focus reporting is now disabled during commands run inside key bindings (:issue:`6942`).
- Cursor changes are applied to all terminals that support them, and the list of specifically-supported terminals has been removed (:issue:`10693`).
- If it cannot find the terminfo entry given by :envvar:`TERM` environment variable, fish will now use an included ``xterm-256color`` definition to match the vast majority of current terminal emulators (:issue:`10905`). If you need to have a specific terminfo profile for your terminal's ``TERM`` variable, install it into the terminfo database.
- Further improvements to the correct display of prompts which fill the width of the terminal (:issue:`8164`).
Other improvements
------------------
-``status`` gained a ``buildinfo`` subcommand, to print information on how fish was built, to help with debugging (:issue:`10896`).
-``fish_indent`` will now collapse multiple empty lines into one (:issue:`10325`).
-``fish_indent`` now preserves the modification time of files if there were no changes (:issue:`10624`).
- Performance in launching external processes has been improved for many cases (:issue:`10869`).
- Performance and interactivity under Windows Subsystem for Linux has been improved, with a workaround for Windows-specific locations being appended to ``$PATH`` by default (:issue:`10506`).
- On macOS, paths from ``/etc/paths`` and ``/etc/manpaths`` containing colons are handled correctly (:issue:`10684`).
- Additional filesystems such as AFS are properly detected as remote, which avoids certain hangs due to expensive filesystem locks (:issue:`10818`).
- A spurious error when launching multiple instances of fish for the first time has been removed (:issue:`10813`).
.._rust-packaging:
For distributors
----------------
fish has been ported to Rust. This means a significant change in dependencies, which are listed in the README. In short, Rust 1.70 or greater is required, and a C++ compiler is no longer needed (although a C compiler is still required, for some C glue code and the tests).
CMake remains the recommended build system, because of cargo's limited support for installing support files. Version 3.5 remains the minimum supported version. The Xcode generator for CMake is not supported any longer (:issue:`9924`). CMake builds default to optimized release builds (:issue:`10799`).
fish no longer depends on the ncurses library, but still uses a terminfo database. When packaging fish, please add a dependency on the package containing your terminfo database instead of curses.
The ``test`` target was removed as it can no longer be defined in new CMake versions. Use ``make fish_run_tests``. Any existing test target will not print output if it fails (:issue:`11116`).
The Web-based configuration has been rewritten to use Alpine.js (:issue:`9554`).
--------------
fish 4.0b1 (released December 17, 2024)
=======================================
A number of improvements were included in fish 4.0.0 following the beta release of 4.0b1. These include fixes for regressions, improvements to completions and documentation, and the removal of a small number of problematic changes.
The full list of fixed issues can be found on the `GitHub milestone page for 4.0-final <https://github.com/fish-shell/fish-shell/milestone/43>`_.
--------------
fish 3.7.1 (released March 19, 2024)
====================================
This release of fish fixes the following problems identified in fish 3.7.0:
- Deleting the last history entry via ``history delete`` works again (:issue:`10190`).
- Wildcards (``*``) will no longer sometimes generate paths that did not exist (:issue:`10205`).
This release also contains some improvements:
- A crash when trying to run an ELF program with a missing interpreter has been fixed. This crashed in the process after fork, so did not affect the fish process that tried to start the program (:issue:`10199`).
-``funced`` will now always ``source`` the file after it has written it, even if the contents did not change. This prevents issues if the file was otherwise modified (:issue:`10318`).
- The warning for when a builtin returns a negative exit code was improved, now mentioning the original status (:issue:`10187`).
- Added completions for
-``cobra-cli`` (:issue:`10293`)
-``dmidecode`` (:issue:`10368`)
-``mycli`` (:issue:`10309`)
-``ollama`` (:issue:`10327`)
-``pstree`` (:issue:`10317`)
- Some improvements to documentation and completions.
--------------
fish 3.7.0 (released January 1, 2024)
=====================================
@@ -8,7 +444,7 @@ Notable improvements and fixes
- Improvements to the history pager, including:
- The history pager will now also attempt subsequence matches (:issue:`9476`), so you can find a command line like ``git log 3.6.1..Integration_3.7.0`` by searching for ``gitInt``.
- Opening the history pager will now fill the search field with a search string if you're already in a search (:issue:`10005`). This makes it nicer to search something with :kbd:`↑` and then later decide to switch to the full pager.
- Opening the history pager will now fill the search field with a search string if you're already in a search (:issue:`10005`). This makes it nicer to search something with :kbd:`up` and then later decide to switch to the full pager.
- Closing the history pager with enter will now copy the search text to the commandline if there was no match, so you can continue editing the command you tried to find right away (:issue:`9934`).
- Performance improvements for command completions and globbing, where supported by the operating system, especially on slow filesystems such as NFS (:issue:`9891`, :issue:`9931`, :issue:`10032`, :issue:`10052`).
@@ -38,21 +474,21 @@ Interactive improvements
- Vi mode now uses :envvar:`fish_cursor_external` to set the cursor shape for external commands (:issue:`4656`).
- Opening the history search in vi mode switches to insert mode correctly (:issue:`10141`).
- Vi mode cursor shaping is now enabled in iTerm2 (:issue:`9698`).
- Working directory reporting is enabled for iTerm2 (:issue:`9955`).
- Completing commands as root includes commands not owned by root, fixing a regression introduced in fish 3.2.0 (:issue:`9699`).
- Selection uses ``fish_color_selection`` for the foreground and background colors, as intended, rather than just the background (:issue:`9717`).
- The completion pager will no longer sometimes skip the last entry when moving through a long list (:issue:`9833`).
- The interactive ``history delete`` interface now allows specifying index ranges like "1..5" (:issue:`9736`), and ``history delete --exact`` now properly saves the history (:issue:`10066`).
- Command completion will now call the stock ``manpath`` on macOS, instead of a potential Homebrew version. This prevents awkward error messages (:issue:`9817`).
-A new bind function ``history-pager-delete``, bound to :kbd:`Shift` + :kbd:`Delete` by default, will delete the currently-selected history pager item from history (:issue:`9454`).
-the ``redo`` special input function restores the pre-undo cursor position.
- A new bind function ``history-pager-delete``, bound to :kbd:`shift-delete` by default, will delete the currently-selected history pager item from history (:issue:`9454`).
-``fish_key_reader`` will now use printable characters as-is, so pressing "ö" no longer leads to it telling you to bind ``\u00F6`` (:issue:`9986`).
-``open`` can be used to launch terminal programs again, as an ``xdg-open`` bug has been fixed and a workaround has been removed (:issue:`10045`).
- The ``repaint-mode`` binding will now only move the cursor if there is repainting to be done. This fixes :kbd:`Alt` combination bindings in vi mode (:issue:`7910`).
- A new ``clear-screen`` bind function is used for :kbd:`Ctrl` + :kbd:`l` by default. This clears the screen and repaints the existing prompt at first,
- The ``repaint-mode`` binding will now only move the cursor if there is repainting to be done. This fixes :kbd:`alt` combination bindings in vi mode (:issue:`7910`).
- A new ``clear-screen`` bind function is used for :kbd:`ctrl-l` by default. This clears the screen and repaints the existing prompt at first,
so it eliminates visible flicker unless the terminal is very slow (:issue:`10044`).
- The ``alias`` convenience function has better support for commands with unusual characters, like ``+`` (:issue:`8720`).
- A longstanding issue where items in the pager would sometimes display without proper formatting has been fixed (:issue:`9617`).
- The :kbd:`Alt` + :kbd:`l` binding, which lists the directory of the token under the cursor, correctly expands tilde (``~``) to the home directory (:issue:`9954`).
- The :kbd:`alt-l` binding, which lists the directory of the token under the cursor, correctly expands tilde (``~``) to the home directory (:issue:`9954`).
- Various fish utilities that use an external pager will now try a selection of common pagers if the :envvar:`PAGER` environment variable is not set, or write the output to the screen without a pager if there is not one available (:issue:`10074`).
- Command-specific tab completions may now offer results whose first character is a period. For example, it is now possible to tab-complete ``git add`` for files with leading periods. The default file completions hide these files, unless the token itself has a leading period (:issue:`3707`).
@@ -156,6 +592,7 @@ This release of fish contains a number of fixes for problems identified in fish
Notable improvements and fixes
------------------------------
-``abbr --erase`` now also erases the universal variables used by the old abbr function. That means::
abbr --erase (abbr --list)
can now be used to clean out all old abbreviations (:issue:`9468`).
@@ -178,10 +615,10 @@ Interactive improvements
- Variables that were set while the locale was C (the default ASCII-only locale) will now properly be encoded if the locale is switched (:issue:`2613`, :issue:`9473`).
- Escape during history search restores the original command line again (fixing a regression in 3.6.0).
- Using ``--help`` on builtins now respects the ``$MANPAGER`` variable, in preference to ``$PAGER`` (:issue:`9488`).
-:kbd:`Control-G` closes the history pager, like other shells (:issue:`9484`).
-:kbd:`ctrl-g` closes the history pager, like other shells (:issue:`9484`).
- The documentation for the ``:``, ``[`` and ``.`` builtin commands can now be looked up with ``man`` (:issue:`9552`).
- fish no longer crashes when searching history for non-ASCII codepoints case-insensitively (:issue:`9628`).
- The :kbd:`Alt-S` binding will now also use ``please`` if available (:issue:`9635`).
- The :kbd:`alt-s` binding will now also use ``please`` if available (:issue:`9635`).
- Themes that don't specify every color option can be installed correctly in the Web-based configuration (:issue:`9590`).
- Compatibility with Midnight Commander's prompt integration has been improved (:issue:`9540`).
- A spurious error, noted when using fish in Google Drive directories under WSL 2, has been silenced (:issue:`9550`).
@@ -227,8 +664,8 @@ fish 3.6.0 (released January 7, 2023)
Notable improvements and fixes
------------------------------
- By default, :kbd:`Control-R` now opens the command history in the pager (:issue:`602`). This is fully searchable and syntax-highlighted, as an alternative to the incremental search seen in other shells. The new special input function ``history-pager`` has been added for custom bindings.
- Abbrevations are more flexible (:issue:`9313`, :issue:`5003`, :issue:`2287`):
- By default, :kbd:`ctrl-r` now opens the command history in the pager (:issue:`602`). This is fully searchable and syntax-highlighted, as an alternative to the incremental search seen in other shells. The new special input function ``history-pager`` has been added for custom bindings.
- Abbreviations are more flexible (:issue:`9313`, :issue:`5003`, :issue:`2287`):
- They may optionally replace tokens anywhere on the command line, instead of only commands
- Matching tokens may be described using a regular expression instead of a literal word
@@ -323,15 +760,15 @@ Interactive improvements
- If the terminal definition for :envvar:`TERM` can't be found, fish now tries using the "xterm-256color" and "xterm" definitions before "ansi" and "dumb". As the majority of terminal emulators in common use are now more or less xterm-compatible (often even explicitly claiming the xterm-256color entry), this should often result in a fully or almost fully usable terminal (:issue:`9026`).
- A new variable, :envvar:`fish_cursor_selection_mode`, can be used to configure whether the command line selection includes the character under the cursor (``inclusive``) or not (``exclusive``). The new default is ``exclusive``; use ``set fish_cursor_selection_mode inclusive`` to get the previous behavior back (:issue:`7762`).
- fish's completion pager now fills half the terminal on first tab press instead of only 4 rows, which should make results visible more often and save key presses, without constantly snapping fish to the top of the terminal (:issue:`9105`, :issue:`2698`).
- The ``complete-and-search`` binding, used with :kbd:`Shift-Tab` by default, selects the first item in the results immediately (:issue:`9080`).
-``bind`` output is now syntax-highlighted when used interacively.
-:kbd:`Alt-H` (the default ``__fish_man_page`` binding) does a better job of showing the manual page of the command under cursor (:issue:`9020`).
- The ``complete-and-search`` binding, used with :kbd:`shift-tab` by default, selects the first item in the results immediately (:issue:`9080`).
-``bind`` output is now syntax-highlighted when used interactively.
-:kbd:`alt-h` (the default ``__fish_man_page`` binding) does a better job of showing the manual page of the command under cursor (:issue:`9020`).
- If :envvar:`fish_color_valid_path` contains an actual color instead of just modifiers, those will be used for valid paths even if the underlying color isn't "normal" (:issue:`9159`).
- The key combination for the QUIT terminal sequence, often :kbd:`Control-Backslash` (``\x1c``), can now be sused as a binding (:issue:`9234`).
- The key combination for the QUIT terminal sequence, often :kbd:`ctrl-\\` (``\x1c``), can now be used as a binding (:issue:`9234`).
- fish's vi mode uses normal xterm-style sequences to signal cursor change, instead of using the iTerm's proprietary escape sequences. This allows for a blinking cursor and makes it work in complicated scenarios with nested terminals. (:issue:`3741`, :issue:`9172`)
- When running fish on a remote system (such as inside SSH or a container), :kbd:`Control-X` now copies to the local client system's clipboard if the terminal supports OSC 52.
- When running fish on a remote system (such as inside SSH or a container), :kbd:`ctrl-x` now copies to the local client system's clipboard if the terminal supports OSC 52.
-``commandline`` gained two new options, ``--selection-start`` and ``--selection-end``, to set the start/end of the current selection (:issue:`9197`, :issue:`9215`).
- fish's builtins now handle keyboard interrupts (:kbd:`Control-C`) correctly (:issue:`9266`).
- fish's builtins now handle keyboard interrupts (:kbd:`ctrl-c`) correctly (:issue:`9266`).
Completions
^^^^^^^^^^^
@@ -441,9 +878,9 @@ This release of fish introduces the following small enhancements:
This release also fixes a number of problems identified in fish 3.5.0.
- Completing ``git blame`` or ``git -C`` works correctly (:issue:`9053`).
- On terminals that emit a ``CSI u`` sequence for :kbd:`Shift-Space`, fish inserts a space instead of printing an error. (:issue:`9054`).
- On terminals that emit a ``CSI u`` sequence for :kbd:`shift-space`, fish inserts a space instead of printing an error. (:issue:`9054`).
-``status fish-path`` on Linux-based platforms could print the path with a " (deleted)" suffix (such as ``/usr/bin/fish (deleted)``), which is now removed (:issue:`9019`).
- Cancelling an initial command (from fish's ``--init-command`` option) with :kbd:`Control-C` no longer prevents configuration scripts from running (:issue:`9024`).
- Cancelling an initial command (from fish's ``--init-command`` option) with :kbd:`ctrl-c` no longer prevents configuration scripts from running (:issue:`9024`).
- The job summary contained extra blank lines if the prompt used multiple lines, which is now fixed (:issue:`9044`).
- Using special input functions in bindings, in combination with ``and``/``or`` conditionals, no longer crashes (:issue:`9051`).
@@ -541,7 +978,7 @@ Interactive improvements
- The ``vared`` command can now successfully edit variables named "tmp" or "prompt" (:issue:`8836`, :issue:`8837`).
-``time`` now emits an error if used after the first command in a pipeline (:issue:`8841`).
-``fish_add_path`` now prints a message for skipped non-existent paths when using the ``-v`` flag (:issue:`8884`).
- Since fish 3.2.0, pressing :kbd:`Control-D` while a command is running would end up inserting a space into the next commandline, which has been fixed (:issue:`8871`).
- Since fish 3.2.0, pressing :kbd:`ctrl-d` while a command is running would end up inserting a space into the next commandline, which has been fixed (:issue:`8871`).
- A bug that caused multi-line prompts to be moved down a line when pasting or switching modes has been fixed (:issue:`3481`).
- The Web-based configuration system no longer strips too many quotes in the abbreviation display (:issue:`8917`, :issue:`8918`).
- Fish started with ``--no-config`` will now use the default keybindings (:issue:`8493`)
@@ -552,10 +989,10 @@ Interactive improvements
New or improved bindings
^^^^^^^^^^^^^^^^^^^^^^^^
- The :kbd:`Alt-S` binding will now insert ``doas`` instead of ``sudo`` if necessary (:issue:`8942`).
- The ``kill-whole-line`` special input function now kills the newline preceeding the last line. This makes ``dd`` in vi-mode clear the last line properly.
- The :kbd:`alt-s` binding will now insert ``doas`` instead of ``sudo`` if necessary (:issue:`8942`).
- The ``kill-whole-line`` special input function now kills the newline preceding the last line. This makes ``dd`` in vi-mode clear the last line properly.
- The new ``kill-inner-line`` special input function kills the line without any newlines, allowing ``cc`` in vi-mode to clear the line while preserving newlines (:issue:`8983`).
- On terminals that emit special sequences for these combinations, :kbd:`Shift-Space` is bound like :kbd:`Space`, and :kbd:`Ctrl-Return` is bound like :kbd:`Return` (:issue:`8874`).
- On terminals that emit special sequences for these combinations, :kbd:`shift-space` is bound like :kbd:`space`, and :kbd:`ctrl-enter` is bound like :kbd:`return` (:issue:`8874`).
Improved prompts
^^^^^^^^^^^^^^^^
@@ -601,7 +1038,7 @@ This release of fish fixes the following problems identified in fish 3.4.0:
- An error printed after upgrading, where old instances could pick up a newer version of the ``fish_title`` function, has been fixed (:issue:`8778`)
- fish builds correctly on NetBSD (:issue:`8788`) and OpenIndiana (:issue:`8780`).
-``nextd-or-forward-word``, bound to :kbd:`Alt-Right Arrow` by default, was inadvertently changed to move like ``forward-bigword``. This has been corrected (:issue:`8790`).
-``nextd-or-forward-word``, bound to :kbd:`alt-right` by default, was inadvertently changed to move like ``forward-bigword``. This has been corrected (:issue:`8790`).
-``funcsave -q`` and ``funcsave --quiet`` now work correctly (:issue:`8830`).
- Issues with the ``csharp`` and ``nmcli`` completions were corrected.
@@ -662,7 +1099,7 @@ Deprecations and removed features
> set -Ua fish_features ampersand-nobg-in-token
-``$status`` is now forbidden as a command, to prevent a surprisingly common error among new users: Running ``if $status`` (:issue:`8171`). This applies *only* to ``$status``, other variables are still allowed.
-``set --query`` now returns an exit status of 255 if given no variable names. This means ``if set -q $foo`` will not enter the if-block if ``$foo`` is empty or unset. To restore the previous behavior, use ``if not set -q foo; or set -q $foo`` - but this is unlikely to be desireable (:issue:`8214`).
-``set --query`` now returns an exit status of 255 if given no variable names. This means ``if set -q $foo`` will not enter the if-block if ``$foo`` is empty or unset. To restore the previous behavior, use ``if not set -q foo; or set -q $foo`` - but this is unlikely to be desirable (:issue:`8214`).
-``_`` is now a reserved keyword (:issue:`8342`).
- The special input functions ``delete-or-exit``, ``nextd-or-forward-word`` and ``prevd-or-backward-word`` replace fish functions of the same names (:issue:`8538`).
- Mac OS X 10.9 is no longer supported. The minimum Mac version is now 10.10 "Yosemite."
@@ -685,7 +1122,7 @@ Scripting improvements
-``commandline`` gained a ``--paging-full-mode`` option to check if the pager is showing all the possible lines (no "7 more rows" message) (:issue:`8485`).
- List expansion correctly reports an error when used with all zero indexes (:issue:`8213`).
- Running ``fish`` with a directory instead of a script as argument (eg ``fish .``) no longer leads to an infinite loop. Instead it errors out immediately (:issue:`8258`)
- Some error messages occuring after fork, like "text file busy" have been replaced by bespoke error messages for fish (like "File is currently open for writing"). This also restores error messages with current glibc versions that removed sys_errlist (:issue:`8234`, :issue:`4183`).
- Some error messages occurring after fork, like "text file busy" have been replaced by bespoke error messages for fish (like "File is currently open for writing"). This also restores error messages with current glibc versions that removed sys_errlist (:issue:`8234`, :issue:`4183`).
- The ``realpath`` builtin now also squashes leading slashes with the ``--no-symlinks`` option (:issue:`8281`).
- When trying to ``cd`` to a dangling (broken) symbolic link, fish will print an error noting that the target is a broken link (:issue:`8264`).
- On MacOS terminals that are not granted permissions to access a folder, ``cd`` would print a spurious "rotten symlink" error, which has been corrected to "permission denied" (:issue:`8264`).
@@ -707,10 +1144,10 @@ Scripting improvements
Interactive improvements
------------------------
- Vi mode cursors are now set properly after :kbd:`Control-C` (:issue:`8125`).
- Vi mode cursors are now set properly after :kbd:`ctrl-c` (:issue:`8125`).
-``funced`` will try to edit the whole file containing a function definition, if there is one (:issue:`391`).
- Running a command line consisting of just spaces now deletes an ephemeral (starting with space) history item again (:issue:`8232`).
- Command substitutions no longer respect job control, instead running inside fish's own process group (:issue:`8172`). This more closely matches other shells, and improves :kbd:`Control-C` reliability inside a command substitution.
- Command substitutions no longer respect job control, instead running inside fish's own process group (:issue:`8172`). This more closely matches other shells, and improves :kbd:`ctrl-c` reliability inside a command substitution.
-``history`` and ``__fish_print_help`` now properly support ``less`` before version 530, including the version that ships with macOS. (:issue:`8157`).
-``help`` now knows which section is in which document again (:issue:`8245`).
- fish's highlighter will now color options (starting with ``-`` or ``--``) with the color given in the new $fish_color_option, up to the first ``--``. It falls back on $fish_color_param, so nothing changes for existing setups (:issue:`8292`).
@@ -723,7 +1160,7 @@ Interactive improvements
- Propagation of universal variables from a fish process that is closing is faster (:issue:`8209`).
- The command line is drawn in the correct place if the prompt ends with a newline (:issue:`8298`).
-``history`` learned a new subcommand ``clear-session`` to erase all history from the current session (:issue:`5791`).
- Pressing :kbd:`Control-C` in ``fish_key_reader`` will no longer print the incorrect "Press [ctrl-C] again to exit" message (:issue:`8510`).
- Pressing :kbd:`ctrl-c` in ``fish_key_reader`` will no longer print the incorrect "Press [ctrl-C] again to exit" message (:issue:`8510`).
- The default command-not-found handler for Fedora/PackageKit now passes the whole command line, allowing for functionality such as running the suggested command directly (:issue:`8579`).
- When looking for locale information, the Debian configuration is now used when available (:issue:`8557`).
- Pasting text containing quotes from the clipboard trims spaces more appropriately (:issue:`8550`).
@@ -736,8 +1173,8 @@ Interactive improvements
New or improved bindings
^^^^^^^^^^^^^^^^^^^^^^^^
-:kbd:`Escape` can now bound without breaking arrow key bindings (:issue:`8428`).
- The :kbd:`Alt-H` binding (to open a command’s manual page) now also ignores ``command`` (:issue:`8447`).
-:kbd:`escape` can now bound without breaking arrow key bindings (:issue:`8428`).
- The :kbd:`alt-h` binding (to open a command’s manual page) now also ignores ``command`` (:issue:`8447`).
Improved prompts
^^^^^^^^^^^^^^^^
@@ -803,7 +1240,7 @@ Improved terminal support
- Vi mode cursors are enabled in Apple Terminal.app (:issue:`8167`).
- Vi cursor shaping and $PWD reporting is now also enabled on foot (:issue:`8422`).
-``ls`` will use colors also on newer versions of Apple Terminal.app (:issue:`8309`).
- The :kbd:`Delete` and :kbd:`Shift-Tab` keys work more reliably under ``st`` (:issue:`8352`, :issue:`8354`).
- The :kbd:`delete` and :kbd:`shift-tab` keys work more reliably under ``st`` (:issue:`8352`, :issue:`8354`).
Other improvements
------------------
@@ -830,7 +1267,7 @@ This release of fish fixes the following problems identified in fish 3.3.0:
- The prompt and command line are redrawn correctly in response to universal variable changes (:issue:`8088`).
- A superfluous error that was produced when setting the ``PATH`` or ``CDPATH`` environment variables to include colon-delimited components that do not exist was removed (:issue:`8095`).
- The Vi mode indicator in the prompt is repainted correctly after :kbd:`Ctrl-C` cancels the current command (:issue:`8103`).
- The Vi mode indicator in the prompt is repainted correctly after :kbd:`ctrl-c` cancels the current command (:issue:`8103`).
- fish builds correctly on platforms that do not have a ``spawn.h`` header, such as old versions of OS X (:issue:`8097`).
A number of improvements to the documentation, and fixes for completions, are included as well.
@@ -900,15 +1337,15 @@ Interactive improvements
New or improved bindings
^^^^^^^^^^^^^^^^^^^^^^^^
- Pasting in Vi mode puts text in the right place in normal mode (:issue:`7847`).
- Vi mode's :kbd:`u` is bound to ``undo`` instead of ``history-search-backward``, following GNU readline's behavior. Similarly, :kbd:`Control-R` is bound to ``redo`` instead of ``history-search-backward``, following Vim (:issue:`7908`).
- Vi mode's :kbd:`u` is bound to ``undo`` instead of ``history-search-backward``, following GNU readline's behavior. Similarly, :kbd:`ctrl-r` is bound to ``redo`` instead of ``history-search-backward``, following Vim (:issue:`7908`).
-:kbd:`s` in Vi visual mode now does the same thing as :kbd:`c` (:issue:`8039`).
- The binding for :kbd:`"*y` now uses ``fish_clipboard_copy``, allowing it to support more than just ``xsel``.
- The :kbd:`Control-Space` binding can be correctly customised (:issue:`7922`).
- The binding for :kbd:`",*,y` now uses ``fish_clipboard_copy``, allowing it to support more than just ``xsel``.
- The :kbd:`ctrl-space` binding can be correctly customised (:issue:`7922`).
-``exit`` works correctly in bindings (:issue:`7967`).
- The :kbd:`F1` binding, which opens the manual page for the current command, now works around a bug in certain ``less`` versions that fail to clear the screen (:issue:`7863`).
- The binding for :kbd:`Alt-S` now toggles whether ``sudo`` is prepended, even when it took the commandline from history instead of only adding it.
- The :kbd:`f1` binding, which opens the manual page for the current command, now works around a bug in certain ``less`` versions that fail to clear the screen (:issue:`7863`).
- The binding for :kbd:`alt-s` now toggles whether ``sudo`` is prepended, even when it took the commandline from history instead of only adding it.
- The new functions ``fish_commandline_prepend`` and ``fish_commandline_append`` allow toggling the presence of a prefix/suffix on the current commandline. (:issue:`7905`).
-``backward-kill-path-component``:kbd:`Control-W`) no longer erases parts of two tokens when the cursor is positioned immediately after ``/``. (:issue:`6258`).
-``backward-kill-path-component``:kbd:`ctrl-w`) no longer erases parts of two tokens when the cursor is positioned immediately after ``/``. (:issue:`6258`).
Improved prompts
^^^^^^^^^^^^^^^^
@@ -1024,8 +1461,8 @@ Notable improvements and fixes
…h-shell/build (makepkg)>
It is still possible to react to the ``COLUMNS`` variable inside the prompt to implement smarter behavior.
-**fish completes ambiguous completions** after pressing :kbd:`Tab` even when they
have a common prefix, without the user having to press :kbd:`Tab` again
-**fish completes ambiguous completions** after pressing :kbd:`tab` even when they
have a common prefix, without the user having to press :kbd:`tab` again
(:issue:`6924`).
- fish is less aggressive about resetting terminal modes, such as flow control, after every command.
Although flow control remains off by default, enterprising users can now enable it with
@@ -1151,7 +1588,7 @@ Interactive improvements
- The interactive reader now allows ending a line in a logical operators (``&&`` and ``||``) instead of complaining about a missing command. (This was already syntactically valid, but interactive sessions didn't know about it yet).
- The prompt is reprinted after a background job exits (:issue:`1018`).
- fish no longer inserts a space after a completion ending in ``.``, ``,`` or ``-`` is accepted, improving completions for tools that provide dynamic completions (:issue:`6928`).
- If a filename is invalid when first pressing :kbd:`Tab`, but becomes valid, it will be completed properly on the next attempt (:issue:`6863`).
- If a filename is invalid when first pressing :kbd:`tab`, but becomes valid, it will be completed properly on the next attempt (:issue:`6863`).
-``help string match/replace/<subcommand>`` will show the help for string subcommands (:issue:`6786`).
-``fish_key_reader`` sets the exit status to 0 when used with ``--help`` or ``--version`` (:issue:`6964`).
-``fish_key_reader`` and ``fish_indent`` send output from ``--version`` to standard output, matching other fish binaries (:issue:`6964`).
@@ -1188,15 +1625,15 @@ Interactive improvements
When it can't find a command, fish now just executes a function called ``fish_command_not_found``
instead of firing an event, making it easier to replace and reason about.
Previously-defined ``__fish_command_not_found_handler`` functions with an appropriate event listener will still work (:issue:`7293`).
-:kbd:`Control-C` handling has been reimplemented in C++ and is therefore quicker (:issue:`5259`), no longer occasionally prints an "unknown command" error (:issue:`7145`) or overwrites multiline prompts (:issue:`3537`).
-:kbd:`Control-C` no longer kills background jobs for which job control is
-:kbd:`ctrl-c` handling has been reimplemented in C++ and is therefore quicker (:issue:`5259`), no longer occasionally prints an "unknown command" error (:issue:`7145`) or overwrites multiline prompts (:issue:`3537`).
-:kbd:`ctrl-c` no longer kills background jobs for which job control is
- Autosuggestions work properly after :kbd:`Control-C` cancels the current commmand line (:issue:`6937`).
- Autosuggestions work properly after :kbd:`ctrl-c` cancels the current command line (:issue:`6937`).
- History search is now case-insensitive unless the search string contains an uppercase character (:issue:`7273`).
-``fish_update_completions`` gained a new ``--keep`` option, which improves speed by skipping completions that already exist (:issue:`6775`, :issue:`6796`).
- Aliases containing an embedded backslash appear properly in the output of ``alias`` (:issue:`6910`).
-``open`` no longer hangs indefinitely on certain systems, as a bug in ``xdg-open`` has been worked around (:issue:`7215`).
- Long command lines no longer add a blank line after execution (:issue:`6826`) and behave better with :kbd:`Backspace` (:issue:`6951`).
- Long command lines no longer add a blank line after execution (:issue:`6826`) and behave better with :kbd:`backspace` (:issue:`6951`).
-``functions -t`` works like the long option ``--handlers-type``, as documented, instead of producing an error (:issue:`6985`).
- History search now flashes when it found no more results (:issue:`7362`)
- fish now creates the path in the environment variable ``XDG_RUNTIME_DIR`` if it does not exist, before using it for runtime data storage (:issue:`7335`).
@@ -1233,27 +1670,27 @@ Interactive improvements
New or improved bindings
^^^^^^^^^^^^^^^^^^^^^^^^
- As mentioned above, new special input functions ``undo`` (:kbd:`Control+\_` or :kbd:`Control+Z`) and ``redo`` (:kbd:`Alt-/`) can be used to revert changes to the command line or the pager search field (:issue:`6570`).
-:kbd:`Control-Z` is now available for binding (:issue:`7152`).
- Additionally, using the ``cancel`` special input function (bound to :kbd:`Escape` by default) right after fish picked an unambiguous completion will undo that (:issue:`7433`).
-``fish_clipboard_paste`` (:kbd:`Control+V`) trims indentation from multiline commands, because fish already indents (:issue:`7662`).
- As mentioned above, new special input functions ``undo`` (:kbd:`ctrl-_` or :kbd:`ctrl-z`) and ``redo`` (:kbd:`alt-/`) can be used to revert changes to the command line or the pager search field (:issue:`6570`).
-:kbd:`ctrl-z` is now available for binding (:issue:`7152`).
- Additionally, using the ``cancel`` special input function (bound to :kbd:`escape` by default) right after fish picked an unambiguous completion will undo that (:issue:`7433`).
-``fish_clipboard_paste`` (:kbd:`ctrl-v`) trims indentation from multiline commands, because fish already indents (:issue:`7662`).
- Vi mode bindings now support ``dh``, ``dl``, ``c0``, ``cf``, ``ct``, ``cF``, ``cT``, ``ch``, ``cl``, ``y0``, ``ci``, ``ca``, ``yi``, ``ya``, ``di``, ``da``, ``d;``, ``d,``, ``o``, ``O`` and Control+left/right keys to navigate by word (:issue:`6648`, :issue:`6755`, :issue:`6769`, :issue:`7442`, :issue:`7516`).
- Vi mode bindings support :kbd:`~` (tilde) to toggle the case of the selected character (:issue:`6908`).
- Functions ``up-or-search`` and ``down-or-search`` (:kbd:`Up` and :kbd:`Down`) can cross empty lines, and don't activate search mode if the search fails, which makes them easier to use to move between lines in some situations.
- Functions ``up-or-search`` and ``down-or-search`` (:kbd:`up` and :kbd:`down`) can cross empty lines, and don't activate search mode if the search fails, which makes them easier to use to move between lines in some situations.
- If history search fails to find a match, the cursor is no longer moved. This is useful when accidentally starting a history search on a multi-line commandline.
- The special input function ``beginning-of-history`` (:kbd:`Page Up`) now moves to the oldest search instead of the youngest - that's ``end-of-history`` (:kbd:`Page Down`).
- The special input function ``beginning-of-history`` (:kbd:`pageup`) now moves to the oldest search instead of the youngest - that's ``end-of-history`` (:kbd:`pagedown`).
- A new special input function ``forward-single-char`` moves one character to the right, and if an autosuggestion is available, only take a single character from it (:issue:`7217`, :issue:`4984`).
- Special input functions can now be joined with ``or`` as a modifier (adding to ``and``), though only some commands set an exit status (:issue:`7217`). This includes ``suppress-autosuggestion`` to reflect whether an autosuggestion was suppressed (:issue:`1419`)
- A new function ``__fish_preview_current_file``, bound to :kbd:`Alt+O`, opens the
- A new function ``__fish_preview_current_file``, bound to :kbd:`alt-o`, opens the
current file at the cursor in a pager (:issue:`6838`, :issue:`6855`).
-``edit_command_buffer`` (:kbd:`Alt-E` and :kbd:`Alt-V`) passes the cursor position
-``edit_command_buffer`` (:kbd:`alt-e` and :kbd:`alt-v`) passes the cursor position
to the external editor if the editor is recognized (:issue:`6138`, :issue:`6954`).
-``__fish_prepend_sudo`` (:kbd:`Alt-S`) now toggles a ``sudo`` prefix (:issue:`7012`) and avoids shifting the cursor (:issue:`6542`).
-``__fish_prepend_sudo`` (:kbd:`Alt-S`) now uses the previous commandline if the current one is empty,
-``__fish_prepend_sudo`` (:kbd:`alt-s`) now toggles a ``sudo`` prefix (:issue:`7012`) and avoids shifting the cursor (:issue:`6542`).
-``__fish_prepend_sudo`` (:kbd:`alt-s`) now uses the previous commandline if the current one is empty,
to simplify rerunning the previous command with ``sudo`` (:issue:`7079`).
-``__fish_toggle_comment_commandline`` (:kbd:`Alt-#`) now uncomments and presents the last comment
-``__fish_toggle_comment_commandline`` (:kbd:`alt-#`) now uncomments and presents the last comment
from history if the commandline is empty (:issue:`7137`).
-``__fish_whatis_current_token`` (:kbd:`Alt-W`) prints descriptions for functions and builtins (:issue:`7191`, :issue:`2083`).
-``__fish_whatis_current_token`` (:kbd:`alt-w`) prints descriptions for functions and builtins (:issue:`7191`, :issue:`2083`).
- The definition of "word" and "bigword" for movements was refined, fixing (eg) vi mode's behavior with :kbd:`e` on the second-to-last char, and bigword's behavior with single-character words and non-blank non-graphical characters (:issue:`7353`, :issue:`7354`, :issue:`4025`, :issue:`7328`, :issue:`7325`)
- fish's clipboard bindings now also support Windows Subsystem for Linux via PowerShell and clip.exe (:issue:`7455`, :issue:`7458`) and will properly copy newlines in multi-line commands.
- Using the ``*-jump`` special input functions before typing anything else no longer crashes fish.
@@ -1745,7 +2182,7 @@ Interactive improvements
argument.
- Syntax highlighting works correctly with variables as commands
(:issue:`5658`) and redirections to close file descriptors (:issue:`6092`).
-``help`` works properly on Windows Subsytem for Linux (:issue:`5759`, :issue:`6338`).
-``help`` works properly on Windows Subsystem for Linux (:issue:`5759`, :issue:`6338`).
- A bug where ``disown`` could crash the shell has been fixed (:issue:`5720`).
- fish will not autosuggest files ending with ``~`` unless there are no
other candidates, as these are generally backup files (:issue:`985`).
@@ -2345,7 +2782,7 @@ Interactive improvements
key both on its own and as part of a control sequence, was applied to
all control characters; this has been reduced to just the escape key.
- Completing a function shows the description properly (:issue:`5206`).
-`commandline` can now be used to set the commandline for the next command, restoring a behavior in 3.4.1 (:issue:`8807`).
-``commandline`` can now be used to set the commandline for the next command, restoring a behavior in 3.4.1 (:issue:`8807`).
- Added completions for
-``ansible``, including ``ansible-galaxy``, ``ansible-playbook``
@@ -2687,7 +3124,7 @@ Other significant changes
- Some systems’``su`` implementations do not set the ``USER``
environment variable; it is now reset for root users (:issue:`3916`).
- Under terminals which support it, bracketed paste is enabled,
escaping problematic characters for security and convience (:issue:`3871`).
escaping problematic characters for security and convenience (:issue:`3871`).
Inside single quotes (``'``), single quotes and backslashes in pasted
text are escaped (:issue:`967`). The ``fish_clipboard_paste`` function (bound
to ``C-v`` by default) is still the recommended pasting method where
@@ -2816,9 +3253,9 @@ Other significant changes
- fish no longer prints a warning when it identifies a running instance
of an old version (2.1.0 and earlier). Changes to universal variables
may not propagate between these old versions and 2.5b1.
- Improved compatiblity with Android (:issue:`3585`), MSYS/mingw (:issue:`2360`), and
- Improved compatibility with Android (:issue:`3585`), MSYS/mingw (:issue:`2360`), and
Solaris (:issue:`3456`, :issue:`3340`).
- Like other shells, the ``test`` builting now returns an error for
- Like other shells, the ``test`` built-in now returns an error for
numeric operations on invalid integers (:issue:`3346`, :issue:`3581`).
-``complete`` no longer recognises ``--authoritative`` and
``--unauthoritative`` options, and they are marked as obsolete.
@@ -3166,8 +3603,8 @@ Other notable fixes and improvements
- Directory autosuggestions will now descend as far as possible if
there is only one child directory (:issue:`2531`)
- Add support for bright colors (:issue:`1464`)
- Allow Ctrl-J (`\cj`) to be bound separately from Ctrl-M
(`\cm`) (:issue:`217`)
- Allow Ctrl-J (``\cj``) to be bound separately from Ctrl-M
(``\cm``) (:issue:`217`)
- psub now has a “-s”/“–suffix” option to name the temporary file with
that suffix
- Enable 24-bit colors on select terminals (:issue:`2495`)
@@ -3311,7 +3748,7 @@ Other notable fixes and improvements
-``type`` has a new ``-q`` option to suppress output (:issue:`1540` and, like
other shells, ``type -a`` now prints all matches for a command
(:issue:`261`).
- Pressing F1 now shows the manual page for the current command
- Pressing :kbd:`f1` now shows the manual page for the current command
(:issue:`1063`).
-``fish_title`` functions have access to the arguments of the
currently running argument as ``$argv[1]`` (:issue:`1542`).
This will create a copy of the fish repository in the directory fish-shell in your current working directory.
Also, for most changes you want to run the tests and so you'd get a setup to compile fish.
For that, you'll require:
- Rust - when in doubt, try rustup
- CMake
- PCRE2 (headers and libraries) - optional, this will be downloaded if missing
- gettext (headers and libraries) - optional, for translation support
- Sphinx - optional, to build the documentation
Of course not everything is required always - if you just want to contribute something to the documentation you'll just need Sphinx,
and if the change is very simple and obvious you can just send it in. Use your judgement!
Once you have your changes, open a pull request on https://github.com/fish-shell/fish-shell/pulls.
Guidelines
==========
In short:
- Be conservative in what you need (``C++11``, few dependencies)
- Use automated tools to help you (including ``make test``,``build_tools/style.fish`` and ``make lint``)
- Be conservative in what you need (keep to the agreed minimum supported Rust version, limit new dependencies)
- Use automated tools to help you (including ``make fish_run_tests`` and``build_tools/style.fish``)
Contributing completions
------------------------
========================
Completion scripts are the most common contribution to fish, and they are very welcome.
In general, we'll take all well-written completion scripts for a command that is publically available.
In general, we'll take all well-written completion scripts for a command that is publicly available.
This means no private tools or personal scripts, and we do reserve the right to reject for other reasons.
Before you try to contribute them to fish, consider if the authors of the tool you are completing want to maintain the script instead.
@@ -42,57 +77,21 @@ Put your completion script into share/completions/name-of-command.fish. If you h
If you want to add tests, you probably want to add a littlecheck test. See below for details.
Contributing to fish's C++ core
-------------------------------
Contributing documentation
==========================
Fish uses C++11. Newer C++ features should not be used to make it possible to use on older systems.
The documentation is stored in ``doc_src/``, and written in ReStructured Text and built with Sphinx.
It does not use exceptions, they are disabled at build time with ``-fno-exceptions``.
To build it locally, run from the main fish-shell directory::
Don't introduce new dependencies unless absolutely necessary, and if you do,
please make it optional with graceful failure if possible.
Add any new dependencies to the README.rst under the *Running* and/or *Building* sections.
sphinx-build -j 8 -b html -n doc_src/ /tmp/fish-doc/
Linters
-------
which will build the docs as html in /tmp/fish-doc. You can open it in a browser and see that it looks okay.
Automated analysis tools like cppcheck can point out
potential bugs or code that is extremely hard to understand. They also
help ensure the code has a consistent style and that it avoids patterns
that tend to confuse people.
To make linting the code easy there are two make targets: ``lint``,
to lint any modified but not committed ``*.cpp`` files, and
``lint-all`` to lint all files.
Fish has custom cppcheck rules in the file ``.cppcheck.rule``. These
help catch mistakes such as using ``wcwidth()`` rather than
``fish_wcwidth()``. Please add a new rule if you find similar mistakes
being made.
Suppressing Lint Warnings
~~~~~~~~~~~~~~~~~~~~~~~~~
Once in a while the lint tools emit a false positive warning. For
example, cppcheck might suggest a memory leak is present when that is
not the case. To suppress that cppcheck warning you should insert a line
like the following immediately prior to the line cppcheck warned about:
::
// cppcheck-suppress memleak // addr not really leaked
The explanatory portion of the suppression comment is optional. For
other types of warnings replace “memleak” with the value inside the
parenthesis (e.g., “nullPointerRedundantCheck”) from a warning like the
following:
::
[src/complete.cpp:1727]: warning (nullPointerRedundantCheck): Either the condition 'cmd_node' is redundant or there is possible null pointer dereference: cmd_node.
The builtins and various functions shipped with fish are documented in doc_src/cmds/.
Code Style
----------
==========
To ensure your changes conform to the style rules run
@@ -102,7 +101,7 @@ To ensure your changes conform to the style rules run
before committing your change. That will run our autoformatters:
-``git-clang-format`` for c++
-``rustfmt`` for Rust
-``fish_indent`` (shipped with fish) for fish script
-``black`` for python
@@ -122,6 +121,20 @@ If you want to check the style of the entire code base run
That command will refuse to restyle any files if you have uncommitted
changes.
Fish Script Style Guide
-----------------------
1. All fish scripts, such as those in the *share/functions* and *tests*
directories, should be formatted using the ``fish_indent`` command.
2. Function names should be in all lowercase with words separated by
underscores. Private functions should begin with an underscore. The
first word should be ``fish`` if the function is unique to fish.
3. The first word of global variable names should generally be ``fish``
for public vars or ``_fish`` for private vars to minimize the
possibility of name clashes with user defined vars.
Configuring Your Editor for Fish Scripts
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -158,65 +171,13 @@ made to run fish_indent via e.g.
1. All fish scripts, such as those in the *share/functions* and *tests*
directories, should be formatted using the ``fish_indent`` command.
2. Function names should be in all lowercase with words separated by
underscores. Private functions should begin with an underscore. The
first word should be ``fish`` if the function is unique to fish.
3. The first word of global variable names should generally be ``fish``
for public vars or ``_fish`` for private vars to minimize the
possibility of name clashes with user defined vars.
C++ Style Guide
---------------
1. The `Google C++ Style
Guide <https://google.github.io/styleguide/cppguide.html>`__ forms
the basis of the fish C++ style guide. There are two major deviations
for the fish project. First, a four, rather than two, space indent.
Second, line lengths up to 100, rather than 80, characters.
2. The ``clang-format`` command is authoritative with respect to
indentation, whitespace around operators, etc.
3. All names in code should be ``small_snake_case``. No Hungarian
notation is used. The names for classes and structs should be
followed by ``_t``.
4. Always attach braces to the surrounding context.
5. Indent with spaces, not tabs and use four spaces per indent.
6. Document the purpose of a function or class with doxygen-style
comment blocks. e.g.:
::
/**
* Sum numbers in a vector.
*
* @param values Container whose values are summed.
* @return sum of `values`, or 0.0 if `values` is empty.
*/
double sum(std::vector<double> & const values) {
...
}
*/
or
::
/// brief description of somefunction()
void somefunction() {
Use ``cargo fmt`` and ``cargo clippy``. Clippy warnings can be turned off if there's a good reason to.
Testing
-------
=======
The source code for fish includes a large collection of tests. If you
are making any changes to fish, running these tests is a good way to make
@@ -230,28 +191,41 @@ regressions in the future (i.e., we don’t reintroduce the bug).
The tests can be found in three places:
- src/fish_tests.cpp for tests to the core C++ code
- src/tests for unit tests.
- tests/checks for script tests, run by `littlecheck <https://github.com/ridiculousfish/littlecheck>`__
- tests/pexpects for interactive tests using `pexpect <https://pexpect.readthedocs.io/en/stable/>`__
When in doubt, the bulk of the tests should be added as a littlecheck test in tests/checks, as they are the easiest to modify and run, and much faster and more dependable than pexpect tests. The syntax is fairly self-explanatory. It's a fish script with the expected output in ``# CHECK:`` or ``# CHECKERR:`` (for stderr) comments.
If your littlecheck test has a specific dependency, use ``# REQUIRE: ...`` with a posix sh script.
fish_tests.cpp is mostly useful for unit tests - if you wish to test that a function does the correct thing for given input, use it.
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.
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.
These tests can be run via the tests/test_driver.py python script, which will set up the environment.
It sets up a temporary $HOME and also uses it as the current directory, so you do not need to create a temporary directory in them.
If you need a command to do something weird to test something, maybe add it to the ``fish_test_helper`` binary (in tests/fish_test_helper.c), or see if it can already do it.
Local testing
~~~~~~~~~~~~~
-------------
The tests can be run on your local computer on all operating systems.
::
cmake path/to/fish-shell
make test
make fish_run_tests
Or you can run them on a fish, without involving cmake::
cargo build
cargo test # for the unit tests
tests/test_driver.py target/debug # for the script and interactive tests
Here, the first argument to test_driver.py refers to a directory with ``fish``, ``fish_indent`` and ``fish_key_reader`` in it.
In this example we're in the root of the git repo and have run ``cargo build`` without ``--release``, so it's a debug build.
Git hooks
~~~~~~~~~
---------
Since developers sometimes forget to run the tests, it can be helpful to
use git hooks (see githooks(5)) to automate it.
@@ -276,7 +250,7 @@ One possibility is a pre-push hook script like this one:
done
if["x$isprotected"= x1 ];then
echo"Running tests before push to master"
make test
make fish_run_tests
RESULT=$?
if[$RESULT -ne 0];then
echo"Tests failed for a push to master, we can't let you do that" >&2
@@ -286,7 +260,7 @@ One possibility is a pre-push hook script like this one:
exit0
This will check if the push is to the master branch and, if it is, only
allow the push if running ``make test`` succeeds. In some circumstances
allow the push if running ``make fish_run_tests`` succeeds. In some circumstances
it may be advisable to circumvent this check with
``git push --no-verify``, but usually that isn’t necessary.
@@ -294,7 +268,7 @@ To install the hook, place the code in a new file
``.git/hooks/pre-push`` and make it executable.
Coverity Scan
~~~~~~~~~~~~~
-------------
We use Coverity’s static analysis tool which offers free access to open
source projects. While access to the tool itself is restricted,
@@ -304,56 +278,106 @@ with their GitHub account. Currently, tests are triggered upon merging
the ``master`` branch into ``coverity_scan_master``. Even if you are not
a fish developer, you can keep an eye on our statistics there.
Installing the Required Tools
-----------------------------
Installing the Linting Tools
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To install the lint checkers on Mac OS X using Homebrew:
::
brew install cppcheck
To install the lint checkers on Debian-based Linux distributions:
::
sudo apt-get install clang
sudo apt-get install cppcheck
Installing the Formatting Tools
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Mac OS X:
::
brew install clang-format
Debian-based:
::
sudo apt-get install clang-format
Message Translations
--------------------
Contributing Translations
=========================
Fish uses the GNU gettext library to translate messages from English to
other languages.
Translation sources are
stored in the ``po`` directory, named ``LANG.po``, where ``LANG`` is the
two letter ISO 639-1 language code of the target language (e.g. ``de`` for
German). A region specifier can also be used (e.g. ``pt_BR`` for Brazilian Portuguese).
Adding translations for a new language
--------------------------------------
Creating new translations requires the Gettext tools.
More specifically, you will need ``msguniq`` and ``msgmerge`` for creating translations for a new
language.
To create a new translation, run::
build_tools/update_translations.fish po/LANG.po
By default, this also creates ``mo`` files, which contain the information from the ``po`` files in a
binary format.
Fish uses these files for translating at runtime.
They are not tracked in version control, but they can help translators check if their translations
show up correctly.
If you build fish locally (``cargo build``), and then run the resulting binary,
it will make use of the ``mo`` files generated by the script.
Use the ``LANG`` environment variable to tell fish which language to use, e.g.::
LANG=pt_BR.utf8 target/debug/fish
If you do not care about the ``mo`` files you can pass the ``--no-mo`` flag to the
``update_translations.fish`` script.
Modifying existing translations
-------------------------------
If you want to work on translations for a language which already has a corresponding ``po`` file, it
is sufficient to edit this file. No other changes are necessary.
to update the binary ``mo`` used by fish. Check the information for adding new languages for a
description on how you can get fish to use these files.
Running this script requires a fish executable and the gettext ``msgfmt`` tool.
Editing PO files
----------------
Many tools are available for editing translation files, including
command-line and graphical user interface programs. For simple use, you can use your text editor.
Open up the po file, for example ``po/sv.po``, and you'll see something like::
msgid "%ls: No suitable job\n"
msgstr ""
The ``msgid`` here is the "name" of the string to translate, typically the English string to translate.
The second line (``msgstr``) is where your translation goes.
For example::
msgid "%ls: No suitable job\n"
msgstr "%ls: Inget passande jobb\n"
Any ``%s`` / ``%ls`` or ``%d`` are placeholders that fish will use for formatting at runtime. It is important that they match - the translated string should have the same placeholders in the same order.
Also any escaped characters, like that ``\n`` newline at the end, should be kept so the translation has the same behavior.
Our tests run ``msgfmt --check-format /path/to/file``, so they would catch mismatched placeholders - otherwise fish would crash at runtime when the string is about to be used.
Be cautious about blindly updating an existing translation file.
``msgid`` strings should never be updated manually, only by running the appropriate script.
Modifications to strings in source files
----------------------------------------
If a string changes in the sources, the old translations will no longer work.
They will be preserved in the ``po`` files, but commented-out (starting with ``#~``).
If you add/remove/change a translatable strings in a source file,
run ``build_tools/update_translations.fish`` to propagate this to all translation files (``po/*.po``).
This is only relevant for developers modifying the source files of fish or fish scripts.
Setting Code Up For Translations
--------------------------------
All non-debug messages output for user consumption should be marked for
translation. In C++, this requires the use of the ``_`` (underscore)
macro:
translation. In Rust, this requires the use of the ``wgettext!`` or ``wgettext_fmt!``
macros:
::
streams.out.append_format(_(L"%ls: There are no jobs\n"), argv[0]);
streams.out.append(wgettext_fmt!("%ls: There are no jobs\n", argv[0]));
All messages in fish script must be enclosed in single or double quote
characters. They must also be translated via a subcommand. This means
characters for our message extraction script to find them.
They must also be translated via a command substitution. This means
that the following are **not** valid:
::
@@ -368,82 +392,15 @@ Above should be written like this instead:
echo (_ "hello")
echo (_ "goodbye")
Note that you can use either single or double quotes to enclose the
You can use either single or double quotes to enclose the
message to be translated. You can also optionally include spaces after
the opening parentheses and once again before the closing parentheses.
Creating and updating translations requires the Gettext tools, including
``xgettext``, ``msgfmt`` and ``msgmerge``. Translation sources are
stored in the ``po`` directory, named ``LANG.po``, where ``LANG`` is the
two letter ISO 639-1 language code of the target language (eg ``de`` for
German).
To create a new translation, for example for German:
* generate a ``messages.pot`` file by running ``build_tools/fish_xgettext.fish`` from
the source tree
* copy ``messages.pot`` to ``po/LANG.po``
To update a translation:
* generate a ``messages.pot`` file by running
``build_tools/fish_xgettext.fish`` from the source tree
@@ -168,64 +146,53 @@ To install into ``/usr/local``, run:
mkdir build;cd build
cmake ..
make
sudo make install
cmake --build .
sudo cmake --install .
The install directory can be changed using the
``-DCMAKE_INSTALL_PREFIX`` parameter for ``cmake``.
Building from source (macOS) - Xcode
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CMake Build options
~~~~~~~~~~~~~~~~~~~
Note: The minimum supported macOS version is 10.10 "Yosemite".
In addition to the normal CMake build options (like ``CMAKE_INSTALL_PREFIX``), fish's CMake build has some other options available to customize it.
..code::bash
mkdir build;cd build
cmake .. -G Xcode
An Xcode project will now be available in the ``build`` subdirectory.
You can open it with Xcode, or run the following to build and install in
``/usr/local``:
..code::bash
xcodebuild
xcodebuild -scheme install
The install directory can be changed using the
``-DCMAKE_INSTALL_PREFIX`` parameter for ``cmake``.
Build options
~~~~~~~~~~~~~
In addition to the normal cmake build options (like ``CMAKE_INSTALL_PREFIX``), fish has some other options available to customize it.
- BUILD_DOCS=ON|OFF - whether to build the documentation. This is automatically set to OFF when sphinx isn't installed.
- Rust_COMPILER=path - the path to rustc. If not set, cmake will check $PATH and ~/.cargo/bin
- Rust_CARGO=path - the path to cargo. If not set, cmake will check $PATH and ~/.cargo/bin
- Rust_CARGO_TARGET=target - the target to pass to cargo. Set this for cross-compilation.
- BUILD_DOCS=ON|OFF - whether to build the documentation. This is automatically set to OFF when Sphinx isn't installed.
- INSTALL_DOCS=ON|OFF - whether to install the docs. This is automatically set to on when BUILD_DOCS is or prebuilt documentation is available (like when building in-tree from a tarball).
- FISH_USE_SYSTEM_PCRE2=ON|OFF - whether to use an installed pcre2. This is normally autodetected.
- MAC_CODESIGN_ID=String|OFF - the codesign ID to use on Mac, or "OFF" to disable codesigning.
- WITH_GETTEXT=ON|OFF - whether to build with gettext support for translations.
- extra_functionsdir, extra_completionsdir and extra_confdir - to compile in an additional directory to be searched for functions, completions and configuration snippets
Note that fish does *not* support static linking and will attempt to error out if it detects it.
Building fish with embedded data (experimental)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Help, it didn’t build!
~~~~~~~~~~~~~~~~~~~~~~
You can also build fish with the data files embedded.
If fish reports that it could not find curses, try installing a curses
development package and build again.
This will include all the datafiles like the included functions or web configuration tool in the main ``fish`` binary.
On Debian or Ubuntu you want:
Fish will then read these right from its own binary, and print them out when needed. Some files, like the webconfig tool and the manpage completion generator, will be extracted to a temporary directory on-demand. You can list the files with ``status list-files`` and print one with ``status get-file path/to/file`` (e.g. ``status get-file functions/fish_prompt.fish`` to get the default prompt).
::
To install fish with embedded files, just use ``cargo``, like::
cargo install --path /path/to/fish # if you have a git clone
cargo install --git https://github.com/fish-shell/fish-shell --tag 4.0.0 # to build from git with a specific version
cargo install --git https://github.com/fish-shell/fish-shell # to build the current development snapshot without cloning
On RedHat, CentOS, or Amazon EC2:
This will place the binaries in ``~/.cargo/bin/``, but you can place them wherever you want.
::
This build won't have the HTML docs (``help`` will open the online version) or translations.
sudo yum install ncurses-devel
It will try to build the man pages with sphinx-build. If that is not available and you would like to include man pages, you need to install it and retrigger the build script, e.g. by setting FISH_BUILD_DOCS=1::
FISH_BUILD_DOCS=1 cargo install --path .
Setting it to "0" disables the inclusion of man pages.
You can also link this build statically (but not against glibc) and move it to other computers.
Contributing Changes to the Code
--------------------------------
@@ -237,8 +204,8 @@ Contact Us
Questions, comments, rants and raves can be posted to the official fish
mailing list at https://lists.sourceforge.net/lists/listinfo/fish-users
or join us on our `gitter.im
channel <https://gitter.im/fish-shell/fish-shell>`__. Or use the `fish tag
or join us on our `matrix
channel <https://matrix.to/#/#fish-shell:matrix.org>`__. Or use the `fish tag
on Unix & Linux Stackexchange <https://unix.stackexchange.com/questions/tagged/fish>`__.
There is also a fish tag on Stackoverflow, but it is typically a poor fit.
echo"Argument $arg is not a file in the directory $(realpath $po_dir)."
echo"Non-option arguments must specify paths to files in this directory."
echo""
echo"If you want to add a new language to the translations not the following:"
echo"The filename must identify a language, with a two letter ISO 639-1 language code of the target language (e.g. 'pt' for Portuguese), and use the file extension '.po'."
echo"Optionally, you can specify a regional variant (e.g. 'pt_BR')."
echo"So valid filenames are of the shape 'll.po' or 'll_CC.po'."
These is a proposed port of fish-shell from C++ to Rust, and from CMake to cargo or related. This document is high level - see the [Development Guide] for more details.
## Why Port
- Gain access to more contributors and enable easier contributions. C++ is becoming a legacy language.
- Free us from the annoyances of C++/CMake, and old toolchains.
- Ensure fish continues to be perceived as modern and relevant.
- Unlock concurrent mode (see below).
## Why Rust
- Rust is a systems programming language with broad platform support, a large community, and a relatively high probability of still being relevant in a decade.
- Rust has a unique strength in its thread safety features, which is the missing piece to enable concurrent mode - see below.
- Other languages considered:
- Java, Python and the scripting family are ruled out for startup latency and memory usage reasons.
- Go would be an awkward fit. fork is [quite the problem](https://stackoverflow.com/questions/28370646/how-do-i-fork-a-go-process/28371586#28371586) in Go.
- Other system languages (D, Nim, Zig...) are too niche: fewer contributors, higher risk of the language becoming irrelevant.
## Risks
- Large amount of work with possible introduction of new bugs.
- Long period of complicated builds.
- Existing contributors will have to learn Rust.
- As of yet unknown compatibility story for Tier 2+ platforms (Cygwin, etc).
## Approach
We will do an **incremental port** in the span of one release. We will have a period of using both C++ and Rust, and both cargo and CMake, leveraging FFI tools (see below).
The work will **proceed on master**: no long-lived branches. Tests and CI continue to pass at every commit for recent Linux and Mac. Centos7, \*BSD, etc may be temporarily disabled if they prove problematic.
The Rust code will initially resemble the replaced C++. Fidelity to existing code is more important than Rust idiomaticity, to aid review and bisecting. But don't take this to extremes - use judgement.
The port will proceed "outside in." We'll start with leaf components (e.g. builtins) and proceed towards the core. Some components will have both a Rust and C++ implementation (e.g. FLOG), in other cases we'll change the existing C++ to invoke the new Rust implementations (builtins).
After porting the C++, we'll replace CMake.
We will continue to use wide chars, locales, gettext, printf format strings, and PCRE2. We will not change the fish scripting language at all. We will _not_ use this as an opportunity to fix existing design flaws, with a few carefully chosen exceptions. See [Strings](#strings).
We will not use tokio, serde, async, or other fancy Rust frameworks initially.
### FFI
Rust/C++ interop will use [autocxx](https://github.com/google/autocxx), [Cxx](https://cxx.rs), and possibly [bindgen](https://rust-lang.github.io/rust-bindgen/). I've forked these for fish (see the [Development Guide]). Once the port is done, we will stop using them, except perhaps bindgen for PCRE2.
We will use [corrosion](https://github.com/corrosion-rs/corrosion) for CMake integration.
Inefficiencies (e.g. extra string copying) at the FFI layer are fine, since it will all get thrown away.
Tests can stay in fish_tests.cpp or be moved into Rust .rs files; either is fine.
### Strings
Rust's `String` / `&str` types cannot represent non-UTF8 filenames or data using the default encoding scheme. That's why all string conversions must go through fish's encoding scheme (using the private-use area to encode invalid sequences). For example, fish cannot use `File::open` with a `&str` because the decoding will be incorrect.
So instead of `String`, fish will use its own string type, and manage encoding and decoding as it does today. However we will make some specific changes:
1. Drop the nul-terminated requirement. When passing `const wchar_t*` back to C++, we will allocate and copy into a nul-terminated buffer.
2. Drop support for 16-bit wchar. fish will use UTF32 on all platforms, and manage conversions itself.
After the port we can consider moving to UTF-8, for memory usage reasons.
See the [Rust Development Guide][Development Guide] for more on strings.
### Thread Safety
Allowing [background functions](https://github.com/fish-shell/fish-shell/issues/238) and concurrent functions has been a goal for many years. I have been nursing [a long-lived branch](https://github.com/ridiculousfish/fish-shell/tree/concurrent_even_simpler) which allows full threaded execution. But though the changes are small, I have been reluctant to propose them, because they will make reasoning about the shell internals too complex: it is difficult in C++ to check and enforce what crosses thread boundaries.
This is Rust's bread and butter: we will encode thread requirements into our types, making it explicit and compiler-checked, via Send and Sync. Rust will allow turning on concurrent mode in a safe way, with a manageable increase in complexity, finally enabling this feature.
## Timeline
Handwaving, 6 months? Frankly unknown - there's 102 remaining .cpp files of various lengths. It'll go faster as we get better at it. Peter (ridiculous_fish) is motivated to work on this, other current contributors have some Rust as well, and we may also get new contributors from the Rust community. Part of the point is to make contribution easier.
## Links
- [Packaging Rust projects](https://wiki.archlinux.org/title/Rust_package_guidelines) from Arch Linux
This describes how to build macOS artifacts as part of a release. These artifacts are uploaded to the GitHub release page, where they are discovered by the web site build script.
Artifacts may be built locally or in CI. Using CI is preferred.
> **Note**
> Only fish-shell administrations may create releases. Released macOS packages require code signing and notarization via private Apple developer keys, which are owned by @ridiculous_fish. These keys are stored in GitHub secrets.
## Building in CI (GitHub Actions)
macOS packages may be built in CI through a GitHub workflow. This requires a fish-shell administrator as it requires invoking secret code signing keys.
Steps:
1. Go to https://github.com/fish-shell/fish-shell/actions
2. On the left side, click on the "macOS build and codesign" Action.
3. On the right, click on the "Run workflow" button, select the branch or tag, and click Run Workflow.
4.**Reload the page**. This is necessary because the workflow will not appear until the page is reloaded.
5. Click on the new workflow. It should be in a Waiting state.
6. Click on Review Deployments, and approve and start the "deployment."
7. Once the workflow completes, expand the `actions/upload-artifact@v4` step in the logs. This should have an "Artifact download URL" - click it and download!
## Building locally (no code signing)
To build locally without notarizing and code signing, use the `build_tools/make_pkg.sh` script:
```
> ./build_tools/make_pkg.sh
```
Packages will be placed in `~/fish_built` by default.
Note these packages will result in loud warnings or errors when others try to install them, because of the lack of code signing.
## Building locally with code signing and notarization
You will need the following:
- The ".p12" certificate files for both "Developer ID Application" and "Developer ID Installer".
- (These can be generated via Export Certificate in Xcode)
- The password for these files (by convention, the same password is used for both).
- The JSON file generated via `rcodesign encode-app-store-connect-api-key`.
This describes how to get started building fish-shell in its partial Rust state, and how to contribute to the port.
## Overview
fish is in the process of transitioning from C++ to Rust. The fish project has a Rust crate embedded at path `fish-rust`. This crate builds a Rust library `libfish_rust.a` which is linked with the C++ `libfish.a`. Existing C++ code will be incrementally migrated to this crate; then CMake will be replaced with cargo and other Rust-native tooling.
Important tools used during this transition:
1. [Corrosion](https://github.com/corrosion-rs/corrosion) to invoke cargo from CMake.
2. [cxx](http://cxx.rs) for basic C++ <-> Rust interop.
3. [autocxx](https://google.github.io/autocxx/) for using C++ types in Rust.
We use forks of the last two - see the [FFI section](#ffi) below. No special action is required to obtain these packages. They're downloaded by cargo.
## Building
### Build Dependencies
fish-shell currently depends on Rust 1.70 or later. To install Rust, follow https://rustup.rs.
### Build via CMake
It is recommended to build inside `fish-shell/build`. This will make it easier for Rust to find the `config.h` file.
Build via CMake as normal (use any generator, here we use Ninja):
```shell
$ cd fish-shell
$ mkdir build &&cd build
$ cmake -G Ninja ..
$ ninja
```
This will create the usual fish executables.
### Build just libfish_rust.a with Cargo
The directory `fish-rust` contains the Rust sources. These require that CMake has been run to produce `config.h` which is necessary for autocxx to succeed.
Follow the "Build from CMake" steps above, and then:
```shell
$ cd fish-shell/fish-rust
$ cargo build
```
This will build only the library, not a full working fish, but it allows faster iteration for Rust development. That is, after running `cmake` you can open the `fish-rust` as the root of a Rust crate, and tools like rust-analyzer will work.
## Development
The basic development loop for this port:
1. Pick a .cpp (or in some cases .h) file to port, say `util.cpp`.
2. Add the corresponding `util.rs` file to `fish-rust/`.
3. Reimplement it in Rust, along with its dependencies as needed. Match the existing C++ code where practical, including propagating any relevant comments.
- Do this even if it results in less idiomatic Rust, but avoid being super-dogmatic either way.
- One technique is to paste the C++ into the Rust code, commented out, and go line by line.
4. Decide whether any existing C++ callers should invoke the Rust implementation, or whether we should keep the C++ one.
- Utility functions may have both a Rust and C++ implementation. An example is `FLOG` where interop is too hard.
- Major components (e.g. builtin implementations) should _not_ be duplicated; instead the Rust should call C++ or vice-versa.
5. Remember to run `cargo fmt` and `cargo clippy` to keep the codebase somewhat clean (otherwise CI will fail). If you use rust-analyzer, you can run clippy automatically by setting `rust-analyzer.checkOnSave.command = "clippy"`.
You will likely run into limitations of [`autocxx`](https://google.github.io/autocxx/) and to a lesser extent [`cxx`](https://cxx.rs/). See the [FFI sections](#ffi) below.
## Type Mapping
### Constants & Type Aliases
The FFI does not support constants (`#define` or `static const`) or type aliases (`typedef`, `using`). Duplicate them using their Rust equivalent (`pub const` and `type`/`struct`/`enum`).
### Non-POD types
Many types cannot currently be passed across the language boundary by value or occur in shared structs. As a workaround, use references, raw pointers or smart pointers (`cxx` provides `SharedPtr` and `UniquePtr`). Try to keep workarounds on the C++ side and the FFI layer of the Rust code. This ensures we will get rid of the workarounds as we peel off the FFI layer.
### Strings
Fish will mostly _not_ use Rust's `String/&str` types as these cannot represent non-UTF8 data using the default encoding.
fish's primary string types will come from the [`widestring` crate](https://docs.rs/widestring). The two main string types are `WString` and `&wstr`, which are renamed [Utf32String](https://docs.rs/widestring/latest/widestring/utfstring/struct.Utf32String.html) and [Utf32Str](https://docs.rs/widestring/latest/widestring/utfstr/struct.Utf32Str.html). `WString` is an owned, heap-allocated UTF32 string, `&wstr` a borrowed UTF32 slice.
In general, follow this mapping when porting from C++:
-`wcstring` -> `WString`
-`const wcstring &` -> `&wstr`
-`const wchar_t *` -> `&wstr`
None of the Rust string types are nul-terminated. We're taking this opportunity to drop the nul-terminated aspect of wide string handling.
#### Creating strings
One may create a `&wstr` from a string literal using the `wchar::L!` macro:
```rust
usecrate::wchar::prelude::*;
// This imports wstr, the L! macro, WString, a ToWString trait that supplies .to_wstring() along with other things
fnget_shell_name()-> &'staticwstr{
L!("fish")
}
```
There is also a `widestrs` proc-macro which enables L as a _suffix_, to reduce the noise. This can be applied to any block, including modules and individual functions:
```rust
usecrate::wchar::{wstr,widestrs}
// also imported by the prelude
#[widestrs]
fnget_shell_name()-> &'staticwstr{
"fish"L// equivalent to L!("fish")
}
```
#### The wchar prelude
We have a prelude to make working with these string types a whole lot more ergonomic. In particular `WExt` supplies the null-terminated-compatible `.char_at(usize)`,
and a whole lot more methods that makes porting C++ code easier. It is also preferred to use char-based-methods like `.char_count()` and `.slice_{from,to}()`
of the `WExt` trait over directly calling `.len()` and `[usize..]/[..usize]`, as that makes the code compatible with a potential future change to UTF8-strings.
`WString` and `&wstr` are the common strings used by Rust components. At the FII boundary there are some additional strings for interop. _All of these are temporary for the duration of the port._
-`CxxWString` is the Rust binding of `std::wstring`. It is the wide-string analog to [`CxxString`](https://cxx.rs/binding/cxxstring.html) and is [added in our fork of cxx](https://github.com/ridiculousfish/cxx/blob/fish/src/cxx_wstring.rs). This is useful for functions which return e.g. `const wcstring &`.
-`W0String` is renamed [U32CString](https://docs.rs/widestring/latest/widestring/ucstring/struct.U32CString.html). This is basically `WString` except it _is_ nul-terminated. This is useful for getting a nul-terminated `const wchar_t *` to pass to C++ implementations.
-`wcharz_t` is an annoying C++ struct which merely wraps a `const wchar_t *`, used for passing these pointers from C++ to Rust. We would prefer to use `const wchar_t *` directly but `autocxx` refuses to generate bindings for types such as `std::vector<const wchar_t *>` so we wrap it in this silly struct.
Note C++ `wchar_t`, Rust `char`, and `u32` are effectively interchangeable: you can cast pointers to them back and forth (except we check upon u32->char conversion). However be aware of which types are nul-terminated.
These types should be confined to the FFI modules, in particular `wchar_ffi`. They should not "leak" into other modules. See the `wchar_ffi` module.
### Format strings
Rust's builtin `std::fmt` modules do not accept runtime-provided format strings, so we mostly won't use them, except perhaps for FLOG / other non-translated text.
Instead we'll continue to use printf-style strings, with a Rust printf implementation.
### Vectors
See [`Vec`](https://cxx.rs/binding/vec.html) and [`CxxVector`](https://cxx.rs/binding/cxxvector.html).
In many cases, `autocxx` refuses to allow vectors of certain types. For example, autocxx supports `std::vector` and `std::shared_ptr` but NOT `std::vector<std::shared_ptr<...>>`. To work around this one can create a helper (pointer, length) struct. Example:
```cpp
structRustFFIJobList{
std::shared_ptr<job_t>*jobs;
size_tcount;
};
```
This is just a POD (plain old data) so autocxx can generate bindings for it. Then it is trivial to convert it to a Rust slice:
Another workaround is to define a struct that contains the shared pointer, and create a vector of that struct.
## Development Tooling
The [autocxx guidance](https://google.github.io/autocxx/workflow.html#how-can-i-see-what-bindings-autocxx-has-generated) is helpful:
1. Install cargo expand (`cargo install cargo-expand`). Then you can use `cargo expand` to see the generated Rust bindings for C++. In particular this is useful for seeing failed expansions for C++ types that autocxx cannot handle.
2. In rust-analyzer, enable Proc Macro and Proc Macro Attributes.
## FFI
The boundary between Rust and C++ is referred to as the Foreign Function Interface, or FFI.
`autocxx` and `cxx` both are designed for long-term interop: C++ and Rust coexisting for years. To this end, both emphasize safety: requiring lots of `unsafe`, `Pin`, etc.
fish plans to use them only temporarily, with a focus on getting things working. To this end, both cxx and autocxx have been forked to support fish:
1. Relax the requirement that all functions taking pointers are `unsafe` (this just added noise).
2. Add support for `wchar_t` as a recognized type, and `CxxWString` analogous to `CxxString`.
See the `Cargo.toml` file for the locations of the forks.
Only typed-in commands use abbreviations. Abbreviations are not expanded in scripts.
For example, a frequently-run command like ``git checkout`` can be abbreviated to ``gco``.
After entering ``gco`` and pressing :kbd:`Space` or :kbd:`Enter`, the full text ``git checkout`` will appear in the command line.
To avoid expanding something that looks like an abbreviation, the default :kbd:`Control`\ +\ :kbd:`Space` binding inserts a space without expanding.
After entering ``gco`` and pressing :kbd:`space` or :kbd:`enter`, the full text ``git checkout`` will appear in the command line.
To avoid expanding something that looks like an abbreviation, the default :kbd:`ctrl-space` binding inserts a space without expanding.
An abbreviation may match a literal word, or it may match a pattern given by a regular expression. When an abbreviation matches a word, that word is replaced by new text, called its *expansion*. This expansion may be a fixed new phrase, or it can be dynamically created via a fish function. This expansion occurs after pressing space or enter.
@@ -49,6 +49,13 @@ Combining these features, it is possible to create custom syntaxes, where a regu
> abbr >> ~/.config/fish/config.fish
> abbr --erase (abbr --list)
Alternatively you can keep them in a separate :ref:`configuration file <configuration>` by doing something like the following::
> abbr > ~/.config/fish/conf.d/myabbrs.fish
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.
Of course any functions will have to be saved separately, see :doc:`funcsave <funcsave>`.
"add" subcommand
--------------------
@@ -56,12 +63,14 @@ Combining these features, it is possible to create custom syntaxes, where a regu
``abbr --add`` creates a new abbreviation. With no other options, the string **NAME** is replaced by **EXPANSION**.
With **--position command**, the abbreviation will only expand when it is positioned as a command, not as an argument to another command. With **--position anywhere** the abbreviation may expand anywhere in the command line. The default is **command**.
With **--command COMMAND**, the abbreviation will only expand when it is used as an argument to the given COMMAND. Multiple **--command** can be used together, and the abbreviation will expand for each. An empty **COMMAND** means it will expand only when there is no command. **--command** implies **--position anywhere** and disallows **--position command**. Even with different **COMMANDS**, the **NAME** of the abbreviation needs to be unique. Consider using **--regex** if you want to expand the same word differently for multiple commands.
With **--regex**, the abbreviation matches using the regular expression given by **PATTERN**, instead of the literal **NAME**. The pattern is interpreted using PCRE2 syntax and must match the entire token. If multiple abbreviations match the same token, the last abbreviation added is used.
With **--set-cursor=MARKER**, the cursor is moved to the first occurrence of **MARKER** in the expansion. The **MARKER** value is erased. The **MARKER** may be omitted (i.e. simply ``--set-cursor``), in which case it defaults to ``%``.
@@ -115,6 +124,12 @@ This first creates a function ``vim_edit`` which prepends ``vim`` before its arg
This creates an abbreviation "4DIRS" which expands to a multi-line loop "template." The template enters each directory and then leaves it. The cursor is positioned ready to enter the command to run in each directory, at the location of the ``!``, which is itself erased.
::
abbr --command git co checkout
Turns "co" as an argument to "git" into "checkout". Multiple commands are possible, ``--command={git,hg}`` would expand "co" to "checkout" for both git and hg.
NOTE: This page documents the fish builtin ``alias``.
To see the documentation on any non-fish versions, use ``command man alias``.
``alias`` is a simple wrapper for the ``function`` builtin, which creates a function wrapping a command. It has similar syntax to POSIX shell ``alias``. For other uses, it is recommended to define a :doc:`function <function>`.
If you want to ease your interactive use, to save typing, consider using an :doc:`abbreviation <abbr>` instead.
@@ -49,9 +54,11 @@ The following code will create ``rmi``, which runs ``rm`` with additional argume
rm -i $argv
end
``alias`` sometimes requires escaping, as you can see here::
# This needs to have the spaces escaped or "Chrome.app..."
# will be seen as an argument to "/Applications/Google":
alias chrome='/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome banana'
alias chrome='/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome'
@@ -20,7 +20,7 @@ Each option specification (``OPTION_SPEC``) is written in the :ref:`domain speci
Each option that is seen in the ARG list will result in variables named ``_flag_X``, where **X** is the short flag letter and the long flag name (if they are defined). For example a **--help** option could cause argparse to define one variable called ``_flag_h`` and another called ``_flag_help``.
The variables will be set with local scope (i.e., as if the script had done ``set -l _flag_X``). If the flag is a boolean (that is, it just is passed or not, it doesn't have a value) the values are the short and long flags seen. If the option is not a boolean the values will be zero or more values corresponding to the values collected when the ARG list is processed. If the flag was not seen the flag variable will not be set.
The variables will be set with local scope (i.e., as if the script had done ``set -l _flag_X``). If the flag is a boolean (that is, it is passed or not, it doesn't have a value) the values are the short and long flags seen. If the option is not a boolean the values will be zero or more values corresponding to the values collected when the ARG list is processed. If the flag was not seen the flag variable will not be set.
Options
-------
@@ -32,6 +32,7 @@ The following ``argparse`` options are available. They must appear before all *O
**-x** or **--exclusive***OPTIONS*
A comma separated list of options that are mutually exclusive. You can use this more than once to define multiple sets of mutually exclusive options.
You give either the short or long version of each option, and you still need to otherwise define the options.
**-N** or **--min-args***NUMBER*
The minimum number of acceptable non-option arguments. The default is zero.
@@ -57,13 +58,28 @@ To use this command, pass the option specifications (**OPTION_SPEC**), a mandato
If ``$argv`` is empty then there is nothing to parse and ``argparse`` returns zero to indicate success. If ``$argv`` is not empty then it is checked for flags ``-h``, ``--help``, ``-n`` and ``--name``. If they are found they are removed from the arguments and local variables called ``_flag_OPTION`` are set so the script can determine which options were seen. If ``$argv`` doesn't have any errors, like a missing mandatory value for an option, then ``argparse`` exits with a status of zero. Otherwise it writes appropriate error messages to stderr and exits with a status of one.
If ``$argv`` is empty then there is nothing to parse and ``argparse`` returns zero to indicate success. If ``$argv`` is not empty then it is checked for flags ``-h``, ``--help``, ``-n`` and ``--name``. If they are found they are removed from the arguments and local variables called ``_flag_OPTION`` are set so the script can determine which options were seen. If ``$argv`` doesn't have any errors, like an unknown option or a missing mandatory value for an option, then ``argparse`` exits with a status of zero. Otherwise it writes appropriate error messages to stderr and exits with a status of one.
The ``or return`` means that the function returns ``argparse``'s status if it failed, so if it goes on ``argparse`` succeeded.
To use the flags argparse has extracted::
# Checking for _flag_h and _flag_help is equivalent
and set myname $_flag_name[-1] # here we use the *last* --name=
Any characters in the flag name that are not valid in a variable name (like ``-`` dashes) will be replaced with underscores.
The ``--`` argument is required. You do not have to include any option specifications or arguments after the ``--`` but you must include the ``--``. For example, this is acceptable::
set -l argv foo
@@ -149,7 +165,7 @@ This isn't specific to argparse but common to all things using ``getopt(3)`` (if
Flag Value Validation
---------------------
Sometimes you need to validate the option values. For example, that it is a valid integer within a specific range, or an ip address, or something entirely different. You can always do this after ``argparse`` returns but you can also request that ``argparse`` perform the validation by executing arbitrary fish script. To do so simply append an ``!`` (exclamation-mark) then the fish script to be run. When that code is executed three vars will be defined:
Sometimes you need to validate the option values. For example, that it is a valid integer within a specific range, or an ip address, or something entirely different. You can always do this after ``argparse`` returns but you can also request that ``argparse`` perform the validation by executing arbitrary fish script. To do so append an ``!`` (exclamation-mark) then the fish script to be run. When that code is executed three vars will be defined:
-``_argparse_cmd`` will be set to the value of the value of the ``argparse --name`` value.
@@ -161,7 +177,7 @@ These variables are passed to the function as local exported variables.
The script should write any error messages to stdout, not stderr. It should return a status of zero if the flag value is valid otherwise a non-zero status to indicate it is invalid.
Fish ships with a ``_validate_int`` function that accepts a ``--min`` and ``--max`` flag. Let's say your command accepts a ``-m`` or ``--max`` flag and the minimum allowable value is zero and the maximum is 5. You would define the option like this: ``m/max=!_validate_int --min 0 --max 5``. The default if you just call ``_validate_int`` without those flags is to simply check that the value is a valid integer with no limits on the min or max value allowed.
Fish ships with a ``_validate_int`` function that accepts a ``--min`` and ``--max`` flag. Let's say your command accepts a ``-m`` or ``--max`` flag and the minimum allowable value is zero and the maximum is 5. You would define the option like this: ``m/max=!_validate_int --min 0 --max 5``. The default if you call ``_validate_int`` without those flags is to check that the value is a valid integer with no limits on the min or max value allowed.
Here are some examples of flag validations::
@@ -205,6 +221,44 @@ After parsing the arguments the ``argv`` variable is set with local scope to any
If an error occurs during argparse processing it will exit with a non-zero status and print error messages to stderr.
Examples
---------
A simple use::
argparse h/help -- $argv
or return
if set -q _flag_help
# TODO: Print help here
return 0
end
This supports one option - ``-h`` / ``--help``. Any other option is an error. If it is given it prints help and exits.
There are a variety of boolean flags, all with long and short versions. A few of these cannot be used together, and that is what the ``-x`` flag is used for.
``-x g,U`` means that ``--global`` and ``--universal`` or their short equivalents conflict, and if they are used together you get an error.
In this case you only need to give the short or long flag, not the full option specification.
After this it figures out which variable it should operate on according to the ``--path`` flag::
@@ -21,6 +22,8 @@ The block is unconditionally executed. ``begin; ...; end`` is equivalent to ``if
``begin`` does not change the current exit status itself. After the block has completed, ``$status`` will be set to the status returned by the most recent command.
Some other shells only support the ``{ [COMMANDS ...] ; }`` notation.
The **-h** or **--help** option displays help about using this command.
A background job is executed simultaneously with fish, and does not have access to the keyboard. If no job is specified, the last job to be used is put in the background. If ``PID`` is specified, the jobs containing the specified process IDs are put in the background.
For compatibility with other shells, job expansion syntax is supported for ``bg``. A PID of the format ``%1`` will be interpreted as the PID of job 1. Job numbers can be seen in the output of :doc:`jobs <jobs>`.
A PID of the format ``%n``, where n is an integer, will be interpreted as the PID of job number n. Job numbers can be seen in the output of :doc:`jobs <jobs>`.
When at least one of the arguments isn't a valid job specifier,
``bg`` will print an error without backgrounding anything.
When at least one of the arguments isn't a valid job specifier,``bg`` will print an error without backgrounding anything.
When all arguments are valid job specifiers, ``bg`` will background all matching jobs that exist.
@@ -29,10 +28,20 @@ The **-h** or **--help** option displays help about using this command.
Example
-------
The typical use is to run something, stop it with ctrl-z, and then continue it in the background with bg::
> find / -name "*.js" >/tmp/jsfiles 2>/dev/null # oh no, this takes too long, let's press Ctrl-z!
fish: Job 1, 'find / -name "*.js" >/tmp/jsfil…' has stopped
It can add bindings if given a SEQUENCE of characters to bind to. These should be written as :ref:`fish escape sequences <escapes>`. The most important of these are ``\c`` for the control key, and``\e``for escape, and because of historical reasons also the Alt key (sometimes also called "Meta").
If both ``KEYS`` and ``COMMAND`` are given,``bind``adds (or replaces) a binding in ``MODE``.
If only ``KEYS`` is given, any existing binding for those keys in the given ``MODE`` will be printed.
If no ``KEYS`` argument is provided, all bindings (in the given ``MODE``) are printed.
For example, :kbd:`Alt`\ +\ :kbd:`W` can be written as ``\ew``, and :kbd:`Control`\ +\ :kbd:`X` (^X) can be written as ``\cx``. Note that Alt-based key bindings are case sensitive and Control-based key bindings are not. This is a constraint of text-based terminals, not ``fish``.
``KEYS`` is a comma-separated list of key names.
Modifier keys can be specified by prefixing a key name with a combination of ``ctrl-``, ``alt-``, ``shift-`` and ``super-`` (i.e. the "windows" or "command" key).
For example, pressing :kbd:`w` while holding the Alt modifier is written as ``alt-w``.
Key names are case-sensitive; for example ``alt-W`` is the same as ``alt-shift-w``.
``ctrl-x,ctrl-e`` would mean pressing :kbd:`ctrl-x` followed by :kbd:`ctrl-e`.
The generic key binding that matches if no other binding does can be set by specifying a ``SEQUENCE`` of the empty string (that is, ``''`` ). For most key bindings, it makes sense to bind this to the ``self-insert`` function (i.e. ``bind '' self-insert``). This will insert any keystrokes not specifically bound to into the editor. Non-printable characters are ignored by the editor, so this will not result in control sequences being inserted.
Some keys have names, usually because they don't have an obvious printable character representation.
They are:
If the ``-k`` switch is used, the name of a key (such as 'down', 'up' or 'backspace') is used instead of a sequence. The names used are the same as the corresponding curses variables, but without the 'key\_' prefix. (See ``terminfo(5)`` for more information, or use ``bind --key-names`` for a list of all available named keys). Normally this will print an error if the current``$TERM``entry doesn't have a given key, unless the ``-s`` switch is given.
- the arrow keys ``up``, ``down``,``left``and ``right``,
-``backspace``,
-``comma`` (``,``),
-``delete``,
-``end``,
-``enter``,
-``escape``,
-``f1`` through ``f12``.
-``home``,
-``insert``,
-``menu``,
-``minus`` (``-``),
-``pageup``,
-``pagedown``,
-``printscreen``,
-``space`` and
-``tab``,
To find out what sequence a key combination sends, you can use :doc:`fish_key_reader <fish_key_reader>`.
These names are case-sensitive.
``COMMAND`` can be any fish command, but it can also be one of a set of special input functions. These include functions for moving the cursor, operating on the kill-ring, performing tab completion, etc. Use ``bind --function-names`` for a complete list of these input functions.
An empty value (``''``) for ``KEYS`` designates the generic binding that will be used if nothing else matches. For most bind modes, it makes sense to bind this to the ``self-insert`` function (i.e. ``bind '' self-insert``). This will insert any keystrokes that have no bindings otherwise. Non-printable characters are ignored by the editor, so this will not result in control sequences being inserted.
When ``COMMAND`` is a shellscript command, it is a good practice to put the actual code into a :ref:`function <syntax-function>` and simply bind to the function name. This way it becomes significantly easier to test the function while editing, and the result is usually more readable as well.
To find the name of a key combination you can use :doc:`fish_key_reader <fish_key_reader>`.
``COMMAND`` can be any fish command, but it can also be one of a set of special input functions. These include functions for moving the cursor, operating on the kill-ring, performing tab completion, etc. Use ``bind --function-names`` or :ref:`see below <special-input-functions>` for a list of these input functions.
..note::
Special input functions cannot be combined with ordinary shell script commands. The commands must be entirely a sequence of special input functions (from ``bind -f``) or all shell script commands (i.e., valid fish script). To run special input functions from regular fish script, use ``commandline -f`` (see also :doc:`commandline <commandline>`). If a script produces output, it should finish by calling ``commandline -f repaint`` to tell fish that a repaint is in order.
If a script changes the commandline, it should finish by calling the ``repaint`` special input function.
If no ``SEQUENCE`` is provided, all bindings (or just the bindings in the given``MODE``) are printed. If ``SEQUENCE`` is provided but no ``COMMAND``, just the binding matching that sequence is printed.
Key bindings may use "modes", which mimics vi's modal input behavior. The default mode is "default" (in vi-mode, that's vi's "normal" mode). Every key binding applies to a single mode; you can specify which one with``-M MODE``. If the key binding should change the mode, you can specify the new mode with ``-m NEW_MODE``. The mode can be viewed and changed via the ``$fish_bind_mode`` variable. If you want to change the mode from inside a fish function, use ``set fish_bind_mode MODE``.
To save custom key bindings, put the ``bind`` statements into :ref:`config.fish <configuration>`. Alternatively, fish also automatically executes a function called ``fish_user_key_bindings`` if it exists.
Key bindings may use "modes", which mimics Vi's modal input behavior. The default mode is "default". Every key binding applies to a single mode; you can specify which one with ``-M MODE``. If the key binding should change the mode, you can specify the new mode with ``-m NEW_MODE``. The mode can be viewed and changed via the ``$fish_bind_mode`` variable. If you want to change the mode from inside a fish function, use ``set fish_bind_mode MODE``.
Options
-------
The following options are available:
**-k** or **--key**
Specify a key name, such as 'left' or 'backspace' instead of a character sequence
**-K** or **--key-names**
Display a list of available key names. Specifying **-a** or **--all** includes keys that don't have a known mapping
**-f** or **--function-names**
Display a list of available input functions
**-K** or **--key-names**
Display a list of available named keys such as ``backspace``.
**-L** or **--list-modes**
Display a list of defined bind modes
**-M MODE** or **--mode***MODE*
Specify a bind mode that the bind is used in. Defaults to "default"
Specify a bind mode that the bind is used in. Defaults to "default".
If you use :ref:`vi bindings <vi-mode>`, that's the *command* mode,
what vi calls "normal" mode.
**-m NEW_MODE** or **--sets-mode***NEW_MODE*
Change the current mode to *NEW_MODE* after this binding is executed
@@ -72,7 +94,7 @@ The following options are available:
Specifying **-a** or **--all** without **-M** or **--mode** erases all binds in all modes regardless of sequence.
**-a** or **--all**
See **--erase** and **--key-names**
See **--erase**
**--preset** and **--user**
Specify if bind should operate on user or preset bindings.
@@ -87,6 +109,8 @@ The following options are available:
**-h** or **--help**
Displays help about using this command.
.._special-input-functions:
Special input functions
-----------------------
The following special input functions are available:
@@ -95,21 +119,31 @@ The following special input functions are available:
only execute the next function if the previous succeeded (note: only some functions report success)
``accept-autosuggestion``
accept the current autosuggestion
accept the current autosuggestion. Returns false when there was nothing to accept.
``backward-char``
move one character to the left.
If the completion pager is active, select the previous completion instead.
``backward-char-passive``
move one character to the left, but do not trigger any non-movement-related operations. If the cursor is at the start of
the commandline, does nothing. Does not change the selected item in the completion pager UI when shown.
``backward-bigword``
move one whitespace-delimited word to the left
``backward-token``
move one argument to the left
``backward-delete-char``
deletes one character of input to the left of the cursor
``backward-kill-bigword``
move the whitespace-delimited word to the left of the cursor to the killring
``backward-kill-token``
move the argument to the left of the cursor to the killring
``backward-kill-line``
move everything from the beginning of the line to the cursor to the killring
@@ -135,7 +169,7 @@ The following special input functions are available:
start selecting text
``cancel``
cancel the current commandline and replace it with a new empty one
close the pager if it is open, or undo the most recent completion if one was just inserted
``cancel-commandline``
cancel the current commandline and replace it with a new empty one, leaving the old one in place with a marker to show that it was cancelled
@@ -143,8 +177,14 @@ The following special input functions are available:
``capitalize-word``
make the current word begin with a capital letter
``clear-commandline``
empty the entire commandline
``clear-screen``
clears the screen and redraws the prompt. if the terminal doesn't support clearing the screen it is the same as ``repaint``.
clears the screen and redraws the prompt.
``scrollback-push``
pushes earlier output to the terminal scrollback, positioning the prompt at the top.
``complete``
guess the remainder of the current token
@@ -188,10 +228,18 @@ The following special input functions are available:
``forward-bigword``
move one whitespace-delimited word to the right
``forward-token``
move one argument to the right
``forward-char``
move one character to the right; or if at the end of the commandline, accept the current autosuggestion.
If the completion pager is active, select the next completion instead.
``forward-char-passive``
move one character to the right, but do not trigger any non-movement-related operations. If the cursor is at the end of the
commandline, does not accept the current autosuggestion (if any). Does not change the selected item in the completion pager,
if shown.
``forward-single-char``
move one character to the right; or if at the end of the commandline, accept a single char from the current autosuggestion.
@@ -202,8 +250,8 @@ The following special input functions are available:
``history-pager``
invoke the searchable pager on history (incremental search); or if the history pager is already active, search further backwards in time.
``history-pager-delete``
permanently delete the history item selected in the history pager
``history-delete``
permanently delete the current history item, either from the history pager or from an active up-arrow history search
``history-search-backward``
search the history for the previous match
@@ -223,18 +271,39 @@ The following special input functions are available:
``history-token-search-forward``
search the history for the next matching argument
``history-last-token-search-backward``
search the history for the previous matching last argument
``history-last-token-search-forward``
search the history for the next matching last argument
``forward-jump`` and ``backward-jump``
read another character and jump to its next 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``
jump to right *before* the next occurence
jump to right *before* the next occurrence
``repeat-jump`` and ``repeat-jump-reverse``
redo the last jump in the same/opposite direction
``jump-to-matching-bracket``
jump to matching bracket if the character under the cursor is bracket;
otherwise, jump to the next occurrence of *any right* bracket after the cursor.
The following brackets are considered: ``([{}])``
``jump-till-matching-bracket``
the same as ``jump-to-matching-bracket`` but offset cursor to the right for left bracket, and offset cursor to the left for right bracket.
The offset is applied for both the position we jump from and position we jump to.
In other words, the cursor will continuously jump inside the brackets but won't reach them by 1 character.
The input function is useful to emulate ``ib`` vi text object.
The following brackets are considered: ``([{}])``
``kill-bigword``
move the next whitespace-delimited word to the killring
``kill-token``
move the next argument to the killring
``kill-line``
move everything from the cursor to the end of the line to the killring
@@ -242,7 +311,7 @@ The following special input functions are available:
move the selected text to the killring
``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``
move the line (without the following newline) to the killring
@@ -267,7 +336,7 @@ The following special input functions are available:
reexecutes the prompt functions and redraws the prompt (also ``force-repaint`` for backwards-compatibility)
``repaint-mode``
reexecutes the :doc:`fish_mode_prompt <fish_mode_prompt>` and redraws the prompt. This is useful for vi-mode. If no ``fish_mode_prompt`` exists or it prints nothing, it acts like a normal repaint.
reexecutes the :doc:`fish_mode_prompt <fish_mode_prompt>` and redraws the prompt. This is useful for vimode. If no ``fish_mode_prompt`` exists or it prints nothing, it acts like a normal repaint.
``self-insert``
inserts the matching sequence into the command line
@@ -339,22 +408,40 @@ The following functions are included as normal functions, but are particularly u
Examples
--------
Exit the shell when :kbd:`Control`\ +\ :kbd:`D` is pressed::
Exit the shell when :kbd:`ctrl-d` is pressed::
bind \cd 'exit'
bind ctrl-d 'exit'
Perform a history search when :kbd:`Page Up` is pressed::
Perform a history search when :kbd:`pageup` is pressed::
bind -k ppage history-search-backward
bind pageup history-search-backward
Turn on :ref:`Vi key bindings <vi-mode>` and rebind :kbd:`Control`\ +\ :kbd:`C` to clear the input line::
Turn on :ref:`vi key bindings <vi-mode>` and rebind :kbd:`ctrl-c` to clear the input line::
set -g fish_key_bindings fish_vi_key_bindings
bind -M insert \cc kill-whole-line repaint
bind -M insert ctrl-c kill-whole-line repaint
Launch ``git diff`` and repaint the commandline afterwards when :kbd:`Control`\ +\ :kbd:`G` is pressed::
Launch ``git diff`` and repaint the commandline afterwards when :kbd:`ctrl-g` is pressed::
bind \cg 'git diff; commandline -f repaint'
bind ctrl-g 'git diff' repaint
Swap :kbd:`tab` and :kbd:`shift-tab`, making tab focus the search field.
But if the search field is already active, keep the behavior (:kbd:`tab` cycles forward, :kbd:`shift-tab` backward).::
bind tab '
if commandline --search-field >/dev/null
commandline -f complete
else
commandline -f complete-and-search
end
'
bind shift-tab '
if commandline --search-field >/dev/null
commandline -f complete-and-search
else
commandline -f complete
end
'
.._cmd-bind-termlimits:
@@ -363,23 +450,33 @@ Terminal Limitations
Unix terminals, like the ones fish operates in, are at heart 70s technology. They have some limitations that applications running inside them can't workaround.
For instance, the control key modifies a character by setting the top three bits to 0. This means:
For instance, historically the control key modifies a character by setting the top three bits to 0. This means:
- Many characters + control are indistinguishable from other keys.:kbd:`Control`\ +\ :kbd:`I`*is* tab,:kbd:`Control`\ +\:kbd:`J`*is* newline (``\n``).
- Control and shift don't work simultaneously
- Many characters + control are indistinguishable from other keys::kbd:`ctrl-i`*is*:kbd:`tab`,:kbd:`ctrl-j`*is* newline (``\n``).
- Control and shift don't work simultaneously - :kbd:`ctrl-X` is the same as :kbd:`ctrl-x`.
Other keys don't have a direct encoding, and are sent as escape sequences. For example :kbd:`→` (Right) often sends ``\e\[C``. These can differ from terminal to terminal, and the mapping is typically available in `terminfo(5)`. Sometimes however a terminal identifies as e.g. ``xterm-256color`` for compatibility, but then implements xterm's sequences incorrectly.
Other keys don't have a direct encoding, and are sent as escape sequences. For example :kbd:`right` (``→``) usually sends ``\e\[C``.
Some modern terminals support newer encodings for keys, that allow distinguishing more characters and modifiers, and fish enables as many of these as it can, automatically.
When in doubt, run :doc:`fish_key_reader`. If that tells you that pressing :kbd:`ctrl-i` sends tab, your terminal does not support these better encodings, and so fish is limited to what it sends.
.._cmd-bind-escape:
Special Case: The Escape Character
----------------------------------
Key timeout
-----------
The escape key can be used standalone, for example, to switch from insertion mode to normal mode when using Vi keybindings. Escape can also be used as a "meta" key, to indicate the start of an escape sequence, like for function or arrow keys. Custom bindings can also be defined that begin with an escape character.
When you've bound a sequence of multiple characters, there is always the possibility that fish has only seen a part of it, and then it needs to disambiguate between the full sequence and part of it.
Holding alt and something else also typically sends escape, for example holding alt+a will send an escape character and then an "a".
For example::
fish waits for a period after receiving the escape character, to determine whether it is standalone or part of an escape sequence. While waiting, additional key presses make the escape key behave as a meta key. If no other key presses come in, it is handled as a standalone escape. The waiting period is set to 30 milliseconds (0.03 seconds). It can be configured by setting the ``fish_escape_delay_ms`` variable to a value between 10 and 5000 ms. This can be a universal variable that you set once from an interactive session.
So the escape character has its own timeout configured with :envvar:`fish_escape_delay_ms`.
bind j,k 'commandline -i foo'
# or `bind jk`
will bind the sequence ``jk`` to insert "foo" into the commandline. When you've only pressed "j", fish doesn't know if it should insert the "j" (because of the default self-insert), or wait for the "k".
You can enable a timeout for this, by setting the :envvar:`fish_sequence_key_delay_ms` variable to the timeout in milliseconds. If the timeout elapses, fish will no longer wait for the sequence to be completed, and do what it can with the characters it already has.
The escape key is a special case, because it can be used standalone as a real key or as part of a longer escape sequence, like function or arrow keys. Holding alt and something else also typically sends escape, for example holding alt+a will send an escape character and then an "a". So the escape character has its own timeout configured with :envvar:`fish_escape_delay_ms`.
See also :ref:`Key sequences <interactive-key-sequences>`.
``block``prevents events triggered by ``fish`` or the :doc:`emit <emit>` command from being delivered and acted upon while the block is in place.
In functions, ``block`` can be useful while performing work that should not be interrupted by the shell.
The block can be removed. Any events which triggered while the block was in place will then be delivered.
``block``delays delivery of all events triggered by ``fish`` or the :doc:`emit <emit>`, thus delaying the execution of any function registered ``--on-event``, ``--on-process-exit``, ``--on-job-exit``, ``--on-variable`` and ``--on-signal`` until after the block is removed.
Event blocks should not be confused with code blocks, which are created with ``begin``, ``if``, ``while`` or ``for``
Without options, the``block``command acts with function scope.
Without options, ``block``sets up a block that is released automatically at the end of the current function scope.
The following options are available:
@@ -36,7 +32,7 @@ The following options are available:
Release global block.
**-h** or **--help**
Displays help about using this command.
Display help about using this command.
Example
-------
@@ -57,4 +53,4 @@ Example
Notes
-----
Events are only received from the current fish process as there is no way to send events from one fish process to another (yet).
Events are only received from the current fish process as there is no way to send events from one fish process to another.
NOTE: This page documents the fish builtin ``command``.
To see the documentation on any non-fish versions, use ``command man command``.
**command** forces the shell to execute the program *COMMANDNAME* and ignore any functions or builtins with the same name.
In ``command foo``, ``command`` is a keyword.
The following options are available:
**-a** or **--all**
Prints all *COMMAND* found in :envvar:`PATH`, in the order found.
**-q** or **--query**
Silence output and print nothing, setting only exit status.
Implies **--search**.
Return 0 if any of the given commands could be found, 127 otherwise.
Don't print anything.
For compatibility, this is also **--quiet** (deprecated).
**-v** (or **-s** or **--search**)
**-s** or **--search** (or **-v**)
Prints the external command that would be executed, or prints nothing if no file with the specified name could be found in :envvar:`PATH`.
**-h** or **--help**
Displays help about using this command.
With the **-v** option, ``command`` treats every argument as a separate command to look up and sets the exit status to 0 if any of the specified commands were found, or 127 if no commands could be found. **--quiet** used with **-v** prevents commands being printed, like ``type -q``.
Examples
--------
|``command ls`` executes the ``ls`` program, even if an ``ls`` function also exists.
|``command -s ls`` prints the path to the ``ls`` program.
|``command -q git; and command git log`` runs ``git log`` only if ``git`` exists.
|``command -sq git`` and ``command -q git`` and ``command -vq git`` return true (0) if a git command could be found and don't print anything.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.