From d009d84ead222c43d0eaab95822a41691be8bc22 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Mon, 8 Apr 2024 14:24:56 -0400 Subject: [PATCH] Add support for using a language server with multiple languages (#10293) This PR updates the `extension.toml` to allow specifying multiple languages for a language server to work with. The `languages` field takes precedence over `language`. In the future the `language` field will be removed. As part of this, the Emmet extension has been extended with support for PHP and ERB. Release Notes: - N/A --------- Co-authored-by: Max --- crates/extension/src/extension_manifest.rs | 25 ++++++++++++++++- crates/extension/src/extension_store.rs | 32 ++++++++++++---------- extensions/emmet/extension.toml | 1 + 3 files changed, 43 insertions(+), 15 deletions(-) diff --git a/crates/extension/src/extension_manifest.rs b/crates/extension/src/extension_manifest.rs index 1e88785648..16f30eb999 100644 --- a/crates/extension/src/extension_manifest.rs +++ b/crates/extension/src/extension_manifest.rs @@ -98,11 +98,34 @@ pub struct GrammarManifestEntry { #[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)] pub struct LanguageServerManifestEntry { - pub language: Arc, + /// Deprecated in favor of `languages`. + #[serde(default)] + language: Option>, + /// The list of languages this language server should work with. + #[serde(default)] + languages: Vec>, #[serde(default)] pub language_ids: HashMap, } +impl LanguageServerManifestEntry { + /// Returns the list of languages for the language server. + /// + /// Prefer this over accessing the `language` or `languages` fields directly, + /// as we currently support both. + /// + /// We can replace this with just field access for the `languages` field once + /// we have removed `language`. + pub fn languages(&self) -> impl IntoIterator> + '_ { + let language = if self.languages.is_empty() { + self.language.clone() + } else { + None + }; + self.languages.iter().cloned().chain(language) + } +} + impl ExtensionManifest { pub async fn load(fs: Arc, extension_dir: &Path) -> Result { let extension_name = extension_dir diff --git a/crates/extension/src/extension_store.rs b/crates/extension/src/extension_store.rs index 9a309e2231..4a087b8402 100644 --- a/crates/extension/src/extension_store.rs +++ b/crates/extension/src/extension_store.rs @@ -962,8 +962,10 @@ impl ExtensionStore { }; grammars_to_remove.extend(extension.manifest.grammars.keys().cloned()); for (language_server_name, config) in extension.manifest.language_servers.iter() { - self.language_registry - .remove_lsp_adapter(config.language.as_ref(), language_server_name); + for language in config.languages() { + self.language_registry + .remove_lsp_adapter(&language, language_server_name); + } } } @@ -1103,18 +1105,20 @@ impl ExtensionStore { for (manifest, wasm_extension) in &wasm_extensions { for (language_server_id, language_server_config) in &manifest.language_servers { - this.language_registry.register_lsp_adapter( - language_server_config.language.clone(), - Arc::new(ExtensionLspAdapter { - extension: wasm_extension.clone(), - host: this.wasm_host.clone(), - language_server_id: language_server_id.clone(), - config: wit::LanguageServerConfig { - name: language_server_id.0.to_string(), - language_name: language_server_config.language.to_string(), - }, - }), - ); + for language in language_server_config.languages() { + this.language_registry.register_lsp_adapter( + language.clone(), + Arc::new(ExtensionLspAdapter { + extension: wasm_extension.clone(), + host: this.wasm_host.clone(), + language_server_id: language_server_id.clone(), + config: wit::LanguageServerConfig { + name: language_server_id.0.to_string(), + language_name: language.to_string(), + }, + }), + ); + } } } this.wasm_extensions.extend(wasm_extensions); diff --git a/extensions/emmet/extension.toml b/extensions/emmet/extension.toml index 821a19b012..5efe3c73f3 100644 --- a/extensions/emmet/extension.toml +++ b/extensions/emmet/extension.toml @@ -9,3 +9,4 @@ repository = "https://github.com/zed-industries/zed" [language_servers.emmet-language-server] name = "Emmet Language Server" language = "HTML" +languages = ["HTML", "PHP", "ERB"]