summaryrefslogtreecommitdiff
path: root/src/exec.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-28 15:53:29 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:15 -0300
commitb67dce15e662ae44de3286686f5a0afc147b918d (patch)
tree9f9dac843b61501bf778bf1d07ed7ee598b26db6 /src/exec.zig
parent2868137e34c973a47cbf667a431e885ca23cd9a2 (diff)
downloadpardes-b67dce15e662ae44de3286686f5a0afc147b918d.tar.gz
pardes-b67dce15e662ae44de3286686f5a0afc147b918d.zip
A REPL takes text only while its program has the terminal
A binding outlived its program: a command pane reused kept the REPL of the command before, a done command pane could be bound, a document pane (a terminal with no emulator) was accepted, and after Ctrl-D in python3 the text went to the shell, which ran import os as ImageMagick's. A command pane's binding now ends with its command and a done one is refused, a pane with no emulator is refused, and an interactive terminal's REPL is live only while a program other than its shell holds the tty (the host's tty_taken); when none of the language's REPLs is, nothing is sent or run and the pane says so. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/exec.zig')
-rw-r--r--src/exec.zig36
1 files changed, 29 insertions, 7 deletions
diff --git a/src/exec.zig b/src/exec.zig
index dbda7217..57eaad8f 100644
--- a/src/exec.zig
+++ b/src/exec.zig
@@ -394,10 +394,15 @@ pub fn langOf(pane: *const Pane) ?u8 {
return null;
}
-/// A bound REPL whose program can still take input: a command pane's is
-/// gone once its command is done.
-pub fn replLive(pane: *const Pane) bool {
- return pane.repl != null and pane.isTerminal() and !(pane.command != null and pane.command_done);
+/// A bound REPL whose program is there to take input: a command pane's
+/// while its command runs; an interactive terminal's while a program, not
+/// the shell, has its tty (the host's `tty_taken`) -- a python3 left with
+/// Ctrl-D leaves the shell, which would run `import os` as ImageMagick's.
+pub fn replLive(p: *const Pardes, id: usize) bool {
+ const pane = p.panes[id] orelse return false;
+ if (pane.repl == null) return false;
+ if (pane.command != null) return !pane.command_done;
+ return p.hostTtyTaken(id);
}
/// `python-a`.
@@ -408,22 +413,37 @@ pub fn replId(buf: []u8, pane: *const Pane) []const u8 {
const Routed = union(enum) { none, sent: usize, asked };
+/// The REPL bound here has no program running to take the text: said,
+/// and nothing sent or run.
+fn replGone(p: *Pardes, from: usize, repl: *const Pane) Routed {
+ var idbuf: [48]u8 = undefined;
+ var said: [128]u8 = undefined;
+ p.setMessage(from, std.fmt.bufPrint(&said, "Repl: {s} has no program running; nothing sent", .{replId(&idbuf, repl)}) catch "Repl: no program running");
+ return .asked;
+}
+
/// Where an exec from `from`'s body goes when a REPL is bound for it: the
/// one there is, or a question when there are several.
fn routeToRepl(p: *Pardes, from: usize, text: []const u8) Routed {
const src = p.panes[from] orelse return .none;
- if (src.repl != null and replLive(src)) {
+ if (src.repl != null) {
+ if (!replLive(p, from)) return replGone(p, from, src);
sendToRepl(p, from, from, text);
return .{ .sent = from };
}
const lang = langOf(src) orelse return .none;
var bound: [26]usize = undefined;
var n: usize = 0;
- for (p.panes, 0..) |slot, i| if (slot) |pane| if (pane.repl) |r| if (r.lang == lang and replLive(pane) and n < bound.len) {
+ var gone: ?usize = null;
+ for (p.panes, 0..) |slot, i| if (slot) |pane| if (pane.repl) |r| if (r.lang == lang and n < bound.len) {
+ if (!replLive(p, i)) {
+ gone = i;
+ continue;
+ }
bound[n] = i;
n += 1;
};
- if (n == 0) return .none;
+ if (n == 0) return if (gone) |i| replGone(p, from, p.panes[i].?) else .none;
if (n == 1) {
sendToRepl(p, from, bound[0], text);
return .{ .sent = bound[0] };
@@ -593,6 +613,8 @@ fn noteRun(p: *Pardes, pane: *Pane, what: []const u8, said: []const u8) void {
pub fn commandDone(p: *Pardes, id: usize, status: ?u8) void {
const pane = p.panes[id] orelse return;
pane.command_done = true;
+ // A REPL it was is gone with its command; the pane's next is not one.
+ pane.repl = null;
pane.command_status = status;
pane.body.mode = .normal;
var buf: [16]u8 = undefined;