1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//! Byte-frame builders for input that must reach the child PTY as a single
//! atomic write.
//!
//! The helpers here ([`bracketed_paste`](crate::frame::bracketed_paste) and
//! [`focus_report`](crate::frame::focus_report)) produce one
//! contiguous `Vec<u8>` / `&[u8]` per call. Correctness depends on that buffer
//! being delivered to the child's parser without being interleaved with other
//! writes. An `\x1b[200~` start marker followed by bytes from a different
//! paste corrupts parser state. Callers must deliver each returned frame as one
//! write.
/// CSI sequence that opens a bracketed-paste block (`ESC [ 2 0 0 ~`).
pub const BRACKETED_PASTE_START: & = b"\x1b[200~";
/// CSI sequence that closes a bracketed-paste block (`ESC [ 2 0 1 ~`).
pub const BRACKETED_PASTE_END: & = b"\x1b[201~";
/// Build the byte frame to send for a paste.
///
/// When `bracketed` is true, wraps the sanitized payload between
/// [`BRACKETED_PASTE_START`] and [`BRACKETED_PASTE_END`] so the child's
/// parser can distinguish pasted content from typed keystrokes. When false,
/// returns the sanitized payload bytes alone.
///
/// The payload is sanitized in both modes before assembly: any embedded
/// [`BRACKETED_PASTE_START`] or [`BRACKETED_PASTE_END`] sequence in `text`
/// is stripped, and C0 control bytes (`0x00..=0x1F`) other than `\t`, `\n`,
/// and `\r` are dropped. This keeps a hostile or malformed payload from
/// closing the bracketed region early or smuggling raw escape sequences
/// into the receiver, regardless of which mode the child requested.
///
/// When `bracketed` is false, every `\n` byte is rewritten to `\r`. Modern
/// shells treat the receiving end of a paste as typed input and only commit
/// a line on `\r`; an `\n` would be inserted as an extra blank line instead.
/// This matches the [xterm rule][xterm-ctlseqs] and applies unconditionally,
/// so `\r\n` is rewritten to `\r\r` and `\n\n` to `\r\r`. Inside a bracketed
/// block the receiver knows the content is pasted text and treats `\n` as
/// part of the payload, so the LF passes through unchanged.
///
/// [xterm-ctlseqs]: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
///
/// The returned `Vec<u8>` must be delivered to the PTY in a single write to
/// preserve parser state; see the module docs.
/// Build the focus-report byte sequence.
///
/// Returns `ESC [ I` when `gained` is true (focus gained) or `ESC [ O`
/// otherwise (focus lost). The child must have requested focus reporting
/// ([DECSET 1004][xterm-ctlseqs]) for these bytes to be meaningful.
///
/// [xterm-ctlseqs]: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html