Use snippets in add_missing_members

This commit is contained in:
Aleksey Kladov 2020-05-20 01:53:21 +02:00
parent e6fc0bdffb
commit a04cababaa
6 changed files with 84 additions and 45 deletions

View file

@ -194,20 +194,30 @@ impl AssistBuilder {
pub(crate) fn insert(&mut self, offset: TextSize, text: impl Into<String>) { pub(crate) fn insert(&mut self, offset: TextSize, text: impl Into<String>) {
self.edit.insert(offset, text.into()) self.edit.insert(offset, text.into())
} }
/// Append specified `text` at the given `offset` /// Append specified `snippet` at the given `offset`
pub(crate) fn insert_snippet( pub(crate) fn insert_snippet(
&mut self, &mut self,
_cap: SnippetCap, _cap: SnippetCap,
offset: TextSize, offset: TextSize,
text: impl Into<String>, snippet: impl Into<String>,
) { ) {
self.is_snippet = true; self.is_snippet = true;
self.edit.insert(offset, text.into()) self.insert(offset, snippet);
} }
/// Replaces specified `range` of text with a given string. /// Replaces specified `range` of text with a given string.
pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) {
self.edit.replace(range, replace_with.into()) self.edit.replace(range, replace_with.into())
} }
/// Replaces specified `range` of text with a given `snippet`.
pub(crate) fn replace_snippet(
&mut self,
_cap: SnippetCap,
range: TextRange,
snippet: impl Into<String>,
) {
self.is_snippet = true;
self.replace(range, snippet);
}
pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) { pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) {
algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit)
} }

View file

