on master help sign in
Total mess but it works: diagnostic marking.
49254d7Blaž Hrastnik
helix-core/src/diagnostic.rs+7−1
@@ -1 +1,7 @@
1+use crate::Range;
2+
1−pub struct Diagnostic {}
3+pub struct Diagnostic {
4+ pub range: (usize, usize),
5+ pub line: usize,
6+ pub message: String,
7+}
helix-lsp/src/lib.rs+3
@@ -10,6 +10,9 @@ use serde_json::Value;
10
10
11use serde::{Deserialize, Serialize};
11use serde::{Deserialize, Serialize};
12
12
13+pub use lsp::Position;
14+pub use lsp::Url;
15+
13use smol::prelude::*;
16use smol::prelude::*;
14use smol::{
17use smol::{
15 channel::{Receiver, Sender},
18 channel::{Receiver, Sender},
helix-term/src/application.rs+79−5
@@ -29,10 +29,10 @@ use tui::{
29 backend::CrosstermBackend,
29 backend::CrosstermBackend,
30 buffer::Buffer as Surface,
30 buffer::Buffer as Surface,
31 layout::Rect,
31 layout::Rect,
32− style::{Color, Style},
32+ style::{Color, Modifier, Style},
33};
33};
34
34
35−const OFFSET: u16 = 6; // 5 linenr + 1 gutter
35+const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
36
36
37type Terminal = tui::Terminal<CrosstermBackend<std::io::Stdout>>;
37type Terminal = tui::Terminal<CrosstermBackend<std::io::Stdout>>;
38
38
@@ -205,6 +205,16 @@ impl Renderer {
205 style
205 style
206 };
206 };
207
207
208+ // ugh, improve with a traverse method
209+ // or interleave highlight spans with selection and diagnostic spans
210+ let style = if view.state.diagnostics.iter().any(|diagnostic| {
211+ diagnostic.range.0 <= char_index && diagnostic.range.1 > char_index
212+ }) {
213+ style.clone().add_modifier(Modifier::UNDERLINED)
214+ } else {
215+ style
216+ };
217+
208 // TODO: paint cursor heads except primary
218 // TODO: paint cursor heads except primary
209
219
210 self.surface
220 self.surface
@@ -212,18 +222,23 @@ impl Renderer {
212
222
213 visual_x += width;
223 visual_x += width;
214 }
224 }
215− // if grapheme == "\t"
216
225
217 char_index += 1;
226 char_index += 1;
218 }
227 }
219 }
228 }
220 }
229 }
221 }
230 }
231+
222 let style: Style = theme.get("ui.linenr");
232 let style: Style = theme.get("ui.linenr");
233+ let warning: Style = theme.get("warning");
223 let last_line = view.last_line();
234 let last_line = view.last_line();
224 for (i, line) in (view.first_line..last_line).enumerate() {
235 for (i, line) in (view.first_line..last_line).enumerate() {
236+ if view.state.diagnostics.iter().any(|d| d.line == line) {
237+ self.surface.set_stringn(0, i as u16, "●", 1, warning);
238+ }
239+
225 self.surface
240 self.surface
226− .set_stringn(0, i as u16, format!("{:>5}", line + 1), 5, style);
241+ .set_stringn(1, i as u16, format!("{:>5}", line + 1), 5, style);
227 }
242 }
228 }
243 }
229
244
@@ -240,6 +255,13 @@ impl Renderer {
240 );
255 );
241 self.surface
256 self.surface
242 .set_string(1, self.size.1 - 2, mode, self.text_color);
257 .set_string(1, self.size.1 - 2, mode, self.text_color);
258+
259+ self.surface.set_string(
260+ self.size.0 - 10,
261+ self.size.1 - 2,
262+ format!("{}", view.state.diagnostics.len()),
263+ self.text_color,
264+ );
243 }
265 }
244
266
245 pub fn render_prompt(&mut self, view: &View, prompt: &Prompt, theme: &Theme) {
267 pub fn render_prompt(&mut self, view: &View, prompt: &Prompt, theme: &Theme) {
@@ -545,7 +567,59 @@ impl<'a> Application<'a> {
545 pub async fn handle_lsp_notification(&mut self, notification: Option<helix_lsp::Notification>) {
567 pub async fn handle_lsp_notification(&mut self, notification: Option<helix_lsp::Notification>) {
546 use helix_lsp::Notification;
568 use helix_lsp::Notification;
547 match notification {
569 match notification {
548− Some(Notification::PublishDiagnostics(params)) => unimplemented!("{:?}", params),
570+ Some(Notification::PublishDiagnostics(params)) => {
571+ let view = self.editor.views.iter_mut().find(|view| {
572+ let path = view
573+ .state
574+ .path
575+ .as_ref()
576+ .map(|path| helix_lsp::Url::from_file_path(path).unwrap());
577+
578+ eprintln!("{:?} {} {}", path, params.uri, params.diagnostics.len());
579+ // HAXX
580+ path == Some(params.uri.clone())
581+ });
582+
583+ fn lsp_pos_to_pos(doc: &helix_core::RopeSlice, pos: helix_lsp::Position) -> usize {
584+ let line = doc.line_to_char(pos.line as usize);
585+ let line_start = doc.char_to_utf16_cu(line);
586+ doc.utf16_cu_to_char(pos.character as usize + line_start)
587+ }
588+
589+ if let Some(view) = view {
590+ let doc = view.state.doc().slice(..);
591+ let diagnostics = params
592+ .diagnostics
593+ .into_iter()
594+ .map(|diagnostic| {
595+ let start = lsp_pos_to_pos(&doc, diagnostic.range.start);
596+ let end = lsp_pos_to_pos(&doc, diagnostic.range.end);
597+
598+ // eprintln!(
599+ // "{:?}-{:?} {}-{} {}",
600+ // diagnostic.range.start,
601+ // diagnostic.range.end,
602+ // start,
603+ // end,
604+ // diagnostic.message
605+ // );
606+
607+ helix_core::Diagnostic {
608+ range: (start, end),
609+ line: diagnostic.range.start.line as usize,
610+ message: diagnostic.message,
611+ // severity
612+ // code
613+ // source
614+ }
615+ })
616+ .collect();
617+
618+ view.state.diagnostics = diagnostics;
619+
620+ self.render();
621+ }
622+ }
549 _ => unreachable!(),
623 _ => unreachable!(),
550 }
624 }
551 }
625 }
helix-view/src/theme.rs+2
@@ -157,6 +157,8 @@ impl Default for Theme {
157 "ui.background" => Style::default().bg(Color::Rgb(59, 34, 76)), // midnight
157 "ui.background" => Style::default().bg(Color::Rgb(59, 34, 76)), // midnight
158 "ui.linenr" => Style::default().fg(Color::Rgb(90, 89, 119)), // comet
158 "ui.linenr" => Style::default().fg(Color::Rgb(90, 89, 119)), // comet
159 "ui.statusline" => Style::default().bg(Color::Rgb(40, 23, 51)), // revolver
159 "ui.statusline" => Style::default().bg(Color::Rgb(40, 23, 51)), // revolver
160+
161+ "warning" => Style::default().fg(Color::Rgb(255, 205, 28)),
160 };
162 };
161
163
162 let scopes = mapping.keys().map(ToString::to_string).collect();
164 let scopes = mapping.keys().map(ToString::to_string).collect();