// struct S;
//
// impl Debug for S {
-//
+// $0
// }
// ```
pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
format!("Add custom impl `{}` for `{}`", trait_token.text().as_str(), annotated_name);
let target = attr.syntax().text_range();
- acc.add(AssistId("add_custom_impl"), label, target, |edit| {
+ acc.add(AssistId("add_custom_impl"), label, target, |builder| {
let new_attr_input = input
.syntax()
.descendants_with_tokens()
let has_more_derives = !new_attr_input.is_empty();
let new_attr_input = new_attr_input.iter().sep_by(", ").surround_with("(", ")").to_string();
- let mut buf = String::new();
- buf.push_str("\n\nimpl ");
- buf.push_str(trait_token.text().as_str());
- buf.push_str(" for ");
- buf.push_str(annotated_name.as_str());
- buf.push_str(" {\n");
-
- let cursor_delta = if has_more_derives {
- let delta = input.syntax().text_range().len() - TextSize::of(&new_attr_input);
- edit.replace(input.syntax().text_range(), new_attr_input);
- delta
+ if has_more_derives {
+ builder.replace(input.syntax().text_range(), new_attr_input);
} else {
let attr_range = attr.syntax().text_range();
- edit.delete(attr_range);
+ builder.delete(attr_range);
let line_break_range = attr
.syntax()
.filter(|t| t.kind() == WHITESPACE)
.map(|t| t.text_range())
.unwrap_or_else(|| TextRange::new(TextSize::from(0), TextSize::from(0)));
- edit.delete(line_break_range);
-
- attr_range.len() + line_break_range.len()
- };
-
- edit.set_cursor(start_offset + TextSize::of(&buf) - cursor_delta);
- buf.push_str("\n}");
- edit.insert(start_offset, buf);
+ builder.delete(line_break_range);
+ }
+
+ match ctx.config.snippet_cap {
+ Some(cap) => {
+ builder.insert_snippet(
+ cap,
+ start_offset,
+ format!("\n\nimpl {} for {} {{\n $0\n}}", trait_token, annotated_name),
+ );
+ }
+ None => {
+ builder.insert(
+ start_offset,
+ format!("\n\nimpl {} for {} {{\n\n}}", trait_token, annotated_name),
+ );
+ }
+ }
})
}
}
impl Debug for Foo {
-<|>
+ $0
}
",
)
}
impl Debug for Foo {
-<|>
+ $0
}
",
)
struct Foo {}
impl Debug for Foo {
-<|>
+ $0
}
",
)
// ```
// ->
// ```
-// #[derive()]
+// #[derive($0)]
// struct Point {
// x: u32,
// y: u32,
// }
// ```
pub(crate) fn add_derive(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
+ let cap = ctx.config.snippet_cap?;
let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?;
let node_start = derive_insertion_offset(&nominal)?;
let target = nominal.syntax().text_range();
- acc.add(AssistId("add_derive"), "Add `#[derive]`", target, |edit| {
+ acc.add(AssistId("add_derive"), "Add `#[derive]`", target, |builder| {
let derive_attr = nominal
.attrs()
.filter_map(|x| x.as_simple_call())
.filter(|(name, _arg)| name == "derive")
.map(|(_name, arg)| arg)
.next();
- let offset = match derive_attr {
+ match derive_attr {
None => {
- edit.insert(node_start, "#[derive()]\n");
- node_start + TextSize::of("#[derive(")
+ builder.insert_snippet(cap, node_start, "#[derive($0)]\n");
+ }
+ Some(tt) => {
+ // Just move the cursor.
+ builder.insert_snippet(
+ cap,
+ tt.syntax().text_range().end() - TextSize::of(')'),
+ "$0",
+ )
}
- Some(tt) => tt.syntax().text_range().end() - TextSize::of(')'),
};
- edit.set_cursor(offset)
})
}
check_assist(
add_derive,
"struct Foo { a: i32, <|>}",
- "#[derive(<|>)]\nstruct Foo { a: i32, }",
+ "#[derive($0)]\nstruct Foo { a: i32, }",
);
check_assist(
add_derive,
"struct Foo { <|> a: i32, }",
- "#[derive(<|>)]\nstruct Foo { a: i32, }",
+ "#[derive($0)]\nstruct Foo { a: i32, }",
);
}
check_assist(
add_derive,
"#[derive(Clone)]\nstruct Foo { a: i32<|>, }",
- "#[derive(Clone<|>)]\nstruct Foo { a: i32, }",
+ "#[derive(Clone$0)]\nstruct Foo { a: i32, }",
);
}
"
/// `Foo` is a pretty important struct.
/// It does stuff.
-#[derive(<|>)]
+#[derive($0)]
struct Foo { a: i32, }
",
);
-use ra_syntax::{
- ast::{self, AstNode, NameOwner, TypeParamsOwner},
- TextSize,
-};
+use ra_syntax::ast::{self, AstNode, NameOwner, TypeParamsOwner};
use stdx::{format_to, SepBy};
use crate::{AssistContext, AssistId, Assists};
//
// ```
// struct Ctx<T: Clone> {
-// data: T,<|>
+// data: T,<|>
// }
// ```
// ->
// ```
// struct Ctx<T: Clone> {
-// data: T,
+// data: T,
// }
//
// impl<T: Clone> Ctx<T> {
-//
+// $0
// }
// ```
pub(crate) fn add_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
let generic_params = lifetime_params.chain(type_params).sep_by(", ");
format_to!(buf, "<{}>", generic_params)
}
- buf.push_str(" {\n");
- edit.set_cursor(start_offset + TextSize::of(&buf));
- buf.push_str("\n}");
- edit.insert(start_offset, buf);
+ match ctx.config.snippet_cap {
+ Some(cap) => {
+ buf.push_str(" {\n $0\n}");
+ edit.insert_snippet(cap, start_offset, buf);
+ }
+ None => {
+ buf.push_str(" {\n}");
+ edit.insert(start_offset, buf);
+ }
+ }
})
}
#[cfg(test)]
mod tests {
- use super::*;
use crate::tests::{check_assist, check_assist_target};
+ use super::*;
+
#[test]
fn test_add_impl() {
- check_assist(add_impl, "struct Foo {<|>}\n", "struct Foo {}\n\nimpl Foo {\n<|>\n}\n");
+ check_assist(add_impl, "struct Foo {<|>}\n", "struct Foo {}\n\nimpl Foo {\n $0\n}\n");
check_assist(
add_impl,
"struct Foo<T: Clone> {<|>}",
- "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n<|>\n}",
+ "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n $0\n}",
);
check_assist(
add_impl,
"struct Foo<'a, T: Foo<'a>> {<|>}",
- "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n<|>\n}",
+ "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n $0\n}",
);
}
struct S;
impl Debug for S {
-
+ $0
}
"#####,
)
}
"#####,
r#####"
-#[derive()]
+#[derive($0)]
struct Point {
x: u32,
y: u32,
"add_impl",
r#####"
struct Ctx<T: Clone> {
- data: T,<|>
+ data: T,<|>
}
"#####,
r#####"
struct Ctx<T: Clone> {
- data: T,
+ data: T,
}
impl<T: Clone> Ctx<T> {
-
+ $0
}
"#####,
)
struct S;
impl Debug for S {
-
+ $0
}
```
}
// AFTER
-#[derive()]
+#[derive($0)]
struct Point {
x: u32,
y: u32,
```rust
// BEFORE
struct Ctx<T: Clone> {
- data: T,┃
+ data: T,┃
}
// AFTER
struct Ctx<T: Clone> {
- data: T,
+ data: T,
}
impl<T: Clone> Ctx<T> {
-
+ $0
}
```