2
2
//! metadata` or `rust-project.json`) into representation stored in the salsa
3
3
//! database -- `CrateGraph`.
4
4
5
- use std:: { collections:: VecDeque , fmt, fs, iter, sync} ;
5
+ use std:: { collections:: VecDeque , fmt, fs, io :: BufRead , iter, sync} ;
6
6
7
7
use anyhow:: { format_err, Context } ;
8
8
use base_db:: {
@@ -115,9 +115,55 @@ pub enum ProjectWorkspace {
115
115
target_layout : TargetLayoutLoadResult ,
116
116
/// A set of cfg overrides for the files.
117
117
cfg_overrides : CfgOverrides ,
118
+ /// Is this file a cargo script file?
119
+ cargo_script : Option < CargoWorkspace > ,
118
120
} ,
119
121
}
120
122
123
+ /// Tracks the cargo toml parts in cargo scripts, to detect if they
124
+ /// changed and reload workspace in that case.
125
+ pub struct CargoScriptTomls ( pub FxHashMap < AbsPathBuf , String > ) ;
126
+
127
+ impl CargoScriptTomls {
128
+ fn extract_toml_part ( p : & AbsPath ) -> Option < String > {
129
+ let mut r = String :: new ( ) ;
130
+ let f = std:: fs:: File :: open ( p) . ok ( ) ?;
131
+ let f = std:: io:: BufReader :: new ( f) ;
132
+ let mut started = false ;
133
+ for line in f. lines ( ) {
134
+ let line = line. ok ( ) ?;
135
+ if started {
136
+ if line. trim ( ) == "//! ```" {
137
+ return Some ( r) ;
138
+ }
139
+ r += & line;
140
+ } else {
141
+ if line. trim ( ) == "//! ```cargo" {
142
+ started = true ;
143
+ }
144
+ }
145
+ }
146
+ None
147
+ }
148
+
149
+ pub fn track_file ( & mut self , p : AbsPathBuf ) {
150
+ let toml = CargoScriptTomls :: extract_toml_part ( & p) . unwrap_or_default ( ) ;
151
+ self . 0 . insert ( p, toml) ;
152
+ }
153
+
154
+ pub fn need_reload ( & mut self , p : & AbsPath ) -> bool {
155
+ let Some ( prev) = self . 0 . get_mut ( p) else {
156
+ return false ; // File is not tracked
157
+ } ;
158
+ let next = CargoScriptTomls :: extract_toml_part ( p) . unwrap_or_default ( ) ;
159
+ if * prev == next {
160
+ return false ;
161
+ }
162
+ * prev = next;
163
+ true
164
+ }
165
+ }
166
+
121
167
impl fmt:: Debug for ProjectWorkspace {
122
168
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
123
169
// Make sure this isn't too verbose.
@@ -174,10 +220,12 @@ impl fmt::Debug for ProjectWorkspace {
174
220
toolchain,
175
221
target_layout,
176
222
cfg_overrides,
223
+ cargo_script,
177
224
} => f
178
225
. debug_struct ( "DetachedFiles" )
179
226
. field ( "n_files" , & files. len ( ) )
180
227
. field ( "sysroot" , & sysroot. is_ok ( ) )
228
+ . field ( "cargo_script" , & cargo_script. is_some ( ) )
181
229
. field ( "n_rustc_cfg" , & rustc_cfg. len ( ) )
182
230
. field ( "toolchain" , & toolchain)
183
231
. field ( "data_layout" , & target_layout)
@@ -431,6 +479,7 @@ impl ProjectWorkspace {
431
479
pub fn load_detached_files (
432
480
detached_files : Vec < AbsPathBuf > ,
433
481
config : & CargoConfig ,
482
+ cargo_script_tomls : & mut CargoScriptTomls ,
434
483
) -> anyhow:: Result < ProjectWorkspace > {
435
484
let dir = detached_files
436
485
. first ( )
@@ -469,13 +518,31 @@ impl ProjectWorkspace {
469
518
None ,
470
519
& config. extra_env ,
471
520
) ;
521
+ let cargo_toml = ManifestPath :: try_from ( detached_files[ 0 ] . clone ( ) ) . unwrap ( ) ;
522
+ let meta = CargoWorkspace :: fetch_metadata (
523
+ & cargo_toml,
524
+ cargo_toml. parent ( ) ,
525
+ config,
526
+ sysroot_ref,
527
+ & |_| ( ) ,
528
+ )
529
+ . with_context ( || {
530
+ format ! ( "Failed to read Cargo metadata from Cargo.toml file {cargo_toml}" )
531
+ } ) ?;
532
+ let cargo = CargoWorkspace :: new ( meta) ;
533
+
534
+ for file in & detached_files {
535
+ cargo_script_tomls. track_file ( file. clone ( ) ) ;
536
+ }
537
+
472
538
Ok ( ProjectWorkspace :: DetachedFiles {
473
539
files : detached_files,
474
540
sysroot,
475
541
rustc_cfg,
476
542
toolchain,
477
543
target_layout : data_layout. map ( Arc :: from) . map_err ( |it| Arc :: from ( it. to_string ( ) ) ) ,
478
544
cfg_overrides : config. cfg_overrides . clone ( ) ,
545
+ cargo_script : Some ( cargo) ,
479
546
} )
480
547
}
481
548
@@ -788,14 +855,27 @@ impl ProjectWorkspace {
788
855
toolchain : _,
789
856
target_layout : _,
790
857
cfg_overrides,
858
+ cargo_script,
791
859
} => (
792
- detached_files_to_crate_graph (
793
- rustc_cfg. clone ( ) ,
794
- load,
795
- files,
796
- sysroot. as_ref ( ) . ok ( ) ,
797
- cfg_overrides,
798
- ) ,
860
+ if let Some ( cargo) = cargo_script {
861
+ cargo_to_crate_graph (
862
+ load,
863
+ None ,
864
+ cargo,
865
+ sysroot. as_ref ( ) . ok ( ) ,
866
+ rustc_cfg. clone ( ) ,
867
+ cfg_overrides,
868
+ & WorkspaceBuildScripts :: default ( ) ,
869
+ )
870
+ } else {
871
+ detached_files_to_crate_graph (
872
+ rustc_cfg. clone ( ) ,
873
+ load,
874
+ files,
875
+ sysroot. as_ref ( ) . ok ( ) ,
876
+ cfg_overrides,
877
+ )
878
+ } ,
799
879
sysroot,
800
880
) ,
801
881
} ;
@@ -873,6 +953,7 @@ impl ProjectWorkspace {
873
953
files,
874
954
sysroot,
875
955
rustc_cfg,
956
+ cargo_script,
876
957
toolchain,
877
958
target_layout,
878
959
cfg_overrides,
@@ -881,6 +962,7 @@ impl ProjectWorkspace {
881
962
files : o_files,
882
963
sysroot : o_sysroot,
883
964
rustc_cfg : o_rustc_cfg,
965
+ cargo_script : o_cargo_script,
884
966
toolchain : o_toolchain,
885
967
target_layout : o_target_layout,
886
968
cfg_overrides : o_cfg_overrides,
@@ -892,6 +974,7 @@ impl ProjectWorkspace {
892
974
&& toolchain == o_toolchain
893
975
&& target_layout == o_target_layout
894
976
&& cfg_overrides == o_cfg_overrides
977
+ && cargo_script == o_cargo_script
895
978
}
896
979
_ => false ,
897
980
}
0 commit comments