499daca1
Remove spacer boundary normalization
a73x 2026-04-09 18:14
Commit message
src/main.zig
| Old | New | ||
|---|---|---|---|
| @@ -583,40 +583,13 @@ fn appendSelectedRowText( | |||
| 583 | span: SelectionSpan, | 583 | span: SelectionSpan, |
| 584 | row_idx: usize, | 584 | row_idx: usize, |
| 585 | ) !void { | 585 | ) !void { |
| 586 | const bounds = canonicalizeSelectedRowBounds(row_cells, span, row_idx) orelse return; | 586 | if (row_cells.len == 0) return; |
| 587 | 587 | ||
| 588 | var end_col = bounds.end_col; | 588 | const start_col: usize = if (row_idx == span.start.row) |
| 589 | while (end_col >= bounds.start_col) { | ||
| 590 | const cell = row_cells.get(end_col); | ||
| 591 | if (!isTrailingBlankCell(cell)) break; | ||
| 592 | if (end_col == 0) return; | ||
| 593 | end_col -= 1; | ||
| 594 | } | ||
| 595 | |||
| 596 | var col = bounds.start_col; | ||
| 597 | while (col <= end_col) : (col += 1) { | ||
| 598 | const cell = row_cells.get(col); | ||
| 599 | try appendSelectedCellText(alloc, out, cell); | ||
| 600 | } | ||
| 601 | } | ||
| 602 | |||
| 603 | const SelectedRowBounds = struct { | ||
| 604 | start_col: usize, | ||
| 605 | end_col: usize, | ||
| 606 | }; | ||
| 607 | |||
| 608 | fn canonicalizeSelectedRowBounds( | ||
| 609 | row_cells: anytype, | ||
| 610 | span: SelectionSpan, | ||
| 611 | row_idx: usize, | ||
| 612 | ) ?SelectedRowBounds { | ||
| 613 | if (row_cells.len == 0) return null; | ||
| 614 | |||
| 615 | var start_col: usize = if (row_idx == span.start.row) | ||
| 616 | @intCast(span.start.col) | 589 | @intCast(span.start.col) |
| 617 | else | 590 | else |
| 618 | 0; | 591 | 0; |
| 619 | if (start_col >= row_cells.len) return null; | 592 | if (start_col >= row_cells.len) return; |
| 620 | 593 | ||
| 621 | var end_col: usize = if (row_idx == span.end.row) | 594 | var end_col: usize = if (row_idx == span.end.row) |
| 622 | @intCast(span.end.col) | 595 | @intCast(span.end.col) |
| @@ -624,26 +597,18 @@ fn canonicalizeSelectedRowBounds( | |||
| 624 | row_cells.len - 1; | 597 | row_cells.len - 1; |
| 625 | if (end_col >= row_cells.len) end_col = row_cells.len - 1; | 598 | if (end_col >= row_cells.len) end_col = row_cells.len - 1; |
| 626 | 599 | ||
| 627 | start_col = canonicalizeSpacerBoundary(row_cells, start_col) orelse return null; | 600 | while (end_col >= start_col) { |
| 628 | end_col = canonicalizeSpacerBoundary(row_cells, end_col) orelse return null; | 601 | const cell = row_cells.get(end_col); |
| 629 | if (end_col < start_col) return null; | 602 | if (!isTrailingBlankCell(cell)) break; |
| 630 | 603 | if (end_col == 0) return; | |
| 631 | return .{ | 604 | end_col -= 1; |
| 632 | .start_col = start_col, | ||
| 633 | .end_col = end_col, | ||
| 634 | }; | ||
| 635 | } | ||
| 636 | |||
| 637 | fn canonicalizeSpacerBoundary(row_cells: anytype, col: usize) ?usize { | ||
| 638 | if (col >= row_cells.len) return null; | ||
| 639 | |||
| 640 | const cell = row_cells.get(col); | ||
| 641 | if (cell.raw.wide == .spacer_tail or cell.raw.wide == .spacer_head) { | ||
| 642 | if (col == 0) return null; | ||
| 643 | return col - 1; | ||
| 644 | } | 605 | } |
| 645 | 606 | ||
| 646 | return col; | 607 | var col = start_col; |
| 608 | while (col <= end_col) : (col += 1) { | ||
| 609 | const cell = row_cells.get(col); | ||
| 610 | try appendSelectedCellText(alloc, out, cell); | ||
| 611 | } | ||
| 647 | } | 612 | } |
| 648 | 613 | ||
| 649 | fn isTrailingBlankCell(cell: anytype) bool { | 614 | fn isTrailingBlankCell(cell: anytype) bool { |
| @@ -2490,7 +2455,7 @@ test "extractSelectedText preserves interior spaces while trimming trailing blan | |||
| 2490 | try std.testing.expectEqualStrings("a b c ", text); | 2455 | try std.testing.expectEqualStrings("a b c ", text); |
| 2491 | } | 2456 | } |
| 2492 | 2457 | ||
| 2493 | test "extractSelectedText copies a wide glyph when selection lands on its spacer cell" { | 2458 | test "extractSelectedText emits a wide glyph once when its spacer cell is selected too" { |
| 2494 | var term = try vt.Terminal.init(std.testing.allocator, .{ | 2459 | var term = try vt.Terminal.init(std.testing.allocator, .{ |
| 2495 | .cols = 4, | 2460 | .cols = 4, |
| 2496 | .rows = 1, | 2461 | .rows = 1, |
| @@ -2505,7 +2470,7 @@ test "extractSelectedText copies a wide glyph when selection lands on its spacer | |||
| 2505 | try std.testing.expectEqual(.spacer_tail, row_cells.get(1).raw.wide); | 2470 | try std.testing.expectEqual(.spacer_tail, row_cells.get(1).raw.wide); |
| 2506 | 2471 | ||
| 2507 | const span = SelectionSpan{ | 2472 | const span = SelectionSpan{ |
| 2508 | .start = .{ .col = 1, .row = 0 }, | 2473 | .start = .{ .col = 0, .row = 0 }, |
| 2509 | .end = .{ .col = 1, .row = 0 }, | 2474 | .end = .{ .col = 1, .row = 0 }, |
| 2510 | }; | 2475 | }; |
| 2511 | const text = try extractSelectedText(std.testing.allocator, term.render_state.row_data.items(.cells), span); | 2476 | const text = try extractSelectedText(std.testing.allocator, term.render_state.row_data.items(.cells), span); |