about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorDropDemBits <r3usrlnd@gmail.com>2024-09-02 00:01:24 -0400
committerDropDemBits <r3usrlnd@gmail.com>2024-09-02 00:09:30 -0400
commit2094a2b117fa0a00a3dcb0a239954b84eeda031c (patch)
treee8a208adb8465e5b58f5f51f619c4a3872e7021b /src
parent5e33650b7277543d793a9abe69b298e73b7531e7 (diff)
downloadrust-2094a2b117fa0a00a3dcb0a239954b84eeda031c.tar.gz
rust-2094a2b117fa0a00a3dcb0a239954b84eeda031c.zip
handle merging two syntax editors together
Diffstat (limited to 'src')
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs15
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs38
2 files changed, 39 insertions, 14 deletions
diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
index 240bba7b483..42373eba827 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs
@@ -37,8 +37,17 @@ impl SyntaxEditor {
         self.annotations.push((element.syntax_element(), annotation))
     }
 
-    pub fn combine(&mut self, other: SyntaxEditor) {
-        todo!()
+    pub fn merge(&mut self, mut other: SyntaxEditor) {
+        debug_assert!(
+            self.root == other.root || other.root.ancestors().any(|node| node == self.root),
+            "{:?} is not in the same tree as {:?}",
+            other.root,
+            self.root
+        );
+
+        self.changes.append(&mut other.changes);
+        self.mappings.merge(other.mappings);
+        self.annotations.append(&mut other.annotations);
     }
 
     pub fn delete(&mut self, element: impl Element) {
@@ -290,7 +299,7 @@ mod tests {
     }
 
     #[test]
-    fn it() {
+    fn basic_usage() {
         let root = make::match_arm(
             [make::wildcard_pat().into()],
             None,
diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs
index 11c7b395b37..8a79f7e186e 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/mapping.rs
@@ -14,7 +14,7 @@ pub struct SyntaxMapping {
 
     // mappings ->  parents
     entry_parents: Vec<SyntaxNode>,
-    node_mappings: FxHashMap<SyntaxNode, (u32, u32)>,
+    node_mappings: FxHashMap<SyntaxNode, MappingEntry>,
 }
 
 impl SyntaxMapping {
@@ -80,11 +80,10 @@ impl SyntaxMapping {
                     return None;
                 }
 
-                if let Some(next) = self.upmap_node(&parent) {
-                    Some((parent.index(), next))
-                } else {
-                    Some((parent.index(), parent))
-                }
+                Some((parent.index(), match self.upmap_node(&parent) {
+                    Some(next) => next,
+                    None => parent
+                }))
             }).map(|(i, _)| i).collect::<Vec<_>>()
         } else {
             vec![]
@@ -100,7 +99,7 @@ impl SyntaxMapping {
                 .children_with_tokens()
                 .nth(index)
                 .and_then(|it| it.into_node())
-                .expect("yep");
+                .expect("equivalent ancestor node should be present in target tree");
         }
 
         debug_assert_eq!(child.kind(), target.kind());
@@ -109,7 +108,7 @@ impl SyntaxMapping {
     }
 
     pub fn upmap_node(&self, input: &SyntaxNode) -> Option<SyntaxNode> {
-        let (parent, child_slot) = self.node_mappings.get(input)?;
+        let MappingEntry { parent, child_slot } = self.node_mappings.get(input)?;
 
         let output = self.entry_parents[*parent as usize]
             .children_with_tokens()
@@ -121,14 +120,25 @@ impl SyntaxMapping {
         Some(output)
     }
 
+    pub fn merge(&mut self, mut other: SyntaxMapping) {
+        // Remap other's entry parents to be after the current list of entry parents
+        let remap_base: u32 = self.entry_parents.len().try_into().unwrap();
+
+        self.entry_parents.append(&mut other.entry_parents);
+        self.node_mappings.extend(other.node_mappings.into_iter().map(|(node, entry)| {
+            (node, MappingEntry { parent: entry.parent + remap_base, ..entry })
+        }));
+    }
+
     fn add_mapping(&mut self, syntax_mapping: SyntaxMappingBuilder) {
         let SyntaxMappingBuilder { parent_node, node_mappings } = syntax_mapping;
 
-        let parent_entry: u32 = self.entry_parents.len() as u32;
+        let parent_entry: u32 = self.entry_parents.len().try_into().unwrap();
         self.entry_parents.push(parent_node);
 
-        let node_entries =
-            node_mappings.into_iter().map(|(node, slot)| (node, (parent_entry, slot)));
+        let node_entries = node_mappings
+            .into_iter()
+            .map(|(node, slot)| (node, MappingEntry { parent: parent_entry, child_slot: slot }));
 
         self.node_mappings.extend(node_entries);
     }
@@ -172,3 +182,9 @@ impl SyntaxMappingBuilder {
         editor.mappings.add_mapping(self);
     }
 }
+
+#[derive(Debug, Clone, Copy)]
+struct MappingEntry {
+    parent: u32,
+    child_slot: u32,
+}