This is a reimplementation of the "vectorized" ASCII detection
from str2wcs_internal. This handles the case where only part of
a string is ASCII. It also avoids pointer overflow issues and improves
commenting.
Prior to this change, str2wcs_internal had an optimization for ASCII
inputs. However the main cost was the repeated bounds checks when
performing push_back() on the resulting wcstring.
Switch to determining the number of ASCII characters, and then appending
those all in one go. This improves the time in the 'convert_ascii' test
from ~450 usec to ~75 usec.
When pressing tab repeatedly, completions only computed on the first one. This
is because the old logic assumed that completions are present if the last
key was tab. Recompute them if there are no completions at all.
Fixes#6863
Since builtins don't actually have the streams connected, but instead
read input via the io_streams_t objects, this would just always say
what *fish's* fds were.
Instead, pass along some of the stream data to check those
specifically - nobody cares that `test`s fd 0 *technically* is stdin.
What they want to know is that, if they used another program in that
place, it would connect to the TTY.
This is pretty hacky - I abused static variables for this, but
since it's two bools and an int it's probably okay.
See #1228.
Fixes#4766.
(regression from d415350aaf)
This is important especially in e.g. the new Windows Terminal, because
for some reason that lets the tab stick around if the process exited
with a non-zero status.
Will add tests as soon as I figure out how.
Taken from GNU realpath, this one makes realpath not resolve symlinks.
It still makes paths absolute and handles duplicate and trailing
slashes.
(useful in fish_add_path)
With a commandline like
```
a b c d
```
and the cursor at the beginning, this would eat "a b", which isn't a
sensible bigword.
Bigword should be "a word, with optional leading whitespace".
This was caused by an overly zealous state-machine that always ate one
char and only *then* started eating leading whitespace.
Instead eat *a character*, and if it was whitespace go on eating
whitespace, and if it was a printable go straight to only eating
printables.
Fixes#7325.
This can easily lead to an infinite loop, if a variable handler
triggers a repaint and the variable is set in the prompt, e.g. some of
the git variables.
A simple way to reproduce:
function fish_mode_prompt
commandline -f repaint
end
Repainting executes the mode prompt, which triggers a repaint, which
triggers the mode prompt, ....
So we just set a flag and check it.
Fixes#7324.
Currently, completions have to be specified like
```fish
complete -c foo -l opt
```
while
```fish
complete foo -l opt
```
just complains about there being too many arguments.
That's kinda useless, so we just assume if there is one left-over
argument that it's meant to be the command.
Theoretically we could also use *all* the arguments as commands to
complete, but that seems unlikely to be what the user wants.
(I don't think multi-command completions really happen)
Currently only `complete` will list completions, and it will list all
of them.
That's a bit ridiculous, especially since `complete -c foo` just does nothing.
So just make `complete -c foo` list all the completions for `foo`.
Found with gcc's -Wmissing-declarations which gives warnings like
../src/tinyexpr.cpp:61:5: warning: no previous declaration for ‘int get_arity(int)’ [-Wmissing-declarations]
61 | int get_arity(const int type) {
The same warnings show up for builtin functions like builtin_bg because they
currently don't include their own headers. I left that.
Also reformat the touched files.
So we can do something on every edit, for example repaint the pager (#7318).
This patch fixes pager refiltering and repainting when pressing Control+U
after typing something in the search field.
Implement this by moving the convenience functions from editable_line_t to
the reader, so we have fewer places where we need to refilter. Essentially we
only have two cases: insertions at the cursor are handled by insert_string(),
and all others go through push_edit(). This should also make it clearer
where we update undo_history.may_coalesce.
This commit was on the history-search-edit-needle branch, so it should
work fine. I hope it does play well with some recent changes.
In 6d339df61 (Factor repainting decions from readline commands better
in the reader), insert_string() was simplified a lot, mirror that.
The tests for editable_line_t are not that useful anymore since the caller has
to decide whether to coalesce insertions, but I guess they don't hurt either.
We should have more tests for some interactive scenarios like undo and the
pager filtering.
This was broken in 6d339df612, when we removed
the normal repainting logic.
The pager *search* however needs to trigger a refilter, and therefore
needs to trigger after every insert/removal.
Fixes#7318
This avoids the heavy hit of __gconv_transform_utf8_internal.
In the worst case, after `is_ascii` returns the string is guaranteed to
be in the CPU cache (assuming realistic input sizes). In the best (and
hopefully extremely common) case, the conversion table lookups are
completely avoided.
In terms of real world gains, simply calling `history` is anywhere from
2x to 3x faster for large history files composed of mostly ascii
content under glibc 2.31 on AMD64.
Previously, when a command wasn't found, fish would emit the
"fish_command_not_found" *event*.
This was annoying as it was hard to override (the code ended up
checking for a function called `__fish_command_not_found_handler`
anyway!), the setup was ugly,
and it's useless - there is no use case for multiple command-not-found handlers.
Instead, let's just call a function `fish_command_not_found` if it
exists, or print the default message otherwise.
The event is completely removed, but because a missing event is not an error
(MEISNAE in C++-speak) this isn't an issue.
Note that, for backwards-compatibility, we still keep the default
handler function around even tho the new one is hard-coded in C++.
Also, if we detect a previous handler, the new handler just calls it.
This way, the backwards-compatible way to install a custom handler is:
```fish
function __fish_command_not_found_handler --on-event fish_command_not_found
# do a little dance, make a little love, get down tonight
end
```
and the new hotness is
```fish
function fish_command_not_found
# do the thing
end
```
Fixes#7293.
It was possible though unlikely for make_autoclose_pipes to close only
one side of pipe, if it fails to find a new fd. This would result in an
fd leak. Ensure that doesn't happen.
On BSDs, anonymous semaphores are implemented using a file descriptor
which is not marked CLOEXEC, so it gets leaked into child processes.
Use ordinary pipes instead of semaphores everywhere except Linux.
Fixes#7304
Now command, jobs, type, abbr, builtin, functions and set take `-q` to
query for existence, but the long option is inconsistent.
The first three use `--quiet`, the latter use `--query`. Add `--query`
to the first three, but keep `--quiet` around.
Fixes#7276.
This concerns how "internal job groups" know to stop executing when an
external command receives a "cancel signal" (SIGINT or SIGQUIT). For
example:
while true
sleep 1
end
The intent is that if any 'sleep' exits from a cancel signal, then so would
the while loop. This is why you can hit control-C to end the loop even
if the SIGINT is delivered to sleep and not fish.
Here the 'while' loop is considered an "internal job group" (no separate
pgid, bash would not fork) while each 'sleep' is a separate external
command with its own job group, pgroup, etc. Prior to this change, after
running each 'sleep', parse_execution_context_t would check to see if its
exit status was a cancel signal, and if so, stash it into an int that the
cancel checker would check. But this became unwieldy: now there were three
sources of cancellation signals (that int, the job group, and fish itself).
Introduce the notion of a "cancellation group" which is a set of job
groups that should cancel together. Even though the while loop and sleep
are in different job groups, they are in the same cancellation group. When
any job gets a SIGINT or SIGQUIT, it marks that signal in its cancellation
group, which prevents running new jobs in that group.
This reduces the number of signals to check from 3 to 2; eventually we can
teach cancellation groups how to check fish's own signals and then it will
just be 1.
The 'time' prefix may come about either because the job itself is marked
with time, or because of the "inside out" weirdness of 'not time...'.
Factor this logic together and precompute it for a job.
This would only check for fish_right_prompt at startup, so if one
wasn't defined then it would never accept one.
The "config" here is just the *name* of the function (which we never
change, so it wouldn't really be necessary, but whatever).
The one exception is the breakpoint, in those we don't run the right
prompt.
Fixes#7302.
This allows us to send proper debug messages via FLOG, and it removes
more things from share/config.fish.
Note that the logic differs in some subtle ways. For instance it will
now obey $COLORTERM, so if that isn't "truecolor" or "24bit" it will
deactivate truecolor.
This adds a new type 'exit_state_t' which encapsulates where fish is in
the process of exiting. This makes it explicit when fish wants to cancel
"ordinary" fish script but still run exit handlers.
There should be no user-visible behavior change here; this is just
refactoring in preparation for the next commit.
The line offset of a trailing newline on the commandline was computed incorrectly.
As a result, up-arrow did not work for a commandline like the one inserted by:
commandline -i echo '' ''
Note this and the previous commit in the changelog.
Enter a multiline commandline, for example using
commandline -i echo echo
And press down-arrow. This will start a new history search which fails.
Then press up-arrow. I expect the cursor to move up, however, because we
are still in history search mode, up-or-search will search instead of moving
the cursor. Correct that by stopping history searches that don't have any results.
Just as `math "bitand(5,3)"` and `math "bitor(6,2)"`.
These cast to long long before doing their thing,
so they truncate to an integer, producing weird results with floats.
That's to be expected because float representation is *very*
different, and performing bitwise operations on floats feels quite useless.
Fixes#7281.
Prior to this change, if we saw more than one repaint readline command in
a row, we would try to ignore the second one. However this was never the
right thing to do since sometimes we really do need to repaint twice in a
row (e.g. the user hits Ctrl+L twice). Previously we were saved by the
buginess of this mechanism but with the repainting refactoring we see
missing redraws.
Remove the coalescing logic and add a test. Fixes#7280.
If you expand an abbreviation by executing the command, fish uses a
synchronous mode of syntax highlighting that performs no I/O, because we
want to highlight the abbreviation but don't know if it's valid or not
without doing I/O. However we were doing this too aggressively, after
every command regardless of whether it contained an abbreviation. Only
do this for commands with abbreviations.
When typing into the command line, some actions should trigger repainting,
others should kick off syntax highlighting or autosuggestions, etc. Prior
to this change, these were all triggered in an ad-hoc manner. Each
possible
This change centralizes the logic around repainting. After each readline
command or text change, we compute the difference between what we would
draw and what was last drawn, and use that to decide whether to repaint
the screen.
This is a fairly involved change. Bugs here would show up as failing to
redraw, not reacting to a keypress, etc. However it better factors the
readline command handling from the drawing.
With the prior commit, the topic_monitor only writes to the pipe if a
thread is known to be waiting. This is effectively a binary semaphore, and
on systems that support anon semaphores (yes Linux, but not Mac) we can use
them. These are more efficient than self-pipes.
We add a binary_semaphore_t class which uses sem_t if sem_init succeeds,
and a self-pipe if it fails.
On Linux the seq_echo benchmark (run 1024 times) goes from 12.40 seconds to
11.59 seconds, about an 11% improvement.
The topic monitor is what allows a thread to wait for any of a set of
events. Events are identified by a bit in a "pending update" mask. Prior to
this fix, post() would atomically set the bit, and if it was newly set,
announce the change by unconditionally writing to a self-pipe. Threads
could wait for new posts by reading from the pipe.
This is less efficient than it could be; in particular if no thread is
waiting on the pipe, then the write() is unnecessary. This slows down our
signal handler.
Change the design in the following way: if a thread is committed to
waiting, then it atomically sets the "pending update" mask (now just called
status) to a sentinel value STATUS_NEEDS_WAKEUP. Then post() will only
write to the self-pipe if it sees that there is a thread waiting. This
reduces the number of syscalls.
The total effect is hardly noticeable (usually there is a thread waiting)
but it will be important for the next commit.
It could be nice to use a heuristic for this in future, but for now let's
stick to the old behavior so we can keep formatting scripts without occasional
bad formatting changes.
A heuristic could also be used to break lines after |, && or || but I don't
think there is much need for that at the moment.
Closes#7252
We weren't correctly updating the internal exit generation value. This
meant that if one internal process exits, every other internal process
that has not exited will continually check, leading to 100% CPU usage.
I think this mainly affects concurrent mode, but it may be reproducible
if you have a command which refuses to consume its input.
Prior to this fix, the `exit` command would set a global variable in the
reader, which parse_execution would check. However in concurrent mode you
may have multiple scripts being sourced at once, and 'exit' should only
apply to the current script.
Switch to using a variable in the parser's libdata instead.
This concerns code like the following:
while true ; sleep 100; end
Here 'while' is a "simple block execution" and does not create a new job,
or get a pgid. Each 'sleep' however is an external command execution, and
is treated as a distinct job. (bash is the same way). So `while` and
`sleep` are always in different job groups.
The problem comes about if 'sleep' is cancelled through SIGINT or SIGQUIT.
Prior to 2a4c545b21, if *any* process got a SIGINT or SIGQUIT, then fish
would mark a global "stop executing" variable. This obviously prevents
background execution of fish functions.
In 2a4c545b21, this was changed so only the job's group gets marked as
cancelled. However in the case of one job group spawning another, we
weren't propagating the signal.
This adds a signal to parse_execution_context which the parser checks after
execution. It's not ideal since now we have three different places where
signals can be recorded. However it fixes this regression which is too
important to leave unfixed for long.
Fixes#7259
This used to be used to determine which token contained the cursor, so
as to highlight potential paths. But now we highlight all potential paths,
so we can remove the field.
In practice we didn't use the cache for anything. Always compute it on
demand.
This eliminates the 'indents' variable which had to be manually kept in
sync with the command line.
Also return the number of failed files.
I decided to *just* print the filenames (newline-separated because
NULLs are annoying here) to make it easier to deal with.
See #7251.
This indents continuations after pipes and conjunctions if they contain
a newline.
Example:
cmd1 &&
cmd2
But it avoids the "double indent" if it indented unconditionally:
cmd1 | begin
cmd2
end
More work towards improving #7252
Prior to this change, when emitting gap text (comments, newlines, etc),
fish_indent would use the indentation of the text at the end of the gap.
But this has the wrong result for this case:
begin
command
# comment
end
as the comment would get the indent of the 'end'. Instead use the indent
computed for the gap text itself.
Addresses one case of #7252.
The ternary expression was causing the list of paths (e.g.
$fish_function_path) to be copied. Avoid that copy with an if statement.
This reduces the time spent in try_autoload from 2.4 sec to 961ms on
the seq_echo benchmark run 1024 times, about 5% improvement.
Oh, C++...
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.
This can be used to determine whether the previous command produced a real status, or just carried over the status from the command before it. Backgrounded commands and variable assignments will not increment status_generation, all other commands will.
This pulls in widechar_width.h from commit 7e9dfdaf05059b3f. The big change
here is that some characters which were previously marked as widened in 9
are now marked as unconditionally narrow; this includes some randoms like
hot pepper (U+1F336) but more importantly all of the regional indicators,
which affects how flags are rendered.
If you put two regional indicators together, you get a flag emoji. It's
unclear what the width of this flag emoji should be; Terminal and iTerm2
renders it as width 1, while kitty renders it as width 2. This is
unaffected by fish_emoji_width because the flag does not have an assigned
codepoint, it is a pair of codepoints.
The regional indicators are marked as "neutral" in EastAsianWidth.txt which
means they conceptually have width 1. So two of them have width 2. So now
we assume that flags are rendered as width 2.
This fixes#7237, for terminals that render flags as width 2 (but not 1,
unfortunately, which includes iTerm2 and Terminal.app).
This pulls in widechar_width.h from commit d4e75d5bb1930291223d1.
This is a "rebuild with latest data" before we attempt a risky bugfix.
The idea here is that bisecting can separate whether any regression is
due to using the latest Unicode data, or the bug fix.
Prior to this change, fish would "resolve" highlight specs to rgb colors
right before use. This requires a series of variable lookups; profiling
showed 30% of draw time was spent here.
Switch to caching these (within a single redraw only).
Have the reader accept a constant configuration object, which controls
whether autosuggestions, etc. are enabled. These things don't change
dynamically.
fish_color_match is a variable which controls syntax highlighting for
matching quotes and parens, but only with interactive `read` with shell
highlighting disabled. It seems unlikely that anybody cares about this.
In principle this would allow 'string split' or whatever to output to
stderr and not lose the item separation. In practice this is not used
but it fixes a TODO.
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.
In commit fd6d814ea4, read_blocked was changed to read until EOF
or the full amount requested is returned. Switch this to returning
as soon as any data is available, which was the behavior prior to
fd6d814ea4.
This will allow builtin_string to output data in a "streaming"
fashion instead of needing to read a large block up-front.
Prior to this fix, if you invoked fish with --private and then used
`read --silent` to read something sensitive, the variable would be
stored in history, with the plain text available through up-arrow.
Fix it to not store items in silent mode.
Note the item was never written to disk; it was only stored in memory.
Fixes#7230
This is like wcs2string, but instead of returning a std::string, it invokes
a user-supplied function with each converted character.
The idea is to allow interleaved conversion and output.
This moves us slightly closer towards fish code in the background. The idea is
that a background job may still have "foreground" sub-jobs, example:
begin ; sleep 5 ; end &
The begin/end job runs in the background but should wait for `sleep`.
Prior to this fix, fish would see the overall job group is in the background
and not wait for any of its processes. With this change we detach waiting from
is_foreground.
This changes how fish attempts to protect itself from calling tcsetpgrp() too
aggressively. Recall that tcsetpgrp() will "force" itself, if SIGTTOU is
ignored (which it is in fish when job control is enabled).
Prior to this fix, we avoided SIGTTINs by only transferring the tty ownership
if fish was already the owner. This dated from a time before we had really
nailed down how pgroups should be assigned. Now we more deliberately assign a
job's pgroup so we don't need this conservative check.
However we still need logic to avoid transferring the tty if fish is not the
owner. The bad case is when job control is enabled while fish is running in the
background - here fish would transfer the tty and "steal" from the foreground
process.
So retain the checks of the current tty owner but migrate them to the point of
calling tcsetpgrp() itself.
add_disowned_pgid skipped jobs that have a PGID equal to the running
process. However, this includes processes started in config.fish or when
job control is turned off, so they never get waited on.
Instead, refactor this function to add_disowned_job, and add either the PGID or
all the PIDs of the job to the list of disowned PIDs/PGIDs.
Fixes#7183.
This is a set of miscellaneous cleanup for profiling.
An errant newline has been removed from 'if' statement output, which got
introduced with the new ast.
Switch from storing unique_ptr to a deque, which allocates less.
Collapse "parse" and "exec" times into just a single value "duration". The
"parse" time no longer makes sense, as we now parse ahead of time.
The prefix has already been case-corrected at this point and the remaining
completions are for the suffix only.
Fixes#7211
Introduced in
28d67c8f Show completion list on Tab also if a common prefix was inserted
These are events that have been queued but not yet fired. There's no
reason to modify the events after creating them. Mark them as const
to ensure that doesn't happen.