Introduce a LanguageServerId wrapper type

Clarify the meaning of all the usizes in use in all of these
struct fields an method signatures.
This commit is contained in:
Max Brunsfeld 2023-04-19 17:37:28 -07:00
parent c5f86bc6af
commit 4dd917c123
16 changed files with 166 additions and 117 deletions

1
Cargo.lock generated
View file

@ -1834,6 +1834,7 @@ dependencies = [
"editor", "editor",
"gpui", "gpui",
"language", "language",
"lsp",
"postage", "postage",
"project", "project",
"serde_json", "serde_json",

View file

@ -22,6 +22,7 @@ use language::{
LanguageConfig, OffsetRangeExt, Point, Rope, LanguageConfig, OffsetRangeExt, Point, Rope,
}; };
use live_kit_client::MacOSDisplay; use live_kit_client::MacOSDisplay;
use lsp::LanguageServerId;
use project::{search::SearchQuery, DiagnosticSummary, Project, ProjectPath}; use project::{search::SearchQuery, DiagnosticSummary, Project, ProjectPath};
use rand::prelude::*; use rand::prelude::*;
use serde_json::json; use serde_json::json;
@ -3477,7 +3478,7 @@ async fn test_collaborating_with_diagnostics(
worktree_id, worktree_id,
path: Arc::from(Path::new("a.rs")), path: Arc::from(Path::new("a.rs")),
}, },
0, LanguageServerId(0),
DiagnosticSummary { DiagnosticSummary {
error_count: 1, error_count: 1,
warning_count: 0, warning_count: 0,
@ -3513,7 +3514,7 @@ async fn test_collaborating_with_diagnostics(
worktree_id, worktree_id,
path: Arc::from(Path::new("a.rs")), path: Arc::from(Path::new("a.rs")),
}, },
0, LanguageServerId(0),
DiagnosticSummary { DiagnosticSummary {
error_count: 1, error_count: 1,
warning_count: 0, warning_count: 0,
@ -3554,7 +3555,7 @@ async fn test_collaborating_with_diagnostics(
worktree_id, worktree_id,
path: Arc::from(Path::new("a.rs")), path: Arc::from(Path::new("a.rs")),
}, },
0, LanguageServerId(0),
DiagnosticSummary { DiagnosticSummary {
error_count: 1, error_count: 1,
warning_count: 1, warning_count: 1,
@ -3570,7 +3571,7 @@ async fn test_collaborating_with_diagnostics(
worktree_id, worktree_id,
path: Arc::from(Path::new("a.rs")), path: Arc::from(Path::new("a.rs")),
}, },
0, LanguageServerId(0),
DiagnosticSummary { DiagnosticSummary {
error_count: 1, error_count: 1,
warning_count: 1, warning_count: 1,

View file

@ -14,7 +14,7 @@ use language::{
ToPointUtf16, ToPointUtf16,
}; };
use log::{debug, error}; use log::{debug, error};
use lsp::LanguageServer; use lsp::{LanguageServer, LanguageServerId};
use node_runtime::NodeRuntime; use node_runtime::NodeRuntime;
use request::{LogMessage, StatusNotification}; use request::{LogMessage, StatusNotification};
use settings::Settings; use settings::Settings;
@ -380,7 +380,7 @@ impl Copilot {
let node_path = node_runtime.binary_path().await?; let node_path = node_runtime.binary_path().await?;
let arguments: &[OsString] = &[server_path.into(), "--stdio".into()]; let arguments: &[OsString] = &[server_path.into(), "--stdio".into()];
let server = LanguageServer::new( let server = LanguageServer::new(
0, LanguageServerId(0),
&node_path, &node_path,
arguments, arguments,
Path::new("/"), Path::new("/"),

View file

@ -14,6 +14,7 @@ smallvec = { version = "1.6", features = ["union"] }
collections = { path = "../collections" } collections = { path = "../collections" }
editor = { path = "../editor" } editor = { path = "../editor" }
language = { path = "../language" } language = { path = "../language" }
lsp = { path = "../lsp" }
gpui = { path = "../gpui" } gpui = { path = "../gpui" }
project = { path = "../project" } project = { path = "../project" }
settings = { path = "../settings" } settings = { path = "../settings" }
@ -27,6 +28,7 @@ unindent = "0.1"
client = { path = "../client", features = ["test-support"] } client = { path = "../client", features = ["test-support"] }
editor = { path = "../editor", features = ["test-support"] } editor = { path = "../editor", features = ["test-support"] }
language = { path = "../language", features = ["test-support"] } language = { path = "../language", features = ["test-support"] }
lsp = { path = "../lsp", features = ["test-support"] }
gpui = { path = "../gpui", features = ["test-support"] } gpui = { path = "../gpui", features = ["test-support"] }
workspace = { path = "../workspace", features = ["test-support"] } workspace = { path = "../workspace", features = ["test-support"] }
serde_json = { workspace = true } serde_json = { workspace = true }

View file

@ -18,6 +18,7 @@ use language::{
Anchor, Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection, Anchor, Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection,
SelectionGoal, SelectionGoal,
}; };
use lsp::LanguageServerId;
use project::{DiagnosticSummary, Project, ProjectPath}; use project::{DiagnosticSummary, Project, ProjectPath};
use serde_json::json; use serde_json::json;
use settings::Settings; use settings::Settings;
@ -56,7 +57,7 @@ struct ProjectDiagnosticsEditor {
summary: DiagnosticSummary, summary: DiagnosticSummary,
excerpts: ModelHandle<MultiBuffer>, excerpts: ModelHandle<MultiBuffer>,
path_states: Vec<PathState>, path_states: Vec<PathState>,
paths_to_update: BTreeMap<ProjectPath, usize>, paths_to_update: BTreeMap<ProjectPath, LanguageServerId>,
} }
struct PathState { struct PathState {
@ -116,7 +117,7 @@ impl View for ProjectDiagnosticsEditor {
}), }),
"summary": self.summary, "summary": self.summary,
"paths_to_update": self.paths_to_update.iter().map(|(path, server_id)| "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::<Vec<_>>(), ).collect::<Vec<_>>(),
"paths_states": self.path_states.iter().map(|state| "paths_states": self.path_states.iter().map(|state|
json!({ json!({
@ -196,7 +197,11 @@ impl ProjectDiagnosticsEditor {
} }
} }
fn update_excerpts(&mut self, language_server_id: Option<usize>, cx: &mut ViewContext<Self>) { fn update_excerpts(
&mut self,
language_server_id: Option<LanguageServerId>,
cx: &mut ViewContext<Self>,
) {
let mut paths = Vec::new(); let mut paths = Vec::new();
self.paths_to_update.retain(|path, server_id| { self.paths_to_update.retain(|path, server_id| {
if language_server_id if language_server_id
@ -809,6 +814,7 @@ mod tests {
) )
.await; .await;
let language_server_id = LanguageServerId(0);
let project = Project::test(app_state.fs.clone(), ["/test".as_ref()], cx).await; 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)); 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(cx, |project, cx| {
project project
.update_diagnostic_entries( .update_diagnostic_entries(
0, language_server_id,
PathBuf::from("/test/main.rs"), PathBuf::from("/test/main.rs"),
None, None,
vec![ vec![
@ -965,10 +971,10 @@ mod tests {
// Diagnostics are added for another earlier path. // Diagnostics are added for another earlier path.
project.update(cx, |project, cx| { project.update(cx, |project, cx| {
project.disk_based_diagnostics_started(0, cx); project.disk_based_diagnostics_started(language_server_id, cx);
project project
.update_diagnostic_entries( .update_diagnostic_entries(
0, language_server_id,
PathBuf::from("/test/consts.rs"), PathBuf::from("/test/consts.rs"),
None, None,
vec![DiagnosticEntry { vec![DiagnosticEntry {
@ -985,7 +991,7 @@ mod tests {
cx, cx,
) )
.unwrap(); .unwrap();
project.disk_based_diagnostics_finished(0, cx); project.disk_based_diagnostics_finished(language_server_id, cx);
}); });
view.next_notification(cx).await; view.next_notification(cx).await;
@ -1065,10 +1071,10 @@ mod tests {
// Diagnostics are added to the first path // Diagnostics are added to the first path
project.update(cx, |project, cx| { project.update(cx, |project, cx| {
project.disk_based_diagnostics_started(0, cx); project.disk_based_diagnostics_started(language_server_id, cx);
project project
.update_diagnostic_entries( .update_diagnostic_entries(
0, language_server_id,
PathBuf::from("/test/consts.rs"), PathBuf::from("/test/consts.rs"),
None, None,
vec![ vec![
@ -1101,7 +1107,7 @@ mod tests {
cx, cx,
) )
.unwrap(); .unwrap();
project.disk_based_diagnostics_finished(0, cx); project.disk_based_diagnostics_finished(language_server_id, cx);
}); });
view.next_notification(cx).await; view.next_notification(cx).await;

View file

@ -7,6 +7,7 @@ use gpui::{
ViewHandle, WeakViewHandle, ViewHandle, WeakViewHandle,
}; };
use language::Diagnostic; use language::Diagnostic;
use lsp::LanguageServerId;
use project::Project; use project::Project;
use settings::Settings; use settings::Settings;
use workspace::{item::ItemHandle, StatusItemView}; use workspace::{item::ItemHandle, StatusItemView};
@ -15,7 +16,7 @@ pub struct DiagnosticIndicator {
summary: project::DiagnosticSummary, summary: project::DiagnosticSummary,
active_editor: Option<WeakViewHandle<Editor>>, active_editor: Option<WeakViewHandle<Editor>>,
current_diagnostic: Option<Diagnostic>, current_diagnostic: Option<Diagnostic>,
in_progress_checks: HashSet<usize>, in_progress_checks: HashSet<LanguageServerId>,
_observe_active_editor: Option<Subscription>, _observe_active_editor: Option<Subscription>,
} }

View file

@ -436,6 +436,7 @@ mod tests {
use indoc::indoc; use indoc::indoc;
use language::{Diagnostic, DiagnosticSet}; use language::{Diagnostic, DiagnosticSet};
use lsp::LanguageServerId;
use project::HoverBlock; use project::HoverBlock;
use smol::stream::StreamExt; use smol::stream::StreamExt;
@ -620,7 +621,7 @@ mod tests {
}], }],
&snapshot, &snapshot,
); );
buffer.update_diagnostics(0, set, cx); buffer.update_diagnostics(LanguageServerId(0), set, cx);
}); });
// Hover pops diagnostic immediately // Hover pops diagnostic immediately

View file

@ -17,6 +17,7 @@ use collections::HashMap;
use fs::LineEnding; use fs::LineEnding;
use futures::FutureExt as _; use futures::FutureExt as _;
use gpui::{fonts::HighlightStyle, AppContext, Entity, ModelContext, Task}; use gpui::{fonts::HighlightStyle, AppContext, Entity, ModelContext, Task};
use lsp::LanguageServerId;
use parking_lot::Mutex; use parking_lot::Mutex;
use settings::Settings; use settings::Settings;
use similar::{ChangeTag, TextDiff}; use similar::{ChangeTag, TextDiff};
@ -72,7 +73,7 @@ pub struct Buffer {
syntax_map: Mutex<SyntaxMap>, syntax_map: Mutex<SyntaxMap>,
parsing_in_background: bool, parsing_in_background: bool,
parse_count: usize, parse_count: usize,
diagnostics: HashMap<usize, DiagnosticSet>, // server_id -> diagnostic set diagnostics: HashMap<LanguageServerId, DiagnosticSet>,
remote_selections: TreeMap<ReplicaId, SelectionSet>, remote_selections: TreeMap<ReplicaId, SelectionSet>,
selections_update_count: usize, selections_update_count: usize,
diagnostics_update_count: usize, diagnostics_update_count: usize,
@ -89,7 +90,7 @@ pub struct BufferSnapshot {
pub git_diff: git::diff::BufferDiff, pub git_diff: git::diff::BufferDiff,
pub(crate) syntax: SyntaxSnapshot, pub(crate) syntax: SyntaxSnapshot,
file: Option<Arc<dyn File>>, file: Option<Arc<dyn File>>,
diagnostics: HashMap<usize, DiagnosticSet>, // server_id -> diagnostic set diagnostics: HashMap<LanguageServerId, DiagnosticSet>,
diagnostics_update_count: usize, diagnostics_update_count: usize,
file_update_count: usize, file_update_count: usize,
git_diff_update_count: usize, git_diff_update_count: usize,
@ -157,7 +158,7 @@ pub struct Completion {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct CodeAction { pub struct CodeAction {
pub server_id: usize, pub server_id: LanguageServerId,
pub range: Range<Anchor>, pub range: Range<Anchor>,
pub lsp_action: lsp::CodeAction, pub lsp_action: lsp::CodeAction,
} }
@ -167,7 +168,7 @@ pub enum Operation {
Buffer(text::Operation), Buffer(text::Operation),
UpdateDiagnostics { UpdateDiagnostics {
server_id: usize, server_id: LanguageServerId,
diagnostics: Arc<[DiagnosticEntry<Anchor>]>, diagnostics: Arc<[DiagnosticEntry<Anchor>]>,
lamport_timestamp: clock::Lamport, lamport_timestamp: clock::Lamport,
}, },
@ -879,7 +880,7 @@ impl Buffer {
pub fn update_diagnostics( pub fn update_diagnostics(
&mut self, &mut self,
server_id: usize, server_id: LanguageServerId,
diagnostics: DiagnosticSet, diagnostics: DiagnosticSet,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) { ) {
@ -1645,7 +1646,7 @@ impl Buffer {
fn apply_diagnostic_update( fn apply_diagnostic_update(
&mut self, &mut self,
server_id: usize, server_id: LanguageServerId,
diagnostics: DiagnosticSet, diagnostics: DiagnosticSet,
lamport_timestamp: clock::Lamport, lamport_timestamp: clock::Lamport,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,

View file

@ -1866,7 +1866,7 @@ fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
buffer, buffer,
); );
log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics); log::info!("peer {} setting diagnostics: {:?}", replica_id, diagnostics);
buffer.update_diagnostics(0, diagnostics, cx); buffer.update_diagnostics(LanguageServerId(0), diagnostics, cx);
}); });
mutation_count -= 1; mutation_count -= 1;
} }

View file

@ -54,6 +54,7 @@ use futures::channel::mpsc;
pub use buffer::Operation; pub use buffer::Operation;
pub use buffer::*; pub use buffer::*;
pub use diagnostic_set::DiagnosticEntry; pub use diagnostic_set::DiagnosticEntry;
pub use lsp::LanguageServerId;
pub use outline::{Outline, OutlineItem}; pub use outline::{Outline, OutlineItem};
pub use tree_sitter::{Parser, Tree}; pub use tree_sitter::{Parser, Tree};
@ -524,7 +525,7 @@ struct LanguageRegistryState {
} }
pub struct PendingLanguageServer { pub struct PendingLanguageServer {
pub server_id: usize, pub server_id: LanguageServerId,
pub task: Task<Result<lsp::LanguageServer>>, pub task: Task<Result<lsp::LanguageServer>>,
} }
@ -819,7 +820,7 @@ impl LanguageRegistry {
Ok(server) 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 }); return Some(PendingLanguageServer { server_id, task });
} }
@ -837,7 +838,7 @@ impl LanguageRegistry {
let adapter = adapter.clone(); let adapter = adapter.clone();
let lsp_binary_statuses = self.lsp_binary_statuses_tx.clone(); let lsp_binary_statuses = self.lsp_binary_statuses_tx.clone();
let login_shell_env_loaded = self.login_shell_env_loaded.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 { let task = cx.spawn(|cx| async move {
login_shell_env_loaded.await; login_shell_env_loaded.await;
@ -884,6 +885,10 @@ impl LanguageRegistry {
} }
impl LanguageRegistryState { 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<Language>) { fn add(&mut self, language: Arc<Language>) {
if let Some(theme) = self.theme.as_ref() { if let Some(theme) = self.theme.as_ref() {
language.set_theme(&theme.editor.syntax); language.set_theme(&theme.editor.syntax);

View file

@ -4,7 +4,7 @@ use crate::{
}; };
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use clock::ReplicaId; use clock::ReplicaId;
use lsp::DiagnosticSeverity; use lsp::{DiagnosticSeverity, LanguageServerId};
use rpc::proto; use rpc::proto;
use std::{ops::Range, sync::Arc}; use std::{ops::Range, sync::Arc};
use text::*; use text::*;
@ -80,7 +80,7 @@ pub fn serialize_operation(operation: &crate::Operation) -> proto::Operation {
} => proto::operation::Variant::UpdateDiagnostics(proto::UpdateDiagnostics { } => proto::operation::Variant::UpdateDiagnostics(proto::UpdateDiagnostics {
replica_id: lamport_timestamp.replica_id as u32, replica_id: lamport_timestamp.replica_id as u32,
lamport_timestamp: lamport_timestamp.value, lamport_timestamp: lamport_timestamp.value,
server_id: *server_id as u64, server_id: server_id.0 as u64,
diagnostics: serialize_diagnostics(diagnostics.iter()), diagnostics: serialize_diagnostics(diagnostics.iter()),
}), }),
@ -277,7 +277,7 @@ pub fn deserialize_operation(message: proto::Operation) -> Result<crate::Operati
replica_id: message.replica_id as ReplicaId, replica_id: message.replica_id as ReplicaId,
value: message.lamport_timestamp, value: message.lamport_timestamp,
}, },
server_id: message.server_id as usize, server_id: LanguageServerId(message.server_id as usize),
diagnostics: deserialize_diagnostics(message.diagnostics), diagnostics: deserialize_diagnostics(message.diagnostics),
} }
} }
@ -469,7 +469,7 @@ pub async fn deserialize_completion(
pub fn serialize_code_action(action: &CodeAction) -> proto::CodeAction { pub fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
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)), start: Some(serialize_anchor(&action.range.start)),
end: Some(serialize_anchor(&action.range.end)), end: Some(serialize_anchor(&action.range.end)),
lsp_action: serde_json::to_vec(&action.lsp_action).unwrap(), lsp_action: serde_json::to_vec(&action.lsp_action).unwrap(),
@ -487,7 +487,7 @@ pub fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction>
.ok_or_else(|| anyhow!("invalid end"))?; .ok_or_else(|| anyhow!("invalid end"))?;
let lsp_action = serde_json::from_slice(&action.lsp_action)?; let lsp_action = serde_json::from_slice(&action.lsp_action)?;
Ok(CodeAction { Ok(CodeAction {
server_id: action.server_id as usize, server_id: LanguageServerId(action.server_id as usize),
range: start..end, range: start..end,
lsp_action, lsp_action,
}) })

View file

@ -16,6 +16,7 @@ use smol::{
process::{self, Child}, process::{self, Child},
}; };
use std::{ use std::{
fmt,
future::Future, future::Future,
io::Write, io::Write,
path::PathBuf, path::PathBuf,
@ -35,7 +36,7 @@ type NotificationHandler = Box<dyn Send + FnMut(Option<usize>, &str, AsyncAppCon
type ResponseHandler = Box<dyn Send + FnOnce(Result<&str, Error>)>; type ResponseHandler = Box<dyn Send + FnOnce(Result<&str, Error>)>;
pub struct LanguageServer { pub struct LanguageServer {
server_id: usize, server_id: LanguageServerId,
next_id: AtomicUsize, next_id: AtomicUsize,
outbound_tx: channel::Sender<Vec<u8>>, outbound_tx: channel::Sender<Vec<u8>>,
name: String, name: String,
@ -51,6 +52,10 @@ pub struct LanguageServer {
_server: Option<Child>, _server: Option<Child>,
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct LanguageServerId(pub usize);
pub struct Subscription { pub struct Subscription {
method: &'static str, method: &'static str,
notification_handlers: Arc<Mutex<HashMap<&'static str, NotificationHandler>>>, notification_handlers: Arc<Mutex<HashMap<&'static str, NotificationHandler>>>,
@ -107,7 +112,7 @@ struct Error {
impl LanguageServer { impl LanguageServer {
pub fn new<T: AsRef<std::ffi::OsStr>>( pub fn new<T: AsRef<std::ffi::OsStr>>(
server_id: usize, server_id: LanguageServerId,
binary_path: &Path, binary_path: &Path,
arguments: &[T], arguments: &[T],
root_path: &Path, root_path: &Path,
@ -158,7 +163,7 @@ impl LanguageServer {
} }
fn new_internal<Stdin, Stdout, F>( fn new_internal<Stdin, Stdout, F>(
server_id: usize, server_id: LanguageServerId,
stdin: Stdin, stdin: Stdin,
stdout: Stdout, stdout: Stdout,
server: Option<Child>, server: Option<Child>,
@ -581,7 +586,7 @@ impl LanguageServer {
&self.capabilities &self.capabilities
} }
pub fn server_id(&self) -> usize { pub fn server_id(&self) -> LanguageServerId {
self.server_id 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 { impl Drop for Subscription {
fn drop(&mut self) { fn drop(&mut self) {
self.notification_handlers.lock().remove(self.method); self.notification_handlers.lock().remove(self.method);
@ -720,7 +731,7 @@ impl LanguageServer {
let (notifications_tx, notifications_rx) = channel::unbounded(); let (notifications_tx, notifications_rx) = channel::unbounded();
let server = Self::new_internal( let server = Self::new_internal(
0, LanguageServerId(0),
stdin_writer, stdin_writer,
stdout_reader, stdout_reader,
None, None,
@ -731,7 +742,7 @@ impl LanguageServer {
); );
let fake = FakeLanguageServer { let fake = FakeLanguageServer {
server: Arc::new(Self::new_internal( server: Arc::new(Self::new_internal(
0, LanguageServerId(0),
stdout_writer, stdout_writer,
stdin_reader, stdin_reader,
None, None,

View file

@ -12,7 +12,7 @@ use language::{
range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, CachedLspAdapter, CharKind, CodeAction, range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, CachedLspAdapter, CharKind, CodeAction,
Completion, OffsetRangeExt, PointUtf16, ToOffset, ToPointUtf16, Unclipped, 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 pulldown_cmark::{CodeBlockKind, Event, Options, Parser, Tag};
use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc}; use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc};
@ -39,7 +39,7 @@ pub(crate) trait LspCommand: 'static + Sized {
message: <Self::LspRequest as lsp::request::Request>::Result, message: <Self::LspRequest as lsp::request::Request>::Result,
project: ModelHandle<Project>, project: ModelHandle<Project>,
buffer: ModelHandle<Buffer>, buffer: ModelHandle<Buffer>,
server_id: usize, server_id: LanguageServerId,
cx: AsyncAppContext, cx: AsyncAppContext,
) -> Result<Self::Response>; ) -> Result<Self::Response>;
@ -143,7 +143,7 @@ impl LspCommand for PrepareRename {
message: Option<lsp::PrepareRenameResponse>, message: Option<lsp::PrepareRenameResponse>,
_: ModelHandle<Project>, _: ModelHandle<Project>,
buffer: ModelHandle<Buffer>, buffer: ModelHandle<Buffer>,
_: usize, _: LanguageServerId,
cx: AsyncAppContext, cx: AsyncAppContext,
) -> Result<Option<Range<Anchor>>> { ) -> Result<Option<Range<Anchor>>> {
buffer.read_with(&cx, |buffer, _| { buffer.read_with(&cx, |buffer, _| {
@ -270,7 +270,7 @@ impl LspCommand for PerformRename {
message: Option<lsp::WorkspaceEdit>, message: Option<lsp::WorkspaceEdit>,
project: ModelHandle<Project>, project: ModelHandle<Project>,
buffer: ModelHandle<Buffer>, buffer: ModelHandle<Buffer>,
server_id: usize, server_id: LanguageServerId,
mut cx: AsyncAppContext, mut cx: AsyncAppContext,
) -> Result<ProjectTransaction> { ) -> Result<ProjectTransaction> {
if let Some(edit) = message { if let Some(edit) = message {
@ -389,7 +389,7 @@ impl LspCommand for GetDefinition {
message: Option<lsp::GotoDefinitionResponse>, message: Option<lsp::GotoDefinitionResponse>,
project: ModelHandle<Project>, project: ModelHandle<Project>,
buffer: ModelHandle<Buffer>, buffer: ModelHandle<Buffer>,
server_id: usize, server_id: LanguageServerId,
cx: AsyncAppContext, cx: AsyncAppContext,
) -> Result<Vec<LocationLink>> { ) -> Result<Vec<LocationLink>> {
location_links_from_lsp(message, project, buffer, server_id, cx).await location_links_from_lsp(message, project, buffer, server_id, cx).await
@ -482,7 +482,7 @@ impl LspCommand for GetTypeDefinition {
message: Option<lsp::GotoTypeDefinitionResponse>, message: Option<lsp::GotoTypeDefinitionResponse>,
project: ModelHandle<Project>, project: ModelHandle<Project>,
buffer: ModelHandle<Buffer>, buffer: ModelHandle<Buffer>,
server_id: usize, server_id: LanguageServerId,
cx: AsyncAppContext, cx: AsyncAppContext,
) -> Result<Vec<LocationLink>> { ) -> Result<Vec<LocationLink>> {
location_links_from_lsp(message, project, buffer, server_id, cx).await location_links_from_lsp(message, project, buffer, server_id, cx).await
@ -548,7 +548,7 @@ impl LspCommand for GetTypeDefinition {
fn language_server_for_buffer( fn language_server_for_buffer(
project: &ModelHandle<Project>, project: &ModelHandle<Project>,
buffer: &ModelHandle<Buffer>, buffer: &ModelHandle<Buffer>,
server_id: usize, server_id: LanguageServerId,
cx: &mut AsyncAppContext, cx: &mut AsyncAppContext,
) -> Result<(Arc<CachedLspAdapter>, Arc<LanguageServer>)> { ) -> Result<(Arc<CachedLspAdapter>, Arc<LanguageServer>)> {
project project
@ -626,7 +626,7 @@ async fn location_links_from_lsp(
message: Option<lsp::GotoDefinitionResponse>, message: Option<lsp::GotoDefinitionResponse>,
project: ModelHandle<Project>, project: ModelHandle<Project>,
buffer: ModelHandle<Buffer>, buffer: ModelHandle<Buffer>,
server_id: usize, server_id: LanguageServerId,
mut cx: AsyncAppContext, mut cx: AsyncAppContext,
) -> Result<Vec<LocationLink>> { ) -> Result<Vec<LocationLink>> {
let message = match message { let message = match message {
@ -770,7 +770,7 @@ impl LspCommand for GetReferences {
locations: Option<Vec<lsp::Location>>, locations: Option<Vec<lsp::Location>>,
project: ModelHandle<Project>, project: ModelHandle<Project>,
buffer: ModelHandle<Buffer>, buffer: ModelHandle<Buffer>,
server_id: usize, server_id: LanguageServerId,
mut cx: AsyncAppContext, mut cx: AsyncAppContext,
) -> Result<Vec<Location>> { ) -> Result<Vec<Location>> {
let mut references = Vec::new(); let mut references = Vec::new();
@ -932,7 +932,7 @@ impl LspCommand for GetDocumentHighlights {
lsp_highlights: Option<Vec<lsp::DocumentHighlight>>, lsp_highlights: Option<Vec<lsp::DocumentHighlight>>,
_: ModelHandle<Project>, _: ModelHandle<Project>,
buffer: ModelHandle<Buffer>, buffer: ModelHandle<Buffer>,
_: usize, _: LanguageServerId,
cx: AsyncAppContext, cx: AsyncAppContext,
) -> Result<Vec<DocumentHighlight>> { ) -> Result<Vec<DocumentHighlight>> {
buffer.read_with(&cx, |buffer, _| { buffer.read_with(&cx, |buffer, _| {
@ -1078,7 +1078,7 @@ impl LspCommand for GetHover {
message: Option<lsp::Hover>, message: Option<lsp::Hover>,
_: ModelHandle<Project>, _: ModelHandle<Project>,
buffer: ModelHandle<Buffer>, buffer: ModelHandle<Buffer>,
_: usize, _: LanguageServerId,
cx: AsyncAppContext, cx: AsyncAppContext,
) -> Result<Self::Response> { ) -> Result<Self::Response> {
Ok(message.and_then(|hover| { Ok(message.and_then(|hover| {
@ -1300,7 +1300,7 @@ impl LspCommand for GetCompletions {
completions: Option<lsp::CompletionResponse>, completions: Option<lsp::CompletionResponse>,
_: ModelHandle<Project>, _: ModelHandle<Project>,
buffer: ModelHandle<Buffer>, buffer: ModelHandle<Buffer>,
_: usize, _: LanguageServerId,
cx: AsyncAppContext, cx: AsyncAppContext,
) -> Result<Vec<Completion>> { ) -> Result<Vec<Completion>> {
let completions = if let Some(completions) = completions { let completions = if let Some(completions) = completions {
@ -1520,7 +1520,7 @@ impl LspCommand for GetCodeActions {
actions: Option<lsp::CodeActionResponse>, actions: Option<lsp::CodeActionResponse>,
_: ModelHandle<Project>, _: ModelHandle<Project>,
_: ModelHandle<Buffer>, _: ModelHandle<Buffer>,
server_id: usize, server_id: LanguageServerId,
_: AsyncAppContext, _: AsyncAppContext,
) -> Result<Vec<CodeAction>> { ) -> Result<Vec<CodeAction>> {
Ok(actions Ok(actions

View file

@ -36,7 +36,7 @@ use language::{
}; };
use lsp::{ use lsp::{
DiagnosticSeverity, DiagnosticTag, DidChangeWatchedFilesRegistrationOptions, DiagnosticSeverity, DiagnosticTag, DidChangeWatchedFilesRegistrationOptions,
DocumentHighlightKind, LanguageServer, LanguageString, MarkedString, DocumentHighlightKind, LanguageServer, LanguageServerId, LanguageString, MarkedString,
}; };
use lsp_command::*; use lsp_command::*;
use lsp_glob_set::LspGlobSet; use lsp_glob_set::LspGlobSet;
@ -95,10 +95,10 @@ pub struct Project {
active_entry: Option<ProjectEntryId>, active_entry: Option<ProjectEntryId>,
buffer_changes_tx: mpsc::UnboundedSender<BufferMessage>, buffer_changes_tx: mpsc::UnboundedSender<BufferMessage>,
languages: Arc<LanguageRegistry>, languages: Arc<LanguageRegistry>,
language_servers: HashMap<usize, LanguageServerState>, language_servers: HashMap<LanguageServerId, LanguageServerState>,
language_server_ids: HashMap<(WorktreeId, LanguageServerName), usize>, language_server_ids: HashMap<(WorktreeId, LanguageServerName), LanguageServerId>,
language_server_statuses: BTreeMap<usize, LanguageServerStatus>, language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
last_workspace_edits_by_language_server: HashMap<usize, ProjectTransaction>, last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
client: Arc<client::Client>, client: Arc<client::Client>,
next_entry_id: Arc<AtomicUsize>, next_entry_id: Arc<AtomicUsize>,
join_project_response_message_id: u32, 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. /// 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 /// Used for re-issuing buffer requests when peers temporarily disconnect
incomplete_remote_buffers: HashMap<u64, Option<ModelHandle<Buffer>>>, incomplete_remote_buffers: HashMap<u64, Option<ModelHandle<Buffer>>>,
buffer_snapshots: HashMap<u64, HashMap<usize, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots buffer_snapshots: HashMap<u64, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
buffers_being_formatted: HashSet<usize>, buffers_being_formatted: HashSet<usize>,
nonce: u128, nonce: u128,
_maintain_buffer_languages: Task<()>, _maintain_buffer_languages: Task<()>,
@ -189,14 +189,14 @@ pub enum Event {
WorktreeAdded, WorktreeAdded,
WorktreeRemoved(WorktreeId), WorktreeRemoved(WorktreeId),
DiskBasedDiagnosticsStarted { DiskBasedDiagnosticsStarted {
language_server_id: usize, language_server_id: LanguageServerId,
}, },
DiskBasedDiagnosticsFinished { DiskBasedDiagnosticsFinished {
language_server_id: usize, language_server_id: LanguageServerId,
}, },
DiagnosticsUpdated { DiagnosticsUpdated {
path: ProjectPath, path: ProjectPath,
language_server_id: usize, language_server_id: LanguageServerId,
}, },
RemoteIdChanged(Option<u64>), RemoteIdChanged(Option<u64>),
DisconnectedFromHost, DisconnectedFromHost,
@ -336,10 +336,14 @@ impl DiagnosticSummary {
self.error_count == 0 && self.warning_count == 0 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 { proto::DiagnosticSummary {
path: path.to_string_lossy().to_string(), 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, error_count: self.error_count as u32,
warning_count: self.warning_count as u32, warning_count: self.warning_count as u32,
} }
@ -541,7 +545,7 @@ impl Project {
.into_iter() .into_iter()
.map(|server| { .map(|server| {
( (
server.id as usize, LanguageServerId(server.id as usize),
LanguageServerStatus { LanguageServerStatus {
name: server.name, name: server.name,
pending_work: Default::default(), pending_work: Default::default(),
@ -1025,7 +1029,7 @@ impl Project {
.send(proto::StartLanguageServer { .send(proto::StartLanguageServer {
project_id, project_id,
server: Some(proto::LanguageServer { server: Some(proto::LanguageServer {
id: *server_id as u64, id: server_id.0 as u64,
name: status.name.clone(), name: status.name.clone(),
}), }),
}) })
@ -1152,7 +1156,7 @@ impl Project {
.into_iter() .into_iter()
.map(|server| { .map(|server| {
( (
server.id as usize, LanguageServerId(server.id as usize),
LanguageServerStatus { LanguageServerStatus {
name: server.name, name: server.name,
pending_work: Default::default(), pending_work: Default::default(),
@ -1444,7 +1448,7 @@ impl Project {
fn open_local_buffer_via_lsp( fn open_local_buffer_via_lsp(
&mut self, &mut self,
abs_path: lsp::Url, abs_path: lsp::Url,
language_server_id: usize, language_server_id: LanguageServerId,
language_server_name: LanguageServerName, language_server_name: LanguageServerName,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) -> Task<Result<ModelHandle<Buffer>>> { ) -> Task<Result<ModelHandle<Buffer>>> {
@ -2381,7 +2385,7 @@ impl Project {
.send(proto::StartLanguageServer { .send(proto::StartLanguageServer {
project_id, project_id,
server: Some(proto::LanguageServer { server: Some(proto::LanguageServer {
id: server_id as u64, id: server_id.0 as u64,
name: language_server.name().to_string(), name: language_server.name().to_string(),
}), }),
}) })
@ -2603,7 +2607,7 @@ impl Project {
fn on_lsp_progress( fn on_lsp_progress(
&mut self, &mut self,
progress: lsp::ProgressParams, progress: lsp::ProgressParams,
server_id: usize, server_id: LanguageServerId,
disk_based_diagnostics_progress_token: Option<String>, disk_based_diagnostics_progress_token: Option<String>,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) { ) {
@ -2715,7 +2719,7 @@ impl Project {
fn on_lsp_work_start( fn on_lsp_work_start(
&mut self, &mut self,
language_server_id: usize, language_server_id: LanguageServerId,
token: String, token: String,
progress: LanguageServerProgress, progress: LanguageServerProgress,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
@ -2728,7 +2732,7 @@ impl Project {
fn on_lsp_work_progress( fn on_lsp_work_progress(
&mut self, &mut self,
language_server_id: usize, language_server_id: LanguageServerId,
token: String, token: String,
progress: LanguageServerProgress, progress: LanguageServerProgress,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
@ -2755,7 +2759,7 @@ impl Project {
fn on_lsp_work_end( fn on_lsp_work_end(
&mut self, &mut self,
language_server_id: usize, language_server_id: LanguageServerId,
token: String, token: String,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) { ) {
@ -2767,7 +2771,7 @@ impl Project {
fn on_lsp_did_change_watched_files( fn on_lsp_did_change_watched_files(
&mut self, &mut self,
language_server_id: usize, language_server_id: LanguageServerId,
params: DidChangeWatchedFilesRegistrationOptions, params: DidChangeWatchedFilesRegistrationOptions,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) { ) {
@ -2785,7 +2789,7 @@ impl Project {
async fn on_lsp_workspace_edit( async fn on_lsp_workspace_edit(
this: WeakModelHandle<Self>, this: WeakModelHandle<Self>,
params: lsp::ApplyWorkspaceEditParams, params: lsp::ApplyWorkspaceEditParams,
server_id: usize, server_id: LanguageServerId,
adapter: Arc<CachedLspAdapter>, adapter: Arc<CachedLspAdapter>,
language_server: Arc<LanguageServer>, language_server: Arc<LanguageServer>,
mut cx: AsyncAppContext, mut cx: AsyncAppContext,
@ -2818,14 +2822,14 @@ impl Project {
fn broadcast_language_server_update( fn broadcast_language_server_update(
&self, &self,
language_server_id: usize, language_server_id: LanguageServerId,
event: proto::update_language_server::Variant, event: proto::update_language_server::Variant,
) { ) {
if let Some(project_id) = self.remote_id() { if let Some(project_id) = self.remote_id() {
self.client self.client
.send(proto::UpdateLanguageServer { .send(proto::UpdateLanguageServer {
project_id, project_id,
language_server_id: language_server_id as u64, language_server_id: language_server_id.0 as u64,
variant: Some(event), variant: Some(event),
}) })
.log_err(); .log_err();
@ -2840,7 +2844,7 @@ impl Project {
pub fn update_diagnostics( pub fn update_diagnostics(
&mut self, &mut self,
language_server_id: usize, language_server_id: LanguageServerId,
mut params: lsp::PublishDiagnosticsParams, mut params: lsp::PublishDiagnosticsParams,
disk_based_sources: &[String], disk_based_sources: &[String],
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
@ -2960,7 +2964,7 @@ impl Project {
pub fn update_diagnostic_entries( pub fn update_diagnostic_entries(
&mut self, &mut self,
server_id: usize, server_id: LanguageServerId,
abs_path: PathBuf, abs_path: PathBuf,
version: Option<i32>, version: Option<i32>,
diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>, diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
@ -2997,7 +3001,7 @@ impl Project {
fn update_buffer_diagnostics( fn update_buffer_diagnostics(
&mut self, &mut self,
buffer: &ModelHandle<Buffer>, buffer: &ModelHandle<Buffer>,
server_id: usize, server_id: LanguageServerId,
version: Option<i32>, version: Option<i32>,
mut diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>, mut diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
@ -4712,7 +4716,7 @@ impl Project {
pub fn language_servers_running_disk_based_diagnostics( pub fn language_servers_running_disk_based_diagnostics(
&self, &self,
) -> impl Iterator<Item = usize> + '_ { ) -> impl Iterator<Item = LanguageServerId> + '_ {
self.language_server_statuses self.language_server_statuses
.iter() .iter()
.filter_map(|(id, status)| { .filter_map(|(id, status)| {
@ -4736,7 +4740,7 @@ impl Project {
pub fn diagnostic_summaries<'a>( pub fn diagnostic_summaries<'a>(
&'a self, &'a self,
cx: &'a AppContext, cx: &'a AppContext,
) -> impl Iterator<Item = (ProjectPath, usize, DiagnosticSummary)> + 'a { ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
self.visible_worktrees(cx).flat_map(move |worktree| { self.visible_worktrees(cx).flat_map(move |worktree| {
let worktree = worktree.read(cx); let worktree = worktree.read(cx);
let worktree_id = worktree.id(); let worktree_id = worktree.id();
@ -4750,7 +4754,7 @@ impl Project {
pub fn disk_based_diagnostics_started( pub fn disk_based_diagnostics_started(
&mut self, &mut self,
language_server_id: usize, language_server_id: LanguageServerId,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) { ) {
cx.emit(Event::DiskBasedDiagnosticsStarted { language_server_id }); cx.emit(Event::DiskBasedDiagnosticsStarted { language_server_id });
@ -4758,7 +4762,7 @@ impl Project {
pub fn disk_based_diagnostics_finished( pub fn disk_based_diagnostics_finished(
&mut self, &mut self,
language_server_id: usize, language_server_id: LanguageServerId,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) { ) {
cx.emit(Event::DiskBasedDiagnosticsFinished { language_server_id }); cx.emit(Event::DiskBasedDiagnosticsFinished { language_server_id });
@ -5065,7 +5069,7 @@ impl Project {
.update_diagnostic_summary(project_path.path.clone(), &summary); .update_diagnostic_summary(project_path.path.clone(), &summary);
}); });
cx.emit(Event::DiagnosticsUpdated { 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, path: project_path,
}); });
} }
@ -5086,7 +5090,7 @@ impl Project {
.ok_or_else(|| anyhow!("invalid server"))?; .ok_or_else(|| anyhow!("invalid server"))?;
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
this.language_server_statuses.insert( this.language_server_statuses.insert(
server.id as usize, LanguageServerId(server.id as usize),
LanguageServerStatus { LanguageServerStatus {
name: server.name, name: server.name,
pending_work: Default::default(), pending_work: Default::default(),
@ -5106,7 +5110,7 @@ impl Project {
mut cx: AsyncAppContext, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<()> {
this.update(&mut cx, |this, cx| { 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 match envelope
.payload .payload
@ -6142,7 +6146,7 @@ impl Project {
&mut self, &mut self,
buffer: &ModelHandle<Buffer>, buffer: &ModelHandle<Buffer>,
lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>, lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
server_id: usize, server_id: LanguageServerId,
version: Option<i32>, version: Option<i32>,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) -> Task<Result<Vec<(Range<Anchor>, String)>>> { ) -> Task<Result<Vec<(Range<Anchor>, String)>>> {
@ -6245,7 +6249,7 @@ impl Project {
fn buffer_snapshot_for_lsp_version( fn buffer_snapshot_for_lsp_version(
&mut self, &mut self,
buffer: &ModelHandle<Buffer>, buffer: &ModelHandle<Buffer>,
server_id: usize, server_id: LanguageServerId,
version: Option<i32>, version: Option<i32>,
cx: &AppContext, cx: &AppContext,
) -> Result<TextBufferSnapshot> { ) -> Result<TextBufferSnapshot> {
@ -6314,14 +6318,18 @@ impl Project {
fn language_server_for_buffer( fn language_server_for_buffer(
&self, &self,
buffer: &Buffer, buffer: &Buffer,
server_id: usize, server_id: LanguageServerId,
cx: &AppContext, cx: &AppContext,
) -> Option<(&Arc<CachedLspAdapter>, &Arc<LanguageServer>)> { ) -> Option<(&Arc<CachedLspAdapter>, &Arc<LanguageServer>)> {
self.language_servers_iter_for_buffer(buffer, cx) self.language_servers_iter_for_buffer(buffer, cx)
.find(|(_, s)| s.server_id() == server_id) .find(|(_, s)| s.server_id() == server_id)
} }
fn language_server_ids_for_buffer(&self, buffer: &Buffer, cx: &AppContext) -> Vec<usize> { fn language_server_ids_for_buffer(
&self,
buffer: &Buffer,
cx: &AppContext,
) -> Vec<LanguageServerId> {
if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) { if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
let worktree_id = file.worktree_id(cx); let worktree_id = file.worktree_id(cx);
language language

View file

@ -303,7 +303,7 @@ async fn test_managing_language_servers(
rust_buffer2.update(cx, |buffer, cx| { rust_buffer2.update(cx, |buffer, cx| {
buffer.update_diagnostics( buffer.update_diagnostics(
0, LanguageServerId(0),
DiagnosticSet::from_sorted_entries( DiagnosticSet::from_sorted_entries(
vec![DiagnosticEntry { vec![DiagnosticEntry {
diagnostic: Default::default(), 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(cx, |project, cx| {
project project
.update_diagnostics( .update_diagnostics(
0, LanguageServerId(0),
lsp::PublishDiagnosticsParams { lsp::PublishDiagnosticsParams {
uri: Url::from_file_path("/dir/a.rs").unwrap(), uri: Url::from_file_path("/dir/a.rs").unwrap(),
version: None, version: None,
@ -599,7 +599,7 @@ async fn test_single_file_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
.unwrap(); .unwrap();
project project
.update_diagnostics( .update_diagnostics(
0, LanguageServerId(0),
lsp::PublishDiagnosticsParams { lsp::PublishDiagnosticsParams {
uri: Url::from_file_path("/dir/b.rs").unwrap(), uri: Url::from_file_path("/dir/b.rs").unwrap(),
version: None, version: None,
@ -675,7 +675,7 @@ async fn test_hidden_worktrees_diagnostics(cx: &mut gpui::TestAppContext) {
project.update(cx, |project, cx| { project.update(cx, |project, cx| {
project project
.update_diagnostics( .update_diagnostics(
0, LanguageServerId(0),
lsp::PublishDiagnosticsParams { lsp::PublishDiagnosticsParams {
uri: Url::from_file_path("/root/other.rs").unwrap(), uri: Url::from_file_path("/root/other.rs").unwrap(),
version: None, version: None,
@ -767,7 +767,7 @@ async fn test_disk_based_diagnostics_progress(cx: &mut gpui::TestAppContext) {
assert_eq!( assert_eq!(
events.next().await.unwrap(), events.next().await.unwrap(),
Event::DiskBasedDiagnosticsStarted { 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!( assert_eq!(
events.next().await.unwrap(), events.next().await.unwrap(),
Event::DiagnosticsUpdated { Event::DiagnosticsUpdated {
language_server_id: 0, language_server_id: LanguageServerId(0),
path: (worktree_id, Path::new("a.rs")).into() 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!( assert_eq!(
events.next().await.unwrap(), events.next().await.unwrap(),
Event::DiskBasedDiagnosticsFinished { 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!( assert_eq!(
events.next().await.unwrap(), events.next().await.unwrap(),
Event::DiagnosticsUpdated { Event::DiagnosticsUpdated {
language_server_id: 0, language_server_id: LanguageServerId(0),
path: (worktree_id, Path::new("a.rs")).into() 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!( assert_eq!(
events.next().await.unwrap(), events.next().await.unwrap(),
Event::DiskBasedDiagnosticsStarted { Event::DiskBasedDiagnosticsStarted {
language_server_id: 1 language_server_id: LanguageServerId(1)
} }
); );
project.read_with(cx, |project, _| { project.read_with(cx, |project, _| {
@ -900,7 +900,7 @@ async fn test_restarting_server_with_diagnostics_running(cx: &mut gpui::TestAppC
project project
.language_servers_running_disk_based_diagnostics() .language_servers_running_disk_based_diagnostics()
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
[1] [LanguageServerId(1)]
); );
}); });
@ -910,7 +910,7 @@ async fn test_restarting_server_with_diagnostics_running(cx: &mut gpui::TestAppC
assert_eq!( assert_eq!(
events.next().await.unwrap(), events.next().await.unwrap(),
Event::DiskBasedDiagnosticsFinished { Event::DiskBasedDiagnosticsFinished {
language_server_id: 1 language_server_id: LanguageServerId(1)
} }
); );
project.read_with(cx, |project, _| { project.read_with(cx, |project, _| {
@ -918,7 +918,7 @@ async fn test_restarting_server_with_diagnostics_running(cx: &mut gpui::TestAppC
project project
.language_servers_running_disk_based_diagnostics() .language_servers_running_disk_based_diagnostics()
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
[0; 0] [LanguageServerId(0); 0]
); );
}); });
} }
@ -1403,7 +1403,7 @@ async fn test_empty_diagnostic_ranges(cx: &mut gpui::TestAppContext) {
project project
.update_buffer_diagnostics( .update_buffer_diagnostics(
&buffer, &buffer,
0, LanguageServerId(0),
None, None,
vec![ vec![
DiagnosticEntry { DiagnosticEntry {
@ -1464,7 +1464,7 @@ async fn test_diagnostics_from_multiple_language_servers(cx: &mut gpui::TestAppC
project.update(cx, |project, cx| { project.update(cx, |project, cx| {
project project
.update_diagnostic_entries( .update_diagnostic_entries(
0, LanguageServerId(0),
Path::new("/dir/a.rs").to_owned(), Path::new("/dir/a.rs").to_owned(),
None, None,
vec![DiagnosticEntry { vec![DiagnosticEntry {
@ -1481,7 +1481,7 @@ async fn test_diagnostics_from_multiple_language_servers(cx: &mut gpui::TestAppC
.unwrap(); .unwrap();
project project
.update_diagnostic_entries( .update_diagnostic_entries(
1, LanguageServerId(1),
Path::new("/dir/a.rs").to_owned(), Path::new("/dir/a.rs").to_owned(),
None, None,
vec![DiagnosticEntry { vec![DiagnosticEntry {
@ -1633,7 +1633,7 @@ async fn test_edits_from_lsp_with_past_version(cx: &mut gpui::TestAppContext) {
new_text: "".into(), new_text: "".into(),
}, },
], ],
0, LanguageServerId(0),
Some(lsp_document_version), Some(lsp_document_version),
cx, cx,
) )
@ -1728,7 +1728,7 @@ async fn test_edits_from_lsp_with_edits_on_adjacent_lines(cx: &mut gpui::TestApp
new_text: "".into(), new_text: "".into(),
}, },
], ],
0, LanguageServerId(0),
None, None,
cx, cx,
) )
@ -1832,7 +1832,7 @@ async fn test_invalid_edits_from_lsp(cx: &mut gpui::TestAppContext) {
.unindent(), .unindent(),
}, },
], ],
0, LanguageServerId(0),
None, None,
cx, cx,
) )
@ -3011,7 +3011,9 @@ async fn test_grouped_diagnostics(cx: &mut gpui::TestAppContext) {
}; };
project project
.update(cx, |p, cx| p.update_diagnostics(0, message, &[], cx)) .update(cx, |p, cx| {
p.update_diagnostics(LanguageServerId(0), message, &[], cx)
})
.unwrap(); .unwrap();
let buffer = buffer.read_with(cx, |buffer, _| buffer.snapshot()); let buffer = buffer.read_with(cx, |buffer, _| buffer.snapshot());

View file

@ -26,6 +26,7 @@ use language::{
}, },
Buffer, DiagnosticEntry, File as _, PointUtf16, Rope, RopeFingerprint, Unclipped, Buffer, DiagnosticEntry, File as _, PointUtf16, Rope, RopeFingerprint, Unclipped,
}; };
use lsp::LanguageServerId;
use parking_lot::Mutex; use parking_lot::Mutex;
use postage::{ use postage::{
barrier, barrier,
@ -67,8 +68,14 @@ pub struct LocalWorktree {
is_scanning: (watch::Sender<bool>, watch::Receiver<bool>), is_scanning: (watch::Sender<bool>, watch::Receiver<bool>),
_background_scanner_task: Task<()>, _background_scanner_task: Task<()>,
share: Option<ShareState>, share: Option<ShareState>,
diagnostics: HashMap<Arc<Path>, Vec<(usize, Vec<DiagnosticEntry<Unclipped<PointUtf16>>>)>>, diagnostics: HashMap<
diagnostic_summaries: HashMap<Arc<Path>, HashMap<usize, DiagnosticSummary>>, Arc<Path>,
Vec<(
LanguageServerId,
Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
)>,
>,
diagnostic_summaries: HashMap<Arc<Path>, HashMap<LanguageServerId, DiagnosticSummary>>,
client: Arc<Client>, client: Arc<Client>,
fs: Arc<dyn Fs>, fs: Arc<dyn Fs>,
visible: bool, visible: bool,
@ -82,7 +89,7 @@ pub struct RemoteWorktree {
updates_tx: Option<UnboundedSender<proto::UpdateWorktree>>, updates_tx: Option<UnboundedSender<proto::UpdateWorktree>>,
snapshot_subscriptions: VecDeque<(usize, oneshot::Sender<()>)>, snapshot_subscriptions: VecDeque<(usize, oneshot::Sender<()>)>,
replica_id: ReplicaId, replica_id: ReplicaId,
diagnostic_summaries: HashMap<Arc<Path>, HashMap<usize, DiagnosticSummary>>, diagnostic_summaries: HashMap<Arc<Path>, HashMap<LanguageServerId, DiagnosticSummary>>,
visible: bool, visible: bool,
disconnected: bool, disconnected: bool,
} }
@ -463,7 +470,7 @@ impl Worktree {
pub fn diagnostic_summaries( pub fn diagnostic_summaries(
&self, &self,
) -> impl Iterator<Item = (Arc<Path>, usize, DiagnosticSummary)> + '_ { ) -> impl Iterator<Item = (Arc<Path>, LanguageServerId, DiagnosticSummary)> + '_ {
match self { match self {
Worktree::Local(worktree) => &worktree.diagnostic_summaries, Worktree::Local(worktree) => &worktree.diagnostic_summaries,
Worktree::Remote(worktree) => &worktree.diagnostic_summaries, Worktree::Remote(worktree) => &worktree.diagnostic_summaries,
@ -518,13 +525,16 @@ impl LocalWorktree {
pub fn diagnostics_for_path( pub fn diagnostics_for_path(
&self, &self,
path: &Path, path: &Path,
) -> Vec<(usize, Vec<DiagnosticEntry<Unclipped<PointUtf16>>>)> { ) -> Vec<(
LanguageServerId,
Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
)> {
self.diagnostics.get(path).cloned().unwrap_or_default() self.diagnostics.get(path).cloned().unwrap_or_default()
} }
pub fn update_diagnostics( pub fn update_diagnostics(
&mut self, &mut self,
server_id: usize, server_id: LanguageServerId,
worktree_path: Arc<Path>, worktree_path: Arc<Path>,
diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>, diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
_: &mut ModelContext<Worktree>, _: &mut ModelContext<Worktree>,
@ -570,7 +580,7 @@ impl LocalWorktree {
worktree_id: self.id().to_proto(), worktree_id: self.id().to_proto(),
summary: Some(proto::DiagnosticSummary { summary: Some(proto::DiagnosticSummary {
path: worktree_path.to_string_lossy().to_string(), 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, error_count: new_summary.error_count as u32,
warning_count: new_summary.warning_count as u32, warning_count: new_summary.warning_count as u32,
}), }),
@ -1135,7 +1145,7 @@ impl RemoteWorktree {
path: Arc<Path>, path: Arc<Path>,
summary: &proto::DiagnosticSummary, 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 { let summary = DiagnosticSummary {
error_count: summary.error_count as usize, error_count: summary.error_count as usize,
warning_count: summary.warning_count as usize, warning_count: summary.warning_count as usize,