Skip to content

Commit 98ea337

Browse files
committed
Add config for keeping menu always open
1 parent 7af8959 commit 98ea337

File tree

5 files changed

+90
-6
lines changed

5 files changed

+90
-6
lines changed

examples/ide_completions.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ fn add_menu_keybindings(keybindings: &mut Keybindings) {
1717
KeyCode::Tab,
1818
ReedlineEvent::UntilFound(vec![
1919
ReedlineEvent::Menu("completion_menu".to_string()),
20-
ReedlineEvent::MenuNext,
20+
ReedlineEvent::MenuAccept,
2121
]),
2222
);
2323
keybindings.add_binding(
@@ -96,7 +96,10 @@ fn main() -> io::Result<()> {
9696
.with_min_description_width(min_description_width)
9797
.with_max_description_width(max_description_width)
9898
.with_description_offset(description_offset)
99-
.with_correct_cursor_pos(correct_cursor_pos);
99+
.with_correct_cursor_pos(correct_cursor_pos)
100+
.with_activate_on_start(true)
101+
.with_keep_active_after_accept(true)
102+
.with_treat_submit_as_accept(false);
100103

101104
if border {
102105
ide_menu = ide_menu.with_default_border();

src/completion/default.rs

+10
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,16 @@ impl Completer for DefaultCompleter {
118118
}
119119
}
120120
}
121+
} else {
122+
let span = Span::new(0, 0);
123+
completions.extend(self.root.collect("").into_iter().map(|value| Suggestion {
124+
value,
125+
description: None,
126+
style: None,
127+
extra: None,
128+
span,
129+
append_whitespace: false,
130+
}));
121131
}
122132
completions.dedup();
123133
completions

src/engine.rs

