From 25e2dc2a9690d9d285ab5495a4da558abb08e50e Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Mon, 19 Feb 2018 16:26:10 -0800 Subject: [PATCH] fix an issue with the selection when in scrollback --- term/src/terminalstate.rs | 25 ++++++++++++------------- term/src/test/mod.rs | 28 ++++++++++++++++++++++++++++ term/src/test/selection.rs | 24 ++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/term/src/terminalstate.rs b/term/src/terminalstate.rs index 567d75f33..e054f1845 100644 --- a/term/src/terminalstate.rs +++ b/term/src/terminalstate.rs @@ -90,7 +90,7 @@ pub struct TerminalState { /// purely for display purposes. /// The offset is measured from the top of the physical viewable /// screen with larger numbers going backwards. - viewport_offset: VisibleRowIndex, + pub(crate) viewport_offset: VisibleRowIndex, /// Remembers the starting coordinate of the selection prior to /// dragging. @@ -281,13 +281,15 @@ impl TerminalState { self.selection_range = None; self.selection_start = Some(SelectionCoordinate { x: event.x, - y: event.y as ScrollbackOrVisibleRowIndex, + y: event.y as ScrollbackOrVisibleRowIndex - + self.viewport_offset as ScrollbackOrVisibleRowIndex, }); host.set_clipboard(None)?; } // Double click to select a word on the current line Some(&LastMouseClick { streak: 2, .. }) => { - let y = event.y as ScrollbackOrVisibleRowIndex; + let y = event.y as ScrollbackOrVisibleRowIndex - + self.viewport_offset as ScrollbackOrVisibleRowIndex; let idx = self.screen().scrollback_or_visible_row(y); let line = self.screen().lines[idx].as_str(); use unicode_segmentation::UnicodeSegmentation; @@ -324,18 +326,14 @@ impl TerminalState { } // triple click to select the current line Some(&LastMouseClick { streak: 3, .. }) => { - self.selection_start = Some(SelectionCoordinate { - x: event.x, - y: event.y as ScrollbackOrVisibleRowIndex, - }); + let y = event.y as ScrollbackOrVisibleRowIndex - + self.viewport_offset as ScrollbackOrVisibleRowIndex; + self.selection_start = Some(SelectionCoordinate { x: event.x, y }); self.selection_range = Some(SelectionRange { - start: SelectionCoordinate { - x: 0, - y: event.y as ScrollbackOrVisibleRowIndex, - }, + start: SelectionCoordinate { x: 0, y }, end: SelectionCoordinate { x: usize::max_value(), - y: event.y as ScrollbackOrVisibleRowIndex, + y, }, }); self.dirty_selection_lines(); @@ -395,7 +393,8 @@ impl TerminalState { self.dirty_selection_lines(); let end = SelectionCoordinate { x: event.x, - y: event.y as ScrollbackOrVisibleRowIndex, + y: event.y as ScrollbackOrVisibleRowIndex - + self.viewport_offset as ScrollbackOrVisibleRowIndex, }; let sel = match self.selection_range.take() { None => { diff --git a/term/src/test/mod.rs b/term/src/test/mod.rs index 6afd8f574..79be56add 100644 --- a/term/src/test/mod.rs +++ b/term/src/test/mod.rs @@ -204,6 +204,34 @@ impl TestTerm { reason ); } + + fn viewport_lines(&self) -> Vec { + let screen = self.screen(); + let line_count = screen.lines.len(); + let viewport = self.viewport_offset; + let phs_rows = screen.physical_rows; + screen + .all_lines() + .iter() + .skip((line_count as i64 - phs_rows as i64 - viewport) as usize) + .take(phs_rows) + .cloned() + .collect() + } + fn print_viewport_lines(&self) { + println!("viewport contents are:"); + for line in self.viewport_lines() { + println!("[{}]", line.as_str()); + } + } + + fn assert_viewport_contents(&self, expect_lines: &[&str]) { + self.print_viewport_lines(); + + let expect: Vec = expect_lines.iter().map(|s| (*s).into()).collect(); + + assert_lines_equal(&self.viewport_lines(), &expect, Compare::TEXT); + } } impl Deref for TestTerm { diff --git a/term/src/test/selection.rs b/term/src/test/selection.rs index 4c1e4cacf..2dd91ff05 100644 --- a/term/src/test/selection.rs +++ b/term/src/test/selection.rs @@ -62,3 +62,27 @@ fn triple_click_selection() { assert_eq!(term.get_clipboard().unwrap(), "hello worl"); } + +/// Make sure that we adjust for the viewport offset when scrolling +#[test] +fn selection_in_scrollback() { + let mut term = TestTerm::new(2, 1, 4); + term.print("1234"); + assert_all_contents(&term, &["1", "2", "3", "4"]); + + // Scroll back one line + term.scroll_viewport(-1); + term.assert_viewport_contents(&["2", "3"]); + + term.click_n(0, 0, MouseButton::Left, 2); + assert_eq!(term.get_clipboard().unwrap(), "2"); + + // Clear the click streak + term.click_n(0, 1, MouseButton::Right, 1); + + term.click_n(0, 1, MouseButton::Left, 3); + assert_eq!(term.get_clipboard().unwrap(), "3"); + + term.drag_select(0, 0, 0, 1); + assert_eq!(term.get_clipboard().unwrap(), "2\n3"); +}