lsp_status.rs

  1use crate::{ItemViewHandle, Settings, StatusItemView};
  2use futures::StreamExt;
  3use gpui::{
  4    action, elements::*, platform::CursorStyle, Entity, MutableAppContext, RenderContext, View,
  5    ViewContext,
  6};
  7use language::{LanguageRegistry, LanguageServerBinaryStatus};
  8use postage::watch;
  9use std::sync::Arc;
 10
 11action!(DismissErrorMessage);
 12
 13pub struct LspStatus {
 14    settings_rx: watch::Receiver<Settings>,
 15    checking_for_update: Vec<String>,
 16    downloading: Vec<String>,
 17    failed: Vec<String>,
 18}
 19
 20pub fn init(cx: &mut MutableAppContext) {
 21    cx.add_action(LspStatus::dismiss_error_message);
 22}
 23
 24impl LspStatus {
 25    pub fn new(
 26        languages: Arc<LanguageRegistry>,
 27        settings_rx: watch::Receiver<Settings>,
 28        cx: &mut ViewContext<Self>,
 29    ) -> Self {
 30        let mut status_events = languages.language_server_binary_statuses();
 31        cx.spawn_weak(|this, mut cx| async move {
 32            while let Some((language, event)) = status_events.next().await {
 33                if let Some(this) = this.upgrade(&cx) {
 34                    this.update(&mut cx, |this, cx| {
 35                        for vector in [
 36                            &mut this.checking_for_update,
 37                            &mut this.downloading,
 38                            &mut this.failed,
 39                        ] {
 40                            vector.retain(|name| name != language.name().as_ref());
 41                        }
 42
 43                        match event {
 44                            LanguageServerBinaryStatus::CheckingForUpdate => {
 45                                this.checking_for_update.push(language.name().to_string());
 46                            }
 47                            LanguageServerBinaryStatus::Downloading => {
 48                                this.downloading.push(language.name().to_string());
 49                            }
 50                            LanguageServerBinaryStatus::Failed => {
 51                                this.failed.push(language.name().to_string());
 52                            }
 53                            LanguageServerBinaryStatus::Downloaded
 54                            | LanguageServerBinaryStatus::Cached => {}
 55                        }
 56
 57                        cx.notify();
 58                    });
 59                } else {
 60                    break;
 61                }
 62            }
 63        })
 64        .detach();
 65        Self {
 66            settings_rx,
 67            checking_for_update: Default::default(),
 68            downloading: Default::default(),
 69            failed: Default::default(),
 70        }
 71    }
 72
 73    fn dismiss_error_message(&mut self, _: &DismissErrorMessage, cx: &mut ViewContext<Self>) {
 74        self.failed.clear();
 75        cx.notify();
 76    }
 77}
 78
 79impl Entity for LspStatus {
 80    type Event = ();
 81}
 82
 83impl View for LspStatus {
 84    fn ui_name() -> &'static str {
 85        "LspStatus"
 86    }
 87
 88    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
 89        let theme = &self.settings_rx.borrow().theme;
 90        if !self.downloading.is_empty() {
 91            Label::new(
 92                format!(
 93                    "Downloading {} language server{}...",
 94                    self.downloading.join(", "),
 95                    if self.downloading.len() > 1 { "s" } else { "" }
 96                ),
 97                theme.workspace.status_bar.lsp_message.clone(),
 98            )
 99            .boxed()
100        } else if !self.checking_for_update.is_empty() {
101            Label::new(
102                format!(
103                    "Checking for updates to {} language server{}...",
104                    self.checking_for_update.join(", "),
105                    if self.checking_for_update.len() > 1 {
106                        "s"
107                    } else {
108                        ""
109                    }
110                ),
111                theme.workspace.status_bar.lsp_message.clone(),
112            )
113            .boxed()
114        } else if !self.failed.is_empty() {
115            MouseEventHandler::new::<Self, _, _>(0, cx, |_, _| {
116                Label::new(
117                    format!(
118                        "Failed to download {} language server{}. Click to dismiss.",
119                        self.failed.join(", "),
120                        if self.failed.len() > 1 { "s" } else { "" }
121                    ),
122                    theme.workspace.status_bar.lsp_message.clone(),
123                )
124                .boxed()
125            })
126            .with_cursor_style(CursorStyle::PointingHand)
127            .on_click(|cx| cx.dispatch_action(DismissErrorMessage))
128            .boxed()
129        } else {
130            Empty::new().boxed()
131        }
132    }
133}
134
135impl StatusItemView for LspStatus {
136    fn set_active_pane_item(&mut self, _: Option<&dyn ItemViewHandle>, _: &mut ViewContext<Self>) {}
137}