aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src
diff options
context:
space:
mode:
authorKirill Bulatov <[email protected]>2021-03-02 23:26:53 +0000
committerKirill Bulatov <[email protected]>2021-03-08 21:59:20 +0000
commit33c83e72b9b48177a6171fd06a26676679963a4d (patch)
treeb787206319b2cf0050e4ce7c89ad4365b9a43c11 /crates/ide_completion/src
parent4d4ac1d4fa0aba107a27d3fd2d209304dfe69b9f (diff)
Work towards better import labels
Diffstat (limited to 'crates/ide_completion/src')
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs101
-rw-r--r--crates/ide_completion/src/item.rs43
-rw-r--r--crates/ide_completion/src/lib.rs17
-rw-r--r--crates/ide_completion/src/render.rs14
4 files changed, 92 insertions, 83 deletions
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index 1ef6f8afb..c1e3f091f 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -87,11 +87,12 @@
87//! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding 87//! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding
88//! capability enabled. 88//! capability enabled.
89 89
90use hir::{AsAssocItem, ModPath, ModuleDef, ScopeDef}; 90use hir::ModPath;
91use ide_db::helpers::{ 91use ide_db::helpers::{
92 import_assets::{ImportAssets, ImportCandidate}, 92 import_assets::{ImportAssets, ImportCandidate},
93 insert_use::ImportScope, 93 insert_use::ImportScope,
94}; 94};
95use itertools::Itertools;
95use syntax::{AstNode, SyntaxNode, T}; 96use syntax::{AstNode, SyntaxNode, T};
96 97
97use crate::{ 98use crate::{
@@ -130,27 +131,23 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
130 &ctx.sema, 131 &ctx.sema,
131 )?; 132 )?;
132 133
133 let mut all_imports = 134 acc.add_all(
134 import_assets.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind); 135 import_assets
135 all_imports.sort_by_cached_key(|import| { 136 .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
136 compute_fuzzy_completion_order_key(import.display_path(), &user_input_lowercased) 137 .into_iter()
137 }); 138 .sorted_by_key(|located_import| {
138 139 compute_fuzzy_completion_order_key(
139 acc.add_all(all_imports.into_iter().filter_map(|import| { 140 &located_import.import_path,
140 let import_for_trait_assoc_item = import 141 &user_input_lowercased,
141 .item_to_display() 142 )
142 .as_module_def_id()
143 .and_then(|module_def_id| {
144 ModuleDef::from(module_def_id).as_assoc_item(ctx.db)?.containing_trait(ctx.db)
145 }) 143 })
146 .is_some(); 144 .filter_map(|import| {
147 let def_to_display = ScopeDef::from(import.item_to_display()); 145 render_resolution_with_import(
148 render_resolution_with_import( 146 RenderContext::new(ctx),
149 RenderContext::new(ctx), 147 ImportEdit { import, import_scope: import_scope.clone() },
150 ImportEdit { import, import_scope: import_scope.clone(), import_for_trait_assoc_item }, 148 )
151 &def_to_display, 149 }),
152 ) 150 );
153 }));
154 Some(()) 151 Some(())
155} 152}
156 153
@@ -190,6 +187,7 @@ fn import_assets<'a>(ctx: &'a CompletionContext, fuzzy_name: String) -> Option<I
190 ctx.scope.clone(), 187 ctx.scope.clone(),
191 )?; 188 )?;
192 189
190 // TODO kb bad: with the path prefix, the "min 3 symbols" limit applies. Fix in a separate PR on the symbol_index level
193 if matches!(assets_for_path.import_candidate(), ImportCandidate::Path(_)) 191 if matches!(assets_for_path.import_candidate(), ImportCandidate::Path(_))
194 && fuzzy_name_length < 2 192 && fuzzy_name_length < 2
195 { 193 {
@@ -796,9 +794,7 @@ fn main() {
796 794
797 #[test] 795 #[test]
798 fn unresolved_qualifier() { 796 fn unresolved_qualifier() {
799 check_edit( 797 let fixture = r#"
800 "Item",
801 r#"
802mod foo { 798mod foo {
803 pub mod bar { 799 pub mod bar {
804 pub mod baz { 800 pub mod baz {
@@ -809,31 +805,34 @@ mod foo {
809 805
810fn main() { 806fn main() {
811 bar::baz::Ite$0 807 bar::baz::Ite$0
812} 808}"#;
813"#, 809
810 check(fixture, expect![["st Item (foo::bar::baz::Item)"]]);
811
812 check_edit(
813 "Item",
814 fixture,
814 r#" 815 r#"
815use foo::bar; 816 use foo::bar;
816 817
817mod foo { 818 mod foo {
818 pub mod bar { 819 pub mod bar {
819 pub mod baz { 820 pub mod baz {
820 pub struct Item; 821 pub struct Item;
822 }
823 }
821 } 824 }
822 }
823}
824 825
825fn main() { 826 fn main() {
826 bar::baz::Item 827 bar::baz::Item
827} 828 }
828"#, 829 "#,
829 ); 830 );
830 } 831 }
831 832
832 #[test] 833 #[test]
833 fn unresolved_assoc_item_container() { 834 fn unresolved_assoc_item_container() {
834 check_edit( 835 let fixture = r#"
835 "TEST_ASSOC",
836 r#"
837mod foo { 836mod foo {
838 pub struct Item; 837 pub struct Item;
839 838
@@ -844,8 +843,13 @@ mod foo {
844 843
845fn main() { 844fn main() {
846 Item::TEST_A$0 845 Item::TEST_A$0
847} 846}"#;
848"#, 847
848 check(fixture, expect![["ct TEST_ASSOC (foo::bar::baz::Item)"]]);
849
850 check_edit(
851 "TEST_ASSOC",
852 fixture,
849 r#" 853 r#"
850use foo::Item; 854use foo::Item;
851 855
@@ -866,9 +870,7 @@ fn main() {
866 870
867 #[test] 871 #[test]
868 fn unresolved_assoc_item_container_with_path() { 872 fn unresolved_assoc_item_container_with_path() {
869 check_edit( 873 let fixture = r#"
870 "TEST_ASSOC",
871 r#"
872mod foo { 874mod foo {
873 pub mod bar { 875 pub mod bar {
874 pub struct Item; 876 pub struct Item;
@@ -881,8 +883,13 @@ mod foo {
881 883
882fn main() { 884fn main() {
883 bar::Item::TEST_A$0 885 bar::Item::TEST_A$0
884} 886}"#;
885"#, 887
888 check(fixture, expect![["ct TEST_ASSOC (foo::bar::baz::Item)"]]);
889
890 check_edit(
891 "TEST_ASSOC",
892 fixture,
886 r#" 893 r#"
887use foo::bar; 894use foo::bar;
888 895
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs
index 0390fe226..d01620500 100644
--- a/crates/ide_completion/src/item.rs
+++ b/crates/ide_completion/src/item.rs
@@ -275,7 +275,6 @@ impl CompletionItem {
275pub struct ImportEdit { 275pub struct ImportEdit {
276 pub import: LocatedImport, 276 pub import: LocatedImport,
277 pub import_scope: ImportScope, 277 pub import_scope: ImportScope,
278 pub import_for_trait_assoc_item: bool,
279} 278}
280 279
281impl ImportEdit { 280impl ImportEdit {
@@ -286,7 +285,7 @@ impl ImportEdit {
286 285
287 let rewriter = insert_use::insert_use( 286 let rewriter = insert_use::insert_use(
288 &self.import_scope, 287 &self.import_scope,
289 mod_path_to_ast(self.import.import_path()), 288 mod_path_to_ast(&self.import.import_path),
290 cfg, 289 cfg,
291 ); 290 );
292 let old_ast = rewriter.rewrite_root()?; 291 let old_ast = rewriter.rewrite_root()?;
@@ -303,6 +302,7 @@ impl ImportEdit {
303pub(crate) struct Builder { 302pub(crate) struct Builder {
304 source_range: TextRange, 303 source_range: TextRange,
305 completion_kind: CompletionKind, 304 completion_kind: CompletionKind,
305 // TODO kb also add a db here, to resolve the completion label?
306 import_to_add: Option<ImportEdit>, 306 import_to_add: Option<ImportEdit>,
307 label: String, 307 label: String,
308 insert_text: Option<String>, 308 insert_text: Option<String>,
@@ -322,19 +322,22 @@ impl Builder {
322 pub(crate) fn build(self) -> CompletionItem { 322 pub(crate) fn build(self) -> CompletionItem {
323 let _p = profile::span("item::Builder::build"); 323 let _p = profile::span("item::Builder::build");
324 324
325 let mut label = self.label; 325 let label = self.label;
326 let mut lookup = self.lookup; 326 let lookup = self.lookup;
327 let mut insert_text = self.insert_text; 327 let insert_text = self.insert_text;
328 328
329 if let Some(import_to_add) = self.import_to_add.as_ref() { 329 if let Some(_import_to_add) = self.import_to_add.as_ref() {
330 lookup = lookup.or_else(|| Some(label.clone())); 330 todo!("todo kb")
331 insert_text = insert_text.or_else(|| Some(label.clone())); 331 // let import = &import_to_add.import;
332 let display_path = import_to_add.import.display_path(); 332 // let item_to_import = import.item_to_import();
333 if import_to_add.import_for_trait_assoc_item { 333 // lookup = lookup.or_else(|| Some(label.clone()));
334 label = format!("{} ({})", label, display_path); 334 // insert_text = insert_text.or_else(|| Some(label.clone()));
335 } else { 335 // let display_path = import_to_add.import.display_path();
336 label = display_path.to_string(); 336 // if import_to_add.import {
337 } 337 // label = format!("{} ({})", label, display_path);
338 // } else {
339 // label = display_path.to_string();
340 // }
338 } 341 }
339 342
340 let text_edit = match self.text_edit { 343 let text_edit = match self.text_edit {
@@ -438,8 +441,8 @@ impl Builder {
438 } 441 }
439} 442}
440 443
441impl<'a> Into<CompletionItem> for Builder { 444// impl<'a> Into<CompletionItem> for Builder {
442 fn into(self) -> CompletionItem { 445// fn into(self) -> CompletionItem {
443 self.build() 446// self.build()
444 } 447// }
445} 448// }
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index ca2e5e706..d19368de0 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -15,7 +15,7 @@ use completions::flyimport::position_for_import;
15use ide_db::{ 15use ide_db::{
16 base_db::FilePosition, 16 base_db::FilePosition,
17 helpers::{import_assets::LocatedImport, insert_use::ImportScope}, 17 helpers::{import_assets::LocatedImport, insert_use::ImportScope},
18 imports_locator, RootDatabase, 18 items_locator, RootDatabase,
19}; 19};
20use text_edit::TextEdit; 20use text_edit::TextEdit;
21 21
@@ -141,7 +141,6 @@ pub fn resolve_completion_edits(
141 position: FilePosition, 141 position: FilePosition,
142 full_import_path: &str, 142 full_import_path: &str,
143 imported_name: String, 143 imported_name: String,
144 import_for_trait_assoc_item: bool,
145) -> Option<Vec<TextEdit>> { 144) -> Option<Vec<TextEdit>> {
146 let ctx = CompletionContext::new(db, position, config)?; 145 let ctx = CompletionContext::new(db, position, config)?;
147 let position_for_import = position_for_import(&ctx, None)?; 146 let position_for_import = position_for_import(&ctx, None)?;
@@ -151,19 +150,17 @@ pub fn resolve_completion_edits(
151 let current_crate = current_module.krate(); 150 let current_crate = current_module.krate();
152 151
153 let (import_path, item_to_import) = 152 let (import_path, item_to_import) =
154 imports_locator::find_exact_imports(&ctx.sema, current_crate, imported_name) 153 items_locator::with_for_exact_name(&ctx.sema, current_crate, imported_name)
154 .into_iter()
155 .filter_map(|candidate| { 155 .filter_map(|candidate| {
156 let item: hir::ItemInNs = candidate.either(Into::into, Into::into);
157 current_module 156 current_module
158 .find_use_path_prefixed(db, item, config.insert_use.prefix_kind) 157 .find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind)
159 .zip(Some(item)) 158 .zip(Some(candidate))
160 }) 159 })
161 .find(|(mod_path, _)| mod_path.to_string() == full_import_path)?; 160 .find(|(mod_path, _)| mod_path.to_string() == full_import_path)?;
162 let import = LocatedImport::new(import_path, item_to_import, None); 161 let import = LocatedImport::new(import_path, item_to_import, item_to_import);
163 162
164 ImportEdit { import_path, import_scope, import_for_trait_assoc_item } 163 ImportEdit { import, import_scope }.to_text_edit(config.insert_use).map(|edit| vec![edit])
165 .to_text_edit(config.insert_use)
166 .map(|edit| vec![edit])
167} 164}
168 165
169#[cfg(test)] 166#[cfg(test)]
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 4bddc3957..fae5685e2 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -53,18 +53,20 @@ pub(crate) fn render_resolution<'a>(
53pub(crate) fn render_resolution_with_import<'a>( 53pub(crate) fn render_resolution_with_import<'a>(
54 ctx: RenderContext<'a>, 54 ctx: RenderContext<'a>,
55 import_edit: ImportEdit, 55 import_edit: ImportEdit,
56 resolution: &ScopeDef,
57) -> Option<CompletionItem> { 56) -> Option<CompletionItem> {
57 let resolution = ScopeDef::from(import_edit.import.original_item);
58 let local_name = match resolution { 58 let local_name = match resolution {
59 ScopeDef::ModuleDef(ModuleDef::Function(f)) => f.name(ctx.completion.db).to_string(), 59 ScopeDef::ModuleDef(ModuleDef::Function(f)) => f.name(ctx.completion.db).to_string(),
60 ScopeDef::ModuleDef(ModuleDef::Const(c)) => c.name(ctx.completion.db)?.to_string(), 60 ScopeDef::ModuleDef(ModuleDef::Const(c)) => c.name(ctx.completion.db)?.to_string(),
61 ScopeDef::ModuleDef(ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db).to_string(), 61 ScopeDef::ModuleDef(ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db).to_string(),
62 _ => item_name(ctx.db(), import_edit.import.item_to_display())?.to_string(), 62 _ => item_name(ctx.db(), import_edit.import.original_item)?.to_string(),
63 }; 63 };
64 Render::new(ctx).render_resolution(local_name, Some(import_edit), resolution).map(|mut item| { 64 Render::new(ctx).render_resolution(local_name, Some(import_edit), &resolution).map(
65 item.completion_kind = CompletionKind::Magic; 65 |mut item| {
66 item 66 item.completion_kind = CompletionKind::Magic;
67 }) 67 item
68 },
69 )
68} 70}
69 71
70/// Interface for data and methods required for items rendering. 72/// Interface for data and methods required for items rendering.