bytebraise_syntax/syntax/
ted.rs

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