If a test fails by throwing an exception (in this case, "Too many open files")
then that exception would propagate, be uncaught, and then the remaining tests
would not be await'ed, leading to a hang.
Fix this by properly catching and reporting exceptions.
Vim supports incrementing & decrementing the number below the cursor (or
after it) via Ctrl-a and Ctrl-x, respectively. Given fish's Vi mode
support, it makes sense to provide similar functionality when working on
the command line, to provide a more natural environment for Vim users.
With this change we add the necessary functionality.
Closes: #8320Closes#11570
Historically, `fish -C "commandline echo"` was silently ignored. Make it do
the expected thing. This won't affect subsequent readers because we only do
it for top-level ones, and reader_pop() will clear the commandline state again.
This improves consistency with the parent commit. We probably don't want to
support arbitrary readline commands before the first reader is initialized,
but setting the initial commandline seems useful: first, it would have helped
me in the past for debugging fish. Second, it would allow one to rewrite
an application launcher:
foot --app-id my-foot-launcher -e fish -C '
set fish_history launcher
bind escape exit
bind ctrl-\[ exit
- function fish_should_add_to_history
- false
- end
- for enter in enter ctrl-j
- bind $enter '\''
- history append -- "$(commandline)"
- commandline "setsid $(commandline) </dev/null >/dev/null 2>&1 & disown && exit"
- commandline -f execute
- '\''
- end
+ commandline "setsid </dev/null >/dev/null 2>&1 & disown && exit"
+ commandline --cursor $(string length "setsid ")
'
which is probably not desirable today because it will disable autosuggestions.
Though that could be fixed eventually by making autosuggestions smarter.
If we find a generally-useful use case, we should mention this in the changelog.
Ref: https://github.com/fish-shell/fish-shell/pull/11570#discussion_r2144544053
Commands like "commandline foo" silently fail, and "complete -C" fails with
a weird "option requires an argument" error.
I think at least the first one can be useful in edge cases, e.g. to test
code that does not separate the `commandline` input and output (#11570),
and to set fish's initial commandline, see the next commit.
I don't think there are super strong reasons to allow these, but if the
existing state is merely due to "no one has ever thought of doing this",
then we should try changing it.
For consistency, also allow "complete -C". I guess an argument for that is
that it's weird to make a command behave differently in non-interactive shells.
For now, keep the historical behavior of disabling access to the command
line in non-interactive shells. If we find a good reason for allowing that
(which seems unlikely), we can.
Ref: https://github.com/fish-shell/fish-shell/pull/11570#discussion_r2144544053
Co-authored-by: Johannes Altmanninger <aclopte@gmail.com>
Nightlies for opensuse/leap:15.6 are failing because their /bin/python3
is Python 3.6 (the "python311" package creates only /bin/python311).
Python3.6 has been EOL for 3.5 years but OpenSuse leap is not even EOL.
Given that we don't write a lot of Python, let's support this for now.
Use wrapping arithmetic when parsing octal and hex escapes in echo to
prevent panics on overflow and ensure consistent behavior with other
shells. This change allows echo to process escape sequences like \5555
without crashing, keeping the same behavior as 3.7.1.
```
$ ./fish --version
fish, version 3.7.1
$ ./fish -c 'echo -e "\5555"'
m5
```
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.
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 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.
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 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.
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
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.
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.
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.
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).
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.