summaryrefslogtreecommitdiff
path: root/src/pardes.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/pardes.zig')
-rw-r--r--src/pardes.zig50
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