diff --git a/src/engine.rs b/src/engine.rs index 0ec861bc..9d35e615 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -801,6 +801,25 @@ impl Reedline { } return Ok(signal); } + EventStatus::MenuUpdated => { + if self.input_mode == InputMode::HistorySearch { + self.history_search_paint(prompt)? + } else { + // Updating the working details of the active menu + for menu in self.menus.iter_mut() { + if menu.is_active() { + menu.update_working_details( + &mut self.editor, + self.completer.as_mut(), + self.history.as_ref(), + &self.painter, + ); + self.painter.print_menu(menu, self.use_ansi_coloring)?; + break; + } + } + } + } EventStatus::Handled => { self.repaint(prompt)?; } @@ -981,7 +1000,7 @@ impl Reedline { ); } menu.menu_event(MenuEvent::NextElement); - Ok(EventStatus::Handled) + Ok(EventStatus::MenuUpdated) } } else { Ok(EventStatus::Inapplicable) @@ -991,49 +1010,49 @@ impl Reedline { self.active_menu() .map_or(Ok(EventStatus::Inapplicable), |menu| { menu.menu_event(MenuEvent::PreviousElement); - Ok(EventStatus::Handled) + Ok(EventStatus::MenuUpdated) }) } ReedlineEvent::MenuUp => { self.active_menu() .map_or(Ok(EventStatus::Inapplicable), |menu| { menu.menu_event(MenuEvent::MoveUp); - Ok(EventStatus::Handled) + Ok(EventStatus::MenuUpdated) }) } ReedlineEvent::MenuDown => { self.active_menu() .map_or(Ok(EventStatus::Inapplicable), |menu| { menu.menu_event(MenuEvent::MoveDown); - Ok(EventStatus::Handled) + Ok(EventStatus::MenuUpdated) }) } ReedlineEvent::MenuLeft => { self.active_menu() .map_or(Ok(EventStatus::Inapplicable), |menu| { menu.menu_event(MenuEvent::MoveLeft); - Ok(EventStatus::Handled) + Ok(EventStatus::MenuUpdated) }) } ReedlineEvent::MenuRight => { self.active_menu() .map_or(Ok(EventStatus::Inapplicable), |menu| { menu.menu_event(MenuEvent::MoveRight); - Ok(EventStatus::Handled) + Ok(EventStatus::MenuUpdated) }) } ReedlineEvent::MenuPageNext => { self.active_menu() .map_or(Ok(EventStatus::Inapplicable), |menu| { menu.menu_event(MenuEvent::NextPage); - Ok(EventStatus::Handled) + Ok(EventStatus::MenuUpdated) }) } ReedlineEvent::MenuPagePrevious => { self.active_menu() .map_or(Ok(EventStatus::Inapplicable), |menu| { menu.menu_event(MenuEvent::PreviousPage); - Ok(EventStatus::Handled) + Ok(EventStatus::MenuUpdated) }) } ReedlineEvent::HistoryHintComplete => { @@ -1241,6 +1260,9 @@ impl Reedline { EventStatus::Handled => { latest_signal = EventStatus::Handled; } + EventStatus::MenuUpdated => { + latest_signal = EventStatus::MenuUpdated; + } EventStatus::Inapplicable => { // NO OP } diff --git a/src/enums.rs b/src/enums.rs index 72cacc43..6eea1c8b 100644 --- a/src/enums.rs +++ b/src/enums.rs @@ -802,6 +802,7 @@ impl Display for ReedlineEvent { pub(crate) enum EventStatus { Handled, Inapplicable, + MenuUpdated, Exits(Signal), } diff --git a/src/painting/painter.rs b/src/painting/painter.rs index bf2917ec..69ede302 100644 --- a/src/painting/painter.rs +++ b/src/painting/painter.rs @@ -93,6 +93,7 @@ pub struct Painter { prompt_start_row: u16, terminal_size: (u16, u16), last_required_lines: u16, + last_cursor_distance: u16, large_buffer: bool, just_resized: bool, after_cursor_lines: Option, @@ -105,6 +106,7 @@ impl Painter { prompt_start_row: 0, terminal_size: (0, 0), last_required_lines: 0, + last_cursor_distance: 0, large_buffer: false, just_resized: false, after_cursor_lines: None, @@ -296,22 +298,15 @@ impl Painter { Ok(()) } - fn print_menu( - &mut self, - menu: &dyn Menu, - lines: &PromptLines, - use_ansi_coloring: bool, - ) -> Result<()> { - let screen_width = self.screen_width(); + pub(crate) fn print_menu(&mut self, menu: &dyn Menu, use_ansi_coloring: bool) -> Result<()> { let screen_height = self.screen_height(); - let cursor_distance = lines.distance_from_prompt(screen_width); // If there is not enough space to print the menu, then the starting // drawing point for the menu will overwrite the last rows in the buffer - let starting_row = if cursor_distance >= screen_height.saturating_sub(1) { + let starting_row = if self.last_cursor_distance >= screen_height.saturating_sub(1) { screen_height.saturating_sub(menu.min_rows()) } else { - self.prompt_start_row + cursor_distance + 1 + self.prompt_start_row + self.last_cursor_distance + 1 }; let remaining_lines = screen_height.saturating_sub(starting_row); @@ -319,9 +314,10 @@ impl Painter { self.stdout .queue(cursor::MoveTo(0, starting_row))? .queue(Clear(ClearType::FromCursorDown))? - .queue(Print(menu_string.trim_end_matches('\n')))?; + .queue(Print(menu_string.trim_end_matches('\n')))? + .queue(RestorePosition)?; - Ok(()) + self.stdout.flush() } fn print_small_buffer( @@ -367,7 +363,9 @@ impl Painter { .queue(Print(&lines.after_cursor))?; if let Some(menu) = menu { - self.print_menu(menu, lines, use_ansi_coloring)?; + let screen_width = self.screen_width(); + self.last_cursor_distance = lines.distance_from_prompt(screen_width); + self.print_menu(menu, use_ansi_coloring)?; } else { self.stdout.queue(Print(&lines.hint))?; } @@ -464,7 +462,9 @@ impl Painter { } else { self.stdout.queue(Print(&lines.after_cursor))?; } - self.print_menu(menu, lines, use_ansi_coloring)?; + let screen_width = self.screen_width(); + self.last_cursor_distance = lines.distance_from_prompt(screen_width); + self.print_menu(menu, use_ansi_coloring)?; } else { // Selecting lines for the hint // The -1 subtraction is done because the remaining lines consider the line where the