summaryrefslogtreecommitdiff
path: root/src/ninep/pane.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 09:11:37 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:16 -0300
commita550753fb60be3cdc040c521ddaab9022f5d3248 (patch)
tree9d392076f417b6a9d53b6a1bc9ce7fe44d4e499b /src/ninep/pane.zig
parent4d4818f7baf356866d323e4b337a64a3dddd8adb (diff)
downloadpardes-a550753fb60be3cdc040c521ddaab9022f5d3248.tar.gz
pardes-a550753fb60be3cdc040c521ddaab9022f5d3248.zip
Every EINVAL a write gets says why; DEL in an exec or look line is a control character
An empty name, a word written to log other than follow, a data, sel, dot or dirty write to a pane with no text, a truncate other than to zero, and a control character in a look line written through a held open were refused with no words, logged as `Invalid argument`. Each says its reason now; and DEL is refused in exec and look lines as in names. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/ninep/pane.zig')
-rw-r--r--src/ninep/pane.zig15
1 files changed, 9 insertions, 6 deletions
diff --git a/src/ninep/pane.zig b/src/ninep/pane.zig
index 66b3728c..4c967fc5 100644
--- a/src/ninep/pane.zig
+++ b/src/ninep/pane.zig
@@ -481,8 +481,11 @@ fn writeTag(req: Req, pane: *Pane) Reply {
return .{ .tag = req.tag, .written = @intCast(take) };
}
+/// A write only text takes, to a pane with none: said, as every EINVAL is.
+pub const e_no_text = "invalid write: this pane has no text (a terminal, an image or a PDF)";
+
fn writeData(p: *Pardes, req: Req, pane: *Pane) Reply {
- if (fileOf(pane) == null) return Reply.fail(req.tag, E.INVAL);
+ if (fileOf(pane) == null) return tree.failText(req.tag, E.INVAL, e_no_text);
const pf = &pane.fs;
if (pf.addr_failed) return tree.failText(req.tag, E.INVAL, e_addr_failed);
clampAddr(pf, bodyOf(pane).len);
@@ -501,7 +504,7 @@ fn writeData(p: *Pardes, req: Req, pane: *Pane) Reply {
}
fn writeSel(p: *Pardes, req: Req, pane: *Pane) Reply {
- if (fileOf(pane) == null) return Reply.fail(req.tag, E.INVAL);
+ if (fileOf(pane) == null) return tree.failText(req.tag, E.INVAL, e_no_text);
const d = dotOf(pane);
const q0: usize = d.q0;
const q1: usize = @max(q0, @as(usize, d.q1));
@@ -558,7 +561,7 @@ fn writeRange(req: Req, pane: *Pane, file: PaneFile) Reply {
.limit => pf.limit = range,
// Setting dot scrolls to it, which is the whole of acme's `show`.
.dot => {
- if (fileOf(pane) == null) return Reply.fail(req.tag, E.INVAL);
+ if (fileOf(pane) == null) return tree.failText(req.tag, E.INVAL, e_no_text);
setDot(pane, range);
},
else => unreachable,
@@ -573,7 +576,7 @@ fn writeFlag(p: *Pardes, req: Req, pane: *Pane, file: PaneFile) Reply {
const pf = &pane.fs;
switch (file) {
.dirty => {
- const f = fileOf(pane) orelse return Reply.fail(req.tag, E.INVAL);
+ const f = fileOf(pane) orelse return tree.failText(req.tag, E.INVAL, e_no_text);
f.saved_revision = if (on) f.revision -% 1 else f.revision;
},
// acme's nomark joins the writes after it into one undo step. The
@@ -616,7 +619,7 @@ fn nameFault(name: []const u8) ?[]const u8 {
fn writeName(p: *Pardes, req: Req, id: usize, pane: *Pane) Reply {
// One name: its newline ends it, as `echo` writes it, and it is one.
const name = if (std.mem.endsWith(u8, req.data, "\n")) req.data[0 .. req.data.len - 1] else req.data;
- if (name.len == 0) return Reply.fail(req.tag, E.INVAL);
+ if (name.len == 0) return tree.failText(req.tag, E.INVAL, e_name_char ++ ": an empty name");
if (nameFault(name)) |why| return tree.failText(req.tag, E.INVAL, why);
if (fileOf(pane) == null) return tree.failText(req.tag, E.PERM, if (pane.isTerminal())
"rename not allowed: a terminal is named by its shell's directory; cd there, or Tty in another"
@@ -624,7 +627,7 @@ fn writeName(p: *Pardes, req: Req, id: usize, pane: *Pane) Reply {
"rename not allowed: an image or PDF is named by the file it shows");
const full = std.fs.path.resolvePosix(p.scratch.allocator(), &.{ pardes.Pardes.paneDir(pane), name }) catch
return Reply.fail(req.tag, E.NOMEM);
- if (!std.fs.path.isAbsolute(full) or full.len >= 4096) return Reply.fail(req.tag, E.INVAL);
+ if (!std.fs.path.isAbsolute(full) or full.len >= 4096) return tree.failText(req.tag, E.INVAL, "invalid file name: longer than a path may be");
nameBuffer(p, id, full, false) catch |err| return Reply.fail(req.tag, switch (err) {
error.OutOfMemory => E.NOMEM,
else => E.INVAL,