summaryrefslogtreecommitdiff
path: root/src/syntax
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-03-11 23:28:35 +0100
committerLaurenz <laurmaedje@gmail.com>2023-03-11 23:29:32 +0100
commitca6edf5283c258d8410134d678347977cb273cdd (patch)
treeb2b46ba70c054b0cbdefa06edbc5fd999cddb1fa /src/syntax
parent1a390deaea040191cf0e5937bd8e1427b49db71b (diff)
Jump to source and preview
Diffstat (limited to 'src/syntax')
-rw-r--r--src/syntax/node.rs75
-rw-r--r--src/syntax/source.rs15
2 files changed, 44 insertions, 46 deletions
diff --git a/src/syntax/node.rs b/src/syntax/node.rs
index 392633f6..afbebe97 100644
--- a/src/syntax/node.rs
+++ b/src/syntax/node.rs
@@ -204,14 +204,6 @@ impl SyntaxNode {
Ok(())
}
- /// If the span points into this node, convert it to a byte range.
- pub(super) fn range(&self, span: Span, offset: usize) -> Option<Range<usize>> {
- match &self.0 {
- Repr::Inner(inner) => inner.range(span, offset),
- _ => (self.span() == span).then(|| offset..offset + self.len()),
- }
- }
-
/// Whether this is a leaf node.
pub(super) fn is_leaf(&self) -> bool {
matches!(self.0, Repr::Leaf(_))
@@ -429,40 +421,6 @@ impl InnerNode {
Ok(())
}
- /// If the span points into this node, convert it to a byte range.
- fn range(&self, span: Span, mut offset: usize) -> Option<Range<usize>> {
- // Check whether we found it.
- if span == self.span {
- return Some(offset..offset + self.len);
- }
-
- // The parent of a subtree has a smaller span number than all of its
- // descendants. Therefore, we can bail out early if the target span's
- // number is smaller than our number.
- if span.number() < self.span.number() {
- return None;
- }
-
- let mut children = self.children.iter().peekable();
- while let Some(child) = children.next() {
- // Every node in this child's subtree has a smaller span number than
- // the next sibling. Therefore we only need to recurse if the next
- // sibling's span number is larger than the target span's number.
- if children
- .peek()
- .map_or(true, |next| next.span().number() > span.number())
- {
- if let Some(range) = child.range(span, offset) {
- return Some(range);
- }
- }
-
- offset += child.len();
- }
-
- None
- }
-
/// Replaces a range of children with a replacement.
///
/// May have mutated the children if it returns `Err(_)`.
@@ -669,6 +627,39 @@ impl<'a> LinkedNode<'a> {
back: self.offset + self.len(),
}
}
+
+ /// Find a descendant with the given span.
+ pub fn find(&self, span: Span) -> Option<LinkedNode<'a>> {
+ if self.span() == span {
+ return Some(self.clone());
+ }
+
+ if let Repr::Inner(inner) = &self.0 {
+ // The parent of a subtree has a smaller span number than all of its
+ // descendants. Therefore, we can bail out early if the target span's
+ // number is smaller than our number.
+ if span.number() < inner.span.number() {
+ return None;
+ }
+
+ let mut children = self.children().peekable();
+ while let Some(child) = children.next() {
+ // Every node in this child's subtree has a smaller span number than
+ // the next sibling. Therefore we only need to recurse if the next
+ // sibling's span number is larger than the target span's number.
+ if children
+ .peek()
+ .map_or(true, |next| next.span().number() > span.number())
+ {
+ if let Some(found) = child.find(span) {
+ return Some(found);
+ }
+ }
+ }
+ }
+
+ None
+ }
}
/// Access to parents and siblings.
diff --git a/src/syntax/source.rs b/src/syntax/source.rs
index f00d779b..607a2603 100644
--- a/src/syntax/source.rs
+++ b/src/syntax/source.rs
@@ -9,7 +9,7 @@ use comemo::Prehashed;
use unscanny::Scanner;
use super::ast::Markup;
-use super::{is_newline, parse, reparse, Span, SyntaxNode};
+use super::{is_newline, parse, reparse, LinkedNode, Span, SyntaxNode};
use crate::diag::SourceResult;
use crate::util::{PathExt, StrExt};
@@ -149,13 +149,20 @@ impl Source {
self.lines.len()
}
+ /// Find the node with the given span.
+ ///
+ /// Panics if the span does not point into this source file.
+ pub fn find(&self, span: Span) -> LinkedNode<'_> {
+ LinkedNode::new(&self.root)
+ .find(span)
+ .expect("span does not point into this source file")
+ }
+
/// Map a span that points into this source file to a byte range.
///
/// Panics if the span does not point into this source file.
pub fn range(&self, span: Span) -> Range<usize> {
- self.root
- .range(span, 0)
- .expect("span does not point into this source file")
+ self.find(span).range()
}
/// Return the index of the UTF-16 code unit at the byte index.