Only generate workspace/configuration for relevant adapter

Julia created

Change summary

crates/language/src/language.rs        | 46 +------------------
crates/project/src/project.rs          | 64 ++++++++++++++-------------
crates/zed/src/languages/json.rs       | 45 +++++++++----------
crates/zed/src/languages/tailwind.rs   | 29 ++++++------
crates/zed/src/languages/typescript.rs | 22 ++++-----
crates/zed/src/languages/yaml.rs       | 23 ++++-----
6 files changed, 95 insertions(+), 134 deletions(-)

Detailed changes

crates/language/src/language.rs 🔗

@@ -46,7 +46,7 @@ use theme::{SyntaxTheme, Theme};
 use tree_sitter::{self, Query};
 use unicase::UniCase;
 use util::{http::HttpClient, paths::PathExt};
-use util::{merge_json_value_into, post_inc, ResultExt, TryFutureExt as _, UnwrapFuture};
+use util::{post_inc, ResultExt, TryFutureExt as _, UnwrapFuture};
 
 #[cfg(any(test, feature = "test-support"))]
 use futures::channel::mpsc;
@@ -175,10 +175,7 @@ impl CachedLspAdapter {
         self.adapter.code_action_kinds()
     }
 
-    pub fn workspace_configuration(
-        &self,
-        cx: &mut AppContext,
-    ) -> Option<BoxFuture<'static, Value>> {
+    pub fn workspace_configuration(&self, cx: &mut AppContext) -> BoxFuture<'static, Value> {
         self.adapter.workspace_configuration(cx)
     }
 
@@ -287,8 +284,8 @@ pub trait LspAdapter: 'static + Send + Sync {
         None
     }
 
-    fn workspace_configuration(&self, _: &mut AppContext) -> Option<BoxFuture<'static, Value>> {
-        None
+    fn workspace_configuration(&self, _: &mut AppContext) -> BoxFuture<'static, Value> {
+        futures::future::ready(serde_json::json!({})).boxed()
     }
 
     fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
@@ -685,41 +682,6 @@ impl LanguageRegistry {
         result
     }
 
-    pub fn workspace_configuration(&self, cx: &mut AppContext) -> Task<serde_json::Value> {
-        let lsp_adapters = {
-            let state = self.state.read();
-            state
-                .available_languages
-                .iter()
-                .filter(|l| !l.loaded)
-                .flat_map(|l| l.lsp_adapters.clone())
-                .chain(
-                    state
-                        .languages
-                        .iter()
-                        .flat_map(|language| &language.adapters)
-                        .map(|adapter| adapter.adapter.clone()),
-                )
-                .collect::<Vec<_>>()
-        };
-
-        let mut language_configs = Vec::new();
-        for adapter in &lsp_adapters {
-            if let Some(language_config) = adapter.workspace_configuration(cx) {
-                language_configs.push(language_config);
-            }
-        }
-
-        cx.background().spawn(async move {
-            let mut config = serde_json::json!({});
-            let language_configs = futures::future::join_all(language_configs).await;
-            for language_config in language_configs {
-                merge_json_value_into(language_config, &mut config);
-            }
-            config
-        })
-    }
-
     pub fn add(&self, language: Arc<Language>) {
         self.state.write().add(language);
     }

crates/project/src/project.rs 🔗

@@ -603,7 +603,7 @@ impl Project {
                     cx.observe_global::<SettingsStore, _>(Self::on_settings_changed)
                 ],
                 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
-                _maintain_workspace_config: Self::maintain_workspace_config(languages.clone(), cx),
+                _maintain_workspace_config: Self::maintain_workspace_config(cx),
                 active_entry: None,
                 languages,
                 client,
@@ -673,7 +673,7 @@ impl Project {
                 collaborators: Default::default(),
                 join_project_response_message_id: response.message_id,
                 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
-                _maintain_workspace_config: Self::maintain_workspace_config(languages.clone(), cx),
+                _maintain_workspace_config: Self::maintain_workspace_config(cx),
                 languages,
                 user_store: user_store.clone(),
                 fs,
@@ -2441,35 +2441,42 @@ impl Project {
         })
     }
 
