diff --git a/src/engine.rs b/src/engine.rs index 0c20861c3..41393cc71 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1050,6 +1050,7 @@ impl Reedline { | ReedlineEvent::MenuRight | ReedlineEvent::MenuPageNext | ReedlineEvent::MenuPagePrevious + | ReedlineEvent::PartialComplete | ReedlineEvent::ViChangeMode(_) => Ok(EventStatus::Inapplicable), } } @@ -1060,6 +1061,22 @@ impl Reedline { event: ReedlineEvent, ) -> io::Result { match event { + ReedlineEvent::PartialComplete => { + let Some(menu) = self.menus.iter_mut().find(|menu| menu.is_active()) else { + return Ok(EventStatus::Inapplicable); + }; + if self.partial_completions + && menu.can_partially_complete( + &mut self.editor, + self.completer.as_mut(), + self.history.as_ref(), + ) + { + Ok(EventStatus::Handled) + } else { + Ok(EventStatus::Inapplicable) + } + } ReedlineEvent::Menu(name) => { if self.active_menu().is_none() { if let Some(menu) = self.menus.iter_mut().find(|menu| menu.name() == name) { @@ -1077,15 +1094,19 @@ impl Reedline { } } - if self.partial_completions - && menu.can_partially_complete( - self.quick_completions, + if self.partial_completions { + if !self.quick_completions { + menu.update_values( + &mut self.editor, + self.completer.as_mut(), + self.history.as_ref(), + ); + } + menu.can_partially_complete( &mut self.editor, self.completer.as_mut(), self.history.as_ref(), - ) - { - return Ok(EventStatus::Handled); + ); } return Ok(EventStatus::Handled); @@ -1093,26 +1114,17 @@ impl Reedline { } Ok(EventStatus::Inapplicable) } - ReedlineEvent::MenuNext => { - if let Some(menu) = self.menus.iter_mut().find(|menu| menu.is_active()) { + ReedlineEvent::MenuNext => match self.active_menu() { + None => Ok(EventStatus::Inapplicable), + Some(menu) => { if menu.get_values().len() == 1 && menu.can_quick_complete() { self.handle_editor_event(prompt, ReedlineEvent::Enter) } else { - if self.partial_completions { - menu.can_partially_complete( - self.quick_completions, - &mut self.editor, - self.completer.as_mut(), - self.history.as_ref(), - ); - } menu.menu_event(MenuEvent::NextElement); Ok(EventStatus::Handled) } - } else { - Ok(EventStatus::Inapplicable) } - } + }, ReedlineEvent::MenuPrevious => { self.active_menu() .map_or(Ok(EventStatus::Inapplicable), |menu| { @@ -1304,7 +1316,6 @@ impl Reedline { .handle_editor_event(prompt, ReedlineEvent::Enter); } else if self.partial_completions && menu.can_partially_complete( - self.quick_completions, &mut self.editor, self.completer.as_mut(), self.history.as_ref(), diff --git a/src/enums.rs b/src/enums.rs index bccaf96ab..5ac465fc7 100644 --- a/src/enums.rs +++ b/src/enums.rs @@ -904,6 +904,9 @@ pub enum ReedlineEvent { /// Move to the previous history page MenuPagePrevious, + /// Complete the command given the common prefix of items in current open menu + PartialComplete, + /// Way to bind the execution of a whole command (directly returning from [`crate::Reedline::read_line()`]) to a keybinding ExecuteHostCommand(String), @@ -960,6 +963,7 @@ impl Display for ReedlineEvent { ReedlineEvent::ExecuteHostCommand(_) => write!(f, "ExecuteHostCommand"), ReedlineEvent::OpenEditor => write!(f, "OpenEditor"), ReedlineEvent::ViChangeMode(_) => write!(f, "ViChangeMode mode: "), + ReedlineEvent::PartialComplete => write!(f, "PartialComplete"), } } } diff --git a/src/menu/columnar_menu.rs b/src/menu/columnar_menu.rs index 4e19514b3..3e79211d5 100644 --- a/src/menu/columnar_menu.rs +++ b/src/menu/columnar_menu.rs @@ -514,19 +514,13 @@ impl Menu for ColumnarMenu { /// in the given line buffer fn can_partially_complete( &mut self, - values_updated: bool, editor: &mut Editor, completer: &mut dyn Completer, ) -> bool { - // If the values were already updated (e.g. quick completions are true) - // there is no need to update the values from the menu - if !values_updated { - self.update_values(editor, completer); - } - if can_partially_complete(self.get_values(), editor) { // The values need to be updated because the spans need to be // recalculated for accurate replacement in the string + // TODO: recalculate the spans instead of calling the completer 1 more time self.update_values(editor, completer); true @@ -784,7 +778,8 @@ mod tests { editor.set_buffer(input.to_string(), UndoBehavior::CreateUndoPoint); let mut completer = FakeCompleter::new(&$completions); - menu.can_partially_complete(false, &mut editor, &mut completer); + menu.update_values(&mut editor, &mut completer); + menu.can_partially_complete(&mut editor, &mut completer); assert_eq!(editor.get_buffer(), expected); } diff --git a/src/menu/description_menu.rs b/src/menu/description_menu.rs index a40552f21..ed8b521e4 100644 --- a/src/menu/description_menu.rs +++ b/src/menu/description_menu.rs @@ -419,7 +419,6 @@ impl Menu for DescriptionMenu { /// The menu does not need to partially complete fn can_partially_complete( &mut self, - _values_updated: bool, _editor: &mut Editor, _completer: &mut dyn Completer, ) -> bool { diff --git a/src/menu/ide_menu.rs b/src/menu/ide_menu.rs index 9fe29925e..2b9abfbe7 100644 --- a/src/menu/ide_menu.rs +++ b/src/menu/ide_menu.rs @@ -580,19 +580,13 @@ impl Menu for IdeMenu { fn can_partially_complete( &mut self, - values_updated: bool, editor: &mut Editor, completer: &mut dyn Completer, ) -> bool { - // If the values were already updated (e.g. quick completions are true) - // there is no need to update the values from the menu - if !values_updated { - self.update_values(editor, completer); - } - if can_partially_complete(self.get_values(), editor) { // The values need to be updated because the spans need to be // recalculated for accurate replacement in the string + // TODO: recalculate the spans instead of calling the completer 1 more time self.update_values(editor, completer); true @@ -1313,7 +1307,8 @@ mod tests { editor.set_buffer(input.to_string(), UndoBehavior::CreateUndoPoint); let mut completer = FakeCompleter::new(&$completions); - menu.can_partially_complete(false, &mut editor, &mut completer); + menu.update_values(&mut editor, &mut completer); + menu.can_partially_complete(&mut editor, &mut completer); assert_eq!(editor.get_buffer(), expected); } diff --git a/src/menu/list_menu.rs b/src/menu/list_menu.rs index 071d5ff5a..6d6dfda60 100644 --- a/src/menu/list_menu.rs +++ b/src/menu/list_menu.rs @@ -323,7 +323,6 @@ impl Menu for ListMenu { /// all registered values fn can_partially_complete( &mut self, - _values_updated: bool, _editor: &mut Editor, _completer: &mut dyn Completer, ) -> bool { diff --git a/src/menu/mod.rs b/src/menu/mod.rs index 8d1fc1652..1d43a10d1 100644 --- a/src/menu/mod.rs +++ b/src/menu/mod.rs @@ -106,7 +106,6 @@ pub trait Menu: Send { /// in the given line buffer fn can_partially_complete( &mut self, - values_updated: bool, editor: &mut Editor, completer: &mut dyn Completer, ) -> bool; @@ -306,23 +305,20 @@ impl ReedlineMenu { pub(crate) fn can_partially_complete( &mut self, - values_updated: bool, editor: &mut Editor, completer: &mut dyn Completer, history: &dyn History, ) -> bool { match self { - Self::EngineCompleter(menu) => { - menu.can_partially_complete(values_updated, editor, completer) - } + Self::EngineCompleter(menu) => menu.can_partially_complete(editor, completer), Self::HistoryMenu(menu) => { let mut history_completer = HistoryCompleter::new(history); - menu.can_partially_complete(values_updated, editor, &mut history_completer) + menu.can_partially_complete(editor, &mut history_completer) } Self::WithCompleter { menu, completer: own_completer, - } => menu.can_partially_complete(values_updated, editor, own_completer.as_mut()), + } => menu.can_partially_complete(editor, own_completer.as_mut()), } } @@ -399,18 +395,17 @@ impl Menu for ReedlineMenu { fn can_partially_complete( &mut self, - values_updated: bool, editor: &mut Editor, completer: &mut dyn Completer, ) -> bool { match self { Self::EngineCompleter(menu) | Self::HistoryMenu(menu) => { - menu.can_partially_complete(values_updated, editor, completer) + menu.can_partially_complete(editor, completer) } Self::WithCompleter { menu, completer: own_completer, - } => menu.can_partially_complete(values_updated, editor, own_completer.as_mut()), + } => menu.can_partially_complete(editor, own_completer.as_mut()), } }