diff options
author | Frojdholm | 2022-08-31 16:26:21 +0000 |
---|---|---|
committer | GitHub | 2022-08-31 16:26:21 +0000 |
commit | 4c9f144dace484ca99cc84053493ed7b5f6946ac (patch) | |
tree | 8bff0da654a9c2ecd33fa1ad7530140a68e0667d /helix-term/src/ui | |
parent | e3e71fa36be14659f0eabe1d4c80ef7e68135a6a (diff) |
fix: Recalculate completion when going through prompt history (#3193)
* fix: Recalculate completion when going through prompt history
* Update completion when the prompt line is changed
It should not be possible to update the line without also updating the
completion since the completion holds an index into the line.
* Fix Prompt::with_line recalculate completion
with_line was the last function where recalculate completion had to be
done manually. This function now also recalculates the completion so
that it's impossible to forget.
* Exit selection when recalculating completion
Keeping the selection index when the completion has been recalculated
doesn't make sense. This clears the selection automatically, removing
most needs to manually clear it.
* Remove &mut on save_filter
Co-authored-by: Blaž Hrastnik <blaz@mxxn.io>
Diffstat (limited to 'helix-term/src/ui')
-rw-r--r-- | helix-term/src/ui/mod.rs | 19 | ||||
-rw-r--r-- | helix-term/src/ui/picker.rs | 2 | ||||
-rw-r--r-- | helix-term/src/ui/prompt.rs | 79 |
3 files changed, 47 insertions, 53 deletions
diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 485ee848..01ffe243 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -35,10 +35,10 @@ pub fn prompt( completion_fn: impl FnMut(&Editor, &str) -> Vec<prompt::Completion> + 'static, callback_fn: impl FnMut(&mut crate::compositor::Context, &str, PromptEvent) + 'static, ) { - show_prompt( - cx, - Prompt::new(prompt, history_register, completion_fn, callback_fn), - ); + let mut prompt = Prompt::new(prompt, history_register, completion_fn, callback_fn); + // Calculate the initial completion + prompt.recalculate_completion(cx.editor); + cx.push_layer(Box::new(prompt)); } pub fn prompt_with_input( @@ -49,15 +49,8 @@ pub fn prompt_with_input( completion_fn: impl FnMut(&Editor, &str) -> Vec<prompt::Completion> + 'static, callback_fn: impl FnMut(&mut crate::compositor::Context, &str, PromptEvent) + 'static, ) { - show_prompt( - cx, - Prompt::new(prompt, history_register, completion_fn, callback_fn).with_line(input), - ); -} - -fn show_prompt(cx: &mut crate::commands::Context, mut prompt: Prompt) { - // Calculate initial completion - prompt.recalculate_completion(cx.editor); + let prompt = Prompt::new(prompt, history_register, completion_fn, callback_fn) + .with_line(input, cx.editor); cx.push_layer(Box::new(prompt)); } diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 2878fc90..24d3b288 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -470,7 +470,7 @@ impl<T: Item> Picker<T> { self.filters .extend(self.matches.iter().map(|(index, _)| *index)); self.filters.sort_unstable(); // used for binary search later - self.prompt.clear(cx); + self.prompt.clear(cx.editor); } pub fn toggle_preview(&mut self) { diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index 1ac83390..55091a54 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -83,10 +83,11 @@ impl Prompt { } } - pub fn with_line(mut self, line: String) -> Self { + pub fn with_line(mut self, line: String, editor: &Editor) -> Self { let cursor = line.len(); self.line = line; self.cursor = cursor; + self.recalculate_completion(editor); self } @@ -95,6 +96,7 @@ impl Prompt { } pub fn recalculate_completion(&mut self, editor: &Editor) { + self.exit_selection(); self.completion = (self.completion_fn)(editor, &self.line); } @@ -213,12 +215,12 @@ impl Prompt { self.cursor = pos; } self.recalculate_completion(cx.editor); - self.exit_selection(); } - pub fn insert_str(&mut self, s: &str) { + pub fn insert_str(&mut self, s: &str, editor: &Editor) { self.line.insert_str(self.cursor, s); self.cursor += s.len(); + self.recalculate_completion(editor); } pub fn move_cursor(&mut self, movement: Movement) { @@ -234,65 +236,65 @@ impl Prompt { self.cursor = self.line.len(); } - pub fn delete_char_backwards(&mut self, cx: &Context) { + pub fn delete_char_backwards(&mut self, editor: &Editor) { let pos = self.eval_movement(Movement::BackwardChar(1)); self.line.replace_range(pos..self.cursor, ""); self.cursor = pos; - self.exit_selection(); - self.recalculate_completion(cx.editor); + self.recalculate_completion(editor); } - pub fn delete_char_forwards(&mut self, cx: &Context) { + pub fn delete_char_forwards(&mut self, editor: &Editor) { let pos = self.eval_movement(Movement::ForwardChar(1)); self.line.replace_range(self.cursor..pos, ""); - self.exit_selection(); - self.recalculate_completion(cx.editor); + self.recalculate_completion(editor); } - pub fn delete_word_backwards(&mut self, cx: &Context) { + pub fn delete_word_backwards(&mut self, editor: &Editor) { let pos = self.eval_movement(Movement::BackwardWord(1)); self.line.replace_range(pos..self.cursor, ""); self.cursor = pos; - self.exit_selection(); - self.recalculate_completion(cx.editor); + self.recalculate_completion(editor); } - pub fn delete_word_forwards(&mut self, cx: &Context) { + pub fn delete_word_forwards(&mut self, editor: &Editor) { let pos = self.eval_movement(Movement::ForwardWord(1)); self.line.replace_range(self.cursor..pos, ""); - self.exit_selection(); - self.recalculate_completion(cx.editor); + self.recalculate_completion(editor); } - pub fn kill_to_start_of_line(&mut self, cx: &Context) { + pub fn kill_to_start_of_line(&mut self, editor: &Editor) { let pos = self.eval_movement(Movement::StartOfLine); self.line.replace_range(pos..self.cursor, ""); self.cursor = pos; - self.exit_selection(); - self.recalculate_completion(cx.editor); + self.recalculate_completion(editor); } - pub fn kill_to_end_of_line(&mut self, cx: &Context) { + pub fn kill_to_end_of_line(&mut self, editor: &Editor) { let pos = self.eval_movement(Movement::EndOfLine); self.line.replace_range(self.cursor..pos, ""); - self.exit_selection(); - self.recalculate_completion(cx.editor); + self.recalculate_completion(editor); } - pub fn clear(&mut self, cx: &Context) { + pub fn clear(&mut self, editor: &Editor) { self.line.clear(); self.cursor = 0; - self.recalculate_completion(cx.editor); - self.exit_selection(); + self.recalculate_completion(editor); } - pub fn change_history(&mut self, register: &[String], direction: CompletionDirection) { + pub fn change_history( + &mut self, + cx: &mut Context, + register: char, + direction: CompletionDirection, + ) { + let register = cx.editor.registers.get_mut(register).read(); + if register.is_empty() { return; } @@ -312,6 +314,7 @@ impl Prompt { self.history_pos = Some(index); self.move_end(); + self.recalculate_completion(cx.editor); } pub fn change_completion_selection(&mut self, direction: CompletionDirection) { @@ -494,16 +497,18 @@ impl Component for Prompt { ctrl!('f') | key!(Right) => self.move_cursor(Movement::ForwardChar(1)), ctrl!('e') | key!(End) => self.move_end(), ctrl!('a') | key!(Home) => self.move_start(), - ctrl!('w') | alt!(Backspace) | ctrl!(Backspace) => self.delete_word_backwards(cx), - alt!('d') | alt!(Delete) | ctrl!(Delete) => self.delete_word_forwards(cx), - ctrl!('k') => self.kill_to_end_of_line(cx), - ctrl!('u') => self.kill_to_start_of_line(cx), + ctrl!('w') | alt!(Backspace) | ctrl!(Backspace) => { + self.delete_word_backwards(cx.editor) + } + alt!('d') | alt!(Delete) | ctrl!(Delete) => self.delete_word_forwards(cx.editor), + ctrl!('k') => self.kill_to_end_of_line(cx.editor), + ctrl!('u') => self.kill_to_start_of_line(cx.editor), ctrl!('h') | key!(Backspace) => { - self.delete_char_backwards(cx); + self.delete_char_backwards(cx.editor); (self.callback_fn)(cx, &self.line, PromptEvent::Update); } ctrl!('d') | key!(Delete) => { - self.delete_char_forwards(cx); + self.delete_char_forwards(cx.editor); (self.callback_fn)(cx, &self.line, PromptEvent::Update); } ctrl!('s') => { @@ -520,14 +525,13 @@ impl Component for Prompt { ); let line = text.slice(range.from()..range.to()).to_string(); if !line.is_empty() { - self.insert_str(line.as_str()); + self.insert_str(line.as_str(), cx.editor); (self.callback_fn)(cx, &self.line, PromptEvent::Update); } } key!(Enter) => { if self.selection.is_some() && self.line.ends_with(std::path::MAIN_SEPARATOR) { self.recalculate_completion(cx.editor); - self.exit_selection(); } else { // handle executing with last command in history if nothing entered let input: Cow<str> = if self.line.is_empty() { @@ -553,15 +557,13 @@ impl Component for Prompt { } ctrl!('p') | key!(Up) => { if let Some(register) = self.history_register { - let register = cx.editor.registers.get_mut(register); - self.change_history(register.read(), CompletionDirection::Backward); + self.change_history(cx, register, CompletionDirection::Backward); (self.callback_fn)(cx, &self.line, PromptEvent::Update); } } ctrl!('n') | key!(Down) => { if let Some(register) = self.history_register { - let register = cx.editor.registers.get_mut(register); - self.change_history(register.read(), CompletionDirection::Forward); + self.change_history(cx, register, CompletionDirection::Forward); (self.callback_fn)(cx, &self.line, PromptEvent::Update); } } @@ -570,7 +572,6 @@ impl Component for Prompt { // if single completion candidate is a directory list content in completion if self.completion.len() == 1 && self.line.ends_with(std::path::MAIN_SEPARATOR) { self.recalculate_completion(cx.editor); - self.exit_selection(); } (self.callback_fn)(cx, &self.line, PromptEvent::Update) } @@ -602,8 +603,8 @@ impl Component for Prompt { .read(c) .and_then(|r| r.first()) .map_or("", |r| r.as_str()), + context.editor, ); - prompt.recalculate_completion(context.editor); })); (self.callback_fn)(cx, &self.line, PromptEvent::Update); return EventResult::Consumed(None); |