In the status bar, show the diagnostic under the cursor

This commit is contained in:
Max Brunsfeld 2021-11-03 12:33:16 -07:00
parent 941d935c4a
commit 8b5089c759
5 changed files with 95 additions and 3 deletions

View file

@ -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<Settings>,
diagnostic: Option<Diagnostic>,
_observe_active_editor: Option<Subscription>,
}
impl DiagnosticMessage {
pub fn new(settings: watch::Receiver<Settings>) -> Self {
Self {
diagnostic: None,
settings,
_observe_active_editor: None,
}
}
fn update(&mut self, editor: ViewHandle<Editor>, cx: &mut ViewContext<Self>) {
let editor = editor.read(cx);
let cursor_position = editor
.selections::<usize>(cx)
.max_by_key(|selection| selection.id)
.unwrap()
.head();
let new_diagnostic = editor
.buffer()
.read(cx)
.diagnostics_in_range::<usize, usize>(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<Self>) -> 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<Self>,
) {
if let Some(editor) = active_pane_item.and_then(|item| item.to_any().downcast::<Editor>()) {
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();
}
}

View file

@ -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
});