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 let start_position = self
.screen_width() .screen_width()
.saturating_sub(prompt_length_right as u16); .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 { if input_width <= start_position {
self.stdout self.stdout
.queue(SavePosition)? .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(Print(&coerce_crlf(&lines.prompt_str_right)))?
.queue(RestorePosition)?; .queue(RestorePosition)?;
} }

View File

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

View File

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