Skip to content

Commit

Permalink
Better behaviour on resize (#675)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
danielsomerfield and Daniel Somerfield authored Dec 15, 2023
1 parent 0046da9 commit a4bfaa5
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 24 deletions.
45 changes: 21 additions & 24 deletions src/painting/painter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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.

// 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;
}

// 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);
}

/// Writes `line` to the terminal with a following carriage return and newline
Expand Down
1 change: 1 addition & 0 deletions src/painting/prompt_lines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down

0 comments on commit a4bfaa5

Please sign in to comment.