From 6f7beca8d27e2e00f7b90bb75015637a9aa4c950 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Sun, 27 Sep 2026 18:07:06 -0300 Subject: Run a line at a terminal's prompt through pty/run and read how it ended /pane//pty/run takes factotum's rpc shape: write one line on an open, read the answer on that same open. The answer is exit N once the command ended and the shell is back at a prompt; busy at once when a command runs, text is typed at the prompt, or the shell has not drawn its first prompt; error not run when the shell refused the line without running it (fish on a syntax error keeps it on the prompt, so it is taken back with Ctrl-U); error shell gone when the pane closes or its shell is replaced; error no prompt marks for a shell pardes could not instrument. The end comes from the shell's OSC 133 marks. ghostty parses D's exit status and drops it, so the stream now runs through a handler that wraps ghostty's and follows prompt -> input -> running -> done. The marks pardes injects into bash and fish carry aid=pardes and only those count, so fish 4's own marks (which doubled ours), a nested shell's, and a stray 133;D in printed output are ignored. Checked end to end against real bash and fish: false, exit 7, a syntax error, sleep, busy while running, and the pane closing mid-command. Co-Authored-By: Claude Opus 5.5 --- src/ninep/pane.zig | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/ninep/pane.zig') diff --git a/src/ninep/pane.zig b/src/ninep/pane.zig index 40d292c0..61073a55 100644 --- a/src/ninep/pane.zig +++ b/src/ninep/pane.zig @@ -41,6 +41,10 @@ pub const State = struct { tag_snap: std.ArrayList(u8) = .empty, pty_readers: u16 = 0, pty_out: events.Queue = .{}, + /// The pty/run open waiting on this shell's current command. + run: ?u8 = null, + /// The host started a shell it could not teach to mark its prompts. + unmarked: bool = false, /// Installed during this update; /log hears about it once the update ends /// and the pane has its file, name and place. unannounced: bool = false, @@ -225,7 +229,7 @@ pub fn fileSize(p: *Pardes, id: usize, f: PaneFile) u64 { .pty_status => pty.status_len, .pty_ctl => pty.ctlLen(pane), .pty_data => events.pending(&pf.pty_out), - .dir, .errors, .pty => 0, + .dir, .errors, .pty, .pty_run => 0, }; } @@ -293,6 +297,7 @@ pub fn read(p: *Pardes, req: Req, id: usize, pane: *Pane, file: PaneFile) Reply .pty_status => pty.readStatus(p, req, id, pane), .pty_data => pty.readData(p, req, pf), .pty_ctl => pty.readCtl(p, req, pane), + .pty_run => pty.readRun(p, req), .dir, .errors, .pty => Reply.fail(req.tag, E.PERM), }; } @@ -386,6 +391,7 @@ pub fn write(p: *Pardes, req: Req, id: usize, pane: *Pane, file: PaneFile) Reply Reply.fail(req.tag, E.IO), .pty_ctl => pty.writeCtl(p, req, id), .pty_data => pty.writeData(p, req, id), + .pty_run => pty.writeRun(p, req, id, pane), .dir, .pty, .pty_status => Reply.fail(req.tag, E.PERM), }; } -- cgit v1.3