diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/exec.zig | 27 | ||||
| -rw-r--r-- | src/pardes.zig | 14 |
2 files changed, 37 insertions, 4 deletions
diff --git a/src/exec.zig b/src/exec.zig index 6e6f528b..b8312a21 100644 --- a/src/exec.zig +++ b/src/exec.zig @@ -444,12 +444,28 @@ fn routeToRepl(p: *Pardes, from: usize, text: []const u8) Routed { } const repl_enter_wait_ns: u64 = 250 * std.time.ns_per_ms; +/// Python echoes a long paste over several reads: its Enter waits for the +/// echo to go quiet this long, not for the first of it. +const repl_quiet_ns: u64 = 100 * std.time.ns_per_ms; + +/// The host's clock now; core time (`now_ns`, `stepped_ns`) is as old as +/// the last frame, seconds in an idle session. +fn clockNow(p: *Pardes) u64 { + return if (p.host.vtable.now) |clock| clock(p.host.ctx) else p.now_ns; +} /// Sends the Enters a paste into pane `id`'s REPL is owed: when the REPL -/// has answered it (`answered`), or once the wait is up. +/// has answered it (`answered`), or once the wait is up. Python's answer +/// only restarts a short wait, so the Enter goes once its echo of the +/// whole paste is in (a multi-line paste read in part would leave it at +/// `...`). pub fn flushReplEnter(p: *Pardes, id: usize, answered: bool) void { const pane = p.panes[id] orelse return; if (pane.repl_enter == 0) return; + if (answered and (if (pane.repl) |r| r.lang == python_lang else false)) { + pane.repl_enter_due_ns = clockNow(p) + repl_quiet_ns; + return; + } if (!answered and p.now_ns < pane.repl_enter_due_ns) return; for (0..pane.repl_enter) |_| p.emitWrite(id, "\r"); pane.repl_enter = 0; @@ -492,7 +508,11 @@ pub fn sendToRepl(p: *Pardes, from: usize, to: usize, text: []const u8) void { // A Python block whose last line is indented, or a bare header, is not // over at one Enter, pasted into 3.13's REPL or typed into the old one: // the blank line a second Enter gives ends it. - const enters: u8 = if ((if (dst.repl) |r| r.lang == python_lang else false) and pythonBlockOpen(clean[0..n])) 2 else 1; + // So is a paste of more than one line: 3.13's REPL takes it as one + // input, which one Enter leaves at `...`. + const python = if (dst.repl) |r| r.lang == python_lang else false; + const lines = std.mem.count(u8, std.mem.trim(u8, clean[0..n], " \t\n"), "\n") + 1; + const enters: u8 = if (python and (pythonBlockOpen(clean[0..n]) or (pasted and lines > 1))) 2 else 1; if (pasted) { // An Enter read with the paste is part of it: 3.13's REPL takes it // as a newline in the pasted text, even a one-line one, and waits. @@ -503,8 +523,7 @@ pub fn sendToRepl(p: *Pardes, from: usize, to: usize, text: []const u8) void { // nobody watches), `stepped_ns` and `now_ns` are as old as the last // frame, and a wait counted from there would be over already, the // Enter going out with the paste. - const now = if (p.host.vtable.now) |clock| clock(p.host.ctx) else p.now_ns; - dst.repl_enter_due_ns = now + repl_enter_wait_ns; + dst.repl_enter_due_ns = clockNow(p) + repl_enter_wait_ns; } else for (0..enters) |_| p.emitWrite(to, "\r"); // Line by line, a blank line inside a Python block ends the block. if (!panes.Terminal.bracketedPaste(dst) and !dst.repl_warned and (if (dst.repl) |r| r.lang == python_lang else false) and diff --git a/src/pardes.zig b/src/pardes.zig index d6859f86..289dcee0 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -1652,7 +1652,21 @@ test "a REPL bound for a language takes the exec made on a body in it; tags, Exe try std.testing.expectEqualStrings("\x1b[200~print(1)\x1b[201~", Sent.said(1)); p.update(.{ .output = .{ .pane = 1, .bytes = "print(1)" } }); Sent.drain(p); + // Python's echo only restarts a short wait: the Enter goes once the + // echo of the whole paste has gone quiet. + try std.testing.expectEqualStrings("", Sent.said(1)); + p.now_ns = p.panes[1].?.repl_enter_due_ns; + p.update(.tick); + Sent.drain(p); try std.testing.expectEqualStrings("\r", Sent.said(1)); + // A paste of more than one line gets the blank line a block gets. + _ = exec.executeFrom(p, 0, "print(11)\nprint(22)", true); + Sent.drain(p); + try std.testing.expectEqualStrings("\x1b[200~print(11)\nprint(22)\x1b[201~", Sent.said(1)); + p.now_ns = p.panes[1].?.repl_enter_due_ns; + p.update(.tick); + Sent.drain(p); + try std.testing.expectEqualStrings("\r\r", Sent.said(1)); // Nothing answering, it goes when its wait is up. _ = exec.executeFrom(p, 0, "print(2)", true); p.update(.tick); // on the clock: not yet, however old core time is |
