From 4dd917c123fe6576d6f38739f875ab1388a2b30d Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 19 Apr 2023 17:37:28 -0700 Subject: [PATCH] Introduce a LanguageServerId wrapper type Clarify the meaning of all the usizes in use in all of these struct fields an method signatures. --- Cargo.lock | 1 + crates/collab/src/tests/integration_tests.rs | 9 ++- crates/copilot/src/copilot.rs | 4 +- crates/diagnostics/Cargo.toml | 2 + crates/diagnostics/src/diagnostics.rs | 26 +++--- crates/diagnostics/src/items.rs | 3 +- crates/editor/src/hover_popover.rs | 3 +- crates/language/src/buffer.rs | 13 +-- crates/language/src/buffer_tests.rs | 2 +- crates/language/src/language.rs | 11 ++- crates/language/src/proto.rs | 10 +-- crates/lsp/src/lsp.rs | 23 ++++-- crates/project/src/lsp_command.rs | 26 +++--- crates/project/src/project.rs | 84 +++++++++++--------- crates/project/src/project_tests.rs | 40 +++++----- crates/project/src/worktree.rs | 26 ++++-- 16 files changed, 166 insertions(+), 117 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d7c0249798..0109c6cbaa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1834,6 +1834,7 @@ dependencies = [ "editor", "gpui", "language", + "lsp", "postage", "project", "serde_json", diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 8542bc2056..206064dc38 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -22,6 +22,7 @@ use language::{ LanguageConfig, OffsetRangeExt, Point, Rope, }; use live_kit_client::MacOSDisplay; +use lsp::LanguageServerId; use project::{search::SearchQuery, DiagnosticSummary, Project, ProjectPath}; use rand::prelude::*; use serde_json::json; @@ -3477,7 +3478,7 @@ async fn test_collaborating_with_diagnostics( worktree_id, path: Arc::from(Path::new("a.rs")), }, - 0, + LanguageServerId(0), DiagnosticSummary { error_count: 1, warning_count: 0, @@ -3513,7 +3514,7 @@ async fn test_collaborating_with_diagnostics( worktree_id, path: Arc::from(Path::new("a.rs")), }, - 0, + LanguageServerId(0), DiagnosticSummary { error_count: 1, warning_count: 0, @@ -3554,7 +3555,7 @@ async fn test_collaborating_with_diagnostics( worktree_id, path: Arc::from(Path::new("a.rs")), }, - 0, + LanguageServerId(0), DiagnosticSummary { error_count: 1, warning_count: 1, @@ -3570,7 +3571,7 @@ async fn test_collaborating_with_diagnostics( worktree_id, path: Arc::from(Path::new("a.rs")), }, - 0, + LanguageServerId(0), DiagnosticSummary { error_count: 1, warning_count: 1, diff --git a/crates/copilot/src/copilot.rs b/crates/copilot/src/copilot.rs index c3ec63c43c..4806826b3c 100644 --- a/crates/copilot/src/copilot.rs +++ b/crates/copilot/src/copilot.rs @@ -14,7 +14,7 @@ use language::{ ToPointUtf16, }; use log::{debug, error}; -use lsp::LanguageServer; +use lsp::{LanguageServer, LanguageServerId}; use node_runtime::NodeRuntime; use request::{LogMessage, StatusNotification}; use settings::Settings; @@ -380,7 +380,7 @@ impl Copilot { let node_path = node_runtime.binary_path().await?; let arguments: &[OsString] = &[server_path.into(), "--stdio".into()]; let server = LanguageServer::new( - 0, + LanguageServerId(0), &node_path, arguments, Path::new("/"), diff --git a/crates/diagnostics/Cargo.toml b/crates/diagnostics/Cargo.toml index 8ef2546b5d..83ee243b82 100644 --- a/crates/diagnostics/Cargo.toml +++ b/crates/diagnostics/Cargo.toml @@ -14,6 +14,7 @@ smallvec = { version = "1.6", features = ["union"] } collections = { path = "../collections" } editor = { path = "../editor" } language = { path = "../language" } +lsp = { path = "../lsp" } gpui = { path = "../gpui" } project = { path = "../project" } settings = { path = "../settings" } @@ -27,6 +28,7 @@ unindent = "0.1" client = { path = "../client", features = ["test-support"] } editor = { path = "../editor", features = ["test-support"] } language = { path = "../language", features = ["test-support"] } +lsp = { path = "../lsp", features = ["test-support"] } gpui = { path = "../gpui", features = ["test-support"] } workspace = { path = "../workspace", features = ["test-support"] } serde_json = { workspace = true } diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 09344a3f4f..9b2964036e 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -18,6 +18,7 @@ use language::{ Anchor, Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection, SelectionGoal, }; +use lsp::LanguageServerId; use project::{DiagnosticSummary, Project, ProjectPath}; use serde_json::json; use settings::Settings; @@ -56,7 +57,7 @@ struct ProjectDiagnosticsEditor { summary: DiagnosticSummary, excerpts: ModelHandle, path_states: Vec, - paths_to_update: BTreeMap, + paths_to_update: BTreeMap, } struct PathState { @@ -116,7 +117,7 @@ impl View for ProjectDiagnosticsEditor { }), "summary": self.summary, "paths_to_update": self.paths_to_update.iter().map(|(path, server_id)| - (path.path.to_string_lossy(), server_id) + (path.path.to_string_lossy(), server_id.0) ).collect::>(), "paths_states": self.path_states.iter().map(|state| json!({ @@ -196,7 +197,11 @@ impl ProjectDiagnosticsEditor { } } - fn update_excerpts(&mut self, language_server_id: Option, cx: &mut ViewContext) { + fn update_excerpts( + &mut self, + language_server_id: Option, + cx: &mut ViewContext, + ) { let mut paths = Vec::new(); self.paths_to_update.retain(|path, server_id| { if language_server_id @@ -809,6 +814,7 @@ mod tests { ) .await; + let language_server_id = LanguageServerId(0); let project = Project::test(app_state.fs.clone(), ["/test".as_ref()], cx).await; let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); @@ -816,7 +822,7 @@ mod tests { project.update(cx, |project, cx| { project .update_diagnostic_entries( - 0, + language_server_id, PathBuf::from("/test/main.rs"), None, vec![ @@ -965,10 +971,10 @@ mod tests { // Diagnostics are added for another earlier path. project.update(cx, |project, cx| { - project.disk_based_diagnostics_started(0, cx); + project.disk_based_diagnostics_started(language_server_id, cx); project .update_diagnostic_entries( - 0, + language_server_id, PathBuf::from("/test/consts.rs"), None, vec![DiagnosticEntry { @@ -985,7 +991,7 @@ mod tests { cx, ) .unwrap(); - project.disk_based_diagnostics_finished(0, cx); + project.disk_based_diagnostics_finished(language_server_id, cx); }); view.next_notification(cx).await; @@ -1065,10 +1071,10 @@ mod tests { // Diagnostics are added to the first path project.update(cx, |project, cx| { - project.disk_based_diagnostics_started(0, cx); + project.disk_based_diagnostics_started(language_server_id, cx); project .update_diagnostic_entries( - 0, + language_server_id, PathBuf::from("/test/consts.rs"), None, vec![ @@ -1101,7 +1107,7 @@ mod tests { cx, ) .unwrap(); - project.disk_based_diagnostics_finished(0, cx); + project.disk_based_diagnostics_finished(language_server_id, cx); }); view.next_notification(cx).await; diff --git a/crates/diagnostics/src/items.rs b/crates/diagnostics/src/items.rs index 6ebae6e204..65b42ab3d4 100644 --- a/crates/diagnostics/src/items.rs +++ b/crates/diagnostics/src/items.rs @@ -7,6 +7,7 @@ use gpui::{ ViewHandle, WeakViewHandle, }; use language::Diagnostic; +use lsp::LanguageServerId; use project::Project; use settings::Settings; use workspace::{item::ItemHandle, StatusItemView}; @@ -15,7 +16,7 @@ pub struct DiagnosticIndicator { summary: project::DiagnosticSummary, active_editor: Option>, current_diagnostic: Option, - in_progress_checks: HashSet, + in_progress_checks: HashSet, _observe_active_editor: Option, } diff --git a/crates/editor/src/hover_popover.rs b/crates/editor/src/hover_popover.rs index f673593413..3e69d2c64b 100644 --- a/crates/editor/src/hover_popover.rs +++ b/crates/editor/src/hover_popover.rs @@ -436,6 +436,7 @@ mod tests { use indoc::indoc; use language::{Diagnostic, DiagnosticSet}; + use lsp::LanguageServerId; use project::HoverBlock; use smol::stream::StreamExt; @@ -620,7 +621,7 @@ mod tests { }], &snapshot, ); - buffer.update_diagnostics(0, set, cx); + buffer.update_diagnostics(LanguageServerId(0), set, cx); }); // Hover pops diagnostic immediately diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 90d6194801..c52ca4d43e 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -17,6 +17,7 @@ use collections::HashMap; use fs::LineEnding; use futures::FutureExt as _; use gpui::{fonts::HighlightStyle, AppContext, Entity, ModelContext, Task}; +use lsp::LanguageServerId; use parking_lot::Mutex; use settings::Settings; use similar::{ChangeTag, TextDiff}; @@ -72,7 +73,7 @@ pub struct Buffer { syntax_map: Mutex, parsing_in_background: bool, parse_count: usize, - diagnostics: HashMap, // server_id -> diagnostic set + diagnostics: HashMap, remote_selections: TreeMap, selections_update_count: usize, diagnostics_update_count: usize, @@ -89,7 +90,7 @@ pub struct BufferSnapshot { pub git_diff: git::diff::BufferDiff, pub(crate) syntax: SyntaxSnapshot, file: Option>, - diagnostics: HashMap, // server_id -> diagnostic set + diagnostics: HashMap, diagnostics_update_count: usize, file_update_count: usize, git_diff_update_count: usize, @@ -157,7 +158,7 @@ pub struct Completion { #[derive(Clone, Debug)] pub struct CodeAction { - pub server_id: usize, + pub server_id: LanguageServerId, pub range: Range, pub lsp_action: lsp::CodeAction, } @@ -167,7 +168,7 @@ pub enum Operation { Buffer(text::Operation), UpdateDiagnostics { - server_id: usize, + server_id: LanguageServerId, diagnostics: Arc<[DiagnosticEntry]>, lamport_timestamp: clock::Lamport, }, @@ -879,7 +880,7 @@ impl Buffer { pub fn update_diagnostics( &mut self, - server_id: usize, + server_id: LanguageServerId, diagnostics: DiagnosticSet, cx: &mut ModelContext, ) { @@ -1645,7 +1646,7 @@ impl Buffer { fn apply_diagnostic_update( &mut self, - server_id: usize, + server_id: LanguageServerId, diagnostics: DiagnosticSet, lamport_timestamp: clock::Lamport, cx: &mut ModelContext, diff --git a/crates/language/src/buffer_tests.rs b/crates/language/src/buffer_tests.rs index 6b6ce041f7..eeac1a4818 100644 --- a/crates/language/src/buffer_tests.rs +++ b/crates/language/src/buffer_tests.rs @@ -1866,7 +1866,7 @@ fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) { buffer, ); log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics); - buffer.update_diagnostics(0, diagnostics, cx); + buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx); }); mutation_count -= 1; } diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 6c440e116b..85c9089952 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -54,6 +54,7 @@ use futures::channel::mpsc; pub use buffer::Operation; pub use buffer::*; pub use diagnostic_set::DiagnosticEntry; +pub use lsp::LanguageServerId; pub use outline::{Outline, OutlineItem}; pub use tree_sitter::{Parser, Tree}; @@ -524,7 +525,7 @@ struct LanguageRegistryState { } pub struct PendingLanguageServer { - pub server_id: usize, + pub server_id: LanguageServerId, pub task: Task>, } @@ -819,7 +820,7 @@ impl LanguageRegistry { Ok(server) }); - let server_id = post_inc(&mut self.state.write().next_language_server_id); + let server_id = self.state.write().next_language_server_id(); return Some(PendingLanguageServer { server_id, task }); } @@ -837,7 +838,7 @@ impl LanguageRegistry { let adapter = adapter.clone(); let lsp_binary_statuses = self.lsp_binary_statuses_tx.clone(); let login_shell_env_loaded = self.login_shell_env_loaded.clone(); - let server_id = post_inc(&mut self.state.write().next_language_server_id); + let server_id = self.state.write().next_language_server_id(); let task = cx.spawn(|cx| async move { login_shell_env_loaded.await; @@ -884,6 +885,10 @@ impl LanguageRegistry { } impl LanguageRegistryState { + fn next_language_server_id(&mut self) -> LanguageServerId { + LanguageServerId(post_inc(&mut self.next_language_server_id)) + } + fn add(&mut self, language: Arc) { if let Some(theme) = self.theme.as_ref() { language.set_theme(&theme.editor.syntax); diff --git a/crates/language/src/proto.rs b/crates/language/src/proto.rs index e4963e0882..bf1d1dd273 100644 --- a/crates/language/src/proto.rs +++ b/crates/language/src/proto.rs @@ -4,7 +4,7 @@ use crate::{ }; use anyhow::{anyhow, Result}; use clock::ReplicaId; -use lsp::DiagnosticSeverity; +use lsp::{DiagnosticSeverity, LanguageServerId}; use rpc::proto; use std::{ops::Range, sync::Arc}; use text::*; @@ -80,7 +80,7 @@ pub fn serialize_operation(operation: &crate::Operation) -> proto::Operation { } => proto::operation::Variant::UpdateDiagnostics(proto::UpdateDiagnostics { replica_id: lamport_timestamp.replica_id as u32, lamport_timestamp: lamport_timestamp.value, - server_id: *server_id as u64, + server_id: server_id.0 as u64, diagnostics: serialize_diagnostics(diagnostics.iter()), }), @@ -277,7 +277,7 @@ pub fn deserialize_operation(message: proto::Operation) -> Result proto::CodeAction { proto::CodeAction { - server_id: action.server_id as u64, + server_id: action.server_id.0 as u64, start: Some(serialize_anchor(&action.range.start)), end: Some(serialize_anchor(&action.range.end)), lsp_action: serde_json::to_vec(&action.lsp_action).unwrap(), @@ -487,7 +487,7 @@ pub fn deserialize_code_action(action: proto::CodeAction) -> Result .ok_or_else(|| anyhow!("invalid end"))?; let lsp_action = serde_json::from_slice(&action.lsp_action)?; Ok(CodeAction { - server_id: action.server_id as usize, + server_id: LanguageServerId(action.server_id as usize), range: start..end, lsp_action, }) diff --git a/crates/lsp/src/lsp.rs b/crates/lsp/src/lsp.rs index 1e37c9765b..b6a4d8513e 100644 --- a/crates/lsp/src/lsp.rs +++ b/crates/lsp/src/lsp.rs @@ -16,6 +16,7 @@ use smol::{ process::{self, Child}, }; use std::{ + fmt, future::Future, io::Write, path::PathBuf, @@ -35,7 +36,7 @@ type NotificationHandler = Box, &str, AsyncAppCon type ResponseHandler = Box)>; pub struct LanguageServer { - server_id: usize, + server_id: LanguageServerId, next_id: AtomicUsize, outbound_tx: channel::Sender>, name: String, @@ -51,6 +52,10 @@ pub struct LanguageServer { _server: Option, } +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct LanguageServerId(pub usize); + pub struct Subscription { method: &'static str, notification_handlers: Arc>>, @@ -107,7 +112,7 @@ struct Error { impl LanguageServer { pub fn new>( - server_id: usize, + server_id: LanguageServerId, binary_path: &Path, arguments: &[T], root_path: &Path, @@ -158,7 +163,7 @@ impl LanguageServer { } fn new_internal( - server_id: usize, + server_id: LanguageServerId, stdin: Stdin, stdout: Stdout, server: Option, @@ -581,7 +586,7 @@ impl LanguageServer { &self.capabilities } - pub fn server_id(&self) -> usize { + pub fn server_id(&self) -> LanguageServerId { self.server_id } @@ -685,6 +690,12 @@ impl Subscription { } } +impl fmt::Display for LanguageServerId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + impl Drop for Subscription { fn drop(&mut self) { self.notification_handlers.lock().remove(self.method); @@ -720,7 +731,7 @@ impl LanguageServer { let (notifications_tx, notifications_rx) = channel::unbounded(); let server = Self::new_internal( - 0, + LanguageServerId(0), stdin_writer, stdout_reader, None, @@ -731,7 +742,7 @@ impl LanguageServer { ); let fake = FakeLanguageServer { server: Arc::new(Self::new_internal( - 0, + LanguageServerId(0), stdout_writer, stdin_reader, None, diff --git a/crates/project/src/lsp_command.rs b/crates/project/src/lsp_command.rs index 96e44d6f84..b26987694e 100644 --- a/crates/project/src/lsp_command.rs +++ b/crates/project/src/lsp_command.rs @@ -12,7 +12,7 @@ use language::{ range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, CachedLspAdapter, CharKind, CodeAction, Completion, OffsetRangeExt, PointUtf16, ToOffset, ToPointUtf16, Unclipped, }; -use lsp::{DocumentHighlightKind, LanguageServer, ServerCapabilities}; +use lsp::{DocumentHighlightKind, LanguageServer, LanguageServerId, ServerCapabilities}; use pulldown_cmark::{CodeBlockKind, Event, Options, Parser, Tag}; use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc}; @@ -39,7 +39,7 @@ pub(crate) trait LspCommand: 'static + Sized { message: ::Result, project: ModelHandle, buffer: ModelHandle, - server_id: usize, + server_id: LanguageServerId, cx: AsyncAppContext, ) -> Result; @@ -143,7 +143,7 @@ impl LspCommand for PrepareRename { message: Option, _: ModelHandle, buffer: ModelHandle, - _: usize, + _: LanguageServerId, cx: AsyncAppContext, ) -> Result>> { buffer.read_with(&cx, |buffer, _| { @@ -270,7 +270,7 @@ impl LspCommand for PerformRename { message: Option, project: ModelHandle, buffer: ModelHandle, - server_id: usize, + server_id: LanguageServerId, mut cx: AsyncAppContext, ) -> Result { if let Some(edit) = message { @@ -389,7 +389,7 @@ impl LspCommand for GetDefinition { message: Option, project: ModelHandle, buffer: ModelHandle, - server_id: usize, + server_id: LanguageServerId, cx: AsyncAppContext, ) -> Result> { location_links_from_lsp(message, project, buffer, server_id, cx).await @@ -482,7 +482,7 @@ impl LspCommand for GetTypeDefinition { message: Option, project: ModelHandle, buffer: ModelHandle, - server_id: usize, + server_id: LanguageServerId, cx: AsyncAppContext, ) -> Result> { location_links_from_lsp(message, project, buffer, server_id, cx).await @@ -548,7 +548,7 @@ impl LspCommand for GetTypeDefinition { fn language_server_for_buffer( project: &ModelHandle, buffer: &ModelHandle, - server_id: usize, + server_id: LanguageServerId, cx: &mut AsyncAppContext, ) -> Result<(Arc, Arc)> { project @@ -626,7 +626,7 @@ async fn location_links_from_lsp( message: Option, project: ModelHandle, buffer: ModelHandle, - server_id: usize, + server_id: LanguageServerId, mut cx: AsyncAppContext, ) -> Result> { let message = match message { @@ -770,7 +770,7 @@ impl LspCommand for GetReferences { locations: Option>, project: ModelHandle, buffer: ModelHandle, - server_id: usize, + server_id: LanguageServerId, mut cx: AsyncAppContext, ) -> Result> { let mut references = Vec::new(); @@ -932,7 +932,7 @@ impl LspCommand for GetDocumentHighlights { lsp_highlights: Option>, _: ModelHandle, buffer: ModelHandle, - _: usize, + _: LanguageServerId, cx: AsyncAppContext, ) -> Result> { buffer.read_with(&cx, |buffer, _| { @@ -1078,7 +1078,7 @@ impl LspCommand for GetHover { message: Option, _: ModelHandle, buffer: ModelHandle, - _: usize, + _: LanguageServerId, cx: AsyncAppContext, ) -> Result { Ok(message.and_then(|hover| { @@ -1300,7 +1300,7 @@ impl LspCommand for GetCompletions { completions: Option, _: ModelHandle, buffer: ModelHandle, - _: usize, + _: LanguageServerId, cx: AsyncAppContext, ) -> Result> { let completions = if let Some(completions) = completions { @@ -1520,7 +1520,7 @@ impl LspCommand for GetCodeActions { actions: Option, _: ModelHandle, _: ModelHandle, - server_id: usize, + server_id: LanguageServerId, _: AsyncAppContext, ) -> Result> { Ok(actions diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 7c0f33a94a..afd0b3bbae 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -36,7 +36,7 @@ use language::{ }; use lsp::{ DiagnosticSeverity, DiagnosticTag, DidChangeWatchedFilesRegistrationOptions, - DocumentHighlightKind, LanguageServer, LanguageString, MarkedString, + DocumentHighlightKind, LanguageServer, LanguageServerId, LanguageString, MarkedString, }; use lsp_command::*; use lsp_glob_set::LspGlobSet; @@ -95,10 +95,10 @@ pub struct Project { active_entry: Option, buffer_changes_tx: mpsc::UnboundedSender, languages: Arc, - language_servers: HashMap, - language_server_ids: HashMap<(WorktreeId, LanguageServerName), usize>, - language_server_statuses: BTreeMap, - last_workspace_edits_by_language_server: HashMap, + language_servers: HashMap, + language_server_ids: HashMap<(WorktreeId, LanguageServerName), LanguageServerId>, + language_server_statuses: BTreeMap, + last_workspace_edits_by_language_server: HashMap, client: Arc, next_entry_id: Arc, join_project_response_message_id: u32, @@ -123,7 +123,7 @@ pub struct Project { /// A mapping from a buffer ID to None means that we've started waiting for an ID but haven't finished loading it. /// Used for re-issuing buffer requests when peers temporarily disconnect incomplete_remote_buffers: HashMap>>, - buffer_snapshots: HashMap>>, // buffer_id -> server_id -> vec of snapshots + buffer_snapshots: HashMap>>, // buffer_id -> server_id -> vec of snapshots buffers_being_formatted: HashSet, nonce: u128, _maintain_buffer_languages: Task<()>, @@ -189,14 +189,14 @@ pub enum Event { WorktreeAdded, WorktreeRemoved(WorktreeId), DiskBasedDiagnosticsStarted { - language_server_id: usize, + language_server_id: LanguageServerId, }, DiskBasedDiagnosticsFinished { - language_server_id: usize, + language_server_id: LanguageServerId, }, DiagnosticsUpdated { path: ProjectPath, - language_server_id: usize, + language_server_id: LanguageServerId, }, RemoteIdChanged(Option), DisconnectedFromHost, @@ -336,10 +336,14 @@ impl DiagnosticSummary { self.error_count == 0 && self.warning_count == 0 } - pub fn to_proto(&self, language_server_id: usize, path: &Path) -> proto::DiagnosticSummary { + pub fn to_proto( + &self, + language_server_id: LanguageServerId, + path: &Path, + ) -> proto::DiagnosticSummary { proto::DiagnosticSummary { path: path.to_string_lossy().to_string(), - language_server_id: language_server_id as u64, + language_server_id: language_server_id.0 as u64, error_count: self.error_count as u32, warning_count: self.warning_count as u32, } @@ -541,7 +545,7 @@ impl Project { .into_iter() .map(|server| { ( - server.id as usize, + LanguageServerId(server.id as usize), LanguageServerStatus { name: server.name, pending_work: Default::default(), @@ -1025,7 +1029,7 @@ impl Project { .send(proto::StartLanguageServer { project_id, server: Some(proto::LanguageServer { - id: *server_id as u64, + id: server_id.0 as u64, name: status.name.clone(), }), }) @@ -1152,7 +1156,7 @@ impl Project { .into_iter() .map(|server| { ( - server.id as usize, + LanguageServerId(server.id as usize), LanguageServerStatus { name: server.name, pending_work: Default::default(), @@ -1444,7 +1448,7 @@ impl Project { fn open_local_buffer_via_lsp( &mut self, abs_path: lsp::Url, - language_server_id: usize, + language_server_id: LanguageServerId, language_server_name: LanguageServerName, cx: &mut ModelContext, ) -> Task>> { @@ -2381,7 +2385,7 @@ impl Project { .send(proto::StartLanguageServer { project_id, server: Some(proto::LanguageServer { - id: server_id as u64, + id: server_id.0 as u64, name: language_server.name().to_string(), }), }) @@ -2603,7 +2607,7 @@ impl Project { fn on_lsp_progress( &mut self, progress: lsp::ProgressParams, - server_id: usize, + server_id: LanguageServerId, disk_based_diagnostics_progress_token: Option, cx: &mut ModelContext, ) { @@ -2715,7 +2719,7 @@ impl Project { fn on_lsp_work_start( &mut self, - language_server_id: usize, + language_server_id: LanguageServerId, token: String, progress: LanguageServerProgress, cx: &mut ModelContext, @@ -2728,7 +2732,7 @@ impl Project { fn on_lsp_work_progress( &mut self, - language_server_id: usize, + language_server_id: LanguageServerId, token: String, progress: LanguageServerProgress, cx: &mut ModelContext, @@ -2755,7 +2759,7 @@ impl Project { fn on_lsp_work_end( &mut self, - language_server_id: usize, + language_server_id: LanguageServerId, token: String, cx: &mut ModelContext, ) { @@ -2767,7 +2771,7 @@ impl Project { fn on_lsp_did_change_watched_files( &mut self, - language_server_id: usize, + language_server_id: LanguageServerId, params: DidChangeWatchedFilesRegistrationOptions, cx: &mut ModelContext, ) { @@ -2785,7 +2789,7 @@ impl Project { async fn on_lsp_workspace_edit( this: WeakModelHandle, params: lsp::ApplyWorkspaceEditParams, - server_id: usize, + server_id: LanguageServerId, adapter: Arc, language_server: Arc, mut cx: AsyncAppContext, @@ -2818,14 +2822,14 @@ impl Project { fn broadcast_language_server_update( &self, - language_server_id: usize, + language_server_id: LanguageServerId, event: proto::update_language_server::Variant, ) { if let Some(project_id) = self.remote_id() { self.client .send(proto::UpdateLanguageServer { project_id, - language_server_id: language_server_id as u64, + language_server_id: language_server_id.0 as u64, variant: Some(event), }) .log_err(); @@ -2840,7 +2844,7 @@ impl Project { pub fn update_diagnostics( &mut self, - language_server_id: usize, + language_server_id: LanguageServerId, mut params: lsp::PublishDiagnosticsParams, disk_based_sources: &[String], cx: &mut ModelContext, @@ -2960,7 +2964,7 @@ impl Project { pub fn update_diagnostic_entries( &mut self, - server_id: usize, + server_id: LanguageServerId, abs_path: PathBuf, version: Option, diagnostics: Vec>>, @@ -2997,7 +3001,7 @@ impl Project { fn update_buffer_diagnostics( &mut self, buffer: &ModelHandle, - server_id: usize, + server_id: LanguageServerId, version: Option, mut diagnostics: Vec>>, cx: &mut ModelContext, @@ -4712,7 +4716,7 @@ impl Project { pub fn language_servers_running_disk_based_diagnostics( &self, - ) -> impl Iterator + '_ { + ) -> impl Iterator + '_ { self.language_server_statuses .iter() .filter_map(|(id, status)| { @@ -4736,7 +4740,7 @@ impl Project { pub fn diagnostic_summaries<'a>( &'a self, cx: &'a AppContext, - ) -> impl Iterator + 'a { + ) -> impl Iterator + 'a { self.visible_worktrees(cx).flat_map(move |worktree| { let worktree = worktree.read(cx); let worktree_id = worktree.id(); @@ -4750,7 +4754,7 @@ impl Project { pub fn disk_based_diagnostics_started( &mut self, - language_server_id: usize, + language_server_id: LanguageServerId, cx: &mut ModelContext, ) { cx.emit(Event::DiskBasedDiagnosticsStarted { language_server_id }); @@ -4758,7 +4762,7 @@ impl Project { pub fn disk_based_diagnostics_finished( &mut self, - language_server_id: usize, + language_server_id: LanguageServerId, cx: &mut ModelContext, ) { cx.emit(Event::DiskBasedDiagnosticsFinished { language_server_id }); @@ -5065,7 +5069,7 @@ impl Project { .update_diagnostic_summary(project_path.path.clone(), &summary); }); cx.emit(Event::DiagnosticsUpdated { - language_server_id: summary.language_server_id as usize, + language_server_id: LanguageServerId(summary.language_server_id as usize), path: project_path, }); } @@ -5086,7 +5090,7 @@ impl Project { .ok_or_else(|| anyhow!("invalid server"))?; this.update(&mut cx, |this, cx| { this.language_server_statuses.insert( - server.id as usize, + LanguageServerId(server.id as usize), LanguageServerStatus { name: server.name, pending_work: Default::default(), @@ -5106,7 +5110,7 @@ impl Project { mut cx: AsyncAppContext, ) -> Result<()> { this.update(&mut cx, |this, cx| { - let language_server_id = envelope.payload.language_server_id as usize; + let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize); match envelope .payload @@ -6142,7 +6146,7 @@ impl Project { &mut self, buffer: &ModelHandle, lsp_edits: impl 'static + Send + IntoIterator, - server_id: usize, + server_id: LanguageServerId, version: Option, cx: &mut ModelContext, ) -> Task, String)>>> { @@ -6245,7 +6249,7 @@ impl Project { fn buffer_snapshot_for_lsp_version( &mut self, buffer: &ModelHandle, - server_id: usize, + server_id: LanguageServerId, version: Option, cx: &AppContext, ) -> Result { @@ -6314,14 +6318,18 @@ impl Project { fn language_server_for_buffer( &self, buffer: &Buffer, - server_id: usize, + server_id: LanguageServerId, cx: &AppContext, ) -> Option<(&Arc, &Arc)> { self.language_servers_iter_for_buffer(buffer, cx) .find(|(_, s)| s.server_id() == server_id) } - fn language_server_ids_for_buffer(&self, buffer: &Buffer, cx: &AppContext) -> Vec { + fn language_server_ids_for_buffer( + &self, + buffer: &Buffer, + cx: &AppContext, + ) -> Vec { if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) { let worktree_id = file.worktree_id(cx); language diff --git a/crates/project/src/project_tests.rs b/crates/project/src/project_tests.rs index 6cda33dc47..5d062d42ce 100644 --- a/crates/project/src/project_tests.rs +++ b/crates/project/src/project_tests.rs @@ -303,7 +303,7 @@ async fn test_managing_language_servers( rust_buffer2.update(cx, |buffer, cx| { buffer.update_diagnostics( - 0, + LanguageServerId(0), DiagnosticSet::from_sorted_entries( vec![DiagnosticEntry { diagnostic: Default::default(), @@ -582,7 +582,7 @@ async fn test_single_file_worktrees_diagnostics(cx: &mut gpui::TestAppContext) { project.update(cx, |project, cx| { project .update_diagnostics( - 0, + LanguageServerId(0), lsp::PublishDiagnosticsParams { uri: Url::from_file_path("/dir/a.rs").unwrap(), version: None, @@ -599,7 +599,7 @@ async fn test_single_file_worktrees_diagnostics(cx: &mut gpui::TestAppContext) { .unwrap(); project .update_diagnostics( - 0, + LanguageServerId(0), lsp::PublishDiagnosticsParams { uri: Url::from_file_path("/dir/b.rs").unwrap(), version: None, @@ -675,7 +675,7 @@ async fn test_hidden_worktrees_diagnostics(cx: &mut gpui::TestAppContext) { project.update(cx, |project, cx| { project .update_diagnostics( - 0, + LanguageServerId(0), lsp::PublishDiagnosticsParams { uri: Url::from_file_path("/root/other.rs").unwrap(), version: None, @@ -767,7 +767,7 @@ async fn test_disk_based_diagnostics_progress(cx: &mut gpui::TestAppContext) { assert_eq!( events.next().await.unwrap(), Event::DiskBasedDiagnosticsStarted { - language_server_id: 0, + language_server_id: LanguageServerId(0), } ); @@ -784,7 +784,7 @@ async fn test_disk_based_diagnostics_progress(cx: &mut gpui::TestAppContext) { assert_eq!( events.next().await.unwrap(), Event::DiagnosticsUpdated { - language_server_id: 0, + language_server_id: LanguageServerId(0), path: (worktree_id, Path::new("a.rs")).into() } ); @@ -793,7 +793,7 @@ async fn test_disk_based_diagnostics_progress(cx: &mut gpui::TestAppContext) { assert_eq!( events.next().await.unwrap(), Event::DiskBasedDiagnosticsFinished { - language_server_id: 0 + language_server_id: LanguageServerId(0) } ); @@ -831,7 +831,7 @@ async fn test_disk_based_diagnostics_progress(cx: &mut gpui::TestAppContext) { assert_eq!( events.next().await.unwrap(), Event::DiagnosticsUpdated { - language_server_id: 0, + language_server_id: LanguageServerId(0), path: (worktree_id, Path::new("a.rs")).into() } ); @@ -892,7 +892,7 @@ async fn test_restarting_server_with_diagnostics_running(cx: &mut gpui::TestAppC assert_eq!( events.next().await.unwrap(), Event::DiskBasedDiagnosticsStarted { - language_server_id: 1 + language_server_id: LanguageServerId(1) } ); project.read_with(cx, |project, _| { @@ -900,7 +900,7 @@ async fn test_restarting_server_with_diagnostics_running(cx: &mut gpui::TestAppC project .language_servers_running_disk_based_diagnostics() .collect::>(), - [1] + [LanguageServerId(1)] ); }); @@ -910,7 +910,7 @@ async fn test_restarting_server_with_diagnostics_running(cx: &mut gpui::TestAppC assert_eq!( events.next().await.unwrap(), Event::DiskBasedDiagnosticsFinished { - language_server_id: 1 + language_server_id: LanguageServerId(1) } ); project.read_with(cx, |project, _| { @@ -918,7 +918,7 @@ async fn test_restarting_server_with_diagnostics_running(cx: &mut gpui::TestAppC project .language_servers_running_disk_based_diagnostics() .collect::>(), - [0; 0] + [LanguageServerId(0); 0] ); }); } @@ -1403,7 +1403,7 @@ async fn test_empty_diagnostic_ranges(cx: &mut gpui::TestAppContext) { project .update_buffer_diagnostics( &buffer, - 0, + LanguageServerId(0), None, vec![ DiagnosticEntry { @@ -1464,7 +1464,7 @@ async fn test_diagnostics_from_multiple_language_servers(cx: &mut gpui::TestAppC project.update(cx, |project, cx| { project .update_diagnostic_entries( - 0, + LanguageServerId(0), Path::new("/dir/a.rs").to_owned(), None, vec![DiagnosticEntry { @@ -1481,7 +1481,7 @@ async fn test_diagnostics_from_multiple_language_servers(cx: &mut gpui::TestAppC .unwrap(); project .update_diagnostic_entries( - 1, + LanguageServerId(1), Path::new("/dir/a.rs").to_owned(), None, vec![DiagnosticEntry { @@ -1633,7 +1633,7 @@ async fn test_edits_from_lsp_with_past_version(cx: &mut gpui::TestAppContext) { new_text: "".into(), }, ], - 0, + LanguageServerId(0), Some(lsp_document_version), cx, ) @@ -1728,7 +1728,7 @@ async fn test_edits_from_lsp_with_edits_on_adjacent_lines(cx: &mut gpui::TestApp new_text: "".into(), }, ], - 0, + LanguageServerId(0), None, cx, ) @@ -1832,7 +1832,7 @@ async fn test_invalid_edits_from_lsp(cx: &mut gpui::TestAppContext) { .unindent(), }, ], - 0, + LanguageServerId(0), None, cx, ) @@ -3011,7 +3011,9 @@ async fn test_grouped_diagnostics(cx: &mut gpui::TestAppContext) { }; project - .update(cx, |p, cx| p.update_diagnostics(0, message, &[], cx)) + .update(cx, |p, cx| { + p.update_diagnostics(LanguageServerId(0), message, &[], cx) + }) .unwrap(); let buffer = buffer.read_with(cx, |buffer, _| buffer.snapshot()); diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 057d89f567..14fb4f2628 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -26,6 +26,7 @@ use language::{ }, Buffer, DiagnosticEntry, File as _, PointUtf16, Rope, RopeFingerprint, Unclipped, }; +use lsp::LanguageServerId; use parking_lot::Mutex; use postage::{ barrier, @@ -67,8 +68,14 @@ pub struct LocalWorktree { is_scanning: (watch::Sender, watch::Receiver), _background_scanner_task: Task<()>, share: Option, - diagnostics: HashMap, Vec<(usize, Vec>>)>>, - diagnostic_summaries: HashMap, HashMap>, + diagnostics: HashMap< + Arc, + Vec<( + LanguageServerId, + Vec>>, + )>, + >, + diagnostic_summaries: HashMap, HashMap>, client: Arc, fs: Arc, visible: bool, @@ -82,7 +89,7 @@ pub struct RemoteWorktree { updates_tx: Option>, snapshot_subscriptions: VecDeque<(usize, oneshot::Sender<()>)>, replica_id: ReplicaId, - diagnostic_summaries: HashMap, HashMap>, + diagnostic_summaries: HashMap, HashMap>, visible: bool, disconnected: bool, } @@ -463,7 +470,7 @@ impl Worktree { pub fn diagnostic_summaries( &self, - ) -> impl Iterator, usize, DiagnosticSummary)> + '_ { + ) -> impl Iterator, LanguageServerId, DiagnosticSummary)> + '_ { match self { Worktree::Local(worktree) => &worktree.diagnostic_summaries, Worktree::Remote(worktree) => &worktree.diagnostic_summaries, @@ -518,13 +525,16 @@ impl LocalWorktree { pub fn diagnostics_for_path( &self, path: &Path, - ) -> Vec<(usize, Vec>>)> { + ) -> Vec<( + LanguageServerId, + Vec>>, + )> { self.diagnostics.get(path).cloned().unwrap_or_default() } pub fn update_diagnostics( &mut self, - server_id: usize, + server_id: LanguageServerId, worktree_path: Arc, diagnostics: Vec>>, _: &mut ModelContext, @@ -570,7 +580,7 @@ impl LocalWorktree { worktree_id: self.id().to_proto(), summary: Some(proto::DiagnosticSummary { path: worktree_path.to_string_lossy().to_string(), - language_server_id: server_id as u64, + language_server_id: server_id.0 as u64, error_count: new_summary.error_count as u32, warning_count: new_summary.warning_count as u32, }), @@ -1135,7 +1145,7 @@ impl RemoteWorktree { path: Arc, summary: &proto::DiagnosticSummary, ) { - let server_id = summary.language_server_id as usize; + let server_id = LanguageServerId(summary.language_server_id as usize); let summary = DiagnosticSummary { error_count: summary.error_count as usize, warning_count: summary.warning_count as usize,