diff options
author | Xiaoyu Yin <yin530@gmail.com> | 2017-01-14 17:53:48 -0800 |
---|---|---|
committer | Joe Wilm <jwilm@users.noreply.github.com> | 2017-02-07 21:04:18 -0800 |
commit | 92e1cec0880313d962d80bf16eca60cebb509eab (patch) | |
tree | 165d470ca13ab89dcf8b399b7491f3766b446ab2 /src/term/mod.rs | |
parent | 59295e44312b3936132965636e5fac92118e5c27 (diff) |
Semantic Selection
Fix tests and add line select
Refactor BidirectionalIter to remove if blocks
Allow for cells tagged with WRAPLINE to continue expanding the selection
Reorganize config into structs
Add test coverage that callbacks are called
Cleanup mouse config
- Uses Duration type for ClickHandler::threshold
- Removes `action` property from ClickHandler--this can be added in a
backwards compatible way later on
- Renames ClickState::DblClick to DoubleClick
fixup! Cleanup mouse config
Diffstat (limited to 'src/term/mod.rs')
-rw-r--r-- | src/term/mod.rs | 145 |
1 files changed, 140 insertions, 5 deletions
diff --git a/src/term/mod.rs b/src/term/mod.rs index 0dc5532c..b0ca2a59 100644 --- a/src/term/mod.rs +++ b/src/term/mod.rs @@ -20,8 +20,8 @@ use std::cmp::min; use std::io; use ansi::{self, Color, NamedColor, Attr, Handler, CharsetIndex, StandardCharset}; -use grid::{Grid, ClearRegion, ToRange}; -use index::{self, Point, Column, Line, Linear, IndexRange, Contains, RangeInclusive}; +use grid::{BidirectionalIterator, Grid, ClearRegion, ToRange}; +use index::{self, Point, Column, Line, Linear, IndexRange, Contains, RangeInclusive, Side}; use selection::{Span, Selection}; use config::{Config}; @@ -352,6 +352,8 @@ pub struct Term { /// Saved cursor from alt grid cursor_save_alt: Cursor, + + semantic_escape_chars: String, } /// Terminal size info @@ -436,11 +438,13 @@ impl Term { size_info: size, empty_cell: template, custom_cursor_colors: config.custom_cursor_colors(), + semantic_escape_chars: config.selection().semantic_escape_chars.clone(), } } pub fn update_config(&mut self, config: &Config) { - self.custom_cursor_colors = config.custom_cursor_colors() + self.custom_cursor_colors = config.custom_cursor_colors(); + self.semantic_escape_chars = config.selection().semantic_escape_chars.clone(); } #[inline] @@ -448,6 +452,64 @@ 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 { @@ -1283,12 +1345,85 @@ impl ansi::Handler for Term { mod tests { extern crate serde_json; - use super::{Term, limit, SizeInfo}; + use super::{Cell, Term, limit, SizeInfo}; + use term::cell; use grid::Grid; use index::{Point, Line, Column}; - use term::{Cell}; use ansi::{Handler, CharsetIndex, StandardCharset}; + use selection::Selection; + use std::mem; + + #[test] + fn semantic_selection_works() { + let size = SizeInfo { + width: 21.0, + height: 51.0, + cell_width: 3.0, + cell_height: 3.0, + }; + let mut term = Term::new(&Default::default(), size); + let mut grid: Grid<Cell> = Grid::new(Line(3), Column(5), &Cell::default()); + for i in 0..5 { + for j in 0..2 { + grid[Line(j)][Column(i)].c = 'a'; + } + } + grid[Line(0)][Column(0)].c = '"'; + grid[Line(0)][Column(3)].c = '"'; + grid[Line(1)][Column(2)].c = '"'; + grid[Line(0)][Column(4)].flags.insert(cell::WRAPLINE); + + let mut escape_chars = String::from("\""); + + mem::swap(&mut term.grid, &mut grid); + mem::swap(&mut term.semantic_escape_chars, &mut escape_chars); + + { + let mut selection = Selection::new(); + 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(); + 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(); + term.semantic_selection(&mut selection, Point { line: Line(1), col: Column(1) }); + assert_eq!(term.string_from_selection(&selection.span().unwrap()), "aaa"); + } + } + + #[test] + fn line_selection_works() { + let size = SizeInfo { + width: 21.0, + height: 51.0, + cell_width: 3.0, + cell_height: 3.0, + }; + let mut term = Term::new(&Default::default(), size); + let mut grid: Grid<Cell> = Grid::new(Line(1), Column(5), &Cell::default()); + for i in 0..5 { + grid[Line(0)][Column(i)].c = 'a'; + } + grid[Line(0)][Column(0)].c = '"'; + grid[Line(0)][Column(3)].c = '"'; + + + mem::swap(&mut term.grid, &mut grid); + + let mut selection = Selection::new(); + 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"), + _ => () + } + } /// Check that the grid can be serialized back and forth losslessly /// |