aboutsummaryrefslogtreecommitdiff
path: root/src/term/mod.rs
diff options
context:
space:
mode:
authorJoe Wilm <joe@jwilm.com>2018-03-06 20:57:40 -0800
committerJoe Wilm <joe@jwilm.com>2018-03-07 09:51:51 -0800
commit143c28953cca8f2a1190c94f6e6944dad391dac7 (patch)
tree0eaa7794088041a37ef1e7c564926407c5c7eb56 /src/term/mod.rs
parent2cfdd595f11377fbd91536a428e87d949ed9a05e (diff)
downloadalacritty-143c28953cca8f2a1190c94f6e6944dad391dac7.tar.gz
alacritty-143c28953cca8f2a1190c94f6e6944dad391dac7.zip
Support selections with scrolling buffer
Selections now *mostly* work. They move as the buffer scrolls, copying works as it should, and it looks like the different selection modes behave properly as well. The new Selection implementation uses buffer coordinates instead of screen coordinates. This leads to doing a transform from mouse input to update the selection, and back to screen coordinates when displaying the selection. Scrolling the selection is fast because the grid is already operating in buffer coordinates. There are several bugs to address: * A _partially_ visible selection will lead to a crash since the drawing routine converts selection coordinates to screen coordinates. The solution will be to clip the coordinates at draw time. * A selection scrolling off the buffer in either direction leads to indexing out-of-bounds. The solution again is to clip, but this needs to be done within Selection::rotate by passing a max limit. It may also need a return type to indicate that the selection is no longer visible and should be discarded. * A selection scrolling out of a logical scrolling region is not clipped. A temporary and robust workaround is to simply discard the selection in the case of scrolling in a region. wip selections fix issue with line selection selection mostly working need to support selection not being on the screen at draw time Fix selection_to_string Uncomment tests
Diffstat (limited to 'src/term/mod.rs')
-rw-r--r--src/term/mod.rs93
1 files changed, 67 insertions, 26 deletions
diff --git a/src/term/mod.rs b/src/term/mod.rs
index e9a4582a..83b9e7da 100644
--- a/src/term/mod.rs
+++ b/src/term/mod.rs
@@ -24,9 +24,9 @@ use unicode_width::UnicodeWidthChar;
use font::{self, Size};
use ansi::{self, Color, NamedColor, Attr, Handler, CharsetIndex, StandardCharset, CursorStyle};
-use grid::{BidirectionalIterator, Grid, ToRange, Indexed, IndexRegion, DisplayIter};
-use index::{self, Point, Column, Line, IndexRange, Contains, RangeInclusive};
-use selection::{self, Span, Selection};
+use grid::{BidirectionalIterator, Grid, Indexed, IndexRegion, DisplayIter};
+use index::{self, Point, Column, Line, IndexRange, Contains, RangeInclusive, Linear};
+use selection::{self, Selection, Locations};
use config::{Config, VisualBellAnimation};
use {MouseCursor, Rgb};
use copypasta::{Clipboard, Load, Store};
@@ -37,7 +37,7 @@ pub use self::cell::Cell;
use self::cell::LineLength;
impl selection::SemanticSearch for Term {
- fn semantic_search_left(&self, mut point: Point) -> Point {
+ fn semantic_search_left(&self, mut point: Point<usize>) -> Point<usize> {
let mut iter = self.grid.iter_from(point);
let last_col = self.grid.num_cols() - Column(1);
@@ -56,7 +56,7 @@ impl selection::SemanticSearch for Term {
point
}
- fn semantic_search_right(&self, mut point: Point) -> Point {
+ fn semantic_search_right(&self, mut point: Point<usize>) -> Point<usize> {
let mut iter = self.grid.iter_from(point);
let last_col = self.grid.num_cols() - Column(1);
@@ -116,12 +116,37 @@ impl<'a> RenderableCellsIter<'a> {
colors: &'b color::List,
mode: TermMode,
config: &'b Config,
- selection: Option<RangeInclusive<index::Linear>>,
+ selection: Option<Locations>,
cursor_style: CursorStyle,
) -> RenderableCellsIter<'b> {
let cursor_offset = grid.line_to_offset(cursor.line);
let inner = grid.display_iter();
+ let selection = selection.map(|loc| {
+ // start and end *lines* are swapped as we switch from buffer to
+ // Line coordinates.
+ let mut end = Point {
+ line: grid.buffer_line_to_visible(loc.start.line),
+ col: loc.start.col
+ };
+ let mut start = Point {
+ line: grid.buffer_line_to_visible(loc.end.line),
+ col: loc.end.col
+ };
+
+ if start > end {
+ ::std::mem::swap(&mut start, &mut end);
+ }
+
+ println!("start={:?}, end={:?}", start, end);
+
+ let cols = grid.num_cols();
+ let start = Linear(start.line.0 * cols.0 + start.col.0);
+ let end = Linear(end.line.0 * cols.0 + end.col.0);
+
+ RangeInclusive::new(start, end)
+ });
+
RenderableCellsIter {
cursor: cursor,
cursor_offset: cursor_offset,
@@ -350,12 +375,13 @@ impl<'a> Iterator for RenderableCellsIter<'a> {
} else {
let cell = self.inner.next()?;
+ let index = Linear(cell.line.0 * self.grid.num_cols().0 + cell.column.0);
+
// XXX (jwilm) selection temp disabled
//
- // let selected = self.selection.as_ref()
- // .map(|range| range.contains_(index))
- // .unwrap_or(false);
- let selected = false;
+ let selected = self.selection.as_ref()
+ .map(|range| range.contains_(index))
+ .unwrap_or(false);
// Skip empty cells
if cell.is_empty() && !selected {
@@ -876,7 +902,7 @@ impl Term {
/// Need a generic push() for the Append trait
trait PushChar {
fn push_char(&mut self, c: char);
- fn maybe_newline(&mut self, grid: &Grid<Cell>, line: Line, ending: Column) {
+ fn maybe_newline(&mut self, grid: &Grid<Cell>, line: usize, ending: Column) {
if ending != Column(0) && !grid[line][ending - 1].flags.contains(cell::Flags::WRAPLINE) {
self.push_char('\n');
}
@@ -893,14 +919,14 @@ impl Term {
use std::ops::Range;
trait Append : PushChar {
- fn append(&mut self, grid: &Grid<Cell>, line: Line, cols: Range<Column>) -> Option<Range<Column>>;
+ fn append(&mut self, grid: &Grid<Cell>, line: usize, cols: Range<Column>) -> Option<Range<Column>>;
}
impl Append for String {
fn append(
&mut self,
grid: &Grid<Cell>,
- line: Line,
+ line: usize,
cols: Range<Column>
) -> Option<Range<Column>> {
let grid_line = &grid[line];
@@ -932,43 +958,54 @@ impl Term {
let mut res = String::new();
- let (start, end) = span.to_locations();
+ let Locations { mut start, mut end } = span.to_locations();
+
+ if start > end {
+ ::std::mem::swap(&mut start, &mut end);
+ }
+
let line_count = end.line - start.line;
let max_col = Column(usize::max_value() - 1);
match line_count {
// Selection within single line
- Line(0) => {
+ 0 => {
res.append(&self.grid, start.line, start.col..end.col);
},
// Selection ends on line following start
- Line(1) => {
+ 1 => {
+ // Ending line
+ res.append(&self.grid, end.line, end.col..max_col);
+
// Starting line
- res.append(&self.grid, start.line, start.col..max_col);
+ res.append(&self.grid, start.line, Column(0)..start.col);
- // Ending line
- res.append(&self.grid, end.line, Column(0)..end.col);
},
// Multi line selection
_ => {
- // Starting line
- res.append(&self.grid, start.line, start.col..max_col);
+ // Ending line
+ res.append(&self.grid, end.line, end.col..max_col);
- let middle_range = IndexRange::from((start.line + 1)..(end.line));
+ let middle_range = (start.line + 1)..(end.line);
for line in middle_range {
res.append(&self.grid, line, Column(0)..max_col);
}
- // Ending line
- res.append(&self.grid, end.line, Column(0)..end.col);
+ // Starting line
+ res.append(&self.grid, start.line, Column(0)..(start.col + 1));
+
}
}
Some(res)
}
+ pub(crate) fn visible_to_buffer(&self, point: Point) -> Point<usize> {
+ self.grid.visible_to_buffer(point)
+ }
+
/// Convert the given pixel values to a grid coordinate
///
/// The mouse coordinates are expected to be relative to the top left. The
@@ -997,8 +1034,12 @@ impl Term {
config: &'b Config,
window_focused: bool,
) -> RenderableCellsIter {
- let selection = self.grid.selection.as_ref().and_then(|s| s.to_span(self))
- .map(|span| span.to_range());
+ let selection = self.grid.selection.as_ref()
+ .and_then(|s| s.to_span(self))
+ .map(|span| {
+ // println!("span={:?}, locations={:?}", span, span.to_locations());
+ span.to_locations()
+ });
let cursor = if window_focused {
self.cursor_style.unwrap_or(self.default_cursor_style)
} else {