Skip to content

Commit db64919

Browse files
committed
handle merging two syntax editors together
1 parent 883e429 commit db64919

File tree

2 files changed

+39
-14
lines changed

2 files changed

+39
-14
lines changed

crates/syntax/src/syntax_editor.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,17 @@ impl SyntaxEditor {
3737
self.annotations.push((element.syntax_element(), annotation))
3838
}
3939

40-
pub fn combine(&mut self, other: SyntaxEditor) {
41-
todo!()
40+
pub fn merge(&mut self, mut other: SyntaxEditor) {
41+
debug_assert!(
42+
self.root == other.root || other.root.ancestors().any(|node| node == self.root),
43+
"{:?} is not in the same tree as {:?}",
44+
other.root,
45+
self.root
46+
);
47+
48+
self.changes.append(&mut other.changes);
49+
self.mappings.merge(other.mappings);
50+
self.annotations.append(&mut other.annotations);
4251
}
4352

4453
pub fn delete(&mut self, element: impl Element) {
@@ -290,7 +299,7 @@ mod tests {
290299
}
291300

292301
#[test]
293-
fn it() {
302+
fn basic_usage() {
294303
let root = make::match_arm(
295304
[make::wildcard_pat().into()],
296305
None,

crates/syntax/src/syntax_editor/mapping.rs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub struct SyntaxMapping {
1414

1515
// mappings -> parents
1616
entry_parents: Vec<SyntaxNode>,
17-
node_mappings: FxHashMap<SyntaxNode, (u32, u32)>,
17+
node_mappings: FxHashMap<SyntaxNode, MappingEntry>,
1818
}
1919

2020
impl SyntaxMapping {
@@ -80,11 +80,10 @@ impl SyntaxMapping {
8080
return None;
8181
}
8282

83-
if let Some(next) = self.upmap_node(&parent) {
84-
Some((parent.index(), next))
85-
} else {
86-
Some((parent.index(), parent))
87-
}
83+
Some((parent.index(), match self.upmap_node(&parent) {
84+
Some(next) => next,
85+
None => parent
86+
}))
8887
}).map(|(i, _)| i).collect::<Vec<_>>()
8988
} else {
9089
vec![]
@@ -100,7 +99,7 @@ impl SyntaxMapping {
10099
.children_with_tokens()
101100
.nth(index)
102101
.and_then(|it| it.into_node())
103-
.expect("yep");
102+
.expect("equivalent ancestor node should be present in target tree");
104103
}
105104

106105
debug_assert_eq!(child.kind(), target.kind());
@@ -109,7 +108,7 @@ impl SyntaxMapping {
109108
}
110109

111110
pub fn upmap_node(&self, input: &SyntaxNode) -> Option<SyntaxNode> {
112-
let (parent, child_slot) = self.node_mappings.get(input)?;
111+
let MappingEntry { parent, child_slot } = self.node_mappings.get(input)?;
113112

114113
let output = self.entry_parents[*parent as usize]
115114
.children_with_tokens()
@@ -121,14 +120,25 @@ impl SyntaxMapping {
121120
Some(output)
122121
}
123122

123+
pub fn merge(&mut self, mut other: SyntaxMapping) {
124+
// Remap other's entry parents to be after the current list of entry parents
125+
let remap_base: u32 = self.entry_parents.len().try_into().unwrap();
126+
127+
self.entry_parents.append(&mut other.entry_parents);
128+
self.node_mappings.extend(other.node_mappings.into_iter().map(|(node, entry)| {
129+
(node, MappingEntry { parent: entry.parent + remap_base, ..entry })
130+
}));
131+
}
132+
124133
fn add_mapping(&mut self, syntax_mapping: SyntaxMappingBuilder) {
125134
let SyntaxMappingBuilder { parent_node, node_mappings } = syntax_mapping;
126135

127-
let parent_entry: u32 = self.entry_parents.len() as u32;
136+
let parent_entry: u32 = self.entry_parents.len().try_into().unwrap();
128137
self.entry_parents.push(parent_node);
129138

130-
let node_entries =
131-
node_mappings.into_iter().map(|(node, slot)| (node, (parent_entry, slot)));
139+
let node_entries = node_mappings
140+
.into_iter()
141+
.map(|(node, slot)| (node, MappingEntry { parent: parent_entry, child_slot: slot }));
132142

133143
self.node_mappings.extend(node_entries);
134144
}
@@ -172,3 +182,9 @@ impl SyntaxMappingBuilder {
172182
editor.mappings.add_mapping(self);
173183
}
174184
}
185+
186+
#[derive(Debug, Clone, Copy)]
187+
struct MappingEntry {
188+
parent: u32,
189+
child_slot: u32,
190+
}

0 commit comments

Comments
 (0)