235 Commits

Author SHA1 Message Date
Mitchell Hashimoto
7ce4010f7a terminal/new: scrolling viewport into active area pins to active 2024-03-22 20:27:30 -07:00
Mitchell Hashimoto
bfa574fa60 terminal/new: Screen new scrolldown should inherit bg color 2024-03-22 20:27:30 -07:00
Mitchell Hashimoto
eaa78477d5 terminal: fix tests for brackets on selectWord 2024-03-04 14:30:28 -08:00
Adam Stephens
59485713b4 screen/selectword: add more boundary characters 2024-02-29 22:30:30 -05:00
Mitchell Hashimoto
2d612ab168 terminal: preserve multi-point grapheme clusters on scrollback deletion
This codepath was not previously tested (an accident). Upon testing
this codepath its clear to see the logic was incorrect. When we have to
remove rows from our scrollback to fit new rows in the circular buffer,
we have to delete graphemes, but we were deleting them from the wrong
row offset.

For the row offset, we previously used the _active_ screen but the
proper offset is the _full_ screen. Tests verify.
2024-01-25 09:35:56 -08:00
Mitchell Hashimoto
48d6c93e09 terminal: select line considers semantic prompt change a boundary
Fixes #1329

Some shells and scripts use spaces and soft-wrapping as a way to move to
the next line instead of using newline (`\n`). Line selection
(triple-click by default) considers a soft-wrapped line as a single
line, so it was selecting the prompt.

This commit makes it so line selection considers semantic prompt state
(prompt vs command output) an additional boundary condition. This
requires shell integration but will make selection behave more
expectedly.
2024-01-19 15:48:53 -08:00
Mitchell Hashimoto
adb7958f61 remove tracy usage from all files 2024-01-13 15:06:08 -08:00
Jeffrey C. Ollie
f4292bccfc replace deprecated std.mem.tokenize with std.mem.tokenizeScalar 2024-01-03 10:22:33 -06:00
Gregory Anders
060bdff117 terminal: track palette color in cell state
Rather than immediately converting a color palette index into an RGB
value for a cell color, when a palette color is used track the palette
color directly in the cell state and convert to an RGB value in the
renderer.

This causes palette color changes to take effect immediately instead of
only for newly drawn cells.
2024-01-02 22:34:06 -06:00
Mitchell Hashimoto
b573ff137a terminal: resize cols should treat old cursor pos as active point
Fixes #1159

The cursor position is an "active" coordinate (defined at the top of
Screen.zig), but our resize was treating it as a "viewport" coordinate.
2023-12-26 13:59:22 -08:00
Mitchell Hashimoto
4a3e1e15e5 core: click to move cursor 2023-12-20 21:33:13 -08:00
Mitchell Hashimoto
6b1fd2b9eb terminal: Screen.promptPath 2023-12-20 20:50:10 -08:00
Mitchell Hashimoto
9a32ea515b terminal: Screen.selectPrompt to get the selection of the prompt 2023-12-20 20:35:05 -08:00
Mitchell Hashimoto
b327aab3d0 terminal: resize to less rows with empty lines should trim lines
Fixes #1030
2023-12-09 14:30:54 -08:00
Chris Marchesi
b84fb25e55 Add rectangle select
This adds rectangle select mode; when dragging with ctrl+alt (or
super+alt on MacOS), this allows you to select a rectangular region of
the terminal instead of the full start-end points of the buffer.
2023-11-30 12:35:52 -08:00
Mitchell Hashimoto
aa86031ff6 terminal: move line searching here, unit test 2023-11-29 15:30:22 -08:00
Mitchell Hashimoto
c7ccded359 terminal: Screen.getLine 2023-11-29 15:30:07 -08:00
Mitchell Hashimoto
3aba42c3f7 terminal: stringmaps 2023-11-29 15:30:07 -08:00
Mitchell Hashimoto
0487dbfb25 terminal: selectionString uses arraylist to build results 2023-11-29 15:30:07 -08:00
Mitchell Hashimoto
7fc95690bc terminal: basic lineIterator on screen 2023-11-29 15:30:07 -08:00
Mitchell Hashimoto
44e28e43d3 terminal: fix cursor pos when resizing more rows not at bottom
Fixes #906

