summaryrefslogtreecommitdiff
path: root/src/edit.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/edit.zig')
-rw-r--r--src/edit.zig41
1 files changed, 27 insertions, 14 deletions
diff --git a/src/edit.zig b/src/edit.zig
index 5249a64c..02e138e8 100644
--- a/src/edit.zig
+++ b/src/edit.zig
@@ -96,18 +96,12 @@ pub fn applyPaste(p: *Pardes, bytes: []const u8) void {
if (normal.selRegexArmed(pane)) |a| normal.applySelRegex(p, pane, a.pat, a.split);
return;
}
- if (pane.tag_edit) {
- const text = p.tagText(p.scratch.allocator(), pane) catch return;
- const range: @TypeOf(Pardes.tagSelBounds(pane)) = if (pane.tag_sel) Pardes.tagSelBounds(pane) else .{ .lo = pane.tag_col, .hi = pane.tag_col };
- const hi = if (pane.tag_sel) modal.nextGrapheme(text, range.hi) else range.hi;
- _ = p.replaceTagText(pane, range.lo, hi, bytes);
- return;
- }
- if (pane.isTerminal() and pane.body.mode == .tty) return typeToTty(p, id, pane, bytes);
+ const t = if (pane.focus == .tag) &pane.tag else &pane.body;
+ if (t.what == .body and pane.isTerminal() and pane.body.mode == .tty) return typeToTty(p, id, pane, bytes);
switch (if (req) |r| r.mode else .after) {
- .after => pasteText(p, &pane.body, bytes, false, 1),
- .before => pasteText(p, &pane.body, bytes, true, 1),
- .replace => replaceWithText(p, &pane.body, bytes),
+ .after => pasteText(p, t, bytes, false, 1),
+ .before => pasteText(p, t, bytes, true, 1),
+ .replace => replaceWithText(p, t, bytes),
}
}
@@ -301,7 +295,7 @@ pub fn exitInsert(p: *Pardes, t: *Text) void {
pub fn paneCursorLines(p: *Pardes, t: *Text) ![]const []const u8 {
const arena = p.scratch.allocator();
if (t.what != .body) {
- const text = t.own orelse "";
+ const text = try flatSurface(p, t);
const lines = try arena.alloc([]const u8, std.mem.count(u8, text, "\n") + 1);
var it = std.mem.splitScalar(u8, text, '\n');
for (lines) |*line| line.* = it.next().?;
@@ -346,6 +340,7 @@ pub fn pinPaneCursor(p: *Pardes, t: *Text) void {
}
pub fn flatSurface(p: *Pardes, t: *Text) ![]const u8 {
+ if (t.what == .tag) return Pardes.curTail(t.pane());
if (t.what != .body) return t.own orelse "";
const pane = t.pane();
if (pane.file) |f| return f.content;
@@ -367,6 +362,10 @@ pub fn paneWrapWidth(p: *const Pardes, t: *Text) usize {
/// Route shared edit operations to the characters `t` edits: its own, or
/// for a body its file's content or its terminal's overlay.
fn editText(p: *Pardes, t: *Text, lo: i32, hi: i32, col: i32) ?panes.EditText {
+ // A tag nobody has changed shows its default; the first edit makes that
+ // default its own text.
+ if (t.what == .tag and t.own == null)
+ t.own = p.gpa.dupe(u8, Pardes.defaultTail(t.pane())) catch return null;
if (t.what != .body) return .{ .text = t.own orelse &.{}, .row0 = 0 };
const pane = t.pane();
if (pane.file) |f| return .{ .text = f.content, .row0 = 0 };
@@ -1544,14 +1543,19 @@ pub fn surroundReplace(p: *Pardes, t: *Text, from: u21, to: u21) void {
pub fn pushUndo(p: *Pardes, t: *Text) void {
// one keystroke, one undo step — even when it edited at ten cursors.
if (p.multi_on and !p.multi_first) return;
- // a prompt's answer is typed once and gone; it keeps no history
- if (t.what != .body) return;
+ switch (t.what) {
+ .body => {},
+ .tag => return t.remember(p.gpa, if (t.own) |own| .{ .text = own } else null),
+ // a prompt's answer is typed once and gone; it keeps no history
+ .input => return,
+ }
const pane = t.pane();
if (pane.file != null) return panes.File.pushUndo(p, pane);
panes.Terminal.pushUndo(p, pane);
}
pub fn doUndo(p: *Pardes, t: *Text) void {
+ if (t.what == .tag) return stepOwn(p, t, true);
if (t.what != .body) return;
const pane = t.pane();
if (pane.file != null) return panes.File.undo(p, pane);
@@ -1559,12 +1563,21 @@ pub fn doUndo(p: *Pardes, t: *Text) void {
}
pub fn doRedo(p: *Pardes, t: *Text) void {
+ if (t.what == .tag) return stepOwn(p, t, false);
if (t.what != .body) return;
const pane = t.pane();
if (pane.file != null) return panes.File.redo(p, pane);
panes.Terminal.redo(p, pane);
}
+/// Undo or redo an edit of a text's own characters; stepping back past its
+/// first edit gives a tag its default again.
+fn stepOwn(p: *Pardes, t: *Text, back: bool) void {
+ const to = t.step(p.gpa, if (t.own) |own| .{ .text = own } else null, back) orelse return;
+ if (t.own) |own| p.gpa.free(own);
+ t.own = if (to.ovl) |buffer| buffer.text else null;
+}
+
const PointerTextSelection = struct {
sel: Pane.Sel,
on_tag: bool,