Skip to content

Commit 3440408

Browse files
committed
propagate annotations to mapped elements
1 parent db64919 commit 3440408

File tree

3 files changed

+168
-52
lines changed

3 files changed

+168
-52
lines changed

crates/syntax/src/syntax_editor.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ impl SyntaxEdit {
7575
&self.root
7676
}
7777

78-
/// Which syntax elements in the modified syntax tree were modified as part
79-
/// of the edit.
78+
/// Which syntax elements in the modified syntax tree were inserted or
79+
/// modified as part of the edit.
8080
///
8181
/// Note that for syntax nodes, only the upper-most parent of a set of
8282
/// changes is included, not any child elements that may have been modified.
@@ -343,11 +343,22 @@ mod tests {
343343
editor.replace(to_wrap.syntax(), new_block.syntax());
344344
// editor.replace(to_replace.syntax(), name_ref.syntax());
345345

346-
// dbg!(&editor.mappings);
347346
let edit = editor.finish();
348347

349-
let expect = expect![];
348+
dbg!(&edit.annotations);
349+
350+
let expect = expect![[r#"
351+
_ => {
352+
let var_name = 2 + 2;
353+
(var_name, true)
354+
}"#]];
350355
expect.assert_eq(&edit.root.to_string());
356+
351357
assert_eq!(edit.find_annotation(placeholder_snippet).len(), 2);
358+
assert!(edit
359+
.annotations
360+
.iter()
361+
.flat_map(|(_, elements)| elements)
362+
.all(|element| element.ancestors().any(|it| &it == edit.root())))
352363
}
353364
}

crates/syntax/src/syntax_editor/edit_algo.rs

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use std::{collections::VecDeque, ops::RangeInclusive};
22

33
use rowan::TextRange;
4+
use rustc_hash::{FxHashMap, FxHashSet};
45

56
use crate::{
6-
syntax_editor::{Change, ChangeKind},
7+
syntax_editor::{mapping::MissingMapping, Change, ChangeKind},
78
ted, SyntaxElement, SyntaxNode, SyntaxNodePtr,
89
};
910

@@ -29,9 +30,6 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
2930

3031
let SyntaxEditor { root, mut changes, mappings, annotations } = editor;
3132

32-
dbg!(("initial: ", &root));
33-
dbg!(&changes);
34-
3533
// Sort changes by range then change kind, so that we can:
3634
// - ensure that parent edits are ordered before child edits
3735
// - ensure that inserts will be guaranteed to be inserted at the right range
@@ -102,15 +100,18 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
102100
}
103101
}
104102

105-
dbg!(("before: ", &changes, &dependent_changes, &independent_changes));
106-
107103
// Map change targets to the correct syntax nodes
108104
let tree_mutator = TreeMutator::new(&root);
105+
let mut changed_elements = vec![];
109106

110107
for index in independent_changes {
111108
match &mut changes[index as usize] {
112-
Change::Replace(target, _) => {
109+
Change::Replace(target, new_node) => {
113110
*target = tree_mutator.make_element_mut(target);
111+
112+
if let Some(new_node) = new_node {
113+
changed_elements.push(new_node.clone());
114+
}
114115
}
115116
}
116117
}
@@ -124,15 +125,20 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
124125
Change::Replace(_, None) => continue, // silently drop outdated change
125126
};
126127

128+
let upmap_target = |target: &SyntaxElement| {
129+
match mappings.upmap_child_element(target, &input_ancestor, &output_ancestor) {
130+
Ok(it) => it,
131+
Err(MissingMapping(current)) => unreachable!("no mappings exist between {current:?} (ancestor of {input_ancestor:?}) and {output_ancestor:?}"),
132+
}
133+
};
134+
127135
match &mut changes[child as usize] {
128136
Change::Replace(target, _) => {
129-
*target = mappings.upmap_child_element(target, &input_ancestor, output_ancestor)
137+
*target = upmap_target(&target);
130138
}
131139
}
132140
}
133141

134-
dbg!(("after: ", &changes));
135-
136142
// Apply changes
137143
for change in changes {
138144
match change {
@@ -141,9 +147,29 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
141147
}
142148
}
143149

144-
dbg!(("modified:", tree_mutator.mutable_clone));
150+
// Propagate annotations
151+
let annotations = annotations.into_iter().filter_map(|(element, annotation)| {
152+
match mappings.upmap_element(&element, &tree_mutator.mutable_clone) {
153+
// Needed to follow the new tree to find the resulting element
154+
Some(Ok(mapped)) => Some((mapped, annotation)),
155+
// Element did not need to be mapped
156+
None => Some((element, annotation)),
157+
// Element did not make it to the final tree
158+
Some(Err(_)) => None,
159+
}
160+
});
161+
162+
let mut annotation_groups = FxHashMap::default();
145163

