From fad08ade5b14047f11501eb127b21aabdddbc192 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 3 Mar 2024 09:40:56 -0800 Subject: [PATCH] terminal/new: lots more tests ported --- src/terminal/Screen.zig | 9 + src/terminal/new/PageList.zig | 10 +- src/terminal/new/Screen.zig | 343 ++++++++++++++++++++++++++++++++++ 3 files changed, 361 insertions(+), 1 deletion(-) diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig index e892f9e25..4d3d11424 100644 --- a/src/terminal/Screen.zig +++ b/src/terminal/Screen.zig @@ -6746,6 +6746,7 @@ test "Screen: resize more cols with reflow that ends in newline" { try testing.expectEqual(@as(u32, '3'), s.getCell(.active, s.cursor.y, s.cursor.x).char); } +// X test "Screen: resize more cols with reflow that forces more wrapping" { const testing = std.testing; const alloc = testing.allocator; @@ -6782,6 +6783,7 @@ test "Screen: resize more cols with reflow that forces more wrapping" { try testing.expectEqual(@as(usize, 0), s.cursor.y); } +// X test "Screen: resize more cols with reflow that unwraps multiple times" { const testing = std.testing; const alloc = testing.allocator; @@ -6818,6 +6820,7 @@ test "Screen: resize more cols with reflow that unwraps multiple times" { try testing.expectEqual(@as(usize, 0), s.cursor.y); } +// X test "Screen: resize more cols with populated scrollback" { const testing = std.testing; const alloc = testing.allocator; @@ -6852,6 +6855,7 @@ test "Screen: resize more cols with populated scrollback" { } } +// X test "Screen: resize more cols with reflow" { const testing = std.testing; const alloc = testing.allocator; @@ -6889,6 +6893,7 @@ test "Screen: resize more cols with reflow" { try testing.expectEqual(@as(usize, 2), s.cursor.y); } +// X test "Screen: resize less rows no scrollback" { const testing = std.testing; const alloc = testing.allocator; @@ -6919,6 +6924,7 @@ test "Screen: resize less rows no scrollback" { } } +// X test "Screen: resize less rows moving cursor" { const testing = std.testing; const alloc = testing.allocator; @@ -6954,6 +6960,7 @@ test "Screen: resize less rows moving cursor" { } } +// X test "Screen: resize less rows with empty scrollback" { const testing = std.testing; const alloc = testing.allocator; @@ -6977,6 +6984,7 @@ test "Screen: resize less rows with empty scrollback" { } } +// X test "Screen: resize less rows with populated scrollback" { const testing = std.testing; const alloc = testing.allocator; @@ -7008,6 +7016,7 @@ test "Screen: resize less rows with populated scrollback" { } } +// X test "Screen: resize less rows with full scrollback" { const testing = std.testing; const alloc = testing.allocator; diff --git a/src/terminal/new/PageList.zig b/src/terminal/new/PageList.zig index 784a87ff7..72e472661 100644 --- a/src/terminal/new/PageList.zig +++ b/src/terminal/new/PageList.zig @@ -655,6 +655,14 @@ fn reflowPage( offset.row_offset == src_cursor.y and c.x == src_cursor.x) { + // std.log.warn("c.x={} c.y={} dst_x={} dst_y={} src_y={}", .{ + // c.x, + // c.y, + // dst_cursor.x, + // dst_cursor.y, + // src_cursor.y, + // }); + // Column always matches our dst x c.x = dst_cursor.x; @@ -664,7 +672,7 @@ fn reflowPage( // better calculate the CHANGE in coordinate by subtracting // our dst from src which will calculate how many rows // we unwrapped to get here. - c.y -= src_cursor.y - dst_cursor.y; + c.y -|= src_cursor.y - dst_cursor.y; c.offset = .{ .page = dst_node, diff --git a/src/terminal/new/Screen.zig b/src/terminal/new/Screen.zig index c19840522..b49c4853e 100644 --- a/src/terminal/new/Screen.zig +++ b/src/terminal/new/Screen.zig @@ -631,6 +631,8 @@ pub fn resizeWithoutReflow( .y = self.cursor.y, }; + const old_rows = self.pages.rows; + try self.pages.resize(.{ .rows = rows, .cols = cols, @@ -638,6 +640,13 @@ pub fn resizeWithoutReflow( .cursor = &cursor, }); + // If we have no scrollback and we shrunk our rows, we must explicitly + // erase our history. This is beacuse PageList always keeps at least + // a page size of history. + if (self.no_scrollback and rows < old_rows) { + self.pages.eraseRows(.{ .history = .{} }, null); + } + if (cursor.x != self.cursor.x or cursor.y != self.cursor.y) { self.cursor.x = cursor.x; self.cursor.y = cursor.y; @@ -2349,3 +2358,337 @@ test "Screen: resize more cols with reflow that ends in newline" { try testing.expectEqual(@as(u21, '3'), list_cell.cell.content.codepoint); } } + +test "Screen: resize more cols with reflow that forces more wrapping" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 5, 3, 0); + defer s.deinit(); + const str = "1ABCD2EFGH\n3IJKL"; + try s.testWriteString(str); + + // Let's put our cursor on row 2, where the soft wrap is + s.cursorAbsolute(0, 1); + { + const list_cell = s.pages.getCell(.{ .active = .{ + .x = s.cursor.x, + .y = s.cursor.y, + } }).?; + try testing.expectEqual(@as(u21, '2'), list_cell.cell.content.codepoint); + } + + // Verify we soft wrapped + { + const contents = try s.dumpStringAlloc(alloc, .{ .viewport = .{} }); + defer alloc.free(contents); + const expected = "1ABCD\n2EFGH\n3IJKL"; + try testing.expectEqualStrings(expected, contents); + } + + // Resize and verify we undid the soft wrap because we have space now + try s.resize(7, 3); + { + const contents = try s.dumpStringAlloc(alloc, .{ .viewport = .{} }); + defer alloc.free(contents); + const expected = "1ABCD2E\nFGH\n3IJKL"; + try testing.expectEqualStrings(expected, contents); + } + + // Our cursor should've moved + try testing.expectEqual(@as(size.CellCountInt, 5), s.cursor.x); + try testing.expectEqual(@as(size.CellCountInt, 0), s.cursor.y); +} + +test "Screen: resize more cols with reflow that unwraps multiple times" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 5, 3, 0); + defer s.deinit(); + const str = "1ABCD2EFGH3IJKL"; + try s.testWriteString(str); + + // Let's put our cursor on row 2, where the soft wrap is + s.cursorAbsolute(0, 2); + { + const list_cell = s.pages.getCell(.{ .active = .{ + .x = s.cursor.x, + .y = s.cursor.y, + } }).?; + try testing.expectEqual(@as(u21, '3'), list_cell.cell.content.codepoint); + } + + // Verify we soft wrapped + { + const contents = try s.dumpStringAlloc(alloc, .{ .viewport = .{} }); + defer alloc.free(contents); + const expected = "1ABCD\n2EFGH\n3IJKL"; + try testing.expectEqualStrings(expected, contents); + } + + // Resize and verify we undid the soft wrap because we have space now + try s.resize(15, 3); + { + const contents = try s.dumpStringAlloc(alloc, .{ .viewport = .{} }); + defer alloc.free(contents); + const expected = "1ABCD2EFGH3IJKL"; + try testing.expectEqualStrings(expected, contents); + } + + // Our cursor should've moved + try testing.expectEqual(@as(size.CellCountInt, 10), s.cursor.x); + try testing.expectEqual(@as(size.CellCountInt, 0), s.cursor.y); +} + +test "Screen: resize more cols with populated scrollback" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 5, 3, 5); + defer s.deinit(); + const str = "1ABCD\n2EFGH\n3IJKL\n4ABCD5EFGH"; + try s.testWriteString(str); + { + const contents = try s.dumpStringAlloc(alloc, .{ .viewport = .{} }); + defer alloc.free(contents); + const expected = "3IJKL\n4ABCD\n5EFGH"; + try testing.expectEqualStrings(expected, contents); + } + + // // Set our cursor to be on the "5" + s.cursorAbsolute(0, 2); + { + const list_cell = s.pages.getCell(.{ .active = .{ + .x = s.cursor.x, + .y = s.cursor.y, + } }).?; + try testing.expectEqual(@as(u21, '5'), list_cell.cell.content.codepoint); + } + + // Resize + try s.resize(10, 3); + { + const contents = try s.dumpStringAlloc(alloc, .{ .viewport = .{} }); + defer alloc.free(contents); + const expected = "2EFGH\n3IJKL\n4ABCD5EFGH"; + try testing.expectEqualStrings(expected, contents); + } + + // Cursor should still be on the "5" + // TODO + // { + // const list_cell = s.pages.getCell(.{ .active = .{ + // .x = s.cursor.x, + // .y = s.cursor.y, + // } }).?; + // try testing.expectEqual(@as(u21, '5'), list_cell.cell.content.codepoint); + // } +} + +test "Screen: resize more cols with reflow" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 2, 3, 5); + defer s.deinit(); + const str = "1ABC\n2DEF\n3ABC\n4DEF"; + try s.testWriteString(str); + + // Let's put our cursor on row 2, where the soft wrap is + s.cursorAbsolute(0, 2); + { + const list_cell = s.pages.getCell(.{ .active = .{ + .x = s.cursor.x, + .y = s.cursor.y, + } }).?; + try testing.expectEqual(@as(u32, 'E'), list_cell.cell.content.codepoint); + } + + // Verify we soft wrapped + { + const contents = try s.dumpStringAlloc(alloc, .{ .viewport = .{} }); + defer alloc.free(contents); + const expected = "BC\n4D\nEF"; + try testing.expectEqualStrings(expected, contents); + } + + // Resize and verify we undid the soft wrap because we have space now + try s.resize(7, 3); + { + const contents = try s.dumpStringAlloc(alloc, .{ .screen = .{} }); + defer alloc.free(contents); + const expected = "1ABC\n2DEF\n3ABC\n4DEF"; + try testing.expectEqualStrings(expected, contents); + } + + // Our cursor should've moved + // TODO + // try testing.expectEqual(@as(size.CellCountInt, 2), s.cursor.x); + // try testing.expectEqual(@as(size.CellCountInt, 2), s.cursor.y); +} + +test "Screen: resize less rows no scrollback" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 5, 3, 0); + defer s.deinit(); + const str = "1ABCD\n2EFGH\n3IJKL"; + try s.testWriteString(str); + + s.cursorAbsolute(0, 0); + const cursor = s.cursor; + try s.resize(5, 1); + + // Cursor should not move + try testing.expectEqual(cursor.x, s.cursor.x); + try testing.expectEqual(cursor.y, s.cursor.y); + + { + const contents = try s.dumpStringAlloc(alloc, .{ .viewport = .{} }); + defer alloc.free(contents); + const expected = "3IJKL"; + try testing.expectEqualStrings(expected, contents); + } + { + const contents = try s.dumpStringAlloc(alloc, .{ .screen = .{} }); + defer alloc.free(contents); + const expected = "3IJKL"; + try testing.expectEqualStrings(expected, contents); + } +} + +test "Screen: resize less rows moving cursor" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 5, 3, 0); + defer s.deinit(); + const str = "1ABCD\n2EFGH\n3IJKL"; + try s.testWriteString(str); + + // Put our cursor on the last line + s.cursorAbsolute(1, 2); + { + const list_cell = s.pages.getCell(.{ .active = .{ + .x = s.cursor.x, + .y = s.cursor.y, + } }).?; + try testing.expectEqual(@as(u32, 'I'), list_cell.cell.content.codepoint); + } + + // Resize + try s.resize(5, 1); + + { + const contents = try s.dumpStringAlloc(alloc, .{ .viewport = .{} }); + defer alloc.free(contents); + const expected = "3IJKL"; + try testing.expectEqualStrings(expected, contents); + } + { + const contents = try s.dumpStringAlloc(alloc, .{ .screen = .{} }); + defer alloc.free(contents); + const expected = "3IJKL"; + try testing.expectEqualStrings(expected, contents); + } + + // Cursor should be on the last line + try testing.expectEqual(@as(size.CellCountInt, 1), s.cursor.x); + try testing.expectEqual(@as(size.CellCountInt, 0), s.cursor.y); +} + +test "Screen: resize less rows with empty scrollback" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 5, 3, 10); + defer s.deinit(); + const str = "1ABCD\n2EFGH\n3IJKL"; + try s.testWriteString(str); + try s.resize(5, 1); + + { + const contents = try s.dumpStringAlloc(alloc, .{ .screen = .{} }); + defer alloc.free(contents); + try testing.expectEqualStrings(str, contents); + } + { + const contents = try s.dumpStringAlloc(alloc, .{ .viewport = .{} }); + defer alloc.free(contents); + const expected = "3IJKL"; + try testing.expectEqualStrings(expected, contents); + } +} + +test "Screen: resize less rows with populated scrollback" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 5, 3, 5); + defer s.deinit(); + const str = "1ABCD\n2EFGH\n3IJKL\n4ABCD\n5EFGH"; + try s.testWriteString(str); + { + const contents = try s.dumpStringAlloc(alloc, .{ .viewport = .{} }); + defer alloc.free(contents); + const expected = "3IJKL\n4ABCD\n5EFGH"; + try testing.expectEqualStrings(expected, contents); + } + + // Resize + try s.resize(5, 1); + + { + const contents = try s.dumpStringAlloc(alloc, .{ .screen = .{} }); + defer alloc.free(contents); + try testing.expectEqualStrings(str, contents); + } + { + const contents = try s.dumpStringAlloc(alloc, .{ .viewport = .{} }); + defer alloc.free(contents); + const expected = "5EFGH"; + try testing.expectEqualStrings(expected, contents); + } +} + +test "Screen: resize less rows with full scrollback" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 5, 3, 3); + defer s.deinit(); + const str = "00000\n1ABCD\n2EFGH\n3IJKL\n4ABCD\n5EFGH"; + try s.testWriteString(str); + { + const contents = try s.dumpStringAlloc(alloc, .{ .viewport = .{} }); + defer alloc.free(contents); + const expected = "3IJKL\n4ABCD\n5EFGH"; + try testing.expectEqualStrings(expected, contents); + } + + try testing.expectEqual(@as(size.CellCountInt, 4), s.cursor.x); + try testing.expectEqual(@as(size.CellCountInt, 2), s.cursor.y); + + // Resize + try s.resize(5, 2); + + // Cursor should stay in the same relative place (bottom of the + // screen, same character). + try testing.expectEqual(@as(size.CellCountInt, 4), s.cursor.x); + try testing.expectEqual(@as(size.CellCountInt, 1), s.cursor.y); + + { + const contents = try s.dumpStringAlloc(alloc, .{ .screen = .{} }); + defer alloc.free(contents); + const expected = "00000\n1ABCD\n2EFGH\n3IJKL\n4ABCD\n5EFGH"; + try testing.expectEqualStrings(expected, contents); + } + { + const contents = try s.dumpStringAlloc(alloc, .{ .viewport = .{} }); + defer alloc.free(contents); + const expected = "4ABCD\n5EFGH"; + try testing.expectEqualStrings(expected, contents); + } +}