Fix crash when selection leaves viewport

There was an issue where alacritty tries to convert the lines in a
selection to the on-screen lines even when the selection is not on the
screen. This results in a crash.

To prevent this from happening the selection now is not shown if it is
off the screen.

There currently still is a bug that when the selection is at the top of
the screen but still half visible, it will not show the top line as
selected but start in the second line.
This bug should be resolved with
https://github.com/jwilm/alacritty/pull/1171.

This fixes #1148.
This commit is contained in:
Christian Duerr 2018-03-10 14:53:54 +01:00 committed by Joe Wilm
parent 786e274dd1
commit 231ef51365
2 changed files with 54 additions and 28 deletions

View File

@ -148,13 +148,17 @@ impl<T: Copy + Clone> Grid<T> {
pub fn buffer_to_visible(&self, point: Point<usize>) -> Point {
Point {
line: self.buffer_line_to_visible(point.line),
line: self.buffer_line_to_visible(point.line).expect("Line not visible"),
col: point.col
}
}
pub fn buffer_line_to_visible(&self, line: usize) -> Line {
self.offset_to_line(line - self.display_offset)
pub fn buffer_line_to_visible(&self, line: usize) -> Option<Line> {
if line >= self.display_offset {
self.offset_to_line(line - self.display_offset)
} else {
None
}
}
pub fn visible_line_to_buffer(&self, line: Line) -> usize {
@ -267,10 +271,12 @@ impl<T: Copy + Clone> Grid<T> {
*(self.num_lines() - line - 1)
}
pub fn offset_to_line(&self, offset: usize) -> Line {
assert!(offset < *self.num_lines());
self.lines - offset - 1
pub fn offset_to_line(&self, offset: usize) -> Option<Line> {
if offset < *self.num_lines() {
Some(self.lines - offset - 1)
} else {
None
}
}
#[inline]

View File

@ -122,29 +122,49 @@ impl<'a> RenderableCellsIter<'a> {
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
let mut selection_range = None;
selection.map(|loc| {
// Get on-screen lines of the selection's locations
let start_line = grid.buffer_line_to_visible(loc.start.line);
let end_line = grid.buffer_line_to_visible(loc.end.line);
// Get start/end locations based on what part of selection is on screen
let locations = match (start_line, end_line) {
(Some(start_line), Some(end_line)) => {
Some((start_line, loc.start.col, end_line, loc.end.col))
},
(Some(start_line), None) => {
Some((start_line, loc.start.col, Line(0), grid.num_cols()))
},
(None, Some(end_line)) => {
Some((grid.num_lines(), Column(0), end_line, loc.end.col))
},
(None, None) => None,
};
if start > end {
::std::mem::swap(&mut start, &mut end);
if let Some((start_line, start_col, end_line, end_col)) = locations {
// start and end *lines* are swapped as we switch from buffer to
// Line coordinates.
let mut end = Point {
line: start_line,
col: start_col,
};
let mut start = Point {
line: end_line,
col: end_col,
};
if start > end {
::std::mem::swap(&mut start, &mut 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);
// Update the selection
selection_range = Some(RangeInclusive::new(start, 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 {
@ -153,7 +173,7 @@ impl<'a> RenderableCellsIter<'a> {
grid: grid,
inner: inner,
mode: mode,
selection: selection,
selection: selection_range,
config: config,
colors: colors,
cursor_cells: ArrayDeque::new(),