summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/exec.zig20
-rw-r--r--src/pardes.zig12
2 files changed, 31 insertions, 1 deletions
diff --git a/src/exec.zig b/src/exec.zig
index cd2b4089..7f2e0e1f 100644
--- a/src/exec.zig
+++ b/src/exec.zig
@@ -471,7 +471,25 @@ pub fn sendToRepl(p: *Pardes, from: usize, to: usize, text: []const u8) void {
const src = p.panes[from] orelse return;
var idbuf: [48]u8 = undefined;
const id = replId(&idbuf, dst);
- edit.typeToTty(p, to, dst, text);
+ // Lines end in \n alone (a \r\n would give Python a blank line that
+ // ends its block), and no ESC or other control byte but a tab goes: an
+ // ESC[201~ in the text would end a bracketed paste early.
+ const clean = p.scratch.allocator().alloc(u8, text.len) catch return;
+ var n: usize = 0;
+ for (text, 0..) |c, i| {
+ if (c == '\r') {
+ if (i + 1 < text.len and text[i + 1] == '\n') continue;
+ clean[n] = '\n';
+ } else if (c < ' ' and c != '\t' and c != '\n' or c == 0x7f) continue else clean[n] = c;
+ n += 1;
+ }
+ // Sent whole or not at all: a send cut short would leave the REPL in a
+ // paste, or with half a block.
+ if (n + 16 > p.writeRoom(to)) {
+ var said: [128]u8 = undefined;
+ return p.setMessage(from, std.fmt.bufPrint(&said, "Repl: {d} bytes is more than can be sent at once; send less", .{n}) catch "Repl: too long to send");
+ }
+ edit.typeToTty(p, to, dst, clean[0..n]);
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 std.mem.startsWith(u8, id, "python") and
diff --git a/src/pardes.zig b/src/pardes.zig
index 64c05fff..85eae10f 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -1487,6 +1487,10 @@ test "a REPL bound for a language takes the exec made on a body in it; tags, Exe
var line: [ctlfs.ctl.pane_text_cap]u8 = undefined;
try std.testing.expect(std.mem.endsWith(u8, ctlfs.ctl.paneText(p, p.panes[1].?, &line), " python-a "));
}
+ // What is sent is plain text: CRLF is LF, no ESC or other control.
+ _ = exec.executeFrom(p, 0, "a = 1\r\nb = \x1b[201~2", true);
+ Sent.drain(p);
+ try std.testing.expectEqualStrings("a = 1\rb = [201~2\r", Sent.said(1));
// Several selections executed at once: each is sent, not the first.
{
const text = try edit.flatSurface(p, &file.body);
@@ -4626,6 +4630,14 @@ pub const Pardes = struct {
if (off < bytes.len) p.parkPendingWrite(id, bytes[off..]);
}
+ /// How many bytes `emitWrite` can take for pane `id` now without
+ /// dropping any: the effects left, then what the pending buffer holds.
+ pub fn writeRoom(p: *const Pardes, id: usize) usize {
+ const pending = limits.pending_write_cap -| p.pending_write_bytes;
+ if (p.pending_write[id] != null) return pending;
+ return (p.effects.len - p.effects_len) * 64 + pending;
+ }
+
fn parkPendingWrite(p: *Pardes, id: usize, bytes: []const u8) void {
if (comptime limits.pending_write_cap == 0) return;
if (p.pending_write_bytes + bytes.len > limits.pending_write_cap) return;