From a97ab5eb3df2307b31b0acb7997e8f6da1e53356 Mon Sep 17 00:00:00 2001 From: Thorsten Ball Date: Mon, 11 Nov 2024 10:18:38 +0100 Subject: [PATCH] language servers: Fix wrong language server name (#20428) This fixes the issue of multiple language servers showing up as `node` in the language server logs dropdown. It does this by changing `language_server.name()` to return the adapter's name, not the binary name, and changing types to make sure that we always use this. Release Notes: - Fixed language server names showing up only as `"node"` --------- Co-authored-by: Sam Rose Co-authored-by: Bennet --- Cargo.lock | 2 + crates/activity_indicator/Cargo.toml | 1 + .../src/activity_indicator.rs | 5 +- crates/collab/src/tests/integration_tests.rs | 5 +- crates/copilot/src/copilot.rs | 4 +- crates/editor/src/editor.rs | 6 +- crates/extension/src/extension_manifest.rs | 3 +- crates/extension_host/src/extension_host.rs | 10 +-- .../src/extension_lsp_adapter.rs | 5 +- crates/extension_host/src/wasm_host/wit.rs | 3 +- .../src/wasm_host/wit/since_v0_0_1.rs | 2 +- .../src/wasm_host/wit/since_v0_1_0.rs | 6 +- .../src/wasm_host/wit/since_v0_2_0.rs | 8 +- crates/extensions_ui/Cargo.toml | 1 + .../src/extension_registration_hooks.rs | 4 +- .../extensions_ui/src/extension_store_test.rs | 3 +- crates/language/src/language.rs | 53 +---------- crates/language_tools/src/lsp_log.rs | 6 +- crates/language_tools/src/lsp_log_tests.rs | 5 +- crates/languages/src/c.rs | 2 +- crates/languages/src/css.rs | 4 +- crates/languages/src/go.rs | 2 +- crates/languages/src/json.rs | 6 +- crates/languages/src/lib.rs | 1 + crates/languages/src/python.rs | 3 +- crates/languages/src/rust.rs | 2 +- crates/languages/src/tailwind.rs | 4 +- crates/languages/src/typescript.rs | 4 +- crates/languages/src/vtsls.rs | 4 +- crates/languages/src/yaml.rs | 5 +- crates/lsp/Cargo.toml | 1 + crates/lsp/src/lsp.rs | 90 ++++++++++++++++--- crates/prettier/src/prettier.rs | 15 ++-- crates/project/src/lsp_store.rs | 17 ++-- crates/project/src/prettier_store.rs | 4 +- crates/project/src/project.rs | 6 +- crates/project/src/project_settings.rs | 2 +- crates/project/src/project_tests.rs | 14 ++- .../remote_server/src/remote_editing_tests.rs | 5 +- 39 files changed, 172 insertions(+), 151 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 93dcbd050e..7aecdd8f33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,6 +13,7 @@ dependencies = [ "futures 0.3.30", "gpui", "language", + "lsp", "project", "smallvec", "ui", @@ -6898,6 +6899,7 @@ dependencies = [ "parking_lot", "postage", "release_channel", + "schemars", "serde", "serde_json", "smol", diff --git a/crates/activity_indicator/Cargo.toml b/crates/activity_indicator/Cargo.toml index 6f026d7662..54c2f49844 100644 --- a/crates/activity_indicator/Cargo.toml +++ b/crates/activity_indicator/Cargo.toml @@ -20,6 +20,7 @@ extension_host.workspace = true futures.workspace = true gpui.workspace = true language.workspace = true +lsp.workspace = true project.workspace = true smallvec.workspace = true ui.workspace = true diff --git a/crates/activity_indicator/src/activity_indicator.rs b/crates/activity_indicator/src/activity_indicator.rs index c9fc51ff1e..21f7bff6d3 100644 --- a/crates/activity_indicator/src/activity_indicator.rs +++ b/crates/activity_indicator/src/activity_indicator.rs @@ -7,9 +7,8 @@ use gpui::{ InteractiveElement as _, Model, ParentElement as _, Render, SharedString, StatefulInteractiveElement, Styled, Transformation, View, ViewContext, VisualContext as _, }; -use language::{ - LanguageRegistry, LanguageServerBinaryStatus, LanguageServerId, LanguageServerName, -}; +use language::{LanguageRegistry, LanguageServerBinaryStatus, LanguageServerId}; +use lsp::LanguageServerName; use project::{EnvironmentErrorMessage, LanguageServerProgress, Project, WorktreeId}; use smallvec::SmallVec; use std::{cmp::Reverse, fmt::Write, sync::Arc, time::Duration}; diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 8c819d6da7..751469a700 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -5130,11 +5130,10 @@ async fn test_lsp_hover( }); let new_server_name = new_server.server.name(); assert!( - !servers_with_hover_requests.contains_key(new_server_name), + !servers_with_hover_requests.contains_key(&new_server_name), "Unexpected: initialized server with the same name twice. Name: `{new_server_name}`" ); - let new_server_name = new_server_name.to_string(); - match new_server_name.as_str() { + match new_server_name.as_ref() { "CrabLang-ls" => { servers_with_hover_requests.insert( new_server_name.clone(), diff --git a/crates/copilot/src/copilot.rs b/crates/copilot/src/copilot.rs index 15b6bf6083..3004c4e985 100644 --- a/crates/copilot/src/copilot.rs +++ b/crates/copilot/src/copilot.rs @@ -21,7 +21,7 @@ use language::{ point_from_lsp, point_to_lsp, Anchor, Bias, Buffer, BufferSnapshot, Language, PointUtf16, ToPointUtf16, }; -use lsp::{LanguageServer, LanguageServerBinary, LanguageServerId}; +use lsp::{LanguageServer, LanguageServerBinary, LanguageServerId, LanguageServerName}; use node_runtime::NodeRuntime; use parking_lot::Mutex; use request::StatusNotification; @@ -446,9 +446,11 @@ impl Copilot { Path::new("/") }; + let server_name = LanguageServerName("copilot".into()); let server = LanguageServer::new( Arc::new(Mutex::new(None)), new_server_id, + server_name, binary, root_path, None, diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 3fd0acd753..ea3c1ee7a6 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -96,9 +96,7 @@ use language::{ CursorShape, Diagnostic, Documentation, IndentKind, IndentSize, Language, OffsetRangeExt, Point, Selection, SelectionGoal, TransactionId, }; -use language::{ - point_to_lsp, BufferRow, CharClassifier, LanguageServerName, Runnable, RunnableRange, -}; +use language::{point_to_lsp, BufferRow, CharClassifier, Runnable, RunnableRange}; use linked_editing_ranges::refresh_linked_ranges; pub use proposed_changes_editor::{ ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar, @@ -111,7 +109,7 @@ use hover_links::{find_file, HoverLink, HoveredLinkState, InlayHighlight}; pub use lsp::CompletionContext; use lsp::{ CompletionItemKind, CompletionTriggerKind, DiagnosticSeverity, InsertTextFormat, - LanguageServerId, + LanguageServerId, LanguageServerName, }; use mouse_context_menu::MouseContextMenu; use movement::TextLayoutDetails; diff --git a/crates/extension/src/extension_manifest.rs b/crates/extension/src/extension_manifest.rs index 77be30c6c0..53fe935c1b 100644 --- a/crates/extension/src/extension_manifest.rs +++ b/crates/extension/src/extension_manifest.rs @@ -1,7 +1,8 @@ use anyhow::{anyhow, Context, Result}; use collections::{BTreeMap, HashMap}; use fs::Fs; -use language::{LanguageName, LanguageServerName}; +use language::LanguageName; +use lsp::LanguageServerName; use semantic_version::SemanticVersion; use serde::{Deserialize, Serialize}; use std::{ diff --git a/crates/extension_host/src/extension_host.rs b/crates/extension_host/src/extension_host.rs index c10a435e2d..9700187f8c 100644 --- a/crates/extension_host/src/extension_host.rs +++ b/crates/extension_host/src/extension_host.rs @@ -28,6 +28,7 @@ use language::{ LanguageConfig, LanguageMatcher, LanguageName, LanguageQueries, LoadedLanguage, QUERY_FILENAME_PREFIXES, }; +use lsp::LanguageServerName; use node_runtime::NodeRuntime; use project::ContextProviderWithTasks; use release_channel::ReleaseChannel; @@ -121,12 +122,7 @@ pub trait ExtensionRegistrationHooks: Send + Sync + 'static { fn register_lsp_adapter(&self, _language: LanguageName, _adapter: ExtensionLspAdapter) {} - fn remove_lsp_adapter( - &self, - _language: &LanguageName, - _server_name: &language::LanguageServerName, - ) { - } + fn remove_lsp_adapter(&self, _language: &LanguageName, _server_name: &LanguageServerName) {} fn register_wasm_grammars(&self, _grammars: Vec<(Arc, PathBuf)>) {} @@ -167,7 +163,7 @@ pub trait ExtensionRegistrationHooks: Send + Sync + 'static { fn update_lsp_status( &self, - _server_name: language::LanguageServerName, + _server_name: lsp::LanguageServerName, _status: language::LanguageServerBinaryStatus, ) { } diff --git a/crates/extension_host/src/extension_lsp_adapter.rs b/crates/extension_host/src/extension_lsp_adapter.rs index 9d8cc90c1c..b15fa5adc4 100644 --- a/crates/extension_host/src/extension_lsp_adapter.rs +++ b/crates/extension_host/src/extension_lsp_adapter.rs @@ -8,10 +8,9 @@ use collections::HashMap; use futures::{Future, FutureExt}; use gpui::AsyncAppContext; use language::{ - CodeLabel, HighlightId, Language, LanguageServerName, LanguageToolchainStore, LspAdapter, - LspAdapterDelegate, + CodeLabel, HighlightId, Language, LanguageToolchainStore, LspAdapter, LspAdapterDelegate, }; -use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions}; +use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerName}; use serde::Serialize; use serde_json::Value; use std::ops::Range; diff --git a/crates/extension_host/src/wasm_host/wit.rs b/crates/extension_host/src/wasm_host/wit.rs index ae85c35e94..13a7ab042f 100644 --- a/crates/extension_host/src/wasm_host/wit.rs +++ b/crates/extension_host/src/wasm_host/wit.rs @@ -3,6 +3,7 @@ mod since_v0_0_4; mod since_v0_0_6; mod since_v0_1_0; mod since_v0_2_0; +use lsp::LanguageServerName; // use indexed_docs::IndexedDocsDatabase; use release_channel::ReleaseChannel; use since_v0_2_0 as latest; @@ -11,7 +12,7 @@ use crate::DocsDatabase; use super::{wasm_engine, WasmState}; use anyhow::{anyhow, Context, Result}; -use language::{LanguageServerName, LspAdapterDelegate}; +use language::LspAdapterDelegate; use semantic_version::SemanticVersion; use std::{ops::RangeInclusive, sync::Arc}; use wasmtime::{ diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_0_1.rs b/crates/extension_host/src/wasm_host/wit/since_v0_0_1.rs index e3e951a4e1..3493d2a74d 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_0_1.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_0_1.rs @@ -149,7 +149,7 @@ impl ExtensionImports for WasmState { self.host .registration_hooks - .update_lsp_status(language::LanguageServerName(server_name.into()), status); + .update_lsp_status(lsp::LanguageServerName(server_name.into()), status); Ok(()) } diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_1_0.rs b/crates/extension_host/src/wasm_host/wit/since_v0_1_0.rs index 706a8ac22d..d8743f2c9c 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_1_0.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_1_0.rs @@ -8,10 +8,10 @@ use async_tar::Archive; use async_trait::async_trait; use futures::{io::BufReader, FutureExt as _}; use futures::{lock::Mutex, AsyncReadExt}; +use language::LanguageName; use language::{ language_settings::AllLanguageSettings, LanguageServerBinaryStatus, LspAdapterDelegate, }; -use language::{LanguageName, LanguageServerName}; use project::project_settings::ProjectSettings; use semantic_version::SemanticVersion; use std::{ @@ -469,7 +469,7 @@ impl ExtensionImports for WasmState { .and_then(|key| { ProjectSettings::get(location, cx) .lsp - .get(&LanguageServerName(key.into())) + .get(&::lsp::LanguageServerName(key.into())) }) .cloned() .unwrap_or_default(); @@ -513,7 +513,7 @@ impl ExtensionImports for WasmState { self.host .registration_hooks - .update_lsp_status(language::LanguageServerName(server_name.into()), status); + .update_lsp_status(::lsp::LanguageServerName(server_name.into()), status); Ok(()) } diff --git a/crates/extension_host/src/wasm_host/wit/since_v0_2_0.rs b/crates/extension_host/src/wasm_host/wit/since_v0_2_0.rs index f920b9215f..86ae7a1f12 100644 --- a/crates/extension_host/src/wasm_host/wit/since_v0_2_0.rs +++ b/crates/extension_host/src/wasm_host/wit/since_v0_2_0.rs @@ -9,9 +9,9 @@ use async_trait::async_trait; use futures::{io::BufReader, FutureExt as _}; use futures::{lock::Mutex, AsyncReadExt}; use language::{ - language_settings::AllLanguageSettings, LanguageServerBinaryStatus, LspAdapterDelegate, + language_settings::AllLanguageSettings, LanguageName, LanguageServerBinaryStatus, + LspAdapterDelegate, }; -use language::{LanguageName, LanguageServerName}; use project::project_settings::ProjectSettings; use semantic_version::SemanticVersion; use std::{ @@ -416,7 +416,7 @@ impl ExtensionImports for WasmState { .and_then(|key| { ProjectSettings::get(location, cx) .lsp - .get(&LanguageServerName::from_proto(key)) + .get(&::lsp::LanguageServerName::from_proto(key)) }) .cloned() .unwrap_or_default(); @@ -460,7 +460,7 @@ impl ExtensionImports for WasmState { self.host .registration_hooks - .update_lsp_status(language::LanguageServerName(server_name.into()), status); + .update_lsp_status(::lsp::LanguageServerName(server_name.into()), status); Ok(()) } diff --git a/crates/extensions_ui/Cargo.toml b/crates/extensions_ui/Cargo.toml index 96c62d3bfb..a13b52b78b 100644 --- a/crates/extensions_ui/Cargo.toml +++ b/crates/extensions_ui/Cargo.toml @@ -30,6 +30,7 @@ fuzzy.workspace = true gpui.workspace = true indexed_docs.workspace = true language.workspace = true +lsp.workspace = true num-format.workspace = true picker.workspace = true project.workspace = true diff --git a/crates/extensions_ui/src/extension_registration_hooks.rs b/crates/extensions_ui/src/extension_registration_hooks.rs index 37fe658894..5a6ca8db06 100644 --- a/crates/extensions_ui/src/extension_registration_hooks.rs +++ b/crates/extensions_ui/src/extension_registration_hooks.rs @@ -121,7 +121,7 @@ impl extension_host::ExtensionRegistrationHooks for ConcreteExtensionRegistratio fn update_lsp_status( &self, - server_name: language::LanguageServerName, + server_name: lsp::LanguageServerName, status: LanguageServerBinaryStatus, ) { self.language_registry @@ -140,7 +140,7 @@ impl extension_host::ExtensionRegistrationHooks for ConcreteExtensionRegistratio fn remove_lsp_adapter( &self, language_name: &language::LanguageName, - server_name: &language::LanguageServerName, + server_name: &lsp::LanguageServerName, ) { self.language_registry .remove_lsp_adapter(language_name, server_name); diff --git a/crates/extensions_ui/src/extension_store_test.rs b/crates/extensions_ui/src/extension_store_test.rs index 88730e8eee..9c5140272d 100644 --- a/crates/extensions_ui/src/extension_store_test.rs +++ b/crates/extensions_ui/src/extension_store_test.rs @@ -14,7 +14,8 @@ use futures::{io::BufReader, AsyncReadExt, StreamExt}; use gpui::{Context, SemanticVersion, TestAppContext}; use http_client::{FakeHttpClient, Response}; use indexed_docs::IndexedDocsRegistry; -use language::{LanguageMatcher, LanguageRegistry, LanguageServerBinaryStatus, LanguageServerName}; +use language::{LanguageMatcher, LanguageRegistry, LanguageServerBinaryStatus}; +use lsp::LanguageServerName; use node_runtime::NodeRuntime; use parking_lot::Mutex; use project::{Project, DEFAULT_COMPLETION_CONTEXT}; diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 48501114b0..580955a98b 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -30,7 +30,7 @@ use gpui::{AppContext, AsyncAppContext, Model, SharedString, Task}; pub use highlight_map::HighlightMap; use http_client::HttpClient; pub use language_registry::{LanguageName, LoadedLanguage}; -use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions}; +use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerName}; use parking_lot::Mutex; use regex::Regex; use schemars::{ @@ -139,57 +139,6 @@ pub trait ToLspPosition { fn to_lsp_position(self) -> lsp::Position; } -/// A name of a language server. -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)] -pub struct LanguageServerName(pub SharedString); - -impl std::fmt::Display for LanguageServerName { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Display::fmt(&self.0, f) - } -} - -impl AsRef for LanguageServerName { - fn as_ref(&self) -> &str { - self.0.as_ref() - } -} - -impl AsRef for LanguageServerName { - fn as_ref(&self) -> &OsStr { - self.0.as_ref().as_ref() - } -} - -impl JsonSchema for LanguageServerName { - fn schema_name() -> String { - "LanguageServerName".into() - } - - fn json_schema(_: &mut SchemaGenerator) -> Schema { - SchemaObject { - instance_type: Some(InstanceType::String.into()), - ..Default::default() - } - .into() - } -} -impl LanguageServerName { - pub const fn new_static(s: &'static str) -> Self { - Self(SharedString::new_static(s)) - } - - pub fn from_proto(s: String) -> Self { - Self(s.into()) - } -} - -impl<'a> From<&'a str> for LanguageServerName { - fn from(str: &'a str) -> LanguageServerName { - LanguageServerName(str.to_string().into()) - } -} - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Location { pub buffer: Model, diff --git a/crates/language_tools/src/lsp_log.rs b/crates/language_tools/src/lsp_log.rs index e57d5dbc4a..16044f941f 100644 --- a/crates/language_tools/src/lsp_log.rs +++ b/crates/language_tools/src/lsp_log.rs @@ -7,10 +7,10 @@ use gpui::{ IntoElement, Model, ModelContext, ParentElement, Render, Styled, Subscription, View, ViewContext, VisualContext, WeakModel, WindowContext, }; -use language::{LanguageServerId, LanguageServerName}; +use language::LanguageServerId; use lsp::{ - notification::SetTrace, IoKind, LanguageServer, MessageType, ServerCapabilities, - SetTraceParams, TraceValue, + notification::SetTrace, IoKind, LanguageServer, LanguageServerName, MessageType, + ServerCapabilities, SetTraceParams, TraceValue, }; use project::{search::SearchQuery, Project, WorktreeId}; use std::{borrow::Cow, sync::Arc}; diff --git a/crates/language_tools/src/lsp_log_tests.rs b/crates/language_tools/src/lsp_log_tests.rs index 6b45cfc8dc..79308b6e10 100644 --- a/crates/language_tools/src/lsp_log_tests.rs +++ b/crates/language_tools/src/lsp_log_tests.rs @@ -5,9 +5,8 @@ use crate::lsp_log::LogMenuItem; use super::*; use futures::StreamExt; use gpui::{Context, SemanticVersion, TestAppContext, VisualTestContext}; -use language::{ - tree_sitter_rust, FakeLspAdapter, Language, LanguageConfig, LanguageMatcher, LanguageServerName, -}; +use language::{tree_sitter_rust, FakeLspAdapter, Language, LanguageConfig, LanguageMatcher}; +use lsp::LanguageServerName; use lsp_log::LogKind; use project::{FakeFs, Project}; use serde_json::json; diff --git a/crates/languages/src/c.rs b/crates/languages/src/c.rs index 28a12b5310..a0e0f6dadb 100644 --- a/crates/languages/src/c.rs +++ b/crates/languages/src/c.rs @@ -4,7 +4,7 @@ use futures::StreamExt; use gpui::AsyncAppContext; use http_client::github::{latest_github_release, GitHubLspBinaryVersion}; pub use language::*; -use lsp::LanguageServerBinary; +use lsp::{LanguageServerBinary, LanguageServerName}; use smol::fs::{self, File}; use std::{any::Any, env::consts, path::PathBuf, sync::Arc}; use util::{fs::remove_matching, maybe, ResultExt}; diff --git a/crates/languages/src/css.rs b/crates/languages/src/css.rs index b4e5feaab7..536f339664 100644 --- a/crates/languages/src/css.rs +++ b/crates/languages/src/css.rs @@ -1,8 +1,8 @@ use anyhow::{anyhow, Result}; use async_trait::async_trait; use futures::StreamExt; -use language::{LanguageServerName, LspAdapter, LspAdapterDelegate}; -use lsp::LanguageServerBinary; +use language::{LspAdapter, LspAdapterDelegate}; +use lsp::{LanguageServerBinary, LanguageServerName}; use node_runtime::NodeRuntime; use serde_json::json; use smol::fs; diff --git a/crates/languages/src/go.rs b/crates/languages/src/go.rs index fb895ed753..7d44a0c128 100644 --- a/crates/languages/src/go.rs +++ b/crates/languages/src/go.rs @@ -5,7 +5,7 @@ use futures::StreamExt; use gpui::{AppContext, AsyncAppContext, Task}; use http_client::github::latest_github_release; pub use language::*; -use lsp::LanguageServerBinary; +use lsp::{LanguageServerBinary, LanguageServerName}; use regex::Regex; use serde_json::json; use smol::{fs, process}; diff --git a/crates/languages/src/json.rs b/crates/languages/src/json.rs index 924d397704..c0c7e6f453 100644 --- a/crates/languages/src/json.rs +++ b/crates/languages/src/json.rs @@ -6,10 +6,8 @@ use collections::HashMap; use futures::StreamExt; use gpui::{AppContext, AsyncAppContext}; use http_client::github::{latest_github_release, GitHubLspBinaryVersion}; -use language::{ - LanguageRegistry, LanguageServerName, LanguageToolchainStore, LspAdapter, LspAdapterDelegate, -}; -use lsp::LanguageServerBinary; +use language::{LanguageRegistry, LanguageToolchainStore, LspAdapter, LspAdapterDelegate}; +use lsp::{LanguageServerBinary, LanguageServerName}; use node_runtime::NodeRuntime; use project::ContextProviderWithTasks; use serde_json::{json, Value}; diff --git a/crates/languages/src/lib.rs b/crates/languages/src/lib.rs index 7bc9d5bd8c..77c8531f3e 100644 --- a/crates/languages/src/lib.rs +++ b/crates/languages/src/lib.rs @@ -2,6 +2,7 @@ use anyhow::Context; use gpui::{AppContext, UpdateGlobal}; use json::json_task_context; pub use language::*; +use lsp::LanguageServerName; use node_runtime::NodeRuntime; use python::{PythonContextProvider, PythonToolchainProvider}; use rust_embed::RustEmbed; diff --git a/crates/languages/src/python.rs b/crates/languages/src/python.rs index cad2e3483a..60b514d3af 100644 --- a/crates/languages/src/python.rs +++ b/crates/languages/src/python.rs @@ -8,8 +8,9 @@ use language::LanguageToolchainStore; use language::Toolchain; use language::ToolchainList; use language::ToolchainLister; -use language::{ContextProvider, LanguageServerName, LspAdapter, LspAdapterDelegate}; +use language::{ContextProvider, LspAdapter, LspAdapterDelegate}; use lsp::LanguageServerBinary; +use lsp::LanguageServerName; use node_runtime::NodeRuntime; use pet_core::os_environment::Environment; use pet_core::python_environment::PythonEnvironmentKind; diff --git a/crates/languages/src/rust.rs b/crates/languages/src/rust.rs index 1f040eb647..e6735ba96b 100644 --- a/crates/languages/src/rust.rs +++ b/crates/languages/src/rust.rs @@ -6,7 +6,7 @@ use futures::{io::BufReader, StreamExt}; use gpui::{AppContext, AsyncAppContext}; use http_client::github::{latest_github_release, GitHubLspBinaryVersion}; pub use language::*; -use lsp::LanguageServerBinary; +use lsp::{LanguageServerBinary, LanguageServerName}; use regex::Regex; use smol::fs::{self, File}; use std::{ diff --git a/crates/languages/src/tailwind.rs b/crates/languages/src/tailwind.rs index 6d4416c7d9..f1b5b87a2c 100644 --- a/crates/languages/src/tailwind.rs +++ b/crates/languages/src/tailwind.rs @@ -3,8 +3,8 @@ use async_trait::async_trait; use collections::HashMap; use futures::StreamExt; use gpui::AsyncAppContext; -use language::{LanguageServerName, LanguageToolchainStore, LspAdapter, LspAdapterDelegate}; -use lsp::LanguageServerBinary; +use language::{LanguageToolchainStore, LspAdapter, LspAdapterDelegate}; +use lsp::{LanguageServerBinary, LanguageServerName}; use node_runtime::NodeRuntime; use project::lsp_store::language_server_settings; use serde_json::{json, Value}; diff --git a/crates/languages/src/typescript.rs b/crates/languages/src/typescript.rs index 345a5f0694..ffce5f8274 100644 --- a/crates/languages/src/typescript.rs +++ b/crates/languages/src/typescript.rs @@ -5,8 +5,8 @@ use async_trait::async_trait; use collections::HashMap; use gpui::AsyncAppContext; use http_client::github::{build_asset_url, AssetKind, GitHubLspBinaryVersion}; -use language::{LanguageServerName, LanguageToolchainStore, LspAdapter, LspAdapterDelegate}; -use lsp::{CodeActionKind, LanguageServerBinary}; +use language::{LanguageToolchainStore, LspAdapter, LspAdapterDelegate}; +use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerName}; use node_runtime::NodeRuntime; use project::lsp_store::language_server_settings; use project::ContextProviderWithTasks; diff --git a/crates/languages/src/vtsls.rs b/crates/languages/src/vtsls.rs index 2d44d178e0..0ad9158003 100644 --- a/crates/languages/src/vtsls.rs +++ b/crates/languages/src/vtsls.rs @@ -2,8 +2,8 @@ use anyhow::{anyhow, Result}; use async_trait::async_trait; use collections::HashMap; use gpui::AsyncAppContext; -use language::{LanguageServerName, LanguageToolchainStore, LspAdapter, LspAdapterDelegate}; -use lsp::{CodeActionKind, LanguageServerBinary}; +use language::{LanguageToolchainStore, LspAdapter, LspAdapterDelegate}; +use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerName}; use node_runtime::NodeRuntime; use project::lsp_store::language_server_settings; use serde_json::Value; diff --git a/crates/languages/src/yaml.rs b/crates/languages/src/yaml.rs index d8f927b770..6d34d9816c 100644 --- a/crates/languages/src/yaml.rs +++ b/crates/languages/src/yaml.rs @@ -3,10 +3,9 @@ use async_trait::async_trait; use futures::StreamExt; use gpui::AsyncAppContext; use language::{ - language_settings::AllLanguageSettings, LanguageServerName, LanguageToolchainStore, LspAdapter, - LspAdapterDelegate, + language_settings::AllLanguageSettings, LanguageToolchainStore, LspAdapter, LspAdapterDelegate, }; -use lsp::LanguageServerBinary; +use lsp::{LanguageServerBinary, LanguageServerName}; use node_runtime::NodeRuntime; use project::lsp_store::language_server_settings; use serde_json::Value; diff --git a/crates/lsp/Cargo.toml b/crates/lsp/Cargo.toml index 0cd4a8837a..3460bf34dd 100644 --- a/crates/lsp/Cargo.toml +++ b/crates/lsp/Cargo.toml @@ -27,6 +27,7 @@ parking_lot.workspace = true postage.workspace = true serde.workspace = true serde_json.workspace = true +schemars.workspace = true smol.workspace = true util.workspace = true release_channel.workspace = true diff --git a/crates/lsp/src/lsp.rs b/crates/lsp/src/lsp.rs index df2ab35fc4..ca09ef4d1f 100644 --- a/crates/lsp/src/lsp.rs +++ b/crates/lsp/src/lsp.rs @@ -6,9 +6,14 @@ pub use lsp_types::*; use anyhow::{anyhow, Context, Result}; use collections::HashMap; use futures::{channel::oneshot, io::BufWriter, select, AsyncRead, AsyncWrite, Future, FutureExt}; -use gpui::{AppContext, AsyncAppContext, BackgroundExecutor, Task}; +use gpui::{AppContext, AsyncAppContext, BackgroundExecutor, SharedString, Task}; use parking_lot::{Mutex, RwLock}; use postage::{barrier, prelude::Stream}; +use schemars::{ + gen::SchemaGenerator, + schema::{InstanceType, Schema, SchemaObject}, + JsonSchema, +}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde_json::{json, value::RawValue, Value}; use smol::{ @@ -21,7 +26,7 @@ use smol::{ use smol::process::windows::CommandExt; use std::{ - ffi::OsString, + ffi::{OsStr, OsString}, fmt, io::Write, ops::DerefMut, @@ -78,7 +83,8 @@ pub struct LanguageServer { server_id: LanguageServerId, next_id: AtomicI32, outbound_tx: channel::Sender, - name: Arc, + name: LanguageServerName, + process_name: Arc, capabilities: RwLock, code_action_kinds: Option>, notification_handlers: Arc>>, @@ -108,6 +114,58 @@ impl LanguageServerId { } } +/// A name of a language server. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)] +pub struct LanguageServerName(pub SharedString); + +impl std::fmt::Display for LanguageServerName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(&self.0, f) + } +} + +impl AsRef for LanguageServerName { + fn as_ref(&self) -> &str { + self.0.as_ref() + } +} + +impl AsRef for LanguageServerName { + fn as_ref(&self) -> &OsStr { + self.0.as_ref().as_ref() + } +} + +impl JsonSchema for LanguageServerName { + fn schema_name() -> String { + "LanguageServerName".into() + } + + fn json_schema(_: &mut SchemaGenerator) -> Schema { + SchemaObject { + instance_type: Some(InstanceType::String.into()), + ..Default::default() + } + .into() + } +} + +impl LanguageServerName { + pub const fn new_static(s: &'static str) -> Self { + Self(SharedString::new_static(s)) + } + + pub fn from_proto(s: String) -> Self { + Self(s.into()) + } +} + +impl<'a> From<&'a str> for LanguageServerName { + fn from(str: &'a str) -> LanguageServerName { + LanguageServerName(str.to_string().into()) + } +} + /// Handle to a language server RPC activity subscription. pub enum Subscription { Notification { @@ -269,6 +327,7 @@ impl LanguageServer { pub fn new( stderr_capture: Arc>>, server_id: LanguageServerId, + server_name: LanguageServerName, binary: LanguageServerBinary, root_path: &Path, code_action_kinds: Option>, @@ -310,6 +369,7 @@ impl LanguageServer { let stderr = server.stderr.take().unwrap(); let mut server = Self::new_internal( server_id, + server_name, stdin, stdout, Some(stderr), @@ -330,7 +390,7 @@ impl LanguageServer { ); if let Some(name) = binary.path.file_name() { - server.name = name.to_string_lossy().into(); + server.process_name = name.to_string_lossy().into(); } Ok(server) @@ -339,6 +399,7 @@ impl LanguageServer { #[allow(clippy::too_many_arguments)] fn new_internal( server_id: LanguageServerId, + server_name: LanguageServerName, stdin: Stdin, stdout: Stdout, stderr: Option, @@ -408,7 +469,8 @@ impl LanguageServer { notification_handlers, response_handlers, io_handlers, - name: Arc::default(), + name: server_name, + process_name: Arc::default(), capabilities: Default::default(), code_action_kinds, next_id: Default::default(), @@ -725,7 +787,7 @@ impl LanguageServer { cx.spawn(|_| async move { let response = self.request::(params).await?; if let Some(info) = response.server_info { - self.name = info.name.into(); + self.process_name = info.name.into(); } self.capabilities = RwLock::new(response.capabilities); @@ -937,8 +999,12 @@ impl LanguageServer { } /// Get the name of the running language server. - pub fn name(&self) -> &str { - &self.name + pub fn name(&self) -> LanguageServerName { + self.name.clone() + } + + pub fn process_name(&self) -> &str { + &self.process_name } /// Get the reported capabilities of the running language server. @@ -1179,8 +1245,11 @@ impl FakeLanguageServer { let root = Self::root_path(); + let server_name = LanguageServerName(name.clone().into()); + let process_name = Arc::from(name.as_str()); let mut server = LanguageServer::new_internal( server_id, + server_name.clone(), stdin_writer, stdout_reader, None::, @@ -1192,12 +1261,13 @@ impl FakeLanguageServer { cx.clone(), |_| {}, ); - server.name = name.as_str().into(); + server.process_name = process_name; let fake = FakeLanguageServer { binary, server: Arc::new({ let mut server = LanguageServer::new_internal( server_id, + server_name, stdout_writer, stdin_reader, None::, @@ -1216,7 +1286,7 @@ impl FakeLanguageServer { .ok(); }, ); - server.name = name.as_str().into(); + server.process_name = name.as_str().into(); server }), notifications_rx, diff --git a/crates/prettier/src/prettier.rs b/crates/prettier/src/prettier.rs index d7b13c9992..3a3b88cba1 100644 --- a/crates/prettier/src/prettier.rs +++ b/crates/prettier/src/prettier.rs @@ -154,7 +154,7 @@ impl Prettier { node: NodeRuntime, cx: AsyncAppContext, ) -> anyhow::Result { - use lsp::LanguageServerBinary; + use lsp::{LanguageServerBinary, LanguageServerName}; let executor = cx.background_executor().clone(); anyhow::ensure!( @@ -170,14 +170,17 @@ impl Prettier { let node_path = executor .spawn(async move { node.binary_path().await }) .await?; + let server_name = LanguageServerName("prettier".into()); + let server_binary = LanguageServerBinary { + path: node_path, + arguments: vec![prettier_server.into(), prettier_dir.as_path().into()], + env: None, + }; let server = LanguageServer::new( Arc::new(parking_lot::Mutex::new(None)), server_id, - LanguageServerBinary { - path: node_path, - arguments: vec![prettier_server.into(), prettier_dir.as_path().into()], - env: None, - }, + server_name, + server_binary, &prettier_dir, None, cx.clone(), diff --git a/crates/project/src/lsp_store.rs b/crates/project/src/lsp_store.rs index 57c046e282..5f1f6a88ad 100644 --- a/crates/project/src/lsp_store.rs +++ b/crates/project/src/lsp_store.rs @@ -38,16 +38,17 @@ use language::{ proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version}, range_from_lsp, Bias, Buffer, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic, DiagnosticEntry, DiagnosticSet, Diff, Documentation, File as _, Language, LanguageName, - LanguageRegistry, LanguageServerBinaryStatus, LanguageServerName, LanguageToolchainStore, - LocalFile, LspAdapter, LspAdapterDelegate, Patch, PointUtf16, TextBufferSnapshot, ToOffset, - ToPointUtf16, Transaction, Unclipped, + LanguageRegistry, LanguageServerBinaryStatus, LanguageToolchainStore, LocalFile, LspAdapter, + LspAdapterDelegate, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Transaction, + Unclipped, }; use lsp::{ CodeActionKind, CompletionContext, DiagnosticSeverity, DiagnosticTag, DidChangeWatchedFilesRegistrationOptions, Edit, FileSystemWatcher, InsertTextFormat, LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, - LspRequestFuture, MessageActionItem, MessageType, OneOf, ServerHealthStatus, ServerStatus, - SymbolKind, TextEdit, Url, WorkDoneProgressCancelParams, WorkspaceFolder, + LanguageServerName, LspRequestFuture, MessageActionItem, MessageType, OneOf, + ServerHealthStatus, ServerStatus, SymbolKind, TextEdit, Url, WorkDoneProgressCancelParams, + WorkspaceFolder, }; use node_runtime::read_package_installed_version; use parking_lot::{Mutex, RwLock}; @@ -5598,6 +5599,7 @@ impl LspStore { let pending_server = cx.spawn({ let adapter = adapter.clone(); + let server_name = adapter.name.clone(); let stderr_capture = stderr_capture.clone(); move |_lsp_store, cx| async move { @@ -5608,7 +5610,7 @@ impl LspStore { .update(&mut cx.clone(), |this, cx| { this.languages.create_fake_language_server( server_id, - &adapter.name, + &server_name, binary.clone(), cx.to_async(), ) @@ -5622,6 +5624,7 @@ impl LspStore { lsp::LanguageServer::new( stderr_capture, server_id, + server_name, binary, &root_path, adapter.code_action_kinds(), @@ -6617,7 +6620,7 @@ impl LspStore { cx.emit(LspStoreEvent::LanguageServerAdded( server_id, - language_server.name().into(), + language_server.name(), Some(key.0), )); diff --git a/crates/project/src/prettier_store.rs b/crates/project/src/prettier_store.rs index b6c99e4a1e..c7ac0ffd0b 100644 --- a/crates/project/src/prettier_store.rs +++ b/crates/project/src/prettier_store.rs @@ -15,9 +15,9 @@ use futures::{ use gpui::{AsyncAppContext, EventEmitter, Model, ModelContext, Task, WeakModel}; use language::{ language_settings::{Formatter, LanguageSettings, SelectedFormatter}, - Buffer, LanguageRegistry, LanguageServerName, LocalFile, + Buffer, LanguageRegistry, LocalFile, }; -use lsp::{LanguageServer, LanguageServerId}; +use lsp::{LanguageServer, LanguageServerId, LanguageServerName}; use node_runtime::NodeRuntime; use paths::default_prettier_dir; use prettier::Prettier; diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 48c88d46ac..4d94622020 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -48,12 +48,12 @@ use itertools::Itertools; use language::{ language_settings::InlayHintKind, proto::split_operations, Buffer, BufferEvent, CachedLspAdapter, Capability, CodeLabel, DiagnosticEntry, Documentation, File as _, Language, - LanguageName, LanguageRegistry, LanguageServerName, PointUtf16, ToOffset, ToPointUtf16, - Toolchain, ToolchainList, Transaction, Unclipped, + LanguageName, LanguageRegistry, PointUtf16, ToOffset, ToPointUtf16, Toolchain, ToolchainList, + Transaction, Unclipped, }; use lsp::{ CompletionContext, CompletionItemKind, DocumentHighlightKind, LanguageServer, LanguageServerId, - MessageActionItem, + LanguageServerName, MessageActionItem, }; use lsp_command::*; use node_runtime::NodeRuntime; diff --git a/crates/project/src/project_settings.rs b/crates/project/src/project_settings.rs index 52594ce5b0..bd0d7cc884 100644 --- a/crates/project/src/project_settings.rs +++ b/crates/project/src/project_settings.rs @@ -2,7 +2,7 @@ use anyhow::Context; use collections::HashMap; use fs::Fs; use gpui::{AppContext, AsyncAppContext, BorrowAppContext, EventEmitter, Model, ModelContext}; -use language::LanguageServerName; +use lsp::LanguageServerName; use paths::{ local_settings_file_relative_path, local_tasks_file_relative_path, local_vscode_tasks_file_relative_path, EDITORCONFIG_NAME, diff --git a/crates/project/src/project_tests.rs b/crates/project/src/project_tests.rs index 49406b9715..2be927458c 100644 --- a/crates/project/src/project_tests.rs +++ b/crates/project/src/project_tests.rs @@ -1243,7 +1243,7 @@ async fn test_disk_based_diagnostics_progress(cx: &mut gpui::TestAppContext) { events.next().await.unwrap(), Event::LanguageServerAdded( LanguageServerId(0), - fake_server.server.name().into(), + fake_server.server.name(), Some(worktree_id) ), ); @@ -1378,7 +1378,7 @@ async fn test_restarting_server_with_diagnostics_running(cx: &mut gpui::TestAppC events.next().await.unwrap(), Event::LanguageServerAdded( LanguageServerId(1), - fake_server.server.name().into(), + fake_server.server.name(), Some(worktree_id) ) ); @@ -4865,11 +4865,10 @@ async fn test_multiple_language_server_hovers(cx: &mut gpui::TestAppContext) { }); let new_server_name = new_server.server.name(); assert!( - !servers_with_hover_requests.contains_key(new_server_name), + !servers_with_hover_requests.contains_key(&new_server_name), "Unexpected: initialized server with the same name twice. Name: `{new_server_name}`" ); - let new_server_name = new_server_name.to_string(); - match new_server_name.as_str() { + match new_server_name.as_ref() { "TailwindServer" | "TypeScriptServer" => { servers_with_hover_requests.insert( new_server_name.clone(), @@ -5089,11 +5088,10 @@ async fn test_multiple_language_server_actions(cx: &mut gpui::TestAppContext) { let new_server_name = new_server.server.name(); assert!( - !servers_with_actions_requests.contains_key(new_server_name), + !servers_with_actions_requests.contains_key(&new_server_name), "Unexpected: initialized server with the same name twice. Name: `{new_server_name}`" ); - let new_server_name = new_server_name.to_string(); - match new_server_name.as_str() { + match new_server_name.0.as_ref() { "TailwindServer" | "TypeScriptServer" => { servers_with_actions_requests.insert( new_server_name.clone(), diff --git a/crates/remote_server/src/remote_editing_tests.rs b/crates/remote_server/src/remote_editing_tests.rs index 0ced691939..e3914c7ae1 100644 --- a/crates/remote_server/src/remote_editing_tests.rs +++ b/crates/remote_server/src/remote_editing_tests.rs @@ -6,10 +6,9 @@ use gpui::{Context, Model, SemanticVersion, TestAppContext}; use http_client::{BlockedHttpClient, FakeHttpClient}; use language::{ language_settings::{language_settings, AllLanguageSettings}, - Buffer, FakeLspAdapter, LanguageConfig, LanguageMatcher, LanguageRegistry, LanguageServerName, - LineEnding, + Buffer, FakeLspAdapter, LanguageConfig, LanguageMatcher, LanguageRegistry, LineEnding, }; -use lsp::{CompletionContext, CompletionResponse, CompletionTriggerKind}; +use lsp::{CompletionContext, CompletionResponse, CompletionTriggerKind, LanguageServerName}; use node_runtime::NodeRuntime; use project::{ search::{SearchQuery, SearchResult},