Unnamed repository; edit this file 'description' to name the repository.
support insert{_all}
DropDemBits 2024-09-03
parent 3440408 · commit 21bb04d
-rw-r--r--crates/syntax/src/syntax_editor.rs32
-rw-r--r--crates/syntax/src/syntax_editor/edit_algo.rs67
2 files changed, 88 insertions, 11 deletions
diff --git a/crates/syntax/src/syntax_editor.rs b/crates/syntax/src/syntax_editor.rs
index 75347aeeed..4b5134249c 100644
--- a/crates/syntax/src/syntax_editor.rs
+++ b/crates/syntax/src/syntax_editor.rs
@@ -50,6 +50,14 @@ impl SyntaxEditor {
self.annotations.append(&mut other.annotations);
}
+ pub fn insert(&mut self, position: Position, element: impl Element) {
+ self.changes.push(Change::Insert(position, element.syntax_element()))
+ }
+
+ pub fn insert_all(&mut self, position: Position, elements: Vec<SyntaxElement>) {
+ self.changes.push(Change::InsertAll(position, elements))
+ }
+
pub fn delete(&mut self, element: impl Element) {
self.changes.push(Change::Replace(element.syntax_element(), None));
}
@@ -117,6 +125,19 @@ pub struct Position {
repr: PositionRepr,
}
+impl Position {
+ pub(crate) fn parent(&self) -> SyntaxNode {
+ self.place().0
+ }
+
+ pub(crate) fn place(&self) -> (SyntaxNode, usize) {
+ match &self.repr {
+ PositionRepr::FirstChild(parent) => (parent.clone(), 0),
+ PositionRepr::After(child) => (child.parent().unwrap(), child.index() + 1),
+ }
+ }
+}
+
#[derive(Debug)]
enum PositionRepr {
FirstChild(SyntaxNode),
@@ -155,6 +176,8 @@ impl Position {
#[derive(Debug)]
enum Change {
+ Insert(Position, SyntaxElement),
+ InsertAll(Position, Vec<SyntaxElement>),
/// Represents both a replace single element and a delete element operation.
Replace(SyntaxElement, Option<SyntaxElement>),
}
@@ -162,18 +185,27 @@ enum Change {
impl Change {
fn target_range(&self) -> TextRange {
match self {
+ Change::Insert(target, _) | Change::InsertAll(target, _) => match &target.repr {
+ PositionRepr::FirstChild(parent) => TextRange::at(
+ parent.first_child_or_token().unwrap().text_range().start(),
+ 0.into(),
+ ),
+ PositionRepr::After(child) => TextRange::at(child.text_range().end(), 0.into()),
+ },
Change::Replace(target, _) => target.text_range(),
}
}
fn target_parent(&self) -> SyntaxNode {
match self {
+ Change::Insert(target, _) | Change::InsertAll(target, _) => target.parent(),
Change::Replace(target, _) => target.parent().unwrap(),
}
}
fn change_kind(&self) -> ChangeKind {
match self {
+ Change::Insert(_, _) | Change::InsertAll(_, _) => ChangeKind::Insert,
Change::Replace(_, _) => ChangeKind::Replace,
}
}
diff --git a/crates/syntax/src/syntax_editor/edit_algo.rs b/crates/syntax/src/syntax_editor/edit_algo.rs
index 734a26b600..4f0b30ed6a 100644
--- a/crates/syntax/src/syntax_editor/edit_algo.rs
+++ b/crates/syntax/src/syntax_editor/edit_algo.rs
@@ -4,8 +4,8 @@ use rowan::TextRange;
use rustc_hash::{FxHashMap, FxHashSet};
use crate::{
- syntax_editor::{mapping::MissingMapping, Change, ChangeKind},
- ted, SyntaxElement, SyntaxNode, SyntaxNodePtr,
+ syntax_editor::{mapping::MissingMapping, Change, ChangeKind, Position, PositionRepr},
+ SyntaxElement, SyntaxNode, SyntaxNodePtr,
};
use super::{SyntaxEdit, SyntaxEditor};
@@ -94,6 +94,7 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
// Add to changed ancestors, if applicable
match change {
+ Change::Insert(_, _) | Change::InsertAll(_, _) => {}
Change::Replace(target, _) => {
changed_ancestors.push_back(ChangedAncestor::single(target, change_index))
}
@@ -106,23 +107,46 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
for index in independent_changes {
match &mut changes[index as usize] {
- Change::Replace(target, new_node) => {
+ Change::Insert(target, _) | Change::InsertAll(target, _) => {
+ match &mut target.repr {
+ PositionRepr::FirstChild(parent) => {
+ *parent = tree_mutator.make_syntax_mut(parent);
+ }
+ PositionRepr::After(child) => {
+ *child = tree_mutator.make_element_mut(child);
+ }
+ };
+ }
+ Change::Replace(target, _) => {
*target = tree_mutator.make_element_mut(target);
-
- if let Some(new_node) = new_node {
- changed_elements.push(new_node.clone());
- }
}
}
+
+ // Collect changed elements
+ match &changes[index as usize] {
+ Change::Insert(_, element) => changed_elements.push(element.clone()),
+ Change::InsertAll(_, elements) => changed_elements.extend(elements.iter().cloned()),
+ Change::Replace(_, Some(element)) => changed_elements.push(element.clone()),
+ Change::Replace(_, None) => {}
+ }
}
for DependentChange { parent, child } in dependent_changes.into_iter() {
let (input_ancestor, output_ancestor) = match &changes[parent as usize] {
- // insert? unreachable
+ // No change will depend on an insert since changes can only depend on nodes in the root tree
+ Change::Insert(_, _) | Change::InsertAll(_, _) => unreachable!(),
Change::Replace(target, Some(new_target)) => {
(to_owning_node(target), to_owning_node(new_target))
}
- Change::Replace(_, None) => continue, // silently drop outdated change
+ // Silently drop outdated change
+ Change::Replace(_, None) => continue,
+ };
+
+ let upmap_target_node = |target: &SyntaxNode| {
+ match mappings.upmap_child(target, &input_ancestor, &output_ancestor) {
+ Ok(it) => it,
+ Err(MissingMapping(current)) => unreachable!("no mappings exist between {current:?} (ancestor of {input_ancestor:?}) and {output_ancestor:?}"),
+ }
};
let upmap_target = |target: &SyntaxElement| {
@@ -133,6 +157,14 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
};
match &mut changes[child as usize] {
+ Change::Insert(target, _) | Change::InsertAll(target, _) => match &mut target.repr {
+ PositionRepr::FirstChild(parent) => {
+ *parent = upmap_target_node(parent);
+ }
+ PositionRepr::After(child) => {
+ *child = upmap_target(child);
+ }
+ },
Change::Replace(target, _) => {
*target = upmap_target(&target);
}
@@ -142,8 +174,21 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
// Apply changes
for change in changes {
match change {
- Change::Replace(target, None) => ted::remove(target),
- Change::Replace(target, Some(new_target)) => ted::replace(target, new_target),
+ Change::Insert(position, element) => {
+ let (parent, index) = position.place();
+ parent.splice_children(index..index, vec![element]);
+ }
+ Change::InsertAll(position, elements) => {
+ let (parent, index) = position.place();
+ parent.splice_children(index..index, elements);
+ }
+ Change::Replace(target, None) => {
+ target.detach();
+ }
+ Change::Replace(target, Some(new_target)) => {
+ let parent = target.parent().unwrap();
+ parent.splice_children(target.index()..target.index() + 1, vec![new_target]);
+ }
}
}