@@ -480,6 +480,13 @@ config_data! {
480
480
/// tests or binaries. For example, it may be `--release`.
481
481
runnables_extraArgs: Vec <String > = "[]" ,
482
482
483
+ /// Optional path to a rust-analyzer specific target directory.
484
+ /// This is useful to prevent rust-analyzer's `cargo check` from blocking builds.
485
+ ///
486
+ /// Set to `true` to use a subdirectory of the existing target directory or
487
+ /// set to a path to use that path.
488
+ rust_analyzerTargetDir: Option <TargetDirectory > = "null" ,
489
+
483
490
/// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private
484
491
/// projects, or "discover" to try to automatically find it if the `rustc-dev` component
485
492
/// is installed.
@@ -1192,6 +1199,7 @@ impl Config {
1192
1199
}
1193
1200
1194
1201
pub fn cargo ( & self ) -> CargoConfig {
1202
+ let target_directory = self . target_dir_from_config ( ) ;
1195
1203
let rustc_source = self . data . rustc_source . as_ref ( ) . map ( |rustc_src| {
1196
1204
if rustc_src == "discover" {
1197
1205
RustLibSource :: Discover
@@ -1209,6 +1217,10 @@ impl Config {
1209
1217
let sysroot_src =
1210
1218
self . data . cargo_sysrootSrc . as_ref ( ) . map ( |sysroot| self . root_path . join ( sysroot) ) ;
1211
1219
1220
+ let mut extra_args = self . data . cargo_extraArgs . clone ( ) ;
1221
+
1222
+ add_target_dir_to_args ( & mut extra_args, target_directory) ;
1223
+
1212
1224
CargoConfig {
1213
1225
features : match & self . data . cargo_features {
1214
1226
CargoFeaturesDef :: All => CargoFeatures :: All ,
@@ -1261,7 +1273,7 @@ impl Config {
1261
1273
InvocationLocation :: Workspace => project_model:: InvocationLocation :: Workspace ,
1262
1274
} ,
1263
1275
run_build_script_command : self . data . cargo_buildScripts_overrideCommand . clone ( ) ,
1264
- extra_args : self . data . cargo_extraArgs . clone ( ) ,
1276
+ extra_args,
1265
1277
extra_env : self . data . cargo_extraEnv . clone ( ) ,
1266
1278
}
1267
1279
}
@@ -1281,10 +1293,14 @@ impl Config {
1281
1293
}
1282
1294
1283
1295
pub fn flycheck ( & self ) -> FlycheckConfig {
1296
+ let target_directory = self . target_dir_from_config ( ) ;
1297
+
1284
1298
match & self . data . check_overrideCommand {
1285
1299
Some ( args) if !args. is_empty ( ) => {
1286
1300
let mut args = args. clone ( ) ;
1287
1301
let command = args. remove ( 0 ) ;
1302
+ add_target_dir_to_args ( & mut args, target_directory) ;
1303
+
1288
1304
FlycheckConfig :: CustomCommand {
1289
1305
command,
1290
1306
args,
@@ -1303,42 +1319,61 @@ impl Config {
1303
1319
} ,
1304
1320
}
1305
1321
}
1306
- Some ( _) | None => FlycheckConfig :: CargoCommand {
1307
- command : self . data . check_command . clone ( ) ,
1308
- target_triples : self
1309
- . data
1310
- . check_targets
1311
- . clone ( )
1312
- . and_then ( |targets| match & targets. 0 [ ..] {
1313
- [ ] => None ,
1314
- targets => Some ( targets. into ( ) ) ,
1315
- } )
1316
- . unwrap_or_else ( || self . data . cargo_target . clone ( ) . into_iter ( ) . collect ( ) ) ,
1317
- all_targets : self . data . check_allTargets ,
1318
- no_default_features : self
1319
- . data
1320
- . check_noDefaultFeatures
1321
- . unwrap_or ( self . data . cargo_noDefaultFeatures ) ,
1322
- all_features : matches ! (
1323
- self . data. check_features. as_ref( ) . unwrap_or( & self . data. cargo_features) ,
1324
- CargoFeaturesDef :: All
1325
- ) ,
1326
- features : match self
1327
- . data
1328
- . check_features
1329
- . clone ( )
1330
- . unwrap_or_else ( || self . data . cargo_features . clone ( ) )
1331
- {
1332
- CargoFeaturesDef :: All => vec ! [ ] ,
1333
- CargoFeaturesDef :: Selected ( it) => it,
1334
- } ,
1335
- extra_args : self . check_extra_args ( ) ,
1336
- extra_env : self . check_extra_env ( ) ,
1337
- ansi_color_output : self . color_diagnostic_output ( ) ,
1338
- } ,
1322
+ Some ( _) | None => {
1323
+ let mut extra_args = self . check_extra_args ( ) ;
1324
+ add_target_dir_to_args ( & mut extra_args, target_directory) ;
1325
+
1326
+ FlycheckConfig :: CargoCommand {
1327
+ command : self . data . check_command . clone ( ) ,
1328
+ target_triples : self
1329
+ . data
1330
+ . check_targets
1331
+ . clone ( )
1332
+ . and_then ( |targets| match & targets. 0 [ ..] {
1333
+ [ ] => None ,
1334
+ targets => Some ( targets. into ( ) ) ,
1335
+ } )
1336
+ . unwrap_or_else ( || self . data . cargo_target . clone ( ) . into_iter ( ) . collect ( ) ) ,
1337
+ all_targets : self . data . check_allTargets ,
1338
+ no_default_features : self
1339
+ . data
1340
+ . check_noDefaultFeatures
1341
+ . unwrap_or ( self . data . cargo_noDefaultFeatures ) ,
1342
+ all_features : matches ! (
1343
+ self . data. check_features. as_ref( ) . unwrap_or( & self . data. cargo_features) ,
1344
+ CargoFeaturesDef :: All
1345
+ ) ,
1346
+ features : match self
1347
+ . data
1348
+ . check_features
1349
+ . clone ( )
1350
+ . unwrap_or_else ( || self . data . cargo_features . clone ( ) )
1351
+ {
1352
+ CargoFeaturesDef :: All => vec ! [ ] ,
1353
+ CargoFeaturesDef :: Selected ( it) => it,
1354
+ } ,
1355
+ extra_args,
1356
+ extra_env : self . check_extra_env ( ) ,
1357
+ ansi_color_output : self . color_diagnostic_output ( ) ,
1358
+ }
1359
+ }
1339
1360
}
1340
1361
}
1341
1362
1363
+ fn target_dir_from_config ( & self ) -> Option < String > {
1364
+ self . data
1365
+ . rust_analyzerTargetDir
1366
+ . as_ref ( )
1367
+ . map ( |target_dir| match target_dir {
1368
+ TargetDirectory :: UseSubdirectory ( yes) if * yes => {
1369
+ Some ( String :: from ( "target/rust-analyzer" ) )
1370
+ }
1371
+ TargetDirectory :: UseSubdirectory ( _) => None ,
1372
+ TargetDirectory :: Directory ( dir) => Some ( dir. clone ( ) ) ,
1373
+ } )
1374
+ . flatten ( )
1375
+ }
1376
+
1342
1377
pub fn check_on_save ( & self ) -> bool {
1343
1378
self . data . checkOnSave
1344
1379
}
@@ -1690,6 +1725,13 @@ impl Config {
1690
1725
self . is_visual_studio_code
1691
1726
}
1692
1727
}
1728
+
1729
+ fn add_target_dir_to_args ( args : & mut Vec < String > , target_dir : Option < String > ) {
1730
+ if let Some ( target_dir) = target_dir {
1731
+ args. push ( format ! ( "--target-dir={}" , target_dir) ) ;
1732
+ }
1733
+ }
1734
+
1693
1735
// Deserialization definitions
1694
1736
1695
1737
macro_rules! create_bool_or_string_de {
@@ -2037,6 +2079,14 @@ pub enum MemoryLayoutHoverRenderKindDef {
2037
2079
Both ,
2038
2080
}
2039
2081
2082
+ #[ derive( Deserialize , Debug , Clone , PartialEq ) ]
2083
+ #[ serde( rename_all = "snake_case" ) ]
2084
+ #[ serde( untagged) ]
2085
+ pub enum TargetDirectory {
2086
+ UseSubdirectory ( bool ) ,
2087
+ Directory ( String ) ,
2088
+ }
2089
+
2040
2090
macro_rules! _config_data {
2041
2091
( struct $name: ident {
2042
2092
$(
@@ -2465,6 +2515,19 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
2465
2515
} ,
2466
2516
] ,
2467
2517
} ,
2518
+ "Option<TargetDirectory>" => set ! {
2519
+ "anyOf" : [
2520
+ {
2521
+ "type" : "null"
2522
+ } ,
2523
+ {
2524
+ "type" : "boolean"
2525
+ } ,
2526
+ {
2527
+ "type" : "string"
2528
+ } ,
2529
+ ] ,
2530
+ } ,
2468
2531
_ => panic ! ( "missing entry for {ty}: {default}" ) ,
2469
2532
}
2470
2533
@@ -2625,4 +2688,73 @@ mod tests {
2625
2688
Some ( AbsPathBuf :: try_from( project_root( ) . join( "./server" ) ) . unwrap( ) )
2626
2689
) ;
2627
2690
}
2691
+
2692
+ #[ test]
2693
+ fn cargo_target_dir_unset ( ) {
2694
+ let mut config = Config :: new (
2695
+ AbsPathBuf :: try_from ( project_root ( ) ) . unwrap ( ) ,
2696
+ Default :: default ( ) ,
2697
+ vec ! [ ] ,
2698
+ false ,
2699
+ ) ;
2700
+ config
2701
+ . update ( serde_json:: json!( {
2702
+ "rust" : { "analyzerTargetDir" : null }
2703
+ } ) )
2704
+ . unwrap ( ) ;
2705
+ assert_eq ! ( config. data. rust_analyzerTargetDir, None ) ;
2706
+ assert_eq ! ( config. cargo( ) . extra_args. len( ) , 0 ) ;
2707
+ assert ! (
2708
+ matches!( config. flycheck( ) , FlycheckConfig :: CargoCommand { extra_args, .. } if extra_args. is_empty( ) )
2709
+ ) ;
2710
+ }
2711
+
2712
+ #[ test]
2713
+ fn cargo_target_dir_subdir ( ) {
2714
+ let mut config = Config :: new (
2715
+ AbsPathBuf :: try_from ( project_root ( ) ) . unwrap ( ) ,
2716
+ Default :: default ( ) ,
2717
+ vec ! [ ] ,
2718
+ false ,
2719
+ ) ;
2720
+ config
2721
+ . update ( serde_json:: json!( {
2722
+ "rust" : { "analyzerTargetDir" : true }
2723
+ } ) )
2724
+ . unwrap ( ) ;
2725
+ assert_eq ! (
2726
+ config. data. rust_analyzerTargetDir,
2727
+ Some ( TargetDirectory :: UseSubdirectory ( true ) )
2728
+ ) ;
2729
+ assert_eq ! (
2730
+ config. cargo( ) . extra_args,
2731
+ vec![ "--target-dir=target/rust-analyzer" . to_string( ) ]
2732
+ ) ;
2733
+ assert ! (
2734
+ matches!( config. flycheck( ) , FlycheckConfig :: CargoCommand { extra_args, .. } if extra_args == vec![ "--target-dir=target/rust-analyzer" . to_string( ) ] )
2735
+ ) ;
2736
+ }
2737
+
2738
+ #[ test]
2739
+ fn cargo_target_dir_relative_dir ( ) {
2740
+ let mut config = Config :: new (
2741
+ AbsPathBuf :: try_from ( project_root ( ) ) . unwrap ( ) ,
2742
+ Default :: default ( ) ,
2743
+ vec ! [ ] ,
2744
+ false ,
2745
+ ) ;
2746
+ config
2747
+ . update ( serde_json:: json!( {
2748
+ "rust" : { "analyzerTargetDir" : "other_folder" }
2749
+ } ) )
2750
+ . unwrap ( ) ;
2751
+ assert_eq ! (
2752
+ config. data. rust_analyzerTargetDir,
2753
+ Some ( TargetDirectory :: Directory ( "other_folder" . to_string( ) ) )
2754
+ ) ;
2755
+ assert_eq ! ( config. cargo( ) . extra_args, vec![ "--target-dir=other_folder" . to_string( ) ] ) ;
2756
+ assert ! (
2757
+ matches!( config. flycheck( ) , FlycheckConfig :: CargoCommand { extra_args, .. } if extra_args == vec![ "--target-dir=other_folder" . to_string( ) ] )
2758
+ ) ;
2759
+ }
2628
2760
}
0 commit comments