Commit Graph

4531 Commits

Author SHA1 Message Date
Johannes Altmanninger
f637fb31b5 highlight: underline prefixes of valid paths only if at cursor
As the user is typing an argument, fish continually checks if the input is
the prefix of a valid file path. If yes, the input is underlined.

The same prefix-logic is used for all tokens on the command line, even for
"finished" tokens. This means we highlight any token that happens to be
a prefix of a valid file path. We actually want this to only apply to the
token that the user is currently typing.

Let's use the prefix-logic only for tokens adjacent to the cursor.  This should
better match user expectations (and reduce IO traffic). I don't think this is
the perfect criteria but I don't know how else we can determine if a token is
"unfinished".
2022-10-26 16:12:43 +02:00
Johannes Altmanninger
6667c9f50c highlighter: pass the cursor position to the highlighter
This allows the next commit to correct highlighting based on the cursor
position.
2022-10-26 16:11:00 +02:00
Johannes Altmanninger
861ac00a61 highlighter: underline valid "cd" arguments also if they come from CDPATH
When visiting the "cd" node, we mark invalid paths as error, but don't
underline valid paths.  This works fine most of the time because we later
underline paths (for any command, not just "cd").
However the latter check fails to honor CDPATH.  Let's correct that, which
also allows to simplify the logic.
2022-10-26 16:11:00 +02:00
Johannes Altmanninger
dfb0c00d72 highlighter: stop performing IO if canceled
The next commit wants to move the "Underline every valid path" logic into the
visit() methods. The logic currently polls the cancel checker before checking
each path. If that's valid, it should probably have the same behavior inside
visit(). Since we currently can't cancel an AST-visitation, the next best
thing seems to suspend all IO operations, the rest should be very fast anyway.

I'm not sure if the motivation is strong enough; a conceivable alternative
would be to stop using the cancel checker altogether for highlighting.
2022-10-26 16:11:00 +02:00
Johannes Altmanninger
9c6f46a808 highlighter: remove redundant check if we can do io
It's done a few lines above.
2022-10-26 16:09:02 +02:00
Johannes Altmanninger
acb47f70d2 history_file.cpp: remove an unused variable
Now that maybe_t<size_t> no longer has a user-defined destructor, the compiler
can better detect an unused variable of this type.
2022-10-26 16:09:02 +02:00
Johannes Altmanninger
9d303a74e3 maybe_t: make maybe_t<T> trivially copyable if T is
When passing a value of type maybe_t<size_t>, clangd complains:

    Parameter 'cursor' is passed by value and only copied once; consider
    moving it to avoid unnecessary copies (fix available)

We get this warning because maybe_t<size_t> is not trivially copyable
because it has a user-defined destructor and copy-constructor.  Let's remove
them if the contained type is trivially copyable, to avoid such warnings.
No functional change.
2022-10-26 16:09:02 +02:00
Johannes Altmanninger
1ce2961561 maybe_t: remove user-defined destructor
The destructor is equivalent to the compiler-generated one.  The user-defined
destructor prevents maybe_t<size_t> from bearing the predicate "trivially
copyable". Let's remove it. No functional change.
2022-10-26 14:54:33 +02:00
Johannes Altmanninger
45da77c5c5 Format some C++ files with clang-format 2022-10-26 14:53:06 +02:00
Mahmoud Al-Qudsi
21599a49ea Make CALL_STACK_LIMIT_EXCEEDED_ERR_MSG more generic
We're now using this when a stack overflow is detected during eval/substitution
loops, too.
2022-10-25 13:40:21 -05:00
Mahmoud Al-Qudsi
175caab583 Prevent stack overflow from eval/substitution recursion
It seems to have originally been thought that the only possible way a stack
overflow could happen is via function calls, but there are other possibilities.

Issue #9302 reports how `eval` can be abused to recursively execute a string
substitution ad infinitum, triggering a stack overflow in fish.

This patch extends the stack overflow check to also check the current
`eval_level` against a new constant `FISH_MAX_EVAL_DEPTH`, currently set to a
conservative but hopefully still fair limit of 500. For future reference, with
the default stack size for the main/foreground thread of 8 MiB, we actually have
room for a stack depth around 2800, but that's only with extremely minimal state
stored in each stack frame.

I'm not entirely sure why we don't check `eval_depth` regardless of block type;
it can't be for performance reasons since it's just a simple integer comparison
- and a ridiculously easily one for the branch predictor handle, at that - but
maybe it's to try and support non-recursive nested execution blocks of greater
than `FISH_MAX_STACK_DEPTH`? But even without recursion, the stack can still
overflow so may be we should just bump the limit up some (to 500 like the new
`FISH_MAX_EVAL_DEPTH`?) and check it all the time?

