summaryrefslogtreecommitdiff
path: root/alacritty_terminal/src/grid/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'alacritty_terminal/src/grid/mod.rs')
-rw-r--r--alacritty_terminal/src/grid/mod.rs125
1 files changed, 77 insertions, 48 deletions
diff --git a/alacritty_terminal/src/grid/mod.rs b/alacritty_terminal/src/grid/mod.rs
index 21e7e2f9..1c23bfc8 100644
--- a/alacritty_terminal/src/grid/mod.rs
+++ b/alacritty_terminal/src/grid/mod.rs
@@ -223,25 +223,49 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> {
T: ResetDiscriminant<D>,
D: PartialEq,
{
- // Whether or not there is a scrolling region active, as long as it
- // starts at the top, we can do a full rotation which just involves
- // changing the start index.
+ let screen_lines = self.screen_lines().0;
+
+ // When rotating the entire region, just reset everything.
+ if positions >= region.end - region.start {
+ for i in region.start.0..region.end.0 {
+ let index = screen_lines - i - 1;
+ self.raw[index].reset(&self.cursor.template);
+ }
+
+ return;
+ }
+
+ // Which implementation we can use depends on the existence of a scrollback history.
//
- // To accommodate scroll regions, rows are reordered at the end.
- if region.start == Line(0) && self.max_scroll_limit == 0 {
- // Rotate the entire line buffer. If there's a scrolling region
- // active, the bottom lines are restored in the next step.
- self.raw.rotate_up(*positions);
-
- // Now, restore any scroll region lines.
- let lines = self.lines;
- for i in IndexRange(region.end..lines) {
- self.raw.swap_lines(i, i + positions);
+ // Since a scrollback history prevents us from rotating the entire buffer downwards, we
+ // instead have to rely on a slower, swap-based implementation.
+ if self.max_scroll_limit == 0 {
+ // Swap the lines fixed at the bottom to their target positions after rotation.
+ //
+ // Since we've made sure that the rotation will never rotate away the entire region, we
+ // know that the position of the fixed lines before the rotation must already be
+ // visible.
+ //
+ // We need to start from the top, to make sure the fixed lines aren't swapped with each
+ // other.
+ let fixed_lines = screen_lines - region.end.0;
+ for i in (0..fixed_lines).rev() {
+ self.raw.swap(i, i + positions.0);
}
- // Finally, reset recycled lines.
- for i in IndexRange(Line(0)..positions) {
- self.raw[i].reset(&self.cursor.template);
+ // Rotate the entire line buffer downward.
+ self.raw.rotate_down(*positions);
+
+ // Ensure all new lines are fully cleared.
+ for i in 0..positions.0 {
+ let index = screen_lines - i - 1;
+ self.raw[index].reset(&self.cursor.template);
+ }
+
+ // Swap the fixed lines at the top back into position.
+ for i in 0..region.start.0 {
+ let index = screen_lines - i - 1;
+ self.raw.swap(index, index - positions.0);
}
} else {
// Subregion rotation.
@@ -263,46 +287,51 @@ impl<T: GridCell + Default + PartialEq + Clone> Grid<T> {
T: ResetDiscriminant<D>,
D: PartialEq,
{
- let num_lines = self.screen_lines().0;
+ let screen_lines = self.screen_lines().0;
- if region.start == Line(0) {
- // Update display offset when not pinned to active area.
- if self.display_offset != 0 {
- self.display_offset = min(self.display_offset + *positions, self.max_scroll_limit);
+ // When rotating the entire region with fixed lines at the top, just reset everything.
+ if positions >= region.end - region.start && region.start != Line(0) {
+ for i in region.start.0..region.end.0 {
+ let index = screen_lines - i - 1;
+ self.raw[index].reset(&self.cursor.template);
}
- self.increase_scroll_limit(*positions);
+ return;
+ }
- // Rotate the entire line buffer. If there's a scrolling region
- // active, the bottom lines are restored in the next step.
- self.raw.rotate(-(*positions as isize));
+ // Update display offset when not pinned to active area.
+ if self.display_offset != 0 {
+ self.display_offset = min(self.display_offset + *positions, self.max_scroll_limit);
+ }
- // This next loop swaps "fixed" lines outside of a scroll region
- // back into place after the rotation. The work is done in buffer-
- // space rather than terminal-space to avoid redundant
- // transformations.
- let fixed_lines = num_lines - *region.end;
+ // Create scrollback for the new lines.
+ self.increase_scroll_limit(*positions);
- for i in 0..fixed_lines {
- self.raw.swap(i, i + *positions);
- }
+ // Swap the lines fixed at the top to their target positions after rotation.
+ //
+ // Since we've made sure that the rotation will never rotate away the entire region, we
+ // know that the position of the fixed lines before the rotation must already be
+ // visible.
+ //
+ // We need to start from the bottom, to make sure the fixed lines aren't swapped with each
+ // other.
+ for i in (0..region.start.0).rev() {
+ let index = screen_lines - i - 1;
+ self.raw.swap(index, index - positions.0);
+ }
- // Finally, reset recycled lines.
- //
- // Recycled lines are just above the end of the scrolling region.
- for i in 0..*positions {
- self.raw[i + fixed_lines].reset(&self.cursor.template);
- }
- } else {
- // Subregion rotation.
- for line in IndexRange(region.start..(region.end - positions)) {
- self.raw.swap_lines(line, line + positions);
- }
+ // Rotate the entire line buffer upward.
+ self.raw.rotate(-(positions.0 as isize));
- // Clear reused lines.
- for line in IndexRange((region.end - positions)..region.end) {
- self.raw[line].reset(&self.cursor.template);
- }
+ // Ensure all new lines are fully cleared.
+ for i in 0..positions.0 {
+ self.raw[i].reset(&self.cursor.template);
+ }
+
+ // Swap the fixed lines at the bottom back into position.
+ let fixed_lines = screen_lines - region.end.0;
+ for i in 0..fixed_lines {
+ self.raw.swap(i, i + positions.0);
}
}