From c84cd0fdb0335fa873f397e95a0a728be0fe15f5 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Tue, 21 Jan 2020 00:56:10 +0100 Subject: 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. --- alacritty_terminal/src/term/mod.rs | 51 +++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 23 deletions(-) (limited to 'alacritty_terminal/src/term/mod.rs') 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 Search for Term { } } -impl selection::Dimensions for Term { - fn dimensions(&self) -> Point { - let line = if self.mode.contains(TermMode::ALT_SCREEN) { - self.grid.num_lines() - } else { - Line(self.grid.len()) - }; - Point { col: self.grid.num_cols(), line } - } -} - /// A key for caching cursor glyphs #[derive(Debug, Eq, PartialEq, Copy, Clone, Hash, Deserialize)] pub struct CursorKey { @@ -214,7 +203,7 @@ pub struct RenderableCellsIter<'a, C> { cursor_style: CursorStyle, config: &'a Config, colors: &'a color::List, - selection: Option, + selection: Option>, } impl<'a, C> RenderableCellsIter<'a, C> { @@ -225,30 +214,46 @@ impl<'a, C> RenderableCellsIter<'a, C> { fn new<'b, T>( term: &'b Term, config: &'b Config, - selection: Option, + selection: Option, mut cursor_style: CursorStyle, ) -> RenderableCellsIter<'b, C> { let grid = &term.grid; + let num_cols = grid.num_cols(); + let num_lines = grid.num_lines(); let cursor_offset = grid.line_to_offset(term.cursor.point.line); let inner = grid.display_iter(); - let selection_range = selection.map(|span| { + let selection_range = selection.and_then(|span| { let (limit_start, limit_end) = if span.is_block { (span.start.col, span.end.col) } else { - (Column(0), term.cols() - 1) + (Column(0), num_cols - 1) }; // Get on-screen lines of the selection's locations - let mut start = term.buffer_to_visible(span.start); - let mut end = term.buffer_to_visible(span.end); + let start = term.buffer_to_visible(span.start); + let end = term.buffer_to_visible(span.end); + + // Clamp visible selection to the viewport + let (mut start, mut end) = match (start, end) { + (Some(start), Some(end)) => (start, end), + (Some(start), None) => { + let end = Point::new(num_lines.0 - 1, num_cols - 1); + (start, end) + }, + (None, Some(end)) => { + let start = Point::new(0, Column(0)); + (start, end) + }, + (None, None) => return None, + }; // Trim start/end with partially visible block selection start.col = max(limit_start, start.col); end.col = min(limit_end, end.col); - SelectionRange::new(start.into(), end.into(), span.is_block) + Some(SelectionRange::new(start.into(), end.into(), span.is_block)) }); // Load cursor glyph @@ -256,7 +261,7 @@ impl<'a, C> RenderableCellsIter<'a, C> { let cursor_visible = term.mode.contains(TermMode::SHOW_CURSOR) && grid.contains(cursor); let cursor_key = if cursor_visible { let is_wide = - grid[cursor].flags.contains(Flags::WIDE_CHAR) && (cursor.col + 1) < grid.num_cols(); + grid[cursor].flags.contains(Flags::WIDE_CHAR) && (cursor.col + 1) < num_cols; Some(CursorKey { style: cursor_style, is_wide }) } else { // Use hidden cursor so text will not get inverted @@ -938,7 +943,7 @@ impl Term { /// Convert the active selection to a String. pub fn selection_to_string(&self) -> Option { let selection = self.grid.selection.clone()?; - let Span { start, end, is_block } = selection.to_span(self)?; + let SelectionRange { start, end, is_block } = selection.to_range(self)?; let mut res = String::new(); @@ -1019,7 +1024,7 @@ impl Term { self.grid.visible_to_buffer(point) } - pub fn buffer_to_visible(&self, point: impl Into>) -> Point { + pub fn buffer_to_visible(&self, point: impl Into>) -> Option> { self.grid.buffer_to_visible(point) } @@ -1043,7 +1048,7 @@ impl Term { /// background color. Cells with an alternate background color are /// considered renderable as are cells with any text content. pub fn renderable_cells<'b, C>(&'b self, config: &'b Config) -> RenderableCellsIter<'_, C> { - let selection = self.grid.selection.as_ref().and_then(|s| s.to_span(self)); + let selection = self.grid.selection.as_ref().and_then(|s| s.to_range(self)); let cursor = if self.is_focused || !config.cursor.unfocused_hollow() { self.cursor_style.unwrap_or(self.default_cursor_style) -- cgit