Replace crossterm ScrollUp with universal workaround (#601)

Replace scrolling via escape sequence with workaround that prints newlines to retain scrollback
regardless of terminal implementation of scroll sequence
This commit is contained in:
Artemiy 2023-07-12 15:30:25 +03:00 committed by GitHub
parent cf841beb92
commit 4f31e200e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -10,7 +10,7 @@ use {
crossterm::{
cursor::{self, MoveTo, RestorePosition, SavePosition},
style::{Attribute, Print, ResetColor, SetAttribute, SetForegroundColor},
terminal::{self, Clear, ClearType, ScrollUp},
terminal::{self, Clear, ClearType},
QueueableCommand, Result,
},
std::io::Write,
@ -156,7 +156,7 @@ impl Painter {
self.prompt_start_row = 0;
} else if required_lines >= remaining_lines {
let extra = required_lines.saturating_sub(remaining_lines);
self.stdout.queue(ScrollUp(extra))?;
self.queue_universal_scroll(extra)?;
self.prompt_start_row = self.prompt_start_row.saturating_sub(extra);
}
@ -475,7 +475,7 @@ impl Painter {
let final_row = self.prompt_start_row + self.last_required_lines;
let scroll = final_row.saturating_sub(self.screen_height() - 1);
if scroll != 0 {
self.stdout.queue(ScrollUp(scroll))?;
self.queue_universal_scroll(scroll)?;
}
self.stdout
.queue(MoveTo(0, final_row.min(self.screen_height() - 1)))?;
@ -535,6 +535,28 @@ impl Painter {
}
Ok(())
}
/// Queue scroll of `num` lines to `self.stdout`.
///
/// On some platforms and terminals (e.g. windows terminal, alacritty on windows and linux)
/// using special escape sequence '\[e<num>S' (provided by [`ScrollUp`]) does not put lines
/// that go offscreen in scrollback history. This method prints newlines near the edge of screen
/// (which always works) instead. See [here](https://github.com/nushell/nushell/issues/9166)
/// for more info on subject.
///
/// ## Note
/// This method does not return cursor to the original position and leaves it at the first
/// column of last line. **Be sure to use [`MoveTo`] afterwards if this is not the desired
/// location**
fn queue_universal_scroll(&mut self, num: u16) -> Result<()> {
// If cursor is not near end of screen printing new will not scroll terminal.
// Move it to the last line to ensure that every newline results in scroll
self.stdout.queue(MoveTo(0, self.screen_height() - 1))?;
for _ in 0..num {
self.stdout.queue(Print(&coerce_crlf("\n")))?;
}
Ok(())
}
}
#[cfg(test)]