From 8b5089c75964ddf699a5065e2cb9fa75e56f86be Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 3 Nov 2021 12:33:16 -0700 Subject: [PATCH] In the status bar, show the diagnostic under the cursor --- crates/language/src/lib.rs | 8 ++- crates/theme/src/lib.rs | 4 ++ crates/workspace/src/items.rs | 80 ++++++++++++++++++++++++++++- crates/workspace/src/lib.rs | 2 + crates/zed/assets/themes/_base.toml | 4 ++ 5 files changed, 95 insertions(+), 3 deletions(-) diff --git a/crates/language/src/lib.rs b/crates/language/src/lib.rs index 7e38cc0c16..a4ac497776 100644 --- a/crates/language/src/lib.rs +++ b/crates/language/src/lib.rs @@ -780,10 +780,14 @@ impl Buffer { Ok(Operation::UpdateDiagnostics(self.diagnostics.clone())) } - pub fn diagnostics_in_range<'a, T: 'a + ToOffset>( + pub fn diagnostics_in_range<'a, T, O>( &'a self, range: Range, - ) -> impl Iterator, &Diagnostic)> + 'a { + ) -> impl Iterator, &Diagnostic)> + 'a + where + T: 'a + ToOffset, + O: 'a + FromAnchor, + { let content = self.content(); self.diagnostics .intersecting_ranges(range, content, true) diff --git a/crates/theme/src/lib.rs b/crates/theme/src/lib.rs index eb60f6cf3a..22d1dcd958 100644 --- a/crates/theme/src/lib.rs +++ b/crates/theme/src/lib.rs @@ -95,6 +95,10 @@ pub struct StatusBar { pub container: ContainerStyle, pub height: f32, pub cursor_position: TextStyle, + pub diagnostic_error: TextStyle, + pub diagnostic_warning: TextStyle, + pub diagnostic_information: TextStyle, + pub diagnostic_hint: TextStyle, } #[derive(Deserialize, Default)] diff --git a/crates/workspace/src/items.rs b/crates/workspace/src/items.rs index d6c20c8fc0..8a3ce6b5c8 100644 --- a/crates/workspace/src/items.rs +++ b/crates/workspace/src/items.rs @@ -7,7 +7,7 @@ use gpui::{ elements::*, fonts::TextStyle, AppContext, Entity, ModelHandle, RenderContext, Subscription, Task, View, ViewContext, ViewHandle, }; -use language::{Buffer, File as _}; +use language::{Buffer, Diagnostic, DiagnosticSeverity, File as _}; use postage::watch; use project::{ProjectPath, Worktree}; use std::fmt::Write; @@ -240,3 +240,81 @@ impl StatusItemView for CursorPosition { cx.notify(); } } + +pub struct DiagnosticMessage { + settings: watch::Receiver, + diagnostic: Option, + _observe_active_editor: Option, +} + +impl DiagnosticMessage { + pub fn new(settings: watch::Receiver) -> Self { + Self { + diagnostic: None, + settings, + _observe_active_editor: None, + } + } + + fn update(&mut self, editor: ViewHandle, cx: &mut ViewContext) { + let editor = editor.read(cx); + let cursor_position = editor + .selections::(cx) + .max_by_key(|selection| selection.id) + .unwrap() + .head(); + let new_diagnostic = editor + .buffer() + .read(cx) + .diagnostics_in_range::(cursor_position..cursor_position) + .min_by_key(|(range, diagnostic)| (diagnostic.severity, range.len())) + .map(|(_, diagnostic)| diagnostic.clone()); + if new_diagnostic != self.diagnostic { + self.diagnostic = new_diagnostic; + cx.notify(); + } + } +} + +impl Entity for DiagnosticMessage { + type Event = (); +} + +impl View for DiagnosticMessage { + fn ui_name() -> &'static str { + "DiagnosticMessage" + } + + fn render(&mut self, _: &mut RenderContext) -> ElementBox { + if let Some(diagnostic) = &self.diagnostic { + let theme = &self.settings.borrow().theme.workspace.status_bar; + let style = match diagnostic.severity { + DiagnosticSeverity::ERROR => theme.diagnostic_error.clone(), + DiagnosticSeverity::WARNING => theme.diagnostic_warning.clone(), + DiagnosticSeverity::INFORMATION => theme.diagnostic_information.clone(), + DiagnosticSeverity::HINT => theme.diagnostic_hint.clone(), + _ => Default::default(), + }; + Label::new(diagnostic.message.replace('\n', " "), style).boxed() + } else { + Empty::new().boxed() + } + } +} + +impl StatusItemView for DiagnosticMessage { + fn set_active_pane_item( + &mut self, + active_pane_item: Option<&dyn crate::ItemViewHandle>, + cx: &mut ViewContext, + ) { + if let Some(editor) = active_pane_item.and_then(|item| item.to_any().downcast::()) { + self._observe_active_editor = Some(cx.observe(&editor, Self::update)); + self.update(editor, cx); + } else { + self.diagnostic = Default::default(); + self._observe_active_editor = None; + } + cx.notify(); + } +} diff --git a/crates/workspace/src/lib.rs b/crates/workspace/src/lib.rs index 08d26e29a2..0ca07d2246 100644 --- a/crates/workspace/src/lib.rs +++ b/crates/workspace/src/lib.rs @@ -350,8 +350,10 @@ impl Workspace { cx.focus(&pane); let cursor_position = cx.add_view(|_| items::CursorPosition::new(params.settings.clone())); + let diagnostic = cx.add_view(|_| items::DiagnosticMessage::new(params.settings.clone())); let status_bar = cx.add_view(|cx| { let mut status_bar = StatusBar::new(&pane, params.settings.clone(), cx); + status_bar.add_left_item(diagnostic, cx); status_bar.add_right_item(cursor_position, cx); status_bar }); diff --git a/crates/zed/assets/themes/_base.toml b/crates/zed/assets/themes/_base.toml index a1a2397f9a..1697422a8d 100644 --- a/crates/zed/assets/themes/_base.toml +++ b/crates/zed/assets/themes/_base.toml @@ -64,6 +64,10 @@ border = { width = 1, color = "$border.0", left = true } padding = { left = 6, right = 6 } height = 24 cursor_position = "$text.2" +diagnostic_error = { extends = "$text.2", color = "$status.bad" } +diagnostic_warning = { extends = "$text.2", color = "$status.warn" } +diagnostic_information = { extends = "$text.2", color = "$status.info" } +diagnostic_hint = { extends = "$text.2", color = "$status.info" } [panel] padding = { top = 12, left = 12, bottom = 12, right = 12 }