aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/handlers/auto_import.rs25
-rw-r--r--crates/ra_hir/src/code_model.rs2
-rw-r--r--crates/ra_hir_def/src/import_map.rs60
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
939fn 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)]
178pub struct Query { 178pub 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
184impl Query { 186impl 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#"