diff options
Diffstat (limited to 'helix-term')
-rw-r--r-- | helix-term/src/commands.rs | 5 | ||||
-rw-r--r-- | helix-term/src/ui/mod.rs | 1 | ||||
-rw-r--r-- | helix-term/src/ui/picker.rs | 1 | ||||
-rw-r--r-- | helix-term/src/ui/prompt.rs | 58 |
4 files changed, 63 insertions, 2 deletions
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 06dca5d5..c51453b0 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1126,7 +1126,7 @@ fn delete_selection(cx: &mut Context) { let reg_name = cx.selected_register.name(); let (view, doc) = current!(cx.editor); let registers = &mut cx.editor.registers; - let reg = registers.get_or_insert(reg_name); + let reg = registers.get_mut(reg_name); delete_selection_impl(reg, doc, view.id); doc.append_changes_to_history(view.id); @@ -1139,7 +1139,7 @@ fn change_selection(cx: &mut Context) { let reg_name = cx.selected_register.name(); let (view, doc) = current!(cx.editor); let registers = &mut cx.editor.registers; - let reg = registers.get_or_insert(reg_name); + let reg = registers.get_mut(reg_name); delete_selection_impl(reg, doc, view.id); enter_insert_mode(doc); } @@ -1920,6 +1920,7 @@ mod cmd { fn command_mode(cx: &mut Context) { let mut prompt = Prompt::new( ":".to_owned(), + Some(':'), |input: &str| { // we use .this over split_whitespace() because we care about empty segments let parts = input.split(' ').collect::<Vec<&str>>(); diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 288d3d2e..9e71cfe7 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -36,6 +36,7 @@ pub fn regex_prompt( Prompt::new( prompt, + None, |_input: &str| Vec::new(), // this is fine because Vec::new() doesn't allocate move |cx: &mut crate::compositor::Context, input: &str, event: PromptEvent| { match event { diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 733be2fc..0b67cd9c 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -43,6 +43,7 @@ impl<T> Picker<T> { ) -> Self { let prompt = Prompt::new( "".to_string(), + None, |_pattern: &str| Vec::new(), |_editor: &mut Context, _pattern: &str, _event: PromptEvent| { // diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index 2df1e281..57daef3a 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -20,6 +20,8 @@ pub struct Prompt { cursor: usize, completion: Vec<Completion>, selection: Option<usize>, + history_register: Option<char>, + history_pos: Option<usize>, completion_fn: Box<dyn FnMut(&str) -> Vec<Completion>>, callback_fn: Box<dyn FnMut(&mut Context, &str, PromptEvent)>, pub doc_fn: Box<dyn Fn(&str) -> Option<&'static str>>, @@ -54,6 +56,7 @@ pub enum Movement { impl Prompt { pub fn new( prompt: String, + history_register: Option<char>, mut completion_fn: impl FnMut(&str) -> Vec<Completion> + 'static, callback_fn: impl FnMut(&mut Context, &str, PromptEvent) + 'static, ) -> Self { @@ -63,6 +66,8 @@ impl Prompt { cursor: 0, completion: completion_fn(""), selection: None, + history_register, + history_pos: None, completion_fn: Box::new(completion_fn), callback_fn: Box::new(callback_fn), doc_fn: Box::new(|_| None), @@ -226,6 +231,28 @@ impl Prompt { self.exit_selection(); } + pub fn change_history(&mut self, register: &[String], direction: CompletionDirection) { + if register.is_empty() { + return; + } + + let end = register.len().saturating_sub(1); + + let index = match direction { + CompletionDirection::Forward => self.history_pos.map_or(0, |i| i + 1), + CompletionDirection::Backward => { + self.history_pos.unwrap_or(register.len()).saturating_sub(1) + } + } + .min(end); + + self.line = register[index].clone(); + + self.history_pos = Some(index); + + self.move_end(); + } + pub fn change_completion_selection(&mut self, direction: CompletionDirection) { if self.completion.is_empty() { return; @@ -468,10 +495,41 @@ impl Component for Prompt { self.exit_selection(); } else { (self.callback_fn)(cx, &self.line, PromptEvent::Validate); + + if let Some(register) = self.history_register { + // store in history + let register = cx.editor.registers.get_mut(register); + register.push(self.line.clone()); + } return close_fn; } } KeyEvent { + code: KeyCode::Char('p'), + modifiers: KeyModifiers::CONTROL, + } + | KeyEvent { + code: KeyCode::Up, .. + } => { + if let Some(register) = self.history_register { + let register = cx.editor.registers.get_mut(register); + self.change_history(register.read(), CompletionDirection::Backward); + } + } + KeyEvent { + code: KeyCode::Char('n'), + modifiers: KeyModifiers::CONTROL, + } + | KeyEvent { + code: KeyCode::Down, + .. + } => { + if let Some(register) = self.history_register { + let register = cx.editor.registers.get_mut(register); + self.change_history(register.read(), CompletionDirection::Forward); + } + } + KeyEvent { code: KeyCode::Tab, .. } => self.change_completion_selection(CompletionDirection::Forward), KeyEvent { |