summaryrefslogtreecommitdiff
path: root/src/ninep
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 12:19:39 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:16 -0300
commit4f57043e39396bc958a103f87466870cf8dafe00 (patch)
tree89ec869d2e3b3eb231f14f9298bb56afa9e0f6ae /src/ninep
parentab220b89afcfda848cf84c18cc135a2e5c392b79 (diff)
downloadpardes-4f57043e39396bc958a103f87466870cf8dafe00.tar.gz
pardes-4f57043e39396bc958a103f87466870cf8dafe00.zip
A language server question that finds nothing, cannot be answered or has no room fails, and so does a write to an image's or PDF's body
Callers or Callees with nothing found, Hover or Lspwhy with no room for its pane, and a question asked of no file's pane said nothing, the 9P write succeeding; a body write to an image or PDF pane went nowhere. A write that asks a language server now waits for its answer (turn.lsp_answers), and what fails there -- nothing found, no answer, a backend's @none why, a placement with no room (ENOSPC) -- fails the write and logs its err. No diagnostics is said, not failed. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/ninep')
-rw-r--r--src/ninep/ctl.zig36
-rw-r--r--src/ninep/pane.zig2
2 files changed, 38 insertions, 0 deletions
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index c2a78fb8..2c6d2010 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -2079,6 +2079,42 @@ test "a script whose interpreter is not there: Tty refuses it up front, only an
try testing.expect(!p.panes[id].?.shell_failed);
}
+test "a language server question that finds nothing, cannot be answered, or is asked of no file fails, and a write to an image's body is refused" {
+ const p = try withFile(testing.allocator, "x\n");
+ defer p.deinit();
+ const id = p.active;
+ // Asked of a pane that is no file's: at once.
+ _ = wr(p, root_exec, "Recent\n");
+ const listed = p.paneBySerial(try std.fmt.parseInt(u32, std.mem.trimEnd(u8, rd(p, root_exec, 0, 64).bytes, "\n"), 10)).?;
+ p.lspRequest(listed, .incoming_calls, "");
+ try testing.expect(std.mem.indexOf(u8, p.panes[listed].?.msg[0..p.panes[listed].?.msg_len], "Callers: only a file's pane asks") != null);
+ // Nothing found: Callers says so, and the waiting write hears it.
+ p.fs.late_failure_len = 0;
+ p.lspRequest(id, .incoming_calls, "");
+ try testing.expect(p.lsp_wait != null);
+ p.lspResponse(p.lsp_wait.?.id, "");
+ try testing.expectEqualStrings("Callers: no callers, not found", p.fs.late_failure[0..p.fs.late_failure_len]);
+ // A backend that cannot answer says why.
+ p.fs.late_failure_len = 0;
+ p.lspRequest(id, .outgoing_calls, "");
+ p.lspResponse(p.lsp_wait.?.id, "@none zls does not answer call hierarchy\n");
+ try testing.expectEqualStrings("Callees: zls does not answer call hierarchy", p.fs.late_failure[0..p.fs.late_failure_len]);
+ // No answer at all.
+ p.fs.late_failure_len = 0;
+ p.lspRequest(id, .hover, "");
+ p.lspResponse(p.lsp_wait.?.id, null);
+ try testing.expectEqualStrings("Hover: the language server did not answer", p.fs.late_failure[0..p.fs.late_failure_len]);
+ // No diagnostics is no failure.
+ p.fs.late_failure_len = 0;
+ p.lspRequest(id, .diagnostics, "");
+ p.lspResponse(p.lsp_wait.?.id, "");
+ try testing.expectEqual(@as(u16, 0), p.fs.late_failure_len);
+ // An image's body takes no write.
+ const slot = p.freeSlot().?;
+ const img = try pardes.panes.Image.create(p, slot, "/tmp/pardes-no-such.png", try p.image_gpa.dupe(u8, "not a png"));
+ try testing.expectEqual(E.INVAL, wr(p, Node.of(img.serial, .body), "text\n").errno());
+}
+
test "every EINVAL a write gets says why, in its err record too; DEL is a control character in a line" {
const p = try withFile(testing.allocator, "x\n");
defer p.deinit();
diff --git a/src/ninep/pane.zig b/src/ninep/pane.zig
index 5ed3f6f4..fe3312b4 100644
--- a/src/ninep/pane.zig
+++ b/src/ninep/pane.zig
@@ -449,6 +449,8 @@ pub fn write(p: *Pardes, req: Req, id: usize, pane: *Pane, file: PaneFile) Reply
fn writeBody(p: *Pardes, req: Req, id: usize, pane: *Pane) Reply {
if (req.data.len == 0) return .{ .tag = req.tag, .written = 0 };
if (pane.file == null) {
+ // An image's or a PDF's body is no text a write goes into.
+ if (!pane.isTerminal()) return tree.failText(req.tag, E.INVAL, e_no_text);
const take = wholeUtf8(req.data);
p.emitWrite(id, req.data[0..take]);
return .{ .tag = req.tag, .written = @intCast(take) };