Send lsp_types::InitializeParams with Zed version (#7216)

Kirill Bulatov created

Based on the great work in
https://github.com/zed-industries/zed/pull/7130 , now sends this data

```
[crates/lsp/src/lsp.rs:588] ClientInfo { name: name.to_string(), version: Some(version.to_string()) } = ClientInfo {
    name: "Zed Dev",
    version: Some(
        "0.122.0",
    ),
}
```

with every LSP server initialization.

Release Notes:

- Added Zed name and version to LSP InitializeParams requests

Change summary

Cargo.lock                                    |  6 +++
crates/copilot/src/copilot.rs                 |  2 
crates/editor/Cargo.toml                      |  1 
crates/editor/src/editor_tests.rs             |  1 
crates/editor/src/inlay_hint_cache.rs         |  1 
crates/language_tools/Cargo.toml              |  1 
crates/language_tools/src/lsp_log_tests.rs    |  1 
crates/lsp/Cargo.toml                         |  1 
crates/lsp/src/lsp.rs                         | 36 ++++++++++++++------
crates/prettier/src/prettier.rs               |  6 +-
crates/project/Cargo.toml                     |  1 
crates/project/src/project.rs                 |  4 +
crates/project/src/project_tests.rs           |  1 
crates/project_symbols/Cargo.toml             |  1 
crates/project_symbols/src/project_symbols.rs |  1 
crates/vim/Cargo.toml                         |  1 
crates/vim/src/test/vim_test_context.rs       |  1 
17 files changed, 50 insertions(+), 16 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -2425,6 +2425,7 @@ dependencies = [
  "postage",
  "project",
  "rand 0.8.5",
+ "release_channel",
  "rich_text",
  "rpc",
  "schemars",
@@ -4021,6 +4022,7 @@ dependencies = [
  "language",
  "lsp",
  "project",
+ "release_channel",
  "serde",
  "serde_json",
  "settings",
@@ -4265,6 +4267,7 @@ dependencies = [
  "lsp-types",
  "parking_lot 0.11.2",
  "postage",
+ "release_channel",
  "serde",
  "serde_derive",
  "serde_json",
@@ -5819,6 +5822,7 @@ dependencies = [
  "pretty_assertions",
  "rand 0.8.5",
  "regex",
+ "release_channel",
  "rpc",
  "schemars",
  "serde",
@@ -5883,6 +5887,7 @@ dependencies = [
  "picker",
  "postage",
  "project",
+ "release_channel",
  "serde_json",
  "settings",
  "smol",
@@ -9443,6 +9448,7 @@ dependencies = [
  "parking_lot 0.11.2",
  "project",
  "regex",
+ "release_channel",
  "search",
  "serde",
  "serde_derive",

crates/copilot/src/copilot.rs 🔗

@@ -445,7 +445,7 @@ impl Copilot {
                     )
                     .detach();
 
-                let server = server.initialize(Default::default()).await?;
+                let server = cx.update(|cx| server.initialize(None, cx))?.await?;
 
                 let status = server
                     .request::<request::CheckStatus>(request::CheckStatusParams {

crates/editor/Cargo.toml 🔗

@@ -79,6 +79,7 @@ language = { path = "../language", features = ["test-support"] }
 lsp = { path = "../lsp", features = ["test-support"] }
 multi_buffer = { path = "../multi_buffer", features = ["test-support"] }
 project = { path = "../project", features = ["test-support"] }
+release_channel = { path = "../release_channel" }
 rand.workspace = true
 settings = { path = "../settings", features = ["test-support"] }
 text = { path = "../text", features = ["test-support"] }

crates/editor/src/editor_tests.rs 🔗

@@ -8392,6 +8392,7 @@ pub(crate) fn init_test(cx: &mut TestAppContext, f: fn(&mut AllLanguageSettingsC
         let store = SettingsStore::test(cx);
         cx.set_global(store);
         theme::init(theme::LoadThemes::JustBase, cx);
+        release_channel::init("0.0.0", cx);
         client::init_settings(cx);
         language::init(cx);
         Project::init_settings(cx);

crates/editor/src/inlay_hint_cache.rs 🔗

@@ -3216,6 +3216,7 @@ pub mod tests {
             let settings_store = SettingsStore::test(cx);
             cx.set_global(settings_store);
             theme::init(theme::LoadThemes::JustBase, cx);
+            release_channel::init("0.0.0", cx);
             client::init_settings(cx);
             language::init(cx);
             Project::init_settings(cx);

crates/language_tools/Cargo.toml 🔗

@@ -30,6 +30,7 @@ workspace = { path = "../workspace" }
 [dev-dependencies]
 client = { path = "../client", features = ["test-support"] }
 editor = { path = "../editor", features = ["test-support"] }
+release_channel = { path = "../release_channel" }
 env_logger.workspace = true
 gpui = { path = "../gpui", features = ["test-support"] }
 unindent.workspace = true

crates/language_tools/src/lsp_log_tests.rs 🔗

@@ -100,6 +100,7 @@ fn init_test(cx: &mut gpui::TestAppContext) {
         let settings_store = SettingsStore::test(cx);
         cx.set_global(settings_store);
         theme::init(theme::LoadThemes::JustBase, cx);
+        release_channel::init("0.0.0", cx);
         language::init(cx);
         client::init_settings(cx);
         Project::init_settings(cx);

crates/lsp/Cargo.toml 🔗

@@ -27,6 +27,7 @@ serde_derive.workspace = true
 serde_json.workspace = true
 smol.workspace = true
 util = { path = "../util" }
+release_channel = { path = "../release_channel" }
 
 [dev-dependencies]
 async-pipe = { git = "https://github.com/zed-industries/async-pipe-rs", rev = "82d00a04211cf4e1236029aa03e6b6ce2a74c553" }

crates/lsp/src/lsp.rs 🔗

@@ -5,7 +5,7 @@ pub use lsp_types::*;
 use anyhow::{anyhow, Context, Result};
 use collections::HashMap;
 use futures::{channel::oneshot, io::BufWriter, AsyncRead, AsyncWrite, FutureExt};
-use gpui::{AsyncAppContext, BackgroundExecutor, Task};
+use gpui::{AppContext, AsyncAppContext, BackgroundExecutor, Task};
 use parking_lot::Mutex;
 use postage::{barrier, prelude::Stream};
 use serde::{de::DeserializeOwned, Deserialize, Serialize};
@@ -450,7 +450,11 @@ impl LanguageServer {
     /// Note that `options` is used directly to construct [`InitializeParams`], which is why it is owned.
     ///
     /// [LSP Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize)
-    pub async fn initialize(mut self, options: Option<Value>) -> Result<Arc<Self>> {
+    pub fn initialize(
+        mut self,
+        options: Option<Value>,
+        cx: &AppContext,
+    ) -> Task<Result<Arc<Self>>> {
         let root_uri = Url::from_file_path(&self.root_path).unwrap();
         #[allow(deprecated)]
         let params = InitializeParams {
@@ -579,18 +583,25 @@ impl LanguageServer {
                 uri: root_uri,
                 name: Default::default(),
             }]),
-            client_info: None,
+            client_info: Some(ClientInfo {
+                name: release_channel::ReleaseChannel::global(cx)
+                    .display_name()
+                    .to_string(),
+                version: Some(release_channel::AppVersion::global(cx).to_string()),
+            }),
             locale: None,
         };
 
-        let response = self.request::<request::Initialize>(params).await?;
-        if let Some(info) = response.server_info {
-            self.name = info.name;
-        }
-        self.capabilities = response.capabilities;
+        cx.spawn(|_| async move {
+            let response = self.request::<request::Initialize>(params).await?;
+            if let Some(info) = response.server_info {
+                self.name = info.name;
+            }
+            self.capabilities = response.capabilities;
 
-        self.notify::<notification::Initialized>(InitializedParams {})?;
-        Ok(Arc::new(self))
+            self.notify::<notification::Initialized>(InitializedParams {})?;
+            Ok(Arc::new(self))
+        })
     }
 
     /// Sends a shutdown request to the language server process and prepares the [`LanguageServer`] to be dropped.
@@ -1213,6 +1224,9 @@ mod tests {
 
     #[gpui::test]
     async fn test_fake(cx: &mut TestAppContext) {
+        cx.update(|cx| {
+            release_channel::init("0.0.0", cx);
+        });
         let (server, mut fake) =
             FakeLanguageServer::new("the-lsp".to_string(), Default::default(), cx.to_async());
 
@@ -1229,7 +1243,7 @@ mod tests {
             })
             .detach();
 
-        let server = server.initialize(None).await.unwrap();
+        let server = cx.update(|cx| server.initialize(None, cx)).await.unwrap();
         server
             .notify::<notification::DidOpenTextDocument>(DidOpenTextDocumentParams {
                 text_document: TextDocumentItem::new(

crates/prettier/src/prettier.rs 🔗

@@ -195,11 +195,11 @@ impl Prettier {
             },
             Path::new("/"),
             None,
-            cx,
+            cx.clone(),
         )
         .context("prettier server creation")?;
-        let server = executor
-            .spawn(server.initialize(None))
+        let server = cx
+            .update(|cx| executor.spawn(server.initialize(None, cx)))?
             .await
             .context("prettier server initialization")?;
         Ok(Self::Real(RealPrettier {

crates/project/Cargo.toml 🔗

@@ -75,6 +75,7 @@ fs = { path = "../fs",  features = ["test-support"] }
 git2.workspace = true
 gpui = { path = "../gpui", features = ["test-support"] }
 language = { path = "../language", features = ["test-support"] }
+release_channel = { path = "../release_channel" }
 lsp = { path = "../lsp", features = ["test-support"] }
 prettier = { path = "../prettier", features = ["test-support"] }
 pretty_assertions.workspace = true

crates/project/src/project.rs 🔗

@@ -3130,7 +3130,9 @@ impl Project {
             (None, override_options) => initialization_options = override_options,
             _ => {}
         }
-        let language_server = language_server.initialize(initialization_options).await?;
+        let language_server = cx
+            .update(|cx| language_server.initialize(initialization_options, cx))?
+            .await?;
 
         language_server
             .notify::<lsp::notification::DidChangeConfiguration>(

crates/project/src/project_tests.rs 🔗

@@ -4380,6 +4380,7 @@ fn init_test(cx: &mut gpui::TestAppContext) {
     cx.update(|cx| {
         let settings_store = SettingsStore::test(cx);
         cx.set_global(settings_store);
+        release_channel::init("0.0.0", cx);
         language::init(cx);
         Project::init_settings(cx);
     });

crates/project_symbols/Cargo.toml 🔗

@@ -33,6 +33,7 @@ gpui = { path = "../gpui", features = ["test-support"] }
 language = { path = "../language", features = ["test-support"] }
 lsp = { path = "../lsp", features = ["test-support"] }
 project = { path = "../project", features = ["test-support"] }
+release_channel = { path = "../release_channel" }
 settings = { path = "../settings", features = ["test-support"] }
 theme = { path = "../theme", features = ["test-support"] }
 workspace = { path = "../workspace", features = ["test-support"] }

crates/project_symbols/src/project_symbols.rs 🔗

@@ -392,6 +392,7 @@ mod tests {
             let store = SettingsStore::test(cx);
             cx.set_global(store);
             theme::init(theme::LoadThemes::JustBase, cx);
+            release_channel::init("0.0.0", cx);
             language::init(cx);
             Project::init_settings(cx);
             workspace::init_settings(cx);

crates/vim/Cargo.toml 🔗

@@ -43,6 +43,7 @@ zed_actions = { path = "../zed_actions" }
 editor = { path = "../editor", features = ["test-support"] }
 futures.workspace = true
 gpui = { path = "../gpui", features = ["test-support"] }
+release_channel = { path = "../release_channel" }
 indoc.workspace = true
 language = { path = "../language", features = ["test-support"] }
 lsp = { path = "../lsp", features = ["test-support"] }

crates/vim/src/test/vim_test_context.rs 🔗

@@ -23,6 +23,7 @@ impl VimTestContext {
             search::init(cx);
             let settings = SettingsStore::test(cx);
             cx.set_global(settings);
+            release_channel::init("0.0.0", cx);
             command_palette::init(cx);
             crate::init(cx);
         });