@@ -51,8 +51,7 @@ pub struct Project {
languages: Arc<LanguageRegistry>,
language_servers: HashMap<(WorktreeId, Arc<str>), Arc<LanguageServer>>,
started_language_servers: HashMap<(WorktreeId, Arc<str>), Task<Option<Arc<LanguageServer>>>>,
- pending_language_server_work: BTreeMap<(usize, String), LanguageServerProgress>,
- language_server_names: HashMap<usize, String>,
+ language_server_statuses: BTreeMap<usize, LanguageServerStatus>,
next_language_server_id: usize,
client: Arc<client::Client>,
user_store: ModelHandle<UserStore>,
@@ -131,6 +130,12 @@ enum LanguageServerEvent {
DiagnosticsUpdate(lsp::PublishDiagnosticsParams),
}
+pub struct LanguageServerStatus {
+ pub name: String,
+ pub pending_work: BTreeMap<String, LanguageServerProgress>,
+ pending_diagnostic_updates: isize,
+}
+
#[derive(Clone, Default)]
pub struct LanguageServerProgress {
pub message: Option<String>,
@@ -326,8 +331,7 @@ impl Project {
language_servers_with_diagnostics_running: 0,
language_servers: Default::default(),
started_language_servers: Default::default(),
- pending_language_server_work: Default::default(),
- language_server_names: Default::default(),
+ language_server_statuses: Default::default(),
next_language_server_id: 0,
nonce: StdRng::from_entropy().gen(),
}
@@ -398,11 +402,19 @@ impl Project {
language_servers_with_diagnostics_running: 0,
language_servers: Default::default(),
started_language_servers: Default::default(),
- pending_language_server_work: Default::default(),
- language_server_names: response
+ language_server_statuses: response
.language_servers
.into_iter()
- .map(|s| (s.id as usize, s.name))
+ .map(|server| {
+ (
+ server.id as usize,
+ LanguageServerStatus {
+ name: server.name,
+ pending_work: Default::default(),
+ pending_diagnostic_updates: 0,
+ },
+ )
+ })
.collect(),
next_language_server_id: 0,
opened_buffers: Default::default(),
@@ -1274,8 +1286,14 @@ impl Project {
this.update(&mut cx, |this, cx| {
this.language_servers
.insert(key.clone(), language_server.clone());
- this.language_server_names
- .insert(server_id, language_server.name().to_string());
+ this.language_server_statuses.insert(
+ server_id,
+ LanguageServerStatus {
+ name: language_server.name().to_string(),
+ pending_work: Default::default(),
+ pending_diagnostic_updates: 0,
+ },
+ );
if let Some(project_id) = this.remote_id() {
this.client
@@ -1359,16 +1377,26 @@ impl Project {
cx: &mut ModelContext<Self>,
) {
let disk_diagnostics_token = language.disk_based_diagnostics_progress_token();
+ let language_server_status =
+ if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
+ status
+ } else {
+ return;
+ };
+
match event {
LanguageServerEvent::WorkStart { token } => {
if Some(&token) == disk_diagnostics_token {
- self.disk_based_diagnostics_started(cx);
- self.broadcast_language_server_update(
- language_server_id,
- proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
- proto::LspDiskBasedDiagnosticsUpdating {},
- ),
- );
+ language_server_status.pending_diagnostic_updates += 1;
+ if language_server_status.pending_diagnostic_updates == 1 {
+ self.disk_based_diagnostics_started(cx);
+ self.broadcast_language_server_update(
+ language_server_id,
+ proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
+ proto::LspDiskBasedDiagnosticsUpdating {},
+ ),
+ );
+ }
} else {
self.on_lsp_work_start(language_server_id, token.clone(), cx);
self.broadcast_language_server_update(
@@ -1401,13 +1429,16 @@ impl Project {
}
LanguageServerEvent::WorkEnd { token } => {
if Some(&token) == disk_diagnostics_token {
- self.disk_based_diagnostics_finished(cx);
- self.broadcast_language_server_update(
- language_server_id,
- proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
- proto::LspDiskBasedDiagnosticsUpdated {},
- ),
- );
+ language_server_status.pending_diagnostic_updates -= 1;
+ if language_server_status.pending_diagnostic_updates == 0 {
+ self.disk_based_diagnostics_finished(cx);
+ self.broadcast_language_server_update(
+ language_server_id,
+ proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
+ proto::LspDiskBasedDiagnosticsUpdated {},
+ ),
+ );
+ }
} else {
self.on_lsp_work_end(language_server_id, token.clone(), cx);
self.broadcast_language_server_update(
@@ -1457,14 +1488,16 @@ impl Project {
token: String,
cx: &mut ModelContext<Self>,
) {
- self.pending_language_server_work.insert(
- (language_server_id, token),
- LanguageServerProgress {
- message: None,
- percentage: None,
- },
- );
- cx.notify();
+ if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
+ status.pending_work.insert(
+ token,
+ LanguageServerProgress {
+ message: None,
+ percentage: None,
+ },
+ );
+ cx.notify();
+ }
}
fn on_lsp_work_progress(
@@ -1474,9 +1507,10 @@ impl Project {
progress: LanguageServerProgress,
cx: &mut ModelContext<Self>,
) {
- self.pending_language_server_work
- .insert((language_server_id, token), progress);
- cx.notify();
+ if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
+ status.pending_work.insert(token, progress);
+ cx.notify();
+ }
}
fn on_lsp_work_end(
@@ -1485,9 +1519,10 @@ impl Project {
token: String,
cx: &mut ModelContext<Self>,
) {
- self.pending_language_server_work
- .remove(&(language_server_id, token));
- cx.notify();
+ if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
+ status.pending_work.remove(&token);
+ cx.notify();
+ }
}
fn broadcast_language_server_update(
@@ -1506,15 +1541,8 @@ impl Project {
}
}
- pub fn pending_language_server_work(
- &self,
- ) -> impl Iterator<Item = (&str, &str, &LanguageServerProgress)> {
- self.pending_language_server_work.iter().filter_map(
- |((language_server_id, token), progress)| {
- let name = self.language_server_names.get(language_server_id)?;
- Some((name.as_str(), token.as_str(), progress))
- },
- )
+ pub fn language_server_statuses(&self) -> impl Iterator<Item = &LanguageServerStatus> {
+ self.language_server_statuses.values()
}
pub fn update_diagnostics(
@@ -3266,8 +3294,14 @@ impl Project {
.server
.ok_or_else(|| anyhow!("invalid server"))?;
this.update(&mut cx, |this, cx| {
- this.language_server_names
- .insert(server.id as usize, server.name);
+ this.language_server_statuses.insert(
+ server.id as usize,
+ LanguageServerStatus {
+ name: server.name,
+ pending_work: Default::default(),
+ pending_diagnostic_updates: 0,
+ },
+ );
cx.notify();
});
Ok(())
@@ -1,12 +1,13 @@
use crate::{ItemViewHandle, Settings, StatusItemView};
use futures::StreamExt;
+use gpui::AppContext;
use gpui::{
action, elements::*, platform::CursorStyle, Entity, ModelHandle, MutableAppContext,
RenderContext, View, ViewContext,
};
use language::{LanguageRegistry, LanguageServerBinaryStatus};
use postage::watch;
-use project::Project;
+use project::{LanguageServerProgress, Project};
use std::fmt::Write;
use std::sync::Arc;
@@ -81,6 +82,27 @@ impl LspStatus {
self.failed.clear();
cx.notify();
}
+
+ fn pending_language_server_work<'a>(
+ &self,
+ cx: &'a AppContext,
+ ) -> impl Iterator<Item = (&'a str, &'a str, &'a LanguageServerProgress)> {
+ self.project
+ .read(cx)
+ .language_server_statuses()
+ .filter_map(|status| {
+ if status.pending_work.is_empty() {
+ None
+ } else {
+ Some(
+ status.pending_work.iter().map(|(token, progress)| {
+ (status.name.as_str(), token.as_str(), progress)
+ }),
+ )
+ }
+ })
+ .flatten()
+ }
}
impl Entity for LspStatus {
@@ -95,7 +117,7 @@ impl View for LspStatus {
fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
let theme = &self.settings_rx.borrow().theme;
- let mut pending_work = self.project.read(cx).pending_language_server_work();
+ let mut pending_work = self.pending_language_server_work(cx);
if let Some((lang_server_name, progress_token, progress)) = pending_work.next() {
let mut message = lang_server_name.to_string();