aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src')
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs9
-rw-r--r--crates/ra_syntax/src/lib.rs2
-rw-r--r--crates/ra_syntax/src/ptr.rs2
-rw-r--r--crates/ra_syntax/src/syntax_node.rs109
4 files changed, 119 insertions, 3 deletions
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/lib.rs b/crates/ra_syntax/src/lib.rs
index a6ce14f06..9cb66b76b 100644
--- a/crates/ra_syntax/src/lib.rs
+++ b/crates/ra_syntax/src/lib.rs
@@ -38,7 +38,7 @@ pub use crate::{
38 ast::AstNode, 38 ast::AstNode,
39 syntax_error::{SyntaxError, SyntaxErrorKind, Location}, 39 syntax_error::{SyntaxError, SyntaxErrorKind, Location},
40 syntax_text::SyntaxText, 40 syntax_text::SyntaxText,
41 syntax_node::{Direction, SyntaxNode, WalkEvent, TreeArc, SyntaxTreeBuilder, SyntaxElement, SyntaxToken}, 41 syntax_node::{Direction, SyntaxNode, WalkEvent, TreeArc, SyntaxTreeBuilder, SyntaxElement, SyntaxToken, InsertPosition},
42 ptr::{SyntaxNodePtr, AstPtr}, 42 ptr::{SyntaxNodePtr, AstPtr},
43 parsing::{tokenize, classify_literal, Token}, 43 parsing::{tokenize, classify_literal, Token},
44}; 44};
diff --git a/crates/ra_syntax/src/ptr.rs b/crates/ra_syntax/src/ptr.rs
index 15a8b94cd..b0816b135 100644
--- a/crates/ra_syntax/src/ptr.rs
+++ b/crates/ra_syntax/src/ptr.rs
@@ -10,7 +10,7 @@ use crate::{
10/// specific node across reparses of the same file. 10/// specific node across reparses of the same file.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub struct SyntaxNodePtr { 12pub struct SyntaxNodePtr {
13 range: TextRange, 13 pub(crate) range: TextRange,
14 kind: SyntaxKind, 14 kind: SyntaxKind,
15} 15}
16 16
diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs
index dc2352c76..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,
@@ -17,13 +18,21 @@ use ra_parser::ParseError;
17use rowan::{TransparentNewType, GreenNodeBuilder}; 18use rowan::{TransparentNewType, GreenNodeBuilder};
18 19
19use crate::{ 20use crate::{
20 SmolStr, SyntaxKind, TextUnit, TextRange, SyntaxText, SourceFile, AstNode, 21 SmolStr, SyntaxKind, TextUnit, TextRange, SyntaxText, SourceFile, AstNode, SyntaxNodePtr,
21 syntax_error::{SyntaxError, SyntaxErrorKind}, 22 syntax_error::{SyntaxError, SyntaxErrorKind},
22}; 23};
23 24
24pub use rowan::WalkEvent; 25pub use rowan::WalkEvent;
25pub(crate) use rowan::{GreenNode, GreenToken}; 26pub(crate) use rowan::{GreenNode, GreenToken};
26 27
28#[derive(Debug, PartialEq, Eq, Clone, Copy)]
29pub enum InsertPosition<T> {
30 First,
31 Last,
32 Before(T),
33 After(T),
34}
35
27/// Marker trait for CST and AST nodes 36/// Marker trait for CST and AST nodes
28pub trait SyntaxNodeWrapper: TransparentNewType<Repr = rowan::SyntaxNode> {} 37pub trait SyntaxNodeWrapper: TransparentNewType<Repr = rowan::SyntaxNode> {}
29impl<T: TransparentNewType<Repr = rowan::SyntaxNode>> SyntaxNodeWrapper for T {} 38impl<T: TransparentNewType<Repr = rowan::SyntaxNode>> SyntaxNodeWrapper for T {}
@@ -309,6 +318,97 @@ impl SyntaxNode {
309 pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode { 318 pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode {
310 self.0.replace_with(replacement) 319 self.0.replace_with(replacement)
311 } 320 }
321
322 /// Adds specified children (tokens or nodes) to the current node at the
323 /// specific position.
324 ///
325 /// This is a type-unsafe low-level editing API, if you need to use it,
326 /// prefer to create a type-safe abstraction on top of it instead.
327 pub fn insert_children<'a>(
328 &self,
329 position: InsertPosition<SyntaxElement<'_>>,
330 to_insert: impl Iterator<Item = SyntaxElement<'a>>,
331 ) -> TreeArc<SyntaxNode> {
332 let mut delta = TextUnit::default();
333 let to_insert = to_insert.map(|element| {
334 delta += element.text_len();
335 to_green_element(element)
336 });
337
338 let old_children = self.0.green().children();
339
340 let new_children = match position {
341 InsertPosition::First => {
342 to_insert.chain(old_children.iter().cloned()).collect::<Box<[_]>>()
343 }
344 InsertPosition::Last => {
345 old_children.iter().cloned().chain(to_insert).collect::<Box<[_]>>()
346 }
347 InsertPosition::Before(anchor) | InsertPosition::After(anchor) => {
348 let take_anchor = if let InsertPosition::After(_) = position { 1 } else { 0 };
349 let split_at = self.position_of_child(anchor) + take_anchor;
350 let (before, after) = old_children.split_at(split_at);
351 before
352 .iter()
353 .cloned()
354 .chain(to_insert)
355 .chain(after.iter().cloned())
356 .collect::<Box<[_]>>()
357 }
358 };
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>();
387 let new_node = GreenNode::new(rowan::SyntaxKind(self.kind() as u16), new_children);
388 let new_file_node = self.replace_with(new_node);
389 let file = SourceFile::new(new_file_node, Vec::new());
390
391 // FIXME: use a more elegant way to re-fetch the node (#1185), make
392 // `range` private afterwards
393 let mut ptr = SyntaxNodePtr::new(self);
394 ptr.range = TextRange::offset_len(ptr.range().start(), len);
395 return ptr.to_node(&file).to_owned();
396 }
397
398 fn position_of_child(&self, child: SyntaxElement) -> usize {
399 self.children_with_tokens()
400 .position(|it| it == child)
401 .expect("elemetn is not a child of current element")
402 }
403}
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()
410 }
411 }
312} 412}
313 413
314#[derive(Clone, Copy, PartialEq, Eq, Hash)] 414#[derive(Clone, Copy, PartialEq, Eq, Hash)]
@@ -451,6 +551,13 @@ impl<'a> SyntaxElement<'a> {
451 } 551 }
452 .ancestors() 552 .ancestors()
453 } 553 }
554
555 fn text_len(&self) -> TextUnit {
556 match self {
557 SyntaxElement::Node(node) => node.0.green().text_len(),
558 SyntaxElement::Token(token) => TextUnit::of_str(token.0.text()),
559 }
560 }
454} 561}
455 562
456impl<'a> From<rowan::SyntaxElement<'a>> for SyntaxElement<'a> { 563impl<'a> From<rowan::SyntaxElement<'a>> for SyntaxElement<'a> {