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 <hello@samwho.dev>
Co-authored-by: Bennet <bennet@zed.dev>
This commit is contained in:
Thorsten Ball 2024-11-11 10:18:38 +01:00 committed by GitHub
parent f4024cc602
commit a97ab5eb3d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
39 changed files with 172 additions and 151 deletions

2
Cargo.lock generated
View file

@ -13,6 +13,7 @@ dependencies = [
"futures 0.3.30", "futures 0.3.30",
"gpui", "gpui",
"language", "language",
"lsp",
"project", "project",
"smallvec", "smallvec",
"ui", "ui",
@ -6898,6 +6899,7 @@ dependencies = [
"parking_lot", "parking_lot",
"postage", "postage",
"release_channel", "release_channel",
"schemars",
"serde", "serde",
"serde_json", "serde_json",
"smol", "smol",

View file

@ -20,6 +20,7 @@ extension_host.workspace = true
futures.workspace = true futures.workspace = true
gpui.workspace = true gpui.workspace = true
language.workspace = true language.workspace = true
lsp.workspace = true
project.workspace = true project.workspace = true
smallvec.workspace = true smallvec.workspace = true
ui.workspace = true ui.workspace = true

View file

@ -7,9 +7,8 @@ use gpui::{
InteractiveElement as _, Model, ParentElement as _, Render, SharedString, InteractiveElement as _, Model, ParentElement as _, Render, SharedString,
StatefulInteractiveElement, Styled, Transformation, View, ViewContext, VisualContext as _, StatefulInteractiveElement, Styled, Transformation, View, ViewContext, VisualContext as _,
}; };
use language::{ use language::{LanguageRegistry, LanguageServerBinaryStatus, LanguageServerId};
LanguageRegistry, LanguageServerBinaryStatus, LanguageServerId, LanguageServerName, use lsp::LanguageServerName;
};
use project::{EnvironmentErrorMessage, LanguageServerProgress, Project, WorktreeId}; use project::{EnvironmentErrorMessage, LanguageServerProgress, Project, WorktreeId};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{cmp::Reverse, fmt::Write, sync::Arc, time::Duration}; use std::{cmp::Reverse, fmt::Write, sync::Arc, time::Duration};

View file

@ -5130,11 +5130,10 @@ async fn test_lsp_hover(
}); });
let new_server_name = new_server.server.name(); let new_server_name = new_server.server.name();
assert!( 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}`" "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_ref() {
match new_server_name.as_str() {
"CrabLang-ls" => { "CrabLang-ls" => {
servers_with_hover_requests.insert( servers_with_hover_requests.insert(
new_server_name.clone(), new_server_name.clone(),

View file

@ -21,7 +21,7 @@ use language::{
point_from_lsp, point_to_lsp, Anchor, Bias, Buffer, BufferSnapshot, Language, PointUtf16, point_from_lsp, point_to_lsp, Anchor, Bias, Buffer, BufferSnapshot, Language, PointUtf16,
ToPointUtf16, ToPointUtf16,
}; };
use lsp::{LanguageServer, LanguageServerBinary, LanguageServerId}; use lsp::{LanguageServer, LanguageServerBinary, LanguageServerId, LanguageServerName};
use node_runtime::NodeRuntime; use node_runtime::NodeRuntime;
use parking_lot::Mutex; use parking_lot::Mutex;
use request::StatusNotification; use request::StatusNotification;
@ -446,9 +446,11 @@ impl Copilot {
Path::new("/") Path::new("/")
}; };
let server_name = LanguageServerName("copilot".into());
let server = LanguageServer::new( let server = LanguageServer::new(
Arc::new(Mutex::new(None)), Arc::new(Mutex::new(None)),
new_server_id, new_server_id,
server_name,
binary, binary,
root_path, root_path,
None, None,

View file

@ -96,9 +96,7 @@ use language::{
CursorShape, Diagnostic, Documentation, IndentKind, IndentSize, Language, OffsetRangeExt, CursorShape, Diagnostic, Documentation, IndentKind, IndentSize, Language, OffsetRangeExt,
Point, Selection, SelectionGoal, TransactionId, Point, Selection, SelectionGoal, TransactionId,
}; };
use language::{ use language::{point_to_lsp, BufferRow, CharClassifier, Runnable, RunnableRange};
point_to_lsp, BufferRow, CharClassifier, LanguageServerName, Runnable, RunnableRange,
};
use linked_editing_ranges::refresh_linked_ranges; use linked_editing_ranges::refresh_linked_ranges;
pub use proposed_changes_editor::{ pub use proposed_changes_editor::{
ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar, ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
@ -111,7 +109,7 @@ use hover_links::{find_file, HoverLink, HoveredLinkState, InlayHighlight};
pub use lsp::CompletionContext; pub use lsp::CompletionContext;
use lsp::{ use lsp::{
CompletionItemKind, CompletionTriggerKind, DiagnosticSeverity, InsertTextFormat, CompletionItemKind, CompletionTriggerKind, DiagnosticSeverity, InsertTextFormat,
LanguageServerId, LanguageServerId, LanguageServerName,
}; };
use mouse_context_menu::MouseContextMenu; use mouse_context_menu::MouseContextMenu;
use movement::TextLayoutDetails; use movement::TextLayoutDetails;

View file

@ -1,7 +1,8 @@
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use collections::{BTreeMap, HashMap}; use collections::{BTreeMap, HashMap};
use fs::Fs; use fs::Fs;
use language::{LanguageName, LanguageServerName}; use language::LanguageName;
use lsp::LanguageServerName;
use semantic_version::SemanticVersion; use semantic_version::SemanticVersion;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ use std::{

View file

@ -28,6 +28,7 @@ use language::{
LanguageConfig, LanguageMatcher, LanguageName, LanguageQueries, LoadedLanguage, LanguageConfig, LanguageMatcher, LanguageName, LanguageQueries, LoadedLanguage,
QUERY_FILENAME_PREFIXES, QUERY_FILENAME_PREFIXES,
}; };
use lsp::LanguageServerName;
use node_runtime::NodeRuntime; use node_runtime::NodeRuntime;
use project::ContextProviderWithTasks; use project::ContextProviderWithTasks;
use release_channel::ReleaseChannel; use release_channel::ReleaseChannel;
@ -121,12 +122,7 @@ pub trait ExtensionRegistrationHooks: Send + Sync + 'static {
fn register_lsp_adapter(&self, _language: LanguageName, _adapter: ExtensionLspAdapter) {} fn register_lsp_adapter(&self, _language: LanguageName, _adapter: ExtensionLspAdapter) {}
fn remove_lsp_adapter( fn remove_lsp_adapter(&self, _language: &LanguageName, _server_name: &LanguageServerName) {}
&self,
_language: &LanguageName,
_server_name: &language::LanguageServerName,
) {
}
fn register_wasm_grammars(&self, _grammars: Vec<(Arc<str>, PathBuf)>) {} fn register_wasm_grammars(&self, _grammars: Vec<(Arc<str>, PathBuf)>) {}
@ -167,7 +163,7 @@ pub trait ExtensionRegistrationHooks: Send + Sync + 'static {
fn update_lsp_status( fn update_lsp_status(
&self, &self,
_server_name: language::LanguageServerName, _server_name: lsp::LanguageServerName,
_status: language::LanguageServerBinaryStatus, _status: language::LanguageServerBinaryStatus,
) { ) {
} }

View file

@ -8,10 +8,9 @@ use collections::HashMap;
use futures::{Future, FutureExt}; use futures::{Future, FutureExt};
use gpui::AsyncAppContext; use gpui::AsyncAppContext;
use language::{ use language::{
CodeLabel, HighlightId, Language, LanguageServerName, LanguageToolchainStore, LspAdapter, CodeLabel, HighlightId, Language, LanguageToolchainStore, LspAdapter, LspAdapterDelegate,
LspAdapterDelegate,
}; };
use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions}; use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerName};
use serde::Serialize; use serde::Serialize;
use serde_json::Value; use serde_json::Value;
use std::ops::Range; use std::ops::Range;

View file

@ -3,6 +3,7 @@ mod since_v0_0_4;
mod since_v0_0_6; mod since_v0_0_6;
mod since_v0_1_0; mod since_v0_1_0;
mod since_v0_2_0; mod since_v0_2_0;
use lsp::LanguageServerName;
// use indexed_docs::IndexedDocsDatabase; // use indexed_docs::IndexedDocsDatabase;
use release_channel::ReleaseChannel; use release_channel::ReleaseChannel;
use since_v0_2_0 as latest; use since_v0_2_0 as latest;
@ -11,7 +12,7 @@ use crate::DocsDatabase;
use super::{wasm_engine, WasmState}; use super::{wasm_engine, WasmState};
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use language::{LanguageServerName, LspAdapterDelegate}; use language::LspAdapterDelegate;
use semantic_version::SemanticVersion; use semantic_version::SemanticVersion;
use std::{ops::RangeInclusive, sync::Arc}; use std::{ops::RangeInclusive, sync::Arc};
use wasmtime::{ use wasmtime::{

View file

@ -149,7 +149,7 @@ impl ExtensionImports for WasmState {
self.host self.host
.registration_hooks .registration_hooks
.update_lsp_status(language::LanguageServerName(server_name.into()), status); .update_lsp_status(lsp::LanguageServerName(server_name.into()), status);
Ok(()) Ok(())
} }

View file

@ -8,10 +8,10 @@ use async_tar::Archive;
use async_trait::async_trait; use async_trait::async_trait;
use futures::{io::BufReader, FutureExt as _}; use futures::{io::BufReader, FutureExt as _};
use futures::{lock::Mutex, AsyncReadExt}; use futures::{lock::Mutex, AsyncReadExt};
use language::LanguageName;
use language::{ use language::{
language_settings::AllLanguageSettings, LanguageServerBinaryStatus, LspAdapterDelegate, language_settings::AllLanguageSettings, LanguageServerBinaryStatus, LspAdapterDelegate,
}; };
use language::{LanguageName, LanguageServerName};
use project::project_settings::ProjectSettings; use project::project_settings::ProjectSettings;
use semantic_version::SemanticVersion; use semantic_version::SemanticVersion;
use std::{ use std::{
@ -469,7 +469,7 @@ impl ExtensionImports for WasmState {
.and_then(|key| { .and_then(|key| {
ProjectSettings::get(location, cx) ProjectSettings::get(location, cx)
.lsp .lsp
.get(&LanguageServerName(key.into())) .get(&::lsp::LanguageServerName(key.into()))
}) })
.cloned() .cloned()
.unwrap_or_default(); .unwrap_or_default();
@ -513,7 +513,7 @@ impl ExtensionImports for WasmState {
self.host self.host
.registration_hooks .registration_hooks
.update_lsp_status(language::LanguageServerName(server_name.into()), status); .update_lsp_status(::lsp::LanguageServerName(server_name.into()), status);
Ok(()) Ok(())
} }

View file

@ -9,9 +9,9 @@ use async_trait::async_trait;
use futures::{io::BufReader, FutureExt as _}; use futures::{io::BufReader, FutureExt as _};
use futures::{lock::Mutex, AsyncReadExt}; use futures::{lock::Mutex, AsyncReadExt};
use language::{ use language::{
language_settings::AllLanguageSettings, LanguageServerBinaryStatus, LspAdapterDelegate, language_settings::AllLanguageSettings, LanguageName, LanguageServerBinaryStatus,
LspAdapterDelegate,
}; };
use language::{LanguageName, LanguageServerName};
use project::project_settings::ProjectSettings; use project::project_settings::ProjectSettings;
use semantic_version::SemanticVersion; use semantic_version::SemanticVersion;
use std::{ use std::{
@ -416,7 +416,7 @@ impl ExtensionImports for WasmState {
.and_then(|key| { .and_then(|key| {
ProjectSettings::get(location, cx) ProjectSettings::get(location, cx)
.lsp .lsp
.get(&LanguageServerName::from_proto(key)) .get(&::lsp::LanguageServerName::from_proto(key))
}) })
.cloned() .cloned()
.unwrap_or_default(); .unwrap_or_default();
@ -460,7 +460,7 @@ impl ExtensionImports for WasmState {
self.host self.host
.registration_hooks .registration_hooks
.update_lsp_status(language::LanguageServerName(server_name.into()), status); .update_lsp_status(::lsp::LanguageServerName(server_name.into()), status);
Ok(()) Ok(())
} }

View file

@ -30,6 +30,7 @@ fuzzy.workspace = true
gpui.workspace = true gpui.workspace = true
indexed_docs.workspace = true indexed_docs.workspace = true
language.workspace = true language.workspace = true
lsp.workspace = true
num-format.workspace = true num-format.workspace = true
picker.workspace = true picker.workspace = true
project.workspace = true project.workspace = true

View file

@ -121,7 +121,7 @@ impl extension_host::ExtensionRegistrationHooks for ConcreteExtensionRegistratio
fn update_lsp_status( fn update_lsp_status(
&self, &self,
server_name: language::LanguageServerName, server_name: lsp::LanguageServerName,
status: LanguageServerBinaryStatus, status: LanguageServerBinaryStatus,
) { ) {
self.language_registry self.language_registry
@ -140,7 +140,7 @@ impl extension_host::ExtensionRegistrationHooks for ConcreteExtensionRegistratio
fn remove_lsp_adapter( fn remove_lsp_adapter(
&self, &self,
language_name: &language::LanguageName, language_name: &language::LanguageName,
server_name: &language::LanguageServerName, server_name: &lsp::LanguageServerName,
) { ) {
self.language_registry self.language_registry
.remove_lsp_adapter(language_name, server_name); .remove_lsp_adapter(language_name, server_name);

View file

@ -14,7 +14,8 @@ use futures::{io::BufReader, AsyncReadExt, StreamExt};
use gpui::{Context, SemanticVersion, TestAppContext}; use gpui::{Context, SemanticVersion, TestAppContext};
use http_client::{FakeHttpClient, Response}; use http_client::{FakeHttpClient, Response};
use indexed_docs::IndexedDocsRegistry; use indexed_docs::IndexedDocsRegistry;
use language::{LanguageMatcher, LanguageRegistry, LanguageServerBinaryStatus, LanguageServerName}; use language::{LanguageMatcher, LanguageRegistry, LanguageServerBinaryStatus};
use lsp::LanguageServerName;
use node_runtime::NodeRuntime; use node_runtime::NodeRuntime;
use parking_lot::Mutex; use parking_lot::Mutex;
use project::{Project, DEFAULT_COMPLETION_CONTEXT}; use project::{Project, DEFAULT_COMPLETION_CONTEXT};

View file

@ -30,7 +30,7 @@ use gpui::{AppContext, AsyncAppContext, Model, SharedString, Task};
pub use highlight_map::HighlightMap; pub use highlight_map::HighlightMap;
use http_client::HttpClient; use http_client::HttpClient;
pub use language_registry::{LanguageName, LoadedLanguage}; pub use language_registry::{LanguageName, LoadedLanguage};
use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions}; use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerName};
use parking_lot::Mutex; use parking_lot::Mutex;
use regex::Regex; use regex::Regex;
use schemars::{ use schemars::{
@ -139,57 +139,6 @@ pub trait ToLspPosition {
fn to_lsp_position(self) -> lsp::Position; 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<str> for LanguageServerName {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
impl AsRef<OsStr> 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)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Location { pub struct Location {
pub buffer: Model<Buffer>, pub buffer: Model<Buffer>,

View file

@ -7,10 +7,10 @@ use gpui::{
IntoElement, Model, ModelContext, ParentElement, Render, Styled, Subscription, View, IntoElement, Model, ModelContext, ParentElement, Render, Styled, Subscription, View,
ViewContext, VisualContext, WeakModel, WindowContext, ViewContext, VisualContext, WeakModel, WindowContext,
}; };
use language::{LanguageServerId, LanguageServerName}; use language::LanguageServerId;
use lsp::{ use lsp::{
notification::SetTrace, IoKind, LanguageServer, MessageType, ServerCapabilities, notification::SetTrace, IoKind, LanguageServer, LanguageServerName, MessageType,
SetTraceParams, TraceValue, ServerCapabilities, SetTraceParams, TraceValue,
}; };
use project::{search::SearchQuery, Project, WorktreeId}; use project::{search::SearchQuery, Project, WorktreeId};
use std::{borrow::Cow, sync::Arc}; use std::{borrow::Cow, sync::Arc};

View file

@ -5,9 +5,8 @@ use crate::lsp_log::LogMenuItem;
use super::*; use super::*;
use futures::StreamExt; use futures::StreamExt;
use gpui::{Context, SemanticVersion, TestAppContext, VisualTestContext}; use gpui::{Context, SemanticVersion, TestAppContext, VisualTestContext};
use language::{ use language::{tree_sitter_rust, FakeLspAdapter, Language, LanguageConfig, LanguageMatcher};
tree_sitter_rust, FakeLspAdapter, Language, LanguageConfig, LanguageMatcher, LanguageServerName, use lsp::LanguageServerName;
};
use lsp_log::LogKind; use lsp_log::LogKind;
use project::{FakeFs, Project}; use project::{FakeFs, Project};
use serde_json::json; use serde_json::json;

View file

@ -4,7 +4,7 @@ use futures::StreamExt;
use gpui::AsyncAppContext; use gpui::AsyncAppContext;
use http_client::github::{latest_github_release, GitHubLspBinaryVersion}; use http_client::github::{latest_github_release, GitHubLspBinaryVersion};
pub use language::*; pub use language::*;
use lsp::LanguageServerBinary; use lsp::{LanguageServerBinary, LanguageServerName};
use smol::fs::{self, File}; use smol::fs::{self, File};
use std::{any::Any, env::consts, path::PathBuf, sync::Arc}; use std::{any::Any, env::consts, path::PathBuf, sync::Arc};
use util::{fs::remove_matching, maybe, ResultExt}; use util::{fs::remove_matching, maybe, ResultExt};

View file

@ -1,8 +1,8 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use async_trait::async_trait; use async_trait::async_trait;
use futures::StreamExt; use futures::StreamExt;
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate}; use language::{LspAdapter, LspAdapterDelegate};
use lsp::LanguageServerBinary; use lsp::{LanguageServerBinary, LanguageServerName};
use node_runtime::NodeRuntime; use node_runtime::NodeRuntime;
use serde_json::json; use serde_json::json;
use smol::fs; use smol::fs;

View file

@ -5,7 +5,7 @@ use futures::StreamExt;
use gpui::{AppContext, AsyncAppContext, Task}; use gpui::{AppContext, AsyncAppContext, Task};
use http_client::github::latest_github_release; use http_client::github::latest_github_release;
pub use language::*; pub use language::*;
use lsp::LanguageServerBinary; use lsp::{LanguageServerBinary, LanguageServerName};
use regex::Regex; use regex::Regex;
use serde_json::json; use serde_json::json;
use smol::{fs, process}; use smol::{fs, process};

View file

@ -6,10 +6,8 @@ use collections::HashMap;
use futures::StreamExt; use futures::StreamExt;
use gpui::{AppContext, AsyncAppContext}; use gpui::{AppContext, AsyncAppContext};
use http_client::github::{latest_github_release, GitHubLspBinaryVersion}; use http_client::github::{latest_github_release, GitHubLspBinaryVersion};
use language::{ use language::{LanguageRegistry, LanguageToolchainStore, LspAdapter, LspAdapterDelegate};
LanguageRegistry, LanguageServerName, LanguageToolchainStore, LspAdapter, LspAdapterDelegate, use lsp::{LanguageServerBinary, LanguageServerName};
};
use lsp::LanguageServerBinary;
use node_runtime::NodeRuntime; use node_runtime::NodeRuntime;
use project::ContextProviderWithTasks; use project::ContextProviderWithTasks;
use serde_json::{json, Value}; use serde_json::{json, Value};

View file

@ -2,6 +2,7 @@ use anyhow::Context;
use gpui::{AppContext, UpdateGlobal}; use gpui::{AppContext, UpdateGlobal};
use json::json_task_context; use json::json_task_context;
pub use language::*; pub use language::*;
use lsp::LanguageServerName;
use node_runtime::NodeRuntime; use node_runtime::NodeRuntime;
use python::{PythonContextProvider, PythonToolchainProvider}; use python::{PythonContextProvider, PythonToolchainProvider};
use rust_embed::RustEmbed; use rust_embed::RustEmbed;

View file

@ -8,8 +8,9 @@ use language::LanguageToolchainStore;
use language::Toolchain; use language::Toolchain;
use language::ToolchainList; use language::ToolchainList;
use language::ToolchainLister; use language::ToolchainLister;
use language::{ContextProvider, LanguageServerName, LspAdapter, LspAdapterDelegate}; use language::{ContextProvider, LspAdapter, LspAdapterDelegate};
use lsp::LanguageServerBinary; use lsp::LanguageServerBinary;
use lsp::LanguageServerName;
use node_runtime::NodeRuntime; use node_runtime::NodeRuntime;
use pet_core::os_environment::Environment; use pet_core::os_environment::Environment;
use pet_core::python_environment::PythonEnvironmentKind; use pet_core::python_environment::PythonEnvironmentKind;

View file

@ -6,7 +6,7 @@ use futures::{io::BufReader, StreamExt};
use gpui::{AppContext, AsyncAppContext}; use gpui::{AppContext, AsyncAppContext};
use http_client::github::{latest_github_release, GitHubLspBinaryVersion}; use http_client::github::{latest_github_release, GitHubLspBinaryVersion};
pub use language::*; pub use language::*;
use lsp::LanguageServerBinary; use lsp::{LanguageServerBinary, LanguageServerName};
use regex::Regex; use regex::Regex;
use smol::fs::{self, File}; use smol::fs::{self, File};
use std::{ use std::{

View file

@ -3,8 +3,8 @@ use async_trait::async_trait;
use collections::HashMap; use collections::HashMap;
use futures::StreamExt; use futures::StreamExt;
use gpui::AsyncAppContext; use gpui::AsyncAppContext;
use language::{LanguageServerName, LanguageToolchainStore, LspAdapter, LspAdapterDelegate}; use language::{LanguageToolchainStore, LspAdapter, LspAdapterDelegate};
use lsp::LanguageServerBinary; use lsp::{LanguageServerBinary, LanguageServerName};
use node_runtime::NodeRuntime; use node_runtime::NodeRuntime;
use project::lsp_store::language_server_settings; use project::lsp_store::language_server_settings;
use serde_json::{json, Value}; use serde_json::{json, Value};

View file

@ -5,8 +5,8 @@ use async_trait::async_trait;
use collections::HashMap; use collections::HashMap;
use gpui::AsyncAppContext; use gpui::AsyncAppContext;
use http_client::github::{build_asset_url, AssetKind, GitHubLspBinaryVersion}; use http_client::github::{build_asset_url, AssetKind, GitHubLspBinaryVersion};
use language::{LanguageServerName, LanguageToolchainStore, LspAdapter, LspAdapterDelegate}; use language::{LanguageToolchainStore, LspAdapter, LspAdapterDelegate};
use lsp::{CodeActionKind, LanguageServerBinary}; use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerName};
use node_runtime::NodeRuntime; use node_runtime::NodeRuntime;
use project::lsp_store::language_server_settings; use project::lsp_store::language_server_settings;
use project::ContextProviderWithTasks; use project::ContextProviderWithTasks;

View file

@ -2,8 +2,8 @@ use anyhow::{anyhow, Result};
use async_trait::async_trait; use async_trait::async_trait;
use collections::HashMap; use collections::HashMap;
use gpui::AsyncAppContext; use gpui::AsyncAppContext;
use language::{LanguageServerName, LanguageToolchainStore, LspAdapter, LspAdapterDelegate}; use language::{LanguageToolchainStore, LspAdapter, LspAdapterDelegate};
use lsp::{CodeActionKind, LanguageServerBinary}; use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerName};
use node_runtime::NodeRuntime; use node_runtime::NodeRuntime;
use project::lsp_store::language_server_settings; use project::lsp_store::language_server_settings;
use serde_json::Value; use serde_json::Value;

View file

@ -3,10 +3,9 @@ use async_trait::async_trait;
use futures::StreamExt; use futures::StreamExt;
use gpui::AsyncAppContext; use gpui::AsyncAppContext;
use language::{ use language::{
language_settings::AllLanguageSettings, LanguageServerName, LanguageToolchainStore, LspAdapter, language_settings::AllLanguageSettings, LanguageToolchainStore, LspAdapter, LspAdapterDelegate,
LspAdapterDelegate,
}; };
use lsp::LanguageServerBinary; use lsp::{LanguageServerBinary, LanguageServerName};
use node_runtime::NodeRuntime; use node_runtime::NodeRuntime;
use project::lsp_store::language_server_settings; use project::lsp_store::language_server_settings;
use serde_json::Value; use serde_json::Value;

View file

@ -27,6 +27,7 @@ parking_lot.workspace = true
postage.workspace = true postage.workspace = true
serde.workspace = true serde.workspace = true
serde_json.workspace = true serde_json.workspace = true
schemars.workspace = true
smol.workspace = true smol.workspace = true
util.workspace = true util.workspace = true
release_channel.workspace = true release_channel.workspace = true

View file

@ -6,9 +6,14 @@ pub use lsp_types::*;
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use collections::HashMap; use collections::HashMap;
use futures::{channel::oneshot, io::BufWriter, select, AsyncRead, AsyncWrite, Future, FutureExt}; 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 parking_lot::{Mutex, RwLock};
use postage::{barrier, prelude::Stream}; use postage::{barrier, prelude::Stream};
use schemars::{
gen::SchemaGenerator,
schema::{InstanceType, Schema, SchemaObject},
JsonSchema,
};
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_json::{json, value::RawValue, Value}; use serde_json::{json, value::RawValue, Value};
use smol::{ use smol::{
@ -21,7 +26,7 @@ use smol::{
use smol::process::windows::CommandExt; use smol::process::windows::CommandExt;
use std::{ use std::{
ffi::OsString, ffi::{OsStr, OsString},
fmt, fmt,
io::Write, io::Write,
ops::DerefMut, ops::DerefMut,
@ -78,7 +83,8 @@ pub struct LanguageServer {
server_id: LanguageServerId, server_id: LanguageServerId,
next_id: AtomicI32, next_id: AtomicI32,
outbound_tx: channel::Sender<String>, outbound_tx: channel::Sender<String>,
name: Arc<str>, name: LanguageServerName,
process_name: Arc<str>,
capabilities: RwLock<ServerCapabilities>, capabilities: RwLock<ServerCapabilities>,
code_action_kinds: Option<Vec<CodeActionKind>>, code_action_kinds: Option<Vec<CodeActionKind>>,
notification_handlers: Arc<Mutex<HashMap<&'static str, NotificationHandler>>>, notification_handlers: Arc<Mutex<HashMap<&'static str, NotificationHandler>>>,
@ -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<str> for LanguageServerName {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
impl AsRef<OsStr> 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. /// Handle to a language server RPC activity subscription.
pub enum Subscription { pub enum Subscription {
Notification { Notification {
@ -269,6 +327,7 @@ impl LanguageServer {
pub fn new( pub fn new(
stderr_capture: Arc<Mutex<Option<String>>>, stderr_capture: Arc<Mutex<Option<String>>>,
server_id: LanguageServerId, server_id: LanguageServerId,
server_name: LanguageServerName,
binary: LanguageServerBinary, binary: LanguageServerBinary,
root_path: &Path, root_path: &Path,
code_action_kinds: Option<Vec<CodeActionKind>>, code_action_kinds: Option<Vec<CodeActionKind>>,
@ -310,6 +369,7 @@ impl LanguageServer {
let stderr = server.stderr.take().unwrap(); let stderr = server.stderr.take().unwrap();
let mut server = Self::new_internal( let mut server = Self::new_internal(
server_id, server_id,
server_name,
stdin, stdin,
stdout, stdout,
Some(stderr), Some(stderr),
@ -330,7 +390,7 @@ impl LanguageServer {
); );
if let Some(name) = binary.path.file_name() { 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) Ok(server)
@ -339,6 +399,7 @@ impl LanguageServer {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn new_internal<Stdin, Stdout, Stderr, F>( fn new_internal<Stdin, Stdout, Stderr, F>(
server_id: LanguageServerId, server_id: LanguageServerId,
server_name: LanguageServerName,
stdin: Stdin, stdin: Stdin,
stdout: Stdout, stdout: Stdout,
stderr: Option<Stderr>, stderr: Option<Stderr>,
@ -408,7 +469,8 @@ impl LanguageServer {
notification_handlers, notification_handlers,
response_handlers, response_handlers,
io_handlers, io_handlers,
name: Arc::default(), name: server_name,
process_name: Arc::default(),
capabilities: Default::default(), capabilities: Default::default(),
code_action_kinds, code_action_kinds,
next_id: Default::default(), next_id: Default::default(),
@ -725,7 +787,7 @@ impl LanguageServer {
cx.spawn(|_| async move { cx.spawn(|_| async move {
let response = self.request::<request::Initialize>(params).await?; let response = self.request::<request::Initialize>(params).await?;
if let Some(info) = response.server_info { if let Some(info) = response.server_info {
self.name = info.name.into(); self.process_name = info.name.into();
} }
self.capabilities = RwLock::new(response.capabilities); self.capabilities = RwLock::new(response.capabilities);
@ -937,8 +999,12 @@ impl LanguageServer {
} }
/// Get the name of the running language server. /// Get the name of the running language server.
pub fn name(&self) -> &str { pub fn name(&self) -> LanguageServerName {
&self.name self.name.clone()
}
pub fn process_name(&self) -> &str {
&self.process_name
} }
/// Get the reported capabilities of the running language server. /// Get the reported capabilities of the running language server.
@ -1179,8 +1245,11 @@ impl FakeLanguageServer {
let root = Self::root_path(); 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( let mut server = LanguageServer::new_internal(
server_id, server_id,
server_name.clone(),
stdin_writer, stdin_writer,
stdout_reader, stdout_reader,
None::<async_pipe::PipeReader>, None::<async_pipe::PipeReader>,
@ -1192,12 +1261,13 @@ impl FakeLanguageServer {
cx.clone(), cx.clone(),
|_| {}, |_| {},
); );
server.name = name.as_str().into(); server.process_name = process_name;
let fake = FakeLanguageServer { let fake = FakeLanguageServer {
binary, binary,
server: Arc::new({ server: Arc::new({
let mut server = LanguageServer::new_internal( let mut server = LanguageServer::new_internal(
server_id, server_id,
server_name,
stdout_writer, stdout_writer,
stdin_reader, stdin_reader,
None::<async_pipe::PipeReader>, None::<async_pipe::PipeReader>,
@ -1216,7 +1286,7 @@ impl FakeLanguageServer {
.ok(); .ok();
}, },
); );
server.name = name.as_str().into(); server.process_name = name.as_str().into();
server server
}), }),
notifications_rx, notifications_rx,

View file

@ -154,7 +154,7 @@ impl Prettier {
node: NodeRuntime, node: NodeRuntime,
cx: AsyncAppContext, cx: AsyncAppContext,
) -> anyhow::Result<Self> { ) -> anyhow::Result<Self> {
use lsp::LanguageServerBinary; use lsp::{LanguageServerBinary, LanguageServerName};
let executor = cx.background_executor().clone(); let executor = cx.background_executor().clone();
anyhow::ensure!( anyhow::ensure!(
@ -170,14 +170,17 @@ impl Prettier {
let node_path = executor let node_path = executor
.spawn(async move { node.binary_path().await }) .spawn(async move { node.binary_path().await })
.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( let server = LanguageServer::new(
Arc::new(parking_lot::Mutex::new(None)), Arc::new(parking_lot::Mutex::new(None)),
server_id, server_id,
LanguageServerBinary { server_name,
path: node_path, server_binary,
arguments: vec![prettier_server.into(), prettier_dir.as_path().into()],
env: None,
},
&prettier_dir, &prettier_dir,
None, None,
cx.clone(), cx.clone(),

View file

@ -38,16 +38,17 @@ use language::{
proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version}, proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
range_from_lsp, Bias, Buffer, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic, range_from_lsp, Bias, Buffer, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
DiagnosticEntry, DiagnosticSet, Diff, Documentation, File as _, Language, LanguageName, DiagnosticEntry, DiagnosticSet, Diff, Documentation, File as _, Language, LanguageName,
LanguageRegistry, LanguageServerBinaryStatus, LanguageServerName, LanguageToolchainStore, LanguageRegistry, LanguageServerBinaryStatus, LanguageToolchainStore, LocalFile, LspAdapter,
LocalFile, LspAdapter, LspAdapterDelegate, Patch, PointUtf16, TextBufferSnapshot, ToOffset, LspAdapterDelegate, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Transaction,
ToPointUtf16, Transaction, Unclipped, Unclipped,
}; };
use lsp::{ use lsp::{
CodeActionKind, CompletionContext, DiagnosticSeverity, DiagnosticTag, CodeActionKind, CompletionContext, DiagnosticSeverity, DiagnosticTag,
DidChangeWatchedFilesRegistrationOptions, Edit, FileSystemWatcher, InsertTextFormat, DidChangeWatchedFilesRegistrationOptions, Edit, FileSystemWatcher, InsertTextFormat,
LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId,
LspRequestFuture, MessageActionItem, MessageType, OneOf, ServerHealthStatus, ServerStatus, LanguageServerName, LspRequestFuture, MessageActionItem, MessageType, OneOf,
SymbolKind, TextEdit, Url, WorkDoneProgressCancelParams, WorkspaceFolder, ServerHealthStatus, ServerStatus, SymbolKind, TextEdit, Url, WorkDoneProgressCancelParams,
WorkspaceFolder,
}; };
use node_runtime::read_package_installed_version; use node_runtime::read_package_installed_version;
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
@ -5598,6 +5599,7 @@ impl LspStore {
let pending_server = cx.spawn({ let pending_server = cx.spawn({
let adapter = adapter.clone(); let adapter = adapter.clone();
let server_name = adapter.name.clone();
let stderr_capture = stderr_capture.clone(); let stderr_capture = stderr_capture.clone();
move |_lsp_store, cx| async move { move |_lsp_store, cx| async move {
@ -5608,7 +5610,7 @@ impl LspStore {
.update(&mut cx.clone(), |this, cx| { .update(&mut cx.clone(), |this, cx| {
this.languages.create_fake_language_server( this.languages.create_fake_language_server(
server_id, server_id,
&adapter.name, &server_name,
binary.clone(), binary.clone(),
cx.to_async(), cx.to_async(),
) )
@ -5622,6 +5624,7 @@ impl LspStore {
lsp::LanguageServer::new( lsp::LanguageServer::new(
stderr_capture, stderr_capture,
server_id, server_id,
server_name,
binary, binary,
&root_path, &root_path,
adapter.code_action_kinds(), adapter.code_action_kinds(),
@ -6617,7 +6620,7 @@ impl LspStore {
cx.emit(LspStoreEvent::LanguageServerAdded( cx.emit(LspStoreEvent::LanguageServerAdded(
server_id, server_id,
language_server.name().into(), language_server.name(),
Some(key.0), Some(key.0),
)); ));

View file

@ -15,9 +15,9 @@ use futures::{
use gpui::{AsyncAppContext, EventEmitter, Model, ModelContext, Task, WeakModel}; use gpui::{AsyncAppContext, EventEmitter, Model, ModelContext, Task, WeakModel};
use language::{ use language::{
language_settings::{Formatter, LanguageSettings, SelectedFormatter}, 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 node_runtime::NodeRuntime;
use paths::default_prettier_dir; use paths::default_prettier_dir;
use prettier::Prettier; use prettier::Prettier;

View file

@ -48,12 +48,12 @@ use itertools::Itertools;
use language::{ use language::{
language_settings::InlayHintKind, proto::split_operations, Buffer, BufferEvent, language_settings::InlayHintKind, proto::split_operations, Buffer, BufferEvent,
CachedLspAdapter, Capability, CodeLabel, DiagnosticEntry, Documentation, File as _, Language, CachedLspAdapter, Capability, CodeLabel, DiagnosticEntry, Documentation, File as _, Language,
LanguageName, LanguageRegistry, LanguageServerName, PointUtf16, ToOffset, ToPointUtf16, LanguageName, LanguageRegistry, PointUtf16, ToOffset, ToPointUtf16, Toolchain, ToolchainList,
Toolchain, ToolchainList, Transaction, Unclipped, Transaction, Unclipped,
}; };
use lsp::{ use lsp::{
CompletionContext, CompletionItemKind, DocumentHighlightKind, LanguageServer, LanguageServerId, CompletionContext, CompletionItemKind, DocumentHighlightKind, LanguageServer, LanguageServerId,
MessageActionItem, LanguageServerName, MessageActionItem,
}; };
use lsp_command::*; use lsp_command::*;
use node_runtime::NodeRuntime; use node_runtime::NodeRuntime;

View file

@ -2,7 +2,7 @@ use anyhow::Context;
use collections::HashMap; use collections::HashMap;
use fs::Fs; use fs::Fs;
use gpui::{AppContext, AsyncAppContext, BorrowAppContext, EventEmitter, Model, ModelContext}; use gpui::{AppContext, AsyncAppContext, BorrowAppContext, EventEmitter, Model, ModelContext};
use language::LanguageServerName; use lsp::LanguageServerName;
use paths::{ use paths::{
local_settings_file_relative_path, local_tasks_file_relative_path, local_settings_file_relative_path, local_tasks_file_relative_path,
local_vscode_tasks_file_relative_path, EDITORCONFIG_NAME, local_vscode_tasks_file_relative_path, EDITORCONFIG_NAME,

View file

@ -1243,7 +1243,7 @@ async fn test_disk_based_diagnostics_progress(cx: &mut gpui::TestAppContext) {
events.next().await.unwrap(), events.next().await.unwrap(),
Event::LanguageServerAdded( Event::LanguageServerAdded(
LanguageServerId(0), LanguageServerId(0),
fake_server.server.name().into(), fake_server.server.name(),
Some(worktree_id) Some(worktree_id)
), ),
); );
@ -1378,7 +1378,7 @@ async fn test_restarting_server_with_diagnostics_running(cx: &mut gpui::TestAppC
events.next().await.unwrap(), events.next().await.unwrap(),
Event::LanguageServerAdded( Event::LanguageServerAdded(
LanguageServerId(1), LanguageServerId(1),
fake_server.server.name().into(), fake_server.server.name(),
Some(worktree_id) 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(); let new_server_name = new_server.server.name();
assert!( 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}`" "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_ref() {
match new_server_name.as_str() {
"TailwindServer" | "TypeScriptServer" => { "TailwindServer" | "TypeScriptServer" => {
servers_with_hover_requests.insert( servers_with_hover_requests.insert(
new_server_name.clone(), 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(); let new_server_name = new_server.server.name();
assert!( 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}`" "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.0.as_ref() {
match new_server_name.as_str() {
"TailwindServer" | "TypeScriptServer" => { "TailwindServer" | "TypeScriptServer" => {
servers_with_actions_requests.insert( servers_with_actions_requests.insert(
new_server_name.clone(), new_server_name.clone(),

View file

@ -6,10 +6,9 @@ use gpui::{Context, Model, SemanticVersion, TestAppContext};
use http_client::{BlockedHttpClient, FakeHttpClient}; use http_client::{BlockedHttpClient, FakeHttpClient};
use language::{ use language::{
language_settings::{language_settings, AllLanguageSettings}, language_settings::{language_settings, AllLanguageSettings},
Buffer, FakeLspAdapter, LanguageConfig, LanguageMatcher, LanguageRegistry, LanguageServerName, Buffer, FakeLspAdapter, LanguageConfig, LanguageMatcher, LanguageRegistry, LineEnding,
LineEnding,
}; };
use lsp::{CompletionContext, CompletionResponse, CompletionTriggerKind}; use lsp::{CompletionContext, CompletionResponse, CompletionTriggerKind, LanguageServerName};
use node_runtime::NodeRuntime; use node_runtime::NodeRuntime;
use project::{ use project::{
search::{SearchQuery, SearchResult}, search::{SearchQuery, SearchResult},