aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/syntax_node.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/syntax_node.rs')
-rw-r--r--crates/ra_syntax/src/syntax_node.rs61
1 files changed, 44 insertions, 17 deletions
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}