mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Add snippet support for some assists
This commit is contained in:
parent
c847c079fd
commit
fa2e5299c3
5 changed files with 71 additions and 60 deletions
|
@ -25,7 +25,7 @@ use crate::{
|
||||||
// struct S;
|
// struct S;
|
||||||
//
|
//
|
||||||
// impl Debug for S {
|
// impl Debug for S {
|
||||||
//
|
// $0
|
||||||
// }
|
// }
|
||||||
// ```
|
// ```
|
||||||
pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
||||||
|
@ -52,7 +52,7 @@ pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<
|
||||||
format!("Add custom impl `{}` for `{}`", trait_token.text().as_str(), annotated_name);
|
format!("Add custom impl `{}` for `{}`", trait_token.text().as_str(), annotated_name);
|
||||||
|
|
||||||
let target = attr.syntax().text_range();
|
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
|
let new_attr_input = input
|
||||||
.syntax()
|
.syntax()
|
||||||
.descendants_with_tokens()
|
.descendants_with_tokens()
|
||||||
|
@ -63,20 +63,11 @@ pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<
|
||||||
let has_more_derives = !new_attr_input.is_empty();
|
let has_more_derives = !new_attr_input.is_empty();
|
||||||
let new_attr_input = new_attr_input.iter().sep_by(", ").surround_with("(", ")").to_string();
|
let new_attr_input = new_attr_input.iter().sep_by(", ").surround_with("(", ")").to_string();
|
||||||
|
|
||||||
let mut buf = String::new();
|
if has_more_derives {
|
||||||
buf.push_str("\n\nimpl ");
|
builder.replace(input.syntax().text_range(), new_attr_input);
|
||||||
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
|
|
||||||
} else {
|
} else {
|
||||||
let attr_range = attr.syntax().text_range();
|
let attr_range = attr.syntax().text_range();
|
||||||
edit.delete(attr_range);
|
builder.delete(attr_range);
|
||||||
|
|
||||||
let line_break_range = attr
|
let line_break_range = attr
|
||||||
.syntax()
|
.syntax()
|
||||||
|
@ -84,14 +75,24 @@ pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<
|
||||||
.filter(|t| t.kind() == WHITESPACE)
|
.filter(|t| t.kind() == WHITESPACE)
|
||||||
.map(|t| t.text_range())
|
.map(|t| t.text_range())
|
||||||
.unwrap_or_else(|| TextRange::new(TextSize::from(0), TextSize::from(0)));
|
.unwrap_or_else(|| TextRange::new(TextSize::from(0), TextSize::from(0)));
|
||||||
edit.delete(line_break_range);
|
builder.delete(line_break_range);
|
||||||
|
}
|
||||||
|
|
||||||
attr_range.len() + line_break_range.len()
|
match ctx.config.snippet_cap {
|
||||||
};
|
Some(cap) => {
|
||||||
|
builder.insert_snippet(
|
||||||
edit.set_cursor(start_offset + TextSize::of(&buf) - cursor_delta);
|
cap,
|
||||||
buf.push_str("\n}");
|
start_offset,
|
||||||
edit.insert(start_offset, buf);
|
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),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +118,7 @@ struct Foo {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Foo {
|
impl Debug for Foo {
|
||||||
<|>
|
$0
|
||||||
}
|
}
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
|
@ -139,7 +140,7 @@ pub struct Foo {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Foo {
|
impl Debug for Foo {
|
||||||
<|>
|
$0
|
||||||
}
|
}
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
|
@ -158,7 +159,7 @@ struct Foo {}
|
||||||
struct Foo {}
|
struct Foo {}
|
||||||
|
|
||||||
impl Debug for Foo {
|
impl Debug for Foo {
|
||||||
<|>
|
$0
|
||||||
}
|
}
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
|
|
|
@ -18,31 +18,37 @@ use crate::{AssistContext, AssistId, Assists};
|
||||||
// ```
|
// ```
|
||||||
// ->
|
// ->
|
||||||
// ```
|
// ```
|
||||||
// #[derive()]
|
// #[derive($0)]
|
||||||
// struct Point {
|
// struct Point {
|
||||||
// x: u32,
|
// x: u32,
|
||||||
// y: u32,
|
// y: u32,
|
||||||
// }
|
// }
|
||||||
// ```
|
// ```
|
||||||
pub(crate) fn add_derive(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
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 nominal = ctx.find_node_at_offset::<ast::NominalDef>()?;
|
||||||
let node_start = derive_insertion_offset(&nominal)?;
|
let node_start = derive_insertion_offset(&nominal)?;
|
||||||
let target = nominal.syntax().text_range();
|
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
|
let derive_attr = nominal
|
||||||
.attrs()
|
.attrs()
|
||||||
.filter_map(|x| x.as_simple_call())
|
.filter_map(|x| x.as_simple_call())
|
||||||
.filter(|(name, _arg)| name == "derive")
|
.filter(|(name, _arg)| name == "derive")
|
||||||
.map(|(_name, arg)| arg)
|
.map(|(_name, arg)| arg)
|
||||||
.next();
|
.next();
|
||||||
let offset = match derive_attr {
|
match derive_attr {
|
||||||
None => {
|
None => {
|
||||||
edit.insert(node_start, "#[derive()]\n");
|
builder.insert_snippet(cap, node_start, "#[derive($0)]\n");
|
||||||
node_start + TextSize::of("#[derive(")
|
}
|
||||||
|
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)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,12 +72,12 @@ mod tests {
|
||||||
check_assist(
|
check_assist(
|
||||||
add_derive,
|
add_derive,
|
||||||
"struct Foo { a: i32, <|>}",
|
"struct Foo { a: i32, <|>}",
|
||||||
"#[derive(<|>)]\nstruct Foo { a: i32, }",
|
"#[derive($0)]\nstruct Foo { a: i32, }",
|
||||||
);
|
);
|
||||||
check_assist(
|
check_assist(
|
||||||
add_derive,
|
add_derive,
|
||||||
"struct Foo { <|> a: i32, }",
|
"struct Foo { <|> a: i32, }",
|
||||||
"#[derive(<|>)]\nstruct Foo { a: i32, }",
|
"#[derive($0)]\nstruct Foo { a: i32, }",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +86,7 @@ mod tests {
|
||||||
check_assist(
|
check_assist(
|
||||||
add_derive,
|
add_derive,
|
||||||
"#[derive(Clone)]\nstruct Foo { a: i32<|>, }",
|
"#[derive(Clone)]\nstruct Foo { a: i32<|>, }",
|
||||||
"#[derive(Clone<|>)]\nstruct Foo { a: i32, }",
|
"#[derive(Clone$0)]\nstruct Foo { a: i32, }",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +102,7 @@ struct Foo { a: i32<|>, }
|
||||||
"
|
"
|
||||||
/// `Foo` is a pretty important struct.
|
/// `Foo` is a pretty important struct.
|
||||||
/// It does stuff.
|
/// It does stuff.
|
||||||
#[derive(<|>)]
|
#[derive($0)]
|
||||||
struct Foo { a: i32, }
|
struct Foo { a: i32, }
|
||||||
",
|
",
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
use ra_syntax::{
|
use ra_syntax::ast::{self, AstNode, NameOwner, TypeParamsOwner};
|
||||||
ast::{self, AstNode, NameOwner, TypeParamsOwner},
|
|
||||||
TextSize,
|
|
||||||
};
|
|
||||||
use stdx::{format_to, SepBy};
|
use stdx::{format_to, SepBy};
|
||||||
|
|
||||||
use crate::{AssistContext, AssistId, Assists};
|
use crate::{AssistContext, AssistId, Assists};
|
||||||
|
@ -22,7 +19,7 @@ use crate::{AssistContext, AssistId, Assists};
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// impl<T: Clone> Ctx<T> {
|
// impl<T: Clone> Ctx<T> {
|
||||||
//
|
// $0
|
||||||
// }
|
// }
|
||||||
// ```
|
// ```
|
||||||
pub(crate) fn add_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
pub(crate) fn add_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
||||||
|
@ -50,30 +47,37 @@ pub(crate) fn add_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
||||||
let generic_params = lifetime_params.chain(type_params).sep_by(", ");
|
let generic_params = lifetime_params.chain(type_params).sep_by(", ");
|
||||||
format_to!(buf, "<{}>", generic_params)
|
format_to!(buf, "<{}>", generic_params)
|
||||||
}
|
}
|
||||||
buf.push_str(" {\n");
|
match ctx.config.snippet_cap {
|
||||||
edit.set_cursor(start_offset + TextSize::of(&buf));
|
Some(cap) => {
|
||||||
buf.push_str("\n}");
|
buf.push_str(" {\n $0\n}");
|
||||||
|
edit.insert_snippet(cap, start_offset, buf);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
buf.push_str(" {\n}");
|
||||||
edit.insert(start_offset, buf);
|
edit.insert(start_offset, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use crate::tests::{check_assist, check_assist_target};
|
use crate::tests::{check_assist, check_assist_target};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_impl() {
|
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(
|
check_assist(
|
||||||
add_impl,
|
add_impl,
|
||||||
"struct Foo<T: Clone> {<|>}",
|
"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(
|
check_assist(
|
||||||
add_impl,
|
add_impl,
|
||||||
"struct Foo<'a, T: Foo<'a>> {<|>}",
|
"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}",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ struct S;
|
||||||
struct S;
|
struct S;
|
||||||
|
|
||||||
impl Debug for S {
|
impl Debug for S {
|
||||||
|
$0
|
||||||
}
|
}
|
||||||
"#####,
|
"#####,
|
||||||
)
|
)
|
||||||
|
@ -32,7 +32,7 @@ struct Point {
|
||||||
}
|
}
|
||||||
"#####,
|
"#####,
|
||||||
r#####"
|
r#####"
|
||||||
#[derive()]
|
#[derive($0)]
|
||||||
struct Point {
|
struct Point {
|
||||||
x: u32,
|
x: u32,
|
||||||
y: u32,
|
y: u32,
|
||||||
|
@ -117,7 +117,7 @@ struct Ctx<T: Clone> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone> Ctx<T> {
|
impl<T: Clone> Ctx<T> {
|
||||||
|
$0
|
||||||
}
|
}
|
||||||
"#####,
|
"#####,
|
||||||
)
|
)
|
||||||
|
|
|
@ -17,7 +17,7 @@ struct S;
|
||||||
struct S;
|
struct S;
|
||||||
|
|
||||||
impl Debug for S {
|
impl Debug for S {
|
||||||
|
$0
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ struct Point {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AFTER
|
// AFTER
|
||||||
#[derive()]
|
#[derive($0)]
|
||||||
struct Point {
|
struct Point {
|
||||||
x: u32,
|
x: u32,
|
||||||
y: u32,
|
y: u32,
|
||||||
|
@ -114,7 +114,7 @@ struct Ctx<T: Clone> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone> Ctx<T> {
|
impl<T: Clone> Ctx<T> {
|
||||||
|
$0
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue