diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index f064e866a..84824b51a 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -217,7 +217,7 @@ impl Application { }) .collect(); - doc.diagnostics = diagnostics; + doc.set_diagnostics(diagnostics); // TODO: we want to process all the events in queue, then render. publishDiagnostic tends to send a whole bunch of events self.render(); } diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 7992a517c..52d3acbc6 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1536,6 +1536,86 @@ pub fn goto_reference(cx: &mut Context) { ); } +fn goto_pos(editor: &mut Editor, pos: usize) { + push_jump(editor); + + let (view, doc) = editor.current(); + + doc.set_selection(view.id, Selection::point(pos)); + align_view(doc, view, Align::Center); +} + +pub fn goto_first_diag(cx: &mut Context) { + let editor = &mut cx.editor; + let (view, doc) = editor.current(); + + let cursor_pos = doc.selection(view.id).cursor(); + let diag = if let Some(diag) = doc.diagnostics().first() { + diag.range.start + } else { + return; + }; + + goto_pos(editor, diag); +} + +pub fn goto_last_diag(cx: &mut Context) { + let editor = &mut cx.editor; + let (view, doc) = editor.current(); + + let cursor_pos = doc.selection(view.id).cursor(); + let diag = if let Some(diag) = doc.diagnostics().last() { + diag.range.start + } else { + return; + }; + + goto_pos(editor, diag); +} + +pub fn goto_next_diag(cx: &mut Context) { + let editor = &mut cx.editor; + let (view, doc) = editor.current(); + + let cursor_pos = doc.selection(view.id).cursor(); + let diag = if let Some(diag) = doc + .diagnostics() + .iter() + .map(|diag| diag.range.start) + .find(|&pos| pos > cursor_pos) + { + diag + } else if let Some(diag) = doc.diagnostics().first() { + diag.range.start + } else { + return; + }; + + goto_pos(editor, diag); +} + +pub fn goto_prev_diag(cx: &mut Context) { + let editor = &mut cx.editor; + let (view, doc) = editor.current(); + + let cursor_pos = doc.selection(view.id).cursor(); + let diag = if let Some(diag) = doc + .diagnostics() + .iter() + .rev() + .map(|diag| diag.range.start) + .find(|&pos| pos < cursor_pos) + { + diag + } else if let Some(diag) = doc.diagnostics().last() { + diag.range.start + } else { + return; + }; + + goto_pos(editor, diag); +} + pub fn signature_help(cx: &mut Context) { let (view, doc) = cx.current(); @@ -2433,3 +2513,35 @@ pub fn view_mode(cx: &mut Context) { } }) } + +pub fn left_bracket_mode(cx: &mut Context) { + cx.on_next_key(move |cx, event| { + if let KeyEvent { + code: KeyCode::Char(ch), + .. + } = event + { + match ch { + 'd' => goto_prev_diag(cx), + 'D' => goto_first_diag(cx), + _ => (), + } + } + }) +} + +pub fn right_bracket_mode(cx: &mut Context) { + cx.on_next_key(move |cx, event| { + if let KeyEvent { + code: KeyCode::Char(ch), + .. + } = event + { + match ch { + 'd' => goto_next_diag(cx), + 'D' => goto_last_diag(cx), + _ => (), + } + } + }) +} diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index 6ef53915f..27ef9b9e0 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -85,6 +85,10 @@ use std::collections::HashMap; // // gd = goto definition // gr = goto reference +// [d = previous diagnostic +// d] = next diagnostic +// [D = first diagnostic +// D] = last diagnostic // } // #[cfg(feature = "term")] @@ -209,7 +213,9 @@ pub fn default() -> Keymaps { // repeat_select // TODO: figure out what key to use - key!('[') => commands::expand_selection, + // key!('[') => commands::expand_selection, ?? + key!('[') => commands::left_bracket_mode, + key!(']') => commands::right_bracket_mode, key!('/') => commands::search, // ? for search_reverse diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 2464528c8..f47d6c26a 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -195,7 +195,7 @@ impl EditorView { } // ugh,interleave highlight spans with diagnostic spans - let is_diagnostic = doc.diagnostics.iter().any(|diagnostic| { + let is_diagnostic = doc.diagnostics().iter().any(|diagnostic| { diagnostic.range.start <= char_index && diagnostic.range.end > char_index }); @@ -343,7 +343,7 @@ impl EditorView { for (i, line) in (view.first_line..=last_line).enumerate() { use helix_core::diagnostic::Severity; - if let Some(diagnostic) = doc.diagnostics.iter().find(|d| d.line == line) { + if let Some(diagnostic) = doc.diagnostics().iter().find(|d| d.line == line) { surface.set_stringn( viewport.x - OFFSET, viewport.y + i as u16, @@ -387,7 +387,7 @@ impl EditorView { let cursor = doc.selection(view.id).cursor(); let line = doc.text().char_to_line(cursor); - let diagnostics = doc.diagnostics.iter().filter(|diagnostic| { + let diagnostics = doc.diagnostics().iter().filter(|diagnostic| { diagnostic.range.start <= cursor && diagnostic.range.end >= cursor }); @@ -469,7 +469,7 @@ impl EditorView { surface.set_stringn( viewport.x + viewport.width.saturating_sub(15), viewport.y, - format!("{}", doc.diagnostics.len()), + format!("{}", doc.diagnostics().len()), 4, text_color, ); diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 9093dbe83..783e11175 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -48,7 +48,7 @@ pub struct Document { last_saved_revision: usize, version: i32, // should be usize? - pub diagnostics: Vec, + diagnostics: Vec, language_server: Option>, } @@ -519,6 +519,14 @@ impl Document { pub fn versioned_identifier(&self) -> lsp::VersionedTextDocumentIdentifier { lsp::VersionedTextDocumentIdentifier::new(self.url().unwrap(), self.version) } + + pub fn diagnostics(&self) -> &[Diagnostic] { + &self.diagnostics + } + + pub fn set_diagnostics(&mut self, diagnostics: Vec) { + self.diagnostics = diagnostics; + } } #[cfg(test)]