diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-28 16:57:01 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:15 -0300 |
| commit | 68e30f560e46bb9a30433eb23b4edb1b93d69f46 (patch) | |
| tree | 3f5f3085051488635ec61c02e33062e1eb94bdd7 /src/normal.zig | |
| parent | cd563b1768c688444cc6d172b3679d95b495207c (diff) | |
| download | pardes-68e30f560e46bb9a30433eb23b4edb1b93d69f46.tar.gz pardes-68e30f560e46bb9a30433eb23b4edb1b93d69f46.zip | |
A selection's other ranges live out of line, made at the second range and freed at one
The ranges beside the primary were an inline array in every Text, which at
1024 grew each pane by about 60 KiB. They are now allocated when a second
range appears (Text.reserveSels) and given back when the selection is one
range again (Text.dropSels); a column's or the workspace's tag allocates from
Text.gpa, any other text from its pane's. A refused tag edit restores them by
copy. The Pane size budget is back to 128 KiB, and a test holds that a single
cursor allocates nothing for them.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/normal.zig')
| -rw-r--r-- | src/normal.zig | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/src/normal.zig b/src/normal.zig index 4459ab53..2aea2e54 100644 --- a/src/normal.zig +++ b/src/normal.zig @@ -686,10 +686,7 @@ fn executeNormalAction(p: *Pardes, t: *Text, semantic: modal.Normal.Action) void .all => return t.setRange(text, 0, .{ .anchor = 0, .head = text.len }, false), }, .multi => |multi| { - if (multi.kind == .keep_primary) { - t.nsel = 0; - return; - } + if (multi.kind == .keep_primary) return t.dropSels(); return t.multiSelAction(text, multi.kind, multi.count); }, // s, S and | answer for the text they are pressed in; `/` searches @@ -922,6 +919,7 @@ test "flat text movement and selection replay need no scratch rows" { pane.body.cur_row = 1024; pane.body.cur_col = 0; pane.body.nsel = 1; + _ = pane.body.reserveSels(); pane.body.sels[0] = .{ .row = 3072, .col = 0, .arow = 3072, .acol = 0 }; handleNormal(p, &pane.body, .{ .cp = 'l' }); handleNormal(p, &pane.body, .{ .cp = 'j' }); @@ -1021,3 +1019,25 @@ test "tree-sitter selection keys do in a JSON file what hx 25.07.1 does" { }; } } + +test "one cursor holds no room for other ranges; a second range makes it and one again gives it back" { + const gpa = std.testing.allocator; + const p = try Pardes.init(gpa, .{ .tty_only = true, .cols = 60, .rows = 12 }); + defer p.deinit(); + const pane = try p.setTestFile("alpha beta\nalpha beta\n"); + for ("wxe%;gg") |cp| handleNormal(p, &pane.body, .{ .cp = cp }); + try std.testing.expectEqual(@as(usize, 0), pane.body.sels.len); + handleNormal(p, &pane.body, .{ .cp = 'C' }); + try std.testing.expectEqual(@as(u16, 1), pane.body.nsel); + try std.testing.expect(pane.body.sels.len > 0); + handleNormal(p, &pane.body, .{ .cp = 'l' }); // replayed at both, still two + try std.testing.expectEqual(@as(u16, 1), pane.body.nsel); + handleNormal(p, &pane.body, .{ .cp = ',' }); + try std.testing.expectEqual(@as(usize, 0), pane.body.sels.len); + handleNormal(p, &pane.body, .{ .cp = 'C' }); + handleNormal(p, &pane.body, .{ .cp = ';' }); + handleNormal(p, &pane.body, .{ .cp = 'x' }); // x at both: still two lines + handleNormal(p, &pane.body, .{ .cp = '_', .alt = true }); // merged to one + try std.testing.expectEqual(@as(u16, 0), pane.body.nsel); + try std.testing.expectEqual(@as(usize, 0), pane.body.sels.len); +} |
