render right prompt on the last line of the left prompt (#492)

* render right prompt on the last line of the left prompt

Closes nushell/nushell#4909

* make rendering the right prompt on the last line configurable

* calculate width of the line where right prompt will be rendered
This commit is contained in:
nibon7 2022-10-21 03:57:01 +08:00 committed by GitHub
parent 21f5e125de
commit 8e1511ad05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 10 deletions

View File

@ -182,12 +182,19 @@ impl Painter {
let start_position = self
.screen_width()
.saturating_sub(prompt_length_right as u16);
let input_width = lines.estimate_first_input_line_width();
let screen_width = self.screen_width();
let input_width = lines.estimate_right_prompt_line_width(screen_width);
let mut row = self.prompt_start_row;
if lines.right_prompt_on_last_line {
let required_lines = lines.required_lines(screen_width, None);
row += required_lines.saturating_sub(1);
}
if input_width <= start_position {
self.stdout
.queue(SavePosition)?
.queue(cursor::MoveTo(start_position, self.prompt_start_row))?
.queue(cursor::MoveTo(start_position, row))?
.queue(Print(&coerce_crlf(&lines.prompt_str_right)))?
.queue(RestorePosition)?;
}

View File

@ -14,6 +14,7 @@ pub(crate) struct PromptLines<'prompt> {
pub(crate) before_cursor: Cow<'prompt, str>,
pub(crate) after_cursor: Cow<'prompt, str>,
pub(crate) hint: Cow<'prompt, str>,
pub(crate) right_prompt_on_last_line: bool,
}
impl<'prompt> PromptLines<'prompt> {
@ -39,6 +40,7 @@ impl<'prompt> PromptLines<'prompt> {
let before_cursor = coerce_crlf(before_cursor);
let after_cursor = coerce_crlf(after_cursor);
let hint = coerce_crlf(hint);
let right_prompt_on_last_line = prompt.right_prompt_on_last_line();
Self {
prompt_str_left,
@ -47,6 +49,7 @@ impl<'prompt> PromptLines<'prompt> {
before_cursor,
after_cursor,
hint,
right_prompt_on_last_line,
}
}
@ -91,8 +94,9 @@ impl<'prompt> PromptLines<'prompt> {
lines.saturating_sub(1) as u16
}
/// Estimated width of the actual input
pub(crate) fn estimate_first_input_line_width(&self) -> u16 {
/// Estimated width of the line where right prompt will be rendered
pub(crate) fn estimate_right_prompt_line_width(&self, terminal_columns: u16) -> u16 {
let first_line_left_prompt = self.prompt_str_left.lines().next();
let last_line_left_prompt = self.prompt_str_left.lines().last();
let prompt_lines_total = self.before_cursor.to_string() + &self.after_cursor + &self.hint;
@ -100,14 +104,30 @@ impl<'prompt> PromptLines<'prompt> {
let mut estimate = 0; // space in front of the input
if let Some(last_line_left_prompt) = last_line_left_prompt {
estimate += line_width(last_line_left_prompt);
}
if self.right_prompt_on_last_line {
if let Some(last_line_left_prompt) = last_line_left_prompt {
estimate += line_width(last_line_left_prompt);
estimate += line_width(&self.prompt_indicator);
estimate += line_width(&self.prompt_indicator);
if let Some(prompt_lines_first) = prompt_lines_first {
estimate += line_width(prompt_lines_first);
}
}
} else {
// Render right prompt on the first line
let required_lines = estimate_required_lines(&self.prompt_str_left, terminal_columns);
if let Some(first_line_left_prompt) = first_line_left_prompt {
estimate += line_width(first_line_left_prompt);
}
if let Some(prompt_lines_first) = prompt_lines_first {
estimate += line_width(prompt_lines_first);
// A single line
if required_lines == 1 {
estimate += line_width(&self.prompt_indicator);
if let Some(prompt_lines_first) = prompt_lines_first {
estimate += line_width(prompt_lines_first);
}
}
}
if estimate > u16::MAX as usize {

View File

@ -113,4 +113,9 @@ pub trait Prompt: Send {
fn get_prompt_right_color(&self) -> Color {
DEFAULT_PROMPT_RIGHT_COLOR
}
/// Whether to render right prompt on the last line
fn right_prompt_on_last_line(&self) -> bool {
false
}
}