aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_cargo_watch/src/conv.rs
diff options
context:
space:
mode:
authorEmil Lauridsen <[email protected]>2020-01-31 18:23:25 +0000
committerEmil Lauridsen <[email protected]>2020-02-03 10:34:24 +0000
commit790788d5f4013d8d92f110bc12a581d18cf4b6ae (patch)
tree311e11529c7546b7a09486d5c161039d8bd8f975 /crates/ra_cargo_watch/src/conv.rs
parent52456c44901c8c38c8bcb742ebe305484af8f36f (diff)
Rework how we send diagnostics to client.
The previous way of sending from the thread pool suffered from stale diagnostics due to being canceled before we could clear the old ones. The key change is moving to sending diagnostics from the main loop thread, but doing all the hard work in the thread pool. This should provide the best of both worlds, with little to no of the downsides. This should hopefully fix a lot of issues, but we'll need testing in each individual issue to be sure.
Diffstat (limited to 'crates/ra_cargo_watch/src/conv.rs')
-rw-r--r--crates/ra_cargo_watch/src/conv.rs66
1 files changed, 21 insertions, 45 deletions
diff --git a/crates/ra_cargo_watch/src/conv.rs b/crates/ra_cargo_watch/src/conv.rs
index 8fba400ae..506370535 100644
--- a/crates/ra_cargo_watch/src/conv.rs
+++ b/crates/ra_cargo_watch/src/conv.rs
@@ -1,12 +1,11 @@
1//! This module provides the functionality needed to convert diagnostics from 1//! This module provides the functionality needed to convert diagnostics from
2//! `cargo check` json format to the LSP diagnostic format. 2//! `cargo check` json format to the LSP diagnostic format.
3use cargo_metadata::diagnostic::{ 3use cargo_metadata::diagnostic::{
4 Applicability, Diagnostic as RustDiagnostic, DiagnosticLevel, DiagnosticSpan, 4 Diagnostic as RustDiagnostic, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion,
5 DiagnosticSpanMacroExpansion,
6}; 5};
7use lsp_types::{ 6use lsp_types::{
8 Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, DiagnosticTag, Location, 7 CodeAction, Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, DiagnosticTag,
9 NumberOrString, Position, Range, Url, 8 Location, NumberOrString, Position, Range, TextEdit, Url, WorkspaceEdit,
10}; 9};
11use std::{ 10use std::{
12 fmt::Write, 11 fmt::Write,
@@ -117,38 +116,9 @@ fn is_deprecated(rd: &RustDiagnostic) -> bool {
117 } 116 }
118} 117}
119 118
120#[derive(Clone, Debug)]
121pub struct SuggestedFix {
122 pub title: String,
123 pub location: Location,
124 pub replacement: String,
125 pub applicability: Applicability,
126 pub diagnostics: Vec<Diagnostic>,
127}
128
129impl std::cmp::PartialEq<SuggestedFix> for SuggestedFix {
130 fn eq(&self, other: &SuggestedFix) -> bool {
131 if self.title == other.title
132 && self.location == other.location
133 && self.replacement == other.replacement
134 {
135 // Applicability doesn't impl PartialEq...
136 match (&self.applicability, &other.applicability) {
137 (Applicability::MachineApplicable, Applicability::MachineApplicable) => true,
138 (Applicability::HasPlaceholders, Applicability::HasPlaceholders) => true,
139 (Applicability::MaybeIncorrect, Applicability::MaybeIncorrect) => true,
140 (Applicability::Unspecified, Applicability::Unspecified) => true,
141 _ => false,
142 }
143 } else {
144 false
145 }
146 }
147}
148
149enum MappedRustChildDiagnostic { 119enum MappedRustChildDiagnostic {
150 Related(DiagnosticRelatedInformation), 120 Related(DiagnosticRelatedInformation),
151 SuggestedFix(SuggestedFix), 121 SuggestedFix(CodeAction),
152 MessageLine(String), 122 MessageLine(String),
153} 123}
154 124
@@ -176,12 +146,20 @@ fn map_rust_child_diagnostic(
176 rd.message.clone() 146 rd.message.clone()
177 }; 147 };
178 148
179 MappedRustChildDiagnostic::SuggestedFix(SuggestedFix { 149 let edit = {
150 let edits = vec![TextEdit::new(location.range, suggested_replacement.clone())];
151 let mut edit_map = std::collections::HashMap::new();
152 edit_map.insert(location.uri, edits);
153 WorkspaceEdit::new(edit_map)
154 };
155
156 MappedRustChildDiagnostic::SuggestedFix(CodeAction {
180 title, 157 title,
181 location, 158 kind: Some("quickfix".to_string()),
182 replacement: suggested_replacement.clone(), 159 diagnostics: None,
183 applicability: span.suggestion_applicability.clone().unwrap_or(Applicability::Unknown), 160 edit: Some(edit),
184 diagnostics: vec![], 161 command: None,
162 is_preferred: None,
185 }) 163 })
186 } else { 164 } else {
187 MappedRustChildDiagnostic::Related(DiagnosticRelatedInformation { 165 MappedRustChildDiagnostic::Related(DiagnosticRelatedInformation {
@@ -195,7 +173,7 @@ fn map_rust_child_diagnostic(
195pub(crate) struct MappedRustDiagnostic { 173pub(crate) struct MappedRustDiagnostic {
196 pub location: Location, 174 pub location: Location,
197 pub diagnostic: Diagnostic, 175 pub diagnostic: Diagnostic,
198 pub suggested_fixes: Vec<SuggestedFix>, 176 pub fixes: Vec<CodeAction>,
199} 177}
200 178
201/// Converts a Rust root diagnostic to LSP form 179/// Converts a Rust root diagnostic to LSP form
@@ -250,15 +228,13 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
250 } 228 }
251 } 229 }
252 230
253 let mut suggested_fixes = vec![]; 231 let mut fixes = vec![];
254 let mut message = rd.message.clone(); 232 let mut message = rd.message.clone();
255 for child in &rd.children { 233 for child in &rd.children {
256 let child = map_rust_child_diagnostic(&child, workspace_root); 234 let child = map_rust_child_diagnostic(&child, workspace_root);
257 match child { 235 match child {
258 MappedRustChildDiagnostic::Related(related) => related_information.push(related), 236 MappedRustChildDiagnostic::Related(related) => related_information.push(related),
259 MappedRustChildDiagnostic::SuggestedFix(suggested_fix) => { 237 MappedRustChildDiagnostic::SuggestedFix(code_action) => fixes.push(code_action.into()),
260 suggested_fixes.push(suggested_fix)
261 }
262 MappedRustChildDiagnostic::MessageLine(message_line) => { 238 MappedRustChildDiagnostic::MessageLine(message_line) => {
263 write!(&mut message, "\n{}", message_line).unwrap(); 239 write!(&mut message, "\n{}", message_line).unwrap();
264 240
@@ -295,7 +271,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
295 tags: if !tags.is_empty() { Some(tags) } else { None }, 271 tags: if !tags.is_empty() { Some(tags) } else { None },
296 }; 272 };
297 273
298 Some(MappedRustDiagnostic { location, diagnostic, suggested_fixes }) 274 Some(MappedRustDiagnostic { location, diagnostic, fixes })
299} 275}
300 276
301/// Returns a `Url` object from a given path, will lowercase drive letters if present. 277/// Returns a `Url` object from a given path, will lowercase drive letters if present.