From 410acd7188a5efb99f8629c7ff0630ce4935350a Mon Sep 17 00:00:00 2001 From: hecatia-elegua <108802164+hecatia-elegua@users.noreply.github.com> Date: Wed, 5 Apr 2023 19:28:55 +0200 Subject: [PATCH 1/4] Add doc(alias)-based field completion --- crates/ide-completion/src/completions.rs | 3 ++- crates/ide-completion/src/context.rs | 12 ++++++++++-- crates/ide-completion/src/item.rs | 12 +++++++----- crates/ide-completion/src/render.rs | 7 ++----- crates/ide-completion/src/tests/special.rs | 19 +++++++++++++++++++ 5 files changed, 40 insertions(+), 13 deletions(-) diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs index b6a066f4f5..333a333875 100644 --- a/crates/ide-completion/src/completions.rs +++ b/crates/ide-completion/src/completions.rs @@ -430,8 +430,9 @@ impl Completions { Visible::Editable => true, Visible::No => return, }; + let doc_aliases = ctx.doc_aliases(&field); let item = render_field( - RenderContext::new(ctx).private_editable(is_private_editable), + RenderContext::new(ctx).private_editable(is_private_editable).doc_aliases(doc_aliases), dot_access, receiver, field, diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index f6478d2ceb..f9bc13f7d2 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -441,6 +441,14 @@ impl<'a> CompletionContext<'a> { self.is_visible_impl(&vis, &attrs, item.krate(self.db)) } + pub(crate) fn doc_aliases(&self, item: &I) -> Vec + where + I: hir::HasAttrs + Copy, + { + let attrs = item.attrs(self.db); + attrs.doc_aliases().collect() + } + /// Check if an item is `#[doc(hidden)]`. pub(crate) fn is_item_hidden(&self, item: &hir::ItemInNs) -> bool { let attrs = item.attrs(self.db); @@ -499,7 +507,7 @@ impl<'a> CompletionContext<'a> { if self.is_scope_def_hidden(def) { return; } - let doc_aliases = self.doc_aliases(def); + let doc_aliases = self.doc_aliases_in_scope(def); f(name, def, doc_aliases); }); } @@ -547,7 +555,7 @@ impl<'a> CompletionContext<'a> { self.krate != defining_crate && attrs.has_doc_hidden() } - fn doc_aliases(&self, scope_def: ScopeDef) -> Vec { + fn doc_aliases_in_scope(&self, scope_def: ScopeDef) -> Vec { if let Some(attrs) = scope_def.attrs(self.db) { attrs.doc_aliases().collect() } else { diff --git a/crates/ide-completion/src/item.rs b/crates/ide-completion/src/item.rs index c2c4a663c6..ab27b8c0a9 100644 --- a/crates/ide-completion/src/item.rs +++ b/crates/ide-completion/src/item.rs @@ -4,6 +4,7 @@ use std::fmt; use hir::{Documentation, Mutability}; use ide_db::{imports::import_assets::LocatedImport, SnippetCap, SymbolKind}; +use itertools::Itertools; use smallvec::SmallVec; use stdx::{impl_from, never}; use syntax::{SmolStr, TextRange, TextSize}; @@ -353,7 +354,7 @@ impl CompletionItem { relevance: CompletionRelevance::default(), ref_match: None, imports_to_add: Default::default(), - doc_aliases: None, + doc_aliases: vec![], } } @@ -386,7 +387,7 @@ pub(crate) struct Builder { source_range: TextRange, imports_to_add: SmallVec<[LocatedImport; 1]>, trait_name: Option, - doc_aliases: Option, + doc_aliases: Vec, label: SmolStr, insert_text: Option, is_snippet: bool, @@ -418,7 +419,8 @@ impl Builder { let mut lookup = self.lookup.unwrap_or_else(|| label.clone()); let insert_text = self.insert_text.unwrap_or_else(|| label.to_string()); - if let Some(doc_aliases) = self.doc_aliases { + if !self.doc_aliases.is_empty() { + let doc_aliases = self.doc_aliases.into_iter().join(", "); label = SmolStr::from(format!("{label} (alias {doc_aliases})")); lookup = SmolStr::from(format!("{lookup} {doc_aliases}")); } @@ -464,8 +466,8 @@ impl Builder { self.trait_name = Some(trait_name); self } - pub(crate) fn doc_aliases(&mut self, doc_aliases: SmolStr) -> &mut Builder { - self.doc_aliases = Some(doc_aliases); + pub(crate) fn doc_aliases(&mut self, doc_aliases: Vec) -> &mut Builder { + self.doc_aliases = doc_aliases; self } pub(crate) fn insert_text(&mut self, insert_text: impl Into) -> &mut Builder { diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index 514a684726..62a357e085 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -152,6 +152,7 @@ pub(crate) fn render_field( } } } + item.doc_aliases(ctx.doc_aliases); item.build() } @@ -361,11 +362,7 @@ fn render_resolution_simple_( item.add_import(import_to_add); } - let doc_aliases = ctx.doc_aliases; - if !doc_aliases.is_empty() { - let doc_aliases = doc_aliases.into_iter().join(", ").into(); - item.doc_aliases(doc_aliases); - } + item.doc_aliases(ctx.doc_aliases); item } diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs index 1749e8e70f..5f53e5b6a9 100644 --- a/crates/ide-completion/src/tests/special.rs +++ b/crates/ide-completion/src/tests/special.rs @@ -1086,3 +1086,22 @@ fn here_we_go() { "#]], ); } + +#[test] +fn completes_field_name_via_doc_alias_in_fn_body() { + check( + r#" +struct Foo { + #[doc(alias = "qux")] + bar: u8 +}; + +fn here_we_go() { + let foo = Foo { q$0 } +} +"#, + expect![[r#" + fd bar (alias qux) u8 + "#]], + ); +} From f87f468dbdba374b5e2b04b832ab99dbd74dc288 Mon Sep 17 00:00:00 2001 From: hecatia-elegua <108802164+hecatia-elegua@users.noreply.github.com> Date: Wed, 5 Apr 2023 19:35:21 +0200 Subject: [PATCH 2/4] Add doc(alias)-based function name completion --- crates/ide-completion/src/render/function.rs | 2 + crates/ide-completion/src/tests/special.rs | 45 ++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs index 197592e78c..bfcd23280c 100644 --- a/crates/ide-completion/src/render/function.rs +++ b/crates/ide-completion/src/render/function.rs @@ -147,6 +147,8 @@ fn render( } } } + + item.doc_aliases(ctx.doc_aliases); item } diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs index 5f53e5b6a9..8d9bd4ba1a 100644 --- a/crates/ide-completion/src/tests/special.rs +++ b/crates/ide-completion/src/tests/special.rs @@ -1105,3 +1105,48 @@ fn here_we_go() { "#]], ); } + +#[test] +fn completes_fn_name_via_doc_alias_in_fn_body() { + check( + r#" +#[doc(alias = "qux")] +fn foo() {} +fn bar() { qu$0 } +"#, + expect![[r#" + fn bar() fn() + fn foo() (alias qux) fn() + bt u32 + kw const + kw crate:: + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw let + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); +} From b4515d987f53c5d874b69609f15708f503d3b32e Mon Sep 17 00:00:00 2001 From: hecatia-elegua <108802164+hecatia-elegua@users.noreply.github.com> Date: Wed, 5 Apr 2023 22:08:59 +0200 Subject: [PATCH 3/4] Add doc(alias)-based use and other mod completion --- crates/ide-completion/src/completions/expr.rs | 2 +- crates/ide-completion/src/context.rs | 2 +- crates/ide-completion/src/item.rs | 3 +- crates/ide-completion/src/tests/special.rs | 39 +++++++++++++++++++ 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index 70c91e6a10..19f4d65320 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -88,7 +88,7 @@ pub(crate) fn complete_expr_path( let module_scope = module.scope(ctx.db, Some(ctx.module)); for (name, def) in module_scope { if scope_def_applicable(def) { - acc.add_path_resolution(ctx, path_ctx, name, def, vec![]); + acc.add_path_resolution(ctx, path_ctx, name, def, ctx.doc_aliases_in_scope(def)); } } } diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index f9bc13f7d2..6089f18ac6 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -555,7 +555,7 @@ impl<'a> CompletionContext<'a> { self.krate != defining_crate && attrs.has_doc_hidden() } - fn doc_aliases_in_scope(&self, scope_def: ScopeDef) -> Vec { + pub(crate) fn doc_aliases_in_scope(&self, scope_def: ScopeDef) -> Vec { if let Some(attrs) = scope_def.attrs(self.db) { attrs.doc_aliases().collect() } else { diff --git a/crates/ide-completion/src/item.rs b/crates/ide-completion/src/item.rs index ab27b8c0a9..a993ea8e90 100644 --- a/crates/ide-completion/src/item.rs +++ b/crates/ide-completion/src/item.rs @@ -409,7 +409,8 @@ impl Builder { local_name: hir::Name, resolution: hir::ScopeDef, ) -> Self { - render_path_resolution(RenderContext::new(ctx), path_ctx, local_name, resolution) + let doc_aliases = ctx.doc_aliases_in_scope(resolution); + render_path_resolution(RenderContext::new(ctx).doc_aliases(doc_aliases), path_ctx, local_name, resolution) } pub(crate) fn build(self) -> CompletionItem { diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs index 8d9bd4ba1a..e11a2c4797 100644 --- a/crates/ide-completion/src/tests/special.rs +++ b/crates/ide-completion/src/tests/special.rs @@ -1150,3 +1150,42 @@ fn bar() { qu$0 } "#]], ); } + +#[test] +fn completes_struct_name_via_doc_alias_in_another_mod() { + check( + r#" +mod foo { + #[doc(alias = "Qux")] + pub struct Bar(u8); +} + +fn here_we_go() { + use foo; + let foo = foo::Q$0 +} +"#, + expect![[r#" + st Bar (alias Qux) + "#]], + ); +} + +#[test] +fn completes_use_via_doc_alias_in_another_mod() { + check( + r#" +mod foo { + #[doc(alias = "Qux")] + pub struct Bar(u8); +} + +fn here_we_go() { + use foo::Q$0; +} +"#, + expect![[r#" + st Bar (alias Qux) + "#]], + ); +} \ No newline at end of file From 33ee157f3b05865984957953df21f4711f8e5cd6 Mon Sep 17 00:00:00 2001 From: hecatia-elegua <108802164+hecatia-elegua@users.noreply.github.com> Date: Thu, 6 Apr 2023 17:25:30 +0200 Subject: [PATCH 4/4] Render alias text for use imports * removes one method breaking the flow --- crates/ide-completion/src/completions.rs | 8 -- crates/ide-completion/src/completions/expr.rs | 8 +- .../src/completions/flyimport.rs | 80 ++++++++----------- crates/ide-completion/src/item.rs | 7 +- crates/ide-completion/src/render.rs | 5 +- crates/ide-completion/src/tests/special.rs | 37 ++++++++- 6 files changed, 84 insertions(+), 61 deletions(-) diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs index 333a333875..b94bbc4065 100644 --- a/crates/ide-completion/src/completions.rs +++ b/crates/ide-completion/src/completions.rs @@ -78,14 +78,6 @@ impl Completions { } } - pub(crate) fn add_all(&mut self, items: I) - where - I: IntoIterator, - I::Item: Into, - { - items.into_iter().for_each(|item| self.add(item.into())) - } - pub(crate) fn add_keyword(&mut self, ctx: &CompletionContext<'_>, keyword: &'static str) { let item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), keyword); item.add_to(self); diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index 19f4d65320..9daa6984c3 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -88,7 +88,13 @@ pub(crate) fn complete_expr_path( let module_scope = module.scope(ctx.db, Some(ctx.module)); for (name, def) in module_scope { if scope_def_applicable(def) { - acc.add_path_resolution(ctx, path_ctx, name, def, ctx.doc_aliases_in_scope(def)); + acc.add_path_resolution( + ctx, + path_ctx, + name, + def, + ctx.doc_aliases_in_scope(def), + ); } } } diff --git a/crates/ide-completion/src/completions/flyimport.rs b/crates/ide-completion/src/completions/flyimport.rs index 0979f6a6df..6d023e12bc 100644 --- a/crates/ide-completion/src/completions/flyimport.rs +++ b/crates/ide-completion/src/completions/flyimport.rs @@ -257,30 +257,22 @@ fn import_on_the_fly( }; let user_input_lowercased = potential_import_name.to_lowercase(); - acc.add_all( - import_assets - .search_for_imports( - &ctx.sema, - ctx.config.insert_use.prefix_kind, - ctx.config.prefer_no_std, - ) - .into_iter() - .filter(ns_filter) - .filter(|import| { - !ctx.is_item_hidden(&import.item_to_import) - && !ctx.is_item_hidden(&import.original_item) - }) - .sorted_by_key(|located_import| { - compute_fuzzy_completion_order_key( - &located_import.import_path, - &user_input_lowercased, - ) - }) - .filter_map(|import| { - render_resolution_with_import(RenderContext::new(ctx), path_ctx, import) - }) - .map(|builder| builder.build()), - ); + import_assets + .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind, ctx.config.prefer_no_std) + .into_iter() + .filter(ns_filter) + .filter(|import| { + !ctx.is_item_hidden(&import.item_to_import) + && !ctx.is_item_hidden(&import.original_item) + }) + .sorted_by_key(|located_import| { + compute_fuzzy_completion_order_key(&located_import.import_path, &user_input_lowercased) + }) + .filter_map(|import| { + render_resolution_with_import(RenderContext::new(ctx), path_ctx, import) + }) + .map(|builder| builder.build()) + .for_each(|item| acc.add(item)); Some(()) } @@ -305,30 +297,22 @@ fn import_on_the_fly_pat_( }; let user_input_lowercased = potential_import_name.to_lowercase(); - acc.add_all( - import_assets - .search_for_imports( - &ctx.sema, - ctx.config.insert_use.prefix_kind, - ctx.config.prefer_no_std, - ) - .into_iter() - .filter(ns_filter) - .filter(|import| { - !ctx.is_item_hidden(&import.item_to_import) - && !ctx.is_item_hidden(&import.original_item) - }) - .sorted_by_key(|located_import| { - compute_fuzzy_completion_order_key( - &located_import.import_path, - &user_input_lowercased, - ) - }) - .filter_map(|import| { - render_resolution_with_import_pat(RenderContext::new(ctx), pattern_ctx, import) - }) - .map(|builder| builder.build()), - ); + import_assets + .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind, ctx.config.prefer_no_std) + .into_iter() + .filter(ns_filter) + .filter(|import| { + !ctx.is_item_hidden(&import.item_to_import) + && !ctx.is_item_hidden(&import.original_item) + }) + .sorted_by_key(|located_import| { + compute_fuzzy_completion_order_key(&located_import.import_path, &user_input_lowercased) + }) + .filter_map(|import| { + render_resolution_with_import_pat(RenderContext::new(ctx), pattern_ctx, import) + }) + .map(|builder| builder.build()) + .for_each(|item| acc.add(item)); Some(()) } diff --git a/crates/ide-completion/src/item.rs b/crates/ide-completion/src/item.rs index a993ea8e90..e95cae9d67 100644 --- a/crates/ide-completion/src/item.rs +++ b/crates/ide-completion/src/item.rs @@ -410,7 +410,12 @@ impl Builder { resolution: hir::ScopeDef, ) -> Self { let doc_aliases = ctx.doc_aliases_in_scope(resolution); - render_path_resolution(RenderContext::new(ctx).doc_aliases(doc_aliases), path_ctx, local_name, resolution) + render_path_resolution( + RenderContext::new(ctx).doc_aliases(doc_aliases), + path_ctx, + local_name, + resolution, + ) } pub(crate) fn build(self) -> CompletionItem { diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index 62a357e085..9673252ff5 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -14,7 +14,6 @@ use hir::{AsAssocItem, HasAttrs, HirDisplay, ScopeDef}; use ide_db::{ helpers::item_name, imports::import_assets::LocatedImport, RootDatabase, SnippetCap, SymbolKind, }; -use itertools::Itertools; use syntax::{AstNode, SmolStr, SyntaxKind, TextRange}; use crate::{ @@ -210,7 +209,9 @@ pub(crate) fn render_resolution_with_import( ) -> Option { let resolution = ScopeDef::from(import_edit.original_item); let local_name = scope_def_to_name(resolution, &ctx, &import_edit)?; - + //this now just renders the alias text, but we need to find the aliases earlier and call this with the alias instead + let doc_aliases = ctx.completion.doc_aliases_in_scope(resolution); + let ctx = ctx.doc_aliases(doc_aliases); Some(render_resolution_path(ctx, path_ctx, local_name, Some(import_edit), resolution)) } diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs index e11a2c4797..e23f3ae72e 100644 --- a/crates/ide-completion/src/tests/special.rs +++ b/crates/ide-completion/src/tests/special.rs @@ -1188,4 +1188,39 @@ fn here_we_go() { st Bar (alias Qux) "#]], ); -} \ No newline at end of file +} + +#[test] +fn completes_flyimport_with_doc_alias_in_another_mod() { + check( + r#" +mod foo { + #[doc(alias = "Qux")] + pub struct Bar(); +} + +fn here_we_go() { + let foo = Bar$0 +} +"#, + expect![[r#" + fn here_we_go() fn() + md foo + st Bar (alias Qux) (use foo::Bar) + bt u32 + kw crate:: + kw false + kw for + kw if + kw if let + kw loop + kw match + kw return + kw self:: + kw true + kw unsafe + kw while + kw while let + "#]], + ); +}