From d38e075a7c93d5e054d9b47545bdf4bc75e170e0 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 26 Feb 2024 14:07:28 -0800 Subject: [PATCH] terminal/new: lots more scroll region tests --- src/terminal/Terminal.zig | 7 ++ src/terminal/new/Terminal.zig | 209 ++++++++++++++++++++++++++++++++-- src/terminal/new/page.zig | 5 + 3 files changed, 210 insertions(+), 11 deletions(-) diff --git a/src/terminal/Terminal.zig b/src/terminal/Terminal.zig index db0f79cdf..fccfbf4ac 100644 --- a/src/terminal/Terminal.zig +++ b/src/terminal/Terminal.zig @@ -3726,6 +3726,7 @@ test "Terminal: deleteLines simple" { } } +// X test "Terminal: deleteLines left/right scroll region" { const alloc = testing.allocator; var t = try init(alloc, 10, 10); @@ -3769,6 +3770,7 @@ test "Terminal: deleteLines left/right scroll region clears row wrap" { } } +// X test "Terminal: deleteLines left/right scroll region from top" { const alloc = testing.allocator; var t = try init(alloc, 10, 10); @@ -3793,6 +3795,7 @@ test "Terminal: deleteLines left/right scroll region from top" { } } +// X test "Terminal: deleteLines left/right scroll region high count" { const alloc = testing.allocator; var t = try init(alloc, 10, 10); @@ -3891,6 +3894,7 @@ test "Terminal: insertLines top/bottom scroll region" { } } +// X test "Terminal: insertLines left/right scroll region" { const alloc = testing.allocator; var t = try init(alloc, 10, 10); @@ -4231,6 +4235,7 @@ test "Terminal: reverseIndex outside top/bottom margins" { } } +// X test "Terminal: reverseIndex left/right margins" { const alloc = testing.allocator; var t = try init(alloc, 5, 5); @@ -4253,6 +4258,7 @@ test "Terminal: reverseIndex left/right margins" { } } +// X test "Terminal: reverseIndex outside left/right margins" { const alloc = testing.allocator; var t = try init(alloc, 5, 5); @@ -4486,6 +4492,7 @@ test "Terminal: index outside left/right margin" { } } +// X test "Terminal: index inside left/right margin" { const alloc = testing.allocator; var t = try init(alloc, 10, 5); diff --git a/src/terminal/new/Terminal.zig b/src/terminal/new/Terminal.zig index e1e1ec83b..cab132b8a 100644 --- a/src/terminal/new/Terminal.zig +++ b/src/terminal/new/Terminal.zig @@ -212,6 +212,14 @@ pub fn printString(self: *Terminal, str: []const u8) !void { } } +/// Print the previous printed character a repeated amount of times. +pub fn printRepeat(self: *Terminal, count_req: usize) !void { + if (self.previous_char) |c| { + const count = @max(count_req, 1); + for (0..count) |_| try self.print(c); + } +} + pub fn print(self: *Terminal, c: u21) !void { // log.debug("print={x} y={} x={}", .{ c, self.screen.cursor.y, self.screen.cursor.x }); @@ -1150,12 +1158,6 @@ pub fn deleteLines(self: *Terminal, count_req: usize) void { self.screen.cursor.x < self.scrolling_region.left or self.screen.cursor.x > self.scrolling_region.right) return; - if (self.scrolling_region.left > 0 or - self.scrolling_region.right < self.cols - 1) - { - @panic("TODO: left/right margins"); - } - // top is just the cursor position. insertLines starts at the cursor // so this is our top. We want to shift lines down, down to the bottom // of the scroll region. @@ -1173,16 +1175,33 @@ pub fn deleteLines(self: *Terminal, count_req: usize) void { // "scroll_amount" is the number of such lines. const scroll_amount = rem - count; if (scroll_amount > 0) { + // If we have left/right scroll margins we have a slower path. + const left_right = self.scrolling_region.left > 0 or + self.scrolling_region.right < self.cols - 1; + const bottom: [*]Row = top + (scroll_amount - 1); while (@intFromPtr(y) <= @intFromPtr(bottom)) : (y += 1) { const src: *Row = @ptrCast(y + count); const dst: *Row = @ptrCast(y); - // Swap the src/dst cells. This ensures that our dst gets the proper - // shifted rows and src gets non-garbage cell data that we can clear. - const dst_row = dst.*; - dst.* = src.*; - src.* = dst_row; + if (!left_right) { + // Swap the src/dst cells. This ensures that our dst gets the proper + // shifted rows and src gets non-garbage cell data that we can clear. + const dst_row = dst.*; + dst.* = src.*; + src.* = dst_row; + continue; + } + + // Left/right scroll margins we have to copy cells, which is much slower... + var page = &self.screen.cursor.page_offset.page.data; + page.moveCells( + src, + self.scrolling_region.left, + dst, + self.scrolling_region.left, + (self.scrolling_region.right - self.scrolling_region.left) + 1, + ); } } @@ -2912,6 +2931,30 @@ test "Terminal: insertLines multi-codepoint graphemes" { } } +test "Terminal: insertLines left/right scroll region" { + const alloc = testing.allocator; + var t = try init(alloc, 10, 10); + defer t.deinit(alloc); + + try t.printString("ABC123"); + t.carriageReturn(); + try t.linefeed(); + try t.printString("DEF456"); + t.carriageReturn(); + try t.linefeed(); + try t.printString("GHI789"); + t.scrolling_region.left = 1; + t.scrolling_region.right = 3; + t.setCursorPos(2, 2); + t.insertLines(1); + + { + const str = try t.plainString(testing.allocator); + defer testing.allocator.free(str); + try testing.expectEqualStrings("ABC123\nD 56\nGEF489\n HI7", str); + } +} + test "Terminal: scrollUp simple" { const alloc = testing.allocator; var t = try init(alloc, 5, 5); @@ -3425,6 +3468,50 @@ test "Terminal: reverseIndex outside top/bottom margins" { } } +test "Terminal: reverseIndex left/right margins" { + const alloc = testing.allocator; + var t = try init(alloc, 5, 5); + defer t.deinit(alloc); + + try t.printString("ABC"); + t.setCursorPos(2, 1); + try t.printString("DEF"); + t.setCursorPos(3, 1); + try t.printString("GHI"); + t.modes.set(.enable_left_and_right_margin, true); + t.setLeftAndRightMargin(2, 3); + t.setCursorPos(1, 2); + t.reverseIndex(); + + { + const str = try t.plainString(testing.allocator); + defer testing.allocator.free(str); + try testing.expectEqualStrings("A\nDBC\nGEF\n HI", str); + } +} + +test "Terminal: reverseIndex outside left/right margins" { + const alloc = testing.allocator; + var t = try init(alloc, 5, 5); + defer t.deinit(alloc); + + try t.printString("ABC"); + t.setCursorPos(2, 1); + try t.printString("DEF"); + t.setCursorPos(3, 1); + try t.printString("GHI"); + t.modes.set(.enable_left_and_right_margin, true); + t.setLeftAndRightMargin(2, 3); + t.setCursorPos(1, 1); + t.reverseIndex(); + + { + const str = try t.plainString(testing.allocator); + defer testing.allocator.free(str); + try testing.expectEqualStrings("ABC\nDEF\nGHI", str); + } +} + test "Terminal: index" { const alloc = testing.allocator; var t = try init(alloc, 2, 5); @@ -3610,6 +3697,34 @@ test "Terminal: index outside left/right margin" { } } +test "Terminal: index inside left/right margin" { + const alloc = testing.allocator; + var t = try init(alloc, 10, 5); + defer t.deinit(alloc); + + try t.printString("AAAAAA"); + t.carriageReturn(); + try t.linefeed(); + try t.printString("AAAAAA"); + t.carriageReturn(); + try t.linefeed(); + try t.printString("AAAAAA"); + t.modes.set(.enable_left_and_right_margin, true); + t.setTopAndBottomMargin(1, 3); + t.setLeftAndRightMargin(1, 3); + t.setCursorPos(3, 1); + try t.index(); + + try testing.expectEqual(@as(usize, 2), t.screen.cursor.y); + try testing.expectEqual(@as(usize, 0), t.screen.cursor.x); + + { + const str = try t.plainString(testing.allocator); + defer testing.allocator.free(str); + try testing.expectEqualStrings("AAAAAA\nAAAAAA\n AAA", str); + } +} + test "Terminal: index bottom of scroll region" { const alloc = testing.allocator; var t = try init(alloc, 5, 5); @@ -4307,6 +4422,78 @@ test "Terminal: deleteLines resets wrap" { } } +test "Terminal: deleteLines left/right scroll region" { + const alloc = testing.allocator; + var t = try init(alloc, 10, 10); + defer t.deinit(alloc); + + try t.printString("ABC123"); + t.carriageReturn(); + try t.linefeed(); + try t.printString("DEF456"); + t.carriageReturn(); + try t.linefeed(); + try t.printString("GHI789"); + t.scrolling_region.left = 1; + t.scrolling_region.right = 3; + t.setCursorPos(2, 2); + t.deleteLines(1); + + { + const str = try t.plainString(testing.allocator); + defer testing.allocator.free(str); + try testing.expectEqualStrings("ABC123\nDHI756\nG 89", str); + } +} + +test "Terminal: deleteLines left/right scroll region from top" { + const alloc = testing.allocator; + var t = try init(alloc, 10, 10); + defer t.deinit(alloc); + + try t.printString("ABC123"); + t.carriageReturn(); + try t.linefeed(); + try t.printString("DEF456"); + t.carriageReturn(); + try t.linefeed(); + try t.printString("GHI789"); + t.scrolling_region.left = 1; + t.scrolling_region.right = 3; + t.setCursorPos(1, 2); + t.deleteLines(1); + + { + const str = try t.plainString(testing.allocator); + defer testing.allocator.free(str); + try testing.expectEqualStrings("AEF423\nDHI756\nG 89", str); + } +} + +test "Terminal: deleteLines left/right scroll region high count" { + const alloc = testing.allocator; + var t = try init(alloc, 10, 10); + defer t.deinit(alloc); + + try t.printString("ABC123"); + t.carriageReturn(); + try t.linefeed(); + try t.printString("DEF456"); + t.carriageReturn(); + try t.linefeed(); + try t.printString("GHI789"); + t.scrolling_region.left = 1; + t.scrolling_region.right = 3; + t.setCursorPos(2, 2); + t.deleteLines(100); + + { + const str = try t.plainString(testing.allocator); + defer testing.allocator.free(str); + try testing.expectEqualStrings("ABC123\nD 56\nG 89", str); + } +} + test "Terminal: default style is empty" { const alloc = testing.allocator; var t = try init(alloc, 5, 5); diff --git a/src/terminal/new/page.zig b/src/terminal/new/page.zig index 5112a74a7..6a37669f7 100644 --- a/src/terminal/new/page.zig +++ b/src/terminal/new/page.zig @@ -470,6 +470,11 @@ pub const Row = packed struct(u64) { /// this will be set to true the first time a style is used, but it /// will not be set to false if the style is no longer used, because /// checking for that condition is too expensive. + /// + /// Why have this weird false positive flag at all? This makes VT operations + /// that erase cells (such as insert lines, delete lines, erase chars, + /// etc.) MUCH MUCH faster in the case that the row was never styled. + /// At the time of writing this, the speed difference is around 4x. styled: bool = false, _padding: u28 = 0,