#11383

Pasted ANSI leaves escape-sequence corpses in the prompt, and an unterminated bracketed paste wedges the editor (Ctrl+C dead)

Opengiovannipapiniopened 14d ago

What

Pasting terminal output that contains ANSI escapes puts the escape bodies into the prompt as literal text, and an unterminated bracketed paste leaves the editor unable to accept any input — Ctrl+C included.

Why

pi-tui 1.4.0, components/editor.ts:

handlePaste() filters pasted text per character:

let filteredText = cleanText
  .split("")
  .filter((char) => char === "\n" || char.charCodeAt(0) >= 32)
  .join("");

ESC (0x1b) is dropped and the rest of the sequence is kept, so \x1b[38;2;111;63;32m is inserted as the visible text [38;2;111;63;32m, and \x1b[<35;153;17M as [<35;153;17M. A pasted screenful of coloured/mouse-reporting output turns into thousands of characters of that. The comment a few lines above already documents this same class of leak for tmux csi-u re-encoding.

handleInput() then handles isInPaste before every keybinding and returns:

if (this.isInPaste) {
    this.pasteBuffer += data;
    const endIndex = this.pasteBuffer.indexOf("\x1b[201~");
    if (endIndex !== -1) { ... }
    return;
}
...
if (kb.matches(data, "tui.input.copy")) {   // Ctrl+C, unreachable while isInPaste
    return;
}

If \x1b[201~ never arrives — another process on the same tty reads it first, the paste is cut short, or a split read loses it — every later keystroke, Ctrl+C included, is appended to pasteBuffer and dropped. The session cannot be typed into again; only a new paste (its own terminator closes the stale one) or killing the process recovers.

Repro

  1. Start pi in a pane whose tty is shared with another process that can read stdin — e.g. a sudo/SUDO_ASKPASS fallback doing read -rs … < /dev/tty, or a tool that hands the terminal to a child.
  2. Paste terminal output containing ANSI (truecolor SGR, SGR mouse reports).
  3. The escape bodies appear as literal text in the prompt. If the paste terminator was consumed by the other reader, the editor stops accepting input permanently and Ctrl+C does nothing.

Observed on macOS in a multiplexer pane (pi 1.4.0), where a password prompt owned the tty while the paste was in flight.

Suggested fix

  • Strip whole escape sequences (there is already a stripTerminalSequences helper) before the per-character filter, so a pasted ANSI stream degrades to plain text instead of escape corpses.
  • Bound isInPaste: clear it on an idle timeout or on a lone ESC, so one missing terminator cannot wedge the editor.

Activity

0

No activity yet.