libghostty_vt/paste.rs
1//! Utilities for validating paste data safety.
2//!
3//! # Example
4//!
5//! ## Safety Check
6//!
7//! ```rust
8//! use libghostty_vt::paste;
9//!
10//! let safe_data = "hello world";
11//! let unsafe_data = "rm -rf /\n";
12//!
13//! if paste::is_safe(safe_data) {
14//! println!("Safe to paste");
15//! }
16//!
17//! if !paste::is_safe(unsafe_data) {
18//! println!("Unsafe! Contains newline");
19//! }
20//! ```
21//!
22//! ## Encoding
23//!
24//! ```rust
25//! use libghostty_vt::paste;
26//!
27//! let mut data = *b"hello\nworld";
28//! let mut buf = [0u8; 64];
29//!
30//! if let Ok(len) = paste::encode(&mut data, true, &mut buf) {
31//! println!("Encoded {len} bytes: {}", buf[..len].escape_ascii());
32//! }
33//! ```
34
35use crate::{
36 error::{Result, from_result_with_len},
37 ffi,
38};
39
40/// Check if paste data is safe to paste into the terminal.
41///
42/// Data is considered unsafe if it contains:
43/// * Newlines (`\n`) which can inject commands
44/// * The bracketed paste end sequence (`\x1b[201~`) which can be used to exit bracketed paste
45/// mode and inject commands
46///
47/// This check is conservative and considers data unsafe regardless of current terminal state.
48#[must_use]
49pub fn is_safe(data: &str) -> bool {
50 unsafe { ffi::ghostty_paste_is_safe(data.as_ptr().cast(), data.len()) }
51}
52
53/// Encode paste data for writing to the terminal pty.
54///
55/// This function prepares paste data for terminal input by:
56///
57/// - Stripping unsafe control bytes (NUL, ESC, DEL, etc.) by replacing them
58/// with spaces
59/// - Wrapping the data in bracketed paste sequences if `bracketed` is true
60/// - Replacing newlines with carriage returns if `bracketed` is false
61///
62/// The input `data` buffer is modified in place during encoding. The encoded
63/// result (potentially with bracketed paste prefix/suffix) is written to the
64/// output buffer.
65///
66/// If the output buffer is too small, the function returns
67/// `Err(Error::OutOfSpace { required })` where `required` is the required
68/// The caller can then retry with a sufficiently sized buffer.
69pub fn encode(data: &mut [u8], bracketed: bool, buf: &mut [u8]) -> Result<usize> {
70 let mut written = 0usize;
71 let result = unsafe {
72 ffi::ghostty_paste_encode(
73 data.as_mut_ptr().cast(),
74 data.len(),
75 bracketed,
76 buf.as_mut_ptr().cast(),
77 buf.len(),
78 &raw mut written,
79 )
80 };
81 from_result_with_len(result, written)
82}