From 63bcb4601198790ccdb96ffec4a360ce3080e685 Mon Sep 17 00:00:00 2001 From: Joe Wilm Date: Thu, 15 Jun 2017 21:43:28 -0700 Subject: Implement semantic and line selection dragging Unlike the regular selection that is by cell, these selection modes highlight either semantic groupings or entire lines while the mouse is dragged. --- src/term/mod.rs | 133 ++++++++++++++++++++++++++------------------------------ 1 file changed, 61 insertions(+), 72 deletions(-) (limited to 'src/term') diff --git a/src/term/mod.rs b/src/term/mod.rs index bbc3f1aa..1a79d309 100644 --- a/src/term/mod.rs +++ b/src/term/mod.rs @@ -25,7 +25,7 @@ use unicode_width::UnicodeWidthChar; use ansi::{self, Color, NamedColor, Attr, Handler, CharsetIndex, StandardCharset, CursorStyle}; use grid::{BidirectionalIterator, Grid, ClearRegion, ToRange, Indexed}; use index::{self, Point, Column, Line, Linear, IndexRange, Contains, RangeInclusive, Side}; -use selection::{Span, Selection}; +use selection::{self, Span, Selection}; use config::{Config, VisualBellAnimation}; use Rgb; @@ -34,6 +34,55 @@ pub mod color; pub use self::cell::Cell; use self::cell::LineLength; +impl<'a> selection::SemanticSearch for &'a Term { + fn semantic_search_left(&self, mut point: Point) -> Point { + let mut iter = self.grid.iter_from(point); + let last_col = self.grid.num_cols() - Column(1); + + while let Some(cell) = iter.prev() { + if self.semantic_escape_chars.contains(cell.c) { + break; + } + + if iter.cur.col == last_col && !cell.flags.contains(cell::WRAPLINE) { + break; // cut off if on new line or hit escape char + } + + point = iter.cur; + } + + point + } + + fn semantic_search_right(&self, mut point: Point) -> Point { + let mut iter = self.grid.iter_from(point); + let last_col = self.grid.num_cols() - Column(1); + + while let Some(cell) = iter.next() { + if self.semantic_escape_chars.contains(cell.c) { + break; + } + + point = iter.cur; + + if iter.cur.col == last_col && !cell.flags.contains(cell::WRAPLINE) { + break; // cut off if on new line or hit escape char + } + } + + point + } +} + +impl<'a> selection::Dimensions for &'a Term { + fn dimensions(&self) -> Point { + Point { + col: self.grid.num_cols(), + line: self.grid.num_lines() + } + } +} + /// Iterator that yields cells needing render /// /// Yields cells that require work to be displayed (that is, not a an empty @@ -66,12 +115,9 @@ impl<'a> RenderableCellsIter<'a> { colors: &'b color::List, mode: TermMode, config: &'b Config, - selection: &Selection, + selection: Option>, cursor_style: CursorStyle, ) -> RenderableCellsIter<'b> { - let selection = selection.span() - .map(|span| span.to_range(grid.num_cols())); - let cursor_index = Linear(cursor.line.0 * grid.num_cols().0 + cursor.col.0); RenderableCellsIter { @@ -737,64 +783,6 @@ impl Term { self.dirty } - pub fn line_selection(&self, selection: &mut Selection, point: Point) { - selection.clear(); - selection.update(Point { - line: point.line, - col: Column(0), - }, Side::Left); - selection.update(Point { - line: point.line, - col: self.grid.num_cols() - Column(1), - }, Side::Right); - } - - pub fn semantic_selection(&self, selection: &mut Selection, point: Point) { - let mut side_left = Point { - line: point.line, - col: point.col - }; - let mut side_right = Point { - line: point.line, - col: point.col - }; - - let mut left_iter = self.grid.iter_from(point); - let mut right_iter = self.grid.iter_from(point); - - let last_col = self.grid.num_cols() - Column(1); - - while let Some(cell) = left_iter.prev() { - if self.semantic_escape_chars.contains(cell.c) { - break; - } - - if left_iter.cur.col == last_col && !cell.flags.contains(cell::WRAPLINE) { - break; // cut off if on new line or hit escape char - } - - side_left.col = left_iter.cur.col; - side_left.line = left_iter.cur.line; - } - - while let Some(cell) = right_iter.next() { - if self.semantic_escape_chars.contains(cell.c) { - break; - } - - side_right.col = right_iter.cur.col; - side_right.line = right_iter.cur.line; - - if right_iter.cur.col == last_col && !cell.flags.contains(cell::WRAPLINE) { - break; // cut off if on new line or hit escape char - } - } - - selection.clear(); - selection.update(side_left, Side::Left); - selection.update(side_right, Side::Right); - } - pub fn string_from_selection(&self, span: &Span) -> String { /// Need a generic push() for the Append trait trait PushChar { @@ -882,7 +870,7 @@ impl Term { let mut res = String::new(); - let (start, end) = span.to_locations(self.grid.num_cols()); + let (start, end) = span.to_locations(); let line_count = end.line - start.line; match line_count { @@ -944,8 +932,11 @@ impl Term { pub fn renderable_cells<'b>( &'b self, config: &'b Config, - selection: &'b Selection + selection: Option<&'b Selection>, ) -> RenderableCellsIter { + let selection = selection.and_then(|s| s.to_span(self)) + .map(|span| span.to_range()); + RenderableCellsIter::new( &self.grid, &self.cursor.point, @@ -1850,19 +1841,19 @@ mod tests { mem::swap(&mut term.semantic_escape_chars, &mut escape_chars); { - let mut selection = Selection::new(); + let mut selection = Selection::new(grid.num_lines(), grid.num_cols()); term.semantic_selection(&mut selection, Point { line: Line(0), col: Column(1) }); assert_eq!(term.string_from_selection(&selection.span().unwrap()), "aa"); } { - let mut selection = Selection::new(); + let mut selection = Selection::new(grid.num_lines(), grid.num_cols()); term.semantic_selection(&mut selection, Point { line: Line(0), col: Column(4) }); assert_eq!(term.string_from_selection(&selection.span().unwrap()), "aaa"); } { - let mut selection = Selection::new(); + let mut selection = Selection::new(grid.num_lines(), grid.num_cols()); term.semantic_selection(&mut selection, Point { line: Line(1), col: Column(1) }); assert_eq!(term.string_from_selection(&selection.span().unwrap()), "aaa"); } @@ -1889,7 +1880,7 @@ mod tests { mem::swap(&mut term.grid, &mut grid); - let mut selection = Selection::new(); + let mut selection = Selection::new(grid.num_lines(), grid.num_cols()); term.line_selection(&mut selection, Point { line: Line(0), col: Column(3) }); match selection.span() { Some(span) => assert_eq!(term.string_from_selection(&span), "\"aa\"a"), @@ -1944,7 +1935,6 @@ mod benches { use std::path::Path; use grid::Grid; - use selection::Selection; use config::Config; use super::{SizeInfo, Term}; @@ -1983,13 +1973,12 @@ mod benches { let size: SizeInfo = json::from_str(&serialized_size).unwrap(); let config = Config::default(); - let selection = Selection::Empty; let mut terminal = Term::new(&config, size); mem::swap(&mut terminal.grid, &mut grid); b.iter(|| { - let iter = terminal.renderable_cells(&config, &selection); + let iter = terminal.renderable_cells(&config, None); for cell in iter { test::black_box(cell); } -- cgit v1.2.3-54-g00ecf