terminal: cub with reverse wrap consumes pending wrap state as one

Related to #1184

See the updated website page and associated test.
This commit is contained in:
Mitchell Hashimoto
2023-12-29 12:45:57 -08:00
parent 884814eb03
commit 3e9a4ea234
2 changed files with 72 additions and 3 deletions

View File

@ -1564,18 +1564,23 @@ pub fn cursorLeft(self: *Terminal, count_req: usize) void {
break :wrap_mode .none;
};
// Unset the pending wrap state no matter what
self.screen.cursor.pending_wrap = false;
var count: usize = @max(count_req, 1);
// If we are in no wrap mode, then we move the cursor left and exit
// since this is the fastest and most typical path.
if (wrap_mode == .none) {
self.screen.cursor.x -|= count;
self.screen.cursor.pending_wrap = false;
return;
}
// If we have a pending wrap state and we are in either reverse wrap
// modes then we decrement the amount we move by one to match xterm.
if (self.screen.cursor.pending_wrap) {
count -= 1;
self.screen.cursor.pending_wrap = false;
}
// The margins we can move to.
const top = self.scrolling_region.top;
const bottom = self.scrolling_region.bottom;
@ -6265,6 +6270,48 @@ test "Terminal: cursorLeft unsets pending wrap state with longer jump" {
}
}
test "Terminal: cursorLeft reverse wrap with pending wrap state" {
const alloc = testing.allocator;
var t = try init(alloc, 5, 5);
defer t.deinit(alloc);
t.modes.set(.wraparound, true);
t.modes.set(.reverse_wrap, true);
for ("ABCDE") |c| try t.print(c);
try testing.expect(t.screen.cursor.pending_wrap);
t.cursorLeft(1);
try testing.expect(!t.screen.cursor.pending_wrap);
try t.print('X');
{
const str = try t.plainString(testing.allocator);
defer testing.allocator.free(str);
try testing.expectEqualStrings("ABCDX", str);
}
}
test "Terminal: cursorLeft reverse wrap extended with pending wrap state" {
const alloc = testing.allocator;
var t = try init(alloc, 5, 5);
defer t.deinit(alloc);
t.modes.set(.wraparound, true);
t.modes.set(.reverse_wrap_extended, true);
for ("ABCDE") |c| try t.print(c);
try testing.expect(t.screen.cursor.pending_wrap);
t.cursorLeft(1);
try testing.expect(!t.screen.cursor.pending_wrap);
try t.print('X');
{
const str = try t.plainString(testing.allocator);
defer testing.allocator.free(str);
try testing.expectEqualStrings("ABCDX", str);
}
}
test "Terminal: cursorLeft reverse wrap" {
const alloc = testing.allocator;
var t = try init(alloc, 5, 5);

View File

@ -51,6 +51,11 @@ 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
@ -159,3 +164,20 @@ 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|
```