diff options
author | Kirill Bulatov <[email protected]> | 2020-12-28 12:24:13 +0000 |
---|---|---|
committer | Kirill Bulatov <[email protected]> | 2020-12-28 13:06:10 +0000 |
commit | c4995cfbd5b265c02d3038d72b8a022cde5f7040 (patch) | |
tree | d2fdb44eedf6c5e806804a1b874643b52586bb44 /crates/hir_def/src | |
parent | 0e48cd0c3c712cea0267476de974012b2b05b508 (diff) |
Better query api and fuzzy search
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r-- | crates/hir_def/src/import_map.rs | 73 |
1 files changed, 40 insertions, 33 deletions
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs index 64d0ec471..ce25e1c6e 100644 --- a/crates/hir_def/src/import_map.rs +++ b/crates/hir_def/src/import_map.rs | |||
@@ -156,7 +156,8 @@ 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_string(&importables[start].1.path); | 159 | let key = fst_path(&importables[start].1.path); |
160 | |||
160 | builder.insert(key, start as u64).unwrap(); | 161 | builder.insert(key, start as u64).unwrap(); |
161 | } | 162 | } |
162 | 163 | ||
@@ -212,15 +213,15 @@ impl fmt::Debug for ImportMap { | |||
212 | } | 213 | } |
213 | } | 214 | } |
214 | 215 | ||
215 | fn fst_string<T: ToString>(t: &T) -> String { | 216 | fn fst_path(path: &ImportPath) -> String { |
216 | let mut s = t.to_string(); | 217 | let mut s = path.to_string(); |
217 | s.make_ascii_lowercase(); | 218 | s.make_ascii_lowercase(); |
218 | s | 219 | s |
219 | } | 220 | } |
220 | 221 | ||
221 | fn cmp((_, lhs): &(&ItemInNs, &ImportInfo), (_, rhs): &(&ItemInNs, &ImportInfo)) -> Ordering { | 222 | fn cmp((_, lhs): &(&ItemInNs, &ImportInfo), (_, rhs): &(&ItemInNs, &ImportInfo)) -> Ordering { |
222 | let lhs_str = fst_string(&lhs.path); | 223 | let lhs_str = fst_path(&lhs.path); |
223 | let rhs_str = fst_string(&rhs.path); | 224 | let rhs_str = fst_path(&rhs.path); |
224 | lhs_str.cmp(&rhs_str) | 225 | lhs_str.cmp(&rhs_str) |
225 | } | 226 | } |
226 | 227 | ||
@@ -237,14 +238,20 @@ pub enum ImportKind { | |||
237 | BuiltinType, | 238 | BuiltinType, |
238 | } | 239 | } |
239 | 240 | ||
241 | /// todo kb | ||
242 | #[derive(Debug)] | ||
243 | pub enum SearchMode { | ||
244 | Equals, | ||
245 | Contains, | ||
246 | Fuzzy, | ||
247 | } | ||
248 | |||
240 | #[derive(Debug)] | 249 | #[derive(Debug)] |
241 | pub struct Query { | 250 | pub struct Query { |
242 | query: String, | 251 | query: String, |
243 | lowercased: String, | 252 | lowercased: String, |
244 | // TODO kb use enums instead? | ||
245 | name_only: bool, | 253 | name_only: bool, |
246 | name_end: bool, | 254 | search_mode: SearchMode, |
247 | strict_include: bool, | ||
248 | case_sensitive: bool, | 255 | case_sensitive: bool, |
249 | limit: usize, | 256 | limit: usize, |
250 | exclude_import_kinds: FxHashSet<ImportKind>, | 257 | exclude_import_kinds: FxHashSet<ImportKind>, |
@@ -253,29 +260,23 @@ pub struct Query { | |||
253 | impl Query { | 260 | impl Query { |
254 | pub fn new(query: &str) -> Self { | 261 | pub fn new(query: &str) -> Self { |
255 | Self { | 262 | Self { |
256 | lowercased: query.to_lowercase(), | ||
257 | query: query.to_string(), | 263 | query: query.to_string(), |
264 | lowercased: query.to_lowercase(), | ||
258 | name_only: false, | 265 | name_only: false, |
259 | name_end: false, | 266 | search_mode: SearchMode::Contains, |
260 | strict_include: false, | ||
261 | case_sensitive: false, | 267 | case_sensitive: false, |
262 | limit: usize::max_value(), | 268 | limit: usize::max_value(), |
263 | exclude_import_kinds: FxHashSet::default(), | 269 | exclude_import_kinds: FxHashSet::default(), |
264 | } | 270 | } |
265 | } | 271 | } |
266 | 272 | ||
267 | pub fn name_end(self) -> Self { | ||
268 | Self { name_end: true, ..self } | ||
269 | } | ||
270 | |||
271 | /// todo kb | ||
272 | pub fn name_only(self) -> Self { | 273 | pub fn name_only(self) -> Self { |
273 | Self { name_only: true, ..self } | 274 | Self { name_only: true, ..self } |
274 | } | 275 | } |
275 | 276 | ||
276 | /// todo kb | 277 | /// todo kb |
277 | pub fn strict_include(self) -> Self { | 278 | pub fn search_mode(self, search_mode: SearchMode) -> Self { |
278 | Self { strict_include: true, ..self } | 279 | Self { search_mode, ..self } |
279 | } | 280 | } |
280 | 281 | ||
281 | /// Limits the returned number of items to `limit`. | 282 | /// Limits the returned number of items to `limit`. |
@@ -309,18 +310,24 @@ fn contains_query(query: &Query, input_path: &ImportPath, enforce_lowercase: boo | |||
309 | let query_string = | 310 | let query_string = |
310 | if !enforce_lowercase && query.case_sensitive { &query.query } else { &query.lowercased }; | 311 | if !enforce_lowercase && query.case_sensitive { &query.query } else { &query.lowercased }; |
311 | 312 | ||
312 | if query.strict_include { | 313 | match query.search_mode { |
313 | if query.name_end { | 314 | SearchMode::Equals => &input == query_string, |
314 | &input == query_string | 315 | SearchMode::Contains => input.contains(query_string), |
315 | } else { | 316 | SearchMode::Fuzzy => { |
316 | input.contains(query_string) | 317 | let mut unchecked_query_chars = query_string.chars(); |
318 | let mut mismatching_query_char = unchecked_query_chars.next(); | ||
319 | |||
320 | for input_char in input.chars() { | ||
321 | match mismatching_query_char { | ||
322 | None => return true, | ||
323 | Some(matching_query_char) if matching_query_char == input_char => { | ||
324 | mismatching_query_char = unchecked_query_chars.next(); | ||
325 | } | ||
326 | _ => (), | ||
327 | } | ||
328 | } | ||
329 | mismatching_query_char.is_none() | ||
317 | } | 330 | } |
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 | } | 331 | } |
325 | } | 332 | } |
326 | 333 | ||
@@ -358,14 +365,14 @@ pub fn search_dependencies<'a>( | |||
358 | continue; | 365 | continue; |
359 | } | 366 | } |
360 | 367 | ||
361 | let common_importables_path_fst = fst_string(common_importables_path); | 368 | let common_importables_path_fst = fst_path(common_importables_path); |
362 | // Add the items from this `ModPath` group. Those are all subsequent items in | 369 | // Add the items from this `ModPath` group. Those are all subsequent items in |
363 | // `importables` whose paths match `path`. | 370 | // `importables` whose paths match `path`. |
364 | let iter = importables | 371 | let iter = importables |
365 | .iter() | 372 | .iter() |
366 | .copied() | 373 | .copied() |
367 | .take_while(|item| { | 374 | .take_while(|item| { |
368 | common_importables_path_fst == fst_string(&import_map.map[item].path) | 375 | common_importables_path_fst == fst_path(&import_map.map[item].path) |
369 | }) | 376 | }) |
370 | .filter(|&item| match item_import_kind(item) { | 377 | .filter(|&item| match item_import_kind(item) { |
371 | Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind), | 378 | Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind), |
@@ -741,7 +748,7 @@ mod tests { | |||
741 | check_search( | 748 | check_search( |
742 | ra_fixture, | 749 | ra_fixture, |
743 | "main", | 750 | "main", |
744 | Query::new("fmt"), | 751 | Query::new("fmt").search_mode(SearchMode::Fuzzy), |
745 | expect![[r#" | 752 | expect![[r#" |
746 | dep::fmt (t) | 753 | dep::fmt (t) |
747 | dep::Fmt (t) | 754 | dep::Fmt (t) |
@@ -756,7 +763,7 @@ mod tests { | |||
756 | check_search( | 763 | check_search( |
757 | ra_fixture, | 764 | ra_fixture, |
758 | "main", | 765 | "main", |
759 | Query::new("fmt").name_only().strict_include(), | 766 | Query::new("fmt").name_only().search_mode(SearchMode::Equals), |
760 | expect![[r#" | 767 | expect![[r#" |
761 | dep::fmt (t) | 768 | dep::fmt (t) |
762 | dep::Fmt (t) | 769 | dep::Fmt (t) |