aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_flycheck/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_flycheck/src/lib.rs')
-rw-r--r--crates/ra_flycheck/src/lib.rs108
1 files changed, 35 insertions, 73 deletions
diff --git a/crates/ra_flycheck/src/lib.rs b/crates/ra_flycheck/src/lib.rs
index b54a30ab8..041e38a9f 100644
--- a/crates/ra_flycheck/src/lib.rs
+++ b/crates/ra_flycheck/src/lib.rs
@@ -1,11 +1,9 @@
1//! cargo_check provides the functionality needed to run `cargo check` or 1//! cargo_check provides the functionality needed to run `cargo check` or
2//! another compatible command (f.x. clippy) in a background thread and provide 2//! another compatible command (f.x. clippy) in a background thread and provide
3//! LSP diagnostics based on the output of the command. 3//! LSP diagnostics based on the output of the command.
4mod conv;
5 4
6use std::{ 5use std::{
7 env, 6 io::{self, BufReader},
8 io::{self, BufRead, BufReader},
9 path::PathBuf, 7 path::PathBuf,
10 process::{Command, Stdio}, 8 process::{Command, Stdio},
11 time::Instant, 9 time::Instant,
@@ -13,18 +11,14 @@ use std::{
13 11
14use cargo_metadata::Message; 12use cargo_metadata::Message;
15use crossbeam_channel::{never, select, unbounded, Receiver, RecvError, Sender}; 13use crossbeam_channel::{never, select, unbounded, Receiver, RecvError, Sender};
16use lsp_types::{
17 CodeAction, CodeActionOrCommand, Diagnostic, Url, WorkDoneProgress, WorkDoneProgressBegin,
18 WorkDoneProgressEnd, WorkDoneProgressReport,
19};
20
21use crate::conv::{map_rust_diagnostic_to_lsp, MappedRustDiagnostic};
22 14
23pub use crate::conv::url_from_path_with_drive_lowercasing; 15pub use cargo_metadata::diagnostic::{
16 Applicability, Diagnostic, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion,
17};
24 18
25#[derive(Clone, Debug, PartialEq, Eq)] 19#[derive(Clone, Debug, PartialEq, Eq)]
26pub enum FlycheckConfig { 20pub enum FlycheckConfig {
27 CargoCommand { command: String, all_targets: bool, extra_args: Vec<String> }, 21 CargoCommand { command: String, all_targets: bool, all_features: bool, extra_args: Vec<String> },
28 CustomCommand { command: String, args: Vec<String> }, 22 CustomCommand { command: String, args: Vec<String> },
29} 23}
30 24
@@ -62,10 +56,17 @@ pub enum CheckTask {
62 ClearDiagnostics, 56 ClearDiagnostics,
63 57
64 /// Request adding a diagnostic with fixes included to a file 58 /// Request adding a diagnostic with fixes included to a file
65 AddDiagnostic { url: Url, diagnostic: Diagnostic, fixes: Vec<CodeActionOrCommand> }, 59 AddDiagnostic { workspace_root: PathBuf, diagnostic: Diagnostic },
66 60
67 /// Request check progress notification to client 61 /// Request check progress notification to client
68 Status(WorkDoneProgress), 62 Status(Status),
63}
64
65#[derive(Debug)]
66pub enum Status {
67 Being,
68 Progress(String),
69 End,
69} 70}
70 71
71pub enum CheckCommand { 72pub enum CheckCommand {
@@ -132,9 +133,7 @@ impl FlycheckThread {
132 133
133 fn clean_previous_results(&self, task_send: &Sender<CheckTask>) { 134 fn clean_previous_results(&self, task_send: &Sender<CheckTask>) {
134 task_send.send(CheckTask::ClearDiagnostics).unwrap(); 135 task_send.send(CheckTask::ClearDiagnostics).unwrap();
135 task_send 136 task_send.send(CheckTask::Status(Status::End)).unwrap();
136 .send(CheckTask::Status(WorkDoneProgress::End(WorkDoneProgressEnd { message: None })))
137 .unwrap();
138 } 137 }
139 138
140 fn should_recheck(&mut self) -> bool { 139 fn should_recheck(&mut self) -> bool {
@@ -156,55 +155,29 @@ impl FlycheckThread {
156 fn handle_message(&self, msg: CheckEvent, task_send: &Sender<CheckTask>) { 155 fn handle_message(&self, msg: CheckEvent, task_send: &Sender<CheckTask>) {
157 match msg { 156 match msg {
158 CheckEvent::Begin => { 157 CheckEvent::Begin => {
159 task_send 158 task_send.send(CheckTask::Status(Status::Being)).unwrap();
160 .send(CheckTask::Status(WorkDoneProgress::Begin(WorkDoneProgressBegin {
161 title: "Running 'cargo check'".to_string(),
162 cancellable: Some(false),
163 message: None,
164 percentage: None,
165 })))
166 .unwrap();
167 } 159 }
168 160
169 CheckEvent::End => { 161 CheckEvent::End => {
170 task_send 162 task_send.send(CheckTask::Status(Status::End)).unwrap();
171 .send(CheckTask::Status(WorkDoneProgress::End(WorkDoneProgressEnd {
172 message: None,
173 })))
174 .unwrap();
175 } 163 }
176 164
177 CheckEvent::Msg(Message::CompilerArtifact(msg)) => { 165 CheckEvent::Msg(Message::CompilerArtifact(msg)) => {
178 task_send 166 task_send.send(CheckTask::Status(Status::Progress(msg.target.name))).unwrap();
179 .send(CheckTask::Status(WorkDoneProgress::Report(WorkDoneProgressReport {
180 cancellable: Some(false),
181 message: Some(msg.target.name),
182 percentage: None,
183 })))
184 .unwrap();
185 } 167 }
186 168
187 CheckEvent::Msg(Message::CompilerMessage(msg)) => { 169 CheckEvent::Msg(Message::CompilerMessage(msg)) => {
188 let map_result = map_rust_diagnostic_to_lsp(&msg.message, &self.workspace_root); 170 task_send
189 if map_result.is_empty() { 171 .send(CheckTask::AddDiagnostic {
190 return; 172 workspace_root: self.workspace_root.clone(),
191 } 173 diagnostic: msg.message,
192 174 })
193 for MappedRustDiagnostic { location, diagnostic, fixes } in map_result { 175 .unwrap();
194 let fixes = fixes
195 .into_iter()
196 .map(|fix| {
197 CodeAction { diagnostics: Some(vec![diagnostic.clone()]), ..fix }.into()
198 })
199 .collect();
200
201 task_send
202 .send(CheckTask::AddDiagnostic { url: location.uri, diagnostic, fixes })
203 .unwrap();
204 }
205 } 176 }
206 177
207 CheckEvent::Msg(Message::BuildScriptExecuted(_msg)) => {} 178 CheckEvent::Msg(Message::BuildScriptExecuted(_msg)) => {}
179 CheckEvent::Msg(Message::BuildFinished(_)) => {}
180 CheckEvent::Msg(Message::TextLine(_)) => {}
208 CheckEvent::Msg(Message::Unknown) => {} 181 CheckEvent::Msg(Message::Unknown) => {}
209 } 182 }
210 } 183 }
@@ -215,14 +188,17 @@ impl FlycheckThread {
215 self.check_process = None; 188 self.check_process = None;
216 189
217 let mut cmd = match &self.config { 190 let mut cmd = match &self.config {
218 FlycheckConfig::CargoCommand { command, all_targets, extra_args } => { 191 FlycheckConfig::CargoCommand { command, all_targets, all_features, extra_args } => {
219 let mut cmd = Command::new(cargo_binary()); 192 let mut cmd = Command::new(ra_toolchain::cargo());
220 cmd.arg(command); 193 cmd.arg(command);
221 cmd.args(&["--workspace", "--message-format=json", "--manifest-path"]); 194 cmd.args(&["--workspace", "--message-format=json", "--manifest-path"])
222 cmd.arg(self.workspace_root.join("Cargo.toml")); 195 .arg(self.workspace_root.join("Cargo.toml"));
223 if *all_targets { 196 if *all_targets {
224 cmd.arg("--all-targets"); 197 cmd.arg("--all-targets");
225 } 198 }
199 if *all_features {
200 cmd.arg("--all-features");
201 }
226 cmd.args(extra_args); 202 cmd.args(extra_args);
227 cmd 203 cmd
228 } 204 }
@@ -267,12 +243,6 @@ impl FlycheckThread {
267 } 243 }
268} 244}
269 245
270#[derive(Debug)]
271pub struct DiagnosticWithFixes {
272 diagnostic: Diagnostic,
273 fixes: Vec<CodeAction>,
274}
275
276enum CheckEvent { 246enum CheckEvent {
277 Begin, 247 Begin,
278 Msg(cargo_metadata::Message), 248 Msg(cargo_metadata::Message),
@@ -296,15 +266,11 @@ fn run_cargo(
296 // erroneus output. 266 // erroneus output.
297 let stdout = BufReader::new(child.stdout.take().unwrap()); 267 let stdout = BufReader::new(child.stdout.take().unwrap());
298 let mut read_at_least_one_message = false; 268 let mut read_at_least_one_message = false;
299 269 for message in cargo_metadata::Message::parse_stream(stdout) {
300 for line in stdout.lines() {
301 let line = line?;
302
303 let message = serde_json::from_str::<cargo_metadata::Message>(&line);
304 let message = match message { 270 let message = match message {
305 Ok(message) => message, 271 Ok(message) => message,
306 Err(err) => { 272 Err(err) => {
307 log::error!("Invalid json from cargo check, ignoring ({}): {:?} ", err, line); 273 log::error!("Invalid json from cargo check, ignoring ({})", err);
308 continue; 274 continue;
309 } 275 }
310 }; 276 };
@@ -334,7 +300,3 @@ fn run_cargo(
334 300
335 Ok(()) 301 Ok(())
336} 302}
337
338fn cargo_binary() -> String {
339 env::var("CARGO").unwrap_or_else(|_| "cargo".to_string())
340}