diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-28 15:53:29 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:15 -0300 |
| commit | b67dce15e662ae44de3286686f5a0afc147b918d (patch) | |
| tree | 9f9dac843b61501bf778bf1d07ed7ee598b26db6 /src/pardes.zig | |
| parent | 2868137e34c973a47cbf667a431e885ca23cd9a2 (diff) | |
| download | pardes-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/pardes.zig')
| -rw-r--r-- | src/pardes.zig | 34 |
1 files changed, 33 insertions, 1 deletions
diff --git a/src/pardes.zig b/src/pardes.zig index 429f33b9..f8328289 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -1446,6 +1446,11 @@ test "a REPL bound for a language takes the exec made on a body in it; tags, Exe return to[pane][0..len[pane]]; } }; + // The programs the REPLs run hold their terminals' ttys. + var host: FakeTtyQuery = .{}; + host.install(p); + host.taken[1] = true; + host.taken[2] = true; // Only a terminal is a REPL; a language's name is the syntax table's. try std.testing.expect(p.executeBuiltinLine(0, "Repl python")); try std.testing.expect(file.repl == null); @@ -1503,6 +1508,18 @@ test "a REPL bound for a language takes the exec made on a body in it; tags, Exe Sent.drain(p); try std.testing.expect(Sent.len[1] == 0 and Sent.len[2] == 0); + // A REPL whose program has left (Ctrl-D: the shell has the tty) is + // sent nothing, and nothing runs: it says so. + host.taken[1] = false; + host.taken[2] = false; + p.exec_from_body = true; + _ = exec.execute(p, 0, "import os"); + Sent.drain(p); + try std.testing.expect(Sent.len[1] == 0 and Sent.len[2] == 0 and !Sent.spawned); + try std.testing.expect(std.mem.indexOf(u8, file.msg[0..file.msg_len], "no program running") != null); + host.taken[1] = true; + host.taken[2] = true; + // Unbound, its letter is free again; bare, it says what it is. try std.testing.expect(p.executeBuiltinLine(1, "Repl -")); try std.testing.expect(p.panes[1].?.repl == null); @@ -1510,6 +1527,21 @@ test "a REPL bound for a language takes the exec made on a body in it; tags, Exe try std.testing.expectEqualStrings("python-a", exec.replId(&idbuf, p.panes[1].?)); try std.testing.expect(p.executeBuiltinLine(2, "Repl")); try std.testing.expectEqualStrings("Repl: python-b", p.panes[2].?.msg[0..p.panes[2].?.msg_len]); + + // A command pane is a REPL while its command runs: done, it is none, + // and a done one cannot be bound. A document pane is no terminal. + const cmd = p.freeSlot().?; + _ = try p.newCommand(cmd, "", "python3"); + try std.testing.expect(p.executeBuiltinLine(cmd, "Repl python")); + try std.testing.expect(p.panes[cmd].?.repl != null); + p.update(.{ .exited = .{ .pane = @intCast(cmd), .status = 0 } }); + try std.testing.expect(p.panes[cmd].?.repl == null); + try std.testing.expect(p.executeBuiltinLine(cmd, "Repl python")); + try std.testing.expect(p.panes[cmd].?.repl == null); + const doc_slot = p.freeSlot().?; + const doc = try p.newDocPane(doc_slot); + try std.testing.expect(p.executeBuiltinLine(doc_slot, "Repl python")); + try std.testing.expect(doc.repl == null); } test "Tty+fish, one word a tag can hold, opens a terminal on that shell" { @@ -5172,7 +5204,7 @@ pub const Pardes = struct { // Its letter sends it there; anything else takes it back. if (key.ctrl or key.alt or key.cp > 'z' or key.cp < 'a') return; for (p.panes, 0..) |target, to| if (target) |repl| if (repl.repl) |r| - if (r.lang == ask.lang and r.letter == key.cp and exec.replLive(repl)) + if (r.lang == ask.lang and r.letter == key.cp and exec.replLive(p, to)) return exec.sendToRepl(p, id, to, ask.text); return; } |
