summaryrefslogtreecommitdiff
path: root/src/edit.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-28 15:33:48 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:15 -0300
commit122281b0ea3473f8950910765c487ef3fc82e7d4 (patch)
tree577eee8e03338446a2f600a74c775dc5af97f50b /src/edit.zig
parent4315121885bebd48f8c03a2b1c7b0bd943c67afd (diff)
downloadpardes-122281b0ea3473f8950910765c487ef3fc82e7d4.tar.gz
pardes-122281b0ea3473f8950910765c487ef3fc82e7d4.zip
Alt-( and Alt-) rotate the text of the selections
helix-golf swaps keys and values with rotate_selection_contents (webS_to_ <ret><A-(>, then per line). Each range's text moves to the next range (the previous one for Alt-(), in one edit; a count rotates by that many ranges, each range comes back over the text it now holds in its own direction, and the primary follows its text. That is the harness's helix; 25.07.1 read the count as a group size and left the primary alone. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/edit.zig')
-rw-r--r--src/edit.zig51
1 files changed, 51 insertions, 0 deletions
diff --git a/src/edit.zig b/src/edit.zig
index 09c3ffe7..2dc79ab5 100644
--- a/src/edit.zig
+++ b/src/edit.zig
@@ -1292,6 +1292,57 @@ pub fn normalJoin(p: *Pardes, t: *Text, select_space: bool) void {
t.setRanges(t2, rs[0..n], &.{}, pri, expl);
}
+/// `Alt-)` / `Alt-(`: rotate the TEXT of the selections forward / back by
+/// one range (count ranges), in one edit (helix reorder_selection_contents).
+/// Each range comes back over the text it now holds, in its own direction,
+/// and the primary moves with the text it had.
+pub fn normalRotateContents(p: *Pardes, t: *Text, forward: bool, cnt: usize) void {
+ const expl = (t.vsel.active and t.vsel.explicit) or t.msel.active;
+ var b = selRows(t);
+ for (t.sels[0..t.nsel]) |s| {
+ b.lo_row = @min(b.lo_row, @min(s.row, s.arow));
+ b.hi_row = @max(b.hi_row, @max(s.row, s.arow));
+ }
+ const eb = editTextEol(p, t, b) orelse return;
+ const text = eb.text;
+ var rs: [Text.max_selections]modal.Selection = undefined;
+ const got = t.ranges(text, eb.row0, &rs);
+ const n = got.n;
+ if (n < 2) return;
+ const by = @min(cnt, n);
+ var chs: [Text.max_selections]TextChange = undefined;
+ for (rs[0..n], 0..) |r, i| {
+ const src = rs[if (forward) (i + n - by) % n else (i + by) % n];
+ chs[i] = .{
+ .from = @min(r.anchor, r.head),
+ .to = @max(r.anchor, r.head),
+ .ins = text[@min(src.anchor, src.head)..@max(src.anchor, src.head)],
+ };
+ }
+ pushUndo(p, t);
+ const new = applyChanges(p, text, chs[0..n]) catch return;
+ var cells: [Text.max_selections]Text.SelRange = undefined;
+ var delta: i64 = 0;
+ for (chs[0..n], rs[0..n], 0..) |ch, r, i| {
+ const from: usize = @intCast(@as(i64, @intCast(ch.from)) + delta);
+ delta += @as(i64, @intCast(ch.ins.len)) - @as(i64, @intCast(ch.to - ch.from));
+ const to = from + ch.ins.len;
+ const c = Text.rangeCells(new, if (r.anchor > r.head) .{ .anchor = to, .head = from } else .{ .anchor = from, .head = to });
+ const cc = modal.positionAt(new, c.cur);
+ const ac = modal.positionAt(new, c.anc);
+ cells[i] = .{
+ .row = @as(i32, @intCast(cc.row)) + eb.row0,
+ .col = @intCast(cc.col),
+ .arow = @as(i32, @intCast(ac.row)) + eb.row0,
+ .acol = @intCast(ac.col),
+ };
+ }
+ setEditText(p, t, new);
+ const t2 = flatSurface(p, t) catch return;
+ for (cells[0..n], 0..) |s, i| rs[i] = Text.cellRange(t2, s.arow, s.acol, s.row, s.col);
+ t.setRanges(t2, rs[0..n], &.{}, if (forward) (got.pri + by) % n else (got.pri + n - by) % n, expl);
+}
+
pub fn normalIndent(p: *Pardes, t: *Text, cnt: usize, add: bool) void {
t.select = false;
const sr = selRows(t);