From f91624ab6102e8af118d4260a40d28fea551e464 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 6 Mar 2024 13:54:03 -0800 Subject: [PATCH] terminal2: selectAll --- src/terminal/Screen.zig | 4 ++ src/terminal2/Screen.zig | 126 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 128 insertions(+), 2 deletions(-) diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig index 8bad89ba9..b13b5b249 100644 --- a/src/terminal/Screen.zig +++ b/src/terminal/Screen.zig @@ -4475,6 +4475,7 @@ test "Screen: clone one line active with extra space" { try testing.expectEqual(@as(usize, 1), s.rowsWritten()); } +// X test "Screen: selectLine" { const testing = std.testing; const alloc = testing.allocator; @@ -4523,6 +4524,8 @@ test "Screen: selectLine" { try testing.expectEqual(@as(usize, 0), sel.end.y); } } + +// X test "Screen: selectAll" { const testing = std.testing; const alloc = testing.allocator; @@ -4549,6 +4552,7 @@ test "Screen: selectAll" { } } +// X test "Screen: selectLine across soft-wrap" { const testing = std.testing; const alloc = testing.allocator; diff --git a/src/terminal2/Screen.zig b/src/terminal2/Screen.zig index baeed55be..af8bec5fc 100644 --- a/src/terminal2/Screen.zig +++ b/src/terminal2/Screen.zig @@ -866,7 +866,9 @@ pub fn selectLine(self: *Screen, pin: Pin) ?Selection { // The real start of the row is the first row in the soft-wrap. const start_pin: Pin = start_pin: { var it = pin.rowIterator(.left_up, null); + var it_prev: Pin = pin; while (it.next()) |p| { + it_prev = p; const row = p.rowAndCell().row; if (!row.wrap) { @@ -882,9 +884,11 @@ pub fn selectLine(self: *Screen, pin: Pin) ?Selection { prev.x = 0; break :start_pin prev; } + } else { + var copy = it_prev; + copy.x = 0; + break :start_pin copy; } - - return null; }; // The real end of the row is the final row in the soft-wrap. @@ -956,6 +960,62 @@ pub fn selectLine(self: *Screen, pin: Pin) ?Selection { return Selection.init(start, end, false); } +/// Return the selection for all contents on the screen. Surrounding +/// whitespace is omitted. If there is no selection, this returns null. +pub fn selectAll(self: *Screen) ?Selection { + const whitespace = &[_]u32{ 0, ' ', '\t' }; + + const start: Pin = start: { + var it = self.pages.cellIterator( + .right_down, + .{ .screen = .{} }, + null, + ); + while (it.next()) |p| { + const cell = p.rowAndCell().cell; + if (!cell.hasText()) continue; + + // Non-empty means we found it. + const this_whitespace = std.mem.indexOfAny( + u32, + whitespace, + &[_]u32{cell.content.codepoint}, + ) != null; + if (this_whitespace) continue; + + break :start p; + } + + return null; + }; + + const end: Pin = end: { + var it = self.pages.cellIterator( + .left_up, + .{ .screen = .{} }, + null, + ); + while (it.next()) |p| { + const cell = p.rowAndCell().cell; + if (!cell.hasText()) continue; + + // Non-empty means we found it. + const this_whitespace = std.mem.indexOfAny( + u32, + whitespace, + &[_]u32{cell.content.codepoint}, + ) != null; + if (this_whitespace) continue; + + break :end p; + } + + return null; + }; + + return Selection.init(start, end, false); +} + /// Dump the screen to a string. The writer given should be buffered; /// this function does not attempt to efficiently write and generally writes /// one byte at a time. @@ -3642,3 +3702,65 @@ test "Screen: selectLine" { } }, s.pages.pointFromPin(.screen, sel.end().*).?); } } + +test "Screen: selectLine across soft-wrap" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 5, 10, 0); + defer s.deinit(); + try s.testWriteString(" 12 34012 \n 123"); + + // Going forward + { + var sel = s.selectLine(s.pages.pin(.{ .active = .{ + .x = 1, + .y = 0, + } }).?).?; + defer sel.deinit(&s); + try testing.expectEqual(point.Point{ .screen = .{ + .x = 1, + .y = 0, + } }, s.pages.pointFromPin(.screen, sel.start().*).?); + try testing.expectEqual(point.Point{ .screen = .{ + .x = 3, + .y = 1, + } }, s.pages.pointFromPin(.screen, sel.end().*).?); + } +} + +test "Screen: selectAll" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 10, 10, 0); + defer s.deinit(); + + { + try s.testWriteString("ABC DEF\n 123\n456"); + var sel = s.selectAll().?; + defer sel.deinit(&s); + try testing.expectEqual(point.Point{ .screen = .{ + .x = 0, + .y = 0, + } }, s.pages.pointFromPin(.screen, sel.start().*).?); + try testing.expectEqual(point.Point{ .screen = .{ + .x = 2, + .y = 2, + } }, s.pages.pointFromPin(.screen, sel.end().*).?); + } + + { + try s.testWriteString("\nFOO\n BAR\n BAZ\n QWERTY\n 12345678"); + var sel = s.selectAll().?; + defer sel.deinit(&s); + try testing.expectEqual(point.Point{ .screen = .{ + .x = 0, + .y = 0, + } }, s.pages.pointFromPin(.screen, sel.start().*).?); + try testing.expectEqual(point.Point{ .screen = .{ + .x = 8, + .y = 7, + } }, s.pages.pointFromPin(.screen, sel.end().*).?); + } +}