+44-4
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,9 @@ impl Reedline {
516516
#[must_use]
517517
pub fn with_menu(mut self, menu: ReedlineMenu) -> Self {
518518
self.menus.push(menu);
519+
if self.active_menu().is_none() {
520+
self.activate_menus_on_start();
521+
}
519522
self
520523
}
521524

@@ -915,6 +918,7 @@ impl Reedline {
915918
| ReedlineEvent::HistoryHintWordComplete
916919
| ReedlineEvent::OpenEditor
917920
| ReedlineEvent::Menu(_)
921+
| ReedlineEvent::MenuAccept
918922
| ReedlineEvent::MenuNext
919923
| ReedlineEvent::MenuPrevious
920924
| ReedlineEvent::MenuUp
@@ -965,6 +969,24 @@ impl Reedline {
965969
}
966970
Ok(EventStatus::Inapplicable)
967971
}
972+
ReedlineEvent::MenuAccept => {
973+
match self.menus.iter_mut().find(|menu| menu.is_active()) {
974+
None => Ok(EventStatus::Inapplicable),
975+
Some(menu) => {
976+
menu.replace_in_buffer(&mut self.editor);
977+
if !menu.settings().keep_active_after_accept {
978+
menu.menu_event(MenuEvent::Deactivate);
979+
} else {
980+
menu.update_values(
981+
&mut self.editor,
982+
self.completer.as_mut(),
983+
self.history.as_ref(),
984+
);
985+
}
986+
Ok(EventStatus::Handled)
987+
}
988+
}
989+
}
968990
ReedlineEvent::MenuNext => match self.active_menu() {
969991
None => Ok(EventStatus::Inapplicable),
970992
Some(menu) => {
@@ -1083,13 +1105,23 @@ impl Reedline {
10831105
Ok(EventStatus::Handled)
10841106
}
10851107
ReedlineEvent::Enter | ReedlineEvent::Submit | ReedlineEvent::SubmitOrNewline
1086-
if self.menus.iter().any(|menu| menu.is_active()) =>
1108+
if self
1109+
.menus
1110+
.iter()
1111+
.any(|menu| menu.is_active() && menu.settings().treat_submit_as_accept) =>
10871112
{
10881113
for menu in self.menus.iter_mut() {
1089-
if menu.is_active() {
1114+
if menu.is_active() && menu.settings().treat_submit_as_accept {
10901115
menu.replace_in_buffer(&mut self.editor);
1091-
menu.menu_event(MenuEvent::Deactivate);
1092-
1116+
if !menu.settings().keep_active_after_accept {
1117+
menu.menu_event(MenuEvent::Deactivate);
1118+
} else {
1119+
menu.update_values(
1120+
&mut self.editor,
1121+
self.completer.as_mut(),
1122+
self.history.as_ref(),
1123+
);
1124+
}
10931125
return Ok(EventStatus::Handled);
10941126
}
10951127
}
@@ -1271,6 +1303,13 @@ impl Reedline {
12711303
.for_each(|menu| menu.menu_event(MenuEvent::Deactivate));
12721304
}
12731305

1306+
fn activate_menus_on_start(&mut self) {
1307+
self.menus
1308+
.iter_mut()
1309+
.filter(|menu| menu.settings().activate_on_start)
1310+
.for_each(|menu| menu.menu_event(MenuEvent::Activate(false)));
1311+
}
1312+
12741313
fn previous_history(&mut self) {
12751314
if self.history_cursor_on_excluded {
12761315
self.history_cursor_on_excluded = false;
@@ -1875,6 +1914,7 @@ impl Reedline {
18751914
}
18761915
self.run_edit_commands(&[EditCommand::Clear]);
18771916
self.editor.reset_undo_stack();
1917+
self.activate_menus_on_start();
18781918

18791919
Ok(EventStatus::Exits(Signal::Success(buffer)))
18801920
}

src/enums.rs

+4
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,9 @@ pub enum ReedlineEvent {
615615
/// Trigger a menu event. It activates a menu with the event name
616616
Menu(String),
617617

618+
/// Accepts the current menu suggestion
619+
MenuAccept,
620+
618621
/// Next element in the menu
619622
MenuNext,
620623

@@ -677,6 +680,7 @@ impl Display for ReedlineEvent {
677680
ReedlineEvent::Multiple(_) => write!(f, "Multiple[ {{ ReedLineEvents, }} ]"),
678681
ReedlineEvent::UntilFound(_) => write!(f, "UntilFound [ {{ ReedLineEvents, }} ]"),
679682
ReedlineEvent::Menu(_) => write!(f, "Menu Name: <string>"),
683+
ReedlineEvent::MenuAccept => write!(f, "MenuAccept"),
680684
ReedlineEvent::MenuNext => write!(f, "MenuNext"),
681685
ReedlineEvent::MenuPrevious => write!(f, "MenuPrevious"),
682686
ReedlineEvent::MenuUp => write!(f, "MenuUp"),

src/menu/mod.rs

+27
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ pub struct MenuSettings {
160160
/// Calls the completer using only the line buffer difference difference
161161
/// after the menu was activated
162162
only_buffer_difference: bool,
163+
pub(crate) activate_on_start: bool,
164+
pub(crate) keep_active_after_accept: bool,
165+
pub(crate) treat_submit_as_accept: bool,
163166
}
164167

165168
impl Default for MenuSettings {
@@ -169,6 +172,9 @@ impl Default for MenuSettings {
169172
color: MenuTextStyle::default(),
170173
marker: "| ".to_string(),
171174
only_buffer_difference: false,
175+
activate_on_start: false,
176+
keep_active_after_accept: false,
177+
treat_submit_as_accept: true,
172178
}
173179
}
174180
}
@@ -268,6 +274,27 @@ pub trait MenuBuilder: Menu + Sized {
268274
self.settings_mut().only_buffer_difference = only_buffer_difference;
269275
self
270276
}
277+
278+
/// Menu builder with new value for activate_on_start
279+
#[must_use]
280+
fn with_activate_on_start(mut self, activate_on_start: bool) -> Self {
281+
self.settings_mut().activate_on_start = activate_on_start;
282+
self
283+
}
284+
285+
/// Menu builder with new value for keep_active_after_accept
286+
#[must_use]
287+
fn with_keep_active_after_accept(mut self, keep_active_after_accept: bool) -> Self {
288+
self.settings_mut().keep_active_after_accept = keep_active_after_accept;
289+
self
290+
}
291+
292+
/// Menu builder with new value for treat_submit_as_accept
293+
#[must_use]
294+
fn with_treat_submit_as_accept(mut self, treat_submit_as_accept: bool) -> Self {
295+
self.settings_mut().treat_submit_as_accept = treat_submit_as_accept;
296+
self
297+
}
271298
}
272299

273300
/// Allowed menus in Reedline

0 commit comments

Comments
 (0)