From 713975b1c1584bb141dfca84818bf5a7ca91a8ee Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Thu, 7 Mar 2019 13:21:56 +0100 Subject: Properly support the case when the cursor is inside an empty block or outside --- crates/ra_assists/src/add_missing_impl_members.rs | 59 +++++++++++++++++------ 1 file changed, 44 insertions(+), 15 deletions(-) (limited to 'crates/ra_assists') diff --git a/crates/ra_assists/src/add_missing_impl_members.rs b/crates/ra_assists/src/add_missing_impl_members.rs index 0888268e4..f121dafb2 100644 --- a/crates/ra_assists/src/add_missing_impl_members.rs +++ b/crates/ra_assists/src/add_missing_impl_members.rs @@ -4,7 +4,7 @@ use crate::{Assist, AssistId, AssistCtx}; use hir::Resolver; use hir::db::HirDatabase; -use ra_syntax::{SmolStr, SyntaxKind, SyntaxNode, TextUnit, TreeArc}; +use ra_syntax::{SmolStr, SyntaxKind, TextRange, TextUnit, TreeArc}; use ra_syntax::ast::{self, AstNode, FnDef, ImplItem, ImplItemKind, NameOwner}; use ra_db::FilePosition; use ra_fmt::{leading_indent, reindent}; @@ -42,17 +42,13 @@ pub(crate) fn build_func_body(def: &ast::FnDef) -> String { } pub(crate) fn add_missing_impl_members(mut ctx: AssistCtx) -> Option { - use SyntaxKind::{IMPL_BLOCK, ITEM_LIST, WHITESPACE}; - let node = ctx.covering_node(); - let kinds = node.ancestors().take(3).map(SyntaxNode::kind); - // Only suggest this in `impl Foo for S { [Item...] <|> }` cursor position - if !Iterator::eq(kinds, [WHITESPACE, ITEM_LIST, IMPL_BLOCK].iter().cloned()) { - return None; - } - let impl_node = node.ancestors().find_map(ast::ImplBlock::cast)?; let impl_item_list = impl_node.item_list()?; + // Don't offer the assist when cursor is at the end, outside the block itself. + if node.range().end() == impl_node.syntax().range().end() { + return None; + } let trait_def = { let db = ctx.db; @@ -82,14 +78,10 @@ pub(crate) fn add_missing_impl_members(mut ctx: AssistCtx) -> .cloned() .filter(|t| def_name(t).map(|n| missing_fn_names.contains(&n)).unwrap_or(false)) .collect(); - if missing_fns.is_empty() { return None; } - let last_whitespace_node = - impl_item_list.syntax().children().filter_map(ast::Whitespace::cast).last()?.syntax(); - ctx.add_action(AssistId("add_impl_missing_members"), "add missing impl members", |edit| { let indent = { // FIXME: Find a way to get the indent already used in the file. @@ -109,7 +101,16 @@ pub(crate) fn add_missing_impl_members(mut ctx: AssistCtx) -> let func_bodies = String::from("\n") + &func_bodies; let func_bodies = reindent(&func_bodies, &indent) + "\n"; - let changed_range = last_whitespace_node.range(); + let changed_range = { + let last_whitespace = impl_item_list.syntax().children(); + let last_whitespace = last_whitespace.filter_map(ast::Whitespace::cast).last(); + let last_whitespace = last_whitespace.map(|w| w.syntax()); + + let cursor_range = TextRange::from_to(node.range().end(), node.range().end()); + + last_whitespace.map(|x| x.range()).unwrap_or(cursor_range) + }; + let replaced_text_range = TextUnit::of_str(&func_bodies); edit.replace(changed_range, func_bodies); @@ -122,7 +123,7 @@ pub(crate) fn add_missing_impl_members(mut ctx: AssistCtx) -> #[cfg(test)] mod tests { use super::*; - use crate::helpers::{ check_assist }; + use crate::helpers::{check_assist, check_assist_not_applicable}; #[test] fn test_add_missing_impl_members() { @@ -157,4 +158,32 @@ impl Foo for S { }", ); } + + #[test] + fn test_empty_impl_block() { + check_assist( + add_missing_impl_members, + " +trait Foo { fn foo(&self); } +struct S; +impl Foo for S {<|>}", + " +trait Foo { fn foo(&self); } +struct S; +impl Foo for S { + fn foo(&self) { unimplemented!() }<|> +}", + ); + } + + #[test] + fn test_cursor_after_empty_impl_block() { + check_assist_not_applicable( + add_missing_impl_members, + " +trait Foo { fn foo(&self); } +struct S; +impl Foo for S {}<|>", + ) + } } -- cgit v1.2.3