diff options
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r-- | crates/hir_def/src/import_map.rs | 96 |
1 files changed, 62 insertions, 34 deletions
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs index c0f108848..64d0ec471 100644 --- a/crates/hir_def/src/import_map.rs +++ b/crates/hir_def/src/import_map.rs | |||
@@ -156,8 +156,7 @@ impl ImportMap { | |||
156 | let start = last_batch_start; | 156 | let start = last_batch_start; |
157 | last_batch_start = idx + 1; | 157 | last_batch_start = idx + 1; |
158 | 158 | ||
159 | let key = fst_path(&importables[start].1.path); | 159 | let key = fst_string(&importables[start].1.path); |
160 | |||
161 | builder.insert(key, start as u64).unwrap(); | 160 | builder.insert(key, start as u64).unwrap(); |
162 | } | 161 | } |
163 | 162 | ||
@@ -213,15 +212,15 @@ impl fmt::Debug for ImportMap { | |||
213 | } | 212 | } |
214 | } | 213 | } |
215 | 214 | ||
216 | fn fst_path(path: &ImportPath) -> String { | 215 | fn fst_string<T: ToString>(t: &T) -> String { |
217 | let mut s = path.to_string(); | 216 | let mut s = t.to_string(); |
218 | s.make_ascii_lowercase(); | 217 | s.make_ascii_lowercase(); |
219 | s | 218 | s |
220 | } | 219 | } |
221 | 220 | ||
222 | fn cmp((_, lhs): &(&ItemInNs, &ImportInfo), (_, rhs): &(&ItemInNs, &ImportInfo)) -> Ordering { | 221 | fn cmp((_, lhs): &(&ItemInNs, &ImportInfo), (_, rhs): &(&ItemInNs, &ImportInfo)) -> Ordering { |
223 | let lhs_str = fst_path(&lhs.path); | 222 | let lhs_str = fst_string(&lhs.path); |
224 | let rhs_str = fst_path(&rhs.path); | 223 | let rhs_str = fst_string(&rhs.path); |
225 | lhs_str.cmp(&rhs_str) | 224 | lhs_str.cmp(&rhs_str) |
226 | } | 225 | } |
227 | 226 | ||
@@ -242,7 +241,10 @@ pub enum ImportKind { | |||
242 | pub struct Query { | 241 | pub struct Query { |
243 | query: String, | 242 | query: String, |
244 | lowercased: String, | 243 | lowercased: String, |
245 | anchor_end: bool, | 244 | // TODO kb use enums instead? |
245 | name_only: bool, | ||
246 | name_end: bool, | ||
247 | strict_include: bool, | ||
246 | case_sensitive: bool, | 248 | case_sensitive: bool, |
247 | limit: usize, | 249 | limit: usize, |
248 | exclude_import_kinds: FxHashSet<ImportKind>, | 250 | exclude_import_kinds: FxHashSet<ImportKind>, |
@@ -253,17 +255,27 @@ impl Query { | |||
253 | Self { | 255 | Self { |
254 | lowercased: query.to_lowercase(), | 256 | lowercased: query.to_lowercase(), |
255 | query: query.to_string(), | 257 | query: query.to_string(), |
256 | anchor_end: false, | 258 | name_only: false, |
259 | name_end: false, | ||
260 | strict_include: false, | ||
257 | case_sensitive: false, | 261 | case_sensitive: false, |
258 | limit: usize::max_value(), | 262 | limit: usize::max_value(), |
259 | exclude_import_kinds: FxHashSet::default(), | 263 | exclude_import_kinds: FxHashSet::default(), |
260 | } | 264 | } |
261 | } | 265 | } |
262 | 266 | ||
263 | /// Only returns items whose paths end with the (case-insensitive) query string as their last | 267 | pub fn name_end(self) -> Self { |
264 | /// segment. | 268 | Self { name_end: true, ..self } |
265 | pub fn anchor_end(self) -> Self { | 269 | } |
266 | Self { anchor_end: true, ..self } | 270 | |
271 | /// todo kb | ||
272 | pub fn name_only(self) -> Self { | ||
273 | Self { name_only: true, ..self } | ||
274 | } | ||
275 | |||
276 | /// todo kb | ||
277 | pub fn strict_include(self) -> Self { | ||
278 | Self { strict_include: true, ..self } | ||
267 | } | 279 | } |
268 | 280 | ||
269 | /// Limits the returned number of items to `limit`. | 281 | /// Limits the returned number of items to `limit`. |
@@ -283,6 +295,35 @@ impl Query { | |||
283 | } | 295 | } |
284 | } | 296 | } |
285 | 297 | ||
298 | // TODO kb: ugly with a special `return true` case and the `enforce_lowercase` one. | ||
299 | fn contains_query(query: &Query, input_path: &ImportPath, enforce_lowercase: bool) -> bool { | ||
300 | let mut input = if query.name_only { | ||
301 | input_path.segments.last().unwrap().to_string() | ||
302 | } else { | ||
303 | input_path.to_string() | ||
304 | }; | ||
305 | if enforce_lowercase || !query.case_sensitive { | ||
306 | input.make_ascii_lowercase(); | ||
307 | } | ||
308 | |||
309 | let query_string = | ||
310 | if !enforce_lowercase && query.case_sensitive { &query.query } else { &query.lowercased }; | ||
311 | |||
312 | if query.strict_include { | ||
313 | if query.name_end { | ||
314 | &input == query_string | ||
315 | } else { | ||
316 | input.contains(query_string) | ||
317 | } | ||
318 | } else if query.name_end { | ||
319 | input.ends_with(query_string) | ||
320 | } else { | ||
321 | let input_chars = input.chars().collect::<FxHashSet<_>>(); | ||
322 | // TODO kb actually check for the order and the quantity | ||
323 | query_string.chars().all(|query_char| input_chars.contains(&query_char)) | ||
324 | } | ||
325 | } | ||
326 | |||
286 | /// Searches dependencies of `krate` for an importable path matching `query`. | 327 | /// Searches dependencies of `krate` for an importable path matching `query`. |
287 | /// | 328 | /// |
288 | /// This returns a list of items that could be imported from dependencies of `krate`. | 329 | /// This returns a list of items that could be imported from dependencies of `krate`. |
@@ -312,39 +353,26 @@ pub fn search_dependencies<'a>( | |||
312 | let importables = &import_map.importables[indexed_value.value as usize..]; | 353 | let importables = &import_map.importables[indexed_value.value as usize..]; |
313 | 354 | ||
314 | // Path shared by the importable items in this group. | 355 | // Path shared by the importable items in this group. |
315 | let path = &import_map.map[&importables[0]].path; | 356 | let common_importables_path = &import_map.map[&importables[0]].path; |
316 | 357 | if !contains_query(&query, common_importables_path, true) { | |
317 | if query.anchor_end { | 358 | continue; |
318 | // Last segment must match query. | ||
319 | let last = path.segments.last().unwrap().to_string(); | ||
320 | if last.to_lowercase() != query.lowercased { | ||
321 | continue; | ||
322 | } | ||
323 | } | 359 | } |
324 | 360 | ||
361 | let common_importables_path_fst = fst_string(common_importables_path); | ||
325 | // Add the items from this `ModPath` group. Those are all subsequent items in | 362 | // Add the items from this `ModPath` group. Those are all subsequent items in |
326 | // `importables` whose paths match `path`. | 363 | // `importables` whose paths match `path`. |
327 | let iter = importables | 364 | let iter = importables |
328 | .iter() | 365 | .iter() |
329 | .copied() | 366 | .copied() |
330 | .take_while(|item| { | 367 | .take_while(|item| { |
331 | let item_path = &import_map.map[item].path; | 368 | common_importables_path_fst == fst_string(&import_map.map[item].path) |
332 | fst_path(item_path) == fst_path(path) | ||
333 | }) | 369 | }) |
334 | .filter(|&item| match item_import_kind(item) { | 370 | .filter(|&item| match item_import_kind(item) { |
335 | Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind), | 371 | Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind), |
336 | None => true, | 372 | None => true, |
337 | }); | 373 | }) |
338 | 374 | .filter(|item| contains_query(&query, &import_map.map[item].path, false)); | |
339 | if query.case_sensitive { | 375 | res.extend(iter); |
340 | // FIXME: This does not do a subsequence match. | ||
341 | res.extend(iter.filter(|item| { | ||
342 | let item_path = &import_map.map[item].path; | ||
343 | item_path.to_string().contains(&query.query) | ||
344 | })); | ||
345 | } else { | ||
346 | res.extend(iter); | ||
347 | } | ||
348 | 376 | ||
349 | if res.len() >= query.limit { | 377 | if res.len() >= query.limit { |
350 | res.truncate(query.limit); | 378 | res.truncate(query.limit); |
@@ -728,7 +756,7 @@ mod tests { | |||
728 | check_search( | 756 | check_search( |
729 | ra_fixture, | 757 | ra_fixture, |
730 | "main", | 758 | "main", |
731 | Query::new("fmt").anchor_end(), | 759 | Query::new("fmt").name_only().strict_include(), |
732 | expect![[r#" | 760 | expect![[r#" |
733 | dep::fmt (t) | 761 | dep::fmt (t) |
734 | dep::Fmt (t) | 762 | dep::Fmt (t) |