summaryrefslogtreecommitdiff
path: root/src/builtins.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-10-01 19:50:32 -0300
committerGabriel Schneider <[email protected]>2026-10-01 19:57:27 -0300
commitdce94f4453735a6f71385cc020ee79c7604609e7 (patch)
tree266e031b92a282187467f5e35c1b0824b4b7a5f2 /src/builtins.zig
parent2868516c215a96d9e1e933ded7ac5744ec16c368 (diff)
downloadpardes-dce94f4453735a6f71385cc020ee79c7604609e7.tar.gz
pardes-dce94f4453735a6f71385cc020ee79c7604609e7.zip
Zerox opens a second pane on a file pane's buffer: one text, undo and unsaved state, a scroll and a cursor each; an edit in either is spliced into both at File.setContentSpan, O(the edit) more, and what a Save, a get, the disk watch or a rename changes on one is copied to the rest after each step
Twins share the content buffer, the History and, while it is one, the line index; the other twin's cursor and scroll move past the splice as acme moves a clone's q0. Del of one twin asks nothing while another holds the text, Exit lists the text once, and a closed twin keeps a copy of its own until it is torn down. Both are in the index, each its serial, one name. An event reader on one hears no edit made through another (first cut). A dump keeps the twins as two panes on the file, not linked again. perf: edit-twin, typing beside a twin of the 50k-line file, gated within 3x of edit-char in the same run; the three baselines re-recorded for it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/builtins.zig')
-rw-r--r--src/builtins.zig28
1 files changed, 28 insertions, 0 deletions
diff --git a/src/builtins.zig b/src/builtins.zig
index 5fdabd87..da87ba37 100644
--- a/src/builtins.zig
+++ b/src/builtins.zig
@@ -575,6 +575,22 @@ fn warnModifiedIn(c: Ctx, asking: Pane.Discarding, which: Asked) bool {
.column => |col| if ((layout.findPane(c.p, id) orelse continue).col != col) continue,
}
const f = pane.file orelse continue;
+ // Twins (Zerox) hold one text: closing one while another stays
+ // loses nothing, and the text is asked about once.
+ if (f.twin != 0) {
+ const asked_elsewhere = for (c.p.panes, 0..) |other_slot, other_id| {
+ const other = other_slot orelse continue;
+ const of = other.file orelse continue;
+ if (other_id == id or of.twin != f.twin) continue;
+ const closing = switch (which) {
+ .all => true,
+ .pane => |only| other_id == only,
+ .column => |col| if (layout.findPane(c.p, other_id)) |at| at.col == col else false,
+ };
+ if (!closing or other_id < id) break true;
+ } else false;
+ if (asked_elsewhere) continue;
+ }
// A +New scratch saves nowhere, but what is typed in it is as lost;
// under 100 bytes it is not asked about, as acme's winclean does not
// whine about a small unnamed window, nor about a command's output.
@@ -1196,6 +1212,18 @@ pub const Incl = struct {
}
};
+/// acme's Zerox: a second pane on this pane's file, the same text, undo and
+/// unsaved state, with a scroll and a cursor of its own (File.zerox).
+pub const Zerox = struct {
+ pub fn run(c: Ctx) void {
+ const f = c.pane.file orelse return c.p.reportFailure(c.id, "Zerox: only a file pane takes it");
+ if (f.output != null or f.listing != null or f.mini != null) return c.p.reportFailure(c.id, "Zerox: only a file pane takes it");
+ const free = c.p.freeSlot() orelse return c.p.reportError(c.id, "Zerox", error.NoPaneSlots);
+ _ = panes.File.zerox(c.p, c.id, free) catch |err| return c.p.reportError(c.id, "Zerox", err);
+ exec.placeNew(c.p, c.id, c.id, free, .doc);
+ }
+};
+
/// Write the pane's text to its file, or to the file its argument names.
pub const Save = struct {
pub const takes_arg = true;