diff options
Diffstat (limited to 'crates/ra_cargo_watch/src/lib.rs')
-rw-r--r-- | crates/ra_cargo_watch/src/lib.rs | 50 |
1 files changed, 41 insertions, 9 deletions
diff --git a/crates/ra_cargo_watch/src/lib.rs b/crates/ra_cargo_watch/src/lib.rs index 7f4c9280c..ea7ddc86b 100644 --- a/crates/ra_cargo_watch/src/lib.rs +++ b/crates/ra_cargo_watch/src/lib.rs | |||
@@ -7,9 +7,9 @@ use lsp_types::{ | |||
7 | Diagnostic, Url, WorkDoneProgress, WorkDoneProgressBegin, WorkDoneProgressEnd, | 7 | Diagnostic, Url, WorkDoneProgress, WorkDoneProgressBegin, WorkDoneProgressEnd, |
8 | WorkDoneProgressReport, | 8 | WorkDoneProgressReport, |
9 | }; | 9 | }; |
10 | use parking_lot::RwLock; | ||
11 | use std::{ | 10 | use std::{ |
12 | collections::HashMap, | 11 | collections::HashMap, |
12 | io::{BufRead, BufReader}, | ||
13 | path::PathBuf, | 13 | path::PathBuf, |
14 | process::{Command, Stdio}, | 14 | process::{Command, Stdio}, |
15 | sync::Arc, | 15 | sync::Arc, |
@@ -38,7 +38,7 @@ pub struct CheckOptions { | |||
38 | #[derive(Debug)] | 38 | #[derive(Debug)] |
39 | pub struct CheckWatcher { | 39 | pub struct CheckWatcher { |
40 | pub task_recv: Receiver<CheckTask>, | 40 | pub task_recv: Receiver<CheckTask>, |
41 | pub state: Arc<RwLock<CheckState>>, | 41 | pub state: Arc<CheckState>, |
42 | cmd_send: Option<Sender<CheckCommand>>, | 42 | cmd_send: Option<Sender<CheckCommand>>, |
43 | handle: Option<JoinHandle<()>>, | 43 | handle: Option<JoinHandle<()>>, |
44 | } | 44 | } |
@@ -46,7 +46,7 @@ pub struct CheckWatcher { | |||
46 | impl CheckWatcher { | 46 | impl CheckWatcher { |
47 | pub fn new(options: &CheckOptions, workspace_root: PathBuf) -> CheckWatcher { | 47 | pub fn new(options: &CheckOptions, workspace_root: PathBuf) -> CheckWatcher { |
48 | let options = options.clone(); | 48 | let options = options.clone(); |
49 | let state = Arc::new(RwLock::new(CheckState::new())); | 49 | let state = Arc::new(CheckState::new()); |
50 | 50 | ||
51 | let (task_send, task_recv) = unbounded::<CheckTask>(); | 51 | let (task_send, task_recv) = unbounded::<CheckTask>(); |
52 | let (cmd_send, cmd_recv) = unbounded::<CheckCommand>(); | 52 | let (cmd_send, cmd_recv) = unbounded::<CheckCommand>(); |
@@ -59,7 +59,7 @@ impl CheckWatcher { | |||
59 | 59 | ||
60 | /// Returns a CheckWatcher that doesn't actually do anything | 60 | /// Returns a CheckWatcher that doesn't actually do anything |
61 | pub fn dummy() -> CheckWatcher { | 61 | pub fn dummy() -> CheckWatcher { |
62 | let state = Arc::new(RwLock::new(CheckState::new())); | 62 | let state = Arc::new(CheckState::new()); |
63 | CheckWatcher { task_recv: never(), cmd_send: None, handle: None, state } | 63 | CheckWatcher { task_recv: never(), cmd_send: None, handle: None, state } |
64 | } | 64 | } |
65 | 65 | ||
@@ -87,7 +87,7 @@ impl std::ops::Drop for CheckWatcher { | |||
87 | } | 87 | } |
88 | } | 88 | } |
89 | 89 | ||
90 | #[derive(Debug)] | 90 | #[derive(Clone, Debug)] |
91 | pub struct CheckState { | 91 | pub struct CheckState { |
92 | diagnostic_collection: HashMap<Url, Vec<Diagnostic>>, | 92 | diagnostic_collection: HashMap<Url, Vec<Diagnostic>>, |
93 | suggested_fix_collection: HashMap<Url, Vec<SuggestedFix>>, | 93 | suggested_fix_collection: HashMap<Url, Vec<SuggestedFix>>, |
@@ -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,15 +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 cargo_metadata::parse_messages(command.stdout.take().unwrap()) { | 353 | // We manually read a line at a time, instead of using serde's |
354 | // stream deserializers, because the deserializer cannot recover | ||
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); | ||
352 | let message = match message { | 372 | let message = match message { |
353 | Ok(message) => message, | 373 | Ok(message) => message, |
354 | Err(err) => { | 374 | Err(err) => { |
355 | log::error!("Invalid json from cargo check, ignoring: {}", err); | 375 | log::error!( |
376 | "Invalid json from cargo check, ignoring ({}): {:?} ", | ||
377 | err, | ||
378 | line | ||
379 | ); | ||
356 | continue; | 380 | continue; |
357 | } | 381 | } |
358 | }; | 382 | }; |
359 | 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 | |||
360 | match message_send.send(CheckEvent::Msg(message)) { | 392 | match message_send.send(CheckEvent::Msg(message)) { |
361 | Ok(()) => {} | 393 | Ok(()) => {} |
362 | Err(_err) => { | 394 | Err(_err) => { |