mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 00:36:07 +03:00
terminal/new: cursorLeft
This commit is contained in:
@ -6519,6 +6519,7 @@ test "Terminal: eraseDisplay scroll complete" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X
|
||||||
test "Terminal: cursorLeft no wrap" {
|
test "Terminal: cursorLeft no wrap" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var t = try init(alloc, 10, 5);
|
var t = try init(alloc, 10, 5);
|
||||||
@ -6537,6 +6538,7 @@ test "Terminal: cursorLeft no wrap" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X
|
||||||
test "Terminal: cursorLeft unsets pending wrap state" {
|
test "Terminal: cursorLeft unsets pending wrap state" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var t = try init(alloc, 5, 5);
|
var t = try init(alloc, 5, 5);
|
||||||
@ -6555,6 +6557,7 @@ test "Terminal: cursorLeft unsets pending wrap state" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X
|
||||||
test "Terminal: cursorLeft unsets pending wrap state with longer jump" {
|
test "Terminal: cursorLeft unsets pending wrap state with longer jump" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var t = try init(alloc, 5, 5);
|
var t = try init(alloc, 5, 5);
|
||||||
@ -6573,6 +6576,7 @@ test "Terminal: cursorLeft unsets pending wrap state with longer jump" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X
|
||||||
test "Terminal: cursorLeft reverse wrap with pending wrap state" {
|
test "Terminal: cursorLeft reverse wrap with pending wrap state" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var t = try init(alloc, 5, 5);
|
var t = try init(alloc, 5, 5);
|
||||||
@ -6594,6 +6598,7 @@ test "Terminal: cursorLeft reverse wrap with pending wrap state" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X
|
||||||
test "Terminal: cursorLeft reverse wrap extended with pending wrap state" {
|
test "Terminal: cursorLeft reverse wrap extended with pending wrap state" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var t = try init(alloc, 5, 5);
|
var t = try init(alloc, 5, 5);
|
||||||
@ -6615,6 +6620,7 @@ test "Terminal: cursorLeft reverse wrap extended with pending wrap state" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X
|
||||||
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);
|
||||||
@ -6635,6 +6641,7 @@ test "Terminal: cursorLeft reverse wrap" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X
|
||||||
test "Terminal: cursorLeft reverse wrap with no soft wrap" {
|
test "Terminal: cursorLeft reverse wrap with no soft wrap" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var t = try init(alloc, 5, 5);
|
var t = try init(alloc, 5, 5);
|
||||||
@ -6657,6 +6664,7 @@ test "Terminal: cursorLeft reverse wrap with no soft wrap" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X
|
||||||
test "Terminal: cursorLeft reverse wrap before left margin" {
|
test "Terminal: cursorLeft reverse wrap before left margin" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var t = try init(alloc, 5, 5);
|
var t = try init(alloc, 5, 5);
|
||||||
@ -6675,6 +6683,7 @@ test "Terminal: cursorLeft reverse wrap before left margin" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X
|
||||||
test "Terminal: cursorLeft extended reverse wrap" {
|
test "Terminal: cursorLeft extended reverse wrap" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var t = try init(alloc, 5, 5);
|
var t = try init(alloc, 5, 5);
|
||||||
@ -6697,6 +6706,7 @@ test "Terminal: cursorLeft extended reverse wrap" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X
|
||||||
test "Terminal: cursorLeft extended reverse wrap bottom wraparound" {
|
test "Terminal: cursorLeft extended reverse wrap bottom wraparound" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var t = try init(alloc, 5, 3);
|
var t = try init(alloc, 5, 3);
|
||||||
@ -6719,6 +6729,7 @@ test "Terminal: cursorLeft extended reverse wrap bottom wraparound" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X
|
||||||
test "Terminal: cursorLeft extended reverse wrap is priority if both set" {
|
test "Terminal: cursorLeft extended reverse wrap is priority if both set" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var t = try init(alloc, 5, 3);
|
var t = try init(alloc, 5, 3);
|
||||||
@ -6742,6 +6753,7 @@ test "Terminal: cursorLeft extended reverse wrap is priority if both set" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X
|
||||||
test "Terminal: cursorLeft extended reverse wrap above top scroll region" {
|
test "Terminal: cursorLeft extended reverse wrap above top scroll region" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var t = try init(alloc, 5, 5);
|
var t = try init(alloc, 5, 5);
|
||||||
@ -6758,6 +6770,7 @@ test "Terminal: cursorLeft extended reverse wrap above top scroll region" {
|
|||||||
try testing.expectEqual(@as(usize, 0), t.screen.cursor.y);
|
try testing.expectEqual(@as(usize, 0), t.screen.cursor.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X
|
||||||
test "Terminal: cursorLeft reverse wrap on first row" {
|
test "Terminal: cursorLeft reverse wrap on first row" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var t = try init(alloc, 5, 5);
|
var t = try init(alloc, 5, 5);
|
||||||
|
@ -134,6 +134,14 @@ pub fn cursorUp(self: *Screen, n: size.CellCountInt) void {
|
|||||||
self.cursor.y -= n;
|
self.cursor.y -= n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn cursorRowUp(self: *Screen, n: size.CellCountInt) *pagepkg.Row {
|
||||||
|
assert(self.cursor.y >= n);
|
||||||
|
|
||||||
|
const page_offset = self.cursor.page_offset.backward(n).?;
|
||||||
|
const page_rac = page_offset.rowAndCell(self.cursor.x);
|
||||||
|
return page_rac.row;
|
||||||
|
}
|
||||||
|
|
||||||
/// Move the cursor down.
|
/// Move the cursor down.
|
||||||
///
|
///
|
||||||
/// Precondition: The cursor is not at the bottom of the screen.
|
/// Precondition: The cursor is not at the bottom of the screen.
|
||||||
|
@ -614,12 +614,12 @@ pub fn cursorLeft(self: *Terminal, count_req: usize) void {
|
|||||||
break :wrap_mode .none;
|
break :wrap_mode .none;
|
||||||
};
|
};
|
||||||
|
|
||||||
var count: size.CellCountInt = @intCast(@max(count_req, 1));
|
var count = @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.cursorLeft(count);
|
self.screen.cursorLeft(@min(count, self.screen.cursor.x));
|
||||||
self.screen.cursor.pending_wrap = false;
|
self.screen.cursor.pending_wrap = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -694,7 +694,8 @@ pub fn cursorLeft(self: *Terminal, count_req: usize) void {
|
|||||||
|
|
||||||
// If our previous line is not wrapped then we are done.
|
// If our previous line is not wrapped then we are done.
|
||||||
if (wrap_mode != .reverse_extended) {
|
if (wrap_mode != .reverse_extended) {
|
||||||
if (!self.screen.cursor.page_row.wrap) break;
|
const prev_row = self.screen.cursorRowUp(1);
|
||||||
|
if (!prev_row.wrap) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.screen.cursorAbsolute(right_margin, self.screen.cursor.y - 1);
|
self.screen.cursorAbsolute(right_margin, self.screen.cursor.y - 1);
|
||||||
@ -3320,6 +3321,261 @@ test "Terminal: cursorUp resets wrap" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "Terminal: cursorLeft no wrap" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 10, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
try t.print('A');
|
||||||
|
t.carriageReturn();
|
||||||
|
try t.linefeed();
|
||||||
|
try t.print('B');
|
||||||
|
t.cursorLeft(10);
|
||||||
|
|
||||||
|
{
|
||||||
|
const str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("A\nB", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: cursorLeft unsets pending wrap state" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 5, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
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("ABCXE", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: cursorLeft unsets pending wrap state with longer jump" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 5, 5);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
for ("ABCDE") |c| try t.print(c);
|
||||||
|
try testing.expect(t.screen.cursor.pending_wrap);
|
||||||
|
t.cursorLeft(3);
|
||||||
|
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("AXCDE", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
t.modes.set(.wraparound, true);
|
||||||
|
t.modes.set(.reverse_wrap, true);
|
||||||
|
|
||||||
|
for ("ABCDE1") |c| try t.print(c);
|
||||||
|
t.cursorLeft(2);
|
||||||
|
try t.print('X');
|
||||||
|
try testing.expect(t.screen.cursor.pending_wrap);
|
||||||
|
|
||||||
|
{
|
||||||
|
const str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("ABCDX\n1", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: cursorLeft reverse wrap with no soft wrap" {
|
||||||
|
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);
|
||||||
|
t.carriageReturn();
|
||||||
|
try t.linefeed();
|
||||||
|
try t.print('1');
|
||||||
|
t.cursorLeft(2);
|
||||||
|
try t.print('X');
|
||||||
|
|
||||||
|
{
|
||||||
|
const str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("ABCDE\nX", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: cursorLeft reverse wrap before left margin" {
|
||||||
|
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);
|
||||||
|
t.setTopAndBottomMargin(3, 0);
|
||||||
|
t.cursorLeft(1);
|
||||||
|
try t.print('X');
|
||||||
|
|
||||||
|
{
|
||||||
|
const str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("\n\nX", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: cursorLeft extended reverse wrap" {
|
||||||
|
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);
|
||||||
|
t.carriageReturn();
|
||||||
|
try t.linefeed();
|
||||||
|
try t.print('1');
|
||||||
|
t.cursorLeft(2);
|
||||||
|
try t.print('X');
|
||||||
|
|
||||||
|
{
|
||||||
|
const str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("ABCDX\n1", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: cursorLeft extended reverse wrap bottom wraparound" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 5, 3);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
t.modes.set(.wraparound, true);
|
||||||
|
t.modes.set(.reverse_wrap_extended, true);
|
||||||
|
|
||||||
|
for ("ABCDE") |c| try t.print(c);
|
||||||
|
t.carriageReturn();
|
||||||
|
try t.linefeed();
|
||||||
|
try t.print('1');
|
||||||
|
t.cursorLeft(1 + t.cols + 1);
|
||||||
|
try t.print('X');
|
||||||
|
|
||||||
|
{
|
||||||
|
const str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("ABCDE\n1\n X", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: cursorLeft extended reverse wrap is priority if both set" {
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, 5, 3);
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
t.modes.set(.wraparound, true);
|
||||||
|
t.modes.set(.reverse_wrap, true);
|
||||||
|
t.modes.set(.reverse_wrap_extended, true);
|
||||||
|
|
||||||
|
for ("ABCDE") |c| try t.print(c);
|
||||||
|
t.carriageReturn();
|
||||||
|
try t.linefeed();
|
||||||
|
try t.print('1');
|
||||||
|
t.cursorLeft(1 + t.cols + 1);
|
||||||
|
try t.print('X');
|
||||||
|
|
||||||
|
{
|
||||||
|
const str = try t.plainString(testing.allocator);
|
||||||
|
defer testing.allocator.free(str);
|
||||||
|
try testing.expectEqualStrings("ABCDE\n1\n X", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: cursorLeft extended reverse wrap above top scroll region" {
|
||||||
|
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);
|
||||||
|
|
||||||
|
t.setTopAndBottomMargin(3, 0);
|
||||||
|
t.setCursorPos(2, 1);
|
||||||
|
t.cursorLeft(1000);
|
||||||
|
|
||||||
|
try testing.expectEqual(@as(usize, 0), t.screen.cursor.x);
|
||||||
|
try testing.expectEqual(@as(usize, 0), t.screen.cursor.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Terminal: cursorLeft reverse wrap on first row" {
|
||||||
|
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);
|
||||||
|
|
||||||
|
t.setTopAndBottomMargin(3, 0);
|
||||||
|
t.setCursorPos(1, 2);
|
||||||
|
t.cursorLeft(1000);
|
||||||
|
|
||||||
|
try testing.expectEqual(@as(usize, 0), t.screen.cursor.x);
|
||||||
|
try testing.expectEqual(@as(usize, 0), t.screen.cursor.y);
|
||||||
|
}
|
||||||
|
|
||||||
test "Terminal: deleteLines simple" {
|
test "Terminal: deleteLines simple" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var t = try init(alloc, 5, 5);
|
var t = try init(alloc, 5, 5);
|
||||||
|
Reference in New Issue
Block a user