be9bf5ac
Fix selection clamping semantics
a73x 2026-04-09 17:44
diff --git a/src/main.zig b/src/main.zig index 00c054e..9514ac6 100644 --- a/src/main.zig +++ b/src/main.zig @@ -562,6 +562,8 @@ const SelectionSpan = struct { } fn containsCell(self: SelectionSpan, col: u32, row: u32) bool { if (self.isEmpty()) return false; const span = self.normalized(); if (row < span.start.row or row > span.end.row) return false; if (span.start.row == span.end.row) { @@ -573,8 +575,20 @@ const SelectionSpan = struct { } }; fn selectionIntersectsVisibleGrid(span: SelectionSpan, cols: u16, rows: u16) bool { if (cols == 0 or rows == 0) return false; const normalized = span.normalized(); const max_col = @as(u32, cols) - 1; const max_row = @as(u32, rows) - 1; if (normalized.start.row > max_row) return false; if (normalized.start.row == normalized.end.row and normalized.start.col > max_col) return false; return true; } fn clampSelectionSpan(span: SelectionSpan, cols: u16, rows: u16) ?SelectionSpan { if (cols == 0 or rows == 0) return null; if (!selectionIntersectsVisibleGrid(span, cols, rows)) return null; const max_col = @as(u32, cols) - 1; const max_row = @as(u32, rows) - 1; @@ -619,21 +633,36 @@ test "SelectionSpan.containsCell includes the normalized endpoints" { try std.testing.expect(!span.containsCell(4, 2)); } test "clampSelectionSpan clears single-cell clicks and trims resized spans" { try std.testing.expect(clampSelectionSpan(.{ test "SelectionSpan.containsCell treats a degenerate span as empty" { const span = SelectionSpan{ .start = .{ .col = 5, .row = 5 }, .end = .{ .col = 5, .row = 5 }, }; try std.testing.expect(span.isEmpty()); try std.testing.expect(!span.containsCell(5, 5)); } test "clampSelectionSpan clears offscreen spans and trims resized spans" { try std.testing.expect(clampSelectionSpan(.{ .start = .{ .col = 5, .row = 30 }, .end = .{ .col = 10, .row = 40 }, }, 80, 24) == null); const clamped = clampSelectionSpan(.{ .start = .{ .col = 78, .row = 30 }, .end = .{ .col = 99, .row = 40 }, .start = .{ .col = 78, .row = 22 }, .end = .{ .col = 99, .row = 30 }, }, 80, 24).?; try std.testing.expectEqual(@as(u32, 78), clamped.start.col); try std.testing.expectEqual(@as(u32, 23), clamped.start.row); try std.testing.expectEqual(@as(u32, 22), clamped.start.row); try std.testing.expectEqual(@as(u32, 79), clamped.end.col); try std.testing.expectEqual(@as(u32, 23), clamped.end.row); try std.testing.expect(clampSelectionSpan(.{ .start = .{ .col = 81, .row = 5 }, .end = .{ .col = 90, .row = 5 }, }, 80, 24) == null); } const ComparisonVariant = struct {