-
Notifications
You must be signed in to change notification settings - Fork 159
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
302 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
--- | ||
title: Cursor | ||
description: |- | ||
The cursor is the row and column where the next | ||
character will be printed or location-sensitive control | ||
sequence will be executed. | ||
--- | ||
|
||
The cursor is always present in a terminal and is located at | ||
some row and column within the active screen area. The cursor | ||
may be visually hidden but the terminal internal state always | ||
has a cursor and it is always located at some active position. | ||
|
||
The cursor most commonly is associated with where the next | ||
printed character will be placed. However, the cursor is also | ||
used for location-sensitive control sequences. For example, | ||
when an [erase line control sequence](/docs/vt/csi/el) is | ||
executed, the cursor determines the first line to erase. | ||
|
||
The terminal has a single cursor [per screen](/docs/concepts/screen). | ||
**Note that this document is about the cursor as it relates | ||
to the [terminal API](/docs/vt).** Applications such as editors may | ||
have their own concept known as a "cursor" that is completely | ||
unrelated to the terminal cursor. For example, an editor may support | ||
"multiple cursors", but the underlying terminal API is both a separate | ||
concept and only supports a single cursor at any given moment. | ||
|
||
## Initial State | ||
|
||
The cursor is always initially located at the top-left corner of the screen. | ||
|
||
## Pending Wrap State | ||
|
||
The pending wrap state is a boolean value that is set when a character | ||
is printed in the rightmost column of the screen to indicate that the | ||
next printed character should wrap to the next line. | ||
|
||
If the pending wrap state is set, the next printed character will | ||
move the cursor to the leftmost column of the next line, unset | ||
the pending wrap state, and then print the character[^1]. | ||
|
||
The pending wrap state may feel like an obvious and inconsequential | ||
feature, but it has a significant (but subtle) impact on cursor | ||
behavior. For example, print followed by [backspace](/docs/vt/control/bs) | ||
behaves differently depending on if you're printing in the rightmost | ||
column of the screen or not. | ||
|
||
If you print a character in any column other than the rightmost column | ||
and then send a [backspace](/docs/vt/control/bs) control character, the | ||
cursor will move back on top of the most recently printed character. | ||
But if you print a character in the rightmost column and then send a | ||
[backspace](/docs/vt/control/bs) control character, the cursor will move | ||
to the left of the character most recently printed. This is the | ||
source of [bugs in multiple popular shell prompts](https://github.com/ghostty-org/ghostty/issues/884). | ||
|
||
You will see that many control sequences note that they | ||
"unset the pending wrap state". This is just as it sounds: if the | ||
pending wrap state is set on the cursor, it becomes unset. The next | ||
printed character will not wrap to the next line. | ||
|
||
[^1]: This isn't strictly true. Wraparound modes and scroll regions | ||
can change this behavior. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
title: Screen | ||
description: TODO | ||
--- | ||
|
||
TODO |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
--- | ||
title: Backspace (BS) | ||
description: Move the cursor backward one position. | ||
--- | ||
|
||
# Backspace (BS) | ||
|
||
<VTSequence sequence="BS" /> | ||
|
||
This sequence performs [cursor backward (CUB)](/docs/vt/csi/cub) | ||
with `Pn = 1`. There is no additional or different behavior for | ||
using `BS`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
--- | ||
title: Cursor Backward (CUB) | ||
description: Move the cursor left `n` cells. | ||
--- | ||
|
||
<VTSequence sequence={["CSI", "Pn", "D"]} /> | ||
|
||
The parameter `n` must be an integer greater than or equal to 1. If `n` is less than | ||
or equal to 0, adjust `n` to be 1. If `n` is omitted, `n` defaults to 1. | ||
|
||
This sequence always unsets the | ||
[pending wrap state](/docs/vt/concepts/cursor#pending-wrap-state). | ||
|
||
The leftmost boundary the cursor can move to is determined by the current | ||
cursor column and the [left margin](#TODO). If the cursor begins to the left of the left margin, modify the left margin to be the leftmost column | ||
for the duration of the sequence. The leftmost column the cursor can be on | ||
is the left margin. | ||
|
||
With the above in place, there are three different cursor backward behaviors | ||
depending on the mode state of the terminal. The possible behaviors are listed | ||
below. In the case of a conflict, the top-most behavior takes priority. | ||
|
||
- **Extended reverse wrap**: [wraparound (mode 7)](#TODO) and [extended reverse wrap (mode 1045)](#TODO) | ||
are **BOTH** enabled | ||
- **Reverse wrap**: [wraparound (mode 7)](#TODO) and [reverse wrap (mode 45)](#TODO) | ||
are **BOTH** enabled | ||
- **No wrap**: The default behavior if the above wrapping behaviors | ||
do not have their conditions met. | ||
|
||
For the **no wrap** behavior, move the cursor to the left `n` cells while | ||
respecting the aforementioned leftmost boundary. Upon reaching the leftmost | ||
boundary, stop moving the cursor left regardless of the remaining value of `n`. | ||
The cursor row remains unchanged. | ||
|
||
For the **extended reverse wrap** behavior, move the cursor to the left `n` | ||
cells while respecting the aforementioned leftmost boundary. Upon reaching the | ||
leftmost boundary, if `n > 0` then move the cursor to the [right margin](#TODO) | ||
of the line above the cursor. If the cursor is already on the | ||
[top margin](#TODO), move the cursor to the right margin of the | ||
[bottom margin](#TODO). Both the cursor column and row can change in this | ||
mode. Compared to non-extended reverse wrap, the two critical differences are | ||
that extended reverse wrap doesn't require the previous line to be wrapped | ||
and extended reverse wrap will wrap around to the bottom margin. | ||
|
||
For the **reverse wrap** (non-extended) behavior, move the cursor to the left `n` | ||
cells while respecting the aforementioned leftmost boundary. Upon reaching the | ||
leftmost boundary, if `n > 0` and the previous line was wrapped, then move the | ||
cursor to the [right margin](#TODO) of the line above the cursor. If the previous | ||
line was not wrapped, the cursor left operation is complete even if there | ||
is a remaining value of `n`. If the cursor | ||
is already on the [top margin](#TODO), do not move the cursor up. | ||
This wrapping mode does not wrap the cursor row back to the bottom margin. | ||
|
||
For **extended reverse wrap** or **reverse wrap** modes, if the pending | ||
wrap state is set, decrease `n` by 1. In these modes, the initial cursor | ||
backward count is consumed by the pending wrap state, as if you pressed | ||
"backspace" on an empty newline and the cursor moved back to the previous line. | ||
|
||
## Validation | ||
|
||
### CUB V-1: Pending Wrap is Unset | ||
|
||
```bash | ||
cols=$(tput cols) | ||
printf "\033[${cols}G" # move to last column | ||
printf "A" # set pending wrap state | ||
printf "\033[D" # move back one | ||
printf "XYZ" | ||
``` | ||
|
||
``` | ||
|________XY| | ||
|Zc________| | ||
``` | ||
|
||
### CUB V-2: Leftmost Boundary with Reverse Wrap Disabled | ||
|
||
```bash | ||
printf "\033[?45l" # disable reverse wrap | ||
echo "A" | ||
printf "\033[10D" # back | ||
printf "B" | ||
``` | ||
|
||
``` | ||
|A_________| | ||
|Bc________| | ||
``` | ||
|
||
### CUB V-3: Reverse Wrap | ||
|
||
```bash | ||
cols=$(tput cols) | ||
printf "\033[?7h" # enable wraparound | ||
printf "\033[?45h" # enable reverse wrap | ||
printf "\033[1;1H" # move to top-left | ||
printf "\033[0J" # clear screen | ||
printf "\033[${cols}G" # move to end of line | ||
printf "AB" # write and wrap | ||
printf "\033[D" # move back two | ||
printf "X" | ||
``` | ||
|
||
``` | ||
|_________Xc | ||
|B_________| | ||
``` | ||
|
||
### CUB V-4: Extended Reverse Wrap Single Line | ||
|
||
```bash | ||
printf "\033[?7h" # enable wraparound | ||
printf "\033[?1045h" # enable extended reverse wrap | ||
printf "\033[1;1H" # move to top-left | ||
printf "\033[0J" # clear screen | ||
echo "A" | ||
printf "B" | ||
printf "\033[2D" # move back two | ||
printf "X" | ||
``` | ||
|
||
``` | ||
|A________Xc | ||
|B_________| | ||
``` | ||
|
||
### CUB V-5: Extended Reverse Wrap Wraps to Bottom | ||
|
||
```bash | ||
cols=$(tput cols) | ||
printf "\033[?7h" # enable wraparound | ||
printf "\033[?1045h" # enable extended reverse wrap | ||
printf "\033[1;1H" # move to top-left | ||
printf "\033[0J" # clear screen | ||
printf "\033[1;3r" # set scrolling region | ||
echo "A" | ||
printf "B" | ||
printf "\033[D" # move back one | ||
printf "\033[${cols}D" # move back entire width | ||
printf "\033[D" # move back one | ||
printf "X" | ||
``` | ||
|
||
``` | ||
|A_________| | ||
|B_________| | ||
|_________Xc | ||
``` | ||
|
||
### CUB V-6: Reverse Wrap Outside of Margins | ||
|
||
```bash | ||
printf "\033[1;1H" | ||
printf "\033[0J" | ||
printf "\033[?45h" | ||
printf "\033[3r" | ||
printf "\b" | ||
printf "X" | ||
``` | ||
|
||
``` | ||
|__________| | ||
|__________| | ||
|Xc________| | ||
``` | ||
|
||
### CUB V-7: Reverse Wrap with Pending Wrap State | ||
|
||
```bash | ||
cols=$(tput cols) | ||
printf "\033[?45h" | ||
printf "\033[${cols}G" | ||
printf "\033[4D" | ||
printf "ABCDE" | ||
printf "\033[D" | ||
printf "X" | ||
``` | ||
|
||
``` | ||
|_____ABCDX| | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters