From 645b4b0031a2e704628e1eed86a5fb20377a2404 Mon Sep 17 00:00:00 2001 From: Daniel Patterson Date: Sat, 25 Jan 2025 23:22:40 +0000 Subject: [PATCH 1/2] Fix cmd+triple click not selecting full output --- src/terminal/Screen.zig | 61 +++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig index eb70d32d07..af3d133921 100644 --- a/src/terminal/Screen.zig +++ b/src/terminal/Screen.zig @@ -2591,13 +2591,24 @@ pub fn selectOutput(self: *Screen, pin: Pin) ?Selection { const start: Pin = boundary: { var it = pin.rowIterator(.left_up, null); var it_prev = pin; + + // First, iterate until we find the first line of command output while (it.next()) |p| { + it_prev = p; const row = p.rowAndCell().row; - switch (row.semantic_prompt) { - .command => break :boundary p, - else => {}, + if (row.semantic_prompt == .command) { + break; } + } + // Because the first line of command output may span multiple visual rows we must now + // iterate until we find the first row of anything other than command output and then + // yield the previous row. + while (it.next()) |p| { + const row = p.rowAndCell().row; + if (row.semantic_prompt != .command) { + break :boundary it_prev; + } it_prev = p; } @@ -7641,17 +7652,17 @@ test "Screen: selectOutput" { // zig fmt: off { - // line number: - try s.testWriteString("output1\n"); // 0 - try s.testWriteString("output1\n"); // 1 - try s.testWriteString("prompt2\n"); // 2 - try s.testWriteString("input2\n"); // 3 - try s.testWriteString("output2\n"); // 4 - try s.testWriteString("output2\n"); // 5 - try s.testWriteString("prompt3$ input3\n"); // 6 - try s.testWriteString("output3\n"); // 7 - try s.testWriteString("output3\n"); // 8 - try s.testWriteString("output3"); // 9 + // line number: + try s.testWriteString("output1\n"); // 0 + try s.testWriteString("output1\n"); // 1 + try s.testWriteString("prompt2\n"); // 2 + try s.testWriteString("input2\n"); // 3 + try s.testWriteString("output2output2output2output2\n"); // 4, 5, 6 due to overflow + try s.testWriteString("output2\n"); // 7 + try s.testWriteString("prompt3$ input3\n"); // 8 + try s.testWriteString("output3\n"); // 9 + try s.testWriteString("output3\n"); // 10 + try s.testWriteString("output3"); // 11 } // zig fmt: on @@ -7670,13 +7681,23 @@ test "Screen: selectOutput" { const row = pin.rowAndCell().row; row.semantic_prompt = .command; } + { + const pin = s.pages.pin(.{ .screen = .{ .y = 5 } }).?; + const row = pin.rowAndCell().row; + row.semantic_prompt = .command; + } { const pin = s.pages.pin(.{ .screen = .{ .y = 6 } }).?; const row = pin.rowAndCell().row; + row.semantic_prompt = .command; + } + { + const pin = s.pages.pin(.{ .screen = .{ .y = 8 } }).?; + const row = pin.rowAndCell().row; row.semantic_prompt = .input; } { - const pin = s.pages.pin(.{ .screen = .{ .y = 7 } }).?; + const pin = s.pages.pin(.{ .screen = .{ .y = 9 } }).?; const row = pin.rowAndCell().row; row.semantic_prompt = .command; } @@ -7701,7 +7722,7 @@ test "Screen: selectOutput" { { var sel = s.selectOutput(s.pages.pin(.{ .active = .{ .x = 3, - .y = 5, + .y = 7, } }).?).?; defer sel.deinit(&s); try testing.expectEqual(point.Point{ .active = .{ @@ -7710,23 +7731,23 @@ test "Screen: selectOutput" { } }, s.pages.pointFromPin(.active, sel.start()).?); try testing.expectEqual(point.Point{ .active = .{ .x = 9, - .y = 5, + .y = 7, } }, s.pages.pointFromPin(.active, sel.end()).?); } // No end marker, should select till the end { var sel = s.selectOutput(s.pages.pin(.{ .active = .{ .x = 2, - .y = 7, + .y = 10, } }).?).?; defer sel.deinit(&s); try testing.expectEqual(point.Point{ .active = .{ .x = 0, - .y = 7, + .y = 9, } }, s.pages.pointFromPin(.active, sel.start()).?); try testing.expectEqual(point.Point{ .active = .{ .x = 9, - .y = 10, + .y = 12, } }, s.pages.pointFromPin(.active, sel.end()).?); } // input / prompt at y = 0, pt.y = 0 From 4b8010a6f4a0a4b56cb1609b6ecc47ff688d70f1 Mon Sep 17 00:00:00 2001 From: Daniel Patterson Date: Sun, 26 Jan 2025 15:22:01 +0000 Subject: [PATCH 2/2] Change ifs to exhaustive switches --- src/terminal/Screen.zig | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig index af3d133921..fe2eab5ac3 100644 --- a/src/terminal/Screen.zig +++ b/src/terminal/Screen.zig @@ -2596,6 +2596,15 @@ pub fn selectOutput(self: *Screen, pin: Pin) ?Selection { while (it.next()) |p| { it_prev = p; const row = p.rowAndCell().row; + switch (row.semantic_prompt) { + .command => break, + + .unknown, + .prompt, + .prompt_continuation, + .input, + => {}, + } if (row.semantic_prompt == .command) { break; } @@ -2606,8 +2615,14 @@ pub fn selectOutput(self: *Screen, pin: Pin) ?Selection { // yield the previous row. while (it.next()) |p| { const row = p.rowAndCell().row; - if (row.semantic_prompt != .command) { - break :boundary it_prev; + switch (row.semantic_prompt) { + .command => {}, + + .unknown, + .prompt, + .prompt_continuation, + .input, + => break :boundary it_prev, } it_prev = p; }