on master help sign in
ui: Render diagnostic errors in sideline.
87e3cd3Blaž Hrastnik
helix-core/src/diagnostic.rs+5−3
@@ -1,5 +1,3 @@
1−use crate::Range;
2−
3pub enum Severity {
1pub enum Severity {
4 Error,
2 Error,
5 Warning,
3 Warning,
@@ -7,8 +5,12 @@ pub enum Severity {
7 Hint,
5 Hint,
8}
6}
9
7
8+pub struct Range {
9+ pub start: usize,
10+ pub end: usize,
11+}
10pub struct Diagnostic {
12pub struct Diagnostic {
11− pub range: (usize, usize),
13+ pub range: Range,
12 pub line: usize,
14 pub line: usize,
13 pub message: String,
15 pub message: String,
14 pub severity: Option<Severity>,
16 pub severity: Option<Severity>,
helix-lsp/src/lib.rs+1−1
@@ -35,7 +35,7 @@ pub mod util {
35 pub fn lsp_pos_to_pos(doc: RopeSlice, pos: lsp::Position) -> usize {
35 pub fn lsp_pos_to_pos(doc: RopeSlice, pos: lsp::Position) -> usize {
36 let line = doc.line_to_char(pos.line as usize);
36 let line = doc.line_to_char(pos.line as usize);
37 let line_start = doc.char_to_utf16_cu(line);
37 let line_start = doc.char_to_utf16_cu(line);
38− doc.utf16_cu_to_char(pos.character as usize + line_start)
38+ doc.utf16_cu_to_char(line_start + pos.character as usize)
39 }
39 }
40 pub fn pos_to_lsp_pos(doc: RopeSlice, pos: usize) -> lsp::Position {
40 pub fn pos_to_lsp_pos(doc: RopeSlice, pos: usize) -> lsp::Position {
41 let line = doc.char_to_line(pos);
41 let line = doc.char_to_line(pos);
helix-term/src/application.rs+5−2
@@ -140,14 +140,17 @@ impl Application {
140 .into_iter()
140 .into_iter()
141 .map(|diagnostic| {
141 .map(|diagnostic| {
142 use helix_core::diagnostic::Severity::*;
142 use helix_core::diagnostic::Severity::*;
143+ use helix_core::{
143− use helix_core::{diagnostic::Severity, Diagnostic};
144+ diagnostic::{Range, Severity},
145+ Diagnostic,
146+ };
144 use helix_lsp::{lsp, util::lsp_pos_to_pos};
147 use helix_lsp::{lsp, util::lsp_pos_to_pos};
145 use lsp::DiagnosticSeverity;
148 use lsp::DiagnosticSeverity;
146 let start = lsp_pos_to_pos(doc, diagnostic.range.start);
149 let start = lsp_pos_to_pos(doc, diagnostic.range.start);
147 let end = lsp_pos_to_pos(doc, diagnostic.range.end);
150 let end = lsp_pos_to_pos(doc, diagnostic.range.end);
148
151
149 Diagnostic {
152 Diagnostic {
150− range: (start, end),
153+ range: Range { start, end },
151 line: diagnostic.range.start.line as usize,
154 line: diagnostic.range.start.line as usize,
152 message: diagnostic.message,
155 message: diagnostic.message,
153 severity: diagnostic.severity.map(
156 severity: diagnostic.severity.map(
helix-term/src/ui/editor.rs+58−1
@@ -56,6 +56,8 @@ impl EditorView {
56 // TODO: this seems to prevent setting style later
56 // TODO: this seems to prevent setting style later
57 // surface.set_style(viewport, theme.get("ui.background"));
57 // surface.set_style(viewport, theme.get("ui.background"));
58
58
59+ self.render_diagnostics(&view.doc, area, surface, theme, is_focused);
60+
59 let area = Rect::new(
61 let area = Rect::new(
60 viewport.x,
62 viewport.x,
61 viewport.y + viewport.height.saturating_sub(1),
63 viewport.y + viewport.height.saturating_sub(1),
@@ -166,7 +168,8 @@ impl EditorView {
166
168
167 // ugh,interleave highlight spans with diagnostic spans
169 // ugh,interleave highlight spans with diagnostic spans
168 let is_diagnostic = view.doc.diagnostics.iter().any(|diagnostic| {
170 let is_diagnostic = view.doc.diagnostics.iter().any(|diagnostic| {
171+ diagnostic.range.start <= char_index
169− diagnostic.range.0 <= char_index && diagnostic.range.1 > char_index
172+ && diagnostic.range.end > char_index
170 });
173 });
171
174
172 let style = if is_diagnostic {
175 let style = if is_diagnostic {
@@ -316,6 +319,60 @@ impl EditorView {
316 }
319 }
317 }
320 }
318
321
322+ pub fn render_diagnostics(
323+ &self,
324+ doc: &Document,
325+ viewport: Rect,
326+ surface: &mut Surface,
327+ theme: &Theme,
328+ is_focused: bool,
329+ ) {
330+ use helix_core::diagnostic::Severity;
331+ use tui::{
332+ layout::Alignment,
333+ text::Text,
334+ widgets::{Paragraph, Widget},
335+ };
336+
337+ let cursor = doc.selection().cursor();
338+ let line = doc.text().char_to_line(cursor);
339+
340+ let diagnostics = doc.diagnostics.iter().filter(|diagnostic| {
341+ diagnostic.range.start <= cursor && diagnostic.range.end >= cursor
342+ });
343+
344+ let warning: Style = theme.get("warning");
345+ let error: Style = theme.get("error");
346+ let info: Style = theme.get("info");
347+ let hint: Style = theme.get("hint");
348+
349+ // Vec::with_capacity(diagnostics.len()); // rough estimate
350+ let mut lines = Vec::new();
351+ for diagnostic in diagnostics {
352+ let text = Text::styled(
353+ &diagnostic.message,
354+ match diagnostic.severity {
355+ Some(Severity::Error) => error,
356+ Some(Severity::Warning) | None => warning,
357+ Some(Severity::Info) => info,
358+ Some(Severity::Hint) => hint,
359+ },
360+ );
361+ lines.extend(text.lines);
362+ }
363+
364+ let paragraph = Paragraph::new(lines).alignment(Alignment::Right);
365+ paragraph.render(
366+ Rect::new(
367+ viewport.x + viewport.width - 80 - 1,
368+ viewport.y as u16 + 1,
369+ 80,
370+ 15,
371+ ),
372+ surface,
373+ );
374+ }
375+
319 pub fn render_statusline(
376 pub fn render_statusline(
320 &self,
377 &self,
321 doc: &Document,
378 doc: &Document,