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