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 240bba7b4838b..42373eba827d2 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 11c7b395b37c9..8a79f7e186eda 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, - node_mappings: FxHashMap, + node_mappings: FxHashMap, } 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::>() } 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 { - 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, +}