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/pardes.zig | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/pardes.zig') diff --git a/src/pardes.zig b/src/pardes.zig index 06bc81ed..29a9ab3a 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -7024,6 +7024,10 @@ pub const Pardes = struct { } pub fn acknowledgeShell(p: *Pardes, id: usize, executable: []const u8, prompt_marks: bool) void { + if (id < MAX_PANES) { + ctlfs.pty.shellGone(p, id); // a respawn replaced whatever ran + p.fs.panes[id].unmarked = !prompt_marks; + } if (id < MAX_PANES) panes.Terminal.shellSpawned(p, id, prompt_marks); if (p.settings.shell.effective.set(executable)) p.settings.shell.pending = false; @@ -7848,6 +7852,7 @@ pub const Pardes = struct { const pane = p.panes[o.pane] orelse return; ctlfs.events.notePtyOutput(p, o.pane, o.bytes); panes.Terminal.feedOutput(p, pane, o.bytes); + ctlfs.pty.noteMarks(p, o.pane, pane); }, .eof => |e| p.removePane(e.pane, null) catch |err| { if (p.panes[e.pane]) |pane| pane.mode = .normal; -- cgit v1.3