Commit Graph

280 Commits

Author SHA1 Message Date
Johannes Altmanninger
3951a858dd reader: do not send queries if stdout is not a terminal
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).
2025-05-29 17:57:38 +02:00
Johannes Altmanninger
c7a19a00ab reader: minor simplification 2025-05-29 17:57:38 +02:00
Johannes Altmanninger
2071df126c Idiomatic type for reader_readline nchars argument 2025-05-29 17:57:38 +02:00
Johannes Altmanninger
b3dbdb90c2 On enter, insert any failed search into the command line
This might help with use cases such as https://github.com/fish-shell/fish-shell/pull/11450.
Not sure.
2025-05-29 16:39:52 +02:00
Johannes Altmanninger
dc129add9e Assert that autosuggestions are always valid
This documents an invariant established by 532abaddae (Invalidate stale
autosuggestions eagerly, 2024-12-25). It was initially broken but fixed in
ba4ead6ead (Stop saving autosuggestions that we can't restore, 2025-01-17).
2025-05-29 16:39:52 +02:00
王宇逸
7c2c7f5874 Use uninit instead of zeroed 2025-05-19 20:54:12 +08:00
Yuyi Wang
c2eaef7273 Update nix to 0.30.1 (#11458)
After nix updated to 0.30, all functions related to file descriptor accepts impl AsFd, e.g., BorrowedFd. This PR is a minimal update. It tries to use impl AsFd as long as possible, but uses BorrowedFd in some places. Yes it introduces unsafe, but doesn't introduce new unsafe code.
2025-05-06 10:52:54 +02:00
Peter Ammon
ccfe949514 ast: make Ast generic
We can parse two different things via Ast:

1. A regular job list
2. A freestanding argument list, as used in `complete --arguments ...`

This second case is specific to one use.

Prior to this commit, we parsed the Ast and then "forgot" what we parsed,
storing a &dyn Node. Then we had to cast it to the right type, and assert,
and etc.

Make Ast generic over the Node type it parsed, and default the Node type to
JobList. This simplifies call sites.
2025-05-04 18:59:13 -07:00
Peter Ammon
dfac66082a ast: adopt Kind in yet more places 2025-05-04 18:59:05 -07:00
Peter Ammon
ee9cf33689 ast: Remove Node::category
This is now unused.
2025-05-04 18:59:05 -07:00
Johannes Altmanninger
094e8b29c2 Cleanup some import statements 2025-04-29 13:51:18 +02:00
Johannes Altmanninger
f8699d2b7e Move mouse click handling from input decoding to the input queue consumer
The input queue doesn't want to be blocked, so let's decide later what to
do with a mouse click.  This fixes the potential problem where a mouse click
is ignored if it is received while we're waiting for the terminal to repond
to a query.
2025-04-29 13:51:18 +02:00
Johannes Altmanninger
168c1a50a4 Don't route query responses until we pop them from the input queue
This makes more sense, see also the next commit.
2025-04-29 13:51:18 +02:00
Johannes Altmanninger
5897d13333 Dedicated input event type for query responses
These code paths have a tiny bit of logic in common, share that.

Maybe this should be nested in ImplicitEvent, and maybe Eof and CheckExit
shouldn't be..
2025-04-29 13:51:18 +02:00
Johannes Altmanninger
d18cb6ce27 Use OnceCell for terminal query state initialization
This object is initialized once just before we start reading from the terminal.
Once seems to be the appropriate type for this.  This gets rid of an awkward
enum variant.
2025-04-29 13:51:18 +02:00
Johannes Altmanninger
9b44a59b80 Rename terminal-query-state data structure
While at it, extract a function for initialization.  This looks pretty ugly
but it will get better with the next commit.
2025-04-29 13:51:18 +02:00
Johannes Altmanninger
788eddd0e8 Make terminal query data state a RefCell instead of mutex
We never need to access this from other threads, so a Mutex is overkill.
Leave behind stale variable names like "wait_guard" to be cleaned up by the
next commit.

Since TestInputEventQueuer is used concurrently in tests,
give it its own private object, to avoid borrowing conflicts.

Same for fish_key_reader; this fixes the issue that fish_key_reader potentially
reads keyboard input before a query is finished.
2025-04-29 13:50:15 +02:00
Johannes Altmanninger
e7c9f6d47e Move terminal query state data structure into the parser
Whenever config.fish runs (interactive) builtin read, we push and pop a
top-level, before the main shell's reader.

The terminal state outlives all readers, so its scope should reflect that
to avoid redundant initialization. Move it into the parser.

This is also used by a following commit that wants to access the query state
from a builtin. This should work even if no reader is active.

Note that Mutex doesn't really make sense here - the next commit will fix that.
2025-04-29 13:31:13 +02:00
Johannes Altmanninger
364d84e620 Remove unused query for cursor position reporting
We only query for the cursor position if either
1. if the terminal sends an XTGETTCAP response indicating it supports scroll
   forward (terminfo code indn)
2. if the terminal sends a mouse click event

In practice, the terminals that do either are also capable of reporting the
cursor position, so let's require that for now.

We could definitely make this optional, and degrade gracefully -- that's
what I originally intended.

But maybe we don't need it? Keeps things simpler. In future, we can add a
timeout, and print an error, to help debugging terminals.
2025-04-29 13:31:13 +02:00
Johannes Altmanninger
829709c9c4 Replace synchronized update workaround
Old versions of ConHost and Putty can't parse DCS sequences.
For this reason, we briefly switch to the alternate screen buffer while sending
DCS-format (e.g. XTGETTCAP) queries. For extra paranoia, we wrapped this
procedure in a synchronized update. This doesn't seem to be needed; neither
ConHost nor Putty show glitches when the synchronized update is omitted.

As of today, every terminal that implements XTGETTCAP also implements
synchronized updates but that might change.

Let's remove it, to reduce surprise for users and terminal developers.

As a bonus, this also fixes a glitch on Terminal.app which fails to parse
the synchronized-update query (`printf '\x1b[?2026$p'`) and echoes the "p"
(bug report ID FB17141059). Else we could work around this with another
alternate screen buffer.

Unfortunately, this change surfaces two issues with GNU screen.  For one,
they don't allow apps to use the alternate screen features (the user may
allow it with "altscreen on"). Second, screen unconditionally echoes
the payload of DCS commands.  A possible fix has been suggested at
https://lists.gnu.org/archive/html/screen-devel/2025-04/msg00010.html

I think this combination of behaviors is unique among terminals.  I'm sure
there are more terminals that don't parse DCS commands yet, but I think almost
all terminals implement alternate screen buffer. Probably only terminal
multiplexers are prone to this issue. AFAICT very few multiplexers exists,
so we can work around those until they are fixed.

Disable XTGETTCAP queries for GNU screen specifically.  Unfortunately screen
does not implement XTVERSION, so I don't know how to reliably identify
it. Instead, check STY and some commonly-used values TERM values.
This has false negatives in some edge cases.
But the worst thing that happens is that "+q696e646e" will be echoed once
at startup, which is easy to ignore, or work around with something like

	function workaround --on-event fish_prompt
		commandline -f repaint
		functions --erase workaround
	end

which I don't think we should apply by default, because it can mask other
issues.

We should give screen more time to respond. I guess I'll open an issue so
we don't forget. In doubt, we can always go back to the previous approach
(but implement it in fish script).

Alternative workaround: instead of the alternative screen buffer, we could
try something like clr_eol/clr_bol to erase the spuriously echoed text. I
tried to do this in various ways but (surprisingly) failed.
2025-04-29 13:31:13 +02:00
Johannes Altmanninger
939902eb29 Remove mysterious workaround for buggy sgr0 handling
This workaround was added in commit d66700a0e4 (Color work, 2012-02-11).
I don't understand why it would be necessary, it seems redundant.  Bravely
remove it. Would be interesting to know which terminal caused the motivating
problem.  Terminal.app and others seem to be unaffected by this change.
2025-04-21 18:11:44 +02:00
Johannes Altmanninger
1a63956860 Move separate bg/fg parsing up the call stack
Our highlighting module allows different highlight roles for foreground
and background.

Other users of our color-parsing logic have no need for this.

Historically we have passed an "is_background" bool and only parsed what we're
interested in.  This sort of makes sense because it's exactly what we need,
but it meant that the special behavior spread quite far.

There is no real need for spreading it; a function with the behavior "parse
a text face but honor is_background" is strictly more complex than "parse a
text face". Additionally, any performance optimization is only relevant if
the user specifies faces that won't be used, which is a very unusual case.

Let's isolate this logic in the highlighting module.
2025-04-21 18:11:43 +02:00
Johannes Altmanninger
d33cc5ea24 Replace tuple return value with struct
The parent commit got rid of the is_background parameter that determined
the meaning of the return value (fg/bg); since we always return both now,
give them names.
2025-04-21 18:11:43 +02:00
Johannes Altmanninger
9c39cab239 Make text style bitflags a plain struct
A following commit wants to add other underline styles.  At most one underline
style can be active at one time.  This can't be modelled well by a flat
bitset, so let's use a composable type here.
2025-04-21 18:11:43 +02:00
Johannes Altmanninger
64c362bb73 Move text face/color parsing functions into new module
No other change.
2025-04-21 17:37:36 +02:00
Johannes Altmanninger
2ce3068465 New type for colors + text styling attributes
Our "Color" type also includes text styling (bold, italics, ...).  This doesn't
seem like the perfect way to model this, because the background text styles
are always unused (this is noticeable with some fish_color_* variables).

Introduce a type that represents attributes to apply to text, and nothing
else. Prefer to pass this instead of two Color values with redundant text
style is redundant.
2025-04-21 17:37:36 +02:00
Johannes Altmanninger
5b9ba559c7 Rename RgbColor to Color
RgbColor can also be a named color, so this name is surprising to readers
who don't have the implicit assumption that named colors are the default
and that RGB support is something novel.
2025-04-21 17:37:36 +02:00
Peter Ammon
119716fbf2 extract_tokens::is_command to stop using ast parent pointers
Simple change to remove a user of parent back-references.
2025-04-20 17:53:43 -07:00
Peter Ammon
7d98cc8850 ast: stop using Node::ptr_eq
This function hid a bug! It converted two Nodes to `*const ()` which discards
the vtable pointer, using only the data pointer; but two nodes can and do have
the same data pointer (e.g. if one node is the first item in another).

Add the (statically dispatched) is_same_node function with a warning comment,
and adopt that instead.
2025-04-20 17:53:43 -07:00
Johannes Altmanninger
267b16235d Fix transient prompt mode for single-line prompts
Extend a hack multi-line prompts to the new transient prompt code path.
This fixes transient prompt with single-line prompts; added a test case.

While at it, add a test that covers the need for this hack.

Patch-by: kerty <g.kabakov@inbox.ru>

See https://github.com/fish-shell/fish-shell/pull/11153#issuecomment-2801014723
2025-04-16 11:22:14 +02:00
Johannes Altmanninger
4b2c707721 Simplify exec_prompt_cmd 2025-04-12 12:07:54 +02:00
kerty
231ab22ce4 Update docs for transient prompt
See #11153
2025-04-12 12:07:26 +02:00
kerty
7ed4dfbd2d Ease condition for the execution of the right prompt
Now, the right prompt will not be executed only if it is undefined `fish_right_prompt`.
This allows the use of `read -p 'echo left' -R 'echo right'`.

Also changes condition for use of `DEFAULT_PROMPT` for consistency.
2025-04-12 10:46:33 +02:00
kerty
cb31f3e092 Refactor Reader::exec_prompt
Also fixes repaint-mode being run interactively
2025-04-12 10:46:33 +02:00
Johannes Altmanninger
b81a55e5f0 Fix bad conflict resolution 2025-04-12 10:34:38 +02:00
Fabian Boehm
66d7c00ba3 Let parser eval string directly
This gets the reader out of asting the source and is needed for
autoloader to get it to read a source string directly

Also add an "eval_file_wstr" method as a convenience to run a wstr as if it is a *file*, with a block and stuff
2025-04-11 17:29:22 +02:00
Johannes Altmanninger
17b4b39c8b Stop reading terminfo database
Our use of the terminfo database in /usr/share/terminfo/$TERM is both
1. a way for users to configure app behavior in their terminal (by
   setting TERM, copying around and modifying terminfo files)
2. a way for terminal emulator developers to advertise support for
   backwards-incompatible features that are not otherwise easily observable.

To 1: this is not ideal (it's very easy to break things). There's not many
things that realistically need configuration; let's use shell variables
instead.

To 2: in practice, feature-probing via terminfo is often wrong.  There's not
many backwards-incompatible features that need this; for the ones that do
we can still use terminfo capabilities but query the terminal via XTGETTCAP
directly, skipping the file (which may not exist on the same system as
the terminal).

---

Get rid of terminfo. If anyone finds a $TERM where we need different behavior,
we can hardcode that into fish.

* Allow to override this with `fish_features=no-ignore-terminfo fish`
  Not sure if we should document this, since it's supposed to be removed soon,
  and if someone needs this (which we don't expect), we'd like to know.
  * This is supported on a best-effort basis; it doesn't match the previous
    behavior exactly.  For simplicity of implementation, it will not change
    the fact that we now:
    * use parm_left_cursor (CSI Ps D) instead of  cursor_left (CSI D) if
      terminfo claims the former is supported
    * no longer support eat_newline_glitch, which seems no longer present
      on today's ConEmu and ConHost
* Tested as described in https://github.com/fish-shell/fish-shell/pull/11345#discussion_r2030121580
* add `man fish-terminal-compatibility` to state our assumptions.
  This could help terminal emulator developers.
* assume `parm_up_cursor` is supported if the terminal supports XTGETTCAP
* Extract all control sequences to src/terminal_command.rs.
* Remove the "\x1b(B" prefix from EXIT_ATTRIBUTE_MODE. I doubt it's really
  needed.
* assume it's generally okay to output 256 colors
  Things have improved since commit 3669805627 (Improve compatibility with
  0-16 color terminals., 2016-07-21).
  Apparently almost every actively developed terminal supports it, including
  Terminal.app and GNU screen.
  * That is, we default `fish_term256` to true and keep it only as a way to
    opt out of the the full 256 palette (e.g. switching to the 16-color
    palette).
    * `TERM=xterm-16color` has the same opt-out effect.
* `TERM` is generally ignored but add back basic compatiblity by turning
  off color for "ansi-m", "linux-m" and "xterm-mono"; these are probably
  not set accidentally.
* Since `TERM` is (mostly) ignored, we don't need the magic "xterm" in
  tests. Unset it instead.
* Note that our pexpect tests used a dumb terminal because:
  1. it makes fish do a full redraw of the commandline everytime, making it
     easier to write assertions.
  2. it disables all control sequences for colors, etc, which we usually
     don't want to test explicitly.
  I don't think TERM=dumb has any other use, so it would be better
  to print escape sequences unconditionally, and strip them in
  the test driver (leaving this for later, since it's a bit more involved).

Closes #11344
Closes #11345
2025-04-11 15:11:22 +02:00
Johannes Altmanninger
0ca08ce81d Buffer OSC 0 terminal title writing 2025-04-11 15:11:22 +02:00
Johannes Altmanninger
ce01b16402 Fix typo 2025-04-11 15:11:22 +02:00
Johannes Altmanninger
39aa478108 Extract unwrapping for buffer-writes that are assumed to not fail 2025-04-11 15:11:22 +02:00
Johannes Altmanninger
9206a91701 Improve BufferedOuputter ergonomics
Factor some redundant logic from call sites into the constructor, even if
it's exactly what the constructor actually needs.
2025-04-11 15:11:22 +02:00
Johannes Altmanninger
af3b49bf9c Fix kill-selection crash when selection start is out-of-bounds
This part of the code could use some love; when we happen to clear the
selected text, we should end the selection.

But that's not how it works today. This is fine for Vi mode, because Vi
mode never deletes in visual mode.

Let's fix the crash for now.

Fixes #11367
2025-04-11 15:11:22 +02:00
Johannes Altmanninger
c94e30293a Fix crash when history pager is closed before search
With

	bind ctrl-r 'sleep 1' history-pager

typing ctrl-r,escape crashes fish in the history pager completion callback,
because the history pager has already been closed.

Prior to 55fd43d86c (Port reader, 2023-12-22), the completion callback
would not crash open a pager -- which causes weird races with the
user input.

Apparently this crash as been triggered by running "playwright",
and -- while that's running typing ctrl-r ligh escape.
Those key strokes were received while the kitty keyboard protocol
was active, possibly a race.

Fixes #11355
2025-04-04 14:34:11 +02:00
Johannes Altmanninger
f88470aa3c Address some unused_must_use warnings for ControlFlow
As seen on nightly Rust.
2025-04-01 17:15:48 +02:00
Johannes Altmanninger
11c7310f17 Prevent commandline modification inside abbreviation callbacks
Consider command line modifications triggered from fish script via abbreviation
expansion:

	function my-abbr-func
	    commandline -r ""
	    echo expanded
	end
	abbr -a foo --function my-abbr-func

Prior to commit 8386088b3d (Update commandline state changes eagerly as well,
2024-04-11), we'd silently ignore the command line modification.
This is because the abbreviation machinery runs something similar to

	if my-abbr-func
	    commandline -rt expanded
	end

except without running "apply_commandline_state_changes()" after
"my-abbr-func", so the «commandline -r ""» update is lost.

Commit 8386088b3d applies the commandline change immediately in the abbrevation
function callback, invalidating abbrevation-expansion state.

The abbreviation design does not tell us what should happen here.  Let's ignore
commandline modifications for now. This mostly matches historical behavior.

Unlike historical behavior we also ignore modifications if the callback fails:

	function my-abbr-func
	    commandline -r ""
	    false
	end

Remove the resulting dead code in editable_line.

See #11324
2025-03-28 12:58:15 +01:00
James Falcon
0dbfb4ccb1 Remove directory name prefix in truncated completions
Sometimes, the dirname of a completion is much longer than the basename.

When the dirname is the same for many completions, a long common dirname
prefix makes it hard to see the interesting differences in the basenames.

Fix this by collapsing the dirname prefix to "…/".

In future, we should find a generic way to collapse completions that don't
contain slashes.

Closes #8618
Closes #11250
2025-03-21 00:53:06 +01:00
Peter Ammon
29ae571afa Make scoped_push nicer
In C++ it's easy to make an RAII-type object like "increment a counter for
the duration of this function." Such an object might accept a pointer or
reference, increment the value, and then restore it in its destructor. We
do this all the time - for example to mark a region of code as
non-interactive, etc.

Rust makes this more awkward, because now the reference is tracked by the
borrow checker: it "owns" the object for the duration of the function. This
leads to approaches like "zelf" where the object that marks the parser as
non-interactive itself becomes the new parser, but we can't call it "self"
and it's just yucky.

In this commit we introduce a notion of the "scoped data" of the Parser,
factored out of the library data. This is data which is typically set in a
scoped fashion: whether we are a subshell, are interactive, emit fish_trace
debugging info, etc. Crucially we set this as Rc: this allow the scope
itself to share data with the Parser and we can get rid of lots of "zelf"s.

Introduce a new function `Parser::push_scope` which creates a new scope and
allows modifying these variables associated with the scope. This ends up as
a nice simplification.
2025-03-15 16:43:16 -07:00
carsonzhu
4ce552bf94 Token search commands that only match the last token in each line
This add two commands history-last-token-search-backward and
history-last-token-search-forward which behaves like bash's yank-last-arg. So
similar to history-token-search-* but only considers the last argument for
each command.

Closes #10756
Closes #11258
2025-03-15 21:54:47 +01:00
Sander Machado
f4a8368c9e builtins: idiomatic error code passing
Remaining code smells:
- exec_subshell_internal needs to convert a number to a result

Closes #10948
2025-03-15 21:30:49 +01:00
Johannes Altmanninger
9f79fe17fc Quote only unique completions, use backslashes for ambiguous ones
Commit 29dc307111 (Insert some completions with quotes instead of backslashes,
2024-04-13) breaks some workflows. Given

	touch '[test] file1'
	touch '[test] file2'
	ls tes<Tab>

we insert completions quoted, which is inconvenient when using globs.

This implicit quoting feature is somewhat minor. But quotes look nicer,
so let's try to keep them.  Either way, users can ask for it by starting a
token with «"».

Use quoting only when we insert unique completions.

Closes #11271
2025-03-14 22:21:42 +01:00