aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/ast_editor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/ast_editor.rs')
-rw-r--r--crates/ra_assists/src/ast_editor.rs123
1 files changed, 65 insertions, 58 deletions
diff --git a/crates/ra_assists/src/ast_editor.rs b/crates/ra_assists/src/ast_editor.rs
index 7b743c9f0..5fbcadfee 100644
--- a/crates/ra_assists/src/ast_editor.rs
+++ b/crates/ra_assists/src/ast_editor.rs
@@ -4,18 +4,18 @@ use arrayvec::ArrayVec;
4use hir::Name; 4use hir::Name;
5use ra_fmt::leading_indent; 5use ra_fmt::leading_indent;
6use ra_syntax::{ 6use ra_syntax::{
7 ast, AstNode, Direction, InsertPosition, SourceFile, SyntaxElement, SyntaxKind::*, TreeArc, T, 7 ast, AstNode, Direction, InsertPosition, SourceFile, SyntaxElement, SyntaxKind::*, T,
8}; 8};
9use ra_text_edit::TextEditBuilder; 9use ra_text_edit::TextEditBuilder;
10 10
11pub struct AstEditor<N: AstNode> { 11pub struct AstEditor<N: AstNode> {
12 original_ast: TreeArc<N>, 12 original_ast: N,
13 ast: TreeArc<N>, 13 ast: N,
14} 14}
15 15
16impl<N: AstNode> AstEditor<N> { 16impl<N: AstNode> AstEditor<N> {
17 pub fn new(node: &N) -> AstEditor<N> { 17 pub fn new(node: N) -> AstEditor<N> {
18 AstEditor { original_ast: node.to_owned(), ast: node.to_owned() } 18 AstEditor { original_ast: node.clone(), ast: node }
19 } 19 }
20 20
21 pub fn into_text_edit(self, builder: &mut TextEditBuilder) { 21 pub fn into_text_edit(self, builder: &mut TextEditBuilder) {
@@ -26,27 +26,27 @@ impl<N: AstNode> AstEditor<N> {
26 } 26 }
27 27
28 pub fn ast(&self) -> &N { 28 pub fn ast(&self) -> &N {
29 &*self.ast 29 &self.ast
30 } 30 }
31 31
32 #[must_use] 32 #[must_use]
33 fn insert_children<'a>( 33 fn insert_children(
34 &self, 34 &self,
35 position: InsertPosition<SyntaxElement<'_>>, 35 position: InsertPosition<SyntaxElement>,
36 to_insert: impl Iterator<Item = SyntaxElement<'a>>, 36 to_insert: impl Iterator<Item = SyntaxElement>,
37 ) -> TreeArc<N> { 37 ) -> N {
38 let new_syntax = self.ast().syntax().insert_children(position, to_insert); 38 let new_syntax = self.ast().syntax().insert_children(position, to_insert);
39 N::cast(&new_syntax).unwrap().to_owned() 39 N::cast(new_syntax).unwrap()
40 } 40 }
41 41
42 #[must_use] 42 #[must_use]
43 fn replace_children<'a>( 43 fn replace_children(
44 &self, 44 &self,
45 to_delete: RangeInclusive<SyntaxElement<'_>>, 45 to_delete: RangeInclusive<SyntaxElement>,
46 to_insert: impl Iterator<Item = SyntaxElement<'a>>, 46 to_insert: impl Iterator<Item = SyntaxElement>,
47 ) -> TreeArc<N> { 47 ) -> N {
48 let new_syntax = self.ast().syntax().replace_children(to_delete, to_insert); 48 let new_syntax = self.ast().syntax().replace_children(to_delete, to_insert);
49 N::cast(&new_syntax).unwrap().to_owned() 49 N::cast(new_syntax).unwrap()
50 } 50 }
51 51
52 fn do_make_multiline(&mut self) { 52 fn do_make_multiline(&mut self) {
@@ -66,16 +66,18 @@ impl<N: AstNode> AstEditor<N> {
66 if ws.text().contains('\n') { 66 if ws.text().contains('\n') {
67 return; 67 return;
68 } 68 }
69 Some(ws) 69 Some(ws.clone())
70 } 70 }
71 }; 71 };
72 72
73 let indent = leading_indent(self.ast().syntax()).unwrap_or(""); 73 let indent = leading_indent(self.ast().syntax()).unwrap_or("".into());
74 let ws = tokens::WsBuilder::new(&format!("\n{}", indent)); 74 let ws = tokens::WsBuilder::new(&format!("\n{}", indent));
75 let to_insert = iter::once(ws.ws().into()); 75 let to_insert = iter::once(ws.ws().into());
76 self.ast = match existing_ws { 76 self.ast = match existing_ws {
77 None => self.insert_children(InsertPosition::After(l_curly), to_insert), 77 None => self.insert_children(InsertPosition::After(l_curly), to_insert),
78 Some(ws) => self.replace_children(RangeInclusive::new(ws.into(), ws.into()), to_insert), 78 Some(ws) => {
79 self.replace_children(RangeInclusive::new(ws.clone().into(), ws.into()), to_insert)
80 }
79 }; 81 };
80 } 82 }
81} 83}
@@ -95,7 +97,7 @@ impl AstEditor<ast::NamedFieldList> {
95 let space = if is_multiline { 97 let space = if is_multiline {
96 ws = tokens::WsBuilder::new(&format!( 98 ws = tokens::WsBuilder::new(&format!(
97 "\n{} ", 99 "\n{} ",
98 leading_indent(self.ast().syntax()).unwrap_or("") 100 leading_indent(self.ast().syntax()).unwrap_or("".into())
99 )); 101 ));
100 ws.ws() 102 ws.ws()
101 } else { 103 } else {
@@ -104,7 +106,7 @@ impl AstEditor<ast::NamedFieldList> {
104 106
105 let mut to_insert: ArrayVec<[SyntaxElement; 4]> = ArrayVec::new(); 107 let mut to_insert: ArrayVec<[SyntaxElement; 4]> = ArrayVec::new();
106 to_insert.push(space.into()); 108 to_insert.push(space.into());
107 to_insert.push(field.syntax().into()); 109 to_insert.push(field.syntax().clone().into());
108 to_insert.push(tokens::comma().into()); 110 to_insert.push(tokens::comma().into());
109 111
110 macro_rules! after_l_curly { 112 macro_rules! after_l_curly {
@@ -127,7 +129,7 @@ impl AstEditor<ast::NamedFieldList> {
127 InsertPosition::After(comma) 129 InsertPosition::After(comma)
128 } else { 130 } else {
129 to_insert.insert(0, tokens::comma().into()); 131 to_insert.insert(0, tokens::comma().into());
130 InsertPosition::After($anchor.syntax().into()) 132 InsertPosition::After($anchor.syntax().clone().into())
131 } 133 }
132 }; 134 };
133 }; 135 };
@@ -144,7 +146,9 @@ impl AstEditor<ast::NamedFieldList> {
144 None => after_l_curly!(), 146 None => after_l_curly!(),
145 } 147 }
146 } 148 }
147 InsertPosition::Before(anchor) => InsertPosition::Before(anchor.syntax().into()), 149 InsertPosition::Before(anchor) => {
150 InsertPosition::Before(anchor.syntax().clone().into())
151 }
148 InsertPosition::After(anchor) => after_field!(anchor), 152 InsertPosition::After(anchor) => after_field!(anchor),
149 }; 153 };
150 154
@@ -157,7 +161,7 @@ impl AstEditor<ast::NamedFieldList> {
157} 161}
158 162
159impl AstEditor<ast::ItemList> { 163impl AstEditor<ast::ItemList> {
160 pub fn append_items<'a>(&mut self, items: impl Iterator<Item = &'a ast::ImplItem>) { 164 pub fn append_items(&mut self, items: impl Iterator<Item = ast::ImplItem>) {
161 let n_existing_items = self.ast().impl_items().count(); 165 let n_existing_items = self.ast().impl_items().count();
162 if n_existing_items == 0 { 166 if n_existing_items == 0 {
163 self.do_make_multiline(); 167 self.do_make_multiline();
@@ -165,22 +169,23 @@ impl AstEditor<ast::ItemList> {
165 items.for_each(|it| self.append_item(it)); 169 items.for_each(|it| self.append_item(it));
166 } 170 }
167 171
168 pub fn append_item(&mut self, item: &ast::ImplItem) { 172 pub fn append_item(&mut self, item: ast::ImplItem) {
169 let (indent, position) = match self.ast().impl_items().last() { 173 let (indent, position) = match self.ast().impl_items().last() {
170 Some(it) => ( 174 Some(it) => (
171 leading_indent(it.syntax()).unwrap_or("").to_string(), 175 leading_indent(it.syntax()).unwrap_or_default().to_string(),
172 InsertPosition::After(it.syntax().into()), 176 InsertPosition::After(it.syntax().clone().into()),
173 ), 177 ),
174 None => match self.l_curly() { 178 None => match self.l_curly() {
175 Some(it) => ( 179 Some(it) => (
176 " ".to_string() + leading_indent(self.ast().syntax()).unwrap_or(""), 180 " ".to_string() + &leading_indent(self.ast().syntax()).unwrap_or_default(),
177 InsertPosition::After(it), 181 InsertPosition::After(it),
178 ), 182 ),
179 None => return, 183 None => return,
180 }, 184 },
181 }; 185 };
182 let ws = tokens::WsBuilder::new(&format!("\n{}", indent)); 186 let ws = tokens::WsBuilder::new(&format!("\n{}", indent));
183 let to_insert: ArrayVec<[SyntaxElement; 2]> = [ws.ws().into(), item.syntax().into()].into(); 187 let to_insert: ArrayVec<[SyntaxElement; 2]> =
188 [ws.ws().into(), item.syntax().clone().into()].into();
184 self.ast = self.insert_children(position, to_insert.into_iter()); 189 self.ast = self.insert_children(position, to_insert.into_iter());
185 } 190 }
186 191
@@ -197,9 +202,9 @@ impl AstEditor<ast::ImplItem> {
197 .children_with_tokens() 202 .children_with_tokens()
198 .find(|it| it.kind() == ATTR || it.kind() == COMMENT) 203 .find(|it| it.kind() == ATTR || it.kind() == COMMENT)
199 { 204 {
200 let end = match start.next_sibling_or_token() { 205 let end = match &start.next_sibling_or_token() {
201 Some(el) if el.kind() == WHITESPACE => el, 206 Some(el) if el.kind() == WHITESPACE => el.clone(),
202 Some(_) | None => start, 207 Some(_) | None => start.clone(),
203 }; 208 };
204 self.ast = self.replace_children(RangeInclusive::new(start, end), iter::empty()); 209 self.ast = self.replace_children(RangeInclusive::new(start, end), iter::empty());
205 } 210 }
@@ -210,18 +215,18 @@ impl AstEditor<ast::FnDef> {
210 pub fn set_body(&mut self, body: &ast::Block) { 215 pub fn set_body(&mut self, body: &ast::Block) {
211 let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new(); 216 let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new();
212 let old_body_or_semi: SyntaxElement = if let Some(old_body) = self.ast().body() { 217 let old_body_or_semi: SyntaxElement = if let Some(old_body) = self.ast().body() {
213 old_body.syntax().into() 218 old_body.syntax().clone().into()
214 } else if let Some(semi) = self.ast().semicolon_token() { 219 } else if let Some(semi) = self.ast().semicolon_token() {
215 to_insert.push(tokens::single_space().into()); 220 to_insert.push(tokens::single_space().into());
216 semi.into() 221 semi.into()
217 } else { 222 } else {
218 to_insert.push(tokens::single_space().into()); 223 to_insert.push(tokens::single_space().into());
219 to_insert.push(body.syntax().into()); 224 to_insert.push(body.syntax().clone().into());
220 self.ast = self.insert_children(InsertPosition::Last, to_insert.into_iter()); 225 self.ast = self.insert_children(InsertPosition::Last, to_insert.into_iter());
221 return; 226 return;
222 }; 227 };
223 to_insert.push(body.syntax().into()); 228 to_insert.push(body.syntax().clone().into());
224 let replace_range = RangeInclusive::new(old_body_or_semi, old_body_or_semi); 229 let replace_range = RangeInclusive::new(old_body_or_semi.clone(), old_body_or_semi);
225 self.ast = self.replace_children(replace_range, to_insert.into_iter()) 230 self.ast = self.replace_children(replace_range, to_insert.into_iter())
226 } 231 }
227} 232}
@@ -231,15 +236,15 @@ pub struct AstBuilder<N: AstNode> {
231} 236}
232 237
233impl AstBuilder<ast::NamedField> { 238impl AstBuilder<ast::NamedField> {
234 pub fn from_name(name: &Name) -> TreeArc<ast::NamedField> { 239 pub fn from_name(name: &Name) -> ast::NamedField {
235 ast_node_from_file_text(&format!("fn f() {{ S {{ {}: (), }} }}", name)) 240 ast_node_from_file_text(&format!("fn f() {{ S {{ {}: (), }} }}", name))
236 } 241 }
237 242
238 fn from_text(text: &str) -> TreeArc<ast::NamedField> { 243 fn from_text(text: &str) -> ast::NamedField {
239 ast_node_from_file_text(&format!("fn f() {{ S {{ {}, }} }}", text)) 244 ast_node_from_file_text(&format!("fn f() {{ S {{ {}, }} }}", text))
240 } 245 }
241 246
242 pub fn from_pieces(name: &ast::NameRef, expr: Option<&ast::Expr>) -> TreeArc<ast::NamedField> { 247 pub fn from_pieces(name: &ast::NameRef, expr: Option<&ast::Expr>) -> ast::NamedField {
243 match expr { 248 match expr {
244 Some(expr) => Self::from_text(&format!("{}: {}", name.syntax(), expr.syntax())), 249 Some(expr) => Self::from_text(&format!("{}: {}", name.syntax(), expr.syntax())),
245 None => Self::from_text(&name.syntax().to_string()), 250 None => Self::from_text(&name.syntax().to_string()),
@@ -248,36 +253,36 @@ impl AstBuilder<ast::NamedField> {
248} 253}
249 254
250impl AstBuilder<ast::Block> { 255impl AstBuilder<ast::Block> {
251 fn from_text(text: &str) -> TreeArc<ast::Block> { 256 fn from_text(text: &str) -> ast::Block {
252 ast_node_from_file_text(&format!("fn f() {}", text)) 257 ast_node_from_file_text(&format!("fn f() {}", text))
253 } 258 }
254 259
255 pub fn single_expr(e: &ast::Expr) -> TreeArc<ast::Block> { 260 pub fn single_expr(e: &ast::Expr) -> ast::Block {
256 Self::from_text(&format!("{{ {} }}", e.syntax())) 261 Self::from_text(&format!("{{ {} }}", e.syntax()))
257 } 262 }
258} 263}
259 264
260impl AstBuilder<ast::Expr> { 265impl AstBuilder<ast::Expr> {
261 fn from_text(text: &str) -> TreeArc<ast::Expr> { 266 fn from_text(text: &str) -> ast::Expr {
262 ast_node_from_file_text(&format!("fn f() {{ {}; }}", text)) 267 ast_node_from_file_text(&format!("fn f() {{ {}; }}", text))
263 } 268 }
264 269
265 pub fn unit() -> TreeArc<ast::Expr> { 270 pub fn unit() -> ast::Expr {
266 Self::from_text("()") 271 Self::from_text("()")
267 } 272 }
268 273
269 pub fn unimplemented() -> TreeArc<ast::Expr> { 274 pub fn unimplemented() -> ast::Expr {
270 Self::from_text("unimplemented!()") 275 Self::from_text("unimplemented!()")
271 } 276 }
272} 277}
273 278
274impl AstBuilder<ast::NameRef> { 279impl AstBuilder<ast::NameRef> {
275 pub fn new(text: &str) -> TreeArc<ast::NameRef> { 280 pub fn new(text: &str) -> ast::NameRef {
276 ast_node_from_file_text(&format!("fn f() {{ {}; }}", text)) 281 ast_node_from_file_text(&format!("fn f() {{ {}; }}", text))
277 } 282 }
278} 283}
279 284
280fn ast_node_from_file_text<N: AstNode>(text: &str) -> TreeArc<N> { 285fn ast_node_from_file_text<N: AstNode>(text: &str) -> N {
281 let parse = SourceFile::parse(text); 286 let parse = SourceFile::parse(text);
282 let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap().to_owned(); 287 let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap().to_owned();
283 res 288 res
@@ -285,47 +290,49 @@ fn ast_node_from_file_text<N: AstNode>(text: &str) -> TreeArc<N> {
285 290
286mod tokens { 291mod tokens {
287 use once_cell::sync::Lazy; 292 use once_cell::sync::Lazy;
288 use ra_syntax::{AstNode, SourceFile, SyntaxKind::*, SyntaxToken, TreeArc, T}; 293 use ra_syntax::{AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken, T};
289 294
290 static SOURCE_FILE: Lazy<TreeArc<SourceFile>> = 295 static SOURCE_FILE: Lazy<Parse<SourceFile>> = Lazy::new(|| SourceFile::parse(",\n; ;"));
291 Lazy::new(|| SourceFile::parse(",\n; ;").tree().to_owned());
292 296
293 pub(crate) fn comma() -> SyntaxToken<'static> { 297 pub(crate) fn comma() -> SyntaxToken {
294 SOURCE_FILE 298 SOURCE_FILE
299 .tree()
295 .syntax() 300 .syntax()
296 .descendants_with_tokens() 301 .descendants_with_tokens()
297 .filter_map(|it| it.as_token()) 302 .filter_map(|it| it.as_token().cloned())
298 .find(|it| it.kind() == T![,]) 303 .find(|it| it.kind() == T![,])
299 .unwrap() 304 .unwrap()
300 } 305 }
301 306
302 pub(crate) fn single_space() -> SyntaxToken<'static> { 307 pub(crate) fn single_space() -> SyntaxToken {
303 SOURCE_FILE 308 SOURCE_FILE
309 .tree()
304 .syntax() 310 .syntax()
305 .descendants_with_tokens() 311 .descendants_with_tokens()
306 .filter_map(|it| it.as_token()) 312 .filter_map(|it| it.as_token().cloned())
307 .find(|it| it.kind() == WHITESPACE && it.text().as_str() == " ") 313 .find(|it| it.kind() == WHITESPACE && it.text().as_str() == " ")
308 .unwrap() 314 .unwrap()
309 } 315 }
310 316
311 #[allow(unused)] 317 #[allow(unused)]
312 pub(crate) fn single_newline() -> SyntaxToken<'static> { 318 pub(crate) fn single_newline() -> SyntaxToken {
313 SOURCE_FILE 319 SOURCE_FILE
320 .tree()
314 .syntax() 321 .syntax()
315 .descendants_with_tokens() 322 .descendants_with_tokens()
316 .filter_map(|it| it.as_token()) 323 .filter_map(|it| it.as_token().cloned())
317 .find(|it| it.kind() == WHITESPACE && it.text().as_str() == "\n") 324 .find(|it| it.kind() == WHITESPACE && it.text().as_str() == "\n")
318 .unwrap() 325 .unwrap()
319 } 326 }
320 327
321 pub(crate) struct WsBuilder(TreeArc<SourceFile>); 328 pub(crate) struct WsBuilder(SourceFile);
322 329
323 impl WsBuilder { 330 impl WsBuilder {
324 pub(crate) fn new(text: &str) -> WsBuilder { 331 pub(crate) fn new(text: &str) -> WsBuilder {
325 WsBuilder(SourceFile::parse(text).ok().unwrap()) 332 WsBuilder(SourceFile::parse(text).ok().unwrap())
326 } 333 }
327 pub(crate) fn ws(&self) -> SyntaxToken<'_> { 334 pub(crate) fn ws(&self) -> SyntaxToken {
328 self.0.syntax().first_child_or_token().unwrap().as_token().unwrap() 335 self.0.syntax().first_child_or_token().unwrap().as_token().cloned().unwrap()
329 } 336 }
330 } 337 }
331 338