Fix terminal bracketed paste handling
Authored by
mfwolffe <wolffemf@dukes.jmu.edu>
- SHA
496c7e27d69625a7a2a4f0fff578586890f076bd- Parents
-
d8851a8 - Tree
fe7dd4a
496c7e2
496c7e27d69625a7a2a4f0fff578586890f076bdd8851a8
fe7dd4a| Status | File | + | - |
|---|---|---|---|
| M |
src/editor/state.rs
|
1 | 1 |
| M |
src/terminal/panel.rs
|
39 | 0 |
| M |
src/terminal/screen.rs
|
5 | 0 |
src/editor/state.rsmodified@@ -1775,7 +1775,7 @@ impl Editor { | ||
| 1775 | 1775 | |
| 1776 | 1776 | // Route paste to terminal when terminal has focus. |
| 1777 | 1777 | if self.focus == Focus::Terminal && self.terminal.visible { |
| 1778 | - self.terminal.send_input(text.as_bytes())?; | |
| 1778 | + self.terminal.send_paste(text.as_bytes())?; | |
| 1779 | 1779 | return Ok(()); |
| 1780 | 1780 | } |
| 1781 | 1781 | |
src/terminal/panel.rsmodified@@ -73,6 +73,16 @@ impl TerminalSession { | ||
| 73 | 73 | Ok(()) |
| 74 | 74 | } |
| 75 | 75 | |
| 76 | + /// Send pasted input, honoring bracketed paste mode when requested by the app. | |
| 77 | + fn send_paste(&mut self, data: &[u8]) -> Result<()> { | |
| 78 | + let payload = if self.screen.bracketed_paste_enabled() { | |
| 79 | + encode_bracketed_paste(data) | |
| 80 | + } else { | |
| 81 | + data.to_vec() | |
| 82 | + }; | |
| 83 | + self.send_input(&payload) | |
| 84 | + } | |
| 85 | + | |
| 76 | 86 | /// Resize this session |
| 77 | 87 | fn resize(&mut self, width: u16, height: u16) { |
| 78 | 88 | self.screen.resize(width, height); |
@@ -227,6 +237,14 @@ impl TerminalPanel { | ||
| 227 | 237 | Ok(()) |
| 228 | 238 | } |
| 229 | 239 | |
| 240 | + /// Send pasted input to the active terminal session. | |
| 241 | + pub fn send_paste(&mut self, data: &[u8]) -> Result<()> { | |
| 242 | + if let Some(session) = self.sessions.get_mut(self.active_session) { | |
| 243 | + session.send_paste(data)?; | |
| 244 | + } | |
| 245 | + Ok(()) | |
| 246 | + } | |
| 247 | + | |
| 230 | 248 | /// Send a key to the active terminal |
| 231 | 249 | pub fn send_key(&mut self, key: &crossterm::event::KeyEvent) -> Result<()> { |
| 232 | 250 | use crossterm::event::{KeyCode, KeyModifiers}; |
@@ -394,3 +412,24 @@ impl TerminalPanel { | ||
| 394 | 412 | } |
| 395 | 413 | } |
| 396 | 414 | } |
| 415 | + | |
| 416 | +fn encode_bracketed_paste(data: &[u8]) -> Vec<u8> { | |
| 417 | + let mut wrapped = Vec::with_capacity(data.len() + 12); | |
| 418 | + wrapped.extend_from_slice(b"\x1b[200~"); | |
| 419 | + wrapped.extend_from_slice(data); | |
| 420 | + wrapped.extend_from_slice(b"\x1b[201~"); | |
| 421 | + wrapped | |
| 422 | +} | |
| 423 | + | |
| 424 | +#[cfg(test)] | |
| 425 | +mod tests { | |
| 426 | + use super::encode_bracketed_paste; | |
| 427 | + | |
| 428 | + #[test] | |
| 429 | + fn bracketed_paste_wraps_raw_bytes() { | |
| 430 | + assert_eq!( | |
| 431 | + encode_bracketed_paste(b"line 1\nline 2"), | |
| 432 | + b"\x1b[200~line 1\nline 2\x1b[201~" | |
| 433 | + ); | |
| 434 | + } | |
| 435 | +} | |
src/terminal/screen.rsmodified@@ -209,6 +209,11 @@ impl TerminalScreen { | ||
| 209 | 209 | std::mem::take(&mut self.response_queue) |
| 210 | 210 | } |
| 211 | 211 | |
| 212 | + /// Whether the application running in the terminal has enabled bracketed paste. | |
| 213 | + pub fn bracketed_paste_enabled(&self) -> bool { | |
| 214 | + self.bracketed_paste | |
| 215 | + } | |
| 216 | + | |
| 212 | 217 | /// Enter alternate screen buffer |
| 213 | 218 | fn enter_alt_screen(&mut self) { |
| 214 | 219 | if !self.using_alt_screen { |