aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-09-28 18:09:57 +0100
committerAleksey Kladov <[email protected]>2019-09-28 18:10:53 +0100
commit0840ec038b2822a424acf238d8db5af569f99a21 (patch)
treec40067afaffe2c7c1b974af668c078bc6d3b3341 /crates/ra_syntax
parent5dbbfda34ae423229487595fd0ae9e727ae42906 (diff)
migrate add impl items to the new editing API
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r--crates/ra_syntax/src/ast/edit.rs97
1 files changed, 94 insertions, 3 deletions
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
index 7013cc9b5..2af6f573e 100644
--- a/crates/ra_syntax/src/ast/edit.rs
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -7,10 +7,14 @@ use arrayvec::ArrayVec;
7 7
8use crate::{ 8use crate::{
9 algo, 9 algo,
10 ast::{self, make, AstNode}, 10 ast::{
11 InsertPosition, SyntaxElement, 11 self,
12 make::{self, tokens},
13 AstNode,
14 },
15 AstToken, InsertPosition, SmolStr, SyntaxElement,
12 SyntaxKind::{ATTR, COMMENT, WHITESPACE}, 16 SyntaxKind::{ATTR, COMMENT, WHITESPACE},
13 SyntaxNode, 17 SyntaxNode, T,
14}; 18};
15 19
16impl ast::FnDef { 20impl ast::FnDef {
@@ -33,6 +37,74 @@ impl ast::FnDef {
33 } 37 }
34} 38}
35 39
40impl ast::ItemList {
41 #[must_use]
42 pub fn append_items(&self, items: impl Iterator<Item = ast::ImplItem>) -> ast::ItemList {
43 let mut res = self.clone();
44 if !self.syntax().text().contains_char('\n') {
45 res = res.make_multiline();
46 }
47 items.for_each(|it| res = res.append_item(it));
48 res
49 }
50
51 #[must_use]
52 pub fn append_item(&self, item: ast::ImplItem) -> ast::ItemList {
53 let (indent, position) = match self.impl_items().last() {
54 Some(it) => (
55 leading_indent(it.syntax()).unwrap_or_default().to_string(),
56 InsertPosition::After(it.syntax().clone().into()),
57 ),
58 None => match self.l_curly() {
59 Some(it) => (
60 " ".to_string() + &leading_indent(self.syntax()).unwrap_or_default(),
61 InsertPosition::After(it),
62 ),
63 None => return self.clone(),
64 },
65 };
66 let ws = tokens::WsBuilder::new(&format!("\n{}", indent));
67 let to_insert: ArrayVec<[SyntaxElement; 2]> =
68 [ws.ws().into(), item.syntax().clone().into()].into();
69 insert_children(self, position, to_insert.into_iter())
70 }
71
72 fn l_curly(&self) -> Option<SyntaxElement> {
73 self.syntax().children_with_tokens().find(|it| it.kind() == T!['{'])
74 }
75
76 fn make_multiline(&self) -> ast::ItemList {
77 let l_curly = match self.syntax().children_with_tokens().find(|it| it.kind() == T!['{']) {
78 Some(it) => it,
79 None => return self.clone(),
80 };
81 let sibling = match l_curly.next_sibling_or_token() {
82 Some(it) => it,
83 None => return self.clone(),
84 };
85 let existing_ws = match sibling.as_token() {
86 None => None,
87 Some(tok) if tok.kind() != WHITESPACE => None,
88 Some(ws) => {
89 if ws.text().contains('\n') {
90 return self.clone();
91 }
92 Some(ws.clone())
93 }
94 };
95
96 let indent = leading_indent(self.syntax()).unwrap_or("".into());
97 let ws = tokens::WsBuilder::new(&format!("\n{}", indent));
98 let to_insert = iter::once(ws.ws().into());
99 match existing_ws {
100 None => insert_children(self, InsertPosition::After(l_curly), to_insert),
101 Some(ws) => {
102 replace_children(self, RangeInclusive::new(ws.clone().into(), ws.into()), to_insert)
103 }
104 }
105 }
106}
107
36pub fn strip_attrs_and_docs<N: ast::AttrsOwner>(node: N) -> N { 108pub fn strip_attrs_and_docs<N: ast::AttrsOwner>(node: N) -> N {
37 N::cast(strip_attrs_and_docs_inner(node.syntax().clone())).unwrap() 109 N::cast(strip_attrs_and_docs_inner(node.syntax().clone())).unwrap()
38} 110}
@@ -50,6 +122,25 @@ fn strip_attrs_and_docs_inner(mut node: SyntaxNode) -> SyntaxNode {
50 node 122 node
51} 123}
52 124
125// Note this is copy-pasted from fmt. It seems like fmt should be a separate
126// crate, but basic tree building should be this crate. However, tree building
127// might want to call into fmt...
128fn leading_indent(node: &SyntaxNode) -> Option<SmolStr> {
129 let prev_tokens = std::iter::successors(node.first_token(), |token| token.prev_token());
130 for token in prev_tokens {
131 if let Some(ws) = ast::Whitespace::cast(token.clone()) {
132 let ws_text = ws.text();
133 if let Some(pos) = ws_text.rfind('\n') {
134 return Some(ws_text[pos + 1..].into());
135 }
136 }
137 if token.text().contains('\n') {
138 break;
139 }
140 }
141 None
142}
143
53#[must_use] 144#[must_use]
54fn insert_children<N: AstNode>( 145fn insert_children<N: AstNode>(
55 parent: &N, 146 parent: &N,