diff options
Diffstat (limited to 'alacritty_terminal/src/grid/resize.rs')
-rw-r--r-- | alacritty_terminal/src/grid/resize.rs | 134 |
1 files changed, 68 insertions, 66 deletions
diff --git a/alacritty_terminal/src/grid/resize.rs b/alacritty_terminal/src/grid/resize.rs index 40492c3a..eb8bef0c 100644 --- a/alacritty_terminal/src/grid/resize.rs +++ b/alacritty_terminal/src/grid/resize.rs @@ -1,9 +1,9 @@ //! Grid resize and reflow. -use std::cmp::{min, Ordering}; +use std::cmp::{max, min, Ordering}; use std::mem; -use crate::index::{Column, Line}; +use crate::index::{Boundary, Column, Line}; use crate::term::cell::{Flags, ResetDiscriminant}; use crate::grid::row::Row; @@ -11,7 +11,7 @@ use crate::grid::{Dimensions, Grid, GridCell}; impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { /// Resize the grid's width and/or height. - pub fn resize<D>(&mut self, reflow: bool, lines: Line, cols: Column) + pub fn resize<D>(&mut self, reflow: bool, lines: usize, columns: usize) where T: ResetDiscriminant<D>, D: PartialEq, @@ -25,9 +25,9 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { Ordering::Equal => (), } - match self.cols.cmp(&cols) { - Ordering::Less => self.grow_cols(reflow, cols), - Ordering::Greater => self.shrink_cols(reflow, cols), + match self.columns.cmp(&columns) { + Ordering::Less => self.grow_columns(reflow, columns), + Ordering::Greater => self.shrink_columns(reflow, columns), Ordering::Equal => (), } @@ -40,32 +40,32 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { /// Alacritty keeps the cursor at the bottom of the terminal as long as there /// is scrollback available. Once scrollback is exhausted, new lines are /// simply added to the bottom of the screen. - fn grow_lines<D>(&mut self, new_line_count: Line) + fn grow_lines<D>(&mut self, target: usize) where T: ResetDiscriminant<D>, D: PartialEq, { - let lines_added = new_line_count - self.lines; + let lines_added = target - self.lines; // Need to resize before updating buffer. - self.raw.grow_visible_lines(new_line_count); - self.lines = new_line_count; + self.raw.grow_visible_lines(target); + self.lines = target; let history_size = self.history_size(); - let from_history = min(history_size, lines_added.0); + let from_history = min(history_size, lines_added); // Move existing lines up for every line that couldn't be pulled from history. - if from_history != lines_added.0 { + if from_history != lines_added { let delta = lines_added - from_history; - self.scroll_up(&(Line(0)..new_line_count), delta); + self.scroll_up(&(Line(0)..Line(target as i32)), delta); } // Move cursor down for every line pulled from history. self.saved_cursor.point.line += from_history; self.cursor.point.line += from_history; - self.display_offset = self.display_offset.saturating_sub(*lines_added); - self.decrease_scroll_limit(*lines_added); + self.display_offset = self.display_offset.saturating_sub(lines_added); + self.decrease_scroll_limit(lines_added); } /// Remove lines from the visible area. @@ -75,37 +75,37 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { /// of the terminal window. /// /// Alacritty takes the same approach. - fn shrink_lines<D>(&mut self, target: Line) + fn shrink_lines<D>(&mut self, target: usize) where T: ResetDiscriminant<D>, D: PartialEq, { // Scroll up to keep content inside the window. - let required_scrolling = (self.cursor.point.line + 1).saturating_sub(target.0); + let required_scrolling = (self.cursor.point.line.0 as usize + 1).saturating_sub(target); if required_scrolling > 0 { - self.scroll_up(&(Line(0)..self.lines), Line(required_scrolling)); + self.scroll_up(&(Line(0)..Line(self.lines as i32)), required_scrolling); // Clamp cursors to the new viewport size. - self.cursor.point.line = min(self.cursor.point.line, target - 1); + self.cursor.point.line = min(self.cursor.point.line, Line(target as i32 - 1)); } // Clamp saved cursor, since only primary cursor is scrolled into viewport. - self.saved_cursor.point.line = min(self.saved_cursor.point.line, target - 1); + self.saved_cursor.point.line = min(self.saved_cursor.point.line, Line(target as i32 - 1)); - self.raw.rotate((self.lines - target).0 as isize); + self.raw.rotate((self.lines - target) as isize); self.raw.shrink_visible_lines(target); self.lines = target; } /// Grow number of columns in each row, reflowing if necessary. - fn grow_cols(&mut self, reflow: bool, cols: Column) { + fn grow_columns(&mut self, reflow: bool, columns: usize) { // Check if a row needs to be wrapped. let should_reflow = |row: &Row<T>| -> bool { let len = Column(row.len()); - reflow && len.0 > 0 && len < cols && row[len - 1].flags().contains(Flags::WRAPLINE) + reflow && len.0 > 0 && len < columns && row[len - 1].flags().contains(Flags::WRAPLINE) }; - self.cols = cols; + self.columns = columns; let mut reversed: Vec<Row<T>> = Vec::with_capacity(self.raw.len()); let mut cursor_line_delta = 0; @@ -138,12 +138,12 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { if last_len >= 1 && last_row[Column(last_len - 1)].flags().contains(Flags::LEADING_WIDE_CHAR_SPACER) { - last_row.shrink(Column(last_len - 1)); + last_row.shrink(last_len - 1); last_len -= 1; } // Don't try to pull more cells from the next line than available. - let mut num_wrapped = cols.0 - last_len; + let mut num_wrapped = columns - last_len; let len = min(row.len(), num_wrapped); // Insert leading spacer when there's not enough room for reflowing wide char. @@ -164,30 +164,30 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { // Add removed cells to previous row and reflow content. last_row.append(&mut cells); - let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0; + let cursor_buffer_line = self.lines - self.cursor.point.line.0 as usize - 1; if i == cursor_buffer_line && reflow { // Resize cursor's line and reflow the cursor if necessary. - let mut target = self.cursor.point.sub(cols, num_wrapped); + let mut target = self.cursor.point.sub(self, Boundary::Cursor, num_wrapped); // Clamp to the last column, if no content was reflown with the cursor. if target.column.0 == 0 && row.is_clear() { self.cursor.input_needs_wrap = true; - target = target.sub(cols, 1); + target = target.sub(self, Boundary::Cursor, 1); } self.cursor.point.column = target.column; - // Get required cursor line changes. Since `num_wrapped` is smaller than `cols` + // Get required cursor line changes. Since `num_wrapped` is smaller than `columns` // this will always be either `0` or `1`. - let line_delta = (self.cursor.point.line - target.line).0; + let line_delta = self.cursor.point.line - target.line; if line_delta != 0 && row.is_clear() { continue; } - cursor_line_delta += line_delta; + cursor_line_delta += line_delta.0 as usize; } else if row.is_clear() { - if i + reversed.len() >= self.lines.0 { + if i + reversed.len() >= self.lines { // Since we removed a line, rotate down the viewport. self.display_offset = self.display_offset.saturating_sub(1); } @@ -210,27 +210,27 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { } // Make sure we have at least the viewport filled. - if reversed.len() < self.lines.0 { - let delta = self.lines.0 - reversed.len(); - self.cursor.point.line.0 = self.cursor.point.line.saturating_sub(delta); - reversed.resize_with(self.lines.0, || Row::new(cols)); + if reversed.len() < self.lines { + let delta = (self.lines - reversed.len()) as i32; + self.cursor.point.line = max(self.cursor.point.line - delta, Line(0)); + reversed.resize_with(self.lines, || Row::new(columns)); } // Pull content down to put cursor in correct position, or move cursor up if there's no // more lines to delete below the cursor. if cursor_line_delta != 0 { - let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0; - let available = min(cursor_buffer_line, reversed.len() - self.lines.0); + let cursor_buffer_line = self.lines - self.cursor.point.line.0 as usize - 1; + let available = min(cursor_buffer_line, reversed.len() - self.lines); let overflow = cursor_line_delta.saturating_sub(available); reversed.truncate(reversed.len() + overflow - cursor_line_delta); - self.cursor.point.line.0 = self.cursor.point.line.saturating_sub(overflow); + self.cursor.point.line = max(self.cursor.point.line - overflow, Line(0)); } // Reverse iterator and fill all rows that are still too short. let mut new_raw = Vec::with_capacity(reversed.len()); for mut row in reversed.drain(..).rev() { - if row.len() < cols.0 { - row.grow(cols); + if row.len() < columns { + row.grow(columns); } new_raw.push(row); } @@ -242,8 +242,8 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { } /// Shrink number of columns in each row, reflowing if necessary. - fn shrink_cols(&mut self, reflow: bool, cols: Column) { - self.cols = cols; + fn shrink_columns(&mut self, reflow: bool, columns: usize) { + self.columns = columns; // Remove the linewrap special case, by moving the cursor outside of the grid. if self.cursor.input_needs_wrap && reflow { @@ -260,7 +260,7 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { if let Some(buffered) = buffered.take() { // Add a column for every cell added before the cursor, if it goes beyond the new // width it is then later reflown. - let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0; + let cursor_buffer_line = self.lines - self.cursor.point.line.0 as usize - 1; if i == cursor_buffer_line { self.cursor.point.column += buffered.len(); } @@ -270,11 +270,11 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { loop { // Remove all cells which require reflowing. - let mut wrapped = match row.shrink(cols) { + let mut wrapped = match row.shrink(columns) { Some(wrapped) if reflow => wrapped, _ => { - let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0; - if reflow && i == cursor_buffer_line && self.cursor.point.column > cols { + let cursor_buffer_line = self.lines - self.cursor.point.line.0 as usize - 1; + if reflow && i == cursor_buffer_line && self.cursor.point.column > columns { // If there are empty cells before the cursor, we assume it is explicit // whitespace and need to wrap it like normal content. Vec::new() @@ -287,11 +287,13 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { }; // Insert spacer if a wide char would be wrapped into the last column. - if row.len() >= cols.0 && row[cols - 1].flags().contains(Flags::WIDE_CHAR) { + if row.len() >= columns + && row[Column(columns - 1)].flags().contains(Flags::WIDE_CHAR) + { let mut spacer = T::default(); spacer.flags_mut().insert(Flags::LEADING_WIDE_CHAR_SPACER); - let wide_char = mem::replace(&mut row[cols - 1], spacer); + let wide_char = mem::replace(&mut row[Column(columns - 1)], spacer); wrapped.insert(0, wide_char); } @@ -299,7 +301,7 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { let len = wrapped.len(); if len > 0 && wrapped[len - 1].flags().contains(Flags::LEADING_WIDE_CHAR_SPACER) { if len == 1 { - row[cols - 1].flags_mut().insert(Flags::WRAPLINE); + row[Column(columns - 1)].flags_mut().insert(Flags::WRAPLINE); new_raw.push(row); break; } else { @@ -320,7 +322,7 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { .last() .map(|c| c.flags().contains(Flags::WRAPLINE) && i >= 1) .unwrap_or(false) - && wrapped.len() < cols.0 + && wrapped.len() < columns { // Make sure previous wrap flag doesn't linger around. if let Some(cell) = wrapped.last_mut() { @@ -332,24 +334,24 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { break; } else { // Reflow cursor if a line below it is deleted. - let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0; - if (i == cursor_buffer_line && self.cursor.point.column < cols) + let cursor_buffer_line = self.lines - self.cursor.point.line.0 as usize - 1; + if (i == cursor_buffer_line && self.cursor.point.column < columns) || i < cursor_buffer_line { - self.cursor.point.line.0 = self.cursor.point.line.saturating_sub(1); + self.cursor.point.line = max(self.cursor.point.line - 1, Line(0)); } // Reflow the cursor if it is on this line beyond the width. - if i == cursor_buffer_line && self.cursor.point.column >= cols { - // Since only a single new line is created, we subtract only `cols` + if i == cursor_buffer_line && self.cursor.point.column >= columns { + // Since only a single new line is created, we subtract only `columns` // from the cursor instead of reflowing it completely. - self.cursor.point.column -= cols; + self.cursor.point.column -= columns; } // Make sure new row is at least as long as new width. let occ = wrapped.len(); - if occ < cols.0 { - wrapped.resize_with(cols.0, T::default); + if occ < columns { + wrapped.resize_with(columns, T::default); } row = Row::from_vec(wrapped, occ); } @@ -358,22 +360,22 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> { // Reverse iterator and use it as the new grid storage. let mut reversed: Vec<Row<T>> = new_raw.drain(..).rev().collect(); - reversed.truncate(self.max_scroll_limit + self.lines.0); + reversed.truncate(self.max_scroll_limit + self.lines); self.raw.replace_inner(reversed); // Reflow the primary cursor, or clamp it if reflow is disabled. if !reflow { - self.cursor.point.column = min(self.cursor.point.column, cols - 1); - } else if self.cursor.point.column == cols - && !self[self.cursor.point.line][cols - 1].flags().contains(Flags::WRAPLINE) + self.cursor.point.column = min(self.cursor.point.column, Column(columns - 1)); + } else if self.cursor.point.column == columns + && !self[self.cursor.point.line][Column(columns - 1)].flags().contains(Flags::WRAPLINE) { self.cursor.input_needs_wrap = true; self.cursor.point.column -= 1; } else { - self.cursor.point = self.cursor.point.add(cols, 0); + self.cursor.point = self.cursor.point.grid_clamp(self, Boundary::Cursor); } // Clamp the saved cursor to the grid. - self.saved_cursor.point.column = min(self.saved_cursor.point.column, cols - 1); + self.saved_cursor.point.column = min(self.saved_cursor.point.column, Column(columns - 1)); } } |