a73x

499daca1

Remove spacer boundary normalization

a73x   2026-04-09 18:14


diff --git a/src/main.zig b/src/main.zig
index c058953..dd823a7 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -583,40 +583,13 @@ fn appendSelectedRowText(
    span: SelectionSpan,
    row_idx: usize,
) !void {
    const bounds = canonicalizeSelectedRowBounds(row_cells, span, row_idx) orelse return;
    if (row_cells.len == 0) return;

    var end_col = bounds.end_col;
    while (end_col >= bounds.start_col) {
        const cell = row_cells.get(end_col);
        if (!isTrailingBlankCell(cell)) break;
        if (end_col == 0) return;
        end_col -= 1;
    }

    var col = bounds.start_col;
    while (col <= end_col) : (col += 1) {
        const cell = row_cells.get(col);
        try appendSelectedCellText(alloc, out, cell);
    }
}

const SelectedRowBounds = struct {
    start_col: usize,
    end_col: usize,
};

fn canonicalizeSelectedRowBounds(
    row_cells: anytype,
    span: SelectionSpan,
    row_idx: usize,
) ?SelectedRowBounds {
    if (row_cells.len == 0) return null;

    var start_col: usize = if (row_idx == span.start.row)
    const start_col: usize = if (row_idx == span.start.row)
        @intCast(span.start.col)
    else
        0;
    if (start_col >= row_cells.len) return null;
    if (start_col >= row_cells.len) return;

    var end_col: usize = if (row_idx == span.end.row)
        @intCast(span.end.col)
@@ -624,26 +597,18 @@ fn canonicalizeSelectedRowBounds(
        row_cells.len - 1;
    if (end_col >= row_cells.len) end_col = row_cells.len - 1;

    start_col = canonicalizeSpacerBoundary(row_cells, start_col) orelse return null;
    end_col = canonicalizeSpacerBoundary(row_cells, end_col) orelse return null;
    if (end_col < start_col) return null;

    return .{
        .start_col = start_col,
        .end_col = end_col,
    };
}

fn canonicalizeSpacerBoundary(row_cells: anytype, col: usize) ?usize {
    if (col >= row_cells.len) return null;

    const cell = row_cells.get(col);
    if (cell.raw.wide == .spacer_tail or cell.raw.wide == .spacer_head) {
        if (col == 0) return null;
        return col - 1;
    while (end_col >= start_col) {
        const cell = row_cells.get(end_col);
        if (!isTrailingBlankCell(cell)) break;
        if (end_col == 0) return;
        end_col -= 1;
    }

    return col;
    var col = start_col;
    while (col <= end_col) : (col += 1) {
        const cell = row_cells.get(col);
        try appendSelectedCellText(alloc, out, cell);
    }
}

fn isTrailingBlankCell(cell: anytype) bool {
@@ -2490,7 +2455,7 @@ test "extractSelectedText preserves interior spaces while trimming trailing blan
    try std.testing.expectEqualStrings("a b  c  ", text);
}

test "extractSelectedText copies a wide glyph when selection lands on its spacer cell" {
test "extractSelectedText emits a wide glyph once when its spacer cell is selected too" {
    var term = try vt.Terminal.init(std.testing.allocator, .{
        .cols = 4,
        .rows = 1,
@@ -2505,7 +2470,7 @@ test "extractSelectedText copies a wide glyph when selection lands on its spacer
    try std.testing.expectEqual(.spacer_tail, row_cells.get(1).raw.wide);

    const span = SelectionSpan{
        .start = .{ .col = 1, .row = 0 },
        .start = .{ .col = 0, .row = 0 },
        .end = .{ .col = 1, .row = 0 },
    };
    const text = try extractSelectedText(std.testing.allocator, term.render_state.row_data.items(.cells), span);