From d378de9c497f46090a3d0d30508f504eae5cd48f Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Thu, 1 Oct 2026 05:10:37 -0300 Subject: A pane ctl takes Tty+bash as exec and the tag do: a word that takes its argument after a + is no unknown control message there checkBuiltin split a line at its first blank only, so `Tty+bash` was one unknown word on a ctl while exec ran it. It now splits at the + for the words whose registry entry says they take one so. Co-Authored-By: Claude Opus 5.5 --- src/ninep/ctl.zig | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/ninep/ctl.zig') diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig index 1e274e0c..b7c529e1 100644 --- a/src/ninep/ctl.zig +++ b/src/ninep/ctl.zig @@ -471,7 +471,11 @@ fn blanked(line: []const u8, buf: []u8) []const u8 { /// Answers the refusal, or null. Words are the builtins' own, capitalised /// as on a tag; acme's lowercase verbs are the pane ctl's and alias none. fn checkBuiltin(p: *Pardes, req: Req, line: []const u8, scope: builtins.Scope) ?Reply { - const sp = std.mem.indexOfAny(u8, line, " \t"); + var sp = std.mem.indexOfAny(u8, line, " \t"); + // `Word+arg` for a word that takes one so (`Tty+bash`), as exec does. + if (sp == null) if (std.mem.indexOfScalar(u8, line, '+')) |at| if (std.meta.stringToEnum(Builtin, line[0..at])) |head| { + if (builtins.registry.plusArg(head)) sp = at; + }; const typed = line[0 .. sp orelse line.len]; // acme's words: checked as the pardes word they run as, or refused. const word = for (pardes.exec.acme_words) |w| { @@ -4081,3 +4085,11 @@ test "a body write to an image pane says its body takes none, not that terminals doc.image = .{ .path = try p.gpa.dupe(u8, "/tmp/pardes-pic.ppm") }; try testing.expectEqualStrings(pane_files.e_no_body, wr(p, Node.of(doc.serial, .body), "x").reply.ename); } + +test "Tty+bash on a pane ctl is Tty with its argument, as exec and the tag take it" { + const p = try withFile(testing.allocator, "x\n"); + defer p.deinit(); + const r = call(p, .{ .tag = 1, .op = .write, .node = Node.of(serialOf(p), .ctl), .data = "Tty+sh\n" }); + try testing.expectEqual(Status.ok, r.reply.status); + try testing.expect(r.spawned); +} -- cgit v1.3