5
5
#![ warn( rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros) ]
6
6
7
7
use std:: {
8
+ cell:: OnceCell ,
8
9
fmt, io,
9
10
process:: { ChildStderr , ChildStdout , Command , Stdio } ,
10
11
time:: Duration ,
11
12
} ;
12
13
13
14
use command_group:: { CommandGroup , GroupChild } ;
14
15
use crossbeam_channel:: { never, select, unbounded, Receiver , Sender } ;
15
- use paths:: AbsPathBuf ;
16
+ use paths:: { AbsPath , AbsPathBuf } ;
16
17
use rustc_hash:: FxHashMap ;
17
18
use serde:: Deserialize ;
18
19
use stdx:: process:: streaming_output;
@@ -173,6 +174,7 @@ struct FlycheckActor {
173
174
/// Either the workspace root of the workspace we are flychecking,
174
175
/// or the project root of the project.
175
176
root : AbsPathBuf ,
177
+ state : OnceCell < FlycheckState > ,
176
178
/// CargoHandle exists to wrap around the communication needed to be able to
177
179
/// run `cargo check` without blocking. Currently the Rust standard library
178
180
/// doesn't provide a way to read sub-process output without blocking, so we
@@ -181,6 +183,11 @@ struct FlycheckActor {
181
183
cargo_handle : Option < CargoHandle > ,
182
184
}
183
185
186
+ #[ derive( Debug ) ]
187
+ struct FlycheckState {
188
+ command : Command ,
189
+ }
190
+
184
191
enum Event {
185
192
RequestStateChange ( StateChange ) ,
186
193
CheckEvent ( Option < CargoMessage > ) ,
@@ -194,7 +201,14 @@ impl FlycheckActor {
194
201
workspace_root : AbsPathBuf ,
195
202
) -> FlycheckActor {
196
203
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
+ }
198
212
}
199
213
200
214
fn report_progress ( & self , progress : Progress ) {
@@ -230,15 +244,25 @@ impl FlycheckActor {
230
244
}
231
245
}
232
246
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" ) ;
235
259
236
- tracing :: debug! ( ? command, "restarting flycheck" ) ;
260
+ let command = self . state . get_mut ( ) . unwrap ( ) ;
237
261
238
- match CargoHandle :: spawn ( command) {
262
+ match CargoHandle :: spawn ( & mut command . command ) {
239
263
Ok ( cargo_handle) => {
240
264
tracing:: debug!(
241
- command = ?command_string ,
265
+ command = ?self . state ,
242
266
"did restart flycheck"
243
267
) ;
244
268
self . cargo_handle = Some ( cargo_handle) ;
@@ -247,7 +271,7 @@ impl FlycheckActor {
247
271
Err ( error) => {
248
272
self . report_progress ( Progress :: DidFailToRestart ( format ! (
249
273
"Failed to run the following command: {:?} error={}" ,
250
- command_string , error
274
+ & self . state , error
251
275
) ) ) ;
252
276
}
253
277
}
@@ -261,7 +285,7 @@ impl FlycheckActor {
261
285
if res. is_err ( ) {
262
286
tracing:: error!(
263
287
"Flycheck failed to run the following command: {:?}" ,
264
- self . check_command ( None )
288
+ self . config
265
289
) ;
266
290
}
267
291
self . report_progress ( Progress :: DidFinish ( res) ) ;
@@ -297,13 +321,13 @@ impl FlycheckActor {
297
321
298
322
fn cancel_check_process ( & mut self ) {
299
323
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" ) ;
301
325
cargo_handle. cancel ( ) ;
302
326
self . report_progress ( Progress :: DidCancel ) ;
303
327
}
304
328
}
305
329
306
- fn check_command ( & self , saved_file : Option < AbsPathBuf > ) -> Command {
330
+ fn make_check_command ( & self , saved_file : Option < & AbsPath > ) -> Command {
307
331
let ( mut cmd, args) = match & self . config {
308
332
FlycheckConfig :: CargoCommand {
309
333
command,
@@ -385,18 +409,7 @@ impl FlycheckActor {
385
409
args[ i] = saved_file. to_string ( ) ;
386
410
( cmd, args)
387
411
}
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" ) ,
400
413
}
401
414
} else {
402
415
( cmd, args. clone ( ) )
@@ -433,7 +446,7 @@ struct CargoHandle {
433
446
}
434
447
435
448
impl CargoHandle {
436
- fn spawn ( mut command : Command ) -> std:: io:: Result < CargoHandle > {
449
+ fn spawn ( command : & mut Command ) -> std:: io:: Result < CargoHandle > {
437
450
command. stdout ( Stdio :: piped ( ) ) . stderr ( Stdio :: piped ( ) ) . stdin ( Stdio :: null ( ) ) ;
438
451
let mut child = command. group_spawn ( ) . map ( JodGroupChild ) ?;
439
452
0 commit comments