-    fn maintain_workspace_config(
-        languages: Arc<LanguageRegistry>,
-        cx: &mut ModelContext<Project>,
-    ) -> Task<()> {
+    fn maintain_workspace_config(cx: &mut ModelContext<Project>) -> Task<()> {
         let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
         let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
 
         let settings_observation = cx.observe_global::<SettingsStore, _>(move |_, _| {
             *settings_changed_tx.borrow_mut() = ();
         });
+
         cx.spawn_weak(|this, mut cx| async move {
             while let Some(_) = settings_changed_rx.next().await {
-                let workspace_config = cx.update(|cx| languages.workspace_configuration(cx)).await;
-                if let Some(this) = this.upgrade(&cx) {
-                    this.read_with(&cx, |this, _| {
-                        for server_state in this.language_servers.values() {
-                            if let LanguageServerState::Running { server, .. } = server_state {
-                                server
-                                    .notify::<lsp::notification::DidChangeConfiguration>(
-                                        lsp::DidChangeConfigurationParams {
-                                            settings: workspace_config.clone(),
-                                        },
-                                    )
-                                    .ok();
-                            }
-                        }
-                    })
-                } else {
+                let Some(this) = this.upgrade(&cx) else {
                     break;
+                };
+
+                let servers: Vec<_> = this.read_with(&cx, |this, _| {
+                    this.language_servers
+                        .values()
+                        .filter_map(|state| match state {
+                            LanguageServerState::Starting(_) => None,
+                            LanguageServerState::Running {
+                                adapter, server, ..
+                            } => Some((adapter.clone(), server.clone())),
+                        })
+                        .collect()
+                });
+
+                for (adapter, server) in servers {
+                    let workspace_config =
+                        cx.update(|cx| adapter.workspace_configuration(cx)).await;
+                    server
+                        .notify::<lsp::notification::DidChangeConfiguration>(
+                            lsp::DidChangeConfigurationParams {
+                                settings: workspace_config.clone(),
+                            },
+                        )
+                        .ok();
                 }
             }
 
@@ -2584,7 +2591,6 @@ impl Project {
         let state = LanguageServerState::Starting({
             let adapter = adapter.clone();
             let server_name = adapter.name.0.clone();
-            let languages = self.languages.clone();
             let language = language.clone();
             let key = key.clone();
 
@@ -2594,7 +2600,6 @@ impl Project {
                     initialization_options,
                     pending_server,
                     adapter.clone(),
-                    languages,
                     language.clone(),
                     server_id,
                     key,
@@ -2698,7 +2703,6 @@ impl Project {
         initialization_options: Option<serde_json::Value>,
         pending_server: PendingLanguageServer,
         adapter: Arc<CachedLspAdapter>,
-        languages: Arc<LanguageRegistry>,
         language: Arc<Language>,
         server_id: LanguageServerId,
         key: (WorktreeId, LanguageServerName),
@@ -2709,7 +2713,6 @@ impl Project {
             initialization_options,
             pending_server,
             adapter.clone(),
-            languages,
             server_id,
             cx,
         );
@@ -2742,11 +2745,10 @@ impl Project {
         initialization_options: Option<serde_json::Value>,
         pending_server: PendingLanguageServer,
         adapter: Arc<CachedLspAdapter>,
-        languages: Arc<LanguageRegistry>,
         server_id: LanguageServerId,
         cx: &mut AsyncAppContext,
     ) -> Result<Option<Arc<LanguageServer>>> {
-        let workspace_config = cx.update(|cx| languages.workspace_configuration(cx)).await;
+        let workspace_config = cx.update(|cx| adapter.workspace_configuration(cx)).await;
         let language_server = match pending_server.task.await? {
             Some(server) => server,
             None => return Ok(None),
@@ -2788,12 +2790,12 @@ impl Project {
 
         language_server
             .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
-                let languages = languages.clone();
+                let adapter = adapter.clone();
                 move |params, mut cx| {
-                    let languages = languages.clone();
+                    let adapter = adapter.clone();
                     async move {
                         let workspace_config =
-                            cx.update(|cx| languages.workspace_configuration(cx)).await;
+                            cx.update(|cx| adapter.workspace_configuration(cx)).await;
                         Ok(params
                             .items
                             .into_iter()

crates/zed/src/languages/json.rs 🔗

@@ -102,7 +102,7 @@ impl LspAdapter for JsonLspAdapter {
     fn workspace_configuration(
         &self,
         cx: &mut AppContext,
-    ) -> Option<BoxFuture<'static, serde_json::Value>> {
+    ) -> BoxFuture<'static, serde_json::Value> {
         let action_names = cx.all_action_names().collect::<Vec<_>>();
         let staff_mode = cx.default_global::<StaffMode>().0;
         let language_names = &self.languages.language_names();
@@ -113,29 +113,28 @@ impl LspAdapter for JsonLspAdapter {
             },
             cx,
         );
-        Some(
-            future::ready(serde_json::json!({
-                "json": {
-                    "format": {
-                        "enable": true,
+
+        future::ready(serde_json::json!({
+            "json": {
+                "format": {
+                    "enable": true,
+                },
+                "schemas": [
+                    {
+                        "fileMatch": [
+                            schema_file_match(&paths::SETTINGS),
+                            &*paths::LOCAL_SETTINGS_RELATIVE_PATH,
+                        ],
+                        "schema": settings_schema,
                     },
-                    "schemas": [
-                        {
-                            "fileMatch": [
-                                schema_file_match(&paths::SETTINGS),
-                                &*paths::LOCAL_SETTINGS_RELATIVE_PATH,
-                            ],
-                            "schema": settings_schema,
-                        },
-                        {
-                            "fileMatch": [schema_file_match(&paths::KEYMAP)],
-                            "schema": KeymapFile::generate_json_schema(&action_names),
-                        }
-                    ]
-                }
-            }))
-            .boxed(),
-        )
+                    {
+                        "fileMatch": [schema_file_match(&paths::KEYMAP)],
+                        "schema": KeymapFile::generate_json_schema(&action_names),
+                    }
+                ]
+            }
+        }))
+        .boxed()
     }
 
     async fn language_ids(&self) -> HashMap<String, String> {

crates/zed/src/languages/tailwind.rs 🔗

@@ -103,23 +103,24 @@ impl LspAdapter for TailwindLspAdapter {
         }))
     }
 
-    fn workspace_configuration(&self, _: &mut AppContext) -> Option<BoxFuture<'static, Value>> {
-        Some(
-            future::ready(json!({
-                "tailwindCSS": {
-                    "emmetCompletions": true,
-                }
-            }))
-            .boxed(),
-        )
+    fn workspace_configuration(&self, _: &mut AppContext) -> BoxFuture<'static, Value> {
+        future::ready(json!({
+            "tailwindCSS": {
+                "emmetCompletions": true,
+            }
+        }))
+        .boxed()
     }
 
     async fn language_ids(&self) -> HashMap<String, String> {
-        HashMap::from([
-            ("HTML".to_string(), "html".to_string()),
-            ("CSS".to_string(), "css".to_string()),
-            ("JavaScript".to_string(), "javascript".to_string()),
-        ])
+        HashMap::from_iter(
+            [
+                ("HTML".to_string(), "html".to_string()),
+                ("CSS".to_string(), "css".to_string()),
+                ("JavaScript".to_string(), "javascript".to_string()),
+            ]
+            .into_iter(),
+        )
     }
 }
 

crates/zed/src/languages/typescript.rs 🔗

@@ -202,18 +202,16 @@ impl EsLintLspAdapter {
 
 #[async_trait]
 impl LspAdapter for EsLintLspAdapter {
-    fn workspace_configuration(&self, _: &mut AppContext) -> Option<BoxFuture<'static, Value>> {
-        Some(
-            future::ready(json!({
-                "": {
-                    "validate": "on",
-                    "rulesCustomizations": [],
-                    "run": "onType",
-                    "nodePath": null,
-                }
-            }))
-            .boxed(),
-        )
+    fn workspace_configuration(&self, _: &mut AppContext) -> BoxFuture<'static, Value> {
+        future::ready(json!({
+            "": {
+                "validate": "on",
+                "rulesCustomizations": [],
+                "run": "onType",
+                "nodePath": null,
+            }
+        }))
+        .boxed()
     }
 
     async fn name(&self) -> LanguageServerName {

crates/zed/src/languages/yaml.rs 🔗

@@ -86,21 +86,20 @@ impl LspAdapter for YamlLspAdapter {
     ) -> Option<LanguageServerBinary> {
         get_cached_server_binary(container_dir, &self.node).await
     }
-    fn workspace_configuration(&self, cx: &mut AppContext) -> Option<BoxFuture<'static, Value>> {
+    fn workspace_configuration(&self, cx: &mut AppContext) -> BoxFuture<'static, Value> {
         let tab_size = all_language_settings(None, cx)
             .language(Some("YAML"))
             .tab_size;
-        Some(
-            future::ready(serde_json::json!({
-                "yaml": {
-                    "keyOrdering": false
-                },
-                "[yaml]": {
-                    "editor.tabSize": tab_size,
-                }
-            }))
-            .boxed(),
-        )
+
+        future::ready(serde_json::json!({
+            "yaml": {
+                "keyOrdering": false
+            },
+            "[yaml]": {
+                "editor.tabSize": tab_size,
+            }
+        }))
+        .boxed()
     }
 }