From 0e48cd0c3c712cea0267476de974012b2b05b508 Mon Sep 17 00:00:00 2001
From: Kirill Bulatov <mail4score@gmail.com>
Date: Mon, 28 Dec 2020 11:41:08 +0200
Subject: Draft the module exclusion in modules

---
 .../completion/src/completions/unqualified_path.rs |  2 +-
 crates/hir_def/src/import_map.rs                   | 96 ++++++++++++++--------
 crates/ide_db/src/imports_locator.rs               | 10 ++-
 3 files changed, 71 insertions(+), 37 deletions(-)

(limited to 'crates')

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<()
         ctx.krate?,
         Some(100),
         &potential_import_name,
-        true,
+        false,
     )
     .filter_map(|import_candidate| {
         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 {
             let start = last_batch_start;
             last_batch_start = idx + 1;
 
-            let key = fst_path(&importables[start].1.path);
-
+            let key = fst_string(&importables[start].1.path);
             builder.insert(key, start as u64).unwrap();
         }
 
@@ -213,15 +212,15 @@ impl fmt::Debug for ImportMap {
     }
 }
 
-fn fst_path(path: &ImportPath) -> String {
-    let mut s = path.to_string();
+fn fst_string<T: ToString>(t: &T) -> String {
+    let mut s = t.to_string();
     s.make_ascii_lowercase();
     s
 }
 
 fn cmp((_, lhs): &(&ItemInNs, &ImportInfo), (_, rhs): &(&ItemInNs, &ImportInfo)) -> Ordering {
-    let lhs_str = fst_path(&lhs.path);
-    let rhs_str = fst_path(&rhs.path);
+    let lhs_str = fst_string(&lhs.path);
+    let rhs_str = fst_string(&rhs.path);
     lhs_str.cmp(&rhs_str)
 }
 
@@ -242,7 +241,10 @@ pub enum ImportKind {
 pub struct Query {
     query: String,
     lowercased: String,
-    anchor_end: bool,
+    // TODO kb use enums instead?
+    name_only: bool,
+    name_end: bool,
+    strict_include: bool,
     case_sensitive: bool,
     limit: usize,
     exclude_import_kinds: FxHashSet<ImportKind>,
@@ -253,17 +255,27 @@ impl Query {
         Self {
             lowercased: query.to_lowercase(),
             query: query.to_string(),
-            anchor_end: false,
+            name_only: false,
+            name_end: false,
+            strict_include: false,
             case_sensitive: false,
             limit: usize::max_value(),
             exclude_import_kinds: FxHashSet::default(),
         }
     }
 
-    /// Only returns items whose paths end with the (case-insensitive) query string as their last
-    /// segment.
-    pub fn anchor_end(self) -> Self {
-        Self { anchor_end: true, ..self }
+    pub fn name_end(self) -> Self {
+        Self { name_end: true, ..self }
+    }
+
+    /// todo kb
+    pub fn name_only(self) -> Self {
+        Self { name_only: true, ..self }
+    }
+
+    /// todo kb
+    pub fn strict_include(self) -> Self {
+        Self { strict_include: true, ..self }
     }
 
     /// Limits the returned number of items to `limit`.
@@ -283,6 +295,35 @@ impl Query {
     }
 }
 
+// TODO kb: ugly with a special `return true` case and the `enforce_lowercase` one.
+fn contains_query(query: &Query, input_path: &ImportPath, enforce_lowercase: bool) -> bool {
+    let mut input = if query.name_only {
+        input_path.segments.last().unwrap().to_string()
+    } else {
+        input_path.to_string()
+    };
+    if enforce_lowercase || !query.case_sensitive {
+        input.make_ascii_lowercase();
+    }
+
+    let query_string =
+        if !enforce_lowercase && query.case_sensitive { &query.query } else { &query.lowercased };
+
+    if query.strict_include {
+        if query.name_end {
+            &input == query_string
+        } else {
+            input.contains(query_string)
+        }
+    } else if query.name_end {
+        input.ends_with(query_string)
+    } else {
+        let input_chars = input.chars().collect::<FxHashSet<_>>();
+        // TODO kb actually check for the order and the quantity
+        query_string.chars().all(|query_char| input_chars.contains(&query_char))
+    }
+}
+
 /// Searches dependencies of `krate` for an importable path matching `query`.
 ///
 /// This returns a list of items that could be imported from dependencies of `krate`.
@@ -312,39 +353,26 @@ pub fn search_dependencies<'a>(
             let importables = &import_map.importables[indexed_value.value as usize..];
 
             // Path shared by the importable items in this group.
-            let path = &import_map.map[&importables[0]].path;
-
-            if query.anchor_end {
-                // Last segment must match query.
-                let last = path.segments.last().unwrap().to_string();
-                if last.to_lowercase() != query.lowercased {
-                    continue;
-                }
+            let common_importables_path = &import_map.map[&importables[0]].path;
+            if !contains_query(&query, common_importables_path, true) {
+                continue;
             }
 
+            let common_importables_path_fst = fst_string(common_importables_path);
             // Add the items from this `ModPath` group. Those are all subsequent items in
             // `importables` whose paths match `path`.
             let iter = importables
                 .iter()
                 .copied()
                 .take_while(|item| {
-                    let item_path = &import_map.map[item].path;
-                    fst_path(item_path) == fst_path(path)
+                    common_importables_path_fst == fst_string(&import_map.map[item].path)
                 })
                 .filter(|&item| match item_import_kind(item) {
                     Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind),
                     None => true,
-                });
-
-            if query.case_sensitive {
-                // FIXME: This does not do a subsequence match.
-                res.extend(iter.filter(|item| {
-                    let item_path = &import_map.map[item].path;
-                    item_path.to_string().contains(&query.query)
-                }));
-            } else {
-                res.extend(iter);
-            }
+                })
+                .filter(|item| contains_query(&query, &import_map.map[item].path, false));
+            res.extend(iter);
 
             if res.len() >= query.limit {
                 res.truncate(query.limit);
@@ -728,7 +756,7 @@ mod tests {
         check_search(
             ra_fixture,
             "main",
-            Query::new("fmt").anchor_end(),
+            Query::new("fmt").name_only().strict_include(),
             expect![[r#"
                 dep::fmt (t)
                 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>(
             local_query.limit(40);
             local_query
         },
-        import_map::Query::new(name_to_import).anchor_end().case_sensitive().limit(40),
+        import_map::Query::new(name_to_import)
+            .limit(40)
+            .name_only()
+            .name_end()
+            .strict_include()
+            .case_sensitive(),
     )
 }
 
@@ -36,11 +41,12 @@ pub fn find_similar_imports<'a>(
     krate: Crate,
     limit: Option<usize>,
     name_to_import: &str,
+    // TODO kb change it to search across the whole path or not?
     ignore_modules: bool,
 ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> {
     let _p = profile::span("find_similar_imports");
 
-    let mut external_query = import_map::Query::new(name_to_import);
+    let mut external_query = import_map::Query::new(name_to_import).name_only();
     if ignore_modules {
         external_query = external_query.exclude_import_kind(import_map::ImportKind::Module);
     }
-- 
cgit v1.2.3


From c4995cfbd5b265c02d3038d72b8a022cde5f7040 Mon Sep 17 00:00:00 2001
From: Kirill Bulatov <mail4score@gmail.com>
Date: Mon, 28 Dec 2020 14:24:13 +0200
Subject: Better query api and fuzzy search

---
 .../completion/src/completions/unqualified_path.rs |  2 +-
 crates/hir_def/src/import_map.rs                   | 73 ++++++++++++----------
 crates/ide_db/src/imports_locator.rs               | 13 ++--
 3 files changed, 47 insertions(+), 41 deletions(-)

(limited to 'crates')

diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs
index 3d72a08b4..d09849752 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<()
         ctx.krate?,
         Some(100),
         &potential_import_name,
-        false,
+        true,
     )
     .filter_map(|import_candidate| {
         Some(match import_candidate {
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 {
             let start = last_batch_start;
             last_batch_start = idx + 1;
 
-            let key = fst_string(&importables[start].1.path);
+            let key = fst_path(&importables[start].1.path);
+
             builder.insert(key, start as u64).unwrap();
         }
 
@@ -212,15 +213,15 @@ impl fmt::Debug for ImportMap {
     }
 }
 
-fn fst_string<T: ToString>(t: &T) -> String {
-    let mut s = t.to_string();
+fn fst_path(path: &ImportPath) -> String {
+    let mut s = path.to_string();
     s.make_ascii_lowercase();
     s
 }
 
 fn cmp((_, lhs): &(&ItemInNs, &ImportInfo), (_, rhs): &(&ItemInNs, &ImportInfo)) -> Ordering {
-    let lhs_str = fst_string(&lhs.path);
-    let rhs_str = fst_string(&rhs.path);
+    let lhs_str = fst_path(&lhs.path);
+    let rhs_str = fst_path(&rhs.path);
     lhs_str.cmp(&rhs_str)
 }
 
@@ -237,14 +238,20 @@ pub enum ImportKind {
     BuiltinType,
 }
 
+/// todo kb
+#[derive(Debug)]
+pub enum SearchMode {
+    Equals,
+    Contains,
+    Fuzzy,
+}
+
 #[derive(Debug)]
 pub struct Query {
     query: String,
     lowercased: String,
-    // TODO kb use enums instead?
     name_only: bool,
-    name_end: bool,
-    strict_include: bool,
+    search_mode: SearchMode,
     case_sensitive: bool,
     limit: usize,
     exclude_import_kinds: FxHashSet<ImportKind>,
@@ -253,29 +260,23 @@ pub struct Query {
 impl Query {
     pub fn new(query: &str) -> Self {
         Self {
-            lowercased: query.to_lowercase(),
             query: query.to_string(),
+            lowercased: query.to_lowercase(),
             name_only: false,
-            name_end: false,
-            strict_include: false,
+            search_mode: SearchMode::Contains,
             case_sensitive: false,
             limit: usize::max_value(),
             exclude_import_kinds: FxHashSet::default(),
         }
     }
 
-    pub fn name_end(self) -> Self {
-        Self { name_end: true, ..self }
-    }
-
-    /// todo kb
     pub fn name_only(self) -> Self {
         Self { name_only: true, ..self }
     }
 
     /// todo kb
-    pub fn strict_include(self) -> Self {
-        Self { strict_include: true, ..self }
+    pub fn search_mode(self, search_mode: SearchMode) -> Self {
+        Self { search_mode, ..self }
     }
 
     /// Limits the returned number of items to `limit`.
@@ -309,18 +310,24 @@ fn contains_query(query: &Query, input_path: &ImportPath, enforce_lowercase: boo
     let query_string =
         if !enforce_lowercase && query.case_sensitive { &query.query } else { &query.lowercased };
 
-    if query.strict_include {
-        if query.name_end {
-            &input == query_string
-        } else {
-            input.contains(query_string)
+    match query.search_mode {
+        SearchMode::Equals => &input == query_string,
+        SearchMode::Contains => input.contains(query_string),
+        SearchMode::Fuzzy => {
+            let mut unchecked_query_chars = query_string.chars();
+            let mut mismatching_query_char = unchecked_query_chars.next();
+
+            for input_char in input.chars() {
+                match mismatching_query_char {
+                    None => return true,
+                    Some(matching_query_char) if matching_query_char == input_char => {
+                        mismatching_query_char = unchecked_query_chars.next();
+                    }
+                    _ => (),
+                }
+            }
+            mismatching_query_char.is_none()
         }
-    } else if query.name_end {
-        input.ends_with(query_string)
-    } else {
-        let input_chars = input.chars().collect::<FxHashSet<_>>();
-        // TODO kb actually check for the order and the quantity
-        query_string.chars().all(|query_char| input_chars.contains(&query_char))
     }
 }
 
@@ -358,14 +365,14 @@ pub fn search_dependencies<'a>(
                 continue;
             }
 
-            let common_importables_path_fst = fst_string(common_importables_path);
+            let common_importables_path_fst = fst_path(common_importables_path);
             // Add the items from this `ModPath` group. Those are all subsequent items in
             // `importables` whose paths match `path`.
             let iter = importables
                 .iter()
                 .copied()
                 .take_while(|item| {
-                    common_importables_path_fst == fst_string(&import_map.map[item].path)
+                    common_importables_path_fst == fst_path(&import_map.map[item].path)
                 })
                 .filter(|&item| match item_import_kind(item) {
                     Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind),
@@ -741,7 +748,7 @@ mod tests {
         check_search(
             ra_fixture,
             "main",
-            Query::new("fmt"),
+            Query::new("fmt").search_mode(SearchMode::Fuzzy),
             expect![[r#"
                 dep::fmt (t)
                 dep::Fmt (t)
@@ -756,7 +763,7 @@ mod tests {
         check_search(
             ra_fixture,
             "main",
-            Query::new("fmt").name_only().strict_include(),
+            Query::new("fmt").name_only().search_mode(SearchMode::Equals),
             expect![[r#"
                 dep::fmt (t)
                 dep::Fmt (t)
diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/imports_locator.rs
index 0de949b9a..986cb5b83 100644
--- a/crates/ide_db/src/imports_locator.rs
+++ b/crates/ide_db/src/imports_locator.rs
@@ -30,8 +30,7 @@ pub fn find_exact_imports<'a>(
         import_map::Query::new(name_to_import)
             .limit(40)
             .name_only()
-            .name_end()
-            .strict_include()
+            .search_mode(import_map::SearchMode::Equals)
             .case_sensitive(),
     )
 }
@@ -41,14 +40,14 @@ pub fn find_similar_imports<'a>(
     krate: Crate,
     limit: Option<usize>,
     name_to_import: &str,
-    // TODO kb change it to search across the whole path or not?
-    ignore_modules: bool,
+    name_only: bool,
 ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> {
     let _p = profile::span("find_similar_imports");
 
-    let mut external_query = import_map::Query::new(name_to_import).name_only();
-    if ignore_modules {
-        external_query = external_query.exclude_import_kind(import_map::ImportKind::Module);
+    let mut external_query =
+        import_map::Query::new(name_to_import).search_mode(import_map::SearchMode::Fuzzy);
+    if name_only {
+        external_query = external_query.name_only();
     }
 
     let mut local_query = symbol_index::Query::new(name_to_import.to_string());
-- 
cgit v1.2.3


From e4c3f753d23752a9fbb01bdf1cd92a8cb1f6681e Mon Sep 17 00:00:00 2001
From: Kirill Bulatov <mail4score@gmail.com>
Date: Mon, 28 Dec 2020 14:54:31 +0200
Subject: Add docs and optimisations

---
 crates/completion/src/completions/unqualified_path.rs |  4 ++--
 crates/hir_def/src/import_map.rs                      | 17 +++++++++++++----
 crates/ide_db/src/imports_locator.rs                  |  6 +++---
 3 files changed, 18 insertions(+), 9 deletions(-)

(limited to 'crates')

diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs
index d09849752..aefbdb163 100644
--- a/crates/completion/src/completions/unqualified_path.rs
+++ b/crates/completion/src/completions/unqualified_path.rs
@@ -101,8 +101,8 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
 //
 // .Fuzzy search details
 //
-// To avoid an excessive amount of the results returned, completion input is checked for inclusion in the identifiers only
-// (i.e. in `HashMap` in the `std::collections::HashMap` path), also not in the module indentifiers.
+// To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only
+// (i.e. in `HashMap` in the `std::collections::HashMap` path).
 //
 // .Merge Behavior
 //
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs
index ce25e1c6e..34a424c60 100644
--- a/crates/hir_def/src/import_map.rs
+++ b/crates/hir_def/src/import_map.rs
@@ -238,11 +238,15 @@ pub enum ImportKind {
     BuiltinType,
 }
 
-/// todo kb
+/// A way to match import map contents against the search query.
 #[derive(Debug)]
 pub enum SearchMode {
+    /// Import map entry should strictly match the query string.
     Equals,
+    /// Import map entry should contain the query string.
     Contains,
+    /// Import map entry should contain all letters from the query string,
+    /// in the same order, but not necessary adjacent.
     Fuzzy,
 }
 
@@ -270,11 +274,14 @@ impl Query {
         }
     }
 
+    /// Matches entries' names only, ignoring the rest of
+    /// the qualifier.
+    /// Example: for `std::marker::PhantomData`, the name is `PhantomData`.
     pub fn name_only(self) -> Self {
         Self { name_only: true, ..self }
     }
 
-    /// todo kb
+    /// Specifies the way to search for the entries using the query.
     pub fn search_mode(self, search_mode: SearchMode) -> Self {
         Self { search_mode, ..self }
     }
@@ -296,7 +303,6 @@ impl Query {
     }
 }
 
-// TODO kb: ugly with a special `return true` case and the `enforce_lowercase` one.
 fn contains_query(query: &Query, input_path: &ImportPath, enforce_lowercase: bool) -> bool {
     let mut input = if query.name_only {
         input_path.segments.last().unwrap().to_string()
@@ -378,7 +384,10 @@ pub fn search_dependencies<'a>(
                     Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind),
                     None => true,
                 })
-                .filter(|item| contains_query(&query, &import_map.map[item].path, false));
+                .filter(|item| {
+                    !query.case_sensitive // we've already checked the common importables path case-insensitively
+                        || contains_query(&query, &import_map.map[item].path, false)
+                });
             res.extend(iter);
 
             if res.len() >= query.limit {
diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/imports_locator.rs
index 986cb5b83..b6355af4b 100644
--- a/crates/ide_db/src/imports_locator.rs
+++ b/crates/ide_db/src/imports_locator.rs
@@ -39,18 +39,18 @@ pub fn find_similar_imports<'a>(
     sema: &Semantics<'a, RootDatabase>,
     krate: Crate,
     limit: Option<usize>,
-    name_to_import: &str,
+    fuzzy_search_string: &str,
     name_only: bool,
 ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> {
     let _p = profile::span("find_similar_imports");
 
     let mut external_query =
-        import_map::Query::new(name_to_import).search_mode(import_map::SearchMode::Fuzzy);
+        import_map::Query::new(fuzzy_search_string).search_mode(import_map::SearchMode::Fuzzy);
     if name_only {
         external_query = external_query.name_only();
     }
 
-    let mut local_query = symbol_index::Query::new(name_to_import.to_string());
+    let mut local_query = symbol_index::Query::new(fuzzy_search_string.to_string());
 
     if let Some(limit) = limit {
         local_query.limit(limit);
-- 
cgit v1.2.3


From 8600cf807ed25684bbbbac96badf383add43b358 Mon Sep 17 00:00:00 2001
From: Kirill Bulatov <mail4score@gmail.com>
Date: Mon, 28 Dec 2020 15:22:03 +0200
Subject: Add tests

---
 crates/hir_def/src/import_map.rs | 73 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 71 insertions(+), 2 deletions(-)

(limited to 'crates')

diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs
index 34a424c60..fcbb3ac14 100644
--- a/crates/hir_def/src/import_map.rs
+++ b/crates/hir_def/src/import_map.rs
@@ -729,7 +729,7 @@ mod tests {
     }
 
     #[test]
-    fn search() {
+    fn search_mode() {
         let ra_fixture = r#"
             //- /main.rs crate:main deps:dep
             //- /dep.rs crate:dep deps:tdep
@@ -772,7 +772,76 @@ mod tests {
         check_search(
             ra_fixture,
             "main",
-            Query::new("fmt").name_only().search_mode(SearchMode::Equals),
+            Query::new("fmt").search_mode(SearchMode::Equals),
+            expect![[r#"
+                dep::fmt (t)
+                dep::Fmt (t)
+                dep::Fmt (v)
+                dep::Fmt (m)
+                dep::fmt::Display (t)
+            "#]],
+        );
+
+        check_search(
+            ra_fixture,
+            "main",
+            Query::new("fmt").search_mode(SearchMode::Contains),
+            expect![[r#"
+                dep::fmt (t)
+                dep::Fmt (t)
+                dep::Fmt (v)
+                dep::Fmt (m)
+                dep::fmt::Display (t)
+                dep::fmt::Display (t)
+            "#]],
+        );
+    }
+
+    #[test]
+    fn name_only() {
+        let ra_fixture = r#"
+            //- /main.rs crate:main deps:dep
+            //- /dep.rs crate:dep deps:tdep
+            use tdep::fmt as fmt_dep;
+            pub mod fmt {
+                pub trait Display {
+                    fn fmt();
+                }
+            }
+            #[macro_export]
+            macro_rules! Fmt {
+                () => {};
+            }
+            pub struct Fmt;
+
+            pub fn format() {}
+            pub fn no() {}
+
+            //- /tdep.rs crate:tdep
+            pub mod fmt {
+                pub struct NotImportableFromMain;
+            }
+        "#;
+
+        check_search(
+            ra_fixture,
+            "main",
+            Query::new("fmt"),
+            expect![[r#"
+                dep::fmt (t)
+                dep::Fmt (t)
+                dep::Fmt (v)
+                dep::Fmt (m)
+                dep::fmt::Display (t)
+                dep::fmt::Display (t)
+            "#]],
+        );
+
+        // TODO kb where does this duplicate `dep::fmt::Display (t)` come from?
+        check_search(
+            ra_fixture,
+            "main",
+            Query::new("fmt").name_only(),
             expect![[r#"
                 dep::fmt (t)
                 dep::Fmt (t)
-- 
cgit v1.2.3


From eecbb51cb39a9d07947e9c474d3e411265282fce Mon Sep 17 00:00:00 2001
From: Kirill Bulatov <mail4score@gmail.com>
Date: Mon, 28 Dec 2020 16:13:37 +0200
Subject: Better display methods in expect tests

---
 crates/hir_def/src/import_map.rs | 46 +++++++++++++++++++++++++++-------------
 1 file changed, 31 insertions(+), 15 deletions(-)

(limited to 'crates')

diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs
index fcbb3ac14..fdc681d6c 100644
--- a/crates/hir_def/src/import_map.rs
+++ b/crates/hir_def/src/import_map.rs
@@ -432,7 +432,7 @@ mod tests {
     use base_db::{fixture::WithFixture, SourceDatabase, Upcast};
     use expect_test::{expect, Expect};
 
-    use crate::{test_db::TestDB, AssocContainerId, Lookup};
+    use crate::{data::FunctionData, test_db::TestDB, AssocContainerId, Lookup};
 
     use super::*;
 
@@ -451,14 +451,31 @@ mod tests {
             .into_iter()
             .filter_map(|item| {
                 let mark = match item {
+                    ItemInNs::Types(ModuleDefId::FunctionId(_))
+                    | ItemInNs::Values(ModuleDefId::FunctionId(_)) => "f",
                     ItemInNs::Types(_) => "t",
                     ItemInNs::Values(_) => "v",
                     ItemInNs::Macros(_) => "m",
                 };
-                let item = assoc_to_trait(&db, item);
                 item.krate(db.upcast()).map(|krate| {
                     let map = db.import_map(krate);
-                    let path = map.path_of(item).unwrap();
+
+                    let path = match assoc_to_trait(&db, item) {
+                        Some(trait_) => {
+                            let mut full_path = map.path_of(trait_).unwrap().to_string();
+                            if let ItemInNs::Types(ModuleDefId::FunctionId(function_id))
+                            | ItemInNs::Values(ModuleDefId::FunctionId(function_id)) = item
+                            {
+                                full_path += &format!(
+                                    "::{}",
+                                    FunctionData::fn_data_query(&db, function_id).name
+                                );
+                            }
+                            full_path
+                        }
+                        None => map.path_of(item).unwrap().to_string(),
+                    };
+
                     format!(
                         "{}::{} ({})\n",
                         crate_graph[krate].display_name.as_ref().unwrap(),
@@ -471,15 +488,15 @@ mod tests {
         expect.assert_eq(&actual)
     }
 
-    fn assoc_to_trait(db: &dyn DefDatabase, item: ItemInNs) -> ItemInNs {
+    fn assoc_to_trait(db: &dyn DefDatabase, item: ItemInNs) -> Option<ItemInNs> {
         let assoc: AssocItemId = match item {
             ItemInNs::Types(it) | ItemInNs::Values(it) => match it {
                 ModuleDefId::TypeAliasId(it) => it.into(),
                 ModuleDefId::FunctionId(it) => it.into(),
                 ModuleDefId::ConstId(it) => it.into(),
-                _ => return item,
+                _ => return None,
             },
-            _ => return item,
+            _ => return None,
         };
 
         let container = match assoc {
@@ -489,8 +506,8 @@ mod tests {
         };
 
         match container {
-            AssocContainerId::TraitId(it) => ItemInNs::Types(it.into()),
-            _ => item,
+            AssocContainerId::TraitId(it) => Some(ItemInNs::Types(it.into())),
+            _ => None,
         }
     }
 
@@ -764,8 +781,8 @@ mod tests {
                 dep::Fmt (v)
                 dep::Fmt (m)
                 dep::fmt::Display (t)
-                dep::format (v)
-                dep::fmt::Display (t)
+                dep::format (f)
+                dep::fmt::Display::fmt (f)
             "#]],
         );
 
@@ -778,7 +795,7 @@ mod tests {
                 dep::Fmt (t)
                 dep::Fmt (v)
                 dep::Fmt (m)
-                dep::fmt::Display (t)
+                dep::fmt::Display::fmt (f)
             "#]],
         );
 
@@ -792,7 +809,7 @@ mod tests {
                 dep::Fmt (v)
                 dep::Fmt (m)
                 dep::fmt::Display (t)
-                dep::fmt::Display (t)
+                dep::fmt::Display::fmt (f)
             "#]],
         );
     }
@@ -833,11 +850,10 @@ mod tests {
                 dep::Fmt (v)
                 dep::Fmt (m)
                 dep::fmt::Display (t)
-                dep::fmt::Display (t)
+                dep::fmt::Display::fmt (f)
             "#]],
         );
 
-        // TODO kb where does this duplicate `dep::fmt::Display (t)` come from?
         check_search(
             ra_fixture,
             "main",
@@ -847,7 +863,7 @@ mod tests {
                 dep::Fmt (t)
                 dep::Fmt (v)
                 dep::Fmt (m)
-                dep::fmt::Display (t)
+                dep::fmt::Display::fmt (f)
             "#]],
         );
     }
-- 
cgit v1.2.3


From 77b4a1c5ef594ddd78c77dd8bb05fba14b99cc9f Mon Sep 17 00:00:00 2001
From: Kirill Bulatov <mail4score@gmail.com>
Date: Mon, 28 Dec 2020 16:19:51 +0200
Subject: Tweak the fuzzy search limits

---
 crates/completion/src/completions/unqualified_path.rs | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

(limited to 'crates')

diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs
index aefbdb163..59f950189 100644
--- a/crates/completion/src/completions/unqualified_path.rs
+++ b/crates/completion/src/completions/unqualified_path.rs
@@ -103,6 +103,7 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
 //
 // To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only
 // (i.e. in `HashMap` in the `std::collections::HashMap` path).
+// For the same reasons, avoids searching for any imports for inputs with their length less that 2 symbols.
 //
 // .Merge Behavior
 //
@@ -126,6 +127,10 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()
     let _p = profile::span("fuzzy_completion");
     let potential_import_name = ctx.token.to_string();
 
+    if potential_import_name.len() < 2 {
+        return None;
+    }
+
     let current_module = ctx.scope.module()?;
     let anchor = ctx.name_ref_syntax.as_ref()?;
     let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?;
@@ -133,7 +138,7 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()
     let mut all_mod_paths = imports_locator::find_similar_imports(
         &ctx.sema,
         ctx.krate?,
-        Some(100),
+        Some(40),
         &potential_import_name,
         true,
     )
-- 
cgit v1.2.3