From e18f5a0a2fbe5b8801dc7d5a402f6a7af1d97d12 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Wed, 15 Jul 2020 02:33:48 +0000 Subject: [PATCH] Fix cursor reflow This resolves three different issues with cursor reflow. The first issue was that the cursor could reach the top of the screen during reflow, since content was pushed into history despite viewport space being available. Since the cursor cannot leave the viewport, this would insert new space between the cursor and content (see #3968). Another issue was that the wrapline flag was not set correctly with content being available behind the cursor. Since the cursor is not necessarily at the end of the line, it is possible that the cursor should reflow to the next line instead of staying on the current one and setting the wrapline flag. The last bug fixed in this is about reflow with content available behind the cursor. Since that might have en effect on new lines being inserted and deleted below the cursor, the cursor needs to be reflown based on it. Fixes #3968. --- alacritty_terminal/src/grid/resize.rs | 42 ++++++++++++++++++--------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/alacritty_terminal/src/grid/resize.rs b/alacritty_terminal/src/grid/resize.rs index 725b7079..acdc040e 100644 --- a/alacritty_terminal/src/grid/resize.rs +++ b/alacritty_terminal/src/grid/resize.rs @@ -146,38 +146,43 @@ impl Grid { last_row.append(&mut cells); let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0; - let mut is_clear = row.is_clear(); 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); // Clamp to the last column, if no content was reflown with the cursor. - if target.col.0 == 0 { + if target.col.0 == 0 && row.is_clear() { self.cursor.input_needs_wrap = true; target = target.sub(cols, 1); } self.cursor.point.col = target.col; + // Get required cursor line changes. Since `num_wrapped` is smaller than `cols` + // this will always be either `0` or `1`. let line_delta = (self.cursor.point.line - target.line).0; + + if line_delta != 0 && row.is_clear() { + continue; + } + cursor_line_delta += line_delta; - is_clear &= line_delta != 0; - } else if is_clear { + } else if row.is_clear() { if i + reversed.len() >= self.lines.0 { // Since we removed a line, rotate down the viewport. self.display_offset = self.display_offset.saturating_sub(1); + } - // Rotate cursor down if content below them was pulled from history. - if i < cursor_buffer_line { - self.cursor.point.line += 1; - } + // Rotate cursor down if content below them was pulled from history. + if i < cursor_buffer_line { + self.cursor.point.line += 1; } // Don't push line into the new buffer. continue; } - if let (Some(cell), false) = (last_row.last_mut(), is_clear) { + if let Some(cell) = last_row.last_mut() { // Set wrap flag if next line still has cells. cell.flags_mut().insert(Flags::WRAPLINE); } @@ -307,11 +312,18 @@ impl Grid { buffered = Some(wrapped); break; } else { - // Reflow the cursor if it is on this line beyond the width. + // Reflow cursor if a line below it is deleted. let cursor_buffer_line = (self.lines - self.cursor.point.line - 1).0; - if cursor_buffer_line == i && self.cursor.point.col >= cols { - // Since only a single new line is created, we subtract only `cols` from - // the cursor instead of reflowing it completely. + if (i == cursor_buffer_line && self.cursor.point.col < cols) + || i < cursor_buffer_line + { + self.cursor.point.line.0 = self.cursor.point.line.saturating_sub(1); + } + + // Reflow the cursor if it is on this line beyond the width. + if i == cursor_buffer_line && self.cursor.point.col >= cols { + // Since only a single new line is created, we subtract only `cols` + // from the cursor instead of reflowing it completely. self.cursor.point.col -= cols; } @@ -333,7 +345,9 @@ impl Grid { // Reflow the primary cursor, or clamp it if reflow is disabled. if !reflow { self.cursor.point.col = min(self.cursor.point.col, cols - 1); - } else if self.cursor.point.col == cols { + } else if self.cursor.point.col == cols + && !self[self.cursor.point.line][cols - 1].flags().contains(Flags::WRAPLINE) + { self.cursor.input_needs_wrap = true; self.cursor.point.col -= 1; } else {