diff options
Diffstat (limited to 'crates/syntax/src/ted.rs')
-rw-r--r-- | crates/syntax/src/ted.rs | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/crates/syntax/src/ted.rs b/crates/syntax/src/ted.rs new file mode 100644 index 000000000..8d6175ed9 --- /dev/null +++ b/crates/syntax/src/ted.rs | |||
@@ -0,0 +1,78 @@ | |||
1 | //! Primitive tree editor, ed for trees | ||
2 | #![allow(unused)] | ||
3 | use std::ops::RangeInclusive; | ||
4 | |||
5 | use crate::{SyntaxElement, SyntaxNode}; | ||
6 | |||
7 | #[derive(Debug)] | ||
8 | pub struct Position { | ||
9 | repr: PositionRepr, | ||
10 | } | ||
11 | |||
12 | #[derive(Debug)] | ||
13 | enum PositionRepr { | ||
14 | FirstChild(SyntaxNode), | ||
15 | After(SyntaxElement), | ||
16 | } | ||
17 | |||
18 | impl Position { | ||
19 | pub fn after(elem: impl Into<SyntaxElement>) -> Position { | ||
20 | let repr = PositionRepr::After(elem.into()); | ||
21 | Position { repr } | ||
22 | } | ||
23 | pub fn before(elem: impl Into<SyntaxElement>) -> Position { | ||
24 | let elem = elem.into(); | ||
25 | let repr = match elem.prev_sibling_or_token() { | ||
26 | Some(it) => PositionRepr::After(it), | ||
27 | None => PositionRepr::FirstChild(elem.parent().unwrap()), | ||
28 | }; | ||
29 | Position { repr } | ||
30 | } | ||
31 | pub fn first_child_of(node: impl Into<SyntaxNode>) -> Position { | ||
32 | let repr = PositionRepr::FirstChild(node.into()); | ||
33 | Position { repr } | ||
34 | } | ||
35 | pub fn last_child_of(node: impl Into<SyntaxNode>) -> Position { | ||
36 | let node = node.into(); | ||
37 | let repr = match node.last_child_or_token() { | ||
38 | Some(it) => PositionRepr::After(it), | ||
39 | None => PositionRepr::FirstChild(node), | ||
40 | }; | ||
41 | Position { repr } | ||
42 | } | ||
43 | } | ||
44 | |||
45 | pub fn insert(position: Position, elem: impl Into<SyntaxElement>) { | ||
46 | insert_all(position, vec![elem.into()]) | ||
47 | } | ||
48 | pub fn insert_all(position: Position, elements: Vec<SyntaxElement>) { | ||
49 | let (parent, index) = match position.repr { | ||
50 | PositionRepr::FirstChild(parent) => (parent, 0), | ||
51 | PositionRepr::After(child) => (child.parent().unwrap(), child.index() + 1), | ||
52 | }; | ||
53 | parent.splice_children(index..index, elements); | ||
54 | } | ||
55 | |||
56 | pub fn remove(elem: impl Into<SyntaxElement>) { | ||
57 | let elem = elem.into(); | ||
58 | remove_all(elem.clone()..=elem) | ||
59 | } | ||
60 | pub fn remove_all(range: RangeInclusive<SyntaxElement>) { | ||
61 | replace_all(range, Vec::new()) | ||
62 | } | ||
63 | |||
64 | pub fn replace(old: impl Into<SyntaxElement>, new: impl Into<SyntaxElement>) { | ||
65 | let old = old.into(); | ||
66 | replace_all(old.clone()..=old, vec![new.into()]) | ||
67 | } | ||
68 | pub fn replace_all(range: RangeInclusive<SyntaxElement>, new: Vec<SyntaxElement>) { | ||
69 | let start = range.start().index(); | ||
70 | let end = range.end().index(); | ||
71 | let parent = range.start().parent().unwrap(); | ||
72 | parent.splice_children(start..end + 1, new) | ||
73 | } | ||
74 | |||
75 | pub fn append_child(node: impl Into<SyntaxNode>, child: impl Into<SyntaxElement>) { | ||
76 | let position = Position::last_child_of(node); | ||
77 | insert(position, child) | ||
78 | } | ||