146-
todo!("draw the rest of the owl")
164+
for (element, annotation) in annotations {
165+
annotation_groups.entry(annotation).or_insert(vec![]).push(element);
166+
}
167+
168+
SyntaxEdit {
169+
root: tree_mutator.mutable_clone,
170+
changed_elements,
171+
annotations: annotation_groups,
172+
}
147173
}
148174

149175
fn to_owning_node(element: &SyntaxElement) -> SyntaxNode {

crates/syntax/src/syntax_editor/mapping.rs

Lines changed: 115 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -22,41 +22,47 @@ impl SyntaxMapping {
2222
Self::default()
2323
}
2424

25+
/// Like [`SyntaxMapping::upmap_child`] but for syntax elements.
2526
pub fn upmap_child_element(
2627
&self,
2728
child: &SyntaxElement,
2829
input_ancestor: &SyntaxNode,
29-
output_ancestor: SyntaxNode,
30-
) -> SyntaxElement {
30+
output_ancestor: &SyntaxNode,
31+
) -> Result<SyntaxElement, MissingMapping> {
3132
match child {
3233
SyntaxElement::Node(node) => {
33-
SyntaxElement::Node(self.upmap_child(node, input_ancestor, output_ancestor))
34+
self.upmap_child(node, input_ancestor, output_ancestor).map(SyntaxElement::Node)
3435
}
3536
SyntaxElement::Token(token) => {
3637
let upmap_parent =
37-
self.upmap_child(&token.parent().unwrap(), input_ancestor, output_ancestor);
38+
self.upmap_child(&token.parent().unwrap(), input_ancestor, output_ancestor)?;
3839

3940
let element = upmap_parent.children_with_tokens().nth(token.index()).unwrap();
4041
debug_assert!(
4142
element.as_token().is_some_and(|it| it.kind() == token.kind()),
4243
"token upmapping mapped to the wrong node ({token:?} -> {element:?})"
4344
);
4445

45-
element
46+
Ok(element)
4647
}
4748
}
4849
}
4950

51+
/// Maps a child node of the input ancestor to the corresponding node in
52+
/// the output ancestor.
5053
pub fn upmap_child(
5154
&self,
5255
child: &SyntaxNode,
5356
input_ancestor: &SyntaxNode,
54-
output_ancestor: SyntaxNode,
55-
) -> SyntaxNode {
56-
debug_assert!(child.ancestors().any(|ancestor| &ancestor == input_ancestor));
57+
output_ancestor: &SyntaxNode,
58+
) -> Result<SyntaxNode, MissingMapping> {
59+
debug_assert!(
60+
child == input_ancestor
61+
|| child.ancestors().any(|ancestor| &ancestor == input_ancestor)
62+
);
5763

5864
// Build a list mapping up to the first mappable ancestor
59-
let to_first_upmap =
65+
let to_first_upmap = if child != input_ancestor {
6066
std::iter::successors(Some((child.index(), child.clone())), |(_, current)| {
6167
let parent = current.parent().unwrap();
6268

@@ -67,32 +73,22 @@ impl SyntaxMapping {
6773
Some((parent.index(), parent))
6874
})
6975
.map(|(i, _)| i)
70-
.collect::<Vec<_>>();
76+
.collect::<Vec<_>>()
77+
} else {
78+
vec![]
79+
};
7180

7281
// Progressively up-map the input ancestor until we get to the output ancestor
73-
let to_output_ancestor = if input_ancestor != &output_ancestor {
74-
std::iter::successors(Some((input_ancestor.index(), self.upmap_node(input_ancestor).unwrap_or_else(|| input_ancestor.clone()))), |(_, current)| {
75-
let Some(parent) = current.parent() else {
76-
unreachable!("no mappings exist between {current:?} (ancestor of {input_ancestor:?}) and {output_ancestor:?}")
77-
};
78-
79-
if &parent == &output_ancestor {
80-
return None;
81-
}
82-
83-
Some((parent.index(), match self.upmap_node(&parent) {
84-
Some(next) => next,
85-
None => parent
86-
}))
87-
}).map(|(i, _)| i).collect::<Vec<_>>()
82+
let to_output_ancestor = if input_ancestor != output_ancestor {
83+
self.upmap_to_ancestor(input_ancestor, output_ancestor)?
8884
} else {
8985
vec![]
9086
};
9187

9288
let to_map_down =
9389
to_output_ancestor.into_iter().rev().chain(to_first_upmap.into_iter().rev());
9490

95-
let mut target = output_ancestor;
91+
let mut target = output_ancestor.clone();
9692

9793
for index in to_map_down {
9894
target = target
@@ -104,20 +100,86 @@ impl SyntaxMapping {
104100

105101
debug_assert_eq!(child.kind(), target.kind());
106102

107-
target
103+
Ok(target)
108104
}
109105

110-
pub fn upmap_node(&self, input: &SyntaxNode) -> Option<SyntaxNode> {
111-
let MappingEntry { parent, child_slot } = self.node_mappings.get(input)?;
106+
fn upmap_to_ancestor(
107+
&self,
108+
input_ancestor: &SyntaxNode,
109+
output_ancestor: &SyntaxNode,
110+
) -> Result<Vec<usize>, MissingMapping> {
111+
eprintln!("mapping ancestor {input_ancestor:#?} to {output_ancestor:#?}");
112+
let mut current =
113+
self.upmap_node_single(input_ancestor).unwrap_or_else(|| input_ancestor.clone());
114+
let mut upmap_chain = vec![current.index()];
115+
116+
loop {
117+
let Some(parent) = current.parent() else { break };
118+
119+
if &parent == output_ancestor {
120+
return Ok(upmap_chain);
121+
}
112122

113-
let output = self.entry_parents[*parent as usize]
114-
.children_with_tokens()
115-
.nth(*child_slot as usize)
116-
.and_then(SyntaxElement::into_node)
117-
.unwrap();
123+
current = match self.upmap_node_single(&parent) {
124+
Some(next) => next,
125+
None => parent,
126+
};
127+
upmap_chain.push(current.index());
128+
}
118129

119-
debug_assert_eq!(input.kind(), output.kind());
120-
Some(output)
130+
Err(MissingMapping(current))
131+
}
132+
133+
pub fn upmap_element(
134+
&self,
135+
input: &SyntaxElement,
136+
output_root: &SyntaxNode,
137+
) -> Option<Result<SyntaxElement, MissingMapping>> {
138+
match input {
139+
SyntaxElement::Node(node) => {
140+
Some(self.upmap_node(node, output_root)?.map(SyntaxElement::Node))
141+
}
142+
SyntaxElement::Token(token) => {
143+
let upmap_parent = match self.upmap_node(&token.parent().unwrap(), output_root)? {
144+
Ok(it) => it,
145+
Err(err) => return Some(Err(err)),
146+
};
147+
148+
let element = upmap_parent.children_with_tokens().nth(token.index()).unwrap();
149+
debug_assert!(
150+
element.as_token().is_some_and(|it| it.kind() == token.kind()),
151+
"token upmapping mapped to the wrong node ({token:?} -> {element:?})"
152+
);
153+
154+
Some(Ok(element))
155+
}
156+
}
157+
}
158+
159+
pub fn upmap_node(
160+
&self,
161+
input: &SyntaxNode,
162+
output_root: &SyntaxNode,
163+
) -> Option<Result<SyntaxNode, MissingMapping>> {
164+
// Try to follow the mapping tree, if it exists
165+
let input_mapping = self.upmap_node_single(input);
166+
let input_ancestor =
167+
input.ancestors().find_map(|ancestor| self.upmap_node_single(&ancestor));
168+
169+
match (input_mapping, input_ancestor) {
170+
(Some(input_mapping), _) => {
171+
// A mapping exists at the input, follow along the tree
172+
Some(self.upmap_child(&input_mapping, &input_mapping, &output_root))
173+
}
174+
(None, Some(input_ancestor)) => {
175+
// A mapping exists at an ancestor, follow along the tree
176+
Some(self.upmap_child(input, &input_ancestor, &output_root))
177+
}
178+
(None, None) => {
179+
// No mapping exists at all, is the same position in the final tree
180+
None
181+
}
182+
}
121183
}
122184

123185
pub fn merge(&mut self, mut other: SyntaxMapping) {
@@ -130,6 +192,20 @@ impl SyntaxMapping {
130192
}));
131193
}
132194

195+
/// Follows the input one step along the syntax mapping tree
196+
fn upmap_node_single(&self, input: &SyntaxNode) -> Option<SyntaxNode> {
197+
let MappingEntry { parent, child_slot } = self.node_mappings.get(input)?;
198+
199+
let output = self.entry_parents[*parent as usize]
200+
.children_with_tokens()
201+
.nth(*child_slot as usize)
202+
.and_then(SyntaxElement::into_node)
203+
.unwrap();
204+
205+
debug_assert_eq!(input.kind(), output.kind());
206+
Some(output)
207+
}
208+
133209
fn add_mapping(&mut self, syntax_mapping: SyntaxMappingBuilder) {
134210
let SyntaxMappingBuilder { parent_node, node_mappings } = syntax_mapping;
135211

@@ -183,6 +259,9 @@ impl SyntaxMappingBuilder {
183259
}
184260
}
185261

262+
#[derive(Debug)]
263+
pub struct MissingMapping(pub SyntaxNode);
264+
186265
#[derive(Debug, Clone, Copy)]
187266
struct MappingEntry {
188267
parent: u32,

0 commit comments

Comments
 (0)