aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_cargo_watch
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_cargo_watch')
-rw-r--r--crates/ra_cargo_watch/Cargo.toml1
-rw-r--r--crates/ra_cargo_watch/src/lib.rs44
2 files changed, 38 insertions, 7 deletions
diff --git a/crates/ra_cargo_watch/Cargo.toml b/crates/ra_cargo_watch/Cargo.toml
index 49e06e0d3..dd814fc9d 100644
--- a/crates/ra_cargo_watch/Cargo.toml
+++ b/crates/ra_cargo_watch/Cargo.toml
@@ -11,6 +11,7 @@ log = "0.4.3"
11cargo_metadata = "0.9.1" 11cargo_metadata = "0.9.1"
12jod-thread = "0.1.0" 12jod-thread = "0.1.0"
13parking_lot = "0.10.0" 13parking_lot = "0.10.0"
14serde_json = "1.0.45"
14 15
15[dev-dependencies] 16[dev-dependencies]
16insta = "0.13.0" 17insta = "0.13.0"
diff --git a/crates/ra_cargo_watch/src/lib.rs b/crates/ra_cargo_watch/src/lib.rs
index e7b700c10..ea7ddc86b 100644
--- a/crates/ra_cargo_watch/src/lib.rs
+++ b/crates/ra_cargo_watch/src/lib.rs
@@ -9,7 +9,7 @@ use lsp_types::{
9}; 9};
10use std::{ 10use std::{
11 collections::HashMap, 11 collections::HashMap,
12 io::BufReader, 12 io::{BufRead, BufReader},
13 path::PathBuf, 13 path::PathBuf,
14 process::{Command, Stdio}, 14 process::{Command, Stdio},
15 sync::Arc, 15 sync::Arc,
@@ -216,8 +216,10 @@ impl CheckWatcherThread {
216 self.last_update_req.take(); 216 self.last_update_req.take();
217 task_send.send(CheckTask::ClearDiagnostics).unwrap(); 217 task_send.send(CheckTask::ClearDiagnostics).unwrap();
218 218
219 // By replacing the watcher, we drop the previous one which 219 // Replace with a dummy watcher first so we drop the original and wait for completion
220 // causes it to shut down automatically. 220 std::mem::replace(&mut self.watcher, WatchThread::dummy());
221
222 // Then create the actual new watcher
221 self.watcher = WatchThread::new(&self.options, &self.workspace_root); 223 self.watcher = WatchThread::new(&self.options, &self.workspace_root);
222 } 224 }
223 } 225 }
@@ -348,17 +350,45 @@ impl WatchThread {
348 // which will break out of the loop, and continue the shutdown 350 // which will break out of the loop, and continue the shutdown
349 let _ = message_send.send(CheckEvent::Begin); 351 let _ = message_send.send(CheckEvent::Begin);
350 352
351 for message in 353 // We manually read a line at a time, instead of using serde's
352 cargo_metadata::parse_messages(BufReader::new(command.stdout.take().unwrap())) 354 // stream deserializers, because the deserializer cannot recover
353 { 355 // from an error, resulting in it getting stuck, because we try to
356 // be resillient against failures.
357 //
358 // Because cargo only outputs one JSON object per line, we can
359 // simply skip a line if it doesn't parse, which just ignores any
360 // erroneus output.
361 let stdout = BufReader::new(command.stdout.take().unwrap());
362 for line in stdout.lines() {
363 let line = match line {
364 Ok(line) => line,
365 Err(err) => {
366 log::error!("Couldn't read line from cargo: {}", err);
367 continue;
368 }
369 };
370
371 let message = serde_json::from_str::<cargo_metadata::Message>(&line);
354 let message = match message { 372 let message = match message {
355 Ok(message) => message, 373 Ok(message) => message,
356 Err(err) => { 374 Err(err) => {
357 log::error!("Invalid json from cargo check, ignoring: {}", err); 375 log::error!(
376 "Invalid json from cargo check, ignoring ({}): {:?} ",
377 err,
378 line
379 );
358 continue; 380 continue;
359 } 381 }
360 }; 382 };
361 383
384 // Skip certain kinds of messages to only spend time on what's useful
385 match &message {
386 Message::CompilerArtifact(artifact) if artifact.fresh => continue,
387 Message::BuildScriptExecuted(_) => continue,
388 Message::Unknown => continue,
389 _ => {}
390 }
391
362 match message_send.send(CheckEvent::Msg(message)) { 392 match message_send.send(CheckEvent::Msg(message)) {
363 Ok(()) => {} 393 Ok(()) => {}
364 Err(_err) => { 394 Err(_err) => {