Tab inline completion (#498)

* On backspace, deactivate menu and do not complete

Fixes #5497

* Make Tab insert (partial) completion instead of select next menu item

* Fix history search filtering
This commit is contained in:
Dan Davison 2022-10-22 16:52:11 -04:00 committed by GitHub
parent da27f0041a
commit 30713abe87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 36 additions and 12 deletions

View File

@ -55,6 +55,7 @@ impl Editor {
EditCommand::MoveWordRightEnd => self.line_buffer.move_word_right_end(), EditCommand::MoveWordRightEnd => self.line_buffer.move_word_right_end(),
EditCommand::MoveBigWordRightEnd => self.line_buffer.move_big_word_right_end(), EditCommand::MoveBigWordRightEnd => self.line_buffer.move_big_word_right_end(),
EditCommand::InsertChar(c) => self.line_buffer.insert_char(*c), EditCommand::InsertChar(c) => self.line_buffer.insert_char(*c),
EditCommand::Complete => {}
EditCommand::InsertString(str) => self.line_buffer.insert_str(str), EditCommand::InsertString(str) => self.line_buffer.insert_str(str),
EditCommand::InsertNewline => self.line_buffer.insert_newline(), EditCommand::InsertNewline => self.line_buffer.insert_newline(),
EditCommand::ReplaceChar(chr) => self.replace_char(*chr), EditCommand::ReplaceChar(chr) => self.replace_char(*chr),

View File

@ -915,25 +915,43 @@ impl Reedline {
self.run_edit_commands(&commands); self.run_edit_commands(&commands);
if let Some(menu) = self.menus.iter_mut().find(|men| men.is_active()) { if let Some(menu) = self.menus.iter_mut().find(|men| men.is_active()) {
if self.quick_completions && menu.can_quick_complete() { if self.quick_completions && menu.can_quick_complete() {
menu.menu_event(MenuEvent::Edit(self.quick_completions)); match commands.first() {
menu.update_values( Some(&EditCommand::Backspace)
&mut self.editor, | Some(&EditCommand::BackspaceWord)
self.completer.as_mut(), | Some(&EditCommand::MoveToLineStart) => {
self.history.as_ref(), menu.menu_event(MenuEvent::Deactivate)
); }
_ => {
if menu.get_values().len() == 1 { menu.menu_event(MenuEvent::Edit(self.quick_completions));
return self.handle_editor_event(prompt, ReedlineEvent::Enter); menu.update_values(
&mut self.editor,
self.completer.as_mut(),
self.history.as_ref(),
);
if let Some(&EditCommand::Complete) = commands.first() {
if menu.get_values().len() == 1 {
return 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(),
)
{
return Ok(EventStatus::Handled);
}
}
}
} }
} }
if self.editor.line_buffer().get_buffer().is_empty() { if self.editor.line_buffer().get_buffer().is_empty() {
menu.menu_event(MenuEvent::Deactivate); menu.menu_event(MenuEvent::Deactivate);
} else { } else {
menu.menu_event(MenuEvent::Edit(self.quick_completions)); menu.menu_event(MenuEvent::Edit(self.quick_completions));
} }
} }
Ok(EventStatus::Handled) Ok(EventStatus::Handled)
} }
ReedlineEvent::OpenEditor => self.open_editor().map(|_| EventStatus::Handled), ReedlineEvent::OpenEditor => self.open_editor().map(|_| EventStatus::Handled),

View File

@ -99,6 +99,9 @@ pub enum EditCommand {
/// Clear to the end of the current line /// Clear to the end of the current line
ClearToLineEnd, ClearToLineEnd,
/// Insert completion: entire completion if there is only one possibility, or else up to shared prefix.
Complete,
/// Cut the current line /// Cut the current line
CutCurrentLine, CutCurrentLine,
@ -216,6 +219,7 @@ impl Display for EditCommand {
EditCommand::DeleteWord => write!(f, "DeleteWord"), EditCommand::DeleteWord => write!(f, "DeleteWord"),
EditCommand::Clear => write!(f, "Clear"), EditCommand::Clear => write!(f, "Clear"),
EditCommand::ClearToLineEnd => write!(f, "ClearToLineEnd"), EditCommand::ClearToLineEnd => write!(f, "ClearToLineEnd"),
EditCommand::Complete => write!(f, "Complete"),
EditCommand::CutCurrentLine => write!(f, "CutCurrentLine"), EditCommand::CutCurrentLine => write!(f, "CutCurrentLine"),
EditCommand::CutFromStart => write!(f, "CutFromStart"), EditCommand::CutFromStart => write!(f, "CutFromStart"),
EditCommand::CutFromLineStart => write!(f, "CutFromLineStart"), EditCommand::CutFromLineStart => write!(f, "CutFromLineStart"),
@ -287,6 +291,7 @@ impl EditCommand {
| EditCommand::DeleteWord | EditCommand::DeleteWord
| EditCommand::Clear | EditCommand::Clear
| EditCommand::ClearToLineEnd | EditCommand::ClearToLineEnd
| EditCommand::Complete
| EditCommand::CutCurrentLine | EditCommand::CutCurrentLine
| EditCommand::CutFromStart | EditCommand::CutFromStart
| EditCommand::CutFromLineStart | EditCommand::CutFromLineStart

View File

@ -262,7 +262,7 @@ fn add_menu_keybindings(keybindings: &mut Keybindings) {
KeyCode::Tab, KeyCode::Tab,
ReedlineEvent::UntilFound(vec![ ReedlineEvent::UntilFound(vec![
ReedlineEvent::Menu("completion_menu".to_string()), ReedlineEvent::Menu("completion_menu".to_string()),
ReedlineEvent::MenuNext, ReedlineEvent::Edit(vec![EditCommand::Complete]),
]), ]),
); );