@ -10,7 +10,11 @@ use ra_syntax::{
}; };
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use crate::{assist_config::SnippetCap, utils::render_snippet, AssistContext, AssistId, Assists}; use crate::{
assist_config::SnippetCap,
utils::{render_snippet, Cursor},
AssistContext, AssistId, Assists,
};
// Assist: add_function // Assist: add_function
// //
@ -81,7 +85,11 @@ struct FunctionTemplate {
impl FunctionTemplate { impl FunctionTemplate {
fn to_string(&self, cap: Option<SnippetCap>) -> String { fn to_string(&self, cap: Option<SnippetCap>) -> String {
let f = match cap { let f = match cap {
Some(cap) => render_snippet(cap, self.fn_def.syntax(), self.placeholder_expr.syntax()), Some(cap) => render_snippet(
cap,
self.fn_def.syntax(),
Cursor::Replace(self.placeholder_expr.syntax()),
),
None => self.fn_def.to_string(), None => self.fn_def.to_string(),
}; };
format!("{}{}{}", self.leading_ws, f, self.trailing_ws) format!("{}{}{}", self.leading_ws, f, self.trailing_ws)

View file

@ -11,7 +11,7 @@ use ra_syntax::{
use crate::{ use crate::{
assist_context::{AssistContext, Assists}, assist_context::{AssistContext, Assists},
ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
utils::{get_missing_assoc_items, resolve_target_trait}, utils::{get_missing_assoc_items, render_snippet, resolve_target_trait, Cursor},
AssistId, AssistId,
}; };
@ -45,7 +45,7 @@ enum AddMissingImplMembersMode {
// } // }
// //
// impl Trait<u32> for () { // impl Trait<u32> for () {
// fn foo(&self) -> u32 { // $0fn foo(&self) -> u32 {
// todo!() // todo!()
// } // }
// //
@ -89,7 +89,7 @@ pub(crate) fn add_missing_impl_members(acc: &mut Assists, ctx: &AssistContext) -
// impl Trait for () { // impl Trait for () {
// Type X = (); // Type X = ();
// fn foo(&self) {} // fn foo(&self) {}
// fn bar(&self) {} // $0fn bar(&self) {}
// //
// } // }
// ``` // ```
@ -147,7 +147,7 @@ fn add_missing_impl_members_inner(
} }
let target = impl_def.syntax().text_range(); let target = impl_def.syntax().text_range();
acc.add(AssistId(assist_id), label, target, |edit| { acc.add(AssistId(assist_id), label, target, |builder| {
let n_existing_items = impl_item_list.assoc_items().count(); let n_existing_items = impl_item_list.assoc_items().count();
let source_scope = ctx.sema.scope_for_def(trait_); let source_scope = ctx.sema.scope_for_def(trait_);
let target_scope = ctx.sema.scope(impl_item_list.syntax()); let target_scope = ctx.sema.scope(impl_item_list.syntax());
@ -162,13 +162,21 @@ fn add_missing_impl_members_inner(
}) })
.map(|it| edit::remove_attrs_and_docs(&it)); .map(|it| edit::remove_attrs_and_docs(&it));
let new_impl_item_list = impl_item_list.append_items(items); let new_impl_item_list = impl_item_list.append_items(items);
let cursor_position = { let first_new_item = new_impl_item_list.assoc_items().nth(n_existing_items).unwrap();
let first_new_item = new_impl_item_list.assoc_items().nth(n_existing_items).unwrap();
first_new_item.syntax().text_range().start()
};
edit.replace_ast(impl_item_list, new_impl_item_list); let original_range = impl_item_list.syntax().text_range();
edit.set_cursor(cursor_position); match ctx.config.snippet_cap {
None => builder.replace(original_range, new_impl_item_list.to_string()),
Some(cap) => builder.replace_snippet(
cap,
original_range,
render_snippet(
cap,
new_impl_item_list.syntax(),
Cursor::Before(first_new_item.syntax()),
),
),
};
}) })
} }
@ -222,7 +230,7 @@ struct S;
impl Foo for S { impl Foo for S {
fn bar(&self) {} fn bar(&self) {}
<|>type Output; $0type Output;
const CONST: usize = 42; const CONST: usize = 42;
fn foo(&self) { fn foo(&self) {
todo!() todo!()
@ -263,7 +271,7 @@ struct S;
impl Foo for S { impl Foo for S {
fn bar(&self) {} fn bar(&self) {}
<|>fn foo(&self) { $0fn foo(&self) {
todo!() todo!()
} }
@ -283,7 +291,7 @@ impl Foo for S { <|> }"#,
trait Foo { fn foo(&self); } trait Foo { fn foo(&self); }
struct S; struct S;
impl Foo for S { impl Foo for S {
<|>fn foo(&self) { $0fn foo(&self) {
todo!() todo!()
} }
}"#, }"#,
@ -302,7 +310,7 @@ impl Foo<u32> for S { <|> }"#,
trait Foo<T> { fn foo(&self, t: T) -> &T; } trait Foo<T> { fn foo(&self, t: T) -> &T; }
struct S; struct S;
impl Foo<u32> for S { impl Foo<u32> for S {
<|>fn foo(&self, t: u32) -> &u32 { $0fn foo(&self, t: u32) -> &u32 {
todo!() todo!()
} }
}"#, }"#,
@ -321,7 +329,7 @@ impl<U> Foo<U> for S { <|> }"#,
trait Foo<T> { fn foo(&self, t: T) -> &T; } trait Foo<T> { fn foo(&self, t: T) -> &T; }
struct S; struct S;
impl<U> Foo<U> for S { impl<U> Foo<U> for S {
<|>fn foo(&self, t: U) -> &U { $0fn foo(&self, t: U) -> &U {
todo!() todo!()
} }
}"#, }"#,
@ -340,7 +348,7 @@ impl Foo for S {}<|>"#,
trait Foo { fn foo(&self); } trait Foo { fn foo(&self); }
struct S; struct S;
impl Foo for S { impl Foo for S {
<|>fn foo(&self) { $0fn foo(&self) {
todo!() todo!()
} }
}"#, }"#,
@ -365,7 +373,7 @@ mod foo {
} }
struct S; struct S;
impl foo::Foo for S { impl foo::Foo for S {
<|>fn foo(&self, bar: foo::Bar) { $0fn foo(&self, bar: foo::Bar) {
todo!() todo!()
} }
}"#, }"#,
@ -390,7 +398,7 @@ mod foo {
} }
struct S; struct S;
impl foo::Foo for S { impl foo::Foo for S {
<|>fn foo(&self, bar: foo::Bar<u32>) { $0fn foo(&self, bar: foo::Bar<u32>) {
todo!() todo!()
} }
}"#, }"#,
@ -415,7 +423,7 @@ mod foo {
} }
struct S; struct S;
impl foo::Foo<u32> for S { impl foo::Foo<u32> for S {
<|>fn foo(&self, bar: foo::Bar<u32>) { $0fn foo(&self, bar: foo::Bar<u32>) {
todo!() todo!()
} }
}"#, }"#,
@ -443,7 +451,7 @@ mod foo {
struct Param; struct Param;
struct S; struct S;
impl foo::Foo<Param> for S { impl foo::Foo<Param> for S {
<|>fn foo(&self, bar: Param) { $0fn foo(&self, bar: Param) {
todo!() todo!()
} }
}"#, }"#,
@ -470,7 +478,7 @@ mod foo {
} }
struct S; struct S;
impl foo::Foo for S { impl foo::Foo for S {
<|>fn foo(&self, bar: foo::Bar<u32>::Assoc) { $0fn foo(&self, bar: foo::Bar<u32>::Assoc) {
todo!() todo!()
} }
}"#, }"#,
@ -497,7 +505,7 @@ mod foo {
} }
struct S; struct S;
impl foo::Foo for S { impl foo::Foo for S {
<|>fn foo(&self, bar: foo::Bar<foo::Baz>) { $0fn foo(&self, bar: foo::Bar<foo::Baz>) {
todo!() todo!()
} }
}"#, }"#,
@ -522,7 +530,7 @@ mod foo {
} }
struct S; struct S;
impl foo::Foo for S { impl foo::Foo for S {
<|>fn foo(&self, bar: dyn Fn(u32) -> i32) { $0fn foo(&self, bar: dyn Fn(u32) -> i32) {
todo!() todo!()
} }
}"#, }"#,
@ -580,7 +588,7 @@ trait Foo {
} }
struct S; struct S;
impl Foo for S { impl Foo for S {
<|>type Output; $0type Output;
fn foo(&self) { fn foo(&self) {
todo!() todo!()
} }
@ -614,7 +622,7 @@ trait Foo {
} }
struct S; struct S;
impl Foo for S { impl Foo for S {
<|>fn valid(some: u32) -> bool { false } $0fn valid(some: u32) -> bool { false }
}"#, }"#,
) )
} }
@ -637,7 +645,7 @@ trait Foo<T = Self> {
struct S; struct S;
impl Foo for S { impl Foo for S {
<|>fn bar(&self, other: &Self) { $0fn bar(&self, other: &Self) {
todo!() todo!()
} }
}"#, }"#,
@ -662,7 +670,7 @@ trait Foo<T1, T2 = Self> {
struct S<T>; struct S<T>;
impl Foo<T> for S<T> { impl Foo<T> for S<T> {
<|>fn bar(&self, this: &T, that: &Self) { $0fn bar(&self, this: &T, that: &Self) {
todo!() todo!()
} }
}"#, }"#,

View file

@ -150,7 +150,7 @@ trait Trait {
impl Trait for () { impl Trait for () {
Type X = (); Type X = ();
fn foo(&self) {} fn foo(&self) {}
fn bar(&self) {} $0fn bar(&self) {}
} }
"#####, "#####,
@ -180,7 +180,7 @@ trait Trait<T> {
} }
impl Trait<u32> for () { impl Trait<u32> for () {
fn foo(&self) -> u32 { $0fn foo(&self) -> u32 {
todo!() todo!()
} }

View file

@ -15,18 +15,31 @@ use crate::assist_config::SnippetCap;
pub(crate) use insert_use::insert_use_statement; pub(crate) use insert_use::insert_use_statement;
pub(crate) fn render_snippet( #[derive(Clone, Copy, Debug)]
_cap: SnippetCap, pub(crate) enum Cursor<'a> {
node: &SyntaxNode, Replace(&'a SyntaxNode),
placeholder: &SyntaxNode, Before(&'a SyntaxNode),
) -> String { }
assert!(placeholder.ancestors().any(|it| it == *node));
let range = placeholder.text_range() - node.text_range().start(); impl<'a> Cursor<'a> {
fn node(self) -> &'a SyntaxNode {
match self {
Cursor::Replace(node) | Cursor::Before(node) => node,
}
}
}
pub(crate) fn render_snippet(_cap: SnippetCap, node: &SyntaxNode, cursor: Cursor) -> String {
assert!(cursor.node().ancestors().any(|it| it == *node));
let range = cursor.node().text_range() - node.text_range().start();
let range: ops::Range<usize> = range.into(); let range: ops::Range<usize> = range.into();
let mut placeholder = placeholder.to_string(); let mut placeholder = cursor.node().to_string();
escape(&mut placeholder); escape(&mut placeholder);
let tab_stop = format!("${{0:{}}}", placeholder); let tab_stop = match cursor {
Cursor::Replace(placeholder) => format!("${{0:{}}}", placeholder),
Cursor::Before(placeholder) => format!("$0{}", placeholder),
};
let mut buf = node.to_string(); let mut buf = node.to_string();
buf.replace_range(range, &tab_stop); buf.replace_range(range, &tab_stop);

View file

@ -146,7 +146,7 @@ trait Trait {
impl Trait for () { impl Trait for () {
Type X = (); Type X = ();
fn foo(&self) {} fn foo(&self) {}
fn bar(&self) {} $0fn bar(&self) {}
} }
``` ```
@ -175,7 +175,7 @@ trait Trait<T> {
} }
impl Trait<u32> for () { impl Trait<u32> for () {
fn foo(&self) -> u32 { $0fn foo(&self) -> u32 {
todo!() todo!()
} }