From 87e3cd3df283a6da055488bbea60637713bd1f35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Mon, 15 Mar 2021 16:19:31 +0900 Subject: [PATCH] ui: Render diagnostic errors in sideline. --- helix-core/src/diagnostic.rs | 8 +++-- helix-lsp/src/lib.rs | 2 +- helix-term/src/application.rs | 7 +++-- helix-term/src/ui/editor.rs | 59 ++++++++++++++++++++++++++++++++++- 4 files changed, 69 insertions(+), 7 deletions(-) diff --git a/helix-core/src/diagnostic.rs b/helix-core/src/diagnostic.rs index c1a3b4c10..5056c26aa 100644 --- a/helix-core/src/diagnostic.rs +++ b/helix-core/src/diagnostic.rs @@ -1,5 +1,3 @@ -use crate::Range; - pub enum Severity { Error, Warning, @@ -7,8 +5,12 @@ pub enum Severity { Hint, } +pub struct Range { + pub start: usize, + pub end: usize, +} pub struct Diagnostic { - pub range: (usize, usize), + pub range: Range, pub line: usize, pub message: String, pub severity: Option, diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 0d04b7111..3e4f55ea8 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -35,7 +35,7 @@ pub mod util { pub fn lsp_pos_to_pos(doc: RopeSlice, pos: lsp::Position) -> usize { let line = doc.line_to_char(pos.line as usize); let line_start = doc.char_to_utf16_cu(line); - doc.utf16_cu_to_char(pos.character as usize + line_start) + doc.utf16_cu_to_char(line_start + pos.character as usize) } pub fn pos_to_lsp_pos(doc: RopeSlice, pos: usize) -> lsp::Position { let line = doc.char_to_line(pos); diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 24b5317bc..c22cf9967 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -140,14 +140,17 @@ impl Application { .into_iter() .map(|diagnostic| { use helix_core::diagnostic::Severity::*; - use helix_core::{diagnostic::Severity, Diagnostic}; + use helix_core::{ + diagnostic::{Range, Severity}, + Diagnostic, + }; use helix_lsp::{lsp, util::lsp_pos_to_pos}; use lsp::DiagnosticSeverity; let start = lsp_pos_to_pos(doc, diagnostic.range.start); let end = lsp_pos_to_pos(doc, diagnostic.range.end); Diagnostic { - range: (start, end), + range: Range { start, end }, line: diagnostic.range.start.line as usize, message: diagnostic.message, severity: diagnostic.severity.map( diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index abdbb7a33..fe4e3439a 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -56,6 +56,8 @@ impl EditorView { // TODO: this seems to prevent setting style later // surface.set_style(viewport, theme.get("ui.background")); + self.render_diagnostics(&view.doc, area, surface, theme, is_focused); + let area = Rect::new( viewport.x, viewport.y + viewport.height.saturating_sub(1), @@ -166,7 +168,8 @@ impl EditorView { // ugh,interleave highlight spans with diagnostic spans let is_diagnostic = view.doc.diagnostics.iter().any(|diagnostic| { - diagnostic.range.0 <= char_index && diagnostic.range.1 > char_index + diagnostic.range.start <= char_index + && diagnostic.range.end > char_index }); let style = if is_diagnostic { @@ -316,6 +319,60 @@ impl EditorView { } } + pub fn render_diagnostics( + &self, + doc: &Document, + viewport: Rect, + surface: &mut Surface, + theme: &Theme, + is_focused: bool, + ) { + use helix_core::diagnostic::Severity; + use tui::{ + layout::Alignment, + text::Text, + widgets::{Paragraph, Widget}, + }; + + let cursor = doc.selection().cursor(); + let line = doc.text().char_to_line(cursor); + + let diagnostics = doc.diagnostics.iter().filter(|diagnostic| { + diagnostic.range.start <= cursor && diagnostic.range.end >= cursor + }); + + let warning: Style = theme.get("warning"); + let error: Style = theme.get("error"); + let info: Style = theme.get("info"); + let hint: Style = theme.get("hint"); + + // Vec::with_capacity(diagnostics.len()); // rough estimate + let mut lines = Vec::new(); + for diagnostic in diagnostics { + let text = Text::styled( + &diagnostic.message, + match diagnostic.severity { + Some(Severity::Error) => error, + Some(Severity::Warning) | None => warning, + Some(Severity::Info) => info, + Some(Severity::Hint) => hint, + }, + ); + lines.extend(text.lines); + } + + let paragraph = Paragraph::new(lines).alignment(Alignment::Right); + paragraph.render( + Rect::new( + viewport.x + viewport.width - 80 - 1, + viewport.y as u16 + 1, + 80, + 15, + ), + surface, + ); + } + pub fn render_statusline( &self, doc: &Document,