diff options
author | Kirill Bulatov <[email protected]> | 2020-12-28 09:41:08 +0000 |
---|---|---|
committer | Kirill Bulatov <[email protected]> | 2020-12-28 13:06:10 +0000 |
commit | 0e48cd0c3c712cea0267476de974012b2b05b508 (patch) | |
tree | e8b0e719409110f077e72a34242e9853e5fc5031 /crates | |
parent | 77ad203a719be074e81485af7a4fb02fac6cbf61 (diff) |
Draft the module exclusion in modules
Diffstat (limited to 'crates')
-rw-r--r-- | crates/completion/src/completions/unqualified_path.rs | 2 | ||||
-rw-r--r-- | crates/hir_def/src/import_map.rs | 96 | ||||
-rw-r--r-- | crates/ide_db/src/imports_locator.rs | 10 |
3 files changed, 71 insertions, 37 deletions
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs index d09849752..3d72a08b4 100644 --- a/crates/completion/src/completions/unqualified_path.rs +++ b/crates/completion/src/completions/unqualified_path.rs | |||
@@ -135,7 +135,7 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<() | |||
135 | ctx.krate?, | 135 | ctx.krate?, |
136 | Some(100), | 136 | Some(100), |
137 | &potential_import_name, | 137 | &potential_import_name, |
138 | true, | 138 | false, |
139 | ) | 139 | ) |
140 | .filter_map(|import_candidate| { | 140 | .filter_map(|import_candidate| { |
141 | Some(match import_candidate { | 141 | Some(match import_candidate { |
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) |
diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/imports_locator.rs index b2980a5d6..0de949b9a 100644 --- a/crates/ide_db/src/imports_locator.rs +++ b/crates/ide_db/src/imports_locator.rs | |||
@@ -27,7 +27,12 @@ pub fn find_exact_imports<'a>( | |||
27 | local_query.limit(40); | 27 | local_query.limit(40); |
28 | local_query | 28 | local_query |
29 | }, | 29 | }, |
30 | import_map::Query::new(name_to_import).anchor_end().case_sensitive().limit(40), | 30 | import_map::Query::new(name_to_import) |
31 | .limit(40) | ||
32 | .name_only() | ||
33 | .name_end() | ||
34 | .strict_include() | ||
35 | .case_sensitive(), | ||
31 | ) | 36 | ) |
32 | } | 37 | } |
33 | 38 | ||
@@ -36,11 +41,12 @@ pub fn find_similar_imports<'a>( | |||
36 | krate: Crate, | 41 | krate: Crate, |
37 | limit: Option<usize>, | 42 | limit: Option<usize>, |
38 | name_to_import: &str, | 43 | name_to_import: &str, |
44 | // TODO kb change it to search across the whole path or not? | ||
39 | ignore_modules: bool, | 45 | ignore_modules: bool, |
40 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | 46 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { |
41 | let _p = profile::span("find_similar_imports"); | 47 | let _p = profile::span("find_similar_imports"); |
42 | 48 | ||
43 | let mut external_query = import_map::Query::new(name_to_import); | 49 | let mut external_query = import_map::Query::new(name_to_import).name_only(); |
44 | if ignore_modules { | 50 | if ignore_modules { |
45 | external_query = external_query.exclude_import_kind(import_map::ImportKind::Module); | 51 | external_query = external_query.exclude_import_kind(import_map::ImportKind::Module); |
46 | } | 52 | } |