87544d89
Fix visible selection text extraction
a73x 2026-04-09 18:04
diff --git a/src/main.zig b/src/main.zig index c5ac0cf..b25ee96 100644 --- a/src/main.zig +++ b/src/main.zig @@ -554,11 +554,19 @@ fn extractSelectedText( span: SelectionSpan, ) ![]u8 { const normalized = span.normalized(); if (row_data.len == 0) return try alloc.alloc(u8, 0); const max_row = row_data.len - 1; if (normalized.start.row > max_row) return try alloc.alloc(u8, 0); const visible_end_row = @min(normalized.end.row, max_row); if (normalized.start.row > visible_end_row) return try alloc.alloc(u8, 0); var out: std.ArrayListUnmanaged(u8) = .empty; errdefer out.deinit(alloc); const start_row: usize = @intCast(normalized.start.row); const end_row: usize = @intCast(normalized.end.row); const end_row: usize = @intCast(visible_end_row); var row_idx = start_row; while (row_idx <= end_row) : (row_idx += 1) { if (row_idx > start_row) try out.append(alloc, '\n'); @@ -592,7 +600,7 @@ fn appendSelectedRowText( while (end_col >= start_col) { const cell = cells[end_col]; if (cellContributesVisibleText(cell)) break; if (!isTrailingBlankCell(cell)) break; if (end_col == 0) return; end_col -= 1; } @@ -600,20 +608,26 @@ fn appendSelectedRowText( var col = start_col; while (col <= end_col) : (col += 1) { const cell = cells[col]; if (!cellContributesVisibleText(cell)) continue; try appendCellText(alloc, out, cell); try appendSelectedCellText(alloc, out, cell); } } fn cellContributesVisibleText(cell: anytype) bool { return cell.hasText() and cell.wide != .spacer_tail and cell.wide != .spacer_head; fn isTrailingBlankCell(cell: anytype) bool { return !cell.hasText() and cell.wide != .spacer_tail and cell.wide != .spacer_head; } fn appendCellText( fn appendSelectedCellText( alloc: std.mem.Allocator, out: *std.ArrayListUnmanaged(u8), cell: anytype, ) !void { if (cell.wide == .spacer_tail or cell.wide == .spacer_head) return; if (!cell.hasText()) { try out.append(alloc, ' '); return; } const cp = cell.codepoint(); if (cp == 0) return; @@ -2410,6 +2424,26 @@ test "extractSelectedText trims trailing blanks on each visible row" { try std.testing.expectEqualStrings("ab\nc", text); } test "extractSelectedText preserves interior spaces while trimming trailing blanks" { var term = try vt.Terminal.init(std.testing.allocator, .{ .cols = 10, .rows = 1, }); defer term.deinit(); term.write("a b c "); try term.snapshot(); const span = SelectionSpan{ .start = .{ .col = 0, .row = 0 }, .end = .{ .col = 9, .row = 0 }, }; const text = try extractSelectedText(std.testing.allocator, term.render_state.row_data.items(.cells), span); defer std.testing.allocator.free(text); try std.testing.expectEqualStrings("a b c ", text); } test "extractSelectedText respects partial first and last rows" { var term = try vt.Terminal.init(std.testing.allocator, .{ .cols = 8, @@ -2430,6 +2464,26 @@ test "extractSelectedText respects partial first and last rows" { try std.testing.expectEqualStrings("bc\nde", text); } test "extractSelectedText clamps an offscreen end row to visible rows" { var term = try vt.Terminal.init(std.testing.allocator, .{ .cols = 8, .rows = 2, }); defer term.deinit(); term.write("row0\r\nrow1"); try term.snapshot(); const span = SelectionSpan{ .start = .{ .col = 0, .row = 0 }, .end = .{ .col = 7, .row = 9 }, }; const text = try extractSelectedText(std.testing.allocator, term.render_state.row_data.items(.cells), span); defer std.testing.allocator.free(text); try std.testing.expectEqualStrings("row0\nrow1", text); } test "drainSelectionPipeThenRoundtrip drains large paste before roundtrip" { const payload_len: usize = 8192; const payload = try std.testing.allocator.alloc(u8, payload_len);