From 7c6cd8957e4f3d4399664fc8e37854f4b3261b3e Mon Sep 17 00:00:00 2001 From: Robin Jadoul Date: Thu, 7 Apr 2022 16:14:07 +0200 Subject: [PATCH 1/2] Send active diagnostics to LSP when requesting code actions. This allows for e.g. clangd to properly send the quickfix code actions corresponding to those diagnostics as options. The LSP spec v3.16.0 introduced an opaque `data` member that would allow the server to persist arbitrary data between the diagnostic and the code actions request, but this is not supported yet by this commit. --- helix-lsp/src/client.rs | 3 ++- helix-lsp/src/lib.rs | 32 ++++++++++++++++++++++++++++++++ helix-term/src/commands/lsp.rs | 30 ++++++++++++++++++++++-------- 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 8b14b0b87bd9..b2d7f384f6e3 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -835,11 +835,12 @@ impl Client { &self, text_document: lsp::TextDocumentIdentifier, range: lsp::Range, + context: lsp::CodeActionContext, ) -> impl Future> { let params = lsp::CodeActionParams { text_document, range, - context: lsp::CodeActionContext::default(), + context, work_done_progress_params: lsp::WorkDoneProgressParams::default(), partial_result_params: lsp::PartialResultParams::default(), }; diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 767481367764..183d08e4515d 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -58,6 +58,38 @@ pub mod util { use super::*; use helix_core::{Range, Rope, Transaction}; + /// Converts a diagnostic in the document to [`lsp::Diagnostic`]. + /// + /// Panics when [`pos_to_lsp_pos`] would for an invalid range on the diagnostic. + pub fn diagnostic_to_lsp_diagnostic( + doc: &Rope, + diag: &helix_core::diagnostic::Diagnostic, + offset_encoding: OffsetEncoding, + ) -> lsp::Diagnostic { + use helix_core::diagnostic::Severity::*; + + let severity = diag.severity.map(|s| match s { + Hint => lsp::DiagnosticSeverity::HINT, + Info => lsp::DiagnosticSeverity::INFORMATION, + Warning => lsp::DiagnosticSeverity::WARNING, + Error => lsp::DiagnosticSeverity::ERROR, + }); + + // TODO: add support for Diagnostic.data + lsp::Diagnostic::new( + lsp::Range::new( + pos_to_lsp_pos(doc, diag.range.start, offset_encoding), + pos_to_lsp_pos(doc, diag.range.end, offset_encoding), + ), + severity, + None, + None, + diag.message.to_owned(), + None, + None, + ) + } + /// Converts [`lsp::Position`] to a position in the document. /// /// Returns `None` if position exceeds document length or an operation overflows. diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 1db57ecf264d..0a12ae392d3d 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -1,6 +1,6 @@ use helix_lsp::{ block_on, lsp, - util::{lsp_pos_to_pos, lsp_range_to_range, range_to_lsp_range}, + util::{diagnostic_to_lsp_diagnostic, lsp_pos_to_pos, lsp_range_to_range, range_to_lsp_range}, OffsetEncoding, }; @@ -192,15 +192,29 @@ pub fn code_action(cx: &mut Context) { let language_server = language_server!(cx.editor, doc); - let range = range_to_lsp_range( - doc.text(), - doc.selection(view.id).primary(), - language_server.offset_encoding(), - ); - - let future = language_server.code_actions(doc.identifier(), range); + let selection_range = doc.selection(view.id).primary(); let offset_encoding = language_server.offset_encoding(); + let range = range_to_lsp_range(doc.text(), selection_range, offset_encoding); + + let future = language_server.code_actions( + doc.identifier(), + range, + // Filter and convert overlapping diagnostics + lsp::CodeActionContext { + diagnostics: doc + .diagnostics() + .iter() + .filter(|&diag| { + selection_range + .overlaps(&helix_core::Range::new(diag.range.start, diag.range.end)) + }) + .map(|diag| diagnostic_to_lsp_diagnostic(doc.text(), diag, offset_encoding)) + .collect(), + only: None, + }, + ); + cx.callback( future, move |editor, compositor, response: Option| { From 315b0f210c2430ed831b32e86296a2eacd76bd66 Mon Sep 17 00:00:00 2001 From: Robin Jadoul Date: Fri, 15 Apr 2022 16:31:21 +0200 Subject: [PATCH 2/2] Reuse existing range_to_lsp_range functionality --- helix-lsp/src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 183d08e4515d..13ac32ff91cf 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -68,6 +68,7 @@ pub mod util { ) -> lsp::Diagnostic { use helix_core::diagnostic::Severity::*; + let range = Range::new(diag.range.start, diag.range.end); let severity = diag.severity.map(|s| match s { Hint => lsp::DiagnosticSeverity::HINT, Info => lsp::DiagnosticSeverity::INFORMATION, @@ -77,10 +78,7 @@ pub mod util { // TODO: add support for Diagnostic.data lsp::Diagnostic::new( - lsp::Range::new( - pos_to_lsp_pos(doc, diag.range.start, offset_encoding), - pos_to_lsp_pos(doc, diag.range.end, offset_encoding), - ), + range_to_lsp_range(doc, range, offset_encoding), severity, None, None,