aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-16 11:11:20 +0100
committerAleksey Kladov <[email protected]>2018-08-16 11:11:20 +0100
commita5515d9d6f215da4351b482d839aab5212fa0e6f (patch)
treea0557e07f57fad65ad32b80010cce08b5559f9e5
parent7094291573dc819e3115950ec3b2316bd5e9ea33 (diff)
Add derive handles cursor
-rw-r--r--crates/libeditor/src/code_actions.rs28
-rw-r--r--crates/libeditor/tests/test.rs7
-rw-r--r--crates/libsyntax2/src/ast/generated.rs1
-rw-r--r--crates/libsyntax2/src/ast/mod.rs30
-rw-r--r--crates/libsyntax2/src/grammar.ron5
5 files changed, 51 insertions, 20 deletions
diff --git a/crates/libeditor/src/code_actions.rs b/crates/libeditor/src/code_actions.rs
index 4987964d2..6df64be12 100644
--- a/crates/libeditor/src/code_actions.rs
+++ b/crates/libeditor/src/code_actions.rs
@@ -1,6 +1,6 @@
1use {TextUnit, File, EditBuilder, Edit}; 1use {TextUnit, File, EditBuilder, Edit};
2use libsyntax2::{ 2use libsyntax2::{
3 ast::{self, AstNode}, 3 ast::{self, AstNode, AttrsOwner},
4 SyntaxKind::COMMA, 4 SyntaxKind::COMMA,
5 SyntaxNodeRef, 5 SyntaxNodeRef,
6 SyntaxRoot, 6 SyntaxRoot,
@@ -39,18 +39,28 @@ pub fn flip_comma<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce()
39} 39}
40 40
41pub fn add_derive<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> ActionResult + 'a> { 41pub fn add_derive<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> ActionResult + 'a> {
42 let syntax = file.syntax(); 42 let nominal = find_node::<ast::NominalDef<_>>(file.syntax_ref(), offset)?;
43 let syntax = syntax.as_ref();
44 let nominal = find_node::<ast::NominalDef<_>>(syntax, offset)?;
45 Some(move || { 43 Some(move || {
44 let derive_attr = nominal
45 .attrs()
46 .filter_map(|x| x.as_call())
47 .filter(|(name, _arg)| name == "derive")
48 .map(|(_name, arg)| arg)
49 .next();
46 let mut edit = EditBuilder::new(); 50 let mut edit = EditBuilder::new();
47 let node_start = nominal.syntax().range().start(); 51 let offset = match derive_attr {
48 edit.insert(node_start, "#[derive()]\n".to_string()); 52 None => {
53 let node_start = nominal.syntax().range().start();
54 edit.insert(node_start, "#[derive()]\n".to_string());
55 node_start + TextUnit::of_str("#[derive(")
56 }
57 Some(tt) => {
58 tt.syntax().range().end() - TextUnit::of_char(')')
59 }
60 };
49 ActionResult { 61 ActionResult {
50 edit: edit.finish(), 62 edit: edit.finish(),
51 cursor_position: CursorPosition::Offset( 63 cursor_position: CursorPosition::Offset(offset),
52 node_start + TextUnit::of_str("#[derive(")
53 ),
54 } 64 }
55 }) 65 })
56} 66}
diff --git a/crates/libeditor/tests/test.rs b/crates/libeditor/tests/test.rs
index d5df9d0cc..97919d347 100644
--- a/crates/libeditor/tests/test.rs
+++ b/crates/libeditor/tests/test.rs
@@ -116,7 +116,12 @@ fn test_add_derive() {
116 "struct Foo { a: i32, <|>}", 116 "struct Foo { a: i32, <|>}",
117 "#[derive(<|>)]\nstruct Foo { a: i32, }", 117 "#[derive(<|>)]\nstruct Foo { a: i32, }",
118 |file, off| add_derive(file, off).map(|f| f()), 118 |file, off| add_derive(file, off).map(|f| f()),
119 ) 119 );
120 check_action(
121 "#[derive(Clone)]\nstruct Foo { a: i32<|>, }",
122 "#[derive(Clone<|>)]\nstruct Foo { a: i32, }",
123 |file, off| add_derive(file, off).map(|f| f()),
124 );
120} 125}
121 126
122#[test] 127#[test]
diff --git a/crates/libsyntax2/src/ast/generated.rs b/crates/libsyntax2/src/ast/generated.rs
index c575e15df..be3f73f7e 100644
--- a/crates/libsyntax2/src/ast/generated.rs
+++ b/crates/libsyntax2/src/ast/generated.rs
@@ -339,6 +339,7 @@ impl<R: TreeRoot> AstNode<R> for NominalDef<R> {
339 } 339 }
340} 340}
341 341
342impl<R: TreeRoot> ast::AttrsOwner<R> for NominalDef<R> {}
342impl<R: TreeRoot> NominalDef<R> {} 343impl<R: TreeRoot> NominalDef<R> {}
343 344
344// ParenType 345// ParenType
diff --git a/crates/libsyntax2/src/ast/mod.rs b/crates/libsyntax2/src/ast/mod.rs
index fe8f91d15..d53b12ab8 100644
--- a/crates/libsyntax2/src/ast/mod.rs
+++ b/crates/libsyntax2/src/ast/mod.rs
@@ -52,19 +52,31 @@ impl<R: TreeRoot> File<R> {
52impl<R: TreeRoot> FnDef<R> { 52impl<R: TreeRoot> FnDef<R> {
53 pub fn has_atom_attr(&self, atom: &str) -> bool { 53 pub fn has_atom_attr(&self, atom: &str) -> bool {
54 self.attrs() 54 self.attrs()
55 .filter_map(|x| x.value()) 55 .filter_map(|x| x.as_atom())
56 .filter_map(|x| as_atom(x))
57 .any(|x| x == atom) 56 .any(|x| x == atom)
58 } 57 }
59} 58}
60 59
61fn as_atom<R: TreeRoot>(tt: TokenTree<R>) -> Option<SmolStr> { 60impl<R: TreeRoot> Attr<R> {
62 let syntax = tt.syntax_ref(); 61 pub fn as_atom(&self) -> Option<SmolStr> {
63 let (_bra, attr, _ket) = syntax.children().collect_tuple()?; 62 let tt = self.value()?;
64 if attr.kind() == IDENT { 63 let (_bra, attr, _ket) = tt.syntax().children().collect_tuple()?;
65 Some(attr.leaf_text().unwrap()) 64 if attr.kind() == IDENT {
66 } else { 65 Some(attr.leaf_text().unwrap())
67 None 66 } else {
67 None
68 }
69 }
70
71 pub fn as_call(&self) -> Option<(SmolStr, TokenTree<R>)> {
72 let tt = self.value()?;
73 let (_bra, attr, args, _ket) = tt.syntax().children().collect_tuple()?;
74 let args = TokenTree::cast(args)?;
75 if attr.kind() == IDENT {
76 Some((attr.leaf_text().unwrap(), args))
77 } else {
78 None
79 }
68 } 80 }
69} 81}
70 82
diff --git a/crates/libsyntax2/src/grammar.ron b/crates/libsyntax2/src/grammar.ron
index 4e523da9a..abeffb2c3 100644
--- a/crates/libsyntax2/src/grammar.ron
+++ b/crates/libsyntax2/src/grammar.ron
@@ -272,6 +272,9 @@ Grammar(
272 "DynTraitType", 272 "DynTraitType",
273 ]), 273 ]),
274 274
275 "NominalDef": ( enum: ["StructDef", "EnumDef"]), 275 "NominalDef": (
276 enum: ["StructDef", "EnumDef"],
277 traits: [ "AttrsOwner" ],
278 ),
276 }, 279 },
277) 280)