]> git.lizzy.rs Git - rust.git/blob - crates/syntax/src/ted.rs
Merge #9489
[rust.git] / crates / syntax / src / ted.rs
1 //! Primitive tree editor, ed for trees.
2 //!
3 //! The `_raw`-suffixed functions insert elements as is, unsuffixed versions fix
4 //! up elements around the edges.
5 use std::{mem, ops::RangeInclusive};
6
7 use parser::T;
8
9 use crate::{
10     ast::{self, edit::IndentLevel, make, AstNode},
11     SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken,
12 };
13
14 /// Utility trait to allow calling `ted` functions with references or owned
15 /// nodes. Do not use outside of this module.
16 pub trait Element {
17     fn syntax_element(self) -> SyntaxElement;
18 }
19
20 impl<E: Element + Clone> Element for &'_ E {
21     fn syntax_element(self) -> SyntaxElement {
22         self.clone().syntax_element()
23     }
24 }
25 impl Element for SyntaxElement {
26     fn syntax_element(self) -> SyntaxElement {
27         self
28     }
29 }
30 impl Element for SyntaxNode {
31     fn syntax_element(self) -> SyntaxElement {
32         self.into()
33     }
34 }
35 impl Element for SyntaxToken {
36     fn syntax_element(self) -> SyntaxElement {
37         self.into()
38     }
39 }
40
41 #[derive(Debug)]
42 pub struct Position {
43     repr: PositionRepr,
44 }
45
46 #[derive(Debug)]
47 enum PositionRepr {
48     FirstChild(SyntaxNode),
49     After(SyntaxElement),
50 }
51
52 impl Position {
53     pub fn after(elem: impl Element) -> Position {
54         let repr = PositionRepr::After(elem.syntax_element());
55         Position { repr }
56     }
57     pub fn before(elem: impl Element) -> Position {
58         let elem = elem.syntax_element();
59         let repr = match elem.prev_sibling_or_token() {
60             Some(it) => PositionRepr::After(it),
61             None => PositionRepr::FirstChild(elem.parent().unwrap()),
62         };
63         Position { repr }
64     }
65     pub fn first_child_of(node: &(impl Into<SyntaxNode> + Clone)) -> Position {
66         let repr = PositionRepr::FirstChild(node.clone().into());
67         Position { repr }
68     }
69     pub fn last_child_of(node: &(impl Into<SyntaxNode> + Clone)) -> Position {
70         let node = node.clone().into();
71         let repr = match node.last_child_or_token() {
72             Some(it) => PositionRepr::After(it),
73             None => PositionRepr::FirstChild(node),
74         };
75         Position { repr }
76     }
77 }
78
79 pub fn insert(position: Position, elem: impl Element) {
80     insert_all(position, vec![elem.syntax_element()])
81 }
82 pub fn insert_raw(position: Position, elem: impl Element) {
83     insert_all_raw(position, vec![elem.syntax_element()])
84 }
85 pub fn insert_all(position: Position, mut elements: Vec<SyntaxElement>) {
86     if let Some(first) = elements.first() {
87         if let Some(ws) = ws_before(&position, first) {
88             elements.insert(0, ws.into())
89         }
90     }
91     if let Some(last) = elements.last() {
92         if let Some(ws) = ws_after(&position, last) {
93             elements.push(ws.into())
94         }
95     }
96     insert_all_raw(position, elements)
97 }
98 pub fn insert_all_raw(position: Position, elements: Vec<SyntaxElement>) {
99     let (parent, index) = match position.repr {
100         PositionRepr::FirstChild(parent) => (parent, 0),
101         PositionRepr::After(child) => (child.parent().unwrap(), child.index() + 1),
102     };
103     parent.splice_children(index..index, elements);
104 }
105
106 pub fn remove(elem: impl Element) {
107     elem.syntax_element().detach()
108 }
109 pub fn remove_all(range: RangeInclusive<SyntaxElement>) {
110     replace_all(range, Vec::new())
111 }
112 pub fn remove_all_iter(range: impl IntoIterator<Item = SyntaxElement>) {
113     let mut it = range.into_iter();
114     if let Some(mut first) = it.next() {
115         match it.last() {
116             Some(mut last) => {
117                 if first.index() > last.index() {
118                     mem::swap(&mut first, &mut last)
119                 }
120                 remove_all(first..=last)
121             }
122             None => remove(first),
123         }
124     }
125 }
126
127 pub fn replace(old: impl Element, new: impl Element) {
128     replace_with_many(old, vec![new.syntax_element()])
129 }
130 pub fn replace_with_many(old: impl Element, new: Vec<SyntaxElement>) {
131     let old = old.syntax_element();
132     replace_all(old.clone()..=old, new)
133 }
134 pub fn replace_all(range: RangeInclusive<SyntaxElement>, new: Vec<SyntaxElement>) {
135     let start = range.start().index();
136     let end = range.end().index();
137     let parent = range.start().parent().unwrap();
138     parent.splice_children(start..end + 1, new)
139 }
140
141 pub fn append_child(node: &(impl Into<SyntaxNode> + Clone), child: impl Element) {
142     let position = Position::last_child_of(node);
143     insert(position, child)
144 }
145 pub fn append_child_raw(node: &(impl Into<SyntaxNode> + Clone), child: impl Element) {
146     let position = Position::last_child_of(node);
147     insert_raw(position, child)
148 }
149
150 fn ws_before(position: &Position, new: &SyntaxElement) -> Option<SyntaxToken> {
151     let prev = match &position.repr {
152         PositionRepr::FirstChild(_) => return None,
153         PositionRepr::After(it) if it.kind() == SyntaxKind::L_CURLY => {
154             if new.kind() == SyntaxKind::USE {
155                 if let Some(item_list) = it.parent().and_then(ast::ItemList::cast) {
156                     let mut indent = IndentLevel::from_element(&item_list.syntax().clone().into());
157                     indent.0 += 1;
158                     return Some(make::tokens::whitespace(&format!("\n{}", indent)));
159                 }
160             }
161             it
162         }
163         PositionRepr::After(it) => it,
164     };
165     ws_between(prev, new)
166 }
167 fn ws_after(position: &Position, new: &SyntaxElement) -> Option<SyntaxToken> {
168     let next = match &position.repr {
169         PositionRepr::FirstChild(parent) => parent.first_child_or_token()?,
170         PositionRepr::After(sibling) => sibling.next_sibling_or_token()?,
171     };
172     ws_between(new, &next)
173 }
174 fn ws_between(left: &SyntaxElement, right: &SyntaxElement) -> Option<SyntaxToken> {
175     if left.kind() == SyntaxKind::WHITESPACE || right.kind() == SyntaxKind::WHITESPACE {
176         return None;
177     }
178     if right.kind() == T![;] || right.kind() == T![,] {
179         return None;
180     }
181     if left.kind() == T![<] || right.kind() == T![>] {
182         return None;
183     }
184     if left.kind() == T![&] && right.kind() == SyntaxKind::LIFETIME {
185         return None;
186     }
187     if right.kind() == SyntaxKind::GENERIC_ARG_LIST {
188         return None;
189     }
190
191     if right.kind() == SyntaxKind::USE {
192         let mut indent = IndentLevel::from_element(left);
193         if left.kind() == SyntaxKind::USE {
194             indent.0 = IndentLevel::from_element(right).0.max(indent.0);
195         }
196         return Some(make::tokens::whitespace(&format!("\n{}", indent)));
197     }
198     Some(make::tokens::single_space())
199 }