summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 05:30:54 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:16 -0300
commit2fe2c920513fc78b61039714bf4d11ae48169f40 (patch)
tree5edb4c35faa895c9b6d5d9a525d2085fbb3173dc /src
parent24729dbbf8b32966a3f33c9bc20599b185856dd3 (diff)
downloadpardes-2fe2c920513fc78b61039714bf4d11ae48169f40.tar.gz
pardes-2fe2c920513fc78b61039714bf4d11ae48169f40.zip
An Edit block cut short through exec is an err, not a msg
An exec write does not fail for what its command says, so an a/c/i text or { group cut short by a write that ended early was only a msg, easy to miss. Over 9P, that failure (a truncated write, not a command's) is now logged as an err record naming exec; the pane still says it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/builtins.zig16
-rw-r--r--src/ninep/tree.zig13
2 files changed, 28 insertions, 1 deletions
diff --git a/src/builtins.zig b/src/builtins.zig
index dfd1e84c..6ca216e3 100644
--- a/src/builtins.zig
+++ b/src/builtins.zig
@@ -946,7 +946,21 @@ pub const Edit = struct {
var why: sam.Why = .{};
var said: [260]u8 = undefined;
const res = sam.run(arena, f.content, ninep_pane.dotOf(c.pane), f.path, c.arg orelse "", &why) catch |err| switch (err) {
- error.Edit => return c.p.reportFailure(c.id, std.fmt.bufPrint(&said, "Edit: {s}", .{why.text()}) catch "Edit: failed"),
+ error.Edit => {
+ const text = std.fmt.bufPrint(&said, "Edit: {s}", .{why.text()}) catch "Edit: failed";
+ // A block cut short (no `.` line, no `}`) that came over
+ // 9P through an exec, whose write does not fail for what
+ // a command says, is still the write's fault: an err.
+ const cut = std.mem.eql(u8, why.text(), "unmatched `{'") or std.mem.startsWith(u8, why.text(), "a, c or i text not ended");
+ if (cut and c.p.fs.serving and !c.p.fs.no_prompt) {
+ var rec: [300]u8 = undefined;
+ pardes.ctlfs.events.notePath(c.p, "err", std.fmt.bufPrint(&rec, "{d} exec: {s}", .{ c.pane.serial, text }) catch "- exec: Edit failed");
+ c.p.fs.unlogged = true;
+ defer c.p.fs.unlogged = false;
+ return c.p.reportFailure(c.id, text);
+ }
+ return c.p.reportFailure(c.id, text);
+ },
error.OutOfMemory => return c.p.reportError(c.id, "Edit", err),
};
if (res.undo != 0) {
diff --git a/src/ninep/tree.zig b/src/ninep/tree.zig
index 54d21da6..27091112 100644
--- a/src/ninep/tree.zig
+++ b/src/ninep/tree.zig
@@ -1547,3 +1547,16 @@ test "an a, c or i text still open when its open closes fails there too and chan
try testing.expect(th.logHas(p, "not ended by a . line"));
try testing.expectEqualStrings("abc\n", p.panes[0].?.file.?.content);
}
+
+test "an a, c or i text cut short through exec is an err in the log, not a msg" {
+ const p = try th.withFile(testing.allocator, "abc\n");
+ defer p.deinit();
+ const exec = Node.of(serialOf(p), .exec);
+ const c = call(p, .{ .tag = 1, .op = .open, .node = exec, .omode = 1 }).reply.handle;
+ _ = call(p, .{ .tag = 2, .op = .write, .node = exec, .handle = c, .data = "Edit $a\nhalf\n" });
+ _ = call(p, .{ .tag = 3, .op = .release, .node = exec, .handle = c, .opened = true });
+ var want: [64]u8 = undefined;
+ try testing.expect(th.logHas(p, try std.fmt.bufPrint(&want, "err {d} exec: Edit: a, c or i text not ended", .{serialOf(p)})));
+ try testing.expect(!th.logHas(p, "msg 1 Edit: a, c or i"));
+ try testing.expectEqualStrings("abc\n", p.panes[0].?.file.?.content);
+}