Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/syntax/src/syntax_editor.rs')
-rw-r--r--crates/syntax/src/syntax_editor.rs47
1 files changed, 40 insertions, 7 deletions
diff --git a/crates/syntax/src/syntax_editor.rs b/crates/syntax/src/syntax_editor.rs
index 77a560bfe5..3a05cc480b 100644
--- a/crates/syntax/src/syntax_editor.rs
+++ b/crates/syntax/src/syntax_editor.rs
@@ -6,6 +6,7 @@
use std::{
num::NonZeroU32,
+ ops::RangeInclusive,
sync::atomic::{AtomicU32, Ordering},
};
@@ -76,6 +77,26 @@ impl SyntaxEditor {
self.changes.push(Change::Replace(old.syntax_element(), Some(new.syntax_element())));
}
+ pub fn replace_with_many(&mut self, old: impl Element, new: Vec<SyntaxElement>) {
+ let old = old.syntax_element();
+ debug_assert!(is_ancestor_or_self_of_element(&old, &self.root));
+ debug_assert!(
+ !(matches!(&old, SyntaxElement::Node(node) if node == &self.root) && new.len() > 1),
+ "cannot replace root node with many elements"
+ );
+ self.changes.push(Change::ReplaceWithMany(old.syntax_element(), new));
+ }
+
+ pub fn replace_all(&mut self, range: RangeInclusive<SyntaxElement>, new: Vec<SyntaxElement>) {
+ if range.start() == range.end() {
+ self.replace_with_many(range.start(), new);
+ return;
+ }
+
+ debug_assert!(is_ancestor_or_self_of_element(range.start(), &self.root));
+ self.changes.push(Change::ReplaceAll(range, new))
+ }
+
pub fn finish(self) -> SyntaxEdit {
edit_algo::apply_edits(self)
}
@@ -186,10 +207,17 @@ impl Position {
#[derive(Debug)]
enum Change {
+ /// Inserts a single element at the specified position.
Insert(Position, SyntaxElement),
+ /// Inserts many elements in-order at the specified position.
InsertAll(Position, Vec<SyntaxElement>),
/// Represents both a replace single element and a delete element operation.
Replace(SyntaxElement, Option<SyntaxElement>),
+ /// Replaces a single element with many elements.
+ ReplaceWithMany(SyntaxElement, Vec<SyntaxElement>),
+ /// Replaces a range of elements with another list of elements.
+ /// Range will always have start != end.
+ ReplaceAll(RangeInclusive<SyntaxElement>, Vec<SyntaxElement>),
}
impl Change {
@@ -202,24 +230,29 @@ impl Change {
),
PositionRepr::After(child) => TextRange::at(child.text_range().end(), 0.into()),
},
- Change::Replace(target, _) => target.text_range(),
+ Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => target.text_range(),
+ Change::ReplaceAll(range, _) => {
+ range.start().text_range().cover(range.end().text_range())
+ }
}
}
fn target_parent(&self) -> SyntaxNode {
match self {
Change::Insert(target, _) | Change::InsertAll(target, _) => target.parent(),
- Change::Replace(SyntaxElement::Node(target), _) => {
- target.parent().unwrap_or_else(|| target.clone())
- }
- Change::Replace(SyntaxElement::Token(target), _) => target.parent().unwrap(),
+ Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => match target {
+ SyntaxElement::Node(target) => target.parent().unwrap_or_else(|| target.clone()),
+ SyntaxElement::Token(target) => target.parent().unwrap(),
+ },
+ Change::ReplaceAll(target, _) => target.start().parent().unwrap(),
}
}
fn change_kind(&self) -> ChangeKind {
match self {
Change::Insert(_, _) | Change::InsertAll(_, _) => ChangeKind::Insert,
- Change::Replace(_, _) => ChangeKind::Replace,
+ Change::Replace(_, _) | Change::ReplaceWithMany(_, _) => ChangeKind::Replace,
+ Change::ReplaceAll(_, _) => ChangeKind::ReplaceRange,
}
}
}
@@ -227,7 +260,7 @@ impl Change {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
enum ChangeKind {
Insert,
- // TODO: deal with replace spans
+ ReplaceRange,
Replace,
}