The topic monitor allows a client to wait for multiple events, e.g. sigchld
or an internal process exit. Prior to this change a client had to specify
the list of generations and the list of topics they are interested in.
Simplify this to just the list of generations, with a max-value generation
meaning the topic is not interesting.
Also remove the use of enum_set and enum_array, it was too complex for what
it offered.
builtins output to stdout and stderr via io_streams_t. Prior to this fix, it
contained an output_stream_t which just wraps a buffer. So all builtin output
went to this buffer (except for eval).
Switch output_stream_t to become a new abstract class which can output to a
buffer, file descriptor, or nowhere. This allows for example `string` to stream
its output as it is produced, instead of buffering it.
When fish receives a "cancellation inducing" signal (SIGINT in particular)
it has to unwind execution - for example while loops or whatever else that
is executing. There are two ways this may come about:
1. The fish process received the signal
2. A child process received the signal
An example of the second case is:
some_command | some_function
Here `some_command` is the tty owner and so will receive control-C, but
then fish has to cancel function execution.
Prior to this change, these were handled uniformly: both would just set a
cancellation signal inside the parser. However in the future we will have
multiple parsers and it may not be obvious which one to set the flag in.
So instead distinguish these cases: if a process receives SIGINT we mark
the signal in its job group, and if fish receives it we set a global
variable.
This error only happens on recent versions of gcc, see previous
commit e6bb7fc973 for more info.
Instead of using `ignore_result()` here, I've added a `system_assert`
function/macro that mimics the behavior of all the other `system()`
calls in the file.
This reworks the "a=" detection to be simpler.
If we detect a variable assignment that produces an error,
simply consume it.
We also take the opportunity to not highlight it as an error,
and add some tests.
Original commit is 1ca05d32d3.
This switches parse_util_compute_indents from parsing with parse_tree to
the new ast.
It also reworks the parse_util_compute_indents tests, because
parse_util_compute_indents will be the backing for fish_indent.
fish's handling of terminal sizes is currently rather twisted. The
essential problem is that the terminal size may change at any point from a
SIGWINCH, and common_get_{width,height} may modify it and post variable
change events from arbitrary locations.
Tighten up the semantics. Assign responsibility for managing the tty size
to a new class, `termsize_container_t`. Rationalize locking and reentrancy.
Explicitly nail down the relationship between $COLUMNS/$LINES and the tty
size. The new semantics are: whatever changed most recently takes
precendence.
Prior to this change, if the user's prompt was wider than the terminal, we
would reduce it to just `> `. With this change, attempt to truncate the
prompt.
For each line of the prompt, calculate its width. If the width exceeds
COLUMNS, prepend ellipsis to that line, and start removing characters
until it fits. Escape sequences are skipped.
Fixes#904
The prefix 'haha' is short enough, (and phonetic enough), that it could collide with an existing user on the system where the tests are running, causing the test to fail.
1. When the wall time and cpu time rows has different units
e.x. running multiple cores
2. When duration is around 1E3 or 1E6 microseconds
printf("%6.2F", 999.995) gives 1000.00 which is 7 digits
debounce_t will be used to limit thread creation from background highlighting
and autosuggestion scenarios. This is a one-element queue backed by a
single thread. New requests displace any existing queued request; this
reflects the fact that autosuggestions and highlighting only care about
the most recent result.
A timeout allows for abandoning hung threads, which may happen if you
attempt to e.g. access a dead hard-mounted NFS server. We don't want
this to defeat autosuggestions and highlighting permanently, so allow
spawning a new thread after the timeout (here 500 ms).
Add the input function undo which is bound to `\c_` (control + / on
some terminals). Redoing the most recent chain of undos is supported,
redo is bound to `\e/` for now.
Closes#1367.
This approach should not have the issues discussed in #5897.
Every single modification to the commandline can be undone individually,
except for adjacent single-character inserts, which are coalesced,
so they can be reverted with a single undo. Coalescing is not done for
space characters, so each word can be undone separately.
When moving between history search entries, only the current history
search entry is reachable via the undo history. This allows to go back
to the original search string with a single undo, or by pressing the
escape key.
Similarly, when moving between pager entries, only the most recent
selection in the pager can be undone.
fd_monitor is a new class which can monitor a set of fds, waiting for them
to become readable. When an fd becomes readable, a callback is invoked.
Timeouts are also supported.
This is intended to replace the "bufferfill" threads. Rather than one
thread per bufferfill, we will have a single fd_monitor which can service
multiple bufferfills. This helps today with nested command substitutions,
and will help in the future with concurrent execution.
Prior to this fix, the cancellation C++ test would mark the parser as
interactive in an effort to install interactive signal handling (so that,
for example, SIGINT would stop the job and return control to the user).
However this flag would also cause fish to attempt to save and restore tty modes
across the job. This would fail since there is no tty, and so the job would fail
with an unexpected error code.
We don't need to mark the parser as interactive, we can just remove that line.
Fixes#6539.
Prior to this fix, fish was rather inconsistent in when $status gets set
in response to an error. For example, a failed expansion like "$foo["
would not modify $status.
This makes the following inter-related changes:
1. String expansion now directly returns the value to set for $status on
error. The value is always used.
2. parser_t::eval() now directly returns the proc_status_t, which cleans
up a lot of call sites.
3. We expose a new function exec_subshell_for_expand() which ignores
$status but returns errors specifically related to subshell expansion.
4. We reify the notion of "expansion breaking" errors. These include
command-not-found, expand syntax errors, and others.
The upshot is we are more consistent about always setting $status on
errors.
This commit recognizes an existing pattern: many operations need some
combination of a set of variables, a way to detect cancellation, and
sometimes a parser. For example, tab completion needs a parser to execute
custom completions, the variable set, should cancel on SIGINT. Background
autosuggestions don't need a parser, but they do need the variables and
should cancel if the user types something new. Etc.
This introduces a new triple operation_context_t that wraps these concepts
up. This simplifies many method signatures and argument passing.
Empty items are used as sentinels to indicate that we've reached the end of
history, so they should not be added as actual items. Enforce this.
Fixes#6032
user_supplied was used to distinguish IO redirections which were
explicit, vs those that came about through "transmogrphication." But
transmogrification is no more. Remove the flag.
parser_t::eval indicates whether there was a parse error. It can be
easily confused with the status of the execution. Use a real type to
make it more clear.
Prior to this fix, a file redirection was turned into an io_file_t. This is
annoying because every place where we want to apply the redirection, we
might fail due to open() failing. Switch to opening the file at the point
we resolve the redirection spec. This will simplify a lot of code.
fish has to ensure that the pipes it creates do not conflict with any
explicit fds named in redirections. Switch this code to using
autoclose_fd_t to make the ownership logic more explicit, and also
introduce fd_set_t to reduce the dependence on io_chain_t.
This adds initial support for statements with prefixed variable assignments.
Statments like this are supported:
a=1 b=$a echo $b # outputs 1
Just like in other shells, the left-hand side of each assignment must
be a valid variable identifier (no quoting/escaping). Array indexing
(PATH[1]=/bin ls $PATH) is *not* yet supported, but can be added fairly
easily.
The right hand side may be any valid string token, like a command
substitution, or a brace expansion.
Since `a=* foo` is equivalent to `begin set -lx a *; foo; end`,
the assignment, like `set`, uses nullglob behavior, e.g. below command
can safely be used to check if a directory is empty.
x=/nothing/{,.}* test (count $x) -eq 0
Generic file completion is done after the equal sign, so for example
pressing tab after something like `HOME=/` completes files in the
root directory
Subcommand completion works, so something like
`GIT_DIR=repo.git and command git ` correctly calls git completions
(but the git completion does not use the variable as of now).
The variable assignment is highlighted like an argument.
Closes#6048
We used to have a global notion of "is the shell interactive" but soon we
will want to have multiple independent execution threads, only some of
which may be interactive. Start tracking this data per-parser.
Now that our interactive signal handlers are a strict superset of
non-interactive ones, there is no reason to "reset" signals or take action
when becoming non-interactive. Clean up how signal handlers get installed.
This runs build_tools/style.fish, which runs clang-format on C++, fish_indent on fish and (new) black on python.
If anything is wrong with the formatting, we should fix the tools, but automated formatting is worth it.
These tests used raw, unescaped parentheses to perform `test` logical
grouping, but the test failures weren't caught because the parser
evaluation errors were not being propagated (fixed in bdbd173e).
Mostly related to usage _(L"foo"), keeping in mind the _
macro does a wcstring().c_str() already.
And a smattering of other trivial micro-optimizations certain
to not help tangibly.
As it turns out, NetBSD's rand(3) is awful - it's possible that in any
given run it'll only return odd numbers, which means
while (rand() % 10)
will never stop.
Since random(3) is also standardized and works, let's use that!
This introduces "internal processes" which are backed by a pthread instead
of a normal process. Internal processes are reaped using the topic
machinery, plugging in neatly alongside the sigchld topic; this means that
process_mark_finished_children() can wait for internal and external
processes simultaneously.
Initially internal processes replace the forked process that fish uses to
write out the output of blocks and functions.
This adds an "in-process" interpretation of dup2s, allowing for fish to
output directly to the correct file descriptor without having to perform
an in-kernel dup2 sequence.
topic_monitor allows for querying changes posted to one or more topics,
initially sigchld. This will eventually replace the waitpid logic in
process_mark_finished_children().
Comment from the new header:
Topic monitoring support. Topics are conceptually "a thing that can
happen." For example, delivery of a SIGINT, a child process exits, etc. It
is possible to post to a topic, which means that that thing happened.
Associated with each topic is a current generation, which is a 64 bit
value. When you query a topic, you get back a generation. If on the next
query the generation has increased, then it indicates someone posted to
the topic.
For example, if you are monitoring a child process, you can query the
sigchld topic. If it has increased since your last query, it is possible
that your child process has exited.
Topic postings may be coalesced. That is there may be two posts to a given
topic, yet the generation only increases by 1. The only guarantee is that
after a topic post, the current generation value is larger than any value
previously queried.
Tying this all together is the topic_monitor_t. This provides the current
topic generations, and also provides the ability to perform a blocking
wait for any topic to change in a particular topic set. This is the real
power of topics: you can wait for a sigchld signal OR a thread exit.
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).
This makes some significant architectual improvements to io_pipe_t and
io_buffer_t.
Prior to this fix, io_buffer_t subclassed io_pipe_t. io_buffer_t is now
replaced with a class io_bufferfill_t, which does not subclass pipe.
io_pipe_t no longer remembers both fds. Instead it has an autoclose_fd_t,
so that the file descriptor ownership is clear.
This represents a "resolved" io_chain_t, where all of the different io_data_t
types have been reduced to a sequence of dup2() and close(). This will
eliminate a lot of the logic duplication around posix_spawn vs fork, and pave
the way for in-process redirections.
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).
This makes some significant architectual improvements to io_pipe_t and
io_buffer_t.
Prior to this fix, io_buffer_t subclassed io_pipe_t. io_buffer_t is now
replaced with a class io_bufferfill_t, which does not subclass pipe.
io_pipe_t no longer remembers both fds. Instead it has an autoclose_fd_t,
so that the file descriptor ownership is clear.
This represents a "resolved" io_chain_t, where all of the different io_data_t
types have been reduced to a sequence of dup2() and close(). This will
eliminate a lot of the logic duplication around posix_spawn vs fork, and pave
the way for in-process redirections.
This requires threading environment_t through many places, such as completions
and history. We introduce null_environment_t for when the environment isn't
important.
Removes the dependency on the current user's home directory, instead
overriding it to be within the current hierarchy.
Fixes the tests on Debian buildd, where the home directory is
deliberately unwriteable to pick up errors in builds.
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
If the user is in a directory which has been unlinked, it is possible
for the path .. to not exist, relative to the working directory.
Always pass in the working directory (potentially virtual) to
path_get_cdpath; this ensures we check absolute paths and are immune
from issues if the working directory has been unlinked.
Also introduce a new function path_normalize_for_cd which normalizes the
"join point" of a path and a working directory. This allows us to 'cd' out of
a non-existent directory, but not cd into such a directory.
Fixes#5341
Limit the fish_wcstod fast path to ASCII digits only, to fix the problem
observed in the discussion for a700acadfa
where LANG=de_DE.UTF-8 would cause `test` to interpret commas instead of
periods inside floating point values.
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
This new function performs normalization of paths including dropping
/./ segments, and resolving /../ segments, in preparation for switching
fish to a "virtual" PWD.
Coalesces commands with leading (if even possible) and trailing
whitespace into the same item, improving the experience when iterating
over history entries.
Closes#4908.
If the replacement in `string replace` is invalid, prior to this fix we would
enter into an infinite loop trying to parse it. Instead report errors correctly.
Fixes#3381
Rather than having tokenizer_error as pointers to objects, switch it back
to just an error code value. This makes reasoning about it easier since
it's immutable values instead of mutable objects, and it avoids allocation
during startup.