Commit Graph

197 Commits

Author SHA1 Message Date
kerty
3fdd2d3fc2 Small refactor of HighlightSpec 2025-01-23 17:09:29 +01:00
kerty
db546da3ca Made undo/redo not update autosuggestion if failed 2025-01-23 17:09:29 +01:00
kerty
6a9f1b925d Make flash highlight autosuggestion on failed deletion 2025-01-23 17:09:29 +01:00
kerty
bffbf0cd57 Make flash highlight relevant commandline section 2025-01-23 17:09:29 +01:00
kerty
b5c869d5e7 Make parse_util_token_extent return its output instead of mutating input. 2025-01-23 17:09:29 +01:00
kerty
4994000a27 Small refactor of Reader::flash 2025-01-23 17:09:29 +01:00
Johannes Altmanninger
8208a12a76 Back out "Support help argument in "{ -h""
This backs out commit efce176ceb.
2025-01-19 18:57:21 +01:00
Johannes Altmanninger
a7fdd8d002 Back out "Back out "Remove awkward assert""
This backs out commit e0c6384ed3.
2025-01-19 18:57:21 +01:00
Fabian Boehm
98a96f5b58 Revert "Swap alt-{left,right,backspace,delete} with ctrl-* on macOS"
This reverts commit ebdc3a0393.

Not discussed, includes a new thing that queries the terminal for the client OS
when what is really needed is just a `uname` - which would also work on Terminal.app.
2025-01-19 18:52:10 +01:00
Johannes Altmanninger
ebdc3a0393 Swap alt-{left,right,backspace,delete} with ctrl-* on macOS
See https://github.com/fish-shell/fish-shell/issues/ 10926
2025-01-19 18:29:07 +01:00
Johannes Altmanninger
e0c6384ed3 Back out "Remove awkward assert"
This backs out commit 6126237bc4.
2025-01-19 18:29:07 +01:00
Johannes Altmanninger
efce176ceb Support help argument in "{ -h"
Unlike other builtins, "{" is a separate token, not a keyword-string
token.

Allow the left brace token as command string; produce it when parsing
"{ -h"/"{ --help" (and nowhere else).  By using a decorated statement,
we reuse logic for redirections etc.

Other syntax elements like "and" are in the builtin list, which
- adds highlighting logic
- adds it to "builtin --names"
- makes it runnable as builtin
  (e.g. "builtin '{'" would hypothetically print the man page)

These don't seem very important (highlighting for '{' needs to match
'}' anyway).

Additionally, making it a real builtin would mean that we'd need to
deactivate a few places that unescape "{" to BRACE_BEGIN.

Let's not add it to the built in list. Instead, simply synthesize
builtin_generic in the right spot.

I'm assuming we want "{ -h" to print help, but '"{" -h' to run an
external command, since the latter is historical behavior.  This works
naturally with the above fake builtin approach which never tries to
unescape the left brace.
2025-01-19 18:29:07 +01:00
kerty
3436836b94 Add automatic history search page change when deleting last element on last page 2025-01-19 18:29:07 +01:00
kerty
4e965cba47 Separate SelectionMotion from HistoryPagerInvocation 2025-01-19 18:29:07 +01:00
kerty
9b14408b1b Make history search banner display start and end indexes 2025-01-19 18:29:07 +01:00
kerty
f28e43717b Fix history pager inconsistent ordering and skipping 13th elements 2025-01-19 18:29:07 +01:00
kerty
059e7424c1 Fix refreshing from deletion after forward search 2025-01-19 18:29:07 +01:00
Johannes Altmanninger
7ad47c34e8 Fix regression causing scrollback-push to not clear text below cursor
If a child program crashes with some text rendered below the cursor,
we fail to clear that text. For example run vim, "pkill -9 vim" and
observe that scrollback-push fails to clean up the leftover text.
Fix that.
2025-01-19 18:29:07 +01:00
Fabian Boehm
1123169bbd Remove some uses of unsafe
libc::getpid and getpgrp *cannot fail*, so an unsafe declaration here
is just noise.

I mean sure, if your libc is broken and these fail, but at that point
I'm comfortable declaring your computer a platypus that we do not need
to support.
2025-01-18 09:55:46 +01:00
Johannes Altmanninger
ba4ead6ead Stop saving autosuggestions that we can't restore
Sorry, commit 51adba6ee0 (Restore autosuggestion after corrected
typo, 2025-01-10) was pushed too early.  One issue is that it saves
autosuggestions also when we edit in the middle, where we can't
restore it.  We'd still restore it in some cases, even though it
doesn't apply. This breaks invariants that may cause various problems
when interacting with the autosuggestion.

Fix it by only saving the autosuggestion when we will be able to
restore it correctly.
2025-01-17 09:58:26 +01:00
Johannes Altmanninger
3d797b9eb8 Refactor autosuggestion saving lifecycle a bit 2025-01-17 09:58:26 +01:00
Fabian Boehm
6126237bc4 Remove awkward assert
We should really stop asserting for things that at worst don't show an
autosuggestion.

Fixes #11055
2025-01-16 13:03:11 +01:00
Johannes Altmanninger
40f5aac764 Fix forward-token hiccup at operators
For better or worse, backward-token completely skips over operators
like > & |.
forward-token is (accidentally?) inconsistent with that. Fix that.

Skipping over those tokens might be wrong weird.  Maybe not for
redirections since they are tighly coupled to their target.  Maybe we
can improve this in future.
2025-01-15 10:52:43 +01:00
Johannes Altmanninger
6f480d1d85 Also trim trailing newlines when adding to history
When pasting and executing a full line, the trailing newline character
will be included in history.

I usually manually delete the newline before executing, but sometimes
I forget. When I recall my (typically single-line) commands, it's
surprising that the cursor is on the blank second line.

The newline doesn't seem useful. Let's remove it automagically.
I wonder if anyone will be thrown off by this smart behavior.

In future, we can make this space trimming configurable, similar to
fish_should_add_to_history.
2025-01-15 10:52:43 +01:00
Johannes Altmanninger
081c3282b7 Refresh TTY timestamps also in some rare cases
As mentioned in
https://github.com/fish-shell/fish-shell/pull/11045#discussion_r1915994998,
we need to refresh TTY timestamps to avoid timing-based issues.

For some context see

	git log --grep='[Rr]efresh.* TTY'

Make things more consistent again. I don't know if all of these are
absolutely necessary, hoping to find out later (and consolidate this
logic in outputter).
2025-01-15 10:52:43 +01:00
kerty
f139d8ebed Improve mouse support 2025-01-15 00:52:15 +01:00
kerty
a0e687965e Fix unsaved screen modification 2025-01-15 00:52:15 +01:00
Fabian Boehm
28233b0711 Make new ctrl-c behavior "clear-commandline"
And leave the old behavior under the name "cancel-commandline".

This renames "cancel-commandline-traditional" back to
"cancel-commandline", so the old name triggers the old behavior.

Fixes #10935
2025-01-14 20:01:56 +01:00
Johannes Altmanninger
24e216ae82 Fix regression causing missing autosuggestions after (
Commit 4f3d6427ce (Fix regression causing crash in "commandline -j",
2025-01-12) wasn't quite right; it mishandles the edge case where
the current process has no token, fix that.
2025-01-13 22:22:42 +01:00
Johannes Altmanninger
b6c249be0c Back out "Escape : and = in file completions"
If you don't care about file paths containing '=' or ':', you can
stop reading now.

In tokens like

	env var=/some/path
	PATH=/bin:/usr/local/b

file completion starts after the last separator (#2178).

Commit db365b5ef8 (Do not treat \: or \= as file completion anchor,
2024-04-19) allowed to override this behavior by escaping separators,
matching Bash.

Commit e97a4fab71 (Escape : and = in file completions, 2024-04-19)
adds this escaping automatically (also matching Bash).

The automatic escaping can be jarring and confusing, because separators
have basically no special meaning in the tokenizer; the escaping is
purely a hint to the completion engine, and often unnecessary.

For "/path/to/some:file", we compute completions for "file" and for
"/path/to/some:file".  Usually the former already matches nothing,
meaning that escaping isn't necessary.

e97a4fab71 refers us to f7dac82ed6 (Escape separators (colon and
equals) to improve completion, 2019-08-23) for the original motivation:

	$ ls /sys/bus/acpi/devices/d<tab>
	$ ls /sys/bus/acpi/devices/device:
	device:00/ device:0a/ …

Before automatic escaping, this scenario would suggest all files from
$PWD in addition to the expected completions shown above.

Since this seems to be mainly about the case where the suffix after
the separator is empty, 

Let's remove the automatic escaping and add a heuristic to skip suffix
completions if:
1. the suffix is empty, to specifically address the above case.
2. the whole token completes to at least one appending completion.
   This makes sure that "git log -- :!:" still gets completions.
   (Not sure about the appending requirement)

This heuristic is probably too conservative; we can relax it later
should we hit this again.

Since this reverts most of e97a4fab71, we address the code clone
pointed out in 421ce13be6 (Fix replacing completions spuriously quoting
~, 2024-12-06). Note that e97a4fab71 quietly fixed completions for
variable overrides with brackets.

	a=bracket[

But it did so in a pretty intrusive way, forcing a lot of completions
to become replacing. Let's move this logic to a more appropriate place.

---

Additionally, we could sort every whole-token completion before every
suffix-completion.  That would probably improve the situation further,
but by itself it wouldn't address the immediate issue.

Closes #11027
2025-01-13 09:50:13 +01:00
Johannes Altmanninger
33d92d2a1f ctrl-u to suppress autosuggestion
ctrl-w and {ctrl,alt}-backspace do the same.
2025-01-13 09:47:34 +01:00
Johannes Altmanninger
4f3d6427ce Fix regression causing crash in "commandline -j"
Commit 3fcc6482cb (Fix parse_util_process_extent including too much
on the left, 2024-12-24) changed the process extent based on the
observation that "A\n\n\nB" comprises three tokens with ranges 0..1,
1..2 and 4..5. Prior to that commit, the second process extent was
2..5, which seems a bit weird because it includes newlines.

Weirdness aside, the real reason for changing it was this snippet in
the autosuggestion performer, where we compute the process extent
around cursor, and check if the line at process start matches the
cached search string.

        // Search history for a matching item unless this line is not a continuation line or quoted.
        if range_of_line_at_cursor(
            &command_line,
            parse_util_process_extent(&command_line, cursor_pos, None).start,
        ) == search_string_range

Given "A\n\n\nB" and cursor_pos=1 commit 3fcc6482cb changed the output
from 2..5 to 4..5. This brings problems:
1. leading spaces will not be included (which is probably
   inconsequential but still ugly).
2. the specified cursor position is not included in the given range.

We could paper over 2 by computing min(cursor_pos)
but that would leave 1.

For now let's revert and solve the autosuggestion issue in a less
brittle way.
2025-01-12 19:55:17 +01:00
Johannes Altmanninger
51adba6ee0 Restore autosuggestion after corrected typo
Backspace signals that the user is not happy with the commandline,
and by extension the autosuggestion.

For this reason, backspace suppresses autosuggestions until the next
text insertion.

However if I
1. type something that has an autosuggestion
2. type *one* wrong letter (removing the autosuggestion)
3. type backspace

backspace does not visibly suppress any autosuggestion but rhater
signal that the user wants to go back to the previous state of the
commandline, which does have an autosuggestion.

Enable this scenario by caching the autosuggestion when it's
invalidated. On certain edits that make the cached autosuggestion
valid again, restore it from the cache.  Currently, only do this up
to a single backspace.  Could extend that in future.

This implementation is really bad.. but it's a start.
Weirdly, it does not restore the cache on undo; but that's
inconsequential because undo doesn't suppress autosuggestion as
of today.

Closes #3549
2025-01-11 18:58:49 +01:00
Johannes Altmanninger
7c539b9539 Rename the readline function for deleting active history item
history-pager-delete now also works for regular history search,
so rename it.
2025-01-11 18:58:49 +01:00
Johannes Altmanninger
0f1408e0ea Also autosuggest lines from multi-line command lines in history
My history often has erroneous single-line commands followed by
corrected versions. Sometimes the corrected versions only exist within
a multi-line commandline.  This means that autosuggestion skips over
the corrected versions and return a false positive.

Fix that by splitting the commandline into lines and suggesting those,
in reverse chronological order.

One other wart: shift-delete won't delete such autosuggestions from
history; instead it will flash the screen.

Line boundaries are not the best heuristic but they are an
improvement for the most part and fits with the current approach
where autosuggestion always operates on the entire line.

In future we should operate on processes and jobs.  But it may be
tricky - a backgrounding `&` should probably be included (in both?)
but `&&` or `;` probably not.

See also the discussion in
1c4e5cadf2 (diff-267c9f4da66412a9f439ac08d224356fe24265b5e1cebb6c44c2d55b96414513R59)
2025-01-11 13:50:08 +01:00
Johannes Altmanninger
411745ebce shift-delete to only delete from history if cursor at autosuggestion
If there is no history search or autosuggestion, shift-delete acts
as backspace, matching native macOS behavior.

I'm not sure if we want to keep that amount of overloaded behavior,
but let's assume so for now.

If that assumption holds, it may be confusing that shift-delete
deletes the autosuggestion if the cursor is here

	echo some command with autosuggstion
		^

So let's only do that if the cursor is actually at the autosuggestion,
I guess.
2025-01-11 13:50:08 +01:00
Johannes Altmanninger
f448ddd579 shift-delete to stop trying to delete completion-based autosuggestions from history
shift-delete attempts to delete the autosuggestion from history even
if the autosuggestion is not from history.

This is weird. We probably shouldn't do this. Let's flash the
commandline instead to try to reduce confusion.
2025-01-11 13:50:08 +01:00
Johannes Altmanninger
0e512f8033 Fix spurious blank lines when executing scrolled commandline
The result of

	commandline -i ": '$(seq $LINES)"\n"first scrolled line'"

is a commandline that is scrolled by one line.

Before executing that commandline, we move the cursor down by one
too many line. This is a regression from 610338cc70 (On undo after
execute, restore the cursor position, 2024-12-21). Fix that.

The test also demonstrates an unrelated problem, probably specific
to tmux.
2025-01-09 14:43:21 +01:00
Johannes Altmanninger
cc9083e220 Add some logging for XTGETTCAP 2025-01-08 12:06:28 +01:00
Johannes Altmanninger
14df28382d Work around terminals that echo DCS queries
Some terminals such as conhost and putty cannot parse DCS commands,
and will echo them back.

Work around this by making sure that this echoed text will not
be visible.

Do so by temporarily enabling the alternative screen buffer when
sending DCS queries (in this case only XTGETTCAP).  The alternative
screen buffer feature seems widely supported, and easier to get right
than trying to clear individual lines etc.

The alternative screen may still be visible for a
short time.  Luckily we can use [Synchronized Output](
https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036)
to make sure the screen change is never visible to the user.

Querying support for that is deemed safe since it only requires a
CSI command.

Note that it seems that every terminal that supports Synchronized
Output also parses DCS commands successfully.  This means that we
could get away without the alternative screen buffer in practice.
Not sure yet.

The implementation is slightly more complex than necessary in that it
defines a redundant ImplicitEvent. This is for two reasons: 1. I have
a pending change that wants to use it, so this removes diff noise and
2. we historically have sc/input_common.rs not depend on src/output.rs.
I dont' think any are strong reasons though.
2025-01-08 12:06:28 +01:00
Johannes Altmanninger
e6d57f2fb2 Minor style fix 2025-01-08 12:06:28 +01:00
Johannes Altmanninger
e697add5b5 Feature flag to prevent executing off buffered keys
If I run "sleep 3", type a command and hit enter, then there is no
obvious way to cancel or edit the imminent command other than ctrl-c
but that also cancels sleep, and doesn't allow editing. (ctrl-z sort
of works, but also doesn't allow editing).

Let's try to limit ourselves to inserting the buffered command
(translating enter to a newline), and only execute once the user
actually presses enter after the previous command is done.
Hide it behind a new feature flag for now.

By making things less scary, this might be more user-friendly, at
the risk of breaking expectations in some cases.

This also fixes a class of security issues where a command like
`cat malicious-file.txt` might output escape sequences, causing
the terminal to echo back a malicious command; such files can still
insert into the command line but at least not execute it directly.
(Since it's only fixed partially I'm not really sure if the security
issue is a good enough motivation for this particular change.)

Note that bracketed paste probably has similar motivation as this feature.

Part of #10987
Closes #10991
2025-01-06 06:24:13 +01:00
Johannes Altmanninger
af137e5e96 scrollback-push to query for indn/cuu via XTGETTCAP
Some terminals like the Linux console don't support indn (scroll
forward). Let's query for the presence of these features, and fall
back to the traditional behavior if absent.

For now, break with the tradition of using the terminfo database that
we read ourselves. Instead ask the terminal directly via XTGETTCAP.
This is a fairly young feature implemented by terminals like xterm,
foot and kitty, however xterm doesn't expose these capabilities at
this point.

This is a good opportunity to try XTGETTCAP, since these are
capabilities we haven't used before. Advantages of XTGETTCAP are that
it works across SSH and is independent of $TERM (of course ignoring
$TERM may also be breaking to some users). Let's see if it sees
adoption in practice.

Tested to work on foot and kitty, allowing the default ctrl-l binding
to work without erasing any screen content.

See #11003
2025-01-06 06:24:13 +01:00
Johannes Altmanninger
75832b3c5d scrollback-push to fall back to clear-screen if missing CPR feature
The new ctrl-l implementation relies on Cursor Position Reporting (CPR)
This may not work on exotic terminals that don't support CSI 6n yet

As a workaround, probe for this feature by sending a CSI 6n (CPR)
on startup.  Until the terminal responds, have scrollback-push fall
back to clear-screen.

The theoretical problem here is that we might handle scrollback-push
before we have handled the response to our feature probe. That seems
fairly unlikely; also e49dde87cc has the same characteristics.

This could query a capability instead (via XTGETTCAP or otherwise)
but I haven't found one; and this seems at least as reliable.

While at it, change the naming a bit.

See #11003
2025-01-06 05:53:24 +01:00
Johannes Altmanninger
10f1f21a4f Don't send kitty kbd protocol probe until ECHO is disabled
With tmux 3.0 (from 2019) inside SSH, the CSI 5n response is echoed.
I guess with all other terminals we were just lucky.  Move it to
right after where we disable ECHO I guess.

In general, asynchronous requests create a lot of potential for error,
we should try to get away from them.
2025-01-06 05:51:38 +01:00
Johannes Altmanninger
e11e62674f Fix bad layout computation with right prompt
Commit 1c4e5cadf2 (Autosuggestions in multi-line
command lines, 2024-12-15) accidentally passed an empty
"commandline_before_suggestion" to compute_layout() when there is
no autosuggestion.

Closes #10996
2025-01-04 00:54:06 +01:00
Johannes Altmanninger
d823444c6e Apply autosuggestions from completions also if cursor is not at EOL
Before 1c4e5cadf2 (Autosuggestions in multi-line command lines,
2024-12-15), the completion code path in the autosuggestion performer
used to do something weird: it used to request completions for the
entire command line (with the implied cursor at end) but try to apply
the same completion at the actual cursor.

That commit changed this to request completions only up to the cursor
position, which could in theory make us produce valid completions even
if the cursor is not at end of the line.  However, that doesn't really
work since autosuggestions can only be rendered at the end of the line.
And the worst of it, that commit tries to compute

	line_at_cursor(&full_line, search_string_range.end)

which crashes as out-of-bounds if the completion needs to replace the token
(like a case-correcting completion does).

Let's apply completions to the end, matching how autosuggestions work
in general.
2025-01-03 12:56:04 +01:00
Peter Ammon
7e9b35be48 Fix a clippy 2025-01-01 17:42:25 -08:00
Johannes Altmanninger
1c4e5cadf2 Autosuggestions in multi-line command lines
If I run

	$ command A
	$ command B
	$ command C

and find myself wanting to re-run the same sequence of commands
multiple times, I like to join them into a single command:

	$ command A &&
	    command B &&
	    command C

When composing this mega-commandline, history search can recall the
first one; the others I usually inserted with a combination of ctrl-k,
ctrl-x or the ctrl-r (since 232483d89a (History pager to only operate
on the line at cursor, 2024-03-22), which is motivated by exactly
this use case).

It's irritating that autosuggestions are missing, so try adding them.

Today, only single-line commands from history are suggested. In
future, we should perhaps also suggest any line from a multi-line
command from history.
2025-01-01 17:22:50 +01:00
Johannes Altmanninger
532abaddae Invalidate stale autosuggestions eagerly
If I type something that invalidates the autosuggestion, the
autosuggestion is still kept around in memory. This is used if
1. there is no valid autosuggestion for the new commandline
2. the user types something like "backspace backspace a"
   that both makes the cached autosuggestion valid again, and does
   not trigger autosuggestion suppression (hence backspace alone is
   not anough)

The fact that an autosuggestion might not match the current command
line makes it more difficult to implement autosuggestions on multiline
command lines.

For now let's invalidate autosuggestions eagerly, to enable the
next commit.  This heuristic invalidates too much but I don't think
that matters. We'll simply recompute the autosuggestion in those few
cases which.
2025-01-01 17:22:50 +01:00