mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
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:
@ -1564,18 +1564,23 @@ pub fn cursorLeft(self: *Terminal, count_req: usize) void {
|
|||||||
break :wrap_mode .none;
|
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);
|
var count: usize = @max(count_req, 1);
|
||||||
|
|
||||||
// If we are in no wrap mode, then we move the cursor left and exit
|
// If we are in no wrap mode, then we move the cursor left and exit
|
||||||
// since this is the fastest and most typical path.
|
// since this is the fastest and most typical path.
|
||||||
if (wrap_mode == .none) {
|
if (wrap_mode == .none) {
|
||||||
self.screen.cursor.x -|= count;
|
self.screen.cursor.x -|= count;
|
||||||
|
self.screen.cursor.pending_wrap = false;
|
||||||
return;
|
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.
|
// The margins we can move to.
|
||||||
const top = self.scrolling_region.top;
|
const top = self.scrolling_region.top;
|
||||||
const bottom = self.scrolling_region.bottom;
|
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" {
|
test "Terminal: cursorLeft reverse wrap" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var t = try init(alloc, 5, 5);
|
var t = try init(alloc, 5, 5);
|
||||||
|
@ -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.
|
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.
|
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
|
## Validation
|
||||||
|
|
||||||
### CUB V-1: Pending Wrap is Unset
|
### CUB V-1: Pending Wrap is Unset
|
||||||
@ -159,3 +164,20 @@ printf "X"
|
|||||||
|__________|
|
|__________|
|
||||||
|Xc________|
|
|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|
|
||||||
|
```
|
||||||
|
Reference in New Issue
Block a user