diff options
author | Kirill Chibisov <contact@kchibisov.com> | 2020-06-26 19:04:55 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-26 16:04:55 +0000 |
commit | 8a39346b753528091ccd0c933a216db7f27a7321 (patch) | |
tree | 82fbbabf69511670c89de9e6702bf9caac730edc | |
parent | 6c8966f426552065f2846c0c1f555d02aba98141 (diff) | |
download | alacritty-8a39346b753528091ccd0c933a216db7f27a7321.tar.gz alacritty-8a39346b753528091ccd0c933a216db7f27a7321.zip |
Clear selection on clear line/screen escapes
Selection is now cleared if clear line or clear screen escape sequences
are clearing content behind it.
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rw-r--r-- | alacritty_terminal/src/grid/mod.rs | 5 | ||||
-rw-r--r-- | alacritty_terminal/src/selection.rs | 47 | ||||
-rw-r--r-- | alacritty_terminal/src/term/mod.rs | 31 |
4 files changed, 78 insertions, 6 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 65cc94e9..1af19d7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Set IUTF8 termios flag for improved UTF8 input support - Dragging files into terminal now adds a space after each path - Default binding replacement conditions +- Adjusted selection clearing granularity to more accurately match content ### Fixed diff --git a/alacritty_terminal/src/grid/mod.rs b/alacritty_terminal/src/grid/mod.rs index 5178ed99..fd555d1b 100644 --- a/alacritty_terminal/src/grid/mod.rs +++ b/alacritty_terminal/src/grid/mod.rs @@ -187,6 +187,11 @@ impl<T: GridCell + Default + PartialEq + Copy> Grid<T> { Point { line: self.lines.0 + self.display_offset - point.line.0 - 1, col: point.col } } + /// Return the cursor position in buffer coordinates. + pub fn cursor_buffer_point(&self) -> Point<usize> { + Point { line: self.lines.0 - self.cursor.point.line.0 - 1, col: self.cursor.point.col } + } + /// Update the size of the scrollback history. pub fn update_history(&mut self, history_size: usize) { let current_history_size = self.history_size(); diff --git a/alacritty_terminal/src/selection.rs b/alacritty_terminal/src/selection.rs index 7e1e108e..dbd11592 100644 --- a/alacritty_terminal/src/selection.rs +++ b/alacritty_terminal/src/selection.rs @@ -7,7 +7,7 @@ use std::convert::TryFrom; use std::mem; -use std::ops::Range; +use std::ops::{Bound, Range, RangeBounds}; use crate::index::{Column, Line, Point, Side}; use crate::term::{Search, Term}; @@ -193,6 +193,30 @@ impl Selection { } } + /// Check whether selection contains any point in a given range. + pub fn intersects_range<R: RangeBounds<usize>>(&self, range: R) -> bool { + let mut start = self.region.start.point.line; + let mut end = self.region.end.point.line; + + if Self::points_need_swap(self.region.start.point, self.region.end.point) { + mem::swap(&mut start, &mut end); + } + + let range_start = match range.start_bound() { + Bound::Included(&range_start) => range_start, + Bound::Excluded(&range_start) => range_start.saturating_add(1), + Bound::Unbounded => 0, + }; + + let range_end = match range.end_bound() { + Bound::Included(&range_end) => range_end, + Bound::Excluded(&range_end) => range_end.saturating_sub(1), + Bound::Unbounded => usize::max_value(), + }; + + range_start <= start && range_end >= end + } + /// Expand selection sides to include all cells. pub fn include_all(&mut self) { let (start, end) = (self.region.start.point, self.region.end.point); @@ -217,7 +241,9 @@ impl Selection { let num_cols = grid.num_cols(); // Order start above the end. - let (mut start, mut end) = (self.region.start, self.region.end); + let mut start = self.region.start; + let mut end = self.region.end; + if Self::points_need_swap(start.point, end.point) { mem::swap(&mut start, &mut end); } @@ -643,4 +669,21 @@ mod tests { is_block: true, }); } + + #[test] + fn range_intersection() { + let mut selection = + Selection::new(SelectionType::Lines, Point::new(6, Column(1)), Side::Left); + selection.update(Point::new(3, Column(1)), Side::Right); + + assert!(selection.intersects_range(..)); + assert!(selection.intersects_range(2..)); + assert!(selection.intersects_range(2..=4)); + assert!(selection.intersects_range(2..=7)); + assert!(selection.intersects_range(4..=5)); + assert!(selection.intersects_range(5..8)); + + assert!(!selection.intersects_range(..=2)); + assert!(!selection.intersects_range(7..=8)); + } } diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs index 33d2e14e..77ad826a 100644 --- a/alacritty_terminal/src/term/mod.rs +++ b/alacritty_terminal/src/term/mod.rs @@ -1763,6 +1763,12 @@ impl<T: EventListener> Handler for Term<T> { } }, } + + let cursor_buffer_line = self.grid.cursor_buffer_point().line; + self.selection = self + .selection + .take() + .filter(|s| !s.intersects_range(cursor_buffer_line..=cursor_buffer_line)); } /// Set the indexed color value. @@ -1840,8 +1846,8 @@ impl<T: EventListener> Handler for Term<T> { trace!("Clearing screen: {:?}", mode); let template = self.grid.cursor.template; - // Remove active selections. - self.selection = None; + let num_lines = self.grid.num_lines().0; + let cursor_buffer_line = self.grid.cursor_buffer_point().line; match mode { ansi::ClearMode::Above => { @@ -1858,15 +1864,24 @@ impl<T: EventListener> Handler for Term<T> { for cell in &mut self.grid[cursor.line][..end] { cell.reset(&template); } + + self.selection = self + .selection + .take() + .filter(|s| !s.intersects_range(cursor_buffer_line..num_lines)); }, ansi::ClearMode::Below => { let cursor = self.grid.cursor.point; for cell in &mut self.grid[cursor.line][cursor.col..] { cell.reset(&template); } - if cursor.line < self.grid.num_lines() - 1 { + + if cursor.line.0 < num_lines - 1 { self.grid.region_mut((cursor.line + 1)..).each(|cell| cell.reset(&template)); } + + self.selection = + self.selection.take().filter(|s| !s.intersects_range(..=cursor_buffer_line)); }, ansi::ClearMode::All => { if self.mode.contains(TermMode::ALT_SCREEN) { @@ -1875,8 +1890,16 @@ impl<T: EventListener> Handler for Term<T> { let template = Cell { bg: template.bg, ..Cell::default() }; self.grid.clear_viewport(template); } + + self.selection = self.selection.take().filter(|s| !s.intersects_range(..num_lines)); + }, + ansi::ClearMode::Saved if self.grid.history_size() > 0 => { + self.grid.clear_history(); + + self.selection = self.selection.take().filter(|s| !s.intersects_range(num_lines..)); }, - ansi::ClearMode::Saved => self.grid.clear_history(), + // We have no history to clear. + ansi::ClearMode::Saved => (), } } |