From e3cda83f90a5e64ccf288438466e6c447df253a8 Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Wed, 22 Jan 2020 22:25:41 -0600 Subject: Added basic support for completing `fn` for trait impl. --- crates/ra_ide/src/completion.rs | 3 + crates/ra_ide/src/completion/complete_impl_fn.rs | 80 ++++++++++++++++++++++++ crates/ra_ide/src/completion/presentation.rs | 33 ++++++++++ 3 files changed, 116 insertions(+) create mode 100644 crates/ra_ide/src/completion/complete_impl_fn.rs (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs index abe1f36ce..f31f2593c 100644 --- a/crates/ra_ide/src/completion.rs +++ b/crates/ra_ide/src/completion.rs @@ -15,6 +15,7 @@ mod complete_path; mod complete_scope; mod complete_postfix; mod complete_macro_in_item_position; +mod complete_impl_fn; use ra_db::SourceDatabase; @@ -73,5 +74,7 @@ pub(crate) fn completions(db: &db::RootDatabase, position: FilePosition) -> Opti complete_pattern::complete_pattern(&mut acc, &ctx); complete_postfix::complete_postfix(&mut acc, &ctx); complete_macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx); + complete_impl_fn::complete_impl_fn(&mut acc, &ctx); + Some(acc) } diff --git a/crates/ra_ide/src/completion/complete_impl_fn.rs b/crates/ra_ide/src/completion/complete_impl_fn.rs new file mode 100644 index 000000000..6d464cc1f --- /dev/null +++ b/crates/ra_ide/src/completion/complete_impl_fn.rs @@ -0,0 +1,80 @@ + +use crate::completion::{CompletionContext, Completions}; + +use hir::{ self, db::HirDatabase, HasSource }; + +use ra_syntax::{ ast, ast::AstNode }; + +pub(crate) fn complete_impl_fn(acc: &mut Completions, ctx: &CompletionContext) { + let impl_trait = ast::ItemList::cast(ctx.token.parent()) + .and_then(|item_list| item_list.syntax().parent()) + .and_then(|item_list_parent| ast::ImplBlock::cast(item_list_parent)) + .and_then(|impl_block| resolve_target_trait(ctx.db, &ctx.analyzer, &impl_block)); + + if let Some(x) = &impl_trait { + for trait_item in x.0.items(ctx.db) { + match trait_item { + hir::AssocItem::Function(f) => acc.add_function_impl(ctx, f), + _ => {} + } + } + } +} + +fn resolve_target_trait( + db: &impl HirDatabase, + analyzer: &hir::SourceAnalyzer, + impl_block: &ast::ImplBlock +) -> Option<(hir::Trait, ast::TraitDef)> { + let ast_path = impl_block + .target_trait() + .map(|it| it.syntax().clone()) + .and_then(ast::PathType::cast)? + .path()?; + + match analyzer.resolve_path(db, &ast_path) { + Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => { + Some((def, def.source(db).value)) + } + _ => None, + } +} + +#[cfg(test)] +mod tests { + use crate::completion::{do_completion, CompletionItem, CompletionKind}; + use insta::assert_debug_snapshot; + + fn complete(code: &str) -> Vec { + do_completion(code, CompletionKind::Reference) + } + + #[test] + fn single_function() { + let completions = complete( + r" + trait Test { + fn foo(); + } + + struct T1; + + impl Test for T1 { + <|> + } + ", + ); + assert_debug_snapshot!(completions, @r###" + [ + CompletionItem { + label: "fn foo()", + source_range: [138; 138), + delete: [138; 138), + insert: "fn foo() { $0 }", + kind: Function, + lookup: "foo", + }, + ] + "###); + } +} \ No newline at end of file diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 97475fc0b..d0a43261f 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs @@ -129,6 +129,39 @@ impl Completions { self.add_function_with_name(ctx, None, func) } + pub(crate) fn add_function_impl(&mut self, ctx: &CompletionContext, func: hir::Function) { + use crate::display::FunctionSignature; + + let display = FunctionSignature::from_hir(ctx.db, func.clone()); + + let func_name = func.name(ctx.db); + + let mut builder = CompletionItem::new( + CompletionKind::Reference, + ctx.source_range(), + format!("fn {}()", func_name.to_string())) + .set_documentation(func.docs(ctx.db)); + + let completion_kind = if func.has_self_param(ctx.db) { + CompletionItemKind::Method + } else { + CompletionItemKind::Function + }; + + let snippet = { + let mut s = format!("{}", display); + s.push_str(" { $0 }"); + s + }; + + builder = builder + .insert_text(snippet) + .kind(completion_kind) + .lookup_by(func_name.to_string()); + + self.add(builder.build()); + } + fn guess_macro_braces(&self, macro_name: &str, docs: &str) -> &'static str { let mut votes = [0, 0, 0]; for (idx, s) in docs.match_indices(¯o_name) { -- cgit v1.2.3 From bc1fc6239d67708112f4f3997b104934dd11b7fd Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Wed, 22 Jan 2020 22:38:03 -0600 Subject: Renamed the trait completion mod. --- crates/ra_ide/src/completion.rs | 4 +- crates/ra_ide/src/completion/complete_impl_fn.rs | 80 ---------------------- .../ra_ide/src/completion/complete_trait_impl.rs | 80 ++++++++++++++++++++++ 3 files changed, 82 insertions(+), 82 deletions(-) delete mode 100644 crates/ra_ide/src/completion/complete_impl_fn.rs create mode 100644 crates/ra_ide/src/completion/complete_trait_impl.rs (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs index f31f2593c..ad7f6ef26 100644 --- a/crates/ra_ide/src/completion.rs +++ b/crates/ra_ide/src/completion.rs @@ -15,7 +15,7 @@ mod complete_path; mod complete_scope; mod complete_postfix; mod complete_macro_in_item_position; -mod complete_impl_fn; +mod complete_trait_impl; use ra_db::SourceDatabase; @@ -74,7 +74,7 @@ pub(crate) fn completions(db: &db::RootDatabase, position: FilePosition) -> Opti complete_pattern::complete_pattern(&mut acc, &ctx); complete_postfix::complete_postfix(&mut acc, &ctx); complete_macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx); - complete_impl_fn::complete_impl_fn(&mut acc, &ctx); + complete_trait_impl::complete_trait_impl(&mut acc, &ctx); Some(acc) } diff --git a/crates/ra_ide/src/completion/complete_impl_fn.rs b/crates/ra_ide/src/completion/complete_impl_fn.rs deleted file mode 100644 index 6d464cc1f..000000000 --- a/crates/ra_ide/src/completion/complete_impl_fn.rs +++ /dev/null @@ -1,80 +0,0 @@ - -use crate::completion::{CompletionContext, Completions}; - -use hir::{ self, db::HirDatabase, HasSource }; - -use ra_syntax::{ ast, ast::AstNode }; - -pub(crate) fn complete_impl_fn(acc: &mut Completions, ctx: &CompletionContext) { - let impl_trait = ast::ItemList::cast(ctx.token.parent()) - .and_then(|item_list| item_list.syntax().parent()) - .and_then(|item_list_parent| ast::ImplBlock::cast(item_list_parent)) - .and_then(|impl_block| resolve_target_trait(ctx.db, &ctx.analyzer, &impl_block)); - - if let Some(x) = &impl_trait { - for trait_item in x.0.items(ctx.db) { - match trait_item { - hir::AssocItem::Function(f) => acc.add_function_impl(ctx, f), - _ => {} - } - } - } -} - -fn resolve_target_trait( - db: &impl HirDatabase, - analyzer: &hir::SourceAnalyzer, - impl_block: &ast::ImplBlock -) -> Option<(hir::Trait, ast::TraitDef)> { - let ast_path = impl_block - .target_trait() - .map(|it| it.syntax().clone()) - .and_then(ast::PathType::cast)? - .path()?; - - match analyzer.resolve_path(db, &ast_path) { - Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => { - Some((def, def.source(db).value)) - } - _ => None, - } -} - -#[cfg(test)] -mod tests { - use crate::completion::{do_completion, CompletionItem, CompletionKind}; - use insta::assert_debug_snapshot; - - fn complete(code: &str) -> Vec { - do_completion(code, CompletionKind::Reference) - } - - #[test] - fn single_function() { - let completions = complete( - r" - trait Test { - fn foo(); - } - - struct T1; - - impl Test for T1 { - <|> - } - ", - ); - assert_debug_snapshot!(completions, @r###" - [ - CompletionItem { - label: "fn foo()", - source_range: [138; 138), - delete: [138; 138), - insert: "fn foo() { $0 }", - kind: Function, - lookup: "foo", - }, - ] - "###); - } -} \ No newline at end of file diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs new file mode 100644 index 000000000..3bec57426 --- /dev/null +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -0,0 +1,80 @@ + +use crate::completion::{CompletionContext, Completions}; + +use hir::{ self, db::HirDatabase, HasSource }; + +use ra_syntax::{ ast, ast::AstNode }; + +pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { + let impl_trait = ast::ItemList::cast(ctx.token.parent()) + .and_then(|item_list| item_list.syntax().parent()) + .and_then(|item_list_parent| ast::ImplBlock::cast(item_list_parent)) + .and_then(|impl_block| resolve_target_trait(ctx.db, &ctx.analyzer, &impl_block)); + + if let Some(x) = &impl_trait { + for trait_item in x.0.items(ctx.db) { + match trait_item { + hir::AssocItem::Function(f) => acc.add_function_impl(ctx, f), + _ => {} + } + } + } +} + +fn resolve_target_trait( + db: &impl HirDatabase, + analyzer: &hir::SourceAnalyzer, + impl_block: &ast::ImplBlock +) -> Option<(hir::Trait, ast::TraitDef)> { + let ast_path = impl_block + .target_trait() + .map(|it| it.syntax().clone()) + .and_then(ast::PathType::cast)? + .path()?; + + match analyzer.resolve_path(db, &ast_path) { + Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => { + Some((def, def.source(db).value)) + } + _ => None, + } +} + +#[cfg(test)] +mod tests { + use crate::completion::{do_completion, CompletionItem, CompletionKind}; + use insta::assert_debug_snapshot; + + fn complete(code: &str) -> Vec { + do_completion(code, CompletionKind::Reference) + } + + #[test] + fn single_function() { + let completions = complete( + r" + trait Test { + fn foo(); + } + + struct T1; + + impl Test for T1 { + <|> + } + ", + ); + assert_debug_snapshot!(completions, @r###" + [ + CompletionItem { + label: "fn foo()", + source_range: [138; 138), + delete: [138; 138), + insert: "fn foo() { $0 }", + kind: Function, + lookup: "foo", + }, + ] + "###); + } +} \ No newline at end of file -- cgit v1.2.3 From 698ff91c1309b189ca0f08e3d62d219305ae5f46 Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Tue, 28 Jan 2020 20:30:53 -0600 Subject: Already implemented fn will no longer be suggested for trait implementations. --- .../ra_ide/src/completion/complete_trait_impl.rs | 144 ++++++++++++++++++--- crates/ra_ide/src/completion/presentation.rs | 4 +- 2 files changed, 131 insertions(+), 17 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index 3bec57426..52ad7dd9d 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -1,22 +1,104 @@ - use crate::completion::{CompletionContext, Completions}; -use hir::{ self, db::HirDatabase, HasSource }; +use ast::{ NameOwner }; +use hir::{ self, db::HirDatabase }; use ra_syntax::{ ast, ast::AstNode }; pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { - let impl_trait = ast::ItemList::cast(ctx.token.parent()) - .and_then(|item_list| item_list.syntax().parent()) - .and_then(|item_list_parent| ast::ImplBlock::cast(item_list_parent)) - .and_then(|impl_block| resolve_target_trait(ctx.db, &ctx.analyzer, &impl_block)); - - if let Some(x) = &impl_trait { - for trait_item in x.0.items(ctx.db) { - match trait_item { - hir::AssocItem::Function(f) => acc.add_function_impl(ctx, f), - _ => {} + let item_list = ast::ItemList::cast(ctx.token.parent()); + let impl_block = item_list + .clone() + .and_then(|i| i.syntax().parent()) + .and_then(|p| ast::ImplBlock::cast(p)); + + if item_list.is_none() || impl_block.is_none() { + return; + } + + let item_list = item_list.unwrap(); + let impl_block = impl_block.unwrap(); + + let target_trait = resolve_target_trait(ctx.db, &ctx.analyzer, &impl_block); + if target_trait.is_none() { + return; + } + + let trait_ = target_trait.unwrap(); + + let trait_items = trait_.items(ctx.db); + let missing_items = trait_items + .iter() + .filter(|i| { + match i { + hir::AssocItem::Function(f) => { + let f_name = f.name(ctx.db).to_string(); + + item_list + .impl_items() + .find(|impl_item| { + match impl_item { + ast::ImplItem::FnDef(impl_f) => { + if let Some(n) = impl_f.name() { + f_name == n.syntax().to_string() + } else { + false + } + }, + _ => false + } + }).is_none() + }, + hir::AssocItem::Const(c) => { + let c_name = c.name(ctx.db) + .map(|f| f.to_string()); + + if c_name.is_none() { + return false; + } + + let c_name = c_name.unwrap(); + + item_list + .impl_items() + .find(|impl_item| { + match impl_item { + ast::ImplItem::ConstDef(c) => { + if let Some(n) = c.name() { + c_name == n.syntax().to_string() + } else { + false + } + }, + _ => false + } + }).is_none() + }, + hir::AssocItem::TypeAlias(t) => { + let t_name = t.name(ctx.db).to_string(); + + item_list + .impl_items() + .find(|impl_item| { + match impl_item { + ast::ImplItem::TypeAliasDef(t) => { + if let Some(n) = t.name() { + t_name == n.syntax().to_string() + } else { + false + } + }, + _ => false + } + }).is_none() + } } + }); + + for item in missing_items { + match item { + hir::AssocItem::Function(f) => acc.add_function_impl(ctx, f), + _ => {} } } } @@ -25,7 +107,7 @@ fn resolve_target_trait( db: &impl HirDatabase, analyzer: &hir::SourceAnalyzer, impl_block: &ast::ImplBlock -) -> Option<(hir::Trait, ast::TraitDef)> { +) -> Option { let ast_path = impl_block .target_trait() .map(|it| it.syntax().clone()) @@ -34,7 +116,7 @@ fn resolve_target_trait( match analyzer.resolve_path(db, &ast_path) { Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => { - Some((def, def.source(db).value)) + Some(def) } _ => None, } @@ -70,11 +152,43 @@ mod tests { label: "fn foo()", source_range: [138; 138), delete: [138; 138), - insert: "fn foo() { $0 }", + insert: "fn foo() { $0}", kind: Function, lookup: "foo", }, ] "###); } + + #[test] + fn hide_implemented_fn() { + let completions = complete( + r" + trait Test { + fn foo(); + fn bar(); + } + + struct T1; + + impl Test for T1 { + fn foo() {} + + <|> + } + ", + ); + assert_debug_snapshot!(completions, @r###" + [ + CompletionItem { + label: "fn bar()", + source_range: [193; 193), + delete: [193; 193), + insert: "fn bar() { $0}", + kind: Function, + lookup: "bar", + }, + ] + "###); + } } \ No newline at end of file diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index d0a43261f..0689013ba 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs @@ -129,7 +129,7 @@ impl Completions { self.add_function_with_name(ctx, None, func) } - pub(crate) fn add_function_impl(&mut self, ctx: &CompletionContext, func: hir::Function) { + pub(crate) fn add_function_impl(&mut self, ctx: &CompletionContext, func: &hir::Function) { use crate::display::FunctionSignature; let display = FunctionSignature::from_hir(ctx.db, func.clone()); @@ -150,7 +150,7 @@ impl Completions { let snippet = { let mut s = format!("{}", display); - s.push_str(" { $0 }"); + s.push_str(" { $0}"); s }; -- cgit v1.2.3 From fc46ed81ee54d342d83e428ca74cbb0083547251 Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Tue, 4 Feb 2020 22:04:57 -0600 Subject: Add detection for a user already starting a fn impl and still providing completion. --- .../ra_ide/src/completion/complete_trait_impl.rs | 162 ++++++++++++++++++++- crates/ra_ide/src/completion/presentation.rs | 33 ----- 2 files changed, 157 insertions(+), 38 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index 52ad7dd9d..c94ebee82 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -1,9 +1,9 @@ -use crate::completion::{CompletionContext, Completions}; +use crate::completion::{CompletionContext, Completions, CompletionItem, CompletionKind, CompletionItemKind}; use ast::{ NameOwner }; use hir::{ self, db::HirDatabase }; -use ra_syntax::{ ast, ast::AstNode }; +use ra_syntax::{ SyntaxKind, ast, ast::AstNode, TextRange }; pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { let item_list = ast::ItemList::cast(ctx.token.parent()); @@ -24,6 +24,37 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext return; } + // for cases where the user has already started writing the function def, navigate + // the previous tokens in order to find the location of that token so that we may + // replace it with our completion. + let start_position = { + let mut prev_token = ctx.token + .prev_token() + .clone(); + + while let Some(token) = &prev_token { + match token.kind() { + SyntaxKind::FN_KW => break, + + // todo: attempt to find a better way of determining when to stop as + // the following feels sketchy. + SyntaxKind::IMPL_KW | + SyntaxKind::L_CURLY | + SyntaxKind::R_CURLY => { + prev_token = None; + break; + } + _ => {} + } + + prev_token = token.prev_token().clone(); + } + + prev_token + .map(|t| t.text_range()) + .unwrap_or(ctx.source_range()) + }; + let trait_ = target_trait.unwrap(); let trait_items = trait_.items(ctx.db); @@ -97,7 +128,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext for item in missing_items { match item { - hir::AssocItem::Function(f) => acc.add_function_impl(ctx, f), + hir::AssocItem::Function(f) => add_function_impl(acc, ctx, f, start_position), _ => {} } } @@ -122,6 +153,40 @@ fn resolve_target_trait( } } +pub(crate) fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, func: &hir::Function, start: TextRange) { + use crate::display::FunctionSignature; + + let display = FunctionSignature::from_hir(ctx.db, func.clone()); + + let func_name = func.name(ctx.db); + + let label = if func.params(ctx.db).len() > 0 { + format!("fn {}(..)", func_name.to_string()) + } else { + format!("fn {}()", func_name.to_string()) + }; + + let builder = CompletionItem::new(CompletionKind::Reference, start, label); + + let completion_kind = if func.has_self_param(ctx.db) { + CompletionItemKind::Method + } else { + CompletionItemKind::Function + }; + + let snippet = { + let mut s = format!("{}", display); + s.push_str(" {}"); + s + }; + + builder + .insert_text(snippet) + .kind(completion_kind) + .lookup_by(func_name.to_string()) + .add_to(acc); +} + #[cfg(test)] mod tests { use crate::completion::{do_completion, CompletionItem, CompletionKind}; @@ -152,7 +217,7 @@ mod tests { label: "fn foo()", source_range: [138; 138), delete: [138; 138), - insert: "fn foo() { $0}", + insert: "fn foo() {}", kind: Function, lookup: "foo", }, @@ -184,11 +249,98 @@ mod tests { label: "fn bar()", source_range: [193; 193), delete: [193; 193), - insert: "fn bar() { $0}", + insert: "fn bar() {}", kind: Function, lookup: "bar", }, ] "###); } + + #[test] + fn generic_fn() { + let completions = complete( + r" + trait Test { + fn foo(); + } + + struct T1; + + impl Test for T1 { + <|> + } + ", + ); + assert_debug_snapshot!(completions, @r###" + [ + CompletionItem { + label: "fn foo()", + source_range: [141; 141), + delete: [141; 141), + insert: "fn foo() {}", + kind: Function, + lookup: "foo", + }, + ] + "###); + } + + #[test] + fn generic_constrait_fn() { + let completions = complete( + r" + trait Test { + fn foo() where T: Into; + } + + struct T1; + + impl Test for T1 { + <|> + } + ", + ); + assert_debug_snapshot!(completions, @r###" + [ + CompletionItem { + label: "fn foo()", + source_range: [163; 163), + delete: [163; 163), + insert: "fn foo()\nwhere T: Into {}", + kind: Function, + lookup: "foo", + }, + ] + "###); + } + + #[test] + fn start_from_fn_kw() { + let completions = complete( + r" + trait Test { + fn foo(); + } + + struct T1; + + impl Test for T1 { + fn <|> + } + ", + ); + assert_debug_snapshot!(completions, @r###" + [ + CompletionItem { + label: "fn foo()", + source_range: [138; 140), + delete: [138; 140), + insert: "fn foo() {}", + kind: Function, + lookup: "foo", + }, + ] + "###); + } } \ No newline at end of file diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 0689013ba..97475fc0b 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs @@ -129,39 +129,6 @@ impl Completions { self.add_function_with_name(ctx, None, func) } - pub(crate) fn add_function_impl(&mut self, ctx: &CompletionContext, func: &hir::Function) { - use crate::display::FunctionSignature; - - let display = FunctionSignature::from_hir(ctx.db, func.clone()); - - let func_name = func.name(ctx.db); - - let mut builder = CompletionItem::new( - CompletionKind::Reference, - ctx.source_range(), - format!("fn {}()", func_name.to_string())) - .set_documentation(func.docs(ctx.db)); - - let completion_kind = if func.has_self_param(ctx.db) { - CompletionItemKind::Method - } else { - CompletionItemKind::Function - }; - - let snippet = { - let mut s = format!("{}", display); - s.push_str(" { $0}"); - s - }; - - builder = builder - .insert_text(snippet) - .kind(completion_kind) - .lookup_by(func_name.to_string()); - - self.add(builder.build()); - } - fn guess_macro_braces(&self, macro_name: &str, docs: &str) -> &'static str { let mut votes = [0, 0, 0]; for (idx, s) in docs.match_indices(¯o_name) { -- cgit v1.2.3 From 5216b09ed67b4d9ff57e3ffb7fec010e73832309 Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Fri, 7 Feb 2020 21:02:01 -0600 Subject: Update completion kind to Magic in the unit tests. --- crates/ra_ide/src/completion/complete_trait_impl.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index c94ebee82..8f38c6325 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -166,7 +166,7 @@ pub(crate) fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, format!("fn {}()", func_name.to_string()) }; - let builder = CompletionItem::new(CompletionKind::Reference, start, label); + let builder = CompletionItem::new(CompletionKind::Magic, start, label); let completion_kind = if func.has_self_param(ctx.db) { CompletionItemKind::Method @@ -193,7 +193,7 @@ mod tests { use insta::assert_debug_snapshot; fn complete(code: &str) -> Vec { - do_completion(code, CompletionKind::Reference) + do_completion(code, CompletionKind::Magic) } #[test] -- cgit v1.2.3 From f801723dd2e4a518c1608909509f47f03d75fe1a Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Sat, 8 Feb 2020 11:28:39 -0600 Subject: Got the magic completion working. --- .../ra_ide/src/completion/complete_trait_impl.rs | 48 ++++------------------ crates/ra_ide/src/completion/completion_context.rs | 9 ++++ 2 files changed, 16 insertions(+), 41 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index 8f38c6325..7af485cdd 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -6,13 +6,12 @@ use hir::{ self, db::HirDatabase }; use ra_syntax::{ SyntaxKind, ast, ast::AstNode, TextRange }; pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { - let item_list = ast::ItemList::cast(ctx.token.parent()); - let impl_block = item_list - .clone() - .and_then(|i| i.syntax().parent()) - .and_then(|p| ast::ImplBlock::cast(p)); + let impl_block = ctx.impl_block.as_ref(); + let item_list = impl_block.and_then(|i| i.item_list()); - if item_list.is_none() || impl_block.is_none() { + if item_list.is_none() + || impl_block.is_none() + || ctx.function_syntax.is_some() { return; } @@ -166,7 +165,8 @@ pub(crate) fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, format!("fn {}()", func_name.to_string()) }; - let builder = CompletionItem::new(CompletionKind::Magic, start, label); + let builder = CompletionItem::new(CompletionKind::Magic, start, label.clone()) + .lookup_by(label); let completion_kind = if func.has_self_param(ctx.db) { CompletionItemKind::Method @@ -183,7 +183,6 @@ pub(crate) fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, builder .insert_text(snippet) .kind(completion_kind) - .lookup_by(func_name.to_string()) .add_to(acc); } @@ -219,7 +218,6 @@ mod tests { delete: [138; 138), insert: "fn foo() {}", kind: Function, - lookup: "foo", }, ] "###); @@ -251,7 +249,6 @@ mod tests { delete: [193; 193), insert: "fn bar() {}", kind: Function, - lookup: "bar", }, ] "###); @@ -280,7 +277,6 @@ mod tests { delete: [141; 141), insert: "fn foo() {}", kind: Function, - lookup: "foo", }, ] "###); @@ -309,36 +305,6 @@ mod tests { delete: [163; 163), insert: "fn foo()\nwhere T: Into {}", kind: Function, - lookup: "foo", - }, - ] - "###); - } - - #[test] - fn start_from_fn_kw() { - let completions = complete( - r" - trait Test { - fn foo(); - } - - struct T1; - - impl Test for T1 { - fn <|> - } - ", - ); - assert_debug_snapshot!(completions, @r###" - [ - CompletionItem { - label: "fn foo()", - source_range: [138; 140), - delete: [138; 140), - insert: "fn foo() {}", - kind: Function, - lookup: "foo", }, ] "###); diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index deaacda6c..18c91a840 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs @@ -24,6 +24,7 @@ pub(crate) struct CompletionContext<'a> { pub(super) use_item_syntax: Option, pub(super) record_lit_syntax: Option, pub(super) record_lit_pat: Option, + pub(super) impl_block: Option, pub(super) is_param: bool, /// If a name-binding or reference to a const in a pattern. /// Irrefutable patterns (like let) are excluded. @@ -71,6 +72,7 @@ impl<'a> CompletionContext<'a> { use_item_syntax: None, record_lit_syntax: None, record_lit_pat: None, + impl_block: None, is_param: false, is_pat_binding: false, is_trivial_path: false, @@ -147,6 +149,13 @@ impl<'a> CompletionContext<'a> { self.record_lit_syntax = find_node_at_offset(original_file.syntax(), self.offset); } + self.impl_block = self + .token + .parent() + .ancestors() + .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) + .find_map(ast::ImplBlock::cast); + let top_node = name_ref .syntax() .ancestors() -- cgit v1.2.3 From 5c0c18926b13d40cff722f603ed8f58550dbbc59 Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Sat, 8 Feb 2020 13:22:31 -0600 Subject: Cleaning up unessicary code that the Magic completion takes care of. --- .../ra_ide/src/completion/complete_trait_impl.rs | 47 ++++------------------ 1 file changed, 8 insertions(+), 39 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index 7af485cdd..d147bd11d 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -1,9 +1,9 @@ use crate::completion::{CompletionContext, Completions, CompletionItem, CompletionKind, CompletionItemKind}; -use ast::{ NameOwner }; -use hir::{ self, db::HirDatabase }; +use ra_syntax::ast::{self, NameOwner, AstNode}; + +use hir::{self, db::HirDatabase}; -use ra_syntax::{ SyntaxKind, ast, ast::AstNode, TextRange }; pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { let impl_block = ctx.impl_block.as_ref(); @@ -23,40 +23,9 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext return; } - // for cases where the user has already started writing the function def, navigate - // the previous tokens in order to find the location of that token so that we may - // replace it with our completion. - let start_position = { - let mut prev_token = ctx.token - .prev_token() - .clone(); - - while let Some(token) = &prev_token { - match token.kind() { - SyntaxKind::FN_KW => break, - - // todo: attempt to find a better way of determining when to stop as - // the following feels sketchy. - SyntaxKind::IMPL_KW | - SyntaxKind::L_CURLY | - SyntaxKind::R_CURLY => { - prev_token = None; - break; - } - _ => {} - } - - prev_token = token.prev_token().clone(); - } - - prev_token - .map(|t| t.text_range()) - .unwrap_or(ctx.source_range()) - }; - - let trait_ = target_trait.unwrap(); + let target_trait = target_trait.unwrap(); - let trait_items = trait_.items(ctx.db); + let trait_items = target_trait.items(ctx.db); let missing_items = trait_items .iter() .filter(|i| { @@ -127,7 +96,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext for item in missing_items { match item { - hir::AssocItem::Function(f) => add_function_impl(acc, ctx, f, start_position), + hir::AssocItem::Function(f) => add_function_impl(acc, ctx, f), _ => {} } } @@ -152,7 +121,7 @@ fn resolve_target_trait( } } -pub(crate) fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, func: &hir::Function, start: TextRange) { +pub(crate) fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, func: &hir::Function) { use crate::display::FunctionSignature; let display = FunctionSignature::from_hir(ctx.db, func.clone()); @@ -165,7 +134,7 @@ pub(crate) fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, format!("fn {}()", func_name.to_string()) }; - let builder = CompletionItem::new(CompletionKind::Magic, start, label.clone()) + let builder = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label.clone()) .lookup_by(label); let completion_kind = if func.has_self_param(ctx.db) { -- cgit v1.2.3 From 22caf982b99c54058e2e9200aeea0e61cada284a Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Sat, 8 Feb 2020 15:41:25 -0600 Subject: Added associated type completion. --- crates/ra_ide/src/completion/complete_trait_impl.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index d147bd11d..528655fbc 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -97,7 +97,8 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext for item in missing_items { match item { hir::AssocItem::Function(f) => add_function_impl(acc, ctx, f), - _ => {} + hir::AssocItem::TypeAlias(t) => add_type_alias_impl(acc, ctx, t), + _ => {}, } } } @@ -121,7 +122,7 @@ fn resolve_target_trait( } } -pub(crate) fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, func: &hir::Function) { +fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, func: &hir::Function) { use crate::display::FunctionSignature; let display = FunctionSignature::from_hir(ctx.db, func.clone()); @@ -135,7 +136,8 @@ pub(crate) fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, }; let builder = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label.clone()) - .lookup_by(label); + .lookup_by(label) + .set_documentation(func.docs(ctx.db)); let completion_kind = if func.has_self_param(ctx.db) { CompletionItemKind::Method @@ -155,6 +157,16 @@ pub(crate) fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, .add_to(acc); } +fn add_type_alias_impl(acc: &mut Completions, ctx: &CompletionContext, type_alias: &hir::TypeAlias) { + let snippet = format!("type {} = ", type_alias.name(ctx.db).to_string()); + + CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) + .insert_text(snippet) + .kind(CompletionItemKind::TypeAlias) + .set_documentation(type_alias.docs(ctx.db)) + .add_to(acc); +} + #[cfg(test)] mod tests { use crate::completion::{do_completion, CompletionItem, CompletionKind}; -- cgit v1.2.3 From d85abd77b98ff5925621c18f2ffe121640d17c80 Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Sun, 9 Feb 2020 12:24:34 -0600 Subject: Added a utility function that can be used to determine the missing impl items. --- crates/ra_ide/src/completion.rs | 2 +- .../ra_ide/src/completion/complete_trait_impl.rs | 132 +++------------------ 2 files changed, 19 insertions(+), 115 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs index 4f24cd1f9..4bdc6ba23 100644 --- a/crates/ra_ide/src/completion.rs +++ b/crates/ra_ide/src/completion.rs @@ -76,6 +76,6 @@ pub(crate) fn completions(db: &RootDatabase, position: FilePosition) -> Option { - let f_name = f.name(ctx.db).to_string(); - - item_list - .impl_items() - .find(|impl_item| { - match impl_item { - ast::ImplItem::FnDef(impl_f) => { - if let Some(n) = impl_f.name() { - f_name == n.syntax().to_string() - } else { - false - } - }, - _ => false - } - }).is_none() - }, - hir::AssocItem::Const(c) => { - let c_name = c.name(ctx.db) - .map(|f| f.to_string()); - - if c_name.is_none() { - return false; - } - - let c_name = c_name.unwrap(); - - item_list - .impl_items() - .find(|impl_item| { - match impl_item { - ast::ImplItem::ConstDef(c) => { - if let Some(n) = c.name() { - c_name == n.syntax().to_string() - } else { - false - } - }, - _ => false - } - }).is_none() - }, - hir::AssocItem::TypeAlias(t) => { - let t_name = t.name(ctx.db).to_string(); - - item_list - .impl_items() - .find(|impl_item| { - match impl_item { - ast::ImplItem::TypeAliasDef(t) => { - if let Some(n) = t.name() { - t_name == n.syntax().to_string() - } else { - false - } - }, - _ => false - } - }).is_none() - } - } - }); - - for item in missing_items { + for item in get_missing_impl_items(ctx.db, &ctx.analyzer, impl_block) { match item { - hir::AssocItem::Function(f) => add_function_impl(acc, ctx, f), - hir::AssocItem::TypeAlias(t) => add_type_alias_impl(acc, ctx, t), - _ => {}, - } - } -} - -fn resolve_target_trait( - db: &impl HirDatabase, - analyzer: &hir::SourceAnalyzer, - impl_block: &ast::ImplBlock -) -> Option { - let ast_path = impl_block - .target_trait() - .map(|it| it.syntax().clone()) - .and_then(ast::PathType::cast)? - .path()?; - - match analyzer.resolve_path(db, &ast_path) { - Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => { - Some(def) + hir::AssocItem::Function(f) => add_function_impl(acc, ctx, &f), + hir::AssocItem::TypeAlias(t) => add_type_alias_impl(acc, ctx, &t), + _ => {} } - _ => None, } } @@ -144,20 +47,21 @@ fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, func: &hir: } else { CompletionItemKind::Function }; - + let snippet = { let mut s = format!("{}", display); s.push_str(" {}"); s }; - builder - .insert_text(snippet) - .kind(completion_kind) - .add_to(acc); + builder.insert_text(snippet).kind(completion_kind).add_to(acc); } -fn add_type_alias_impl(acc: &mut Completions, ctx: &CompletionContext, type_alias: &hir::TypeAlias) { +fn add_type_alias_impl( + acc: &mut Completions, + ctx: &CompletionContext, + type_alias: &hir::TypeAlias, +) { let snippet = format!("type {} = ", type_alias.name(ctx.db).to_string()); CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) @@ -290,4 +194,4 @@ mod tests { ] "###); } -} \ No newline at end of file +} -- cgit v1.2.3 From 3ffc84fd156d9474d7b2bd491da9eec431bc7ff2 Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Sun, 9 Feb 2020 20:59:12 -0600 Subject: Added associated const magic completion. --- .../ra_ide/src/completion/complete_trait_impl.rs | 64 ++++++++++++++++++---- 1 file changed, 53 insertions(+), 11 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index e2854ee97..cb15da647 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -2,25 +2,26 @@ use crate::completion::{ CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, }; -use hir::{self, Docs}; +use ra_syntax::{ast::{self, edit}, AstNode, SyntaxKind, TextRange}; +use hir::{self, Docs, HasSource}; use ra_assists::utils::get_missing_impl_items; pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { - let impl_block = ctx.impl_block.as_ref(); - let item_list = impl_block.and_then(|i| i.item_list()); - if item_list.is_none() || impl_block.is_none() || ctx.function_syntax.is_some() { + // it is possible to have a parent `fn` and `impl` block. Ignore completion + // attempts from within a `fn` block. + if ctx.function_syntax.is_some() { return; } - let impl_block = impl_block.unwrap(); - - for item in get_missing_impl_items(ctx.db, &ctx.analyzer, impl_block) { - match item { - hir::AssocItem::Function(f) => add_function_impl(acc, ctx, &f), - hir::AssocItem::TypeAlias(t) => add_type_alias_impl(acc, ctx, &t), - _ => {} + if let Some(ref impl_block) = ctx.impl_block { + for item in get_missing_impl_items(ctx.db, &ctx.analyzer, impl_block) { + match item { + hir::AssocItem::Function(f) => add_function_impl(acc, ctx, &f), + hir::AssocItem::TypeAlias(t) => add_type_alias_impl(acc, ctx, &t), + hir::AssocItem::Const(c) => add_const_impl(acc, ctx, &c), + } } } } @@ -71,6 +72,47 @@ fn add_type_alias_impl( .add_to(acc); } +fn add_const_impl( + acc: &mut Completions, + ctx: &CompletionContext, + const_: &hir::Const, +) { + let snippet = make_const_compl_syntax(&const_.source(ctx.db).value); + + CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) + .insert_text(snippet) + .kind(CompletionItemKind::Const) + .set_documentation(const_.docs(ctx.db)) + .add_to(acc); +} + +fn make_const_compl_syntax(const_: &ast::ConstDef) -> String { + let const_ = edit::strip_attrs_and_docs(const_); + + let const_start = const_.syntax().text_range().start(); + let const_end = const_.syntax().text_range().end(); + + let start = const_ + .syntax() + .first_child_or_token() + .map_or( + const_start, + |f| f.text_range().start()); + + let end = const_ + .syntax() + .children_with_tokens() + .find(|s| s.kind() == SyntaxKind::SEMI || s.kind() == SyntaxKind::EQ) + .map_or(const_end, |f| f.text_range().start()); + + let len = end - start; + let range = TextRange::from_to(0.into(), len); + + let syntax = const_.syntax().text().slice(range).to_string(); + + format!("{} = ", syntax.trim_end()) +} + #[cfg(test)] mod tests { use crate::completion::{do_completion, CompletionItem, CompletionKind}; -- cgit v1.2.3 From 52c4324e31361d062ff111835abaec2c4eff0db4 Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Mon, 10 Feb 2020 20:55:49 -0600 Subject: Added some documentation to the `complete_trait_impl` completion. --- .../ra_ide/src/completion/complete_trait_impl.rs | 49 +++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index cb15da647..eb12b7d28 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -7,6 +7,45 @@ use hir::{self, Docs, HasSource}; use ra_assists::utils::get_missing_impl_items; +/// Analyzes the specified `CompletionContext` and provides magic completions +/// if the context falls within a `impl Trait for` block. +/// +/// # Completion Activation +/// The completion will activate when a user begins to type a function +/// definition, an associated type, or an associated constant. +/// +/// ### Functions +/// ```ignore +/// trait SomeTrait { +/// fn foo(&self); +/// } +/// +/// impl SomeTrait for () { +/// fn <|> +/// } +/// ``` +/// +/// ### Associated Types +/// ```ignore +/// trait SomeTrait { +/// type SomeType; +/// } +/// +/// impl SomeTrait for () { +/// type <|> +/// } +/// ``` +/// +/// ### Associated Constants +/// ```ignore +/// trait SomeTrait { +/// const SOME_CONST: u16; +/// } +/// +/// impl SomeTrait for () { +/// const <|> +/// } +/// ``` pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { // it is possible to have a parent `fn` and `impl` block. Ignore completion @@ -86,9 +125,17 @@ fn add_const_impl( .add_to(acc); } +/// Using a `ConstDef` `SyntaxNode` to create a `String` that represents +/// the output of the magic completion. +/// +/// There isn't a whole lot of information about a `hir::Const` or +/// `ast::ConstDef` to prove useful when creating the magic completion for the +/// associated constant. This method simply copies the syntax tree of the +/// target trait up until a `;` or `=` is found. From the sliced syntax tree +/// it formulates the magic completion string. fn make_const_compl_syntax(const_: &ast::ConstDef) -> String { let const_ = edit::strip_attrs_and_docs(const_); - + let const_start = const_.syntax().text_range().start(); let const_end = const_.syntax().text_range().end(); -- cgit v1.2.3 From 785723e0d942bba935fb2de6fb451d57a2c06b1a Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Mon, 10 Feb 2020 21:02:51 -0600 Subject: Added tests to test associated types and consts. --- .../ra_ide/src/completion/complete_trait_impl.rs | 78 ++++++++++++++++++++++ 1 file changed, 78 insertions(+) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index eb12b7d28..c0e83b124 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -283,4 +283,82 @@ mod tests { ] "###); } + + #[test] + fn associated_type() { + let completions = complete( + r" + trait Test { + type SomeType; + } + + impl Test for () { + <|> + } + ", + ); + assert_debug_snapshot!(completions, @r###" + [ + CompletionItem { + label: "type SomeType = ", + source_range: [119; 119), + delete: [119; 119), + insert: "type SomeType = ", + kind: TypeAlias, + }, + ] + "###); + } + + #[test] + fn associated_const() { + let completions = complete( + r" + trait Test { + const SOME_CONST: u16; + } + + impl Test for () { + <|> + } + ", + ); + assert_debug_snapshot!(completions, @r###" + [ + CompletionItem { + label: "const SOME_CONST: u16 = ", + source_range: [127; 127), + delete: [127; 127), + insert: "const SOME_CONST: u16 = ", + kind: Const, + }, + ] + "###); + } + + #[test] + fn associated_const_with_default() { + let completions = complete( + r" + trait Test { + const SOME_CONST: u16 = 42; + } + + impl Test for () { + <|> + } + ", + ); + assert_debug_snapshot!(completions, @r###" + [ + CompletionItem { + label: "const SOME_CONST: u16 = ", + source_range: [132; 132), + delete: [132; 132), + insert: "const SOME_CONST: u16 = ", + kind: Const, + }, + ] + "###); + } } -- cgit v1.2.3 From d7e36c3dd2b601401feb86bef3c0f8bb62fb4331 Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Tue, 11 Feb 2020 07:31:39 -0600 Subject: Removed docs from private method. --- crates/ra_ide/src/completion/complete_trait_impl.rs | 8 -------- 1 file changed, 8 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index c0e83b124..f6f4a99c5 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -125,14 +125,6 @@ fn add_const_impl( .add_to(acc); } -/// Using a `ConstDef` `SyntaxNode` to create a `String` that represents -/// the output of the magic completion. -/// -/// There isn't a whole lot of information about a `hir::Const` or -/// `ast::ConstDef` to prove useful when creating the magic completion for the -/// associated constant. This method simply copies the syntax tree of the -/// target trait up until a `;` or `=` is found. From the sliced syntax tree -/// it formulates the magic completion string. fn make_const_compl_syntax(const_: &ast::ConstDef) -> String { let const_ = edit::strip_attrs_and_docs(const_); -- cgit v1.2.3 From 3aaf46afa13b6fcbfdc36d8eb0cce48196d824a7 Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Tue, 11 Feb 2020 09:40:08 -0600 Subject: Formatted changes. --- .../ra_ide/src/completion/complete_trait_impl.rs | 38 +++++++++------------- 1 file changed, 16 insertions(+), 22 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index f6f4a99c5..cd3f016bf 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -2,53 +2,55 @@ use crate::completion::{ CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, }; -use ra_syntax::{ast::{self, edit}, AstNode, SyntaxKind, TextRange}; use hir::{self, Docs, HasSource}; +use ra_syntax::{ + ast::{self, edit}, + AstNode, SyntaxKind, TextRange, +}; use ra_assists::utils::get_missing_impl_items; /// Analyzes the specified `CompletionContext` and provides magic completions /// if the context falls within a `impl Trait for` block. -/// +/// /// # Completion Activation -/// The completion will activate when a user begins to type a function +/// The completion will activate when a user begins to type a function /// definition, an associated type, or an associated constant. -/// +/// /// ### Functions /// ```ignore /// trait SomeTrait { /// fn foo(&self); /// } -/// +/// /// impl SomeTrait for () { /// fn <|> /// } /// ``` -/// +/// /// ### Associated Types /// ```ignore /// trait SomeTrait { /// type SomeType; /// } -/// +/// /// impl SomeTrait for () { /// type <|> /// } /// ``` -/// +/// /// ### Associated Constants /// ```ignore /// trait SomeTrait { /// const SOME_CONST: u16; /// } -/// +/// /// impl SomeTrait for () { /// const <|> /// } /// ``` pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { - - // it is possible to have a parent `fn` and `impl` block. Ignore completion + // it is possible to have a parent `fn` and `impl` block. Ignore completion // attempts from within a `fn` block. if ctx.function_syntax.is_some() { return; @@ -111,11 +113,7 @@ fn add_type_alias_impl( .add_to(acc); } -fn add_const_impl( - acc: &mut Completions, - ctx: &CompletionContext, - const_: &hir::Const, -) { +fn add_const_impl(acc: &mut Completions, ctx: &CompletionContext, const_: &hir::Const) { let snippet = make_const_compl_syntax(&const_.source(ctx.db).value); CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) @@ -131,12 +129,8 @@ fn make_const_compl_syntax(const_: &ast::ConstDef) -> String { let const_start = const_.syntax().text_range().start(); let const_end = const_.syntax().text_range().end(); - let start = const_ - .syntax() - .first_child_or_token() - .map_or( - const_start, - |f| f.text_range().start()); + let start = + const_.syntax().first_child_or_token().map_or(const_start, |f| f.text_range().start()); let end = const_ .syntax() -- cgit v1.2.3 From e664cd73e3f91086dc765fb5ec74ebec2daa8ffa Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Tue, 11 Feb 2020 09:48:26 -0600 Subject: Removed doc comments entirely from the changes. --- .../ra_ide/src/completion/complete_trait_impl.rs | 39 ---------------------- 1 file changed, 39 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index cd3f016bf..bea3ce106 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -10,45 +10,6 @@ use ra_syntax::{ use ra_assists::utils::get_missing_impl_items; -/// Analyzes the specified `CompletionContext` and provides magic completions -/// if the context falls within a `impl Trait for` block. -/// -/// # Completion Activation -/// The completion will activate when a user begins to type a function -/// definition, an associated type, or an associated constant. -/// -/// ### Functions -/// ```ignore -/// trait SomeTrait { -/// fn foo(&self); -/// } -/// -/// impl SomeTrait for () { -/// fn <|> -/// } -/// ``` -/// -/// ### Associated Types -/// ```ignore -/// trait SomeTrait { -/// type SomeType; -/// } -/// -/// impl SomeTrait for () { -/// type <|> -/// } -/// ``` -/// -/// ### Associated Constants -/// ```ignore -/// trait SomeTrait { -/// const SOME_CONST: u16; -/// } -/// -/// impl SomeTrait for () { -/// const <|> -/// } -/// ``` pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { // it is possible to have a parent `fn` and `impl` block. Ignore completion // attempts from within a `fn` block. -- cgit v1.2.3 From 47d314e85681c075ff859e13343927e7406e1b46 Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Tue, 11 Feb 2020 10:04:30 -0600 Subject: Fixing minor suggestions and added module level documentation. --- crates/ra_ide/src/completion/complete_trait_impl.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index bea3ce106..f2661b623 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -1,5 +1,8 @@ -use crate::completion::{ - CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, +//! FIXME: write short doc here + +use crate::{ + completion::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}, + display::FunctionSignature, }; use hir::{self, Docs, HasSource}; @@ -29,8 +32,6 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext } fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, func: &hir::Function) { - use crate::display::FunctionSignature; - let display = FunctionSignature::from_hir(ctx.db, func.clone()); let func_name = func.name(ctx.db); @@ -51,11 +52,7 @@ fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, func: &hir: CompletionItemKind::Function }; - let snippet = { - let mut s = format!("{}", display); - s.push_str(" {}"); - s - }; + let snippet = format!("{} {{}}", display); builder.insert_text(snippet).kind(completion_kind).add_to(acc); } -- cgit v1.2.3 From 6f130e7ef8fea374bbcfb2c9c60009f558ce3ecf Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Tue, 11 Feb 2020 10:07:23 -0600 Subject: Formatting. --- crates/ra_ide/src/completion/complete_trait_impl.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index f2661b623..c8f26c954 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -1,7 +1,9 @@ //! FIXME: write short doc here use crate::{ - completion::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}, + completion::{ + CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, + }, display::FunctionSignature, }; -- cgit v1.2.3 From 877cfbacf98d9d803aa5e0f54be560c7da7acbca Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Wed, 12 Feb 2020 20:21:43 -0600 Subject: Started to refactor the trigger of the trait_impl completion. --- .../ra_ide/src/completion/complete_trait_impl.rs | 110 ++++++++++++++------- 1 file changed, 77 insertions(+), 33 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index c8f26c954..b1017e57a 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -16,19 +16,63 @@ use ra_syntax::{ use ra_assists::utils::get_missing_impl_items; pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { - // it is possible to have a parent `fn` and `impl` block. Ignore completion - // attempts from within a `fn` block. - if ctx.function_syntax.is_some() { - return; - } + let trigger = ctx.token + .ancestors() + .find(|p| match p.kind() { + SyntaxKind::FN_DEF | + SyntaxKind::TYPE_ALIAS_DEF | + SyntaxKind::CONST_DEF | + SyntaxKind::ITEM_LIST => true, + _ => false + }); + + let impl_block = trigger + .as_ref() + .and_then(|node| node.parent()) + .and_then(|node| node.parent()) + .and_then(|node| ast::ImplBlock::cast(node)); + + if let (Some(trigger), Some(impl_block)) = (trigger, impl_block) { + match trigger.kind() { + SyntaxKind::FN_DEF => { + for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block) + .iter() + .filter_map(|item| { + match item { + hir::AssocItem::Function(fn_item) => Some(fn_item), + _ => None + } + }) + { + add_function_impl(acc, ctx, &missing_fn); + } + }, - if let Some(ref impl_block) = ctx.impl_block { - for item in get_missing_impl_items(ctx.db, &ctx.analyzer, impl_block) { - match item { - hir::AssocItem::Function(f) => add_function_impl(acc, ctx, &f), - hir::AssocItem::TypeAlias(t) => add_type_alias_impl(acc, ctx, &t), - hir::AssocItem::Const(c) => add_const_impl(acc, ctx, &c), - } + SyntaxKind::TYPE_ALIAS_DEF => { + for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block) + .iter() + .filter_map(|item| match item { + hir::AssocItem::TypeAlias(type_item) => Some(type_item), + _ => None + }) + { + add_type_alias_impl(acc, ctx, &missing_fn); + } + }, + + SyntaxKind::CONST_DEF => { + for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block) + .iter() + .filter_map(|item| match item { + hir::AssocItem::Const(const_item) => Some(const_item), + _ => None + }) + { + add_const_impl(acc, ctx, &missing_fn); + } + }, + + _ => {} } } } @@ -126,7 +170,7 @@ mod tests { struct T1; impl Test for T1 { - <|> + fn<|> } ", ); @@ -134,8 +178,8 @@ mod tests { [ CompletionItem { label: "fn foo()", - source_range: [138; 138), - delete: [138; 138), + source_range: [140; 140), + delete: [140; 140), insert: "fn foo() {}", kind: Function, }, @@ -157,7 +201,7 @@ mod tests { impl Test for T1 { fn foo() {} - <|> + fn<|> } ", ); @@ -165,8 +209,8 @@ mod tests { [ CompletionItem { label: "fn bar()", - source_range: [193; 193), - delete: [193; 193), + source_range: [195; 195), + delete: [195; 195), insert: "fn bar() {}", kind: Function, }, @@ -185,7 +229,7 @@ mod tests { struct T1; impl Test for T1 { - <|> + fn<|> } ", ); @@ -193,8 +237,8 @@ mod tests { [ CompletionItem { label: "fn foo()", - source_range: [141; 141), - delete: [141; 141), + source_range: [143; 143), + delete: [143; 143), insert: "fn foo() {}", kind: Function, }, @@ -213,7 +257,7 @@ mod tests { struct T1; impl Test for T1 { - <|> + fn<|> } ", ); @@ -221,8 +265,8 @@ mod tests { [ CompletionItem { label: "fn foo()", - source_range: [163; 163), - delete: [163; 163), + source_range: [165; 165), + delete: [165; 165), insert: "fn foo()\nwhere T: Into {}", kind: Function, }, @@ -239,7 +283,7 @@ mod tests { } impl Test for () { - <|> + type<|> } ", ); @@ -247,8 +291,8 @@ mod tests { [ CompletionItem { label: "type SomeType = ", - source_range: [119; 119), - delete: [119; 119), + source_range: [123; 123), + delete: [123; 123), insert: "type SomeType = ", kind: TypeAlias, }, @@ -265,7 +309,7 @@ mod tests { } impl Test for () { - <|> + const<|> } ", ); @@ -273,8 +317,8 @@ mod tests { [ CompletionItem { label: "const SOME_CONST: u16 = ", - source_range: [127; 127), - delete: [127; 127), + source_range: [132; 132), + delete: [132; 132), insert: "const SOME_CONST: u16 = ", kind: Const, }, @@ -291,7 +335,7 @@ mod tests { } impl Test for () { - <|> + const<|> } ", ); @@ -299,8 +343,8 @@ mod tests { [ CompletionItem { label: "const SOME_CONST: u16 = ", - source_range: [132; 132), - delete: [132; 132), + source_range: [137; 137), + delete: [137; 137), insert: "const SOME_CONST: u16 = ", kind: Const, }, -- cgit v1.2.3 From 43e62a87ab97f946f3d2da2db0aa0b1f0ef7d8bf Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Wed, 12 Feb 2020 20:46:12 -0600 Subject: Cheese const tests as they requre an ident before becoming a CONST_DEF. --- .../ra_ide/src/completion/complete_trait_impl.rs | 49 ++++++++++------------ 1 file changed, 21 insertions(+), 28 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index b1017e57a..912bf789e 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -16,15 +16,10 @@ use ra_syntax::{ use ra_assists::utils::get_missing_impl_items; pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { - let trigger = ctx.token - .ancestors() - .find(|p| match p.kind() { - SyntaxKind::FN_DEF | - SyntaxKind::TYPE_ALIAS_DEF | - SyntaxKind::CONST_DEF | - SyntaxKind::ITEM_LIST => true, - _ => false - }); + let trigger = ctx.token.ancestors().find(|p| match p.kind() { + SyntaxKind::FN_DEF | SyntaxKind::TYPE_ALIAS_DEF | SyntaxKind::CONST_DEF => true, + _ => false, + }); let impl_block = trigger .as_ref() @@ -37,40 +32,38 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext SyntaxKind::FN_DEF => { for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block) .iter() - .filter_map(|item| { - match item { - hir::AssocItem::Function(fn_item) => Some(fn_item), - _ => None - } - }) + .filter_map(|item| match item { + hir::AssocItem::Function(fn_item) => Some(fn_item), + _ => None, + }) { add_function_impl(acc, ctx, &missing_fn); } - }, + } SyntaxKind::TYPE_ALIAS_DEF => { for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block) .iter() .filter_map(|item| match item { hir::AssocItem::TypeAlias(type_item) => Some(type_item), - _ => None - }) + _ => None, + }) { add_type_alias_impl(acc, ctx, &missing_fn); } - }, + } SyntaxKind::CONST_DEF => { for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block) .iter() .filter_map(|item| match item { hir::AssocItem::Const(const_item) => Some(const_item), - _ => None - }) + _ => None, + }) { add_const_impl(acc, ctx, &missing_fn); } - }, + } _ => {} } @@ -309,7 +302,7 @@ mod tests { } impl Test for () { - const<|> + const S<|> } ", ); @@ -317,8 +310,8 @@ mod tests { [ CompletionItem { label: "const SOME_CONST: u16 = ", - source_range: [132; 132), - delete: [132; 132), + source_range: [133; 134), + delete: [133; 134), insert: "const SOME_CONST: u16 = ", kind: Const, }, @@ -335,7 +328,7 @@ mod tests { } impl Test for () { - const<|> + const S<|> } ", ); @@ -343,8 +336,8 @@ mod tests { [ CompletionItem { label: "const SOME_CONST: u16 = ", - source_range: [137; 137), - delete: [137; 137), + source_range: [138; 139), + delete: [138; 139), insert: "const SOME_CONST: u16 = ", kind: Const, }, -- cgit v1.2.3 From 0bc9e623747b462ab11a4660a19a50bc38313875 Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Wed, 12 Feb 2020 21:00:47 -0600 Subject: Completion now replaces whole fn/const/type def with snippet. --- .../ra_ide/src/completion/complete_trait_impl.rs | 47 ++++++++++++++-------- 1 file changed, 31 insertions(+), 16 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index 912bf789e..81899308b 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -10,10 +10,11 @@ use crate::{ use hir::{self, Docs, HasSource}; use ra_syntax::{ ast::{self, edit}, - AstNode, SyntaxKind, TextRange, + AstNode, SyntaxKind, SyntaxNode, TextRange, }; use ra_assists::utils::get_missing_impl_items; +use ra_text_edit::TextEdit; pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { let trigger = ctx.token.ancestors().find(|p| match p.kind() { @@ -37,7 +38,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext _ => None, }) { - add_function_impl(acc, ctx, &missing_fn); + add_function_impl(&trigger, acc, ctx, &missing_fn); } } @@ -49,7 +50,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext _ => None, }) { - add_type_alias_impl(acc, ctx, &missing_fn); + add_type_alias_impl(&trigger, acc, ctx, &missing_fn); } } @@ -61,7 +62,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext _ => None, }) { - add_const_impl(acc, ctx, &missing_fn); + add_const_impl(&trigger, acc, ctx, &missing_fn); } } @@ -70,7 +71,12 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext } } -fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, func: &hir::Function) { +fn add_function_impl( + fn_def_node: &SyntaxNode, + acc: &mut Completions, + ctx: &CompletionContext, + func: &hir::Function, +) { let display = FunctionSignature::from_hir(ctx.db, func.clone()); let func_name = func.name(ctx.db); @@ -93,10 +99,14 @@ fn add_function_impl(acc: &mut Completions, ctx: &CompletionContext, func: &hir: let snippet = format!("{} {{}}", display); - builder.insert_text(snippet).kind(completion_kind).add_to(acc); + builder + .text_edit(TextEdit::replace(fn_def_node.text_range(), snippet)) + .kind(completion_kind) + .add_to(acc); } fn add_type_alias_impl( + type_def_node: &SyntaxNode, acc: &mut Completions, ctx: &CompletionContext, type_alias: &hir::TypeAlias, @@ -104,17 +114,22 @@ fn add_type_alias_impl( let snippet = format!("type {} = ", type_alias.name(ctx.db).to_string()); CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) - .insert_text(snippet) + .text_edit(TextEdit::replace(type_def_node.text_range(), snippet)) .kind(CompletionItemKind::TypeAlias) .set_documentation(type_alias.docs(ctx.db)) .add_to(acc); } -fn add_const_impl(acc: &mut Completions, ctx: &CompletionContext, const_: &hir::Const) { +fn add_const_impl( + const_def_node: &SyntaxNode, + acc: &mut Completions, + ctx: &CompletionContext, + const_: &hir::Const, +) { let snippet = make_const_compl_syntax(&const_.source(ctx.db).value); CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) - .insert_text(snippet) + .text_edit(TextEdit::replace(const_def_node.text_range(), snippet)) .kind(CompletionItemKind::Const) .set_documentation(const_.docs(ctx.db)) .add_to(acc); @@ -172,7 +187,7 @@ mod tests { CompletionItem { label: "fn foo()", source_range: [140; 140), - delete: [140; 140), + delete: [138; 140), insert: "fn foo() {}", kind: Function, }, @@ -203,7 +218,7 @@ mod tests { CompletionItem { label: "fn bar()", source_range: [195; 195), - delete: [195; 195), + delete: [193; 195), insert: "fn bar() {}", kind: Function, }, @@ -231,7 +246,7 @@ mod tests { CompletionItem { label: "fn foo()", source_range: [143; 143), - delete: [143; 143), + delete: [141; 143), insert: "fn foo() {}", kind: Function, }, @@ -259,7 +274,7 @@ mod tests { CompletionItem { label: "fn foo()", source_range: [165; 165), - delete: [165; 165), + delete: [163; 165), insert: "fn foo()\nwhere T: Into {}", kind: Function, }, @@ -285,7 +300,7 @@ mod tests { CompletionItem { label: "type SomeType = ", source_range: [123; 123), - delete: [123; 123), + delete: [119; 123), insert: "type SomeType = ", kind: TypeAlias, }, @@ -311,7 +326,7 @@ mod tests { CompletionItem { label: "const SOME_CONST: u16 = ", source_range: [133; 134), - delete: [133; 134), + delete: [127; 134), insert: "const SOME_CONST: u16 = ", kind: Const, }, @@ -337,7 +352,7 @@ mod tests { CompletionItem { label: "const SOME_CONST: u16 = ", source_range: [138; 139), - delete: [138; 139), + delete: [132; 139), insert: "const SOME_CONST: u16 = ", kind: Const, }, -- cgit v1.2.3 From be97cbfdb4dc83b07bfc0e2fd6f8d2d3d90a5c65 Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Thu, 13 Feb 2020 19:10:08 -0600 Subject: Adjusted the completion lookups to filter by just the name. --- .../ra_ide/src/completion/complete_trait_impl.rs | 73 +++++++++++++--------- 1 file changed, 44 insertions(+), 29 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index 81899308b..bff19c5bb 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -79,16 +79,16 @@ fn add_function_impl( ) { let display = FunctionSignature::from_hir(ctx.db, func.clone()); - let func_name = func.name(ctx.db); + let fn_name = func.name(ctx.db).to_string(); let label = if func.params(ctx.db).len() > 0 { - format!("fn {}(..)", func_name.to_string()) + format!("fn {}(..)", fn_name) } else { - format!("fn {}()", func_name.to_string()) + format!("fn {}()", fn_name) }; let builder = CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label.clone()) - .lookup_by(label) + .lookup_by(fn_name) .set_documentation(func.docs(ctx.db)); let completion_kind = if func.has_self_param(ctx.db) { @@ -111,10 +111,13 @@ fn add_type_alias_impl( ctx: &CompletionContext, type_alias: &hir::TypeAlias, ) { - let snippet = format!("type {} = ", type_alias.name(ctx.db).to_string()); + let alias_name = type_alias.name(ctx.db).to_string(); + + let snippet = format!("type {} = ", alias_name); CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) .text_edit(TextEdit::replace(type_def_node.text_range(), snippet)) + .lookup_by(alias_name) .kind(CompletionItemKind::TypeAlias) .set_documentation(type_alias.docs(ctx.db)) .add_to(acc); @@ -126,13 +129,18 @@ fn add_const_impl( ctx: &CompletionContext, const_: &hir::Const, ) { - let snippet = make_const_compl_syntax(&const_.source(ctx.db).value); + let const_name = const_.name(ctx.db).map(|n| n.to_string()); - CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) - .text_edit(TextEdit::replace(const_def_node.text_range(), snippet)) - .kind(CompletionItemKind::Const) - .set_documentation(const_.docs(ctx.db)) - .add_to(acc); + if let Some(const_name) = const_name { + let snippet = make_const_compl_syntax(&const_.source(ctx.db).value); + + CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) + .text_edit(TextEdit::replace(const_def_node.text_range(), snippet)) + .lookup_by(const_name) + .kind(CompletionItemKind::Const) + .set_documentation(const_.docs(ctx.db)) + .add_to(acc); + } } fn make_const_compl_syntax(const_: &ast::ConstDef) -> String { @@ -178,7 +186,7 @@ mod tests { struct T1; impl Test for T1 { - fn<|> + fn f<|> } ", ); @@ -186,10 +194,11 @@ mod tests { [ CompletionItem { label: "fn foo()", - source_range: [140; 140), - delete: [138; 140), + source_range: [141; 142), + delete: [138; 142), insert: "fn foo() {}", kind: Function, + lookup: "foo", }, ] "###); @@ -201,7 +210,7 @@ mod tests { r" trait Test { fn foo(); - fn bar(); + fn foo_bar(); } struct T1; @@ -209,18 +218,19 @@ mod tests { impl Test for T1 { fn foo() {} - fn<|> + fn f<|> } ", ); assert_debug_snapshot!(completions, @r###" [ CompletionItem { - label: "fn bar()", - source_range: [195; 195), - delete: [193; 195), - insert: "fn bar() {}", + label: "fn foo_bar()", + source_range: [200; 201), + delete: [197; 201), + insert: "fn foo_bar() {}", kind: Function, + lookup: "foo_bar", }, ] "###); @@ -237,7 +247,7 @@ mod tests { struct T1; impl Test for T1 { - fn<|> + fn f<|> } ", ); @@ -245,10 +255,11 @@ mod tests { [ CompletionItem { label: "fn foo()", - source_range: [143; 143), - delete: [141; 143), + source_range: [144; 145), + delete: [141; 145), insert: "fn foo() {}", kind: Function, + lookup: "foo", }, ] "###); @@ -265,7 +276,7 @@ mod tests { struct T1; impl Test for T1 { - fn<|> + fn f<|> } ", ); @@ -273,10 +284,11 @@ mod tests { [ CompletionItem { label: "fn foo()", - source_range: [165; 165), - delete: [163; 165), + source_range: [166; 167), + delete: [163; 167), insert: "fn foo()\nwhere T: Into {}", kind: Function, + lookup: "foo", }, ] "###); @@ -291,7 +303,7 @@ mod tests { } impl Test for () { - type<|> + type S<|> } ", ); @@ -299,10 +311,11 @@ mod tests { [ CompletionItem { label: "type SomeType = ", - source_range: [123; 123), - delete: [119; 123), + source_range: [124; 125), + delete: [119; 125), insert: "type SomeType = ", kind: TypeAlias, + lookup: "SomeType", }, ] "###); @@ -329,6 +342,7 @@ mod tests { delete: [127; 134), insert: "const SOME_CONST: u16 = ", kind: Const, + lookup: "SOME_CONST", }, ] "###); @@ -355,6 +369,7 @@ mod tests { delete: [132; 139), insert: "const SOME_CONST: u16 = ", kind: Const, + lookup: "SOME_CONST", }, ] "###); -- cgit v1.2.3 From fc13b7fc9a9944f33170a8f1ce13782dc5bde781 Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Fri, 14 Feb 2020 18:54:00 -0600 Subject: Reordered the `use` items. --- crates/ra_ide/src/completion/complete_trait_impl.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index bff19c5bb..54301cdf2 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -1,21 +1,20 @@ //! FIXME: write short doc here -use crate::{ - completion::{ - CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, - }, - display::FunctionSignature, -}; - use hir::{self, Docs, HasSource}; +use ra_assists::utils::get_missing_impl_items; use ra_syntax::{ ast::{self, edit}, AstNode, SyntaxKind, SyntaxNode, TextRange, }; - -use ra_assists::utils::get_missing_impl_items; use ra_text_edit::TextEdit; +use crate::{ + completion::{ + CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, + }, + display::FunctionSignature, +}; + pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { let trigger = ctx.token.ancestors().find(|p| match p.kind() { SyntaxKind::FN_DEF | SyntaxKind::TYPE_ALIAS_DEF | SyntaxKind::CONST_DEF => true, -- cgit v1.2.3 From ae8ae650fcf8fcdc178fb839b9dbdd67b5864816 Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Sat, 15 Feb 2020 09:50:07 -0600 Subject: Fixed bug that allowed for completion in a nested method. --- .../ra_ide/src/completion/complete_trait_impl.rs | 43 ++++++++++++++++++---- 1 file changed, 36 insertions(+), 7 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index 54301cdf2..83b97eb76 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -17,7 +17,10 @@ use crate::{ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { let trigger = ctx.token.ancestors().find(|p| match p.kind() { - SyntaxKind::FN_DEF | SyntaxKind::TYPE_ALIAS_DEF | SyntaxKind::CONST_DEF => true, + SyntaxKind::FN_DEF + | SyntaxKind::TYPE_ALIAS_DEF + | SyntaxKind::CONST_DEF + | SyntaxKind::BLOCK_EXPR => true, _ => false, }); @@ -98,10 +101,9 @@ fn add_function_impl( let snippet = format!("{} {{}}", display); - builder - .text_edit(TextEdit::replace(fn_def_node.text_range(), snippet)) - .kind(completion_kind) - .add_to(acc); + let range = TextRange::from_to(fn_def_node.text_range().start(), ctx.source_range().end()); + + builder.text_edit(TextEdit::replace(range, snippet)).kind(completion_kind).add_to(acc); } fn add_type_alias_impl( @@ -114,8 +116,10 @@ fn add_type_alias_impl( let snippet = format!("type {} = ", alias_name); + let range = TextRange::from_to(type_def_node.text_range().start(), ctx.source_range().end()); + CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) - .text_edit(TextEdit::replace(type_def_node.text_range(), snippet)) + .text_edit(TextEdit::replace(range, snippet)) .lookup_by(alias_name) .kind(CompletionItemKind::TypeAlias) .set_documentation(type_alias.docs(ctx.db)) @@ -133,8 +137,11 @@ fn add_const_impl( if let Some(const_name) = const_name { let snippet = make_const_compl_syntax(&const_.source(ctx.db).value); + let range = + TextRange::from_to(const_def_node.text_range().start(), ctx.source_range().end()); + CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) - .text_edit(TextEdit::replace(const_def_node.text_range(), snippet)) + .text_edit(TextEdit::replace(range, snippet)) .lookup_by(const_name) .kind(CompletionItemKind::Const) .set_documentation(const_.docs(ctx.db)) @@ -235,6 +242,28 @@ mod tests { "###); } + #[test] + fn completes_only_on_top_level() { + let completions = complete( + r" + trait Test { + fn foo(); + + fn foo_bar(); + } + + struct T1; + + impl Test for T1 { + fn foo() { + <|> + } + } + ", + ); + assert_debug_snapshot!(completions, @r###"[]"###); + } + #[test] fn generic_fn() { let completions = complete( -- cgit v1.2.3 From 057d0bee5516dc7cba71479b27227c5ad22140ee Mon Sep 17 00:00:00 2001 From: Kevin DeLorey <2295721+kdelorey@users.noreply.github.com> Date: Sat, 15 Feb 2020 10:27:04 -0600 Subject: Added module doc comment to explain the purpose of the completion. --- .../ra_ide/src/completion/complete_trait_impl.rs | 33 +++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index 83b97eb76..6ff10c017 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs @@ -1,4 +1,35 @@ -//! FIXME: write short doc here +//! Completion for associated items in a trait implementation. +//! +//! This module adds the completion items related to implementing associated +//! items within a `impl Trait for Struct` block. The current context node +//! must be within either a `FN_DEF`, `TYPE_ALIAS_DEF`, or `CONST_DEF` node +//! and an direct child of an `IMPL_BLOCK`. +//! +//! # Examples +//! +//! Considering the following trait `impl`: +//! +//! ```ignore +//! trait SomeTrait { +//! fn foo(); +//! } +//! +//! impl SomeTrait for () { +//! fn f<|> +//! } +//! ``` +//! +//! may result in the completion of the following method: +//! +//! ```ignore +//! # trait SomeTrait { +//! # fn foo(); +//! # } +//! +//! impl SomeTrait for () { +//! fn foo() {}<|> +//! } +//! ``` use hir::{self, Docs, HasSource}; use ra_assists::utils::get_missing_impl_items; -- cgit v1.2.3