summaryrefslogtreecommitdiff
path: root/src
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
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')
-rw-r--r--src/config.zig2
-rw-r--r--src/edit.zig51
-rw-r--r--src/modal.zig15
-rw-r--r--src/normal.zig2
4 files changed, 69 insertions, 1 deletions
diff --git a/src/config.zig b/src/config.zig
index 372c4884..edc73837 100644
--- a/src/config.zig
+++ b/src/config.zig
@@ -539,6 +539,8 @@ pub const to_lowercase: []const Chord = &.{.{ .cp = '`' }};
pub const to_uppercase: []const Chord = &.{.{ .cp = '`', .alt = true }};
pub const join_lines: []const Chord = &.{.{ .cp = 'J' }};
pub const join_select_space: []const Chord = &.{.{ .cp = 'J', .alt = true }};
+pub const rotate_contents_fwd: []const Chord = &.{.{ .cp = ')', .alt = true }};
+pub const rotate_contents_back: []const Chord = &.{.{ .cp = '(', .alt = true }};
pub const indent: []const Chord = &.{.{ .cp = '>' }};
pub const unindent: []const Chord = &.{.{ .cp = '<' }};
pub const format: []const Chord = &.{.{ .cp = '=' }};
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);
diff --git a/src/modal.zig b/src/modal.zig
index 0e6aba61..6bf7918f 100644
--- a/src/modal.zig
+++ b/src/modal.zig
@@ -109,6 +109,8 @@ pub const Normal = struct {
to_uppercase,
join_lines,
join_select_space,
+ rotate_contents_fwd,
+ rotate_contents_back,
indent,
unindent,
format,
@@ -262,6 +264,8 @@ pub const Normal = struct {
uppercase,
join_lines,
join_select_space,
+ rotate_contents_forward,
+ rotate_contents_backward,
indent,
unindent,
comment_toggle,
@@ -319,7 +323,14 @@ pub const Normal = struct {
.search_step,
=> .once,
.edit => |edit| switch (edit.kind) {
- .join_lines, .join_select_space, .comment_toggle, .undo, .redo => .once,
+ .join_lines,
+ .join_select_space,
+ .rotate_contents_forward,
+ .rotate_contents_backward,
+ .comment_toggle,
+ .undo,
+ .redo,
+ => .once,
else => .per_selection,
},
else => .per_selection,
@@ -552,6 +563,8 @@ pub const Normal = struct {
if (key.has(.to_uppercase)) return resultAction(.{ .edit = .{ .kind = .uppercase, .count = count } });
if (key.has(.join_lines)) return resultAction(.{ .edit = .{ .kind = .join_lines, .count = count } });
if (key.has(.join_select_space)) return resultAction(.{ .edit = .{ .kind = .join_select_space, .count = count } });
+ if (key.has(.rotate_contents_fwd)) return resultAction(.{ .edit = .{ .kind = .rotate_contents_forward, .count = count } });
+ if (key.has(.rotate_contents_back)) return resultAction(.{ .edit = .{ .kind = .rotate_contents_backward, .count = count } });
if (key.has(.indent)) return resultAction(.{ .edit = .{ .kind = .indent, .count = count } });
if (key.has(.unindent)) return resultAction(.{ .edit = .{ .kind = .unindent, .count = count } });
if (key.has(.format)) return resultAction(.{ .lsp = .format });
diff --git a/src/normal.zig b/src/normal.zig
index c976823c..9c6f2acd 100644
--- a/src/normal.zig
+++ b/src/normal.zig
@@ -542,6 +542,8 @@ fn executeNormalAction(p: *Pardes, t: *Text, semantic: modal.Normal.Action) void
.uppercase => return edit.normalCase(p, t, .upper),
.join_lines => return edit.normalJoin(p, t, false),
.join_select_space => return edit.normalJoin(p, t, true),
+ .rotate_contents_forward => return edit.normalRotateContents(p, t, true, op.count),
+ .rotate_contents_backward => return edit.normalRotateContents(p, t, false, op.count),
.indent => return edit.normalIndent(p, t, op.count, true),
.unindent => return edit.normalIndent(p, t, op.count, false),
.comment_toggle => return edit.normalToggleComment(p, t),