languages: Add support for passing user settings to Go LSP adapter (#50472)

Finn Evers created

Closes https://github.com/zed-industries/zed/issues/50276

Release Notes:

- Added support for specifying settings for the Go LSP adapter

Change summary

crates/language/src/language.rs                        |  2 
crates/language_extension/src/extension_lsp_adapter.rs |  1 
crates/languages/src/css.rs                            |  1 
crates/languages/src/go.rs                             | 38 ++++++++++-
crates/languages/src/json.rs                           |  1 
crates/languages/src/python.rs                         |  2 
crates/languages/src/tailwind.rs                       |  1 
crates/languages/src/tailwindcss.rs                    |  1 
crates/languages/src/typescript.rs                     |  1 
crates/project/src/lsp_store.rs                        |  5 +
10 files changed, 47 insertions(+), 6 deletions(-)

Detailed changes

crates/language/src/language.rs 🔗

@@ -491,6 +491,7 @@ pub trait LspAdapter: 'static + Send + Sync + DynLspInstaller {
     async fn initialization_options(
         self: Arc<Self>,
         _: &Arc<dyn LspAdapterDelegate>,
+        _cx: &mut AsyncApp,
     ) -> Result<Option<Value>> {
         Ok(None)
     }
@@ -2638,6 +2639,7 @@ impl LspAdapter for FakeLspAdapter {
     async fn initialization_options(
         self: Arc<Self>,
         _: &Arc<dyn LspAdapterDelegate>,
+        _cx: &mut AsyncApp,
     ) -> Result<Option<Value>> {
         Ok(self.initialization_options.clone())
     }

crates/language_extension/src/extension_lsp_adapter.rs 🔗

@@ -309,6 +309,7 @@ impl LspAdapter for ExtensionLspAdapter {
     async fn initialization_options(
         self: Arc<Self>,
         delegate: &Arc<dyn LspAdapterDelegate>,
+        _: &mut AsyncApp,
     ) -> Result<Option<serde_json::Value>> {
         let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _;
         let json_options = self

crates/languages/src/css.rs 🔗

@@ -134,6 +134,7 @@ impl LspAdapter for CssLspAdapter {
     async fn initialization_options(
         self: Arc<Self>,
         _: &Arc<dyn LspAdapterDelegate>,
+        _: &mut AsyncApp,
     ) -> Result<Option<serde_json::Value>> {
         Ok(Some(json!({
             "provideFormatter": true

crates/languages/src/go.rs 🔗

@@ -8,8 +8,9 @@ pub use language::*;
 use language::{LanguageToolchainStore, LspAdapterDelegate, LspInstaller};
 use lsp::{LanguageServerBinary, LanguageServerName};
 
+use project::lsp_store::language_server_settings;
 use regex::Regex;
-use serde_json::json;
+use serde_json::{Value, json};
 use smol::fs;
 use std::{
     borrow::Cow,
@@ -24,7 +25,7 @@ use std::{
     },
 };
 use task::{TaskTemplate, TaskTemplates, TaskVariables, VariableName};
-use util::{ResultExt, fs::remove_matching, maybe};
+use util::{ResultExt, fs::remove_matching, maybe, merge_json_value_into};
 
 fn server_binary_arguments() -> Vec<OsString> {
     vec!["-mode=stdio".into()]
@@ -192,9 +193,10 @@ impl LspAdapter for GoLspAdapter {
 
     async fn initialization_options(
         self: Arc<Self>,
-        _: &Arc<dyn LspAdapterDelegate>,
+        delegate: &Arc<dyn LspAdapterDelegate>,
+        cx: &mut AsyncApp,
     ) -> Result<Option<serde_json::Value>> {
-        Ok(Some(json!({
+        let mut default_config = json!({
             "usePlaceholders": false,
             "hints": {
                 "assignVariableTypes": true,
@@ -205,7 +207,33 @@ impl LspAdapter for GoLspAdapter {
                 "parameterNames": true,
                 "rangeVariableTypes": true
             }
-        })))
+        });
+
+        let project_initialization_options = cx.update(|cx| {
+            language_server_settings(delegate.as_ref(), &self.name(), cx)
+                .and_then(|s| s.initialization_options.clone())
+        });
+
+        if let Some(override_options) = project_initialization_options {
+            merge_json_value_into(override_options, &mut default_config);
+        }
+
+        Ok(Some(default_config))
+    }
+
+    async fn workspace_configuration(
+        self: Arc<Self>,
+        delegate: &Arc<dyn LspAdapterDelegate>,
+        _: Option<Toolchain>,
+        _: Option<lsp::Uri>,
+        cx: &mut AsyncApp,
+    ) -> Result<Value> {
+        Ok(cx
+            .update(|cx| {
+                language_server_settings(delegate.as_ref(), &self.name(), cx)
+                    .and_then(|settings| settings.settings.clone())
+            })
+            .unwrap_or_default())
     }
 
     async fn label_for_completion(

crates/languages/src/json.rs 🔗

@@ -245,6 +245,7 @@ impl LspAdapter for JsonLspAdapter {
     async fn initialization_options(
         self: Arc<Self>,
         _: &Arc<dyn LspAdapterDelegate>,
+        _: &mut AsyncApp,
     ) -> Result<Option<serde_json::Value>> {
         Ok(Some(json!({
             "provideFormatter": true

crates/languages/src/python.rs 🔗

@@ -507,6 +507,7 @@ impl LspAdapter for PyrightLspAdapter {
     async fn initialization_options(
         self: Arc<Self>,
         _: &Arc<dyn LspAdapterDelegate>,
+        _: &mut AsyncApp,
     ) -> Result<Option<Value>> {
         // Provide minimal initialization options
         // Virtual environment configuration will be handled through workspace configuration
@@ -1972,6 +1973,7 @@ impl LspAdapter for BasedPyrightLspAdapter {
     async fn initialization_options(
         self: Arc<Self>,
         _: &Arc<dyn LspAdapterDelegate>,
+        _: &mut AsyncApp,
     ) -> Result<Option<Value>> {
         // Provide minimal initialization options
         // Virtual environment configuration will be handled through workspace configuration

crates/languages/src/tailwind.rs 🔗

@@ -139,6 +139,7 @@ impl LspAdapter for TailwindLspAdapter {
     async fn initialization_options(
         self: Arc<Self>,
         _: &Arc<dyn LspAdapterDelegate>,
+        _: &mut AsyncApp,
     ) -> Result<Option<serde_json::Value>> {
         Ok(Some(json!({
             "provideFormatter": true,

crates/languages/src/tailwindcss.rs 🔗

@@ -135,6 +135,7 @@ impl LspAdapter for TailwindCssLspAdapter {
     async fn initialization_options(
         self: Arc<Self>,
         _: &Arc<dyn LspAdapterDelegate>,
+        _: &mut AsyncApp,
     ) -> Result<Option<serde_json::Value>> {
         Ok(Some(json!({
             "provideFormatter": true

crates/languages/src/typescript.rs 🔗

@@ -804,6 +804,7 @@ impl LspAdapter for TypeScriptLspAdapter {
     async fn initialization_options(
         self: Arc<Self>,
         adapter: &Arc<dyn LspAdapterDelegate>,
+        _: &mut AsyncApp,
     ) -> Result<Option<serde_json::Value>> {
         let tsdk_path = self.tsdk_path(adapter).await;
         Ok(Some(json!({

crates/project/src/lsp_store.rs 🔗

@@ -548,6 +548,7 @@ impl LocalLspStore {
                     let mut initialization_options = Self::initialization_options_for_adapter(
                         adapter.adapter.clone(),
                         &delegate,
+                        cx,
                     )
                     .await?;
 
@@ -3771,9 +3772,10 @@ impl LocalLspStore {
     async fn initialization_options_for_adapter(
         adapter: Arc<dyn LspAdapter>,
         delegate: &Arc<dyn LspAdapterDelegate>,
+        cx: &mut AsyncApp,
     ) -> Result<Option<serde_json::Value>> {
         let Some(mut initialization_config) =
-            adapter.clone().initialization_options(delegate).await?
+            adapter.clone().initialization_options(delegate, cx).await?
         else {
             return Ok(None);
         };
@@ -13986,6 +13988,7 @@ impl LspAdapter for SshLspAdapter {
     async fn initialization_options(
         self: Arc<Self>,
         _: &Arc<dyn LspAdapterDelegate>,
+        _: &mut AsyncApp,
     ) -> Result<Option<serde_json::Value>> {
         let Some(options) = &self.initialization_options else {
             return Ok(None);