From 197819db6dab174c1bdd6e1481e71253171b45c1 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Fri, 9 Mar 2018 22:15:06 -0800 Subject: [PATCH] Add basic support for ICH which is used by bash CTRL-R --- term/src/csi.rs | 6 ++++++ term/src/screen.rs | 8 ++++++++ term/src/terminalstate.rs | 14 ++++++++++++++ term/src/test/csi.rs | 14 ++++++++++++++ 4 files changed, 42 insertions(+) diff --git a/term/src/csi.rs b/term/src/csi.rs index 0b3f9b01c..3f5e653ea 100644 --- a/term/src/csi.rs +++ b/term/src/csi.rs @@ -59,6 +59,7 @@ pub enum CSIAction { SoftReset, EraseCharacter(i64), DeleteCharacter(i64), + InsertCharacter(i64), } /// Constrol Sequence Initiator (CSI) Parser. @@ -430,6 +431,11 @@ impl<'a> Iterator for CSIParser<'a> { #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))] match (self.byte, self.intermediates, params) { (_, _, None) => None, + + // ICH: Insert Character + ('@', &[], Some(&[])) => Some(CSIAction::InsertCharacter(1)), + ('@', &[], Some(&[n])) => Some(CSIAction::InsertCharacter(n)), + // CUU - Cursor Up n times ('A', &[], Some(&[])) => Some(CSIAction::SetCursorXY { x: Position::Relative(0), diff --git a/term/src/screen.rs b/term/src/screen.rs index 3514ffaf8..e0b5ea59c 100644 --- a/term/src/screen.rs +++ b/term/src/screen.rs @@ -100,9 +100,17 @@ impl Screen { self.lines.iter().map(|l| l.clone()).collect() } + pub fn insert_cell(&mut self, x: usize, y: VisibleRowIndex) { + let line_idx = self.phys_row(y); + let line = self.line_mut(line_idx); + line.invalidate_implicit_links(); + line.cells.insert(x, Cell::default()); + } + pub fn erase_cell(&mut self, x: usize, y: VisibleRowIndex) { let line_idx = self.phys_row(y); let line = self.line_mut(line_idx); + line.invalidate_implicit_links(); line.cells.remove(x); line.cells.push(Cell::default()); } diff --git a/term/src/terminalstate.rs b/term/src/terminalstate.rs index 611d4b329..735989346 100644 --- a/term/src/terminalstate.rs +++ b/term/src/terminalstate.rs @@ -1034,6 +1034,20 @@ impl TerminalState { } self.clear_selection_if_intersects(x..limit, y as ScrollbackOrVisibleRowIndex); } + CSIAction::InsertCharacter(n) => { + let y = self.cursor.y; + let x = self.cursor.x; + // TODO: this limiting behavior may not be correct. There's also a + // SEM sequence that impacts the scope of ICH and ECH to consider. + let limit = (x + n as usize).min(self.screen().physical_cols); + { + let screen = self.screen_mut(); + for x in x..limit as usize { + screen.insert_cell(x, y); + } + } + self.clear_selection_if_intersects(x..limit, y as ScrollbackOrVisibleRowIndex); + } CSIAction::EraseCharacter(n) => { let y = self.cursor.y; let x = self.cursor.x; diff --git a/term/src/test/csi.rs b/term/src/test/csi.rs index 6ae8ceb52..c5868444f 100644 --- a/term/src/test/csi.rs +++ b/term/src/test/csi.rs @@ -19,6 +19,20 @@ fn test_vpa() { term.assert_cursor_pos(0, 1, None); } +#[test] +fn test_ich() { + let mut term = TestTerm::new(3, 4, 0); + term.print("hey!wat?"); + term.cup(1, 0); + term.print("\x1b[2@"); + assert_visible_contents(&term, &["h ey!", "wat?", " "]); + // check how we handle overflowing the width + term.print("\x1b[12@"); + assert_visible_contents(&term, &["h ey!", "wat?", " "]); + term.print("\x1b[-12@"); + assert_visible_contents(&term, &["h ey!", "wat?", " "]); +} + #[test] fn test_ech() { let mut term = TestTerm::new(3, 4, 0);