2020-05-30 20:45:44 +00:00
|
|
|
//! Grid resize and reflow.
|
|
|
|
|
2021-03-30 23:25:38 +00:00
|
|
|
use std::cmp::{max, min, Ordering};
|
2020-11-05 04:45:14 +00:00
|
|
|
use std::mem;
|
2020-05-30 20:45:44 +00:00
|
|
|
|
2021-03-30 23:25:38 +00:00
|
|
|
use crate::index::{Boundary, Column, Line};
|
2020-11-05 04:45:14 +00:00
|
|
|
use crate::term::cell::{Flags, ResetDiscriminant};
|
2020-05-30 20:45:44 +00:00
|
|
|
|
|
|
|
use crate::grid::row::Row;
|
2020-07-09 21:45:22 +00:00
|
|
|
use crate::grid::{Dimensions, Grid, GridCell};
|
2020-05-30 20:45:44 +00:00
|
|
|
|
2020-11-05 04:45:14 +00:00
|
|
|
impl<T: GridCell + Default + PartialEq + Clone> Grid<T> {
|
2020-05-30 20:45:44 +00:00
|
|
|
/// Resize the grid's width and/or height.
|
2021-03-30 23:25:38 +00:00
|
|
|
pub fn resize<D>(&mut self, reflow: bool, lines: usize, columns: usize)
|
2020-11-05 04:45:14 +00:00
|
|
|
where
|
|
|
|
T: ResetDiscriminant<D>,
|
|
|
|
D: PartialEq,
|
|
|
|
{
|
|
|
|
// Use empty template cell for resetting cells due to resize.
|
|
|
|
let template = mem::take(&mut self.cursor.template);
|
|
|
|
|
2020-05-30 20:45:44 +00:00
|
|
|
match self.lines.cmp(&lines) {
|
|
|
|
Ordering::Less => self.grow_lines(lines),
|
|
|
|
Ordering::Greater => self.shrink_lines(lines),
|
|
|
|
Ordering::Equal => (),
|
|
|
|
}
|
|
|
|
|
2021-03-30 23:25:38 +00:00
|
|
|
match self.columns.cmp(&columns) {
|
|
|
|
Ordering::Less => self.grow_columns(reflow, columns),
|
|
|
|
Ordering::Greater => self.shrink_columns(reflow, columns),
|
2020-05-30 20:45:44 +00:00
|
|
|
Ordering::Equal => (),
|
|
|
|
}
|
2020-11-05 04:45:14 +00:00
|
|
|
|
|
|
|
// Restore template cell.
|
|
|
|
self.cursor.template = template;
|
2020-05-30 20:45:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Add lines to the visible area.
|
|
|
|
///
|
|
|
|
/// 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.
|
2021-03-30 23:25:38 +00:00
|
|
|
fn grow_lines<D>(&mut self, target: usize)
|
2020-11-05 04:45:14 +00:00
|
|
|
where
|
|
|
|
T: ResetDiscriminant<D>,
|
|
|
|
D: PartialEq,
|
|
|
|
{
|
2021-03-30 23:25:38 +00:00
|
|
|
let lines_added = target - self.lines;
|
2020-05-30 20:45:44 +00:00
|
|
|
|
|
|
|
// Need to resize before updating buffer.
|
2021-03-30 23:25:38 +00:00
|
|
|
self.raw.grow_visible_lines(target);
|
|
|
|
self.lines = target;
|
2020-05-30 20:45:44 +00:00
|
|
|
|
|
|
|
let history_size = self.history_size();
|
2021-03-30 23:25:38 +00:00
|
|
|
let from_history = min(history_size, lines_added);
|
2020-05-30 20:45:44 +00:00
|
|
|
|
|
|
|
// Move existing lines up for every line that couldn't be pulled from history.
|
2021-03-30 23:25:38 +00:00
|
|
|
if from_history != lines_added {
|
2020-05-30 20:45:44 +00:00
|
|
|
let delta = lines_added - from_history;
|
2021-03-30 23:25:38 +00:00
|
|
|
self.scroll_up(&(Line(0)..Line(target as i32)), delta);
|
2020-05-30 20:45:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Move cursor down for every line pulled from history.
|
|
|
|
self.saved_cursor.point.line += from_history;
|
|
|
|
self.cursor.point.line += from_history;
|
|
|
|
|
2021-03-30 23:25:38 +00:00
|
|
|
self.display_offset = self.display_offset.saturating_sub(lines_added);
|
|
|
|
self.decrease_scroll_limit(lines_added);
|
2020-05-30 20:45:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Remove lines from the visible area.
|
|
|
|
///
|
|
|
|
/// The behavior in Terminal.app and iTerm.app is to keep the cursor at the
|
|
|
|
/// bottom of the screen. This is achieved by pushing history "out the top"
|
|
|
|
/// of the terminal window.
|
|
|
|
///
|
|
|
|
/// Alacritty takes the same approach.
|
2021-03-30 23:25:38 +00:00
|
|
|
fn shrink_lines<D>(&mut self, target: usize)
|
2020-11-05 04:45:14 +00:00
|
|
|
where
|
|
|
|
T: ResetDiscriminant<D>,
|
|
|
|
D: PartialEq,
|
|
|
|
{
|
2020-05-30 20:45:44 +00:00
|
|
|
// Scroll up to keep content inside the window.
|
2021-03-30 23:25:38 +00:00
|
|
|
let required_scrolling = (self.cursor.point.line.0 as usize + 1).saturating_sub(target);
|
2020-05-30 20:45:44 +00:00
|
|
|
if required_scrolling > 0 {
|
2021-03-30 23:25:38 +00:00
|
|
|
self.scroll_up(&(Line(0)..Line(self.lines as i32)), required_scrolling);
|
2020-05-30 20:45:44 +00:00
|
|
|
|
|
|
|
// Clamp cursors to the new viewport size.
|
2021-03-30 23:25:38 +00:00
|
|
|
self.cursor.point.line = min(self.cursor.point.line, Line(target as i32 - 1));
|
2020-05-30 20:45:44 +00:00
|
|
|
}
|
|
|
|
|
2020-07-01 06:58:06 +00:00
|
|
|
// Clamp saved cursor, since only primary cursor is scrolled into viewport.
|
2021-03-30 23:25:38 +00:00
|
|
|
self.saved_cursor.point.line = min(self.saved_cursor.point.line, Line(target as i32 - 1));
|
2020-07-01 06:58:06 +00:00
|
|
|
|
2021-03-30 23:25:38 +00:00
|
|
|
self.raw.rotate((self.lines - target) as isize);
|
2020-05-30 20:45:44 +00:00
|
|
|
self.raw.shrink_visible_lines(target);
|
|
|
|
self.lines = target;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Grow number of columns in each row, reflowing if necessary.
|
2021-03-30 23:25:38 +00:00
|
|
|
fn grow_columns(&mut self, reflow: bool, columns: usize) {
|
2020-05-30 20:45:44 +00:00
|
|
|
// Check if a row needs to be wrapped.
|
|
|
|
let should_reflow = |row: &Row<T>| -> bool {
|
|
|
|
let len = Column(row.len());
|
2021-03-30 23:25:38 +00:00
|
|
|
reflow && len.0 > 0 && len < columns && row[len - 1].flags().contains(Flags::WRAPLINE)
|
2020-05-30 20:45:44 +00:00
|
|
|
};
|
|
|
|
|
2021-03-30 23:25:38 +00:00
|
|
|
self.columns = columns;
|
2020-05-30 20:45:44 +00:00
|
|
|
|
|
|
|
let mut reversed: Vec<Row<T>> = Vec::with_capacity(self.raw.len());
|
2020-07-09 02:16:20 +00:00
|
|
|
let mut cursor_line_delta = 0;
|
|
|
|
|
|
|
|
// Remove the linewrap special case, by moving the cursor outside of the grid.
|
|
|
|
if self.cursor.input_needs_wrap && reflow {
|
|
|
|
self.cursor.input_needs_wrap = false;
|
2021-01-24 21:45:36 +00:00
|
|
|
self.cursor.point.column += 1;
|
2020-07-09 02:16:20 +00:00
|
|
|
}
|
2020-05-30 20:45:44 +00:00
|
|
|
|
|
|
|
let mut rows = self.raw.take_all();
|
|
|
|
|
|
|
|
for (i, mut row) in rows.drain(..).enumerate().rev() {
|
|
|
|
// Check if reflowing should be performed.
|
|
|
|
let last_row = match reversed.last_mut() {
|
|
|
|
Some(last_row) if should_reflow(last_row) => last_row,
|
|
|
|
_ => {
|
|
|
|
reversed.push(row);
|
|
|
|
continue;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
// Remove wrap flag before appending additional cells.
|
|
|
|
if let Some(cell) = last_row.last_mut() {
|
|
|
|
cell.flags_mut().remove(Flags::WRAPLINE);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove leading spacers when reflowing wide char to the previous line.
|
|
|
|
let mut last_len = last_row.len();
|
2020-07-09 21:45:22 +00:00
|
|
|
if last_len >= 1
|
|
|
|
&& last_row[Column(last_len - 1)].flags().contains(Flags::LEADING_WIDE_CHAR_SPACER)
|
2020-05-30 20:45:44 +00:00
|
|
|
{
|
2021-03-30 23:25:38 +00:00
|
|
|
last_row.shrink(last_len - 1);
|
2020-05-30 20:45:44 +00:00
|
|
|
last_len -= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't try to pull more cells from the next line than available.
|
2021-03-30 23:25:38 +00:00
|
|
|
let mut num_wrapped = columns - last_len;
|
2020-07-09 02:16:20 +00:00
|
|
|
let len = min(row.len(), num_wrapped);
|
2020-05-30 20:45:44 +00:00
|
|
|
|
|
|
|
// Insert leading spacer when there's not enough room for reflowing wide char.
|
|
|
|
let mut cells = if row[Column(len - 1)].flags().contains(Flags::WIDE_CHAR) {
|
2020-07-09 02:16:20 +00:00
|
|
|
num_wrapped -= 1;
|
|
|
|
|
2020-05-30 20:45:44 +00:00
|
|
|
let mut cells = row.front_split_off(len - 1);
|
|
|
|
|
|
|
|
let mut spacer = T::default();
|
2020-07-09 21:45:22 +00:00
|
|
|
spacer.flags_mut().insert(Flags::LEADING_WIDE_CHAR_SPACER);
|
2020-05-30 20:45:44 +00:00
|
|
|
cells.push(spacer);
|
|
|
|
|
|
|
|
cells
|
|
|
|
} else {
|
|
|
|
row.front_split_off(len)
|
|
|
|
};
|
|
|
|
|
2020-07-09 21:45:22 +00:00
|
|
|
// Add removed cells to previous row and reflow content.
|
2020-05-30 20:45:44 +00:00
|
|
|
last_row.append(&mut cells);
|
|
|
|
|
2021-03-30 23:25:38 +00:00
|
|
|
let cursor_buffer_line = self.lines - self.cursor.point.line.0 as usize - 1;
|
2020-07-09 02:16:20 +00:00
|
|
|
|
|
|
|
if i == cursor_buffer_line && reflow {
|
|
|
|
// Resize cursor's line and reflow the cursor if necessary.
|
2021-03-30 23:25:38 +00:00
|
|
|
let mut target = self.cursor.point.sub(self, Boundary::Cursor, num_wrapped);
|
2020-07-09 02:16:20 +00:00
|
|
|
|
|
|
|
// Clamp to the last column, if no content was reflown with the cursor.
|
2021-01-24 21:45:36 +00:00
|
|
|
if target.column.0 == 0 && row.is_clear() {
|
2020-07-09 02:16:20 +00:00
|
|
|
self.cursor.input_needs_wrap = true;
|
2021-03-30 23:25:38 +00:00
|
|
|
target = target.sub(self, Boundary::Cursor, 1);
|
2020-07-09 02:16:20 +00:00
|
|
|
}
|
2021-01-24 21:45:36 +00:00
|
|
|
self.cursor.point.column = target.column;
|
2020-07-09 02:16:20 +00:00
|
|
|
|
2021-03-30 23:25:38 +00:00
|
|
|
// Get required cursor line changes. Since `num_wrapped` is smaller than `columns`
|
2020-07-15 02:33:48 +00:00
|
|
|
// this will always be either `0` or `1`.
|
2021-03-30 23:25:38 +00:00
|
|
|
let line_delta = self.cursor.point.line - target.line;
|
2020-07-15 02:33:48 +00:00
|
|
|
|
|
|
|
if line_delta != 0 && row.is_clear() {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-03-30 23:25:38 +00:00
|
|
|
cursor_line_delta += line_delta.0 as usize;
|
2020-07-15 02:33:48 +00:00
|
|
|
} else if row.is_clear() {
|
2021-04-08 20:29:47 +00:00
|
|
|
if i < self.display_offset {
|
2020-05-30 20:45:44 +00:00
|
|
|
// Since we removed a line, rotate down the viewport.
|
|
|
|
self.display_offset = self.display_offset.saturating_sub(1);
|
2020-07-15 02:33:48 +00:00
|
|
|
}
|
2020-07-01 06:58:06 +00:00
|
|
|
|
2020-07-15 02:33:48 +00:00
|
|
|
// Rotate cursor down if content below them was pulled from history.
|
|
|
|
if i < cursor_buffer_line {
|
|
|
|
self.cursor.point.line += 1;
|
2020-05-30 20:45:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Don't push line into the new buffer.
|
|
|
|
continue;
|
2020-07-09 02:16:20 +00:00
|
|
|
}
|
|
|
|
|
2020-07-15 02:33:48 +00:00
|
|
|
if let Some(cell) = last_row.last_mut() {
|
2020-05-30 20:45:44 +00:00
|
|
|
// Set wrap flag if next line still has cells.
|
|
|
|
cell.flags_mut().insert(Flags::WRAPLINE);
|
|
|
|
}
|
|
|
|
|
|
|
|
reversed.push(row);
|
|
|
|
}
|
|
|
|
|
2020-07-09 02:16:20 +00:00
|
|
|
// Make sure we have at least the viewport filled.
|
2021-03-30 23:25:38 +00:00
|
|
|
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));
|
2020-07-09 02:16:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
2021-03-30 23:25:38 +00:00
|
|
|
let cursor_buffer_line = self.lines - self.cursor.point.line.0 as usize - 1;
|
|
|
|
let available = min(cursor_buffer_line, reversed.len() - self.lines);
|
2020-07-09 02:16:20 +00:00
|
|
|
let overflow = cursor_line_delta.saturating_sub(available);
|
|
|
|
reversed.truncate(reversed.len() + overflow - cursor_line_delta);
|
2021-03-30 23:25:38 +00:00
|
|
|
self.cursor.point.line = max(self.cursor.point.line - overflow, Line(0));
|
2020-07-09 02:16:20 +00:00
|
|
|
}
|
2020-05-30 20:45:44 +00:00
|
|
|
|
|
|
|
// 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() {
|
2021-03-30 23:25:38 +00:00
|
|
|
if row.len() < columns {
|
|
|
|
row.grow(columns);
|
2020-05-30 20:45:44 +00:00
|
|
|
}
|
|
|
|
new_raw.push(row);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.raw.replace_inner(new_raw);
|
|
|
|
|
|
|
|
// Clamp display offset in case lines above it got merged.
|
|
|
|
self.display_offset = min(self.display_offset, self.history_size());
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Shrink number of columns in each row, reflowing if necessary.
|
2021-03-30 23:25:38 +00:00
|
|
|
fn shrink_columns(&mut self, reflow: bool, columns: usize) {
|
|
|
|
self.columns = columns;
|
2020-05-30 20:45:44 +00:00
|
|
|
|
2020-07-09 02:16:20 +00:00
|
|
|
// Remove the linewrap special case, by moving the cursor outside of the grid.
|
|
|
|
if self.cursor.input_needs_wrap && reflow {
|
|
|
|
self.cursor.input_needs_wrap = false;
|
2021-01-24 21:45:36 +00:00
|
|
|
self.cursor.point.column += 1;
|
2020-07-09 02:16:20 +00:00
|
|
|
}
|
2020-05-30 20:45:44 +00:00
|
|
|
|
|
|
|
let mut new_raw = Vec::with_capacity(self.raw.len());
|
|
|
|
let mut buffered: Option<Vec<T>> = None;
|
|
|
|
|
2020-07-09 02:16:20 +00:00
|
|
|
let mut rows = self.raw.take_all();
|
2020-05-30 20:45:44 +00:00
|
|
|
for (i, mut row) in rows.drain(..).enumerate().rev() {
|
|
|
|
// Append lines left over from the previous row.
|
|
|
|
if let Some(buffered) = buffered.take() {
|
2020-07-09 02:16:20 +00:00
|
|
|
// Add a column for every cell added before the cursor, if it goes beyond the new
|
|
|
|
// width it is then later reflown.
|
2021-03-30 23:25:38 +00:00
|
|
|
let cursor_buffer_line = self.lines - self.cursor.point.line.0 as usize - 1;
|
2020-07-09 02:16:20 +00:00
|
|
|
if i == cursor_buffer_line {
|
2021-01-24 21:45:36 +00:00
|
|
|
self.cursor.point.column += buffered.len();
|
2020-07-09 02:16:20 +00:00
|
|
|
}
|
|
|
|
|
2020-05-30 20:45:44 +00:00
|
|
|
row.append_front(buffered);
|
|
|
|
}
|
|
|
|
|
|
|
|
loop {
|
|
|
|
// Remove all cells which require reflowing.
|
2021-03-30 23:25:38 +00:00
|
|
|
let mut wrapped = match row.shrink(columns) {
|
2020-05-30 20:45:44 +00:00
|
|
|
Some(wrapped) if reflow => wrapped,
|
|
|
|
_ => {
|
2021-03-30 23:25:38 +00:00
|
|
|
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 {
|
2020-07-09 02:16:20 +00:00
|
|
|
// If there are empty cells before the cursor, we assume it is explicit
|
|
|
|
// whitespace and need to wrap it like normal content.
|
|
|
|
Vec::new()
|
|
|
|
} else {
|
|
|
|
// Since it fits, just push the existing line without any reflow.
|
|
|
|
new_raw.push(row);
|
|
|
|
break;
|
|
|
|
}
|
2020-05-30 20:45:44 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
// Insert spacer if a wide char would be wrapped into the last column.
|
2021-03-30 23:25:38 +00:00
|
|
|
if row.len() >= columns
|
|
|
|
&& row[Column(columns - 1)].flags().contains(Flags::WIDE_CHAR)
|
|
|
|
{
|
2020-05-30 20:45:44 +00:00
|
|
|
let mut spacer = T::default();
|
2020-07-09 21:45:22 +00:00
|
|
|
spacer.flags_mut().insert(Flags::LEADING_WIDE_CHAR_SPACER);
|
2020-11-05 04:45:14 +00:00
|
|
|
|
2021-03-30 23:25:38 +00:00
|
|
|
let wide_char = mem::replace(&mut row[Column(columns - 1)], spacer);
|
2020-11-05 04:45:14 +00:00
|
|
|
wrapped.insert(0, wide_char);
|
2020-05-30 20:45:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Remove wide char spacer before shrinking.
|
|
|
|
let len = wrapped.len();
|
2020-07-14 00:30:17 +00:00
|
|
|
if len > 0 && wrapped[len - 1].flags().contains(Flags::LEADING_WIDE_CHAR_SPACER) {
|
2020-05-30 20:45:44 +00:00
|
|
|
if len == 1 {
|
2021-03-30 23:25:38 +00:00
|
|
|
row[Column(columns - 1)].flags_mut().insert(Flags::WRAPLINE);
|
2020-05-30 20:45:44 +00:00
|
|
|
new_raw.push(row);
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
// Remove the leading spacer from the end of the wrapped row.
|
|
|
|
wrapped[len - 2].flags_mut().insert(Flags::WRAPLINE);
|
|
|
|
wrapped.truncate(len - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
new_raw.push(row);
|
|
|
|
|
|
|
|
// Set line as wrapped if cells got removed.
|
|
|
|
if let Some(cell) = new_raw.last_mut().and_then(|r| r.last_mut()) {
|
|
|
|
cell.flags_mut().insert(Flags::WRAPLINE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if wrapped
|
|
|
|
.last()
|
|
|
|
.map(|c| c.flags().contains(Flags::WRAPLINE) && i >= 1)
|
|
|
|
.unwrap_or(false)
|
2021-03-30 23:25:38 +00:00
|
|
|
&& wrapped.len() < columns
|
2020-05-30 20:45:44 +00:00
|
|
|
{
|
|
|
|
// Make sure previous wrap flag doesn't linger around.
|
|
|
|
if let Some(cell) = wrapped.last_mut() {
|
|
|
|
cell.flags_mut().remove(Flags::WRAPLINE);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add removed cells to start of next row.
|
|
|
|
buffered = Some(wrapped);
|
|
|
|
break;
|
|
|
|
} else {
|
2020-07-15 02:33:48 +00:00
|
|
|
// Reflow cursor if a line below it is deleted.
|
2021-03-30 23:25:38 +00:00
|
|
|
let cursor_buffer_line = self.lines - self.cursor.point.line.0 as usize - 1;
|
|
|
|
if (i == cursor_buffer_line && self.cursor.point.column < columns)
|
2020-07-15 02:33:48 +00:00
|
|
|
|| i < cursor_buffer_line
|
|
|
|
{
|
2021-03-30 23:25:38 +00:00
|
|
|
self.cursor.point.line = max(self.cursor.point.line - 1, Line(0));
|
2020-07-15 02:33:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Reflow the cursor if it is on this line beyond the width.
|
2021-03-30 23:25:38 +00:00
|
|
|
if i == cursor_buffer_line && self.cursor.point.column >= columns {
|
|
|
|
// Since only a single new line is created, we subtract only `columns`
|
2020-07-15 02:33:48 +00:00
|
|
|
// from the cursor instead of reflowing it completely.
|
2021-03-30 23:25:38 +00:00
|
|
|
self.cursor.point.column -= columns;
|
2020-05-30 20:45:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure new row is at least as long as new width.
|
|
|
|
let occ = wrapped.len();
|
2021-03-30 23:25:38 +00:00
|
|
|
if occ < columns {
|
|
|
|
wrapped.resize_with(columns, T::default);
|
2020-05-30 20:45:44 +00:00
|
|
|
}
|
|
|
|
row = Row::from_vec(wrapped, occ);
|
2021-03-31 19:11:16 +00:00
|
|
|
|
2021-04-08 20:29:47 +00:00
|
|
|
if i < self.display_offset {
|
2021-03-31 19:11:16 +00:00
|
|
|
// Since we added a new line, rotate up the viewport.
|
|
|
|
self.display_offset += 1;
|
|
|
|
}
|
2020-05-30 20:45:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reverse iterator and use it as the new grid storage.
|
|
|
|
let mut reversed: Vec<Row<T>> = new_raw.drain(..).rev().collect();
|
2021-03-30 23:25:38 +00:00
|
|
|
reversed.truncate(self.max_scroll_limit + self.lines);
|
2020-05-30 20:45:44 +00:00
|
|
|
self.raw.replace_inner(reversed);
|
|
|
|
|
2020-07-09 02:16:20 +00:00
|
|
|
// Reflow the primary cursor, or clamp it if reflow is disabled.
|
|
|
|
if !reflow {
|
2021-03-30 23:25:38 +00:00
|
|
|
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)
|
2020-07-15 02:33:48 +00:00
|
|
|
{
|
2020-07-09 02:16:20 +00:00
|
|
|
self.cursor.input_needs_wrap = true;
|
2021-01-24 21:45:36 +00:00
|
|
|
self.cursor.point.column -= 1;
|
2020-07-09 02:16:20 +00:00
|
|
|
} else {
|
2021-03-30 23:25:38 +00:00
|
|
|
self.cursor.point = self.cursor.point.grid_clamp(self, Boundary::Cursor);
|
2020-07-09 02:16:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Clamp the saved cursor to the grid.
|
2021-03-30 23:25:38 +00:00
|
|
|
self.saved_cursor.point.column = min(self.saved_cursor.point.column, Column(columns - 1));
|
2020-05-30 20:45:44 +00:00
|
|
|
}
|
|
|
|
}
|