This printed things like
```
in function 'f'
called on standard input
in function 'd'
called on standard input
in function 'b'
called on standard input
in function 'a'
called on standard input
```
As a first step, it removes the empty lines so it's now
```
in function 'f'
called on standard input
in function 'd'
called on standard input
in function 'b'
called on standard input
in function 'a'
called on standard input
```
See #5434.
If a function process is deferred, allow it to be unbuffered.
This permits certain simple cases where functions are piped to external
commands to execute without buffering.
This is a somewhat-hacky stopgap measure that can't really be extended
to more general concurrent processes. However it is overall an improvement
in user experience that might help flush out some bugs too.
POSIX dictates here that incomplete conversions, like in
printf %d\n 15.2
or
printf %d 14g
are still printed along with any error.
This seems alright, as it allows users to silence stderr to accept incomplete conversions.
This commit implements it, but what's a bit weird is the ordering between stdout and stderr,
causing the error to be printed _after_, like
15
14
15.1: value not completely converted
14,2: value not completely converted
but that seems like a general issue with how we buffer the streams.
(I know that nonfatal_error is a copy of most of fatal_error - I tried
differently, and va_* is weird)
Fixes#5532.
Before this change, - was sorted with other punctuation before
A-Z. Now, it sorts above the rest of the characters.
This has a practical effect on completions, where when there are
both -s and --long with the same description, the short option
is now before the long option in the pager, which is what is now
selected when navigating `foo -<TAB>`. The long options can be
picked out with `foo --<TAB>`. Before, short options which
duplicated a long option literally could not be selected by
any means from the pager.
Fixes#5634
This tweaks wcsfilecmp such that certain punctuation characters will
come after A-Z.
A big win with `set <TAB>` - the __prefixed fish junk now comes
after the stuff users should care about.
This disables an extra round of escaping in the `string replace -r`
replacement string.
Currently, to add a backslash to an a or b (to "escape" it):
string replace -ra '([ab])' '\\\\\\\$1' a
7 backslashes!
This removes one of the layers, so now 3 or 4 works (each one escaped
for the single-quotes, so pcre receives two, which it reads as one literal):
string replace -ra '([ab])' '\\\\$1' a
This is backwards-incompatible as replacement strings will change
meaning, so we put it behind a feature flag.
The name is kinda crappy, though.
Fixes#5474.
As a simple replacement for `wc -l`.
This counts both lines on stdin _and_ arguments.
So if "file" has three lines, then `count a b c < file` will print 6.
And since it counts newlines, like wc, `echo -n foo | count` prints 0.
It turns out that `string split0` didn't actually ever do any
splitting. The arg_iterator_t already split stdin on NUL, and split0 just
performed an additional search that could never succeed (since
arguments from argv already can't contain NUL).
Let the arg_iterator_t not perform any splitting if asked, and then
let split0 split in 0.
One slight wart is that split0 ignores a trailing NUL, which normal
split doesn't.
Fixes#5701.
In a galaxy far, far away, event_blockage_t was intended to block only cetain
events. But it always just blocked everything. Eliminate the event block
mask.
On some systems, this sometimes uses unicode quotation marks.
Not on mine, but on Travis it does.
The only other workaround I can think of is setting locale to C, but
that implies not being able to test anything unicode-related in the
entire invocation tests.
So for now disable this test.
Illumos/OpenIndiana/SunOS/Solaris has an rm/rmdir that tries to
protect the user by not allowing them to delete $PWD.
Normally, this would be a good thing as deleting $PWD is a stupid
thing to do. Except in this case, we absolutely need to do that.
So instead we weasel around it by invoking an sh to cd out of the
directory to then invoke an `rmdir` to delete it. That should throw
off any attempts at protection (we could also have tried $PWD/. or
similar, but that's possibly still protected against).
This is the last failing test on
Illumos/OpenIndiana/SunOS/Solaris/afunnyquip, so:
Fixes#5472.
This tested #1728, where redirecting a directory (`begin; something;
end < .`) would cause `status` to misbehave.
Unfortunately, on Illumos/OpenIndiana/SunOS, this returns a different
error (EINVAL instead of EISDIR), so we can't check that with our test harness, because
we can't redirect it.
Since it's not important that this gives the same error across
systems (and indeed we provide no way of intercepting the error!),
use an invocation test instead, because that allows different output per-uname.
See #5472.
300ms was waaay too long, and even 100ms wasn't necessary.
Emacs' evil mode uses 10ms (0.01s), so let's stay a tad higher in case
some terminals are slow.
If anyone really wants to be able to type alt+h with escape, let them
raise the timeout.
Fixes#3904.
This is a large change to how io_buffers are filled. The essential problem
comes about with code like (example):
echo ( /bin/pwd )
The output of /bin/pwd must go to fish, not the tty. To arrange for this,
fish does the following:
1. Invoke pipe() to create a pipe.
2. Add an io_bufferfill_t redirection that owns the write end of the pipe.
3. After fork (or equiv), call dup2() to replace pwd's stdout with this pipe.
Now when /bin/pwd writes, it will send output to the read end of the pipe.
But who reads it?
Prior to this fix, fish would do the following in a loop:
1. select() on the pipe with a 10 msec timeout
2. waitpid(WNOHANG) on the pwd proc
This polling is ugly and confusing and is what is replaced here.
With this new change, fish now reads from the pipe via a background thread:
1. Spawn a background pthread, which select()s on the pipe's read end with
a long (100 msec) timeout.
2. In the foreground, waitpid() (allowing hanging) on the pwd proc.
The big win here is a major simplification of job_t::continue_job() since
it no longer has to worry about filling buffers. This will make things
easier for concurrent execution.
It may not be obvious why the background thread still needs a poll (100 msec).
The answer is for cases where the write end of the fd escapes, in particular
background processes invoked inside command substitutions. psub is perhaps
the only important case of this (other shells typically just hang here).
Using printf like
printf "The message"
is unsafe, because if the message contains any formatting characters,
they'll be interpreted.
In this case it's not all that important because the message contains
only filenames of our tests and static strings, but still.
A while loop now evaluates to the last executed command in the body, or
zero if the loop body is empty. This matches POSIX semantics.
Add a bunch of tricky tests.
See #4982
For some reason, we have two places where a variable can be read-only:
- By key in env.cpp:is_read_only(), which is checked via set*
- By flag on the actual env_var_t, which is checked e.g. in
parse_execution
The latter didn't happen for non-electric variables like hostname,
because they used the default constructor, because they were
constructed via operator[] (or some such C++-iness).
This caused for-loops to crash on an assert if they used a
non-electric read-only var like $hostname or $SHLVL.
Instead, we explicitly set the flag.
We might want to remove one of the two read-only checks, or something?
Fixes#5548.
There's just waaayy too many things that could go wrong with it, so it
annoys more than it helps, especially since we don't get any
indication what failed.
E.g. on FreeBSD, the test failed without a usable message just because
`tput` couldn't find an attribute (so colors were unset).
The one thing I was missing:
`echo -n` isn't POSIX. In practice, it appears the only shell to encounter this
is macOS' crusty old bash in sh-mode. Just replace it with `touch`.
This reverts commit fc5e8f9fec.
This makes the script worse, but it's good enough.
The required changes are:
- `shopt -s nullglob`, which we simply don't use (we have one glob, but that's
guaranteed to match because we ship the files)
- One array, which we replace with a direct use of the glob (plus it
used `echo` again?)
- The `function` word, which I'm still annoyed is even a thing!
- Variable indirection (`color=${!color_var}` - instead we pass the
value directly - which makes the script uglier!)
- One array, which we replace with a function
- A use of `type -t`, replaced with `command -v`
- A use of `${var:begin:end}` substring expansion, replaced with trickery.
- `set -o pipefail` is replaced with a function
Note that checkbashisms still complains about `command -v`, because
we're not using it with "-p". But we _want_ to check the current
$PATH, and `command -v` is POSIX.
This still uses `local`, which technically isn't in POSIX.
The tests now appear to pass in:
- bash
- dash
- zsh
- mksh
- busybox
Rather than killing the process with close, read EOF after sending the
"exit" command and wait for OS cleanup (per the expect examples).
Not cleaning up with wait caused expect to crash on all 32-bit platforms
including i586 and armv7l with "alloc: invalid block: 0xbf993ccb: 3d 3b".
64-bit platforms were not affected, for reasons that are not clear.
Turns out busybox diff (used on alpine) defaults to unified output,
which we can't use because that prints filenames, and those are
tempfiles made by psub.
Instead, we use builtins to print the first line and compare the others.
This isn't all that important, and it breaks on musl just because the message is different.
Just skip it for now, until we figure out how to better test this.
This `set TERM`. Which, if $TERM is inherited, is already exported,
but not if it isn't.
This is the case on sr.ht's arch images, so we failed without a TERM variable.
Return STATUS_INVALID_ARGS when failing due to evaluation errors,
so we can tell the difference between an error and falseness.
Add a test for the ERANGE error
This previously used /dev/tty to make sure we have `source` connected
to a terminal. Only as it turns out, FreeBSD doesn't have that (https://builds.sr.ht/~faho/job/15308).
So instead, let's just use the expect tests since stdin there is by
definition a terminal.
This broke fishtape, which did
somestuff | fish -c "source"
Because `source` didn't have a redirection, it refused to read from
stdin.
So, to keep the common issue of `source (command that does not print)`
from seeminly stopping fish, we instead actually check if stdin is a terminal.
The colors happening for the interactive tests didn't match the
expected output. For `history search` commands we test, have them
pipe through `cat` so the fishscript does not use a pager or try
to colorize.
realpath() will return NULL and sets errno if it fails.
We asserted that realpath(".") does not fail. We also didn't really
check that it was successful. Made sure we'll get a perror telling
us about what went wrong if something like this happens again.
Updated tests and added test case
Fixes#5351
Prior to this fix, cding into a symlink and then completing .. would complete
from the physical directory instead of the logical directory, which could not
actually be cd'd to. Teach cd completiond to use the logical directory.
For things like
source $undefined
or
source (nooutput)
it was quite annoying that it read from tty.
Instead we now require a "-" as the filename to read from the tty.
This does not apply to reading from stdin if it's redirected, so
something | source
still works.
Fixes#2633.
This adds flags --path and --unpath to builtin set, analogous to
--export and --unexport. These flags change whether a variable is
marked as a path variable.
Universal variables cannot yet be path variables.
This switches quoted expansion like "$foo" to use foo's delimiter instead of
space. The delimiter is space for normal variables and colonf or path variables.
Expansions like "$PATH" will now expand using ':'.
This commit begins to bake in a notion of path-style variables.
Prior to this fix, fish would export arrays as ASCII record separator
delimited, except for a whitelist (PATH, CDPATH, MANPATH). This is
surprising and awkward for other programs to deal with, and there's no way
to get similar behavior for other variables like GOPATH or LD_LIBRARY_PATH.
This commit does the following:
1. Exports all arrays as colon delimited strings, instead of RS.
2. Introduces a notion of "path variable." A path variable will be
"colon-delimited" which means it gets colon-separated in quoted expansion,
and automatically splits on colons. In this commit we only do the exporting
part.
Colons are not escaped in exporting; this is deliberate to support uses
like
`set -x PYTHONPATH "/foo:/bar"`
which ought to work (and already do, we don't want to make a compat break
here).
This switches fish to a "virtual" PWD, where it no longer uses getcwd to
discover its PWD but instead synthesizes it based on normalizing cd against
the $PWD variable.
Both pwd and $PWD contain the virtual path. pwd is taught about -P to
return the physical path, and -L the logical path (which is the default).
Fixes#3350
Mostly resolves#4862, though there remains the lingering question of
whether or not to emit a warning to /dev/tty or stderr when a
non-literal-zero index evaluates to zero.
This allows for marking certain bindings as part of a preset, which allows us to
- only erase those when switching presets
- go back to the preset binding when erasing a user binding
- only show user customization if requested
- make bare bind statements in config.fish work (!!!11elf!!!)
Fixes#5191.
Fixes#3699.
- Add support for:
- Jumping to the character before a target.
- Repeating the previous jump (same direction, same precision).
- Repeating the previous jump in the reverse order.
- Enhance vi bindings.
When running a builtin, if we are an interactive shell and stdin is a tty,
then acquire ownership of the terminal via tcgetpgrp() before running the
builtin, and set it back after.
Fixes#4540
This changes the behavior of builtin math to floating point by default.
If the result of a computation is an integer, then it will be printed as an
integer; otherwise it will be printed as a floating point decimal with up to
'scale' digits past the decimal point (default is 6, matching printf).
Trailing zeros are trimmed. Values are rounded following printf semantics.
Fixes#4478
This adds a new string command split0, which splits on zero bytes.
split0 has superpowers because its output is not further split on
newlines when used in command substitutions.
If just one of the range ends is negative, this now forces direction away from it.
I.e. if the beginning is negative, we go in reverse.
If the end is negative, we go forwards.
This fixes cases like
$var[2..-1]
if $var only has one element.
This partially reverts 5b489ca30f, with
carets acting as redirections unless the stderr-nocaret flag is set.
This flag is off by default but may be enabled on the command line:
fish --features stderr-nocaret
This introduces a new command line option --features which can be used for
enabling or disabling features for a particular fish session.
Examples:
fish --features stderr-nocaret
fish --features 3.0,no-stderr-nocaret
fish --features all
Note that the feature set cannot be changed in an existing session.
This teaches the status command to work with features.
'status features' will show a table listing all known features and whether
they are currently on or off.
`status test-feature` will test an individual feature, setting the exit status to
0 if the feature is on, 1 if off, 2 if unknown.
`read` with IFS empty was expected to set all parameters after the first
n filled variables to an empty string, but that was inconsistent with
the behavior of `read` everywhere else.
I'm not sure why fish differed from the spec with regards to the
behavior in the event of an empty IFS: we eschew IFS where possible, yet
here we adopt non-standard behavior splitting on every (unicode)
character instead of not splitting at all with IFS empty. We still do
that, but now the unset variables are treated as they normally would be,
i.e. cleared and not set to an empty string (which is what an empty
value between two IFS separators would contain).
This removes the caret as a shorthand for redirecting stderr.
Note that stderr may be redirected to a file via 2>/some/path...
and may be redirected with a pipe via 2>|.
Fixes#4394
Variables set in if and while conditions are in the enclosing block, not
the if/while statement block. For example:
if set -l var (somecommand) ; end
echo $var
will now work as expected.
Fixes#4820. Fixes#1212.
This promotes "and" and "or" from a type of statement to "job
decorators," as a possible prefix on a job. The point is to rationalize
how they interact with && and ||.
In the new world 'and' and 'or' apply to a entire job conjunction, i.e.
they have "lower precedence." Example:
if [ $age -ge 0 ] && [ $age -le 18 ]
or [ $age -ge 75 ] && [ $age -le 100 ]
echo "Child or senior"
end
This now reports "TOO_MANY_ARGS" instead of no error (and triggering
an assertion).
We might want to add a new error type or report the missing operator
before, but this is okay for now.
This enables some limited use of arguments for wrapping completions. The
simplest example is that complete gco -w 'git checkout' now works like
you would want: `gco <tab>` now invokes git's completions with the
`checkout` argument prepended.
Fixes#1976
`argparse`, `read`, `set`, `status`, `test` and `[` now can't be used
as function names anymore.
This is because (except for `test` and `[`) there is no way to wrap these properly, so any
function called that will be broken anyway.
For `test` (and `[`), there is nothing that can be added and there
have been confused users who created a function that then broke
everything.
Fixes#3000.
This switches function execution from the function's source code to
its stored node and pstree. This means we no longer have to re-parse
the function every time we execute it.
Some of these were failing on Travis quite often, and this is probably
the result of too tight a window.
E.g. one emacs test (transpose words, default timeout, short delay)
waited 250ms to enter something else, with a timeout of 300ms. That
meant a window of 50ms.