diff options
author | Jonas Schievink <[email protected]> | 2020-06-10 15:04:55 +0100 |
---|---|---|
committer | Jonas Schievink <[email protected]> | 2020-06-10 15:04:55 +0100 |
commit | 7e83ed99a887f959bd4cf97357faf373a09f9269 (patch) | |
tree | 31e55b5e2c28b71b5ebc9549da45e84e1c0ec701 | |
parent | ed2817e599a9c0e812af26587badad6da7a4d949 (diff) |
Respect casing when searching for imports
-rw-r--r-- | crates/ra_assists/src/handlers/auto_import.rs | 25 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_def/src/import_map.rs | 60 |
3 files changed, 81 insertions, 6 deletions
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index 86a173ff5..5092bf336 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -917,4 +917,29 @@ fn main() { | |||
917 | ", | 917 | ", |
918 | ); | 918 | ); |
919 | } | 919 | } |
920 | |||
921 | #[test] | ||
922 | fn casing() { | ||
923 | // Tests that differently cased names don't interfere and we only suggest the matching one. | ||
924 | check_assist( | ||
925 | auto_import, | ||
926 | r" | ||
927 | //- /lib.rs crate:dep | ||
928 | |||
929 | pub struct FMT; | ||
930 | pub struct fmt; | ||
931 | |||
932 | //- /main.rs crate:main deps:dep | ||
933 | |||
934 | fn main() { | ||
935 | FMT<|>; | ||
936 | }", | ||
937 | r"use dep::FMT; | ||
938 | |||
939 | fn main() { | ||
940 | FMT; | ||
941 | } | ||
942 | ", | ||
943 | ); | ||
944 | } | ||
920 | } | 945 | } |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index a55fe03a6..1a9f6cc76 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -107,7 +107,7 @@ impl Crate { | |||
107 | import_map::search_dependencies( | 107 | import_map::search_dependencies( |
108 | db, | 108 | db, |
109 | self.into(), | 109 | self.into(), |
110 | import_map::Query::new(query).anchor_end().limit(40), | 110 | import_map::Query::new(query).anchor_end().case_sensitive().limit(40), |
111 | ) | 111 | ) |
112 | .into_iter() | 112 | .into_iter() |
113 | .map(|item| match item { | 113 | .map(|item| match item { |
diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs index 70368d8df..a55d7d83b 100644 --- a/crates/ra_hir_def/src/import_map.rs +++ b/crates/ra_hir_def/src/import_map.rs | |||
@@ -177,13 +177,21 @@ fn cmp((_, lhs): &(&ItemInNs, &ModPath), (_, rhs): &(&ItemInNs, &ModPath)) -> Or | |||
177 | #[derive(Debug)] | 177 | #[derive(Debug)] |
178 | pub struct Query { | 178 | pub struct Query { |
179 | query: String, | 179 | query: String, |
180 | lowercased: String, | ||
180 | anchor_end: bool, | 181 | anchor_end: bool, |
182 | case_sensitive: bool, | ||
181 | limit: usize, | 183 | limit: usize, |
182 | } | 184 | } |
183 | 185 | ||
184 | impl Query { | 186 | impl Query { |
185 | pub fn new(query: &str) -> Self { | 187 | pub fn new(query: &str) -> Self { |
186 | Self { query: query.to_lowercase(), anchor_end: false, limit: usize::max_value() } | 188 | Self { |
189 | lowercased: query.to_lowercase(), | ||
190 | query: query.to_string(), | ||
191 | anchor_end: false, | ||
192 | case_sensitive: false, | ||
193 | limit: usize::max_value(), | ||
194 | } | ||
187 | } | 195 | } |
188 | 196 | ||
189 | /// Only returns items whose paths end with the (case-insensitive) query string as their last | 197 | /// Only returns items whose paths end with the (case-insensitive) query string as their last |
@@ -196,6 +204,11 @@ impl Query { | |||
196 | pub fn limit(self, limit: usize) -> Self { | 204 | pub fn limit(self, limit: usize) -> Self { |
197 | Self { limit, ..self } | 205 | Self { limit, ..self } |
198 | } | 206 | } |
207 | |||
208 | /// Respect casing of the query string when matching. | ||
209 | pub fn case_sensitive(self) -> Self { | ||
210 | Self { case_sensitive: true, ..self } | ||
211 | } | ||
199 | } | 212 | } |
200 | 213 | ||
201 | /// Searches dependencies of `krate` for an importable path matching `query`. | 214 | /// Searches dependencies of `krate` for an importable path matching `query`. |
@@ -212,7 +225,7 @@ pub fn search_dependencies<'a>( | |||
212 | let import_maps: Vec<_> = | 225 | let import_maps: Vec<_> = |
213 | graph[krate].dependencies.iter().map(|dep| db.import_map(dep.crate_id)).collect(); | 226 | graph[krate].dependencies.iter().map(|dep| db.import_map(dep.crate_id)).collect(); |
214 | 227 | ||
215 | let automaton = fst::automaton::Subsequence::new(&query.query); | 228 | let automaton = fst::automaton::Subsequence::new(&query.lowercased); |
216 | 229 | ||
217 | let mut op = fst::map::OpBuilder::new(); | 230 | let mut op = fst::map::OpBuilder::new(); |
218 | for map in &import_maps { | 231 | for map in &import_maps { |
@@ -232,17 +245,27 @@ pub fn search_dependencies<'a>( | |||
232 | if query.anchor_end { | 245 | if query.anchor_end { |
233 | // Last segment must match query. | 246 | // Last segment must match query. |
234 | let last = path.segments.last().unwrap().to_string(); | 247 | let last = path.segments.last().unwrap().to_string(); |
235 | if last.to_lowercase() != query.query { | 248 | if last.to_lowercase() != query.lowercased { |
236 | continue; | 249 | continue; |
237 | } | 250 | } |
238 | } | 251 | } |
239 | 252 | ||
240 | // Add the items from this `ModPath` group. Those are all subsequent items in | 253 | // Add the items from this `ModPath` group. Those are all subsequent items in |
241 | // `importables` whose paths match `path`. | 254 | // `importables` whose paths match `path`. |
242 | res.extend(importables.iter().copied().take_while(|item| { | 255 | let iter = importables.iter().copied().take_while(|item| { |
243 | let item_path = &import_map.map[item]; | 256 | let item_path = &import_map.map[item]; |
244 | fst_path(item_path) == fst_path(path) | 257 | fst_path(item_path) == fst_path(path) |
245 | })); | 258 | }); |
259 | |||
260 | if query.case_sensitive { | ||
261 | // FIXME: This does not do a subsequence match. | ||
262 | res.extend(iter.filter(|item| { | ||
263 | let item_path = &import_map.map[item]; | ||
264 | item_path.to_string().contains(&query.query) | ||
265 | })); | ||
266 | } else { | ||
267 | res.extend(iter); | ||
268 | } | ||
246 | 269 | ||
247 | if res.len() >= query.limit { | 270 | if res.len() >= query.limit { |
248 | res.truncate(query.limit); | 271 | res.truncate(query.limit); |
@@ -583,6 +606,33 @@ mod tests { | |||
583 | } | 606 | } |
584 | 607 | ||
585 | #[test] | 608 | #[test] |
609 | fn search_casing() { | ||
610 | let ra_fixture = r#" | ||
611 | //- /main.rs crate:main deps:dep | ||
612 | //- /dep.rs crate:dep | ||
613 | |||
614 | pub struct fmt; | ||
615 | pub struct FMT; | ||
616 | "#; | ||
617 | |||
618 | let res = search_dependencies_of(ra_fixture, "main", Query::new("FMT")); | ||
619 | |||
620 | assert_snapshot!(res, @r###" | ||
621 | dep::FMT (v) | ||
622 | dep::FMT (t) | ||
623 | dep::fmt (t) | ||
624 | dep::fmt (v) | ||
625 | "###); | ||
626 | |||
627 | let res = search_dependencies_of(ra_fixture, "main", Query::new("FMT").case_sensitive()); | ||
628 | |||
629 | assert_snapshot!(res, @r###" | ||
630 | dep::FMT (v) | ||
631 | dep::FMT (t) | ||
632 | "###); | ||
633 | } | ||
634 | |||
635 | #[test] | ||
586 | fn search_limit() { | 636 | fn search_limit() { |
587 | let res = search_dependencies_of( | 637 | let res = search_dependencies_of( |
588 | r#" | 638 | r#" |