diff options
| author | Gabriel Schneider <[email protected]> | 2026-10-01 17:43:39 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 20:04:42 -0300 |
| commit | 805b9f188768fee523d462411d846912e0877ff3 (patch) | |
| tree | dc17de5cee6e4b554446052a29fd55e8a5285498 /src/pardes.zig | |
| parent | 0728b937028418232a1da3d9922615a6f49680f2 (diff) | |
| download | pardes-805b9f188768fee523d462411d846912e0877ff3.tar.gz pardes-805b9f188768fee523d462411d846912e0877ff3.zip | |
Edit runs acme's file and shell commands: < | > through the session's Shell off the loop (one undo step, a failure changes nothing, its stderr in +Errors, a 9P write answered when done), X and Y over the open text panes, b B D e r f w and the "file" address; checked against sam -d, and the reference's Edit section and Coming from acme row say so
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/pardes.zig')
| -rw-r--r-- | src/pardes.zig | 50 |
1 files changed, 49 insertions, 1 deletions
diff --git a/src/pardes.zig b/src/pardes.zig index 7ae73636..cf3d5128 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -123,6 +123,9 @@ pub const Turn = struct { /// Bumped each time a language server's answer (or its lack) is taken /// in (`lspResponse`): a write that asked one waits for this. lsp_answers: u64 = 0, + /// Bumped each time an Edit's commands (`< | >`) have answered and the + /// Edit is done, or failed (edit_cmd.zig): a write that ran one waits. + edit_answers: u64 = 0, /// All of the above, and `out` reaching zero. settled: std.Io.Condition = .init, @@ -220,6 +223,16 @@ pub const Turn = struct { while (t.lsp_answers == answers) t.settled.wait(t.io.?, &t.mutex) catch return; } + pub fn editAnswered(t: *Turn) void { + t.edit_answers +%= 1; + const io = t.io orelse return; + t.settled.broadcast(io); + } + + pub fn awaitEdit(t: *Turn, answers: u64) void { + while (t.edit_answers == answers) t.settled.wait(t.io.?, &t.mutex) catch return; + } + pub fn awaitRestored(t: *Turn, restores: u64) void { while (t.restores == restores) t.settled.wait(t.io.?, &t.mutex) catch return; } @@ -483,6 +496,7 @@ test { _ = @import("exec.zig"); _ = @import("look.zig"); _ = @import("sam_edit.zig"); + _ = @import("edit_cmd.zig"); _ = @import("mouse.zig"); _ = @import("normal.zig"); _ = @import("regexp.zig"); @@ -3702,6 +3716,8 @@ pub const Effect = union(enum) { /// Snapshot the matching request with pipeRequest(id), then run it away /// from the UI/event loop and answer with pipe_resp. pipe: struct { id: u32 }, + /// Write what an Edit's `w` took (`Pipe.writes`), in order. + edit_write, watch: struct { pane: u8, on: bool, mode: WatchMode = .reconcile }, theme_file: struct { generation: u32, on: bool }, /// Write the build-time theme ring below the per-user config directory. @@ -4907,7 +4923,7 @@ pub const Pardes = struct { if (p.custom_theme) |theme_value| std.zon.parse.free(gpa, theme_value); if (p.chord_arg) |a| gpa.free(a); for (p.spawn_dirs) |d| if (d) |dir| gpa.free(dir); - if (p.pipe.wait) |*wait| wait.deinit(gpa); + p.pipe.deinit(gpa); p.locations_cache.deinit(p.tree_sitter_gpa); p.fs.deinit(gpa); p.shell_rows.reset(gpa); @@ -5795,6 +5811,37 @@ pub const Pardes = struct { f(p.host.ctx, q.id) else p.update(.{ .pipe_resp = .{ .id = q.id, .success = false, .outputs = &.{} } }), + .edit_write => { + // Each write takes the bytes `w` took when it ran: the text + // as it was before the Edit's changes. + var writes = p.pipe.writes; + p.pipe.writes = .empty; + defer { + for (writes.items) |*w| w.deinit(p.gpa); + writes.deinit(p.gpa); + } + for (writes.items) |w| { + const was = if (p.panes[w.pane]) |pane| (if (pane.file) |f| f.saved_revision else 0) else 0; + const failures = p.fs.failures; + makeParents(w.path); + p.hostWriteFile(w.pane, w.path, w.bytes); + const pane = p.panes[w.pane] orelse continue; + if (pane.serial != w.serial) continue; + const f = if (pane.file) |*file| file else continue; + // Failed, it changes nothing, as save_text's does not. + if (p.fs.failures != failures) { + f.saved_revision = was; + continue; + } + if (w.promote) { + p.promoteSaved(w.pane, w.path); + } else if (w.clean != null and w.clean.? == f.revision) { + f.saved_revision = f.revision; + f.disk_gone = false; + ctlfs.events.noteLog(p, .save, pane); + } else ctlfs.events.noteLogAs(p, .save, pane, w.path); + } + }, .watch => |w| if (v.watch_file) |f| f(p.host.ctx, w.pane, p.watchPath(w.pane) orelse "", w.on, w.mode) else { @@ -5881,6 +5928,7 @@ pub const Pardes = struct { look.cancelLookHover(p); p.fs.serving = true; p.fs.lsp_answer_at = null; + p.fs.edit_answer_at = null; const reply = ctlfs.handle(p, req); p.fs.serving = false; // The one-failure rule is a write's: a refused open (its OTRUNC's |
