summaryrefslogtreecommitdiff
path: root/src/exec.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/exec.zig')
-rw-r--r--src/exec.zig27
1 files changed, 23 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