Closes #9302.
2022-10-25 13:40:21 -05:00
Mahmoud Al-Qudsi
e7bf98adc1 Make block_t moveable
The presence of the explicit constructor (even though it did nothing) prevented
the compiler from generating a move constructor for `block_t`.
2022-10-24 22:06:30 -05:00
Mahmoud Al-Qudsi
84b53b4cae Significantly reduce size of block_t
A `block_t` instance is allocated for each live block type in memory when
executing a script or snippet of fish code. While many of the items in a
`block_t` class are specific to a particular type of block, the overhead of
`maybe_t<event_t>` that's unused except in the relatively extremely rare case of
an event block is more significant than the rest, given that 88 out of the 216
bytes of a `block_t` are set aside for this field that is rarely used.

This patch reorders the `block_t` members by order of decreasing alignment,
bringing down the size to 208 bytes, then changes `maybe_t<event_t>` to
`shared_ptr<event_t>` instead of allocating room for the event on the stack.
This brings down the runtime memory size of a `block_t` to 136 bytes for a 37%
reduction in size.

I would like to investigate using inheritance and virtual methods to have a
`block_t` only include the values that actually make sense for the block rather
than always allocating some sort of storage for them and then only sometimes
using it. In addition to further reducing the memory, I think this could also be
a safer and saner approach overall, as it would make it very clear when and
where we can expect each block_type_type_t-dependent member to be present and
hold a value.
2022-10-24 21:04:17 -05:00
Mahmoud Al-Qudsi
44c9c51841 Disable leak detection in test_autosuggest_suggest_special() under CI
This is a false positive as a result of disabling TLS support in LSAN due to an
incompatibility with newer versions of glibc.

