Better behaviour on resize (#675)

* First shot at resolving the resizing issues with terminals

* Comment for known bug

* Checking the start row repeatedly to see how it affects performance

---------

Co-authored-by: Daniel Somerfield <daniel.somerfield@hatchdata.com>
This commit is contained in:
Daniel Somerfield 2023-12-15 09:18:05 -08:00 committed by GitHub
parent 0046da98b5
commit a4bfaa512b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 22 additions and 24 deletions

View File

@ -82,7 +82,7 @@ impl Painter {
/// Returns the available lines from the prompt down
pub fn remaining_lines(&self) -> u16 {
self.screen_height() - self.prompt_start_row
self.screen_height().saturating_sub(self.prompt_start_row)
}
/// Sets the prompt origin position and screen size for a new line editor
@ -151,8 +151,14 @@ impl Painter {
// Marking the painter state as larger buffer to avoid animations
self.large_buffer = required_lines >= screen_height;
// This might not be terribly performant. Testing it out
let is_reset = || match cursor::position() {
Ok(position) => position.1 < self.prompt_start_row,
Err(_) => false,
};
// Moving the start position of the cursor based on the size of the required lines
if self.large_buffer {
if self.large_buffer || is_reset() {
self.prompt_start_row = 0;
} else if required_lines >= remaining_lines {
let extra = required_lines.saturating_sub(remaining_lines);
@ -400,31 +406,22 @@ impl Painter {
/// Updates prompt origin and offset to handle a screen resize event
pub(crate) fn handle_resize(&mut self, width: u16, height: u16) {
let prev_terminal_size = self.terminal_size;
let prev_prompt_row = self.prompt_start_row;
self.terminal_size = (width, height);
if prev_prompt_row < height
&& height <= prev_terminal_size.1
&& width == prev_terminal_size.0
{
// The terminal got smaller in height but the start of the prompt is still visible
// The width didn't change
return;
}
// `cursor::position() is blocking and can timeout.
// The question is whether we can afford it. If not, perhaps we should use it in some scenarios but not others
// The problem is trying to calculate this internally doesn't seem to be reliable because terminals might
// have additional text in their buffer that messes with the offset on scroll.
// It seems like it _should_ be ok because it only happens on resize.
// Either:
// - The terminal got larger in height
// - Note: if the terminal doesn't have sufficient history, this will leave a trail
// of previous prompts currently.
// - Note: if the the prompt contains multiple lines, this will leave a trail of
// previous prompts currently.
// - The terminal got smaller in height and the whole prompt is no longer visible
// - Note: if the the prompt contains multiple lines, this will leave a trail of
// previous prompts currently.
// - The width changed
self.prompt_start_row = height.saturating_sub(1);
// Known bug: on iterm2 and kitty, clearing the screen via CMD-K doesn't reset
// the position. Might need to special-case this.
//
// I assume this is a bug with the position() call but haven't figured that
// out yet.
if let Ok(position) = cursor::position() {
self.prompt_start_row = position.1;
}
}
/// Writes `line` to the terminal with a following carriage return and newline

View File

@ -7,6 +7,7 @@ use crate::{
use std::borrow::Cow;
/// Aggregate of prompt and input string used by `Painter`
#[derive(Debug)]
pub(crate) struct PromptLines<'prompt> {
pub(crate) prompt_str_left: Cow<'prompt, str>,
pub(crate) prompt_str_right: Cow<'prompt, str>,