Skip to content

Commit

Permalink
fix multiline prompt cursor pos
Browse files Browse the repository at this point in the history
  • Loading branch information
maxomatic458 committed Jan 18, 2024
1 parent 1970a03 commit 980f921
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 15 deletions.
7 changes: 6 additions & 1 deletion src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1663,7 +1663,7 @@ impl Reedline {
// Needs to add return carriage to newlines because when not in raw mode
// some OS don't fully return the carriage

let lines = PromptLines::new(
let mut lines = PromptLines::new(

Check warning on line 1666 in src/engine.rs

View check run for this annotation

Codecov / codecov/patch

src/engine.rs#L1666

Added line #L1666 was not covered by tests
prompt,
self.prompt_edit_mode(),
None,
Expand All @@ -1675,6 +1675,11 @@ impl Reedline {
// Updating the working details of the active menu
for menu in self.menus.iter_mut() {
if menu.is_active() {
lines.prompt_indicator = menu.indicator().to_owned().into();
// If the menu requires the cursor position, update it (ide menu)
let cursor_pos = lines.cursor_pos(self.painter.screen_width());
menu.set_cursor_pos(cursor_pos);

Check warning on line 1682 in src/engine.rs

View check run for this annotation

Codecov / codecov/patch

src/engine.rs#L1678-L1682

Added lines #L1678 - L1682 were not covered by tests
menu.update_working_details(
&mut self.editor,
self.completer.as_mut(),
Expand Down
4 changes: 4 additions & 0 deletions src/menu/columnar_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,10 @@ impl Menu for ColumnarMenu {
.collect()
}
}

fn set_cursor_pos(&mut self, _pos: (u16, u16)) {
// The columnar menu does not need the cursor position
}

Check warning on line 734 in src/menu/columnar_menu.rs

View check run for this annotation

Codecov / codecov/patch

src/menu/columnar_menu.rs#L732-L734

Added lines #L732 - L734 were not covered by tests
}

#[cfg(test)]
Expand Down
8 changes: 7 additions & 1 deletion src/menu/ide_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ impl Default for DefaultIdeMenuDetails {

#[derive(Default)]
struct IdeMenuDetails {
/// Column of the cursor
pub cursor_col: u16,
/// Width of the menu, including the padding and border and the description
pub menu_width: u16,
/// width of the completion box, including the padding and border
Expand Down Expand Up @@ -736,7 +738,7 @@ impl Menu for IdeMenu {
});

let terminal_width = painter.screen_width();
let cursor_pos = crossterm::cursor::position().unwrap().0;
let cursor_pos = self.working_details.cursor_col;

Check warning on line 741 in src/menu/ide_menu.rs

View check run for this annotation

Codecov / codecov/patch

src/menu/ide_menu.rs#L738-L741

Added lines #L738 - L741 were not covered by tests

let border_width = if self.default_details.border.is_some() {
2

Check warning on line 744 in src/menu/ide_menu.rs

View check run for this annotation

Codecov / codecov/patch

src/menu/ide_menu.rs#L743-L744

Added lines #L743 - L744 were not covered by tests
Expand Down Expand Up @@ -1038,6 +1040,10 @@ impl Menu for IdeMenu {
strings.join("\r\n")

Check warning on line 1040 in src/menu/ide_menu.rs

View check run for this annotation

Codecov / codecov/patch

src/menu/ide_menu.rs#L1040

Added line #L1040 was not covered by tests
}
}

Check warning on line 1042 in src/menu/ide_menu.rs

View check run for this annotation

Codecov / codecov/patch

src/menu/ide_menu.rs#L1042

Added line #L1042 was not covered by tests

fn set_cursor_pos(&mut self, pos: (u16, u16)) {
self.working_details.cursor_col = pos.0;
}

Check warning on line 1046 in src/menu/ide_menu.rs

View check run for this annotation

Codecov / codecov/patch

src/menu/ide_menu.rs#L1044-L1046

Added lines #L1044 - L1046 were not covered by tests
}

/// Split the input into strings that are at most `max_length` (in columns, not in chars) long
Expand Down
4 changes: 4 additions & 0 deletions src/menu/list_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,10 @@ impl Menu for ListMenu {
fn min_rows(&self) -> u16 {
self.max_lines + 1
}

fn set_cursor_pos(&mut self, _pos: (u16, u16)) {
// The list menu does not need the cursor position
}

Check warning on line 676 in src/menu/list_menu.rs

View check run for this annotation

Codecov / codecov/patch

src/menu/list_menu.rs#L674-L676

Added lines #L674 - L676 were not covered by tests
}

fn number_of_lines(entry: &str, max_lines: usize, terminal_columns: u16) -> u16 {
Expand Down
6 changes: 6 additions & 0 deletions src/menu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ pub trait Menu: Send {

/// Gets cached values from menu that will be displayed
fn get_values(&self) -> &[Suggestion];
/// Sets the position of the cursor (currently only required by the IDE menu)
fn set_cursor_pos(&mut self, pos: (u16, u16));
}

/// Allowed menus in Reedline
Expand Down Expand Up @@ -314,4 +316,8 @@ impl Menu for ReedlineMenu {
fn get_values(&self) -> &[Suggestion] {
self.as_ref().get_values()
}

fn set_cursor_pos(&mut self, pos: (u16, u16)) {
self.as_mut().set_cursor_pos(pos);
}

Check warning on line 322 in src/menu/mod.rs

View check run for this annotation

Codecov / codecov/patch

src/menu/mod.rs#L320-L322

Added lines #L320 - L322 were not covered by tests
}
17 changes: 4 additions & 13 deletions src/painting/painter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,17 +271,13 @@ impl Painter {
self.stdout
.queue(Print(&coerce_crlf(&lines.prompt_str_left)))?;

let prompt_indicator = match menu {
Some(menu) => menu.indicator(),
None => &lines.prompt_indicator,
};

if use_ansi_coloring {
self.stdout
.queue(SetForegroundColor(prompt.get_indicator_color()))?;
}

self.stdout.queue(Print(&coerce_crlf(prompt_indicator)))?;
self.stdout
.queue(Print(&coerce_crlf(&lines.prompt_indicator)))?;

Check warning on line 280 in src/painting/painter.rs

View check run for this annotation

Codecov / codecov/patch

src/painting/painter.rs#L279-L280

Added lines #L279 - L280 were not covered by tests

if use_ansi_coloring {
self.stdout
Expand Down Expand Up @@ -327,12 +323,7 @@ impl Painter {
// indicator is printed in the same line as the first line of the buffer
let prompt_lines = lines.prompt_lines_with_wrap(screen_width) as usize;

let prompt_indicator = match menu {
Some(menu) => menu.indicator(),
None => &lines.prompt_indicator,
};

let prompt_indicator_lines = prompt_indicator.lines().count();
let prompt_indicator_lines = &lines.prompt_indicator.lines().count();

Check warning on line 326 in src/painting/painter.rs

View check run for this annotation

Codecov / codecov/patch

src/painting/painter.rs#L326

Added line #L326 was not covered by tests
let before_cursor_lines = lines.before_cursor.lines().count();
let total_lines_before = prompt_lines + prompt_indicator_lines + before_cursor_lines - 1;

Expand All @@ -357,7 +348,7 @@ impl Painter {
// Adjusting extra_rows base on the calculated prompt line size
let extra_rows = extra_rows.saturating_sub(prompt_lines);

let indicator_skipped = skip_buffer_lines(prompt_indicator, extra_rows, None);
let indicator_skipped = skip_buffer_lines(&lines.prompt_indicator, extra_rows, None);

Check warning on line 351 in src/painting/painter.rs

View check run for this annotation

Codecov / codecov/patch

src/painting/painter.rs#L351

Added line #L351 was not covered by tests
self.stdout.queue(Print(&coerce_crlf(indicator_skipped)))?;

if use_ansi_coloring {
Expand Down
16 changes: 16 additions & 0 deletions src/painting/prompt_lines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,22 @@ impl<'prompt> PromptLines<'prompt> {
lines.saturating_sub(1) as u16
}

/// Calculate the cursor pos, based on the buffer and prompt.
/// The height is relative to the prompt
pub(crate) fn cursor_pos(&self, terminal_columns: u16) -> (u16, u16) {
// If we have a multiline prompt (e.g starship), we expect the cursor to be on the last line
let prompt_str = self.prompt_str_left.lines().last().unwrap_or_default();
let prompt_width = line_width(&format!("{}{}", prompt_str, self.prompt_indicator));
let buffer_width = line_width(&self.before_cursor);

let total_width = prompt_width + buffer_width;

let cursor_x = (total_width % terminal_columns as usize) as u16;
let cursor_y = (total_width / terminal_columns as usize) as u16;

(cursor_x, cursor_y)
}

Check warning on line 105 in src/painting/prompt_lines.rs

View check run for this annotation

Codecov / codecov/patch

src/painting/prompt_lines.rs#L93-L105

Added lines #L93 - L105 were not covered by tests

/// Total lines that the prompt uses considering that it may wrap the screen
pub(crate) fn prompt_lines_with_wrap(&self, screen_width: u16) -> u16 {
let complete_prompt = self.prompt_str_left.to_string() + &self.prompt_indicator;
Expand Down

0 comments on commit 980f921

Please sign in to comment.