diff --git a/book/src/configuration.md b/book/src/configuration.md index 2af0e6326..4c8ff0647 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -127,6 +127,7 @@ The following statusline elements can be configured: | `auto-signature-help` | Enable automatic popup of signature help (parameter hints) | `true` | | `display-inlay-hints` | Display inlay hints[^2] | `false` | | `display-signature-help-docs` | Display docs under signature help popup | `true` | +| `snippets` | Enables snippet completions. Requires a server restart (`:lsp-restart`) to take effect after `:config-reload`/`:set`. | `true` | [^1]: By default, a progress spinner is shown in the statusline beside the file path. [^2]: You may also have to activate them in the LSP config for them to appear, not just in Helix. diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index f94963386..94e994899 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -411,7 +411,7 @@ impl Client { // General messages // ------------------------------------------------------------------------------------------- - pub(crate) async fn initialize(&self) -> Result { + pub(crate) async fn initialize(&self, enable_snippets: bool) -> Result { if let Some(config) = &self.config { log::info!("Using custom LSP config: {}", config); } @@ -459,7 +459,7 @@ impl Client { text_document: Some(lsp::TextDocumentClientCapabilities { completion: Some(lsp::CompletionClientCapabilities { completion_item: Some(lsp::CompletionItemCapability { - snippet_support: Some(true), + snippet_support: Some(enable_snippets), resolve_support: Some(lsp::CompletionItemCapabilityResolveSupport { properties: vec![ String::from("documentation"), diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index d56148a41..c3a5d816e 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -647,6 +647,7 @@ impl Registry { language_config: &LanguageConfiguration, doc_path: Option<&std::path::PathBuf>, root_dirs: &[PathBuf], + enable_snippets: bool, ) -> Result>> { let config = match &language_config.language_server { Some(config) => config, @@ -661,8 +662,14 @@ impl Registry { // initialize a new client let id = self.counter.fetch_add(1, Ordering::Relaxed); - let NewClientResult(client, incoming) = - start_client(id, language_config, config, doc_path, root_dirs)?; + let NewClientResult(client, incoming) = start_client( + id, + language_config, + config, + doc_path, + root_dirs, + enable_snippets, + )?; self.incoming.push(UnboundedReceiverStream::new(incoming)); let old_clients = entry.insert(vec![(id, client.clone())]); @@ -695,6 +702,7 @@ impl Registry { language_config: &LanguageConfiguration, doc_path: Option<&std::path::PathBuf>, root_dirs: &[PathBuf], + enable_snippets: bool, ) -> Result>> { let config = match &language_config.language_server { Some(config) => config, @@ -711,8 +719,14 @@ impl Registry { // initialize a new client let id = self.counter.fetch_add(1, Ordering::Relaxed); - let NewClientResult(client, incoming) = - start_client(id, language_config, config, doc_path, root_dirs)?; + let NewClientResult(client, incoming) = start_client( + id, + language_config, + config, + doc_path, + root_dirs, + enable_snippets, + )?; clients.push((id, client.clone())); self.incoming.push(UnboundedReceiverStream::new(incoming)); Ok(Some(client)) @@ -811,6 +825,7 @@ fn start_client( ls_config: &LanguageServerConfiguration, doc_path: Option<&std::path::PathBuf>, root_dirs: &[PathBuf], + enable_snippets: bool, ) -> Result { let (client, incoming, initialize_notify) = Client::start( &ls_config.command, @@ -834,7 +849,7 @@ fn start_client( .capabilities .get_or_try_init(|| { _client - .initialize() + .initialize(enable_snippets) .map_ok(|response| response.capabilities) }) .await; diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index ca55151ad..0255bbea4 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1378,9 +1378,12 @@ fn lsp_restart( .context("LSP not defined for the current document")?; let scope = config.scope.clone(); - cx.editor - .language_servers - .restart(config, doc.path(), &editor_config.workspace_lsp_roots)?; + cx.editor.language_servers.restart( + config, + doc.path(), + &editor_config.workspace_lsp_roots, + editor_config.lsp.snippets, + )?; // This collect is needed because refresh_language_server would need to re-borrow editor. let document_ids_to_refresh: Vec = cx diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 727e1261d..34c59b9b4 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -352,6 +352,8 @@ pub struct LspConfig { pub display_signature_help_docs: bool, /// Display inlay hints pub display_inlay_hints: bool, + /// Whether to enable snippet support + pub snippets: bool, } impl Default for LspConfig { @@ -362,6 +364,7 @@ impl Default for LspConfig { auto_signature_help: true, display_signature_help_docs: true, display_inlay_hints: false, + snippets: true, } } } @@ -1092,12 +1095,13 @@ impl Editor { // if doc doesn't have a URL it's a scratch buffer, ignore it let doc = self.document(doc_id)?; let (lang, path) = (doc.language.clone(), doc.path().cloned()); - let root_dirs = &doc.config.load().workspace_lsp_roots; + let config = doc.config.load(); + let root_dirs = &config.workspace_lsp_roots; // try to find a language server based on the language name let language_server = lang.as_ref().and_then(|language| { self.language_servers - .get(language, path.as_ref(), root_dirs) + .get(language, path.as_ref(), root_dirs, config.lsp.snippets) .map_err(|e| { log::error!( "Failed to initialize the LSP for `{}` {{ {} }}",