diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/config.zig | 2 | ||||
| -rw-r--r-- | src/edit.zig | 51 | ||||
| -rw-r--r-- | src/modal.zig | 15 | ||||
| -rw-r--r-- | src/normal.zig | 2 |
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), |
