diff options
author | Christian Duerr <contact@christianduerr.com> | 2020-01-21 00:56:10 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-21 00:56:10 +0100 |
commit | c84cd0fdb0335fa873f397e95a0a728be0fe15f5 (patch) | |
tree | b4fc5dc3dc19d2bdd92c4a3396b509e988c86e65 /alacritty_terminal | |
parent | 5e22512fe6a1a6a8e347c09bbc486408753bff95 (diff) |
Fix first cell when selection is off screen
Since the expansion of the selection was done after clamping it to the
grid, the selection would incorrectly move the clamped start over by one
cell when the start was to the right of the original column. By
resetting the side of the start point to `Left` before expanding, this
can be circumvented.
This also resolves a regression which broke backwards bracket selection.
Fixes #3223.
Diffstat (limited to 'alacritty_terminal')
-rw-r--r-- | alacritty_terminal/src/grid/mod.rs | 18 | ||||
-rw-r--r-- | alacritty_terminal/src/selection.rs | 567 | ||||
-rw-r--r-- | alacritty_terminal/src/term/mod.rs | 51 |
3 files changed, 317 insertions, 319 deletions
diff --git a/alacritty_terminal/src/grid/mod.rs b/alacritty_terminal/src/grid/mod.rs index 53f7ebea..9c26fac0 100644 --- a/alacritty_terminal/src/grid/mod.rs +++ b/alacritty_terminal/src/grid/mod.rs @@ -158,22 +158,16 @@ impl<T: GridCell + PartialEq + Copy> Grid<T> { } } - pub fn buffer_to_visible(&self, point: impl Into<Point<usize>>) -> Point<usize> { + pub fn buffer_to_visible(&self, point: impl Into<Point<usize>>) -> Option<Point<usize>> { let mut point = point.into(); - let offset = point.line.saturating_sub(self.display_offset); - - if point.line < self.display_offset { - point.col = self.num_cols(); - point.line = self.num_lines().0 - 1; - } else if offset >= *self.num_lines() { - point.col = Column(0); - point.line = 0; - } else { - point.line = self.lines.0 - offset - 1; + if point.line < self.display_offset || point.line >= self.display_offset + self.lines.0 { + return None; } - point + point.line = self.lines.0 + self.display_offset - point.line - 1; + + Some(point) } pub fn visible_to_buffer(&self, point: Point) -> Point<usize> { diff --git a/alacritty_terminal/src/selection.rs b/alacritty_terminal/src/selection.rs index 1c747d99..95614502 100644 --- a/alacritty_terminal/src/selection.rs +++ b/alacritty_terminal/src/selection.rs @@ -18,13 +18,55 @@ //! finalized when the button is released. The selection should be cleared //! when text is added/removed/scrolled on the screen. The selection should //! also be cleared if the user clicks off of the selection. +use std::convert::TryFrom; +use std::mem; use std::ops::Range; -use crate::index::{Column, Line, Point, Side}; +use crate::index::{Column, Point, Side}; use crate::term::cell::Flags; use crate::term::{Search, Term}; -/// Describes a region of a 2-dimensional area +/// A Point and side within that point. +#[derive(Debug, Clone, PartialEq)] +pub struct Anchor { + point: Point<usize>, + side: Side, +} + +impl Anchor { + fn new(point: Point<usize>, side: Side) -> Anchor { + Anchor { point, side } + } +} + +/// Represents a range of selected cells. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct SelectionRange<L = usize> { + /// Start point, top left of the selection. + pub start: Point<L>, + /// End point, bottom right of the selection. + pub end: Point<L>, + /// Whether this selection is a block selection. + pub is_block: bool, +} + +impl<L> SelectionRange<L> { + pub fn new(start: Point<L>, end: Point<L>, is_block: bool) -> Self { + Self { start, end, is_block } + } + + pub fn contains(&self, col: Column, line: L) -> bool + where + L: PartialEq + PartialOrd, + { + self.start.line <= line + && self.end.line >= line + && (self.start.col <= col || (self.start.line != line && !self.is_block)) + && (self.end.col >= col || (self.end.line != line && !self.is_block)) + } +} + +/// Describes a region of a 2-dimensional area. /// /// Used to track a text selection. There are three supported modes, each with its own constructor: /// [`simple`], [`semantic`], and [`lines`]. The [`simple`] mode precisely tracks which cells are @@ -43,96 +85,61 @@ use crate::term::{Search, Term}; #[derive(Debug, Clone, PartialEq)] pub enum Selection { Simple { - /// The region representing start and end of cursor movement + /// The region representing start and end of cursor movement. region: Range<Anchor>, }, Block { - /// The region representing start and end of cursor movement + /// The region representing start and end of cursor movement. region: Range<Anchor>, }, Semantic { - /// The region representing start and end of cursor movement - region: Range<Point<isize>>, + /// The region representing start and end of cursor movement. + region: Range<Point<usize>>, }, Lines { - /// The region representing start and end of cursor movement - region: Range<Point<isize>>, + /// The region representing start and end of cursor movement. + region: Range<Point<usize>>, }, } -/// A Point and side within that point. -#[derive(Debug, Clone, PartialEq)] -pub struct Anchor { - point: Point<isize>, - side: Side, -} - -impl Anchor { - fn new(point: Point<isize>, side: Side) -> Anchor { - Anchor { point, side } - } -} - -/// A type that has 2-dimensional boundaries -pub trait Dimensions { - /// Get the size of the area - fn dimensions(&self) -> Point; -} - impl Selection { - pub fn rotate(&mut self, offset: isize) { - match *self { - Selection::Simple { ref mut region } | Selection::Block { ref mut region } => { - region.start.point.line += offset; - region.end.point.line += offset; - }, - Selection::Semantic { ref mut region } | Selection::Lines { ref mut region } => { - region.start.line += offset; - region.end.line += offset; - }, - } - } - pub fn simple(location: Point<usize>, side: Side) -> Selection { Selection::Simple { - region: Range { - start: Anchor::new(location.into(), side), - end: Anchor::new(location.into(), side), - }, + region: Range { start: Anchor::new(location, side), end: Anchor::new(location, side) }, } } pub fn block(location: Point<usize>, side: Side) -> Selection { Selection::Block { - region: Range { - start: Anchor::new(location.into(), side), - end: Anchor::new(location.into(), side), - }, + region: Range { start: Anchor::new(location, side), end: Anchor::new(location, side) }, } } pub fn semantic(point: Point<usize>) -> Selection { - Selection::Semantic { region: Range { start: point.into(), end: point.into() } } + Selection::Semantic { region: Range { start: point, end: point } } } pub fn lines(point: Point<usize>) -> Selection { - Selection::Lines { region: Range { start: point.into(), end: point.into() } } + Selection::Lines { region: Range { start: point, end: point } } } pub fn update(&mut self, location: Point<usize>, side: Side) { - // Always update the `end`; can normalize later during span generation. - match *self { - Selection::Simple { ref mut region } | Selection::Block { ref mut region } => { - region.end = Anchor::new(location.into(), side); - }, - Selection::Semantic { ref mut region } | Selection::Lines { ref mut region } => { - region.end = location.into(); - }, + let (_, end) = self.points_mut(); + *end = location; + + if let Some((_, end_side)) = self.sides_mut() { + *end_side = side; } } + pub fn rotate(&mut self, offset: isize) { + let (start, end) = self.points_mut(); + start.line = usize::try_from(start.line as isize + offset).unwrap_or(0); + end.line = usize::try_from(end.line as isize + offset).unwrap_or(0); + } + pub fn is_empty(&self) -> bool { - match *self { + match self { Selection::Simple { ref region } => { let (start, end) = if Selection::points_need_swap(region.start.point, region.end.point) { @@ -165,266 +172,260 @@ impl Selection { } } - pub fn to_span<T>(&self, term: &Term<T>) -> Option<Span> { - // Get both sides of the selection - let (mut start, mut end) = match *self { - Selection::Simple { ref region } | Selection::Block { ref region } => { - (region.start.point, region.end.point) - }, - Selection::Semantic { ref region } | Selection::Lines { ref region } => { - (region.start, region.end) - }, - }; + /// Convert selection to grid coordinates. + pub fn to_range<T>(&self, term: &Term<T>) -> Option<SelectionRange> { + let grid = term.grid(); + let num_cols = grid.num_cols(); - // Order the start/end - let needs_swap = Selection::points_need_swap(start, end); - if needs_swap { - std::mem::swap(&mut start, &mut end); - } + // Get selection boundaries + let points = self.points(); + let (start, end) = (*points.0, *points.1); - // Clamp to visible region in grid/normal - let num_cols = term.dimensions().col; - let num_lines = term.dimensions().line.0 as isize; - let (start, end) = Selection::grid_clamp(start, end, num_lines, num_cols)?; + // Get selection sides, falling back to `Side::Left` if it will not be used + let sides = self.sides().unwrap_or((&Side::Left, &Side::Left)); + let (start_side, end_side) = (*sides.0, *sides.1); - let span = match *self { - Selection::Simple { ref region } => { - let (start_side, end_side) = if needs_swap { - (region.end.side, region.start.side) - } else { - (region.start.side, region.end.side) - }; + // Order start above the end + let (start, end) = if Self::points_need_swap(start, end) { + (Anchor { point: end, side: end_side }, Anchor { point: start, side: start_side }) + } else { + (Anchor { point: start, side: start_side }, Anchor { point: end, side: end_side }) + }; - self.span_simple(term, start, end, start_side, end_side) - }, - Selection::Block { ref region } => { - let (start_side, end_side) = if needs_swap { - (region.end.side, region.start.side) - } else { - (region.start.side, region.end.side) - }; + // Clamp to inside the grid buffer + let (start, end) = Self::grid_clamp(start, end, self.is_block(), grid.len()).ok()?; - self.span_block(start, end, start_side, end_side) - }, - Selection::Semantic { .. } => Selection::span_semantic(term, start, end), - Selection::Lines { .. } => Selection::span_lines(term, start, end), + let range = match self { + Self::Simple { .. } => self.range_simple(start, end, num_cols), + Self::Block { .. } => self.range_block(start, end), + Self::Semantic { .. } => Self::range_semantic(term, start.point, end.point), + Self::Lines { .. } => Self::range_lines(term, start.point, end.point), }; - // Expand selection across double-width cells - span.map(|mut span| { - let grid = term.grid(); - - // Helper for checking if cell at `point` contains `flag` - let flag_at = |point: Point<usize>, flag: Flags| -> bool { - grid[point.line][point.col].flags.contains(flag) - }; - - // Include all double-width cells and placeholders at top left of selection - if span.start.col < num_cols { - // Expand from wide char spacer to wide char - if span.start.line + 1 != grid.len() || span.start.col.0 != 0 { - let prev = span.start.sub(num_cols.0, 1, true); - if flag_at(span.start, Flags::WIDE_CHAR_SPACER) - && flag_at(prev, Flags::WIDE_CHAR) - { - span.start = prev; - } - } + // Expand selection across fullwidth cells + range.map(|range| Self::range_expand_fullwidth(term, range)) + } - // Expand from wide char to wide char spacer for linewrapping - if span.start.line + 1 != grid.len() || span.start.col.0 != 0 { - let prev = span.start.sub(num_cols.0, 1, true); - if (prev.line + 1 != grid.len() || prev.col.0 != 0) - && flag_at(prev, Flags::WIDE_CHAR_SPACER) - && !flag_at(prev.sub(num_cols.0, 1, true), Flags::WIDE_CHAR) - { - span.start = prev; - } + /// Expand the start/end of the selection range to account for fullwidth glyphs. + fn range_expand_fullwidth<T>(term: &Term<T>, mut range: SelectionRange) -> SelectionRange { + let grid = term.grid(); + let num_cols = grid.num_cols(); + + // Helper for checking if cell at `point` contains `flag` + let flag_at = |point: Point<usize>, flag: Flags| -> bool { + grid[point.line][point.col].flags.contains(flag) + }; + + // Include all double-width cells and placeholders at top left of selection + if range.start.col < num_cols { + // Expand from wide char spacer to wide char + if range.start.line + 1 != grid.len() || range.start.col.0 != 0 { + let prev = range.start.sub(num_cols.0, 1, true); + if flag_at(range.start, Flags::WIDE_CHAR_SPACER) && flag_at(prev, Flags::WIDE_CHAR) + { + range.start = prev; } } - // Include all double-width cells and placeholders at bottom right of selection - if span.end.line != 0 || span.end.col < num_cols { - // Expand from wide char spacer for linewrapping to wide char - if (span.end.line + 1 != grid.len() || span.end.col.0 != 0) - && flag_at(span.end, Flags::WIDE_CHAR_SPACER) - && !flag_at(span.end.sub(num_cols.0, 1, true), Flags::WIDE_CHAR) + // Expand from wide char to wide char spacer for linewrapping + if range.start.line + 1 != grid.len() || range.start.col.0 != 0 { + let prev = range.start.sub(num_cols.0, 1, true); + if (prev.line + 1 != grid.len() || prev.col.0 != 0) + && flag_at(prev, Flags::WIDE_CHAR_SPACER) + && !flag_at(prev.sub(num_cols.0, 1, true), Flags::WIDE_CHAR) { - span.end = span.end.add(num_cols.0, 1, true); + range.start = prev; } + } + } - // Expand from wide char to wide char spacer - if flag_at(span.end, Flags::WIDE_CHAR) { - span.end = span.end.add(num_cols.0, 1, true); - } + // Include all double-width cells and placeholders at bottom right of selection + if range.end.line != 0 || range.end.col < num_cols { + // Expand from wide char spacer for linewrapping to wide char + if (range.end.line + 1 != grid.len() || range.end.col.0 != 0) + && flag_at(range.end, Flags::WIDE_CHAR_SPACER) + && !flag_at(range.end.sub(num_cols.0, 1, true), Flags::WIDE_CHAR) + { + range.end = range.end.add(num_cols.0, 1, true); + } + + // Expand from wide char to wide char spacer + if flag_at(range.end, Flags::WIDE_CHAR) { + range.end = range.end.add(num_cols.0, 1, true); } + } - span - }) + range } // Bring start and end points in the correct order - fn points_need_swap(start: Point<isize>, end: Point<isize>) -> bool { + fn points_need_swap(start: Point<usize>, end: Point<usize>) -> bool { start.line < end.line || start.line == end.line && start.col > end.col } - // Clamp selection inside the grid to prevent out of bounds errors + /// Clamp selection inside grid to prevent OOB. fn grid_clamp( - mut start: Point<isize>, - mut end: Point<isize>, - lines: isize, - cols: Column, - ) -> Option<(Point<isize>, Point<isize>)> { - if start.line >= lines { - // Don't show selection above visible region - if end.line >= lines { - return None; + mut start: Anchor, + end: Anchor, + is_block: bool, + lines: usize, + ) -> Result<(Anchor, Anchor), ()> { + // Clamp selection inside of grid to prevent OOB + if start.point.line >= lines { + // Remove selection if it is fully out of the grid + if end.point.line >= lines { + return Err(()); } - // Clamp selection above viewport to visible region - start.line = lines - 1; - start.col = Column(0); - } - - if end.line < 0 { - // Don't show selection below visible region - if start.line < 0 { - return None; + // Clamp to grid if it is still partially visible + if !is_block { + start.side = Side::Left; + start.point.col = Column(0); } - - // Clamp selection below viewport to visible region - end.line = 0; - end.col = cols - 1; + start.point.line = lines - 1; } - Some((start, end)) + Ok((start, end)) } - fn span_semantic<T>(term: &T, start: Point<isize>, end: Point<isize>) -> Option<Span> - where - T: Search + Dimensions, - { - let (start, end) = if start == end { - if let Some(end) = term.bracket_search(start.into()) { - (start.into(), end) - } else { - (term.semantic_search_left(start.into()), term.semantic_search_right(end.into())) + fn range_semantic<T>( + term: &Term<T>, + mut start: Point<usize>, + mut end: Point<usize>, + ) -> Option<SelectionRange> { + if start == end { + if let Some(matching) = term.bracket_search(start) { + if (matching.line == start.line && matching.col < start.col) + || (matching.line > start.line) + { + start = matching; + } else { + end = matching; + } + + return Some(SelectionRange { start, end, is_block: false }); } - } else { - (term.semantic_search_left(start.into()), term.semantic_search_right(end.into())) - }; + } + + start = term.semantic_search_left(start); + end = term.semantic_search_right(end); - Some(Span { start, end, is_block: false }) + Some(SelectionRange { start, end, is_block: false }) } - fn span_lines<T>(term: &T, start: Point<isize>, end: Point<isize>) -> Option<Span> - where - T: Search, - { - let start = term.line_search_left(start.into()); - let end = term.line_search_right(end.into()); + fn range_lines<T>( + term: &Term<T>, + mut start: Point<usize>, + mut end: Point<usize>, + ) -> Option<SelectionRange> { + start = term.line_search_left(start); + end = term.line_search_right(end); - Some(Span { start, end, is_block: false }) + Some(SelectionRange { start, end, is_block: false }) } - fn span_simple<T>( + fn range_simple( &self, - term: &T, - mut start: Point<isize>, - mut end: Point<isize>, - start_side: Side, - end_side: Side, - ) -> Option<Span> - where - T: Dimensions, - { + mut start: Anchor, + mut end: Anchor, + num_cols: Column, + ) -> Option<SelectionRange> { if self.is_empty() { return None; } // Remove last cell if selection ends to the left of a cell - if end_side == Side::Left && start != end { + if end.side == Side::Left && start.point != end.point { // Special case when selection ends to left of first cell - if end.col == Column(0) { - end.col = term.dimensions().col - 1; - end.line += 1; + if end.point.col == Column(0) { + end.point.col = num_cols; + end.point.line += 1; } else { - end.col -= 1; + end.point.col -= 1; } } // Remove first cell if selection starts at the right of a cell - if start_side == Side::Right && start != end { - start.col += 1; + if start.side == Side::Right && start.point != end.point { + start.point.col += 1; } - // Return the selection with all cells inclusive - Some(Span { start: start.into(), end: end.into(), is_block: false }) + Some(SelectionRange { start: start.point, end: end.point, is_block: false }) } - fn span_block( - &self, - mut start: Point<isize>, - mut end: Point<isize>, - mut start_side: Side, - mut end_side: Side, - ) -> Option<Span> { + fn range_block(&self, mut start: Anchor, mut end: Anchor) -> Option<SelectionRange> { if self.is_empty() { return None; } // Always go top-left -> bottom-right - if start.col > end.col { - std::mem::swap(&mut start_side, &mut end_side); - std::mem::swap(&mut start.col, &mut end.col); + if start.point.col > end.point.col { + mem::swap(&mut start.side, &mut end.side); + mem::swap(&mut start.point.col, &mut end.point.col); } // Remove last cell if selection ends to the left of a cell - if end_side == Side::Left && start != end && end.col.0 > 0 { - end.col -= 1; + if end.side == Side::Left && start.point != end.point && end.point.col.0 > 0 { + end.point.col -= 1; } // Remove first cell if selection starts at the right of a cell - if start_side == Side::Right && start != end { - start.col += 1; + if start.side == Side::Right && start.point != end.point { + start.point.col += 1; } - // Return the selection with all cells inclusive - Some(Span { start: start.into(), end: end.into(), is_block: true }) + Some(SelectionRange { start: start.point, end: end.point, is_block: true }) } -} -/// Represents a span of selected cells -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Span { - /// Start point from bottom of buffer - pub start: Point<usize>, - /// End point towards top of buffer - pub end: Point<usize>, - /// Whether this selection is a block selection - pub is_block: bool, -} + fn points(&self) -> (&Point<usize>, &Point<usize>) { + match self { + Self::Simple { ref region } | Self::Block { ref region } => { + (®ion.start.point, ®ion.end.point) + }, + Self::Semantic { ref region } | Self::Lines { ref region } => { + (®ion.start, ®ion.end) + }, + } + } -pub struct SelectionRange { - start: Point, - end: Point, - is_block: bool, -} + fn points_mut(&mut self) -> (&mut Point<usize>, &mut Point<usize>) { + match self { + Self::Simple { ref mut region } | Self::Block { ref mut region } => { + (&mut region.start.point, &mut region.end.point) + }, + Self::Semantic { ref mut region } | Self::Lines { ref mut region } => { + (&mut region.start, &mut region.end) + }, + } + } -impl SelectionRange { - pub fn new(start: Point, end: Point, is_block: bool) -> Self { - Self { start, end, is_block } + fn sides(&self) -> Option<(&Side, &Side)> { + match self { + Self::Simple { ref region } | Self::Block { ref region } => { + Some((®ion.start.side, ®ion.end.side)) + }, + Self::Semantic { .. } | Self::Lines { .. } => None, + } } - pub fn contains(&self, col: Column, line: Line) -> bool { - self.start.line <= line - && self.end.line >= line - && (self.start.col <= col || (self.start.line != line && !self.is_block)) - && (self.end.col >= col || (self.end.line != line && !self.is_block)) + fn sides_mut(&mut self) -> Option<(&mut Side, &mut Side)> { + match self { + Self::Simple { ref mut region } | Self::Block { ref mut region } => { + Some((&mut region.start.side, &mut region.end.side)) + }, + Self::Semantic { .. } | Self::Lines { .. } => None, + } + } + + fn is_block(&self) -> bool { + match self { + Self::Block { .. } => true, + _ => false, + } } } -/// Tests for selection +/// Tests for selection. /// /// There are comments on all of the tests describing the selection. Pictograms /// are used to avoid ambiguity. Grid cells are represented by a [ ]. Only @@ -437,7 +438,7 @@ impl SelectionRange { mod test { use std::mem; - use super::{Selection, Span}; + use super::{Selection, SelectionRange}; use crate::clipboard::Clipboard; use crate::config::MockConfig; use crate::event::{Event, EventListener}; @@ -464,7 +465,7 @@ mod test { Term::new(&MockConfig::default(), &size, Clipboard::new_nop(), Mock) } - /// Test case of single cell selection + /// Test case of single cell selection. /// /// 1. [ ] /// 2. [B ] @@ -475,14 +476,14 @@ mod test { let mut selection = Selection::simple(location, Side::Left); selection.update(location, Side::Right); - assert_eq!(selection.to_span(&term(1, 1)).unwrap(), Span { + assert_eq!(selection.to_range(&term(1, 1)).unwrap(), SelectionRange { start: location, end: location, is_block: false }); } - /// Test case of single cell selection + /// Test case of single cell selection. /// /// 1. [ ] /// 2. [ B] @@ -493,14 +494,14 @@ mod test { let mut selection = Selection::simple(location, Side::Right); selection.update(location, Side::Left); - assert_eq!(selection.to_span(&term(1, 1)).unwrap(), Span { + assert_eq!(selection.to_range(&term(1, 1)).unwrap(), SelectionRange { start: location, end: location, is_block: false }); } - /// Test adjacent cell selection from left to right + /// Test adjacent cell selection from left to right. /// /// 1. [ ][ ] /// 2. [ B][ ] @@ -510,10 +511,10 @@ mod test { let mut selection = Selection::simple(Point::new(0, Column(0)), Side::Right); selection.update(Point::new(0, Column(1)), Side::Left); - assert_eq!(selection.to_span(&term(2, 1)), None); + assert_eq!(selection.to_range(&term(2, 1)), None); } - /// Test adjacent cell selection from right to left + /// Test adjacent cell selection from right to left. /// /// 1. [ ][ ] /// 2. [ ][B ] @@ -523,11 +524,10 @@ mod test { let mut selection = Selection::simple(Point::new(0, Column(1)), Side::Left); selection.update(Point::new(0, Column(0)), Side::Right); - assert_eq!(selection.to_span(&term(2, 1)), None); + assert_eq!(selection.to_range(&term(2, 1)), None); } - /// Test selection across adjacent lines - /// + /// Test selection across adjacent lines. /// /// 1. [ ][ ][ ][ ][ ] /// [ ][ ][ ][ ][ ] @@ -540,15 +540,14 @@ mod test { let mut selection = Selection::simple(Point::new(1, Column(1)), Side::Right); selection.update(Point::new(0, Column(1)), Side::Right); - assert_eq!(selection.to_span(&term(5, 2)).unwrap(), Span { + assert_eq!(selection.to_range(&term(5, 2)).unwrap(), SelectionRange { start: Point::new(1, Column(2)), end: Point::new(0, Column(1)), is_block: false, }); } - /// Test selection across adjacent lines - /// + /// Test selection across adjacent lines. /// /// 1. [ ][ ][ ][ ][ ] /// [ ][ ][ ][ ][ ] @@ -564,7 +563,7 @@ mod test { selection.update(Point::new(1, Column(1)), Side::Right); selection.update(Point::new(1, Column(0)), Side::Right); - assert_eq!(selection.to_span(&term(5, 2)).unwrap(), Span { + assert_eq!(selection.to_range(&term(5, 2)).unwrap(), SelectionRange { start: Point::new(1, Column(1)), end: Point::new(0, Column(1)), is_block: false, @@ -573,52 +572,52 @@ mod test { #[test] fn line_selection() { - let mut selection = Selection::lines(Point::new(0, Column(0))); - selection.update(Point::new(5, Column(3)), Side::Right); - selection.rotate(-3); + let mut selection = Selection::lines(Point::new(0, Column(1))); + selection.update(Point::new(5, Column(1)), Side::Right); + selection.rotate(7); - assert_eq!(selection.to_span(&term(5, 10)).unwrap(), Span { - start: Point::new(2, Column(0)), - end: Point::new(0, Column(4)), + assert_eq!(selection.to_range(&term(5, 10)).unwrap(), SelectionRange { + start: Point::new(9, Column(0)), + end: Point::new(7, Column(4)), is_block: false, }); } #[test] fn semantic_selection() { - let mut selection = Selection::semantic(Point::new(0, Column(0))); - selection.update(Point::new(5, Column(3)), Side::Right); - selection.rotate(-3); + let mut selection = Selection::semantic(Point::new(0, Column(3))); + selection.update(Point::new(5, Column(1)), Side::Right); + selection.rotate(7); - assert_eq!(selection.to_span(&term(5, 10)).unwrap(), Span { - start: Point::new(2, Column(3)), - end: Point::new(0, Column(4)), + assert_eq!(selection.to_range(&term(5, 10)).unwrap(), SelectionRange { + start: Point::new(9, Column(0)), + end: Point::new(7, Column(3)), is_block: false, }); } #[test] fn simple_selection() { - let mut selection = Selection::simple(Point::new(0, Column(0)), Side::Right); - selection.update(Point::new(5, Column(3)), Side::Right); - selection.rotate(-3); + let mut selection = Selection::simple(Point::new(0, Column(3)), Side::Right); + selection.update(Point::new(5, Column(1)), Side::Right); + selection.rotate(7); - assert_eq!(selection.to_span(&term(5, 10)).unwrap(), Span { - start: Point::new(2, Column(4)), - end: Point::new(0, Column(4)), + assert_eq!(selection.to_range(&term(5, 10)).unwrap(), SelectionRange { + start: Point::new(9, Column(0)), + end: Point::new(7, Column(3)), is_block: false, }); } #[test] fn block_selection() { - let mut selection = Selection::block(Point::new(0, Column(0)), Side::Right); - selection.update(Point::new(5, Column(3)), Side::Right); - selection.rotate(-3); + let mut selection = Selection::block(Point::new(0, Column(3)), Side::Right); + selection.update(Point::new(5, Column(1)), Side::Right); + selection.rotate(7); - assert_eq!(selection.to_span(&term(5, 10)).unwrap(), Span { - start: Point::new(2, Column(4)), - end: Point::new(0, Column(4)), + assert_eq!(selection.to_range(&term(5, 10)).unwrap(), SelectionRange { + start: Point::new(9, Column(2)), + end: Point::new(7, Column(3)), is_block: true }); } @@ -636,7 +635,7 @@ mod test { let mut selection = Selection::simple(Point::new(0, Column(1)), Side::Left); selection.update(Point::new(0, Column(8)), Side::Right); - assert_eq!(selection.to_span(&term).unwrap(), Span { + assert_eq!(selection.to_range(&term).unwrap(), SelectionRange { start: Point::new(0, Column(0)), end: Point::new(0, Column(9)), is_block: false, diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs index 9cd1f75b..e1f8fb30 100644 --- a/alacritty_terminal/src/term/mod.rs +++ b/alacritty_terminal/src/term/mod.rs @@ -32,7 +32,7 @@ use crate::grid::{ BidirectionalIterator, DisplayIter, Grid, GridCell, IndexRegion, Indexed, Scroll, }; use crate::index::{self, Column, IndexRange, Line, Point}; -use crate::selection::{self, Selection, SelectionRange, Span}; +use crate::selection::{Selection, SelectionRange}; use crate::term::cell::{Cell, Flags, LineLength}; use crate::term::color::Rgb; #[cfg(windows)] @@ -179,17 +179,6 @@ impl<T> Search for Term<T> { } } -impl<T> selection::Dimensions for Term<T> { - fn dimensions(&self) -> Point { - let line = if self.mode.contains(TermMode::ALT_SCREEN) { - self.grid.num_lines() - } else { - Line(self.grid.len()) - }; |