From 505d15e238e4e9c5020a8e567d700bdbf67a8528 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Wed, 30 Sep 2026 14:23:50 -0300 Subject: A paste into a terminal is xterm's paste: bracketed when the program set 2004, and the control bytes a paste could smuggle a command in by, ESC first, become spaces, so no ESC[201~ in the text ends the brackets early Every paste path goes through edit.typeToTty (the GUI's and the tty's paste, p from a register, the acme chord's paste, a REPL's send), which now takes ghostty's paste encoder. A 9P write to a terminal's body or pty/data stays typed input, not a paste. The GUI test shell's stdin now takes a bracketed paste as one paste, as the tty does, not as keys. Co-Authored-By: Claude Opus 5.5 --- src/terminal.zig | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/terminal.zig') diff --git a/src/terminal.zig b/src/terminal.zig index af540202..4cdfa52d 100644 --- a/src/terminal.zig +++ b/src/terminal.zig @@ -380,6 +380,21 @@ pub fn reportsMouse(pane: *const Pane) bool { return state.vt.flags.mouse_event != .none; } +/// A paste as xterm makes one (ghostty's encoder): the control bytes a +/// paste could smuggle a command in by (ESC, so no ESC[201~ can end +/// 2004's brackets early, NUL, ^C and the rest of xterm's list) become +/// spaces, then the text goes inside the brackets when the program set +/// 2004, else with its newlines as Returns. `text` is rewritten in place. +pub fn encodePaste(pane: *const Pane, text: []u8) [3][]const u8 { + if (comptime !enabled) { + for (text) |*ch| if (ch.* == '\n') { + ch.* = '\r'; + }; + return .{ "", text, "" }; + } + return ghostty_vt.input.encodePaste(text, .{ .bracketed = bracketedPaste(pane) }); +} + /// DECSET 1004: the program wants to hear when it gains and loses focus. pub fn reportsFocus(pane: *const Pane) bool { if (comptime !enabled) return false; -- cgit v1.3