use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
const PASTE_START: &str = "\x1b[200~";
const PASTE_END: &str = "\x1b[201~";
pub fn encode_paste(text: &str, bracketed: bool) -> Vec<u8> {
let normalized = text.replace("\r\n", "\r").replace('\n', "\r");
let safe = normalized.replace(PASTE_START, "").replace(PASTE_END, "");
let mut out = Vec::with_capacity(safe.len() + PASTE_START.len() + PASTE_END.len());
if bracketed {
out.extend_from_slice(PASTE_START.as_bytes());
}
out.extend_from_slice(safe.as_bytes());
if bracketed {
out.extend_from_slice(PASTE_END.as_bytes());
}
out
}
pub fn paste_to_keys(text: &str) -> Vec<KeyEvent> {
let mut keys = Vec::new();
let mut chars = text.chars().peekable();
while let Some(c) = chars.next() {
let code = match c {
'\r' => {
if chars.peek() == Some(&'\n') {
chars.next();
}
KeyCode::Enter
}
'\n' => KeyCode::Enter,
'\t' => KeyCode::Tab,
other => KeyCode::Char(other),
};
keys.push(KeyEvent::new(code, KeyModifiers::NONE));
}
keys
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn encode_wraps_only_when_bracketed() {
assert_eq!(encode_paste("abc", false), b"abc".to_vec());
assert_eq!(encode_paste("abc", true), b"\x1b[200~abc\x1b[201~".to_vec());
}
#[test]
fn encode_normalizes_newlines_to_cr() {
assert_eq!(encode_paste("a\r\nb\nc", false), b"a\rb\rc".to_vec());
}
#[test]
fn encode_strips_embedded_markers() {
let hostile = "a\x1b[201~rm -rf\x1b[200~b";
assert_eq!(
encode_paste(hostile, true),
b"\x1b[200~arm -rfb\x1b[201~".to_vec()
);
}
#[test]
fn paste_to_keys_maps_chars_and_newlines() {
let keys = paste_to_keys("ab\r\nc");
let codes: Vec<KeyCode> = keys.iter().map(|k| k.code).collect();
assert_eq!(
codes,
vec![
KeyCode::Char('a'),
KeyCode::Char('b'),
KeyCode::Enter,
KeyCode::Char('c'),
]
);
}
}