diff --git a/src/grid/mod.rs b/src/grid/mod.rs index 9b36fcdf..0998d640 100644 --- a/src/grid/mod.rs +++ b/src/grid/mod.rs @@ -334,7 +334,6 @@ impl Grid { /// scroll_up moves lines at the bottom towards the top /// /// This is the performance-sensitive part of scrolling. - #[inline] pub fn scroll_up( &mut self, region: &Range, @@ -356,17 +355,21 @@ impl Grid { selection.rotate(*positions as isize); } - // Now, restore any lines outside the scroll region - for idx in (*region.end .. *self.num_lines()).rev() { - // First do the swap - self.raw.swap_lines(Line(idx), Line(idx) - positions); + // // 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 = *self.num_lines() - *region.end; + + for i in 0..fixed_lines { + self.raw.swap(i, i + *positions); } // Finally, reset recycled lines // // Recycled lines are just above the end of the scrolling region. for i in 0..*positions { - self.raw[region.end - i - 1].reset(&template); + self.raw[i + fixed_lines].reset(&template); } } else { // Subregion rotation diff --git a/src/grid/storage.rs b/src/grid/storage.rs index e7c1a307..eb87c622 100644 --- a/src/grid/storage.rs +++ b/src/grid/storage.rs @@ -171,12 +171,25 @@ impl Storage { self.len } - /// Compute actual index in underlying storage given the requested index. #[inline] + pub fn raw_len(&self) -> usize { + self.inner.len() + } + + /// Compute actual index in underlying storage given the requested index. fn compute_index(&self, requested: usize) -> usize { (requested + self.zero) % self.inner.len() } + #[inline] + pub fn line_offset(&self) -> usize { + self.inner.len() + self.zero + *self.visible_lines + } + + pub fn compute_line_index(&self, a: Line) -> usize { + (self.line_offset() - *a) % self.inner.len() + } + pub fn swap_lines(&mut self, a: Line, b: Line) { let offset = self.inner.len() + self.zero + *self.visible_lines; let a = (offset - *a) % self.inner.len(); @@ -184,6 +197,19 @@ impl Storage { self.inner.swap(a, b); } + /// Swap two lines in raw buffer + /// + /// # Panics + /// + /// `swap` will panic if either `a` or `b` are out-of-bounds of the + /// underlying storage. + pub fn swap(&mut self, a: usize, b: usize) { + let a = self.compute_index(a); + let b = self.compute_index(b); + + self.inner.swap(a, b); + } + /// Iterator over *logical* entries in the storage /// /// This *does not* iterate over hidden entries.