Show more information in lsp status bar item

* Distinguish between checking for updates and downloading
* Show dismissable error message when downloading failed and there
  is no cached server.

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Max Brunsfeld 2022-02-21 16:11:40 -08:00
parent ededfff3a8
commit 79910ba931
6 changed files with 263 additions and 90 deletions

View file

@ -1,13 +1,24 @@
use crate::{ItemViewHandle, Settings, StatusItemView};
use futures::StreamExt;
use gpui::{elements::*, Entity, RenderContext, View, ViewContext};
use language::LanguageRegistry;
use gpui::{
action, elements::*, platform::CursorStyle, Entity, MutableAppContext, RenderContext, View,
ViewContext,
};
use language::{LanguageRegistry, LanguageServerBinaryStatus};
use postage::watch;
use std::sync::Arc;
action!(DismissErrorMessage);
pub struct LspStatus {
pending_lsp_binaries: usize,
settings_rx: watch::Receiver<Settings>,
checking_for_update: Vec<String>,
downloading: Vec<String>,
failed: Vec<String>,
}
pub fn init(cx: &mut MutableAppContext) {
cx.add_action(LspStatus::dismiss_error_message);
}
impl LspStatus {
@ -16,12 +27,33 @@ impl LspStatus {
settings_rx: watch::Receiver<Settings>,
cx: &mut ViewContext<Self>,
) -> Self {
let mut pending_lsp_binaries = languages.pending_lsp_binaries();
let mut status_events = languages.language_server_binary_statuses();
cx.spawn_weak(|this, mut cx| async move {
while let Some(pending_lsp_binaries) = pending_lsp_binaries.next().await {
while let Some((language, event)) = status_events.next().await {
if let Some(this) = this.upgrade(&cx) {
this.update(&mut cx, |this, cx| {
this.pending_lsp_binaries = pending_lsp_binaries;
for vector in [
&mut this.checking_for_update,
&mut this.downloading,
&mut this.failed,
] {
vector.retain(|name| name != language.name());
}
match event {
LanguageServerBinaryStatus::CheckingForUpdate => {
this.checking_for_update.push(language.name().to_string());
}
LanguageServerBinaryStatus::Downloading => {
this.downloading.push(language.name().to_string());
}
LanguageServerBinaryStatus::Failed => {
this.failed.push(language.name().to_string());
}
LanguageServerBinaryStatus::Downloaded
| LanguageServerBinaryStatus::Cached => {}
}
cx.notify();
});
} else {
@ -31,10 +63,17 @@ impl LspStatus {
})
.detach();
Self {
pending_lsp_binaries: 0,
settings_rx,
checking_for_update: Default::default(),
downloading: Default::default(),
failed: Default::default(),
}
}
fn dismiss_error_message(&mut self, _: &DismissErrorMessage, cx: &mut ViewContext<Self>) {
self.failed.clear();
cx.notify();
}
}
impl Entity for LspStatus {
@ -46,16 +85,49 @@ impl View for LspStatus {
"LspStatus"
}
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
if self.pending_lsp_binaries == 0 {
Empty::new().boxed()
} else {
let theme = &self.settings_rx.borrow().theme;
fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
let theme = &self.settings_rx.borrow().theme;
if !self.downloading.is_empty() {
Label::new(
"Downloading language servers...".to_string(),
format!(
"Downloading {} language server{}...",
self.downloading.join(", "),
if self.downloading.len() > 1 { "s" } else { "" }
),
theme.workspace.status_bar.lsp_message.clone(),
)
.boxed()
} else if !self.checking_for_update.is_empty() {
Label::new(
format!(
"Checking for updates to {} language server{}...",
self.checking_for_update.join(", "),
if self.checking_for_update.len() > 1 {
"s"
} else {
""
}
),
theme.workspace.status_bar.lsp_message.clone(),
)
.boxed()
} else if !self.failed.is_empty() {
MouseEventHandler::new::<Self, _, _>(0, cx, |_, _| {
Label::new(
format!(
"Failed to download {} language server{}. Click to dismiss.",
self.failed.join(", "),
if self.failed.len() > 1 { "s" } else { "" }
),
theme.workspace.status_bar.lsp_message.clone(),
)
.boxed()
})
.with_cursor_style(CursorStyle::PointingHand)
.on_click(|cx| cx.dispatch_action(DismissErrorMessage))
.boxed()
} else {
Empty::new().boxed()
}
}
}