1
1
use itertools:: Itertools ;
2
- use log:: { debug, error, info} ;
2
+ use log:: { debug, error, info, warn } ;
3
3
use ra_ap_base_db:: SourceDatabase ;
4
4
use ra_ap_hir:: Semantics ;
5
5
use ra_ap_ide_db:: RootDatabase ;
@@ -16,6 +16,7 @@ use ra_ap_syntax::SyntaxError;
16
16
use ra_ap_vfs:: Vfs ;
17
17
use ra_ap_vfs:: VfsPath ;
18
18
use ra_ap_vfs:: { AbsPathBuf , FileId } ;
19
+ use serde:: Deserialize ;
19
20
use std:: borrow:: Cow ;
20
21
use std:: collections:: { HashMap , HashSet } ;
21
22
use std:: fs;
@@ -131,8 +132,19 @@ impl<'a> RustAnalyzer<'a> {
131
132
}
132
133
}
133
134
135
+ #[ derive( Deserialize ) ]
136
+ struct CargoManifestMembersSlice {
137
+ #[ serde( default ) ]
138
+ members : Vec < String > ,
139
+ }
140
+
141
+ #[ derive( Deserialize ) ]
142
+ struct CargoManifestSlice {
143
+ workspace : Option < CargoManifestMembersSlice > ,
144
+ }
145
+
134
146
struct ToMlReader {
135
- cache : HashMap < ManifestPath , Rc < toml :: Table > > ,
147
+ cache : HashMap < ManifestPath , Rc < CargoManifestSlice > > ,
136
148
}
137
149
138
150
impl ToMlReader {
@@ -142,15 +154,15 @@ impl ToMlReader {
142
154
}
143
155
}
144
156
145
- fn read ( & mut self , manifest : & ManifestPath ) -> anyhow:: Result < Rc < toml :: Table > > {
157
+ fn read ( & mut self , manifest : & ManifestPath ) -> anyhow:: Result < Rc < CargoManifestSlice > > {
146
158
if let Some ( table) = self . cache . get ( manifest) {
147
159
return Ok ( table. clone ( ) ) ;
148
160
}
149
161
let content = fs:: read_to_string ( manifest) . map_err ( |e| {
150
162
error ! ( "failed to read {} ({e})" , manifest. as_str( ) ) ;
151
163
e
152
164
} ) ?;
153
- let table = Rc :: < toml :: Table > :: new ( content . parse ( ) . map_err ( |e| {
165
+ let table = Rc :: < CargoManifestSlice > :: new ( toml :: from_str ( & content ) . map_err ( |e| {
154
166
error ! ( "failed to parse {} ({e})" , manifest. as_str( ) ) ;
155
167
e
156
168
} ) ?) ;
@@ -159,46 +171,50 @@ impl ToMlReader {
159
171
}
160
172
}
161
173
162
- fn find_workspace (
163
- reader : & mut ToMlReader ,
164
- manifest : & ProjectManifest ,
165
- ) -> anyhow:: Result < ProjectManifest > {
174
+ fn find_workspace ( reader : & mut ToMlReader , manifest : & ProjectManifest ) -> Option < ProjectManifest > {
166
175
let ProjectManifest :: CargoToml ( cargo) = manifest else {
167
- return Err ( anyhow :: anyhow! ( "{manifest} not a cargo manifest" ) ) ;
176
+ return None ;
168
177
} ;
169
- let toml = reader. read ( cargo) ?;
170
- if toml. contains_key ( "workspace" ) {
171
- return Ok ( manifest. clone ( ) ) ;
178
+ let parsed_cargo = reader. read ( cargo) . ok ( ) ?;
179
+ if parsed_cargo. workspace . is_some ( ) {
180
+ debug ! ( "{cargo} is a workspace" ) ;
181
+ return Some ( manifest. clone ( ) ) ;
172
182
}
173
183
let Some ( parent_dir) = cargo. parent ( ) . parent ( ) else {
174
- return Err ( anyhow:: anyhow!( "no parent dir for {cargo}" ) ) ;
184
+ warn ! ( "no parent dir for {cargo}" ) ;
185
+ return None ;
175
186
} ;
176
- let discovered = ProjectManifest :: discover ( parent_dir) ?;
187
+ let discovered = ProjectManifest :: discover ( parent_dir)
188
+ . map_err ( |e| {
189
+ error ! (
190
+ "encountered error while searching for manifests under {}: {e}" ,
191
+ parent_dir. as_str( )
192
+ ) ;
193
+ e
194
+ } )
195
+ . ok ( ) ?;
177
196
discovered
178
197
. iter ( )
179
- . filter_map ( |it| match it {
198
+ . find_map ( |it| match it {
180
199
ProjectManifest :: CargoToml ( other)
181
200
if cargo. starts_with ( other. parent ( ) )
182
201
&& reader. read ( other) . is_ok_and ( |it| {
183
- it. get ( "workspace" )
184
- . and_then ( |w| w. as_table ( ) )
185
- . and_then ( |t| t. get ( "members" ) )
186
- . and_then ( |ms| ms. as_array ( ) )
187
- . is_some_and ( |ms| {
188
- ms. iter ( ) . any ( |m| {
189
- m. as_str ( )
190
- . is_some_and ( |s| other. parent ( ) . join ( s) == cargo. parent ( ) )
191
- } )
192
- } )
202
+ it. workspace . as_ref ( ) . is_some_and ( |w| {
203
+ w. members
204
+ . iter ( )
205
+ . any ( |m| other. parent ( ) . join ( m) == cargo. parent ( ) )
206
+ } )
193
207
} ) =>
194
208
{
195
209
debug ! ( "found workspace {other} containing {cargo}" ) ;
196
210
Some ( it. clone ( ) )
197
211
}
198
212
_ => None ,
199
213
} )
200
- . next ( )
201
- . ok_or ( anyhow:: anyhow!( "no workspace found for {manifest}" ) )
214
+ . or_else ( || {
215
+ debug ! ( "no workspace found for {cargo}" ) ;
216
+ None
217
+ } )
202
218
}
203
219
204
220
pub fn find_project_manifests (
0 commit comments