Also remove the older workaround (because it didn't work).
2022-10-24 19:02:49 -05:00
Mahmoud Al-Qudsi
fed64999bc Allow erasing in multiple scopes in one go 2022-10-20 11:21:05 -05:00
Mahmoud Al-Qudsi
99bc112de0 Fix unqualified calls to std::move
`using` is for types, not functions :(
2022-10-19 12:31:55 -05:00
Mahmoud Al-Qudsi
920ded26b9 history: Handle Ctrl-C/SIGINT or other errors on output append
When there are multiple screens worth of output and `history` is writing to the
pager, pressing Ctrl-C at the end of a screen doesn't exit the pager (`q` is
needed for that) but previously caused fish to emit an error ("write:
Interrupted system call) until we starting silently handling SIGINT in
`fd_output_stream_t::append()`.

This patch makes `history` detect when the `append()` call returns with an error
and causes it to end early rather than repeatedly trying (and failing) to write
to the output stream.
2022-10-16 15:38:11 -05:00
Mahmoud Al-Qudsi
83636fa599 Silently handle fd_output_stream_t append errors in case of SIGINT
If EINTR caused by SIGINT is encountered while writing to the
`fd_output_stream_t` output fd, mark the output stream as errored and return
false to the caller but do not visibly complain.

Addressing the outstanding TODO notwithstanding, this is needed to avoid
littering the tty with spurious errors when the user hits Ctrl-C to abort a
long-running builtin's output (w/ the primary example being `history`).
2022-10-16 15:38:11 -05:00
Mahmoud Al-Qudsi
8e97fcb22c Make output_stream_t::append() fallible
Allow errors encountered by certain implementations of `output_stream_t` when
writing to the output sink to be bubbled back to the caller.
2022-10-16 15:38:11 -05:00
Mahmoud Al-Qudsi
b94b896503 Shrink size of env_mode_flags_t 2022-10-15 15:15:04 -05:00
Fabian Boehm
52dcfe11af Make \x the same as \X
Up to now, in normal locales \x was essentially the same as \X, except
that it errored if given a value > 0x7f.

That's kind of annoying and useless.

A subtle change is that `\xHH` now represents the character (if any)
encoded by the byte value "HH", so even for values <= 0x7f if that's
not the same as the ASCII value we would diverge.

I do not believe anyone has ever run fish on a system where that
distinction matters. It isn't a thing for UTF-8, it isn't a thing for
ASCII, it isn't a thing for UTF-16, it isn't a thing for any extended
ASCII scheme - ISO8859-X, it isn't a thing for SHIFT-JIS.

I am reasonably certain we are making that same assumption in other
places.

Fixes #1352
2022-10-09 15:24:01 +02:00
Mahmoud Al-Qudsi
85d4834b35 Make maybe_t safer against accidental misuse
Closes #9240.

Squash of the following commits (in reverse-chronological order):

commit 03b5cab3dc40eca9d50a9df07a8a32524338a807
Author: Mahmoud Al-Qudsi <mqudsi@neosmart.net>
Date:   Sun Sep 25 15:09:04 2022 -0500

    Handle differently declared posix_spawnxxx_t on macOS

    On macOS, posix_spawnattr_t and posix_spawn_file_actions_t are declared as void
    pointers, so we can't use maybe_t's bool operator to test if it has a value.

commit aed83b8bb308120c0f287814d108b5914593630a
Author: Mahmoud Al-Qudsi <mqudsi@neosmart.net>
Date:   Sun Sep 25 14:48:46 2022 -0500

    Update maybe_t tests to reflect dynamic bool conversion

    maybe_t<T> is now bool-convertible only if T _isn't_ already bool-convertible.

commit 2b5a12ca97b46f96b1c6b56a41aafcbdb0dfddd6
Author: Mahmoud Al-Qudsi <mqudsi@neosmart.net>
Date:   Sun Sep 25 14:34:03 2022 -0500

    Make maybe_t a little harder to misuse

    We've had a few bugs over the years stemming from accidental misuse of maybe_t
    with bool-convertible types. This patch disables maybe_t's bool operator if the
    type T is already bool convertible, forcing the (barely worth mentioning) need
    to use maybe_t::has_value() instead.

    This patch both removes maybe_t's bool conversion for bool-convertible types and
    updates the existing codebase to use the explicit `has_value()` method in place
    of existing implicit bool conversions.
2022-10-08 11:56:38 -05:00
Johannes Altmanninger
485873b19b Share logic between move constructor/assignment of dir_iter_t
The parent commit made the destructor of the DIR* member close it if necessary
(i.e. only if it's not null).  This means that we can use the same logic in
the move constructor (where the source DIR* is null) and for move assignment
(where it might not be).

No functional change.
2022-10-08 17:32:12 +02:00
Johannes Altmanninger
da5d93b4de dir_iter_t to use unique_ptr for closing directory
dir_iter_t closes its DIR* member in two places: the move assignment and
the destructor. Simplify this by closing it in the destructor of the DIR*
member which is called in both places. Use std::unique_ptr, which is shorter
than a dedicated wrapper class. Conveniently, it calls the deleter only if
the pointer is not-null.  Unfortunately, std::unique_ptr requires explicit
conversion to DIR* when interacting with C APIs but it's probably still
better than a wrapper class.

This means that the noncopyable_t annotation is now implied due to the
unique_ptr member.
Additionally, we could probably remove the user-declared move constructor
and move assignment (the compiler-generated ones should be good enough). To
be safe, keep them around since they also erase the fd (though I hope we
don't rely on that behavior anywhere).

We should perhaps remove the user-declared destructor entirely but
dir_iter_t::entry_t also has one, I'm not sure why. Maybe there's a good
reason, like code size.

No functional change.
2022-10-08 17:31:47 +02:00
Johannes Altmanninger
f82537bcdc color_string_internal to use a sentinel value that's definitely invalid
I think -1 is slightly more elegant than 0 because 0 could be a valid offset.

No functional change.
2022-10-05 22:27:00 -05:00
Johannes Altmanninger
5868b3c380 read_unquoted_escape: remove dead loop condition
This was recently converted to a while-loop. However, we only
loop in a specific case when (by hitting "continue") so a
loop condition is not necessary.

No functional change.
2022-10-05 22:27:00 -05:00
Fabian Boehm
e7a7a58030 Remove use of maybe_t that makes gcc grumpy
We have a state machine here already, we can just use the state where
the variable is valid.
2022-10-05 22:34:19 +02:00
Fabian Boehm
460f56f95a Revert "Silence gcc warning"
This reverts commit 8ab437a989.

It introduced a warning for clang - because that read the GCC pragma and didn't understand it.
2022-10-05 22:29:04 +02:00
Fabian Boehm
8ab437a989 Silence gcc warning
This complained that the variable might be uninitialized *right* after
the check that it wasn't, because it doesn't understand maybe_t.
2022-10-05 19:07:41 +02:00
Fabian Boehm
396e276286 Decode multibyte escapes immediately
We forgot to decode (i.e. turn into nice wchar_t codepoints)
"byte_literal" escape sequences. This meant that e.g.

```fish
string match ö \Xc3\Xb6

math 5 \X2b 5
```

didn't work, but `math 5 \x2b 5` did, and would print the wonderful
error:

```
math: Error: Missing operator
'5 + 5'
   ^
```

So, instead, we decode eagerly.
2022-10-05 18:55:01 +02:00
Sergei Shilovsky
e274ef6c0d
commandline --selection-start and --selection-end implementation
Fixes #9197
2022-10-05 18:51:00 +02:00
Fabian Boehm
dcf52dbba5 fix path --null-out
Regression from 7bc4c9674b.

Appending `"\0"` to an std::string does nothing.

I blame C++.
2022-10-05 17:25:00 +02:00
Fabian Boehm
cb28b39b24 string shorten: Make max of 0 mean no shortening
This makes it easier to just slot in `string shorten` wherever,
without having to do a weird "if test $max -gt 0" check.
2022-10-04 18:44:21 +02:00
Fabian Boehm
cdf1a94e29 ifdef DT_WHT 2022-10-04 17:00:04 +02:00
ridiculousfish
757c117591 Handle symlink loops in descend_unique_hierarchy
descend_unique_hierarchy is used for the cd autosuggestion: if a directory
contains exactly one subdirectory and no other entries, then propose that
as part of the cd autosuggestion.

This had a bug: if the subdirectory is a symlink to the parent, we would
chase that, going around the loop suggesting a longer path until we hit
PATH_MAX.

Fix this by using the new API which provides the inode "for free," and
track whether we've seen this inode before. This is technically too
conservative since the inode may be for a directory on a different device,
but devices are not available for free so this would incur a cost. In
practice encountering the same inode twice with different devices in a
unique hierarchy is unlikely, and should it happen the consequences are
merely cosmetic: we fail to suggest a longer path.
2022-10-02 18:56:46 -07:00
ridiculousfish
0b47ba0642 Remove wreaddir and wreaddir_resolving
dir_iter_t has replaced these functions; we can remove them.
2022-10-02 18:48:16 -07:00
ridiculousfish
a2d816710f Adopt dir_iter_t in wildcard.cpp
Migrate wildcard's directory iteration to the new dir_iter_t.
Remove a now-unused function.
2022-10-02 18:48:16 -07:00
ridiculousfish
749d71288d Adopt dir_iter_t in descend_unique_hierarchy
Migrate this function from wreaddir_resolving to dir_iter_t
2022-10-02 18:48:16 -07:00
ridiculousfish
2a9366f938 Migrate highlight.cpp usage of wreaddir to dir_iter_t
Switch to the new API instead of using opendir directly.
2022-10-02 18:48:16 -07:00
ridiculousfish
36fbfef74c Switch uses of dir_t to dir_iter_t
dir_t was a thin wrapper around readdir; switch to the new dir_iter_t API
and remove dir_t.
2022-10-02 18:48:16 -07:00
ridiculousfish
b684f7b076 Introduce dir_iter_t
This introduces dir_iter_t, a new class for iterating the contents of a
directory. dir_iter_t encapsulates the logic that tries to avoid using
stat() to determine the type of a file, when possible.
2022-10-02 18:48:16 -07:00
Fabian Boehm
942308bf72 highlight: Unicode above 0x10FFFF is an error
This should really just be using read_unquoted_escape, where this was
changed in #1107
2022-09-29 17:16:42 +02:00
Fabian Boehm
5ada59996f Reduce write() calls for explicitly separated buffers
This can improve performance for `string split ""` for up to 1.8x.
2022-09-27 16:33:47 +02:00
ridiculousfish
9a3a67ba31 Migrate PUA constants out of wutil.h
These defines are only used inside the .cpp file. Place them in there
and switch to an enum.
2022-09-26 10:21:45 -07:00
Fabian Boehm
e726627993 Upgrade widechar_width to Unicode 15 2022-09-26 17:17:17 +02:00
Mahmoud Al-Qudsi
5d64b56127 Remove needless usage of maybe_t
builtin_function() never returns `none()`; this must have been leftover from a
previous version of the code.
2022-09-25 14:40:49 -05:00
Mahmoud Al-Qudsi
ff00d3ca08 fixup! Fix stomping of last_option_requires_param
Fix accidental misuse of maybe_t boolean operator instead of maybe_t payload.
2022-09-25 13:33:33 -05:00
Mahmoud Al-Qudsi
1811a2d725 Prevent undefined behavior by intercepting return -1
While we hardcode the return values for the rest of our builtins, the `return`
builtin bubbles up whatever the user returned in their fish script, allowing
invalid return values such as negative numbers to make it into our C++ side of
things.

In creating a `proc_status_t` from the return code of a builtin, we invoke
W_EXITCODE() which is a macro that shifts left the return code by some amount,
and left-shifting a negative integer is undefined behavior.

Aside from causing us to land in UB territory, it also can cause some negative
return values to map to a "successful" exit code of 0, which was probably not
the fish script author's intention.

This patch also adds error logging to help catch any inadvertent additions of
cases where a builtin returns a negative value (should one forget that unix
return codes are always positive) and an assertion protecting against UB.
2022-09-25 12:33:40 -05:00
Fabian Boehm
ccca5b553f Disable VQUIT for shell modes
This allows binding ctrl+\ by default.

Fixes #9234
2022-09-25 13:27:01 +02:00
ridiculousfish
bc4e7c3fea 'C_' function to use g_empty_string
Use the global empty string instead of having its own.
2022-09-23 14:32:20 -07:00