This changes our resize behavior when increasing row height.

If the cursor was originally at the bottom of the viewport, existing
scrollback (if it exists) will be "pulled down" from the top,
effectively keeping the cursor at the bottom. This is the behavior
today, prior to this commit.

If the cursor is not at the bottom of the viewport, scrollback will NOT
be "pulled down" and instead blank lines will be added _below_. This is
new behavior.
2023-11-21 11:27:02 -08:00
Mitchell Hashimoto
db7262a8dd terminal: resize less cols attempts to preserve cursor y
Fixes #906

Previously, when the cursor isn't at the bottom and you resized to less
cols, the cursor would jump to the bottom of the viewport. But if you
resized to more columns it didn't do this. This was jarring. This commit
attempts to keep the cursor at the same place.
2023-11-20 14:00:14 -08:00
Mitchell Hashimoto
a325ab5712 terminal: remove invalid test 2023-11-19 21:13:22 -08:00
Mitchell Hashimoto
39c2549b1a terminal: add ESC [ 22 J (scroll and clear) 2023-11-19 20:45:57 -08:00
Mitchell Hashimoto
b220179c3a terminal: add "clear" screen scroll mode 2023-11-19 20:39:57 -08:00
Mitchell Hashimoto
542f605d54 terminal: add explicit errorset to scroll screen 2023-11-19 20:39:40 -08:00
Mitchell Hashimoto
54d4aed762 Merge pull request #899 from Raiden1411/select-all
core: implement select all binding
2023-11-17 21:37:57 -08:00
Mitchell Hashimoto
cb0cfab438 comments 2023-11-17 21:37:37 -08:00
Raiden1411
e3b83249d6 core: implement select all binding 2023-11-17 18:01:39 +00:00
Krzysztof Wolicki
44a48f62f1 change unmodified vars to consts in anticipation of zig changes 2023-11-17 15:46:46 +01:00
Mitchell Hashimoto
af6cc66369 core: Fix various double-click word selection bugs
Fixes #741

This completely reimplements double-click-and-drag logic for selecting
by word. The previous implementation was horribly broken. See #741 for
all the details.

The implemented logic now is:

* A double-click initiates a select-by-word selection mechanism.
  - A double-click may start on a word or whitespace
  - If the initial double-click is on a word, that word is immediately selected.
  - If the initial double-click is on whitespace, the whitespace is not selected.
* A "word" is determined by a non-boundary character meeting a boundary character.
  - A boundary character is `NUL` ` ` (space) `\t` `'` `"`
  - This list is somewhat arbitrary to make the terminal "feel" good.
  - Cell SGR states (fg/bg, bold, italic, etc.) have no effect on boundary determination or selection logic.
* As the user drags _on the same line_:
  - No selection change occurs until the cursor is over a new word. Whitespace change does nothing.
  - When selection is over a new word, that entire word added to the selection.
* When the user drags _up_ one or more lines:
  - If the cursor is over whitespace, all lines from the selection point up to but not including the cursor line are selected.
    * This selection is done in accordance to the previous rules.
  - If the cursor is over a word, the word becomes the beginning of the selection.
  - The end of the selection in all cases is the first word at or before the initial double-click point.
* When the user drags _down_ one or more lines:
  - The same logic as _up_ but swap the "beginning" and "end" of selection terminology.
* With this logic, the behavior of Ghostty has the following invariants:
  - Whitespace is never selected unless it is between two selected words
  - Selection implies at least one word is highlighted
  - The initial double-click point marks the beginning or end of a selection, never the middle.
2023-11-11 22:45:31 -08:00
Mitchell Hashimoto
4781a83e4a replace utf8proc with ziglyph 2023-11-07 13:17:56 -08:00
Chinmay Dalal
481af8039b disable zig fmt for aligned comments 2023-10-31 23:08:51 +05:30
Chinmay Dalal
bccf1216bc exit early when cursor is on a prompt line 2023-10-30 12:42:58 +05:30
Chinmay Dalal
0920ab08cd handle cursor on a prompt line 2023-10-30 11:52:35 +05:30
Chinmay Dalal
3ff20c7418 add tests 2023-10-30 10:19:21 +05:30
Chinmay Dalal
fae356be5a implement selecting output a ScreenPoint is in
This works by finding prompt markers provided by shell integration
Does not yet close #752 as this is not exposed
2023-10-30 01:30:43 +05:30
Mitchell Hashimoto
4ed6112e6d move circular buffer to src/ 2023-10-24 15:27:16 -07:00
Mitchell Hashimoto
06f7cfb398 terminal: save cursor and restore cursor xterm audit 2023-10-15 21:25:47 -07:00
Mitchell Hashimoto
3cc0cbcc9d terminal: SU, fix DL bug 2023-10-10 13:00:00 -07:00
Mitchell Hashimoto
76bbb7c361 terminal: insert lines (IL) handles left/right scroll regions 2023-10-08 20:51:00 -07:00
Mitchell Hashimoto
fa73fa0de2 terminal: ECH handles protection attributes properly 2023-10-07 22:36:29 -07:00
Mitchell Hashimoto
9e506ac7e1 terminal: cursor back handles reverse wrap (mode 45) 2023-10-06 08:35:02 -07:00
Mitchell Hashimoto
6fd082ed63 terminal: scroll region scroll up copied the wrong length of data
Fixes #315

This function has various cases that can be hit depending on the state
of the underlying circular buffer. It is a very well tested function but
this particular branch wasn't tested and unsurprisingly turns out there
is a bug in it.

Consider the following circular buffer state representing a terminal
screen with 1 column, 5 rows. Assume the circular buffer representing
this screen is such that `head == tail` and `head = 4` (zero-indexed,
full buffer size is 5). The head and tail are shown with an arrow below.

┌───────────────────────────────────────────────────────────────┐
│                               B                               │
├───────────────────────────────────────────────────────────────┤
│                               C                               │
├───────────────────────────────────────────────────────────────┤
│                               D                               │
├───────────────────────────────────────────────────────────────┤
│                               E                               │
├───────────────────────────────────────────────────────────────┤ ◀───  Head
│                               A                               │       Tail
└───────────────────────────────────────────────────────────────┘

The screen contents are "A B C D E" with each character on a new line.

Next, we set a scroll region from y=0 to y=3 (len=4). The scroll region
contents are "A B C D". Next, we issue a "delete lines" command with
n=2 (`CSI 2 M`) while the cursor is at the top-left corner. The delete
lines command deletes the given number of lines (n=2 in this case) and
shifts the remaining lines up. It does this only within the context
of the scroll region. Therefore, for `CSI 2 M` we would expect our
screen to become "C D _ _ E" (A, B are deleted, C, D shift up, and
E is untouched because its outside of the scroll region).

When executing this operation, we request the memory regions containing
the scroll region. This results in two pointers and lengths. For our
circular buffer state, we get the following:

┌───────────────────────────────────────────────────────────────┐ ◀──── ptr0
│                               A                               │
└───────────────────────────────────────────────────────────────┘

┌───────────────────────────────────────────────────────────────┐ ◀──── ptr1
│                               B                               │
├───────────────────────────────────────────────────────────────┤
│                               C                               │
├───────────────────────────────────────────────────────────────┤
│                               D                               │
└───────────────────────────────────────────────────────────────┘

We get two pointers because our circular buffer wraps around the bottom.
The diagram above shows them in top/bottom order not in memory order
(The value of `ptr0 > ptr1` but it doesn't matter for the bug).

The way the math works is as follows:

  1. We calculate the number of lines we need to shift up. That
     value is `height - n`. Our height is 4 (scroll region height) and
     our n is 2 (`CSI 2 M`), so we know we're shifting up 2 lines.
     Let's call this `shift_lines`.

  2. Our start copy offset is `n` because the lines we are retaining
     are exactly after the `n` we're deleting (i.e. we're deleting 2
     lines so the start of the lines we're shifting up is the 3rd line).
     Let's call this `start_offset`.

  3. We realize that our start offset is greater than the size of ptr0,
     so we must be copy from ptr1 into ptr0. Further, we know our start
     offset into ptr1 must be `start_offset - ptr0.len`.
     Let's call this `start_offset_ptr1 = 1`.

  4. Copy `ptr1[start_offset_ptr1]` to `ptr0`. We copy up to
     `shift_lines` amount. `shift_lines` is 2 but `ptr0.len` is only
     `1`. So, we actually copy `@min(shift_lines, ptr0.len)` and have
     `1` line remaining.
     Let's call that `remaining = 1`.

  5. Copy `remaining` from `ptr1[ptr0.len]` to `ptr1`.

  6. Next we need to zero our remaining lines. Our slices only contain
     our scroll region so we know we can zero the memory from
     `ptr1[remaining]` to the end of `ptr1`. We know this because step 5
     only copied `remaining` bytes.

The end result looks like this:

┌───────────────────────────────────────────────────────────────┐ ◀──── ptr[0]
│                               C                               │
└───────────────────────────────────────────────────────────────┘

┌───────────────────────────────────────────────────────────────┐ ◀──── ptr[1]
│                               D                               │
├───────────────────────────────────────────────────────────────┤
│                                                               │
├───────────────────────────────────────────────────────────────┤
│                                                               │
└───────────────────────────────────────────────────────────────┘

The bug was in step 6. We were incorrectly zeroing from `start_offset_ptr1`
instead of `remaining`. This was just a simple typo. The results are
devastating, but only under the exactly correct circumstances (those
in this commit message). In that scenario, the bug produced the
following:

┌───────────────────────────────────────────────────────────────┐ ◀────────── ptr[0]
│                               C                               │
└───────────────────────────────────────────────────────────────┘

┌───────────────────────────────────────────────────────────────┐ ◀────────── ptr[1]
│                               D                               │
├───────────────────────────────────────────────────────────────┤
│                               C                               │
├───────────────────────────────────────────────────────────────┤
│                                                               │
└───────────────────────────────────────────────────────────────┘

Notice the incorrect "C" that remains and is not zeroed.

This example showed a scenario with 1 column and leaving only 1 line out
of the scroll region. The real bug in #315 would often mistakingly leave
multiple lines in the scroll region. The effect was that scrolling
produced garbage lines because you'd "scroll" and part of what should've
scrolled would remain.

This garbage state was only in the terminal screen state, so it didn't
impact actual programs running or their data (i.e. vim). But, it made
the program unusable.
2023-09-28 21:10:37 -07:00
Tim Culverhouse
6b1d99dc6e terminal: rows created from IND should inherit the current bg attr
Any row created from scrolling via IND ("\x1BD") should have it's
background set as the current background. This can be verified in any
terminal with

  $ echo -e "\x1B[41m" && cat -v"

Followed by pressing enter to scroll the screen. We expect to see red
rows appear. Add test case to verify.

Fixes: alacritty/vim_large_screen_scroll
2023-09-26 22:10:05 -05:00
Tim Culverhouse
cfdce572b9 screen: only use bg attr for inserted rows
When scrolling up or deleting lines (effectively the same operation),
the inserted lines should only inherit the bg attribute of the cursor.
This behavior is similar to erase display and erase line. Update tests
to reflect this behavior.
2023-09-25 16:07:48 -05:00
Mitchell Hashimoto
2a390785f5 terminal: add protected mode flag to cursor pen 2023-09-25 10:56:57 -07:00
Tim Culverhouse
66875206bb terminal: move charset to screen
Each screen (primary and alternate) retains the state of the current
charset when DECSC (save cursor) is called. Move the CharsetState into
the screen to enable saving the state with each screen.

Add a test for charset state on screen change
2023-09-25 10:43:39 -05:00
Mitchell Hashimoto
d9cfd00e9f Big Cursor State Refactor
This makes a few major changes:

  - cursor style on terminal is single source of stylistic truth
  - cursor style is split between style and style request
  - cursor blinking is handled by the renderer thread
  - cursor style/visibility is no longer stored as persistent state on
    renderers
  - cursor style computation is extracted to be shared by all renderers
  - mode 12 "cursor_blinking" is now source of truth on whether blinking
    is enabled or not
  - CSI q and mode 12 are synced like xterm
2023-09-09 20:19:37 -07:00
Mitchell Hashimoto
cdf81b610d terminal: mark prompt continuation lines, end prompt clear at first
prompt
2023-09-03 14:00:56 -07:00