mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 05:38:46 +00:00
Add derive handles cursor
This commit is contained in:
parent
7094291573
commit
a5515d9d6f
5 changed files with 51 additions and 20 deletions
|
@ -1,6 +1,6 @@
|
||||||
use {TextUnit, File, EditBuilder, Edit};
|
use {TextUnit, File, EditBuilder, Edit};
|
||||||
use libsyntax2::{
|
use libsyntax2::{
|
||||||
ast::{self, AstNode},
|
ast::{self, AstNode, AttrsOwner},
|
||||||
SyntaxKind::COMMA,
|
SyntaxKind::COMMA,
|
||||||
SyntaxNodeRef,
|
SyntaxNodeRef,
|
||||||
SyntaxRoot,
|
SyntaxRoot,
|
||||||
|
@ -39,18 +39,28 @@ pub fn flip_comma<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_derive<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> ActionResult + 'a> {
|
pub fn add_derive<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> ActionResult + 'a> {
|
||||||
let syntax = file.syntax();
|
let nominal = find_node::<ast::NominalDef<_>>(file.syntax_ref(), offset)?;
|
||||||
let syntax = syntax.as_ref();
|
|
||||||
let nominal = find_node::<ast::NominalDef<_>>(syntax, offset)?;
|
|
||||||
Some(move || {
|
Some(move || {
|
||||||
|
let derive_attr = nominal
|
||||||
|
.attrs()
|
||||||
|
.filter_map(|x| x.as_call())
|
||||||
|
.filter(|(name, _arg)| name == "derive")
|
||||||
|
.map(|(_name, arg)| arg)
|
||||||
|
.next();
|
||||||
let mut edit = EditBuilder::new();
|
let mut edit = EditBuilder::new();
|
||||||
let node_start = nominal.syntax().range().start();
|
let offset = match derive_attr {
|
||||||
edit.insert(node_start, "#[derive()]\n".to_string());
|
None => {
|
||||||
|
let node_start = nominal.syntax().range().start();
|
||||||
|
edit.insert(node_start, "#[derive()]\n".to_string());
|
||||||
|
node_start + TextUnit::of_str("#[derive(")
|
||||||
|
}
|
||||||
|
Some(tt) => {
|
||||||
|
tt.syntax().range().end() - TextUnit::of_char(')')
|
||||||
|
}
|
||||||
|
};
|
||||||
ActionResult {
|
ActionResult {
|
||||||
edit: edit.finish(),
|
edit: edit.finish(),
|
||||||
cursor_position: CursorPosition::Offset(
|
cursor_position: CursorPosition::Offset(offset),
|
||||||
node_start + TextUnit::of_str("#[derive(")
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,7 +116,12 @@ fn test_add_derive() {
|
||||||
"struct Foo { a: i32, <|>}",
|
"struct Foo { a: i32, <|>}",
|
||||||
"#[derive(<|>)]\nstruct Foo { a: i32, }",
|
"#[derive(<|>)]\nstruct Foo { a: i32, }",
|
||||||
|file, off| add_derive(file, off).map(|f| f()),
|
|file, off| add_derive(file, off).map(|f| f()),
|
||||||
)
|
);
|
||||||
|
check_action(
|
||||||
|
"#[derive(Clone)]\nstruct Foo { a: i32<|>, }",
|
||||||
|
"#[derive(Clone<|>)]\nstruct Foo { a: i32, }",
|
||||||
|
|file, off| add_derive(file, off).map(|f| f()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -339,6 +339,7 @@ impl<R: TreeRoot> AstNode<R> for NominalDef<R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<R: TreeRoot> ast::AttrsOwner<R> for NominalDef<R> {}
|
||||||
impl<R: TreeRoot> NominalDef<R> {}
|
impl<R: TreeRoot> NominalDef<R> {}
|
||||||
|
|
||||||
// ParenType
|
// ParenType
|
||||||
|
|
|
@ -52,19 +52,31 @@ impl<R: TreeRoot> File<R> {
|
||||||
impl<R: TreeRoot> FnDef<R> {
|
impl<R: TreeRoot> FnDef<R> {
|
||||||
pub fn has_atom_attr(&self, atom: &str) -> bool {
|
pub fn has_atom_attr(&self, atom: &str) -> bool {
|
||||||
self.attrs()
|
self.attrs()
|
||||||
.filter_map(|x| x.value())
|
.filter_map(|x| x.as_atom())
|
||||||
.filter_map(|x| as_atom(x))
|
|
||||||
.any(|x| x == atom)
|
.any(|x| x == atom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_atom<R: TreeRoot>(tt: TokenTree<R>) -> Option<SmolStr> {
|
impl<R: TreeRoot> Attr<R> {
|
||||||
let syntax = tt.syntax_ref();
|
pub fn as_atom(&self) -> Option<SmolStr> {
|
||||||
let (_bra, attr, _ket) = syntax.children().collect_tuple()?;
|
let tt = self.value()?;
|
||||||
if attr.kind() == IDENT {
|
let (_bra, attr, _ket) = tt.syntax().children().collect_tuple()?;
|
||||||
Some(attr.leaf_text().unwrap())
|
if attr.kind() == IDENT {
|
||||||
} else {
|
Some(attr.leaf_text().unwrap())
|
||||||
None
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_call(&self) -> Option<(SmolStr, TokenTree<R>)> {
|
||||||
|
let tt = self.value()?;
|
||||||
|
let (_bra, attr, args, _ket) = tt.syntax().children().collect_tuple()?;
|
||||||
|
let args = TokenTree::cast(args)?;
|
||||||
|
if attr.kind() == IDENT {
|
||||||
|
Some((attr.leaf_text().unwrap(), args))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -272,6 +272,9 @@ Grammar(
|
||||||
"DynTraitType",
|
"DynTraitType",
|
||||||
]),
|
]),
|
||||||
|
|
||||||
"NominalDef": ( enum: ["StructDef", "EnumDef"]),
|
"NominalDef": (
|
||||||
|
enum: ["StructDef", "EnumDef"],
|
||||||
|
traits: [ "AttrsOwner" ],
|
||||||
|
),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue