From 451a427162137af9e5903e62807aeb83627828c7 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Tue, 25 Mar 2025 12:43:53 -0400 Subject: [PATCH 1/5] Complete words from open buffers --- helix-view/src/handlers/word_index.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/helix-view/src/handlers/word_index.rs b/helix-view/src/handlers/word_index.rs index 9c3f83384..dfb2adba3 100644 --- a/helix-view/src/handlers/word_index.rs +++ b/helix-view/src/handlers/word_index.rs @@ -127,7 +127,8 @@ const MIN_WORD_GRAPHEMES: usize = 3; /// Maximum word length allowed (in chars) const MAX_WORD_LEN: usize = 50; -type Word = kstring::KString; +// TODO: choose or create a suitable small string type. +type Word = String; #[derive(Debug, Default)] struct WordIndexInner { @@ -149,11 +150,7 @@ impl WordIndexInner { if let Some(rc) = self.words.get_mut(word.as_ref()) { *rc = rc.saturating_add(1); } else { - let word = match word { - Cow::Owned(s) => Word::from_string(s), - Cow::Borrowed(s) => Word::from_ref(s), - }; - self.words.insert(word, 1); + self.words.insert(word.into_owned(), 1); } } @@ -183,10 +180,7 @@ impl WordIndex { let inner = self.inner.read(); let mut matches = fuzzy_match(pattern, inner.words(), false); matches.sort_unstable_by_key(|(_, score)| *score); - matches - .into_iter() - .map(|(word, _)| word.to_string()) - .collect() + matches.into_iter().map(|(word, _)| word.clone()).collect() } fn add_document(&self, text: &Rope) { @@ -443,7 +437,7 @@ mod tests { impl WordIndex { fn words(&self) -> HashSet { let inner = self.inner.read(); - inner.words().map(|w| w.to_string()).collect() + inner.words().cloned().collect() } } From 0103cf526e70efc2140ae4e898655ac8309b50cc Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sat, 21 Jun 2025 13:40:47 -0400 Subject: [PATCH 2/5] Use KString as the small-string type for the WordIndex It's already used in gix and tree-house so it does not introduce a new dependency. It's a small-string type that fits into 16B (like a `Box`) meant to be primarily used as keys for large maps. --- helix-view/src/handlers/word_index.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/helix-view/src/handlers/word_index.rs b/helix-view/src/handlers/word_index.rs index dfb2adba3..9c3f83384 100644 --- a/helix-view/src/handlers/word_index.rs +++ b/helix-view/src/handlers/word_index.rs @@ -127,8 +127,7 @@ const MIN_WORD_GRAPHEMES: usize = 3; /// Maximum word length allowed (in chars) const MAX_WORD_LEN: usize = 50; -// TODO: choose or create a suitable small string type. -type Word = String; +type Word = kstring::KString; #[derive(Debug, Default)] struct WordIndexInner { @@ -150,7 +149,11 @@ impl WordIndexInner { if let Some(rc) = self.words.get_mut(word.as_ref()) { *rc = rc.saturating_add(1); } else { - self.words.insert(word.into_owned(), 1); + let word = match word { + Cow::Owned(s) => Word::from_string(s), + Cow::Borrowed(s) => Word::from_ref(s), + }; + self.words.insert(word, 1); } } @@ -180,7 +183,10 @@ impl WordIndex { let inner = self.inner.read(); let mut matches = fuzzy_match(pattern, inner.words(), false); matches.sort_unstable_by_key(|(_, score)| *score); - matches.into_iter().map(|(word, _)| word.clone()).collect() + matches + .into_iter() + .map(|(word, _)| word.to_string()) + .collect() } fn add_document(&self, text: &Rope) { @@ -437,7 +443,7 @@ mod tests { impl WordIndex { fn words(&self) -> HashSet { let inner = self.inner.read(); - inner.words().cloned().collect() + inner.words().map(|w| w.to_string()).collect() } } From dacaef17eac93a861b96442474410e1bcad314f6 Mon Sep 17 00:00:00 2001 From: GladkihEgor Date: Mon, 18 Nov 2024 21:42:13 +0500 Subject: [PATCH 3/5] feat: add config for disable autostart LSP --- book/src/editor.md | 1 + helix-lsp/src/lib.rs | 7 +++++++ helix-view/src/editor.rs | 5 ++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/book/src/editor.md b/book/src/editor.md index 7f1de68bb..ea6fbf728 100644 --- a/book/src/editor.md +++ b/book/src/editor.md @@ -155,6 +155,7 @@ The following statusline elements can be configured: | Key | Description | Default | | --- | ----------- | ------- | | `enable` | Enables LSP integration. Setting to false will completely disable language servers regardless of language settings.| `true` | +| `autostart` | Enables LSP autostart on file opening. Setting to false will require running the `:lsp-restart` command to manually start the language server.| `true` | | `display-messages` | Display LSP `window/showMessage` messages below statusline[^1] | `true` | | `display-progress-messages` | Display LSP progress messages below statusline[^1] | `false` | | `auto-signature-help` | Enable automatic popup of signature help (parameter hints) | `true` | diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 567e8a702..b9335ec9b 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -682,6 +682,7 @@ impl Registry { doc_path: Option<&'a std::path::PathBuf>, root_dirs: &'a [PathBuf], enable_snippets: bool, + autostart: bool, ) -> impl Iterator>)> + 'a { language_config.language_servers.iter().filter_map( move |LanguageServerFeatures { name, .. }| { @@ -703,6 +704,12 @@ impl Registry { }) { return Some((name.to_owned(), Ok(client.clone()))); } + } else { + // If autostart LSP turned off, do not automatically start a client for server + // Try emulate the empty clients list behavior for disable LSP + if !autostart { + return None; + } } match self.start_client( name.clone(), diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 57e130881..5e844197d 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -455,6 +455,8 @@ pub fn get_terminal_provider() -> Option { pub struct LspConfig { /// Enables LSP pub enable: bool, + /// Autostart LSP on open file + pub autostart: bool, /// Display LSP messagess from $/progress below statusline pub display_progress_messages: bool, /// Display LSP messages from window/showMessage below statusline @@ -480,6 +482,7 @@ impl Default for LspConfig { fn default() -> Self { Self { enable: true, + autostart: true, display_progress_messages: false, display_messages: true, auto_signature_help: true, @@ -1547,7 +1550,7 @@ impl Editor { // store only successfully started language servers let language_servers = lang.as_ref().map_or_else(HashMap::default, |language| { self.language_servers - .get(language, path.as_ref(), root_dirs, config.lsp.snippets) + .get(language, path.as_ref(), root_dirs, config.lsp.snippets, config.lsp.autostart) .filter_map(|(lang, client)| match client { Ok(client) => Some((lang, client)), Err(err) => { From 7afdd1cc9438ca6d5d84da667863c20d3ba568b1 Mon Sep 17 00:00:00 2001 From: GladkihEgor Date: Thu, 20 Mar 2025 23:33:48 +0500 Subject: [PATCH 4/5] reduce indentation level --- helix-lsp/src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index b9335ec9b..e2fa19f57 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -704,12 +704,10 @@ impl Registry { }) { return Some((name.to_owned(), Ok(client.clone()))); } - } else { + } else if !autostart { // If autostart LSP turned off, do not automatically start a client for server // Try emulate the empty clients list behavior for disable LSP - if !autostart { - return None; - } + return None; } match self.start_client( name.clone(), From f61b72976e8788119a7343f56bed2be04fc610d4 Mon Sep 17 00:00:00 2001 From: GladkihEgor Date: Mon, 21 Jul 2025 19:45:40 +0500 Subject: [PATCH 5/5] applay completion by `C-x` If only one completion applay it by pressing completion hotkey --- helix-term/src/ui/menu.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs index 76e50229a..51c890969 100644 --- a/helix-term/src/ui/menu.rs +++ b/helix-term/src/ui/menu.rs @@ -169,6 +169,10 @@ impl Menu { } pub fn selection(&self) -> Option<&T> { + if self.options.len() == 1 { + return Some(&self.options[0]); + } + self.cursor.and_then(|cursor| { self.matches .get(cursor) @@ -177,6 +181,10 @@ impl Menu { } pub fn selection_mut(&mut self) -> Option<&mut T> { + if self.options.len() == 1 { + return Some(&mut self.options[0]); + } + self.cursor.and_then(|cursor| { self.matches .get(cursor)