diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 2c1535b6..9cf5630d 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1435,7 +1435,7 @@ fn select_regex(cx: &mut Context) { cx, "select:".into(), Some(reg), - |_ctx: &compositor::Context, _input: &str| Vec::new(), + ui::completers::none, move |view, doc, regex, event| { if event != PromptEvent::Update { return; @@ -1458,7 +1458,7 @@ fn split_selection(cx: &mut Context) { cx, "split:".into(), Some(reg), - |_ctx: &compositor::Context, _input: &str| Vec::new(), + ui::completers::none, move |view, doc, regex, event| { if event != PromptEvent::Update { return; @@ -1600,7 +1600,7 @@ fn searcher(cx: &mut Context, direction: Direction) { cx, "search:".into(), Some(reg), - move |_ctx: &compositor::Context, input: &str| { + move |_editor: &Editor, input: &str| { completions .iter() .filter(|comp| comp.starts_with(input)) @@ -1701,7 +1701,7 @@ fn global_search(cx: &mut Context) { cx, "global-search:".into(), None, - move |_ctx: &compositor::Context, input: &str| { + move |_editor: &Editor, input: &str| { completions .iter() .filter(|comp| comp.starts_with(input)) @@ -3298,7 +3298,7 @@ fn command_mode(cx: &mut Context) { let mut prompt = Prompt::new( ":".into(), Some(':'), - |ctx: &compositor::Context, input: &str| { + |editor: &Editor, input: &str| { static FUZZY_MATCHER: Lazy = Lazy::new(fuzzy_matcher::skim::SkimMatcherV2::default); @@ -3330,7 +3330,7 @@ fn command_mode(cx: &mut Context) { .. }) = cmd::TYPABLE_COMMAND_MAP.get(parts[0]) { - completer(ctx, part) + completer(editor, part) .into_iter() .map(|(range, file)| { // offset ranges to input @@ -5394,7 +5394,7 @@ fn keep_or_remove_selections_impl(cx: &mut Context, remove: bool) { cx, if !remove { "keep:" } else { "remove:" }.into(), Some(reg), - |_ctx: &compositor::Context, _input: &str| Vec::new(), + ui::completers::none, move |view, doc, regex, event| { if event != PromptEvent::Update { return; @@ -6158,7 +6158,7 @@ fn shell_keep_pipe(cx: &mut Context) { let prompt = Prompt::new( "keep-pipe:".into(), Some('|'), - |_ctx: &compositor::Context, _input: &str| Vec::new(), + ui::completers::none, move |cx: &mut compositor::Context, input: &str, event: PromptEvent| { let shell = &cx.editor.config.shell; if event != PromptEvent::Validate { @@ -6254,7 +6254,7 @@ fn shell(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) { let prompt = Prompt::new( prompt, Some('|'), - |_ctx: &compositor::Context, _input: &str| Vec::new(), + ui::completers::none, move |cx: &mut compositor::Context, input: &str, event: PromptEvent| { let shell = &cx.editor.config.shell; if event != PromptEvent::Validate { @@ -6350,7 +6350,7 @@ fn rename_symbol(cx: &mut Context) { let prompt = Prompt::new( "rename-to:".into(), None, - |_ctx: &compositor::Context, _input: &str| Vec::new(), + ui::completers::none, move |cx: &mut compositor::Context, input: &str, event: PromptEvent| { if event != PromptEvent::Validate { return; diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 263342b7..e9ff9d1a 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -22,7 +22,7 @@ pub use text::Text; use helix_core::regex::Regex; use helix_core::regex::RegexBuilder; -use helix_view::{Document, View}; +use helix_view::{Document, Editor, View}; use std::path::PathBuf; @@ -30,7 +30,7 @@ pub fn regex_prompt( cx: &mut crate::commands::Context, prompt: std::borrow::Cow<'static, str>, history_register: Option, - completion_fn: impl FnMut(&crate::compositor::Context, &str) -> Vec + 'static, + completion_fn: impl FnMut(&Editor, &str) -> Vec + 'static, fun: impl Fn(&mut View, &mut Document, Regex, PromptEvent) + 'static, ) -> Prompt { let (view, doc) = current!(cx.editor); @@ -168,26 +168,24 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi } pub mod completers { - use crate::compositor::Context; use crate::ui::prompt::Completion; use fuzzy_matcher::skim::SkimMatcherV2 as Matcher; use fuzzy_matcher::FuzzyMatcher; use helix_view::document::SCRATCH_BUFFER_NAME; - use helix_view::editor::Config; use helix_view::theme; + use helix_view::{editor::Config, Editor}; use once_cell::sync::Lazy; use std::borrow::Cow; use std::cmp::Reverse; - pub type Completer = fn(&Context, &str) -> Vec; + pub type Completer = fn(&Editor, &str) -> Vec; - pub fn none(_cx: &Context, _input: &str) -> Vec { + pub fn none(_editor: &Editor, _input: &str) -> Vec { Vec::new() } - pub fn buffer(cx: &Context, input: &str) -> Vec { - let mut names: Vec<_> = cx - .editor + pub fn buffer(editor: &Editor, input: &str) -> Vec { + let mut names: Vec<_> = editor .documents .iter() .map(|(_id, doc)| { @@ -214,7 +212,7 @@ pub mod completers { names } - pub fn theme(_cx: &Context, input: &str) -> Vec { + pub fn theme(_editor: &Editor, input: &str) -> Vec { let mut names = theme::Loader::read_names(&helix_core::runtime_dir().join("themes")); names.extend(theme::Loader::read_names( &helix_core::config_dir().join("themes"), @@ -242,7 +240,7 @@ pub mod completers { names } - pub fn setting(_cx: &Context, input: &str) -> Vec { + pub fn setting(_editor: &Editor, input: &str) -> Vec { static KEYS: Lazy> = Lazy::new(|| { serde_json::to_value(Config::default()) .unwrap() @@ -267,7 +265,7 @@ pub mod completers { .collect() } - pub fn filename(_cx: &Context, input: &str) -> Vec { + pub fn filename(_editor: &Editor, input: &str) -> Vec { filename_impl(input, |entry| { let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir()); @@ -279,7 +277,7 @@ pub mod completers { }) } - pub fn directory(_cx: &Context, input: &str) -> Vec { + pub fn directory(_editor: &Editor, input: &str) -> Vec { filename_impl(input, |entry| { let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir()); diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index dcc64002..622af387 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -1,7 +1,7 @@ use crate::{ compositor::{Component, Compositor, Context, EventResult}, ctrl, key, shift, - ui::EditorView, + ui::{self, EditorView}, }; use crossterm::event::Event; use tui::{ @@ -302,7 +302,7 @@ impl Picker { let prompt = Prompt::new( "".into(), None, - |_ctx: &Context, _pattern: &str| Vec::new(), + ui::completers::none, |_editor: &mut Context, _pattern: &str, _event: PromptEvent| { // }, diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index ff6b8c76..18b390dd 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -24,7 +24,7 @@ pub struct Prompt { selection: Option, history_register: Option, history_pos: Option, - completion_fn: Box Vec>, + completion_fn: Box Vec>, callback_fn: Box, pub doc_fn: Box Option<&'static str>>, } @@ -59,7 +59,7 @@ impl Prompt { pub fn new( prompt: Cow<'static, str>, history_register: Option, - completion_fn: impl FnMut(&Context, &str) -> Vec + 'static, + completion_fn: impl FnMut(&Editor, &str) -> Vec + 'static, callback_fn: impl FnMut(&mut Context, &str, PromptEvent) + 'static, ) -> Self { Self { @@ -76,6 +76,10 @@ impl Prompt { } } + pub fn recalculate_completion(&mut self, editor: &Editor) { + self.completion = (self.completion_fn)(editor, &self.line); + } + /// Compute the cursor position after applying movement /// Taken from: https://github.com/wez/wezterm/blob/e0b62d07ca9bf8ce69a61e30a3c20e7abc48ce7e/termwiz/src/lineedit/mod.rs#L516-L611 fn eval_movement(&self, movement: Movement) -> usize { @@ -183,7 +187,7 @@ impl Prompt { if let Ok(Some(pos)) = cursor.next_boundary(&self.line, 0) { self.cursor = pos; } - self.completion = (self.completion_fn)(cx, &self.line); + self.recalculate_completion(cx.editor); self.exit_selection(); } @@ -211,7 +215,7 @@ impl Prompt { self.cursor = pos; self.exit_selection(); - self.completion = (self.completion_fn)(cx, &self.line); + self.recalculate_completion(cx.editor); } pub fn delete_char_forwards(&mut self, cx: &Context) { @@ -219,7 +223,7 @@ impl Prompt { self.line.replace_range(self.cursor..pos, ""); self.exit_selection(); - self.completion = (self.completion_fn)(cx, &self.line); + self.recalculate_completion(cx.editor); } pub fn delete_word_backwards(&mut self, cx: &Context) { @@ -228,7 +232,7 @@ impl Prompt { self.cursor = pos; self.exit_selection(); - self.completion = (self.completion_fn)(cx, &self.line); + self.recalculate_completion(cx.editor); } pub fn delete_word_forwards(&mut self, cx: &Context) { @@ -236,7 +240,7 @@ impl Prompt { self.line.replace_range(self.cursor..pos, ""); self.exit_selection(); - self.completion = (self.completion_fn)(cx, &self.line); + self.recalculate_completion(cx.editor); } pub fn kill_to_start_of_line(&mut self, cx: &Context) { @@ -245,7 +249,7 @@ impl Prompt { self.cursor = pos; self.exit_selection(); - self.completion = (self.completion_fn)(cx, &self.line); + self.recalculate_completion(cx.editor); } pub fn kill_to_end_of_line(&mut self, cx: &Context) { @@ -253,13 +257,13 @@ impl Prompt { self.line.replace_range(self.cursor..pos, ""); self.exit_selection(); - self.completion = (self.completion_fn)(cx, &self.line); + self.recalculate_completion(cx.editor); } pub fn clear(&mut self, cx: &Context) { self.line.clear(); self.cursor = 0; - self.completion = (self.completion_fn)(cx, &self.line); + self.recalculate_completion(cx.editor); self.exit_selection(); } @@ -474,7 +478,7 @@ impl Component for Prompt { } key!(Enter) => { if self.selection.is_some() && self.line.ends_with(std::path::MAIN_SEPARATOR) { - self.completion = (self.completion_fn)(cx, &self.line); + self.recalculate_completion(cx.editor); self.exit_selection(); } else { (self.callback_fn)(cx, &self.line, PromptEvent::Validate); @@ -525,7 +529,6 @@ impl Component for Prompt { } fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) { - self.completion = (self.completion_fn)(cx, &self.line); self.render_prompt(area, surface, cx) }