55#![ warn( rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros) ]
66
77use std:: {
8+ cell:: OnceCell ,
89 fmt, io,
910 process:: { ChildStderr , ChildStdout , Command , Stdio } ,
1011 time:: Duration ,
1112} ;
1213
1314use command_group:: { CommandGroup , GroupChild } ;
1415use crossbeam_channel:: { never, select, unbounded, Receiver , Sender } ;
15- use paths:: AbsPathBuf ;
16+ use paths:: { AbsPath , AbsPathBuf } ;
1617use rustc_hash:: FxHashMap ;
1718use serde:: Deserialize ;
1819use stdx:: process:: streaming_output;
@@ -173,6 +174,7 @@ struct FlycheckActor {
173174 /// Either the workspace root of the workspace we are flychecking,
174175 /// or the project root of the project.
175176 root : AbsPathBuf ,
177+ state : OnceCell < FlycheckState > ,
176178 /// CargoHandle exists to wrap around the communication needed to be able to
177179 /// run `cargo check` without blocking. Currently the Rust standard library
178180 /// doesn't provide a way to read sub-process output without blocking, so we
@@ -181,6 +183,11 @@ struct FlycheckActor {
181183 cargo_handle : Option < CargoHandle > ,
182184}
183185
186+ #[ derive( Debug ) ]
187+ struct FlycheckState {
188+ command : Command ,
189+ }
190+
184191enum Event {
185192 RequestStateChange ( StateChange ) ,
186193 CheckEvent ( Option < CargoMessage > ) ,
@@ -194,7 +201,14 @@ impl FlycheckActor {
194201 workspace_root : AbsPathBuf ,
195202 ) -> FlycheckActor {
196203 tracing:: info!( %id, ?workspace_root, "Spawning flycheck" ) ;
197- FlycheckActor { id, sender, config, root : workspace_root, cargo_handle : None }
204+ FlycheckActor {
205+ id,
206+ sender,
207+ config,
208+ root : workspace_root,
209+ state : OnceCell :: new ( ) ,
210+ cargo_handle : None ,
211+ }
198212 }
199213
200214 fn report_progress ( & self , progress : Progress ) {
@@ -230,15 +244,25 @@ impl FlycheckActor {
230244 }
231245 }
232246
233- let command = self . check_command ( saved_file) ;
234- let command_string = format ! ( "{:?}" , command) ;
247+ let command = self . make_check_command ( saved_file. as_deref ( ) ) ;
248+ let state = FlycheckState { command } ;
249+ match self . state . get_mut ( ) {
250+ Some ( old_state) => * old_state = state,
251+ None => {
252+ self . state . set ( state) . expect (
253+ "Unreachable code, as the state of the OnceCell was checked." ,
254+ ) ;
255+ }
256+ } ;
257+
258+ tracing:: debug!( state = ?self . config, "restarting flycheck" ) ;
235259
236- tracing :: debug! ( ? command, "restarting flycheck" ) ;
260+ let command = self . state . get_mut ( ) . unwrap ( ) ;
237261
238- match CargoHandle :: spawn ( command) {
262+ match CargoHandle :: spawn ( & mut command . command ) {
239263 Ok ( cargo_handle) => {
240264 tracing:: debug!(
241- command = ?command_string ,
265+ command = ?self . state ,
242266 "did restart flycheck"
243267 ) ;
244268 self . cargo_handle = Some ( cargo_handle) ;
@@ -247,7 +271,7 @@ impl FlycheckActor {
247271 Err ( error) => {
248272 self . report_progress ( Progress :: DidFailToRestart ( format ! (
249273 "Failed to run the following command: {:?} error={}" ,
250- command_string , error
274+ & self . state , error
251275 ) ) ) ;
252276 }
253277 }
@@ -261,7 +285,7 @@ impl FlycheckActor {
261285 if res. is_err ( ) {
262286 tracing:: error!(
263287 "Flycheck failed to run the following command: {:?}" ,
264- self . check_command ( None )
288+ self . config
265289 ) ;
266290 }
267291 self . report_progress ( Progress :: DidFinish ( res) ) ;
@@ -297,13 +321,13 @@ impl FlycheckActor {
297321
298322 fn cancel_check_process ( & mut self ) {
299323 if let Some ( cargo_handle) = self . cargo_handle . take ( ) {
300- tracing:: debug!( command = ?self . check_command ( None ) , "did cancel flycheck" ) ;
324+ tracing:: debug!( command = ?self . config , "did cancel flycheck" ) ;
301325 cargo_handle. cancel ( ) ;
302326 self . report_progress ( Progress :: DidCancel ) ;
303327 }
304328 }
305329
306- fn check_command ( & self , saved_file : Option < AbsPathBuf > ) -> Command {
330+ fn make_check_command ( & self , saved_file : Option < & AbsPath > ) -> Command {
307331 let ( mut cmd, args) = match & self . config {
308332 FlycheckConfig :: CargoCommand {
309333 command,
@@ -385,18 +409,7 @@ impl FlycheckActor {
385409 args[ i] = saved_file. to_string ( ) ;
386410 ( cmd, args)
387411 }
388- ( None , Some ( saved_file) ) => {
389- dbg ! ( "no index, saved file included: {}" , & saved_file) ;
390- unreachable ! ( )
391- }
392- ( Some ( i) , None ) => {
393- dbg ! ( "index, no saved file included: {}" , & i) ;
394- unreachable ! ( )
395- }
396- ( None , None ) => {
397- dbg ! ( "No index or no saved file included" ) ;
398- unreachable ! ( )
399- }
412+ _ => unreachable ! ( "This is a broken invariant inside of rust-analyzer" ) ,
400413 }
401414 } else {
402415 ( cmd, args. clone ( ) )
@@ -433,7 +446,7 @@ struct CargoHandle {
433446}
434447
435448impl CargoHandle {
436- fn spawn ( mut command : Command ) -> std:: io:: Result < CargoHandle > {
449+ fn spawn ( command : & mut Command ) -> std:: io:: Result < CargoHandle > {
437450 command. stdout ( Stdio :: piped ( ) ) . stderr ( Stdio :: piped ( ) ) . stdin ( Stdio :: null ( ) ) ;
438451 let mut child = command. group_spawn ( ) . map ( JodGroupChild ) ?;
439452
0 commit comments