summaryrefslogtreecommitdiff
path: root/crates/typst-syntax/src/node.rs
diff options
context:
space:
mode:
authorMatthew Toohey <contact@mtoohey.com>2024-04-01 16:22:54 -0400
committerGitHub <noreply@github.com>2024-04-01 20:22:54 +0000
commitdee8ccf04810ee4032fd28b366a4f796b7bf3062 (patch)
treec1a93c99c762527e0181508037318ced1bd82e46 /crates/typst-syntax/src/node.rs
parent16c3af7c92de97d14f52319bd375f842ce37a949 (diff)
Add side parameter to leaf_at (#3767)
Diffstat (limited to 'crates/typst-syntax/src/node.rs')
-rw-r--r--crates/typst-syntax/src/node.rs61
1 files changed, 54 insertions, 7 deletions
diff --git a/crates/typst-syntax/src/node.rs b/crates/typst-syntax/src/node.rs
index 3c93cd84..d047e751 100644
--- a/crates/typst-syntax/src/node.rs
+++ b/crates/typst-syntax/src/node.rs
@@ -811,6 +811,13 @@ impl<'a> LinkedNode<'a> {
}
}
+/// Indicates whether the cursor is before the related byte index, or after.
+#[derive(Debug, Clone)]
+pub enum Side {
+ Before,
+ After,
+}
+
/// Access to leafs.
impl<'a> LinkedNode<'a> {
/// Get the rightmost non-trivia leaf before this node.
@@ -840,8 +847,8 @@ impl<'a> LinkedNode<'a> {
None
}
- /// Get the leaf at the specified byte offset.
- pub fn leaf_at(&self, cursor: usize) -> Option<Self> {
+ /// Get the leaf immediately before the specified byte offset.
+ fn leaf_before(&self, cursor: usize) -> Option<Self> {
if self.node.children().len() == 0 && cursor <= self.offset + self.len() {
return Some(self.clone());
}
@@ -853,7 +860,7 @@ impl<'a> LinkedNode<'a> {
if (offset < cursor && cursor <= offset + len)
|| (offset == cursor && i + 1 == count)
{
- return child.leaf_at(cursor);
+ return child.leaf_before(cursor);
}
offset += len;
}
@@ -861,6 +868,32 @@ impl<'a> LinkedNode<'a> {
None
}
+ /// Get the leaf after the specified byte offset.
+ fn leaf_after(&self, cursor: usize) -> Option<Self> {
+ if self.node.children().len() == 0 && cursor < self.offset + self.len() {
+ return Some(self.clone());
+ }
+
+ let mut offset = self.offset;
+ for child in self.children() {
+ let len = child.len();
+ if offset <= cursor && cursor < offset + len {
+ return child.leaf_after(cursor);
+ }
+ offset += len;
+ }
+
+ None
+ }
+
+ /// Get the leaf at the specified byte offset.
+ pub fn leaf_at(&self, cursor: usize, side: Side) -> Option<Self> {
+ match side {
+ Side::Before => self.leaf_before(cursor),
+ Side::After => self.leaf_after(cursor),
+ }
+ }
+
/// Find the rightmost contained non-trivia leaf.
pub fn rightmost_leaf(&self) -> Option<Self> {
if self.is_leaf() && !self.kind().is_trivia() {
@@ -974,8 +1007,13 @@ mod tests {
fn test_linked_node() {
let source = Source::detached("#set text(12pt, red)");
- // Find "text".
- let node = LinkedNode::new(source.root()).leaf_at(7).unwrap();
+ // Find "text" with Before.
+ let node = LinkedNode::new(source.root()).leaf_at(7, Side::Before).unwrap();
+ assert_eq!(node.offset(), 5);
+ assert_eq!(node.text(), "text");
+
+ // Find "text" with After.
+ let node = LinkedNode::new(source.root()).leaf_at(7, Side::After).unwrap();
assert_eq!(node.offset(), 5);
assert_eq!(node.text(), "text");
@@ -988,17 +1026,26 @@ mod tests {
#[test]
fn test_linked_node_non_trivia_leaf() {
let source = Source::detached("#set fun(12pt, red)");
- let leaf = LinkedNode::new(source.root()).leaf_at(6).unwrap();
+ let leaf = LinkedNode::new(source.root()).leaf_at(6, Side::Before).unwrap();
let prev = leaf.prev_leaf().unwrap();
assert_eq!(leaf.text(), "fun");
assert_eq!(prev.text(), "set");
+ // Check position 9 with Before.
let source = Source::detached("#let x = 10");
- let leaf = LinkedNode::new(source.root()).leaf_at(9).unwrap();
+ let leaf = LinkedNode::new(source.root()).leaf_at(9, Side::Before).unwrap();
let prev = leaf.prev_leaf().unwrap();
let next = leaf.next_leaf().unwrap();
assert_eq!(prev.text(), "=");
assert_eq!(leaf.text(), " ");
assert_eq!(next.text(), "10");
+
+ // Check position 9 with After.
+ let source = Source::detached("#let x = 10");
+ let leaf = LinkedNode::new(source.root()).leaf_at(9, Side::After).unwrap();
+ let prev = leaf.prev_leaf().unwrap();
+ assert!(leaf.next_leaf().is_none());
+ assert_eq!(prev.text(), "=");
+ assert_eq!(leaf.text(), "10");
}
}