diff options
| author | Gabriel Schneider <[email protected]> | 2026-10-01 19:50:32 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 19:57:27 -0300 |
| commit | dce94f4453735a6f71385cc020ee79c7604609e7 (patch) | |
| tree | 266e031b92a282187467f5e35c1b0824b4b7a5f2 /src/pardes.zig | |
| parent | 2868516c215a96d9e1e933ded7ac5744ec16c368 (diff) | |
| download | pardes-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/pardes.zig')
| -rw-r--r-- | src/pardes.zig | 11 |
1 files changed, 11 insertions, 0 deletions
diff --git a/src/pardes.zig b/src/pardes.zig index af2b80a2..7ae73636 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -4369,6 +4369,10 @@ pub const Pardes = struct { /// (`stdio.h`, `<foo.h>`) is tried in, in order. The session's, seeded /// with C's (/usr/include, /usr/local/include), kept in a dump. incl: std.ArrayList([]u8) = .empty, + /// Zerox's groups of panes on one buffer (File.syncTwins), and the id + /// the next takes. + twin_groups: std.ArrayList(panes.File.TwinGroup) = .empty, + next_twin: u32 = 1, /// The kept list was read (or there was none): only then is it written, /// so a session never writes over one it did not read. recent_loaded: bool = false, @@ -4872,6 +4876,8 @@ pub const Pardes = struct { p.recent.deinit(p.recentGpa()); for (p.incl.items) |dir| p.gpa.free(dir); p.incl.deinit(p.gpa); + for (p.twin_groups.items) |group| p.gpa.free(group.path); + p.twin_groups.deinit(p.gpa); p.fs.batch.bytes.deinit(p.gpa); if (p.stand_in) |pane| p.teardownPane(pane); look.cancelLookHover(p); @@ -5006,6 +5012,7 @@ pub const Pardes = struct { // to it reopen it there. p.noteClosed(pane); panes.Output.dropUnsaved(p, pane); + if (pane.file) |*file| panes.File.leaveTwins(p, file); const watched = (if (pane.file) |f| f.output == null else false) or pane.hasPdf(); for (p.panes, 0..) |slot, id| if (slot == pane) { if (watched) p.emit(.{ .watch = .{ .pane = @intCast(id), .on = false } }); @@ -5682,6 +5689,8 @@ pub const Pardes = struct { } pub fn perform(p: *Pardes, e: Effect) void { + // A Save performed on one twin is every twin's (File.syncTwins). + defer panes.File.syncTwins(p); const v = p.host.vtable; switch (e) { // The host reads the pane (its command, its shell) as it forks, @@ -5862,6 +5871,7 @@ pub const Pardes = struct { /// that changes a pane costs a frame, which is why a round trip on a /// local socket costs microseconds and not a vsync. pub fn serveFs(p: *Pardes, req: ctlfs.Req) ctlfs.Reply { + defer panes.File.syncTwins(p); if (!ctlfs.changesPane(p, req)) return ctlfs.handle(p, req); // An address, a limit or the mark flag is nothing drawn: a script's // addr write then its close costs no frame between them. @@ -5892,6 +5902,7 @@ pub const Pardes = struct { } pub fn update(p: *Pardes, ev: Event) void { + defer panes.File.syncTwins(p); defer p.reportFocus(); // A tick with nothing animating is the one event that cannot change // the screen. |
