Allow extensions to provide data for `language_ids` (#10053)

Marshall Bowers and Max created

This PR makes it so extensions can provide values for the `language_ids`
method on the `LspAdapter` trait.

These are provided as data in the `language_servers` section of the
`extension.toml`, like so:

```toml
[language_servers.intelephense]
name = "Intelephense"
language = "PHP"
language_ids = { PHP = "php"}
```

Release Notes:

- N/A

Co-authored-by: Max <max@zed.dev>

Change summary

crates/extension/src/extension_lsp_adapter.rs | 16 ++++++++++++----
crates/extension/src/extension_manifest.rs    |  4 +++-
extensions/php/extension.toml                 |  1 +
3 files changed, 16 insertions(+), 5 deletions(-)

Detailed changes

crates/extension/src/extension_lsp_adapter.rs 🔗

@@ -113,14 +113,22 @@ impl LspAdapter for ExtensionLspAdapter {
     }
 
     fn language_ids(&self) -> HashMap<String, String> {
-        // TODO: Eventually we'll want to expose an extension API for doing this, but for
-        // now we just manually language ID mappings for extensions that we know need it.
-
+        // TODO: The language IDs can be provided via the language server options
+        // in `extension.toml now but we're leaving these existing usages in place temporarily
+        // to avoid any compatibility issues between Zed and the extension versions.
+        //
+        // We can remove once the following extension versions no longer see any use:
+        // - php@0.0.1
         if self.extension.manifest.id.as_ref() == "php" {
             return HashMap::from_iter([("PHP".into(), "php".into())]);
         }
 
-        Default::default()
+        self.extension
+            .manifest
+            .language_servers
+            .get(&LanguageServerName(self.config.name.clone().into()))
+            .map(|server| server.language_ids.clone())
+            .unwrap_or_default()
     }
 
     async fn initialization_options(

crates/extension/src/extension_manifest.rs 🔗

@@ -1,5 +1,5 @@
 use anyhow::{anyhow, Context, Result};
-use collections::BTreeMap;
+use collections::{BTreeMap, HashMap};
 use fs::Fs;
 use language::LanguageServerName;
 use semantic_version::SemanticVersion;
@@ -99,6 +99,8 @@ pub struct GrammarManifestEntry {
 #[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
 pub struct LanguageServerManifestEntry {
     pub language: Arc<str>,
+    #[serde(default)]
+    pub language_ids: HashMap<String, String>,
 }
 
 impl ExtensionManifest {

extensions/php/extension.toml 🔗

@@ -9,6 +9,7 @@ repository = "https://github.com/zed-industries/zed"
 [language_servers.intelephense]
 name = "Intelephense"
 language = "PHP"
+language_ids = { PHP = "php"}
 
 [grammars.php]
 repository = "https://github.com/tree-sitter/tree-sitter-php"