aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-04-22 11:01:33 +0100
committerAleksey Kladov <[email protected]>2019-04-22 11:01:33 +0100
commit268e739c94d2e9edbb45374dfcc252b1648d3181 (patch)
tree25820553d53e8a638003e315076c6c074464fd9e
parentb811922a530b7b22469b386a521946f1003911c7 (diff)
move add_missing_members to structured editing API
Currently, this is more code, and we also loose auto-indenting of bodies, but, long-term, this is the right approach
-rw-r--r--crates/ra_assists/src/add_missing_impl_members.rs149
-rw-r--r--crates/ra_assists/src/ast_editor.rs158
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs9
-rw-r--r--crates/ra_syntax/src/syntax_node.rs61
4 files changed, 231 insertions, 146 deletions
diff --git a/crates/ra_assists/src/add_missing_impl_members.rs b/crates/ra_assists/src/add_missing_impl_members.rs
index c82447b84..17c2af899 100644
--- a/crates/ra_assists/src/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/add_missing_impl_members.rs
@@ -1,14 +1,9 @@
1use std::fmt::Write; 1use crate::{Assist, AssistId, AssistCtx, ast_editor::{AstEditor, AstBuilder}};
2
3use crate::{Assist, AssistId, AssistCtx};
4 2
5use hir::db::HirDatabase; 3use hir::db::HirDatabase;
6use ra_syntax::{SmolStr, SyntaxKind, TextRange, TextUnit, TreeArc}; 4use ra_syntax::{SmolStr, TreeArc};
7use ra_syntax::ast::{self, AstNode, AstToken, FnDef, ImplItem, ImplItemKind, NameOwner}; 5use ra_syntax::ast::{self, AstNode, FnDef, ImplItem, ImplItemKind, NameOwner};
8use ra_db::FilePosition; 6use ra_db::FilePosition;
9use ra_fmt::{leading_indent, reindent};
10
11use itertools::Itertools;
12 7
13enum AddMissingImplMembersMode { 8enum AddMissingImplMembersMode {
14 DefaultMethodsOnly, 9 DefaultMethodsOnly,
@@ -76,48 +71,35 @@ fn add_missing_impl_members_inner(
76 } 71 }
77 72
78 ctx.add_action(AssistId(assist_id), label, |edit| { 73 ctx.add_action(AssistId(assist_id), label, |edit| {
79 let (parent_indent, indent) = { 74 let n_existing_items = impl_item_list.impl_items().count();
80 // FIXME: Find a way to get the indent already used in the file. 75 let fns = missing_fns.into_iter().map(add_body_and_strip_docstring).collect::<Vec<_>>();
81 // Now, we copy the indent of first item or indent with 4 spaces relative to impl block 76
82 const DEFAULT_INDENT: &str = " "; 77 let mut ast_editor = AstEditor::new(impl_item_list);
83 let first_item = impl_item_list.impl_items().next(); 78 if n_existing_items == 0 {
84 let first_item_indent = 79 ast_editor.make_multiline();
85 first_item.and_then(|i| leading_indent(i.syntax())).map(ToOwned::to_owned); 80 }
86 let impl_block_indent = leading_indent(impl_node.syntax()).unwrap_or_default(); 81 ast_editor.append_functions(fns.iter().map(|it| &**it));
87 82 let first_new_item = ast_editor.ast().impl_items().nth(n_existing_items).unwrap();
88 ( 83 let cursor_poisition = first_new_item.syntax().range().start();
89 impl_block_indent.to_owned(), 84 ast_editor.into_text_edit(edit.text_edit_builder());
90 first_item_indent.unwrap_or_else(|| impl_block_indent.to_owned() + DEFAULT_INDENT), 85
91 ) 86 edit.set_cursor(cursor_poisition);
92 };
93
94 let changed_range = {
95 let children = impl_item_list.syntax().children_with_tokens();
96 let last_whitespace =
97 children.filter_map(|it| ast::Whitespace::cast(it.as_token()?)).last();
98
99 last_whitespace.map(|w| w.syntax().range()).unwrap_or_else(|| {
100 let in_brackets = impl_item_list.syntax().range().end() - TextUnit::of_str("}");
101 TextRange::from_to(in_brackets, in_brackets)
102 })
103 };
104
105 let func_bodies = format!("\n{}", missing_fns.into_iter().map(build_func_body).join("\n"));
106 let trailing_whitespace = format!("\n{}", parent_indent);
107 let func_bodies = reindent(&func_bodies, &indent) + &trailing_whitespace;
108
109 let replaced_text_range = TextUnit::of_str(&func_bodies);
110
111 edit.replace(changed_range, func_bodies);
112 // FIXME: place the cursor on the first unimplemented?
113 edit.set_cursor(
114 changed_range.start() + replaced_text_range - TextUnit::of_str(&trailing_whitespace),
115 );
116 }); 87 });
117 88
118 ctx.build() 89 ctx.build()
119} 90}
120 91
92fn add_body_and_strip_docstring(fn_def: &ast::FnDef) -> TreeArc<ast::FnDef> {
93 let mut ast_editor = AstEditor::new(fn_def);
94 if fn_def.body().is_none() {
95 ast_editor.set_body(&AstBuilder::<ast::Block>::single_expr(
96 &AstBuilder::<ast::Expr>::unimplemented(),
97 ));
98 }
99 ast_editor.strip_attrs_and_docs();
100 ast_editor.ast().to_owned()
101}
102
121/// Given an `ast::ImplBlock`, resolves the target trait (the one being 103/// Given an `ast::ImplBlock`, resolves the target trait (the one being
122/// implemented) to a `ast::TraitDef`. 104/// implemented) to a `ast::TraitDef`.
123fn resolve_target_trait_def( 105fn resolve_target_trait_def(
@@ -134,22 +116,6 @@ fn resolve_target_trait_def(
134 } 116 }
135} 117}
136 118
137fn build_func_body(def: &ast::FnDef) -> String {
138 let mut buf = String::new();
139
140 for child in def.syntax().children_with_tokens() {
141 match (child.prev_sibling_or_token().map(|c| c.kind()), child.kind()) {
142 (_, SyntaxKind::SEMI) => buf.push_str(" {\n unimplemented!()\n}"),
143 (_, SyntaxKind::ATTR) | (_, SyntaxKind::COMMENT) => {}
144 (Some(SyntaxKind::ATTR), SyntaxKind::WHITESPACE)
145 | (Some(SyntaxKind::COMMENT), SyntaxKind::WHITESPACE) => {}
146 _ => write!(buf, "{}", child).unwrap(),
147 };
148 }
149
150 buf.trim_end().to_string()
151}
152
153#[cfg(test)] 119#[cfg(test)]
154mod tests { 120mod tests {
155 use super::*; 121 use super::*;
@@ -170,7 +136,7 @@ struct S;
170 136
171impl Foo for S { 137impl Foo for S {
172 fn bar(&self) {} 138 fn bar(&self) {}
173 <|> 139<|>
174}", 140}",
175 " 141 "
176trait Foo { 142trait Foo {
@@ -183,12 +149,9 @@ struct S;
183 149
184impl Foo for S { 150impl Foo for S {
185 fn bar(&self) {} 151 fn bar(&self) {}
186 fn foo(&self) { 152 <|>fn foo(&self) { unimplemented!() }
187 unimplemented!() 153 fn baz(&self) { unimplemented!() }
188 } 154
189 fn baz(&self) {
190 unimplemented!()
191 }<|>
192}", 155}",
193 ); 156 );
194 } 157 }
@@ -208,7 +171,7 @@ struct S;
208 171
209impl Foo for S { 172impl Foo for S {
210 fn bar(&self) {} 173 fn bar(&self) {}
211 <|> 174<|>
212}", 175}",
213 " 176 "
214trait Foo { 177trait Foo {
@@ -221,9 +184,8 @@ struct S;
221 184
222impl Foo for S { 185impl Foo for S {
223 fn bar(&self) {} 186 fn bar(&self) {}
224 fn foo(&self) { 187 <|>fn foo(&self) { unimplemented!() }
225 unimplemented!() 188
226 }<|>
227}", 189}",
228 ); 190 );
229 } 191 }
@@ -240,9 +202,7 @@ impl Foo for S { <|> }",
240trait Foo { fn foo(&self); } 202trait Foo { fn foo(&self); }
241struct S; 203struct S;
242impl Foo for S { 204impl Foo for S {
243 fn foo(&self) { 205 <|>fn foo(&self) { unimplemented!() }
244 unimplemented!()
245 }<|>
246}", 206}",
247 ); 207 );
248 } 208 }
@@ -259,9 +219,7 @@ impl Foo for S {}<|>",
259trait Foo { fn foo(&self); } 219trait Foo { fn foo(&self); }
260struct S; 220struct S;
261impl Foo for S { 221impl Foo for S {
262 fn foo(&self) { 222 <|>fn foo(&self) { unimplemented!() }
263 unimplemented!()
264 }<|>
265}", 223}",
266 ) 224 )
267 } 225 }
@@ -292,35 +250,6 @@ impl Foo for S { <|> }",
292 } 250 }
293 251
294 #[test] 252 #[test]
295 fn test_indented_impl_block() {
296 check_assist(
297 add_missing_impl_members,
298 "
299trait Foo {
300 fn valid(some: u32) -> bool;
301}
302struct S;
303
304mod my_mod {
305 impl crate::Foo for S { <|> }
306}",
307 "
308trait Foo {
309 fn valid(some: u32) -> bool;
310}
311struct S;
312
313mod my_mod {
314 impl crate::Foo for S {
315 fn valid(some: u32) -> bool {
316 unimplemented!()
317 }<|>
318 }
319}",
320 )
321 }
322
323 #[test]
324 fn test_with_docstring_and_attrs() { 253 fn test_with_docstring_and_attrs() {
325 check_assist( 254 check_assist(
326 add_missing_impl_members, 255 add_missing_impl_members,
@@ -342,9 +271,7 @@ trait Foo {
342} 271}
343struct S; 272struct S;
344impl Foo for S { 273impl Foo for S {
345 fn foo(&self) { 274 <|>fn foo(&self) { unimplemented!() }
346 unimplemented!()
347 }<|>
348}"#, 275}"#,
349 ) 276 )
350 } 277 }
@@ -367,7 +294,7 @@ trait Foo {
367} 294}
368struct S; 295struct S;
369impl Foo for S { 296impl Foo for S {
370 fn valid(some: u32) -> bool { false }<|> 297 <|>fn valid(some: u32) -> bool { false }
371}", 298}",
372 ) 299 )
373 } 300 }
diff --git a/crates/ra_assists/src/ast_editor.rs b/crates/ra_assists/src/ast_editor.rs
index 13ee82879..283b280b6 100644
--- a/crates/ra_assists/src/ast_editor.rs
+++ b/crates/ra_assists/src/ast_editor.rs
@@ -1,4 +1,4 @@
1use std::iter; 1use std::{iter, ops::RangeInclusive};
2 2
3use arrayvec::ArrayVec; 3use arrayvec::ArrayVec;
4use ra_text_edit::TextEditBuilder; 4use ra_text_edit::TextEditBuilder;
@@ -26,6 +26,7 @@ impl<N: AstNode> AstEditor<N> {
26 &*self.ast 26 &*self.ast
27 } 27 }
28 28
29 #[must_use]
29 fn insert_children<'a>( 30 fn insert_children<'a>(
30 &self, 31 &self,
31 position: InsertPosition<SyntaxElement<'_>>, 32 position: InsertPosition<SyntaxElement<'_>>,
@@ -34,31 +35,55 @@ impl<N: AstNode> AstEditor<N> {
34 let new_syntax = self.ast().syntax().insert_children(position, to_insert); 35 let new_syntax = self.ast().syntax().insert_children(position, to_insert);
35 N::cast(&new_syntax).unwrap().to_owned() 36 N::cast(&new_syntax).unwrap().to_owned()
36 } 37 }
37}
38 38
39impl AstEditor<ast::NamedFieldList> { 39 #[must_use]
40 pub fn append_field(&mut self, field: &ast::NamedField) { 40 fn replace_children<'a>(
41 self.insert_field(InsertPosition::Last, field) 41 &self,
42 to_delete: RangeInclusive<SyntaxElement<'_>>,
43 to_insert: impl Iterator<Item = SyntaxElement<'a>>,
44 ) -> TreeArc<N> {
45 let new_syntax = self.ast().syntax().replace_children(to_delete, to_insert);
46 N::cast(&new_syntax).unwrap().to_owned()
42 } 47 }
43 48
44 pub fn make_multiline(&mut self) { 49 fn do_make_multiline(&mut self) {
45 let l_curly = match self.l_curly() { 50 let l_curly =
46 Some(it) => it, 51 match self.ast().syntax().children_with_tokens().find(|it| it.kind() == L_CURLY) {
47 None => return, 52 Some(it) => it,
48 }; 53 None => return,
54 };
49 let sibling = match l_curly.next_sibling_or_token() { 55 let sibling = match l_curly.next_sibling_or_token() {
50 Some(it) => it, 56 Some(it) => it,
51 None => return, 57 None => return,
52 }; 58 };
53 if sibling.as_token().map(|it| it.text().contains('\n')) == Some(true) { 59 let existing_ws = match sibling.as_token() {
54 return; 60 None => None,
55 } 61 Some(tok) if tok.kind() != WHITESPACE => None,
62 Some(ws) => {
63 if ws.text().contains('\n') {
64 return;
65 }
66 Some(ws)
67 }
68 };
69
70 let indent = leading_indent(self.ast().syntax()).unwrap_or("");
71 let ws = tokens::WsBuilder::new(&format!("\n{}", indent));
72 let to_insert = iter::once(ws.ws().into());
73 self.ast = match existing_ws {
74 None => self.insert_children(InsertPosition::After(l_curly), to_insert),
75 Some(ws) => self.replace_children(RangeInclusive::new(ws.into(), ws.into()), to_insert),
76 };
77 }
78}
79
80impl AstEditor<ast::NamedFieldList> {
81 pub fn append_field(&mut self, field: &ast::NamedField) {
82 self.insert_field(InsertPosition::Last, field)
83 }
56 84
57 let ws = tokens::WsBuilder::new(&format!( 85 pub fn make_multiline(&mut self) {
58 "\n{}", 86 self.do_make_multiline()
59 leading_indent(self.ast().syntax()).unwrap_or("")
60 ));
61 self.ast = self.insert_children(InsertPosition::After(l_curly), iter::once(ws.ws().into()));
62 } 87 }
63 88
64 pub fn insert_field( 89 pub fn insert_field(
@@ -132,6 +157,79 @@ impl AstEditor<ast::NamedFieldList> {
132 } 157 }
133} 158}
134 159
160impl AstEditor<ast::ItemList> {
161 pub fn make_multiline(&mut self) {
162 self.do_make_multiline()
163 }
164
165 pub fn append_functions<'a>(&mut self, fns: impl Iterator<Item = &'a ast::FnDef>) {
166 fns.for_each(|it| self.append_function(it))
167 }
168
169 pub fn append_function(&mut self, fn_def: &ast::FnDef) {
170 let (indent, position) = match self.ast().impl_items().last() {
171 Some(it) => (
172 leading_indent(it.syntax()).unwrap_or("").to_string(),
173 InsertPosition::After(it.syntax().into()),
174 ),
175 None => match self.l_curly() {
176 Some(it) => (
177 " ".to_string() + leading_indent(self.ast().syntax()).unwrap_or(""),
178 InsertPosition::After(it),
179 ),
180 None => return,
181 },
182 };
183 let ws = tokens::WsBuilder::new(&format!("\n{}", indent));
184 let to_insert: ArrayVec<[SyntaxElement; 2]> =
185 [ws.ws().into(), fn_def.syntax().into()].into();
186 self.ast = self.insert_children(position, to_insert.into_iter());
187 }
188
189 fn l_curly(&self) -> Option<SyntaxElement> {
190 self.ast().syntax().children_with_tokens().find(|it| it.kind() == L_CURLY)
191 }
192}
193
194impl AstEditor<ast::FnDef> {
195 pub fn set_body(&mut self, body: &ast::Block) {
196 let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new();
197 let old_body_or_semi: SyntaxElement = if let Some(old_body) = self.ast().body() {
198 old_body.syntax().into()
199 } else if let Some(semi) = self.ast().semicolon_token() {
200 to_insert.push(tokens::single_space().into());
201 semi.into()
202 } else {
203 to_insert.push(tokens::single_space().into());
204 to_insert.push(body.syntax().into());
205 self.ast = self.insert_children(InsertPosition::Last, to_insert.into_iter());
206 return;
207 };
208 to_insert.push(body.syntax().into());
209 let replace_range = RangeInclusive::new(old_body_or_semi, old_body_or_semi);
210 self.ast = self.replace_children(replace_range, to_insert.into_iter())
211 }
212
213 pub fn strip_attrs_and_docs(&mut self) {
214 loop {
215 if let Some(start) = self
216 .ast()
217 .syntax()
218 .children_with_tokens()
219 .find(|it| it.kind() == ATTR || it.kind() == COMMENT)
220 {
221 let end = match start.next_sibling_or_token() {
222 Some(el) if el.kind() == WHITESPACE => el,
223 Some(_) | None => start,
224 };
225 self.ast = self.replace_children(RangeInclusive::new(start, end), iter::empty());
226 } else {
227 break;
228 }
229 }
230 }
231}
232
135pub struct AstBuilder<N: AstNode> { 233pub struct AstBuilder<N: AstNode> {
136 _phantom: std::marker::PhantomData<N>, 234 _phantom: std::marker::PhantomData<N>,
137} 235}
@@ -149,6 +247,16 @@ impl AstBuilder<ast::NamedField> {
149 } 247 }
150} 248}
151 249
250impl AstBuilder<ast::Block> {
251 fn from_text(text: &str) -> TreeArc<ast::Block> {
252 ast_node_from_file_text(&format!("fn f() {}", text))
253 }
254
255 pub fn single_expr(e: &ast::Expr) -> TreeArc<ast::Block> {
256 Self::from_text(&format!("{{ {} }}", e.syntax()))
257 }
258}
259
152impl AstBuilder<ast::Expr> { 260impl AstBuilder<ast::Expr> {
153 fn from_text(text: &str) -> TreeArc<ast::Expr> { 261 fn from_text(text: &str) -> TreeArc<ast::Expr> {
154 ast_node_from_file_text(&format!("fn f() {{ {}; }}", text)) 262 ast_node_from_file_text(&format!("fn f() {{ {}; }}", text))
@@ -157,6 +265,10 @@ impl AstBuilder<ast::Expr> {
157 pub fn unit() -> TreeArc<ast::Expr> { 265 pub fn unit() -> TreeArc<ast::Expr> {
158 Self::from_text("()") 266 Self::from_text("()")
159 } 267 }
268
269 pub fn unimplemented() -> TreeArc<ast::Expr> {
270 Self::from_text("unimplemented!()")
271 }
160} 272}
161 273
162impl AstBuilder<ast::NameRef> { 274impl AstBuilder<ast::NameRef> {
@@ -197,6 +309,16 @@ mod tokens {
197 .unwrap() 309 .unwrap()
198 } 310 }
199 311
312 #[allow(unused)]
313 pub(crate) fn single_newline() -> SyntaxToken<'static> {
314 SOURCE_FILE
315 .syntax()
316 .descendants_with_tokens()
317 .filter_map(|it| it.as_token())
318 .find(|it| it.kind() == WHITESPACE && it.text().as_str() == "\n")
319 .unwrap()
320 }
321
200 pub(crate) struct WsBuilder(TreeArc<SourceFile>); 322 pub(crate) struct WsBuilder(TreeArc<SourceFile>);
201 323
202 impl WsBuilder { 324 impl WsBuilder {
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs
index 5c4c0ffc1..9cbd2c6b8 100644
--- a/crates/ra_syntax/src/ast/extensions.rs
+++ b/crates/ra_syntax/src/ast/extensions.rs
@@ -210,6 +210,15 @@ impl ast::EnumVariant {
210 } 210 }
211} 211}
212 212
213impl ast::FnDef {
214 pub fn semicolon_token(&self) -> Option<SyntaxToken<'_>> {
215 self.syntax()
216 .last_child_or_token()
217 .and_then(|it| it.as_token())
218 .filter(|it| it.kind() == SEMI)
219 }
220}
221
213impl ast::LetStmt { 222impl ast::LetStmt {
214 pub fn has_semi(&self) -> bool { 223 pub fn has_semi(&self) -> bool {
215 match self.syntax().last_child_or_token() { 224 match self.syntax().last_child_or_token() {
diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs
index 628cabc29..92c15234e 100644
--- a/crates/ra_syntax/src/syntax_node.rs
+++ b/crates/ra_syntax/src/syntax_node.rs
@@ -7,6 +7,7 @@
7//! modules just wraps its API. 7//! modules just wraps its API.
8 8
9use std::{ 9use std::{
10 ops::RangeInclusive,
10 fmt::{self, Write}, 11 fmt::{self, Write},
11 any::Any, 12 any::Any,
12 borrow::Borrow, 13 borrow::Borrow,
@@ -323,8 +324,6 @@ impl SyntaxNode {
323 /// 324 ///
324 /// This is a type-unsafe low-level editing API, if you need to use it, 325 /// This is a type-unsafe low-level editing API, if you need to use it,
325 /// prefer to create a type-safe abstraction on top of it instead. 326 /// prefer to create a type-safe abstraction on top of it instead.
326 ///
327 ///
328 pub fn insert_children<'a>( 327 pub fn insert_children<'a>(
329 &self, 328 &self,
330 position: InsertPosition<SyntaxElement<'_>>, 329 position: InsertPosition<SyntaxElement<'_>>,
@@ -338,12 +337,6 @@ impl SyntaxNode {
338 337
339 let old_children = self.0.green().children(); 338 let old_children = self.0.green().children();
340 339
341 let get_anchor_pos = |anchor: SyntaxElement| -> usize {
342 self.children_with_tokens()
343 .position(|it| it == anchor)
344 .expect("anchor is not a child of current element")
345 };
346
347 let new_children = match position { 340 let new_children = match position {
348 InsertPosition::First => { 341 InsertPosition::First => {
349 to_insert.chain(old_children.iter().cloned()).collect::<Box<[_]>>() 342 to_insert.chain(old_children.iter().cloned()).collect::<Box<[_]>>()
@@ -353,7 +346,8 @@ impl SyntaxNode {
353 } 346 }
354 InsertPosition::Before(anchor) | InsertPosition::After(anchor) => { 347 InsertPosition::Before(anchor) | InsertPosition::After(anchor) => {
355 let take_anchor = if let InsertPosition::After(_) = position { 1 } else { 0 }; 348 let take_anchor = if let InsertPosition::After(_) = position { 1 } else { 0 };
356 let (before, after) = old_children.split_at(get_anchor_pos(anchor) + take_anchor); 349 let split_at = self.position_of_child(anchor) + take_anchor;
350 let (before, after) = old_children.split_at(split_at);
357 before 351 before
358 .iter() 352 .iter()
359 .cloned() 353 .cloned()
@@ -363,6 +357,33 @@ impl SyntaxNode {
363 } 357 }
364 }; 358 };
365 359
360 self.with_children(new_children)
361 }
362
363 /// Replaces all nodes in `to_delete` with nodes from `to_insert`
364 ///
365 /// This is a type-unsafe low-level editing API, if you need to use it,
366 /// prefer to create a type-safe abstraction on top of it instead.
367 pub fn replace_children<'a>(
368 &self,
369 to_delete: RangeInclusive<SyntaxElement<'_>>,
370 to_insert: impl Iterator<Item = SyntaxElement<'a>>,
371 ) -> TreeArc<SyntaxNode> {
372 let start = self.position_of_child(*to_delete.start());
373 let end = self.position_of_child(*to_delete.end());
374 let old_children = self.0.green().children();
375
376 let new_children = old_children[..start]
377 .iter()
378 .cloned()
379 .chain(to_insert.map(to_green_element))
380 .chain(old_children[end + 1..].iter().cloned())
381 .collect::<Box<[_]>>();
382 self.with_children(new_children)
383 }
384
385 fn with_children(&self, new_children: Box<[rowan::GreenElement]>) -> TreeArc<SyntaxNode> {
386 let len = new_children.iter().map(|it| it.text_len()).sum::<TextUnit>();
366 let new_node = GreenNode::new(rowan::SyntaxKind(self.kind() as u16), new_children); 387 let new_node = GreenNode::new(rowan::SyntaxKind(self.kind() as u16), new_children);
367 let new_file_node = self.replace_with(new_node); 388 let new_file_node = self.replace_with(new_node);
368 let file = SourceFile::new(new_file_node, Vec::new()); 389 let file = SourceFile::new(new_file_node, Vec::new());
@@ -370,16 +391,22 @@ impl SyntaxNode {
370 // FIXME: use a more elegant way to re-fetch the node (#1185), make 391 // FIXME: use a more elegant way to re-fetch the node (#1185), make
371 // `range` private afterwards 392 // `range` private afterwards
372 let mut ptr = SyntaxNodePtr::new(self); 393 let mut ptr = SyntaxNodePtr::new(self);
373 ptr.range = TextRange::from_to(ptr.range().start(), ptr.range().end() + delta); 394 ptr.range = TextRange::offset_len(ptr.range().start(), len);
374 return ptr.to_node(&file).to_owned(); 395 return ptr.to_node(&file).to_owned();
396 }
375 397
376 fn to_green_element(element: SyntaxElement) -> rowan::GreenElement { 398 fn position_of_child(&self, child: SyntaxElement) -> usize {
377 match element { 399 self.children_with_tokens()
378 SyntaxElement::Node(node) => node.0.green().clone().into(), 400 .position(|it| it == child)
379 SyntaxElement::Token(tok) => { 401 .expect("elemetn is not a child of current element")
380 GreenToken::new(rowan::SyntaxKind(tok.kind() as u16), tok.text().clone()).into() 402 }
381 } 403}
382 } 404
405fn to_green_element(element: SyntaxElement) -> rowan::GreenElement {
406 match element {
407 SyntaxElement::Node(node) => node.0.green().clone().into(),
408 SyntaxElement::Token(tok) => {
409 GreenToken::new(rowan::SyntaxKind(tok.kind() as u16), tok.text().clone()).into()
383 } 410 }
384 } 411 }
385} 412}