Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/syntax/src/syntax_editor/mapping.rs')
| -rw-r--r-- | crates/syntax/src/syntax_editor/mapping.rs | 151 |
1 files changed, 115 insertions, 36 deletions
diff --git a/crates/syntax/src/syntax_editor/mapping.rs b/crates/syntax/src/syntax_editor/mapping.rs index 8a79f7e186..f14d0b347d 100644 --- a/crates/syntax/src/syntax_editor/mapping.rs +++ b/crates/syntax/src/syntax_editor/mapping.rs @@ -22,19 +22,20 @@ impl SyntaxMapping { Self::default() } + /// Like [`SyntaxMapping::upmap_child`] but for syntax elements. pub fn upmap_child_element( &self, child: &SyntaxElement, input_ancestor: &SyntaxNode, - output_ancestor: SyntaxNode, - ) -> SyntaxElement { + output_ancestor: &SyntaxNode, + ) -> Result<SyntaxElement, MissingMapping> { match child { SyntaxElement::Node(node) => { - SyntaxElement::Node(self.upmap_child(node, input_ancestor, output_ancestor)) + self.upmap_child(node, input_ancestor, output_ancestor).map(SyntaxElement::Node) } SyntaxElement::Token(token) => { let upmap_parent = - self.upmap_child(&token.parent().unwrap(), input_ancestor, output_ancestor); + self.upmap_child(&token.parent().unwrap(), input_ancestor, output_ancestor)?; let element = upmap_parent.children_with_tokens().nth(token.index()).unwrap(); debug_assert!( @@ -42,21 +43,26 @@ impl SyntaxMapping { "token upmapping mapped to the wrong node ({token:?} -> {element:?})" ); - element + Ok(element) } } } + /// Maps a child node of the input ancestor to the corresponding node in + /// the output ancestor. pub fn upmap_child( &self, child: &SyntaxNode, input_ancestor: &SyntaxNode, - output_ancestor: SyntaxNode, - ) -> SyntaxNode { - debug_assert!(child.ancestors().any(|ancestor| &ancestor == input_ancestor)); + output_ancestor: &SyntaxNode, + ) -> Result<SyntaxNode, MissingMapping> { + debug_assert!( + child == input_ancestor + || child.ancestors().any(|ancestor| &ancestor == input_ancestor) + ); // Build a list mapping up to the first mappable ancestor - let to_first_upmap = + let to_first_upmap = if child != input_ancestor { std::iter::successors(Some((child.index(), child.clone())), |(_, current)| { let parent = current.parent().unwrap(); @@ -67,24 +73,14 @@ impl SyntaxMapping { Some((parent.index(), parent)) }) .map(|(i, _)| i) - .collect::<Vec<_>>(); + .collect::<Vec<_>>() + } else { + vec![] + }; // Progressively up-map the input ancestor until we get to the output ancestor - let to_output_ancestor = if input_ancestor != &output_ancestor { - std::iter::successors(Some((input_ancestor.index(), self.upmap_node(input_ancestor).unwrap_or_else(|| input_ancestor.clone()))), |(_, current)| { - let Some(parent) = current.parent() else { - unreachable!("no mappings exist between {current:?} (ancestor of {input_ancestor:?}) and {output_ancestor:?}") - }; - - if &parent == &output_ancestor { - return None; - } - - Some((parent.index(), match self.upmap_node(&parent) { - Some(next) => next, - None => parent - })) - }).map(|(i, _)| i).collect::<Vec<_>>() + let to_output_ancestor = if input_ancestor != output_ancestor { + self.upmap_to_ancestor(input_ancestor, output_ancestor)? } else { vec![] }; @@ -92,7 +88,7 @@ impl SyntaxMapping { let to_map_down = to_output_ancestor.into_iter().rev().chain(to_first_upmap.into_iter().rev()); - let mut target = output_ancestor; + let mut target = output_ancestor.clone(); for index in to_map_down { target = target @@ -104,20 +100,86 @@ impl SyntaxMapping { debug_assert_eq!(child.kind(), target.kind()); - target + Ok(target) } - pub fn upmap_node(&self, input: &SyntaxNode) -> Option<SyntaxNode> { - let MappingEntry { parent, child_slot } = self.node_mappings.get(input)?; + fn upmap_to_ancestor( + &self, + input_ancestor: &SyntaxNode, + output_ancestor: &SyntaxNode, + ) -> Result<Vec<usize>, MissingMapping> { + eprintln!("mapping ancestor {input_ancestor:#?} to {output_ancestor:#?}"); + let mut current = + self.upmap_node_single(input_ancestor).unwrap_or_else(|| input_ancestor.clone()); + let mut upmap_chain = vec![current.index()]; + + loop { + let Some(parent) = current.parent() else { break }; + + if &parent == output_ancestor { + return Ok(upmap_chain); + } - let output = self.entry_parents[*parent as usize] - .children_with_tokens() - .nth(*child_slot as usize) - .and_then(SyntaxElement::into_node) - .unwrap(); + current = match self.upmap_node_single(&parent) { + Some(next) => next, + None => parent, + }; + upmap_chain.push(current.index()); + } - debug_assert_eq!(input.kind(), output.kind()); - Some(output) + Err(MissingMapping(current)) + } + + pub fn upmap_element( + &self, + input: &SyntaxElement, + output_root: &SyntaxNode, + ) -> Option<Result<SyntaxElement, MissingMapping>> { + match input { + SyntaxElement::Node(node) => { + Some(self.upmap_node(node, output_root)?.map(SyntaxElement::Node)) + } + SyntaxElement::Token(token) => { + let upmap_parent = match self.upmap_node(&token.parent().unwrap(), output_root)? { + Ok(it) => it, + Err(err) => return Some(Err(err)), + }; + + let element = upmap_parent.children_with_tokens().nth(token.index()).unwrap(); + debug_assert!( + element.as_token().is_some_and(|it| it.kind() == token.kind()), + "token upmapping mapped to the wrong node ({token:?} -> {element:?})" + ); + + Some(Ok(element)) + } + } + } + + pub fn upmap_node( + &self, + input: &SyntaxNode, + output_root: &SyntaxNode, + ) -> Option<Result<SyntaxNode, MissingMapping>> { + // Try to follow the mapping tree, if it exists + let input_mapping = self.upmap_node_single(input); + let input_ancestor = + input.ancestors().find_map(|ancestor| self.upmap_node_single(&ancestor)); + + match (input_mapping, input_ancestor) { + (Some(input_mapping), _) => { + // A mapping exists at the input, follow along the tree + Some(self.upmap_child(&input_mapping, &input_mapping, &output_root)) + } + (None, Some(input_ancestor)) => { + // A mapping exists at an ancestor, follow along the tree + Some(self.upmap_child(input, &input_ancestor, &output_root)) + } + (None, None) => { + // No mapping exists at all, is the same position in the final tree + None + } + } } pub fn merge(&mut self, mut other: SyntaxMapping) { @@ -130,6 +192,20 @@ impl SyntaxMapping { })); } + /// Follows the input one step along the syntax mapping tree + fn upmap_node_single(&self, input: &SyntaxNode) -> Option<SyntaxNode> { + let MappingEntry { parent, child_slot } = self.node_mappings.get(input)?; + + let output = self.entry_parents[*parent as usize] + .children_with_tokens() + .nth(*child_slot as usize) + .and_then(SyntaxElement::into_node) + .unwrap(); + + debug_assert_eq!(input.kind(), output.kind()); + Some(output) + } + fn add_mapping(&mut self, syntax_mapping: SyntaxMappingBuilder) { let SyntaxMappingBuilder { parent_node, node_mappings } = syntax_mapping; @@ -183,6 +259,9 @@ impl SyntaxMappingBuilder { } } +#[derive(Debug)] +pub struct MissingMapping(pub SyntaxNode); + #[derive(Debug, Clone, Copy)] struct MappingEntry { parent: u32, |