pactole_syntax/span.rs
1//! Byte-offset and row/column spans for syntax nodes.
2
3use std::fmt;
4
5/// A single position in the source text, expressed both as a byte offset and
6/// as a zero-indexed (row, column) pair.
7///
8/// The `column` is a byte offset within its `row`, matching tree-sitter's
9/// [`tree_sitter::Point`] semantics.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub struct Point {
12 /// Zero-indexed byte offset of the position within the whole source text.
13 pub byte: usize,
14 /// Zero-indexed row (line number).
15 pub row: usize,
16 /// Zero-indexed column (byte offset within `row`).
17 pub column: usize,
18}
19
20impl Point {
21 /// Builds a [`Point`] from a tree-sitter [`tree_sitter::Point`] and a byte offset.
22 pub fn new(byte: usize, ts_point: tree_sitter::Point) -> Self {
23 Self {
24 byte,
25 row: ts_point.row,
26 column: ts_point.column,
27 }
28 }
29}
30
31impl fmt::Display for Point {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 write!(f, "{}:{}", self.row + 1, self.column + 1)
34 }
35}
36
37/// A contiguous range in the source text, delimited by a start and end [`Point`].
38///
39/// The range is half-open: `start` is inclusive and `end` is exclusive, mirroring
40/// tree-sitter's node range semantics.
41#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
42pub struct Span {
43 /// Inclusive start position of the span.
44 pub start: Point,
45 /// Exclusive end position of the span.
46 pub end: Point,
47}
48
49impl Span {
50 /// Builds a [`Span`] from a start and end [`Point`].
51 pub fn new(start: Point, end: Point) -> Self {
52 Self { start, end }
53 }
54
55 /// Builds a [`Span`] covering the full range of a tree-sitter [`tree_sitter::Node`].
56 pub fn from_node(node: &tree_sitter::Node) -> Self {
57 Self {
58 start: Point::new(node.start_byte(), node.start_position()),
59 end: Point::new(node.end_byte(), node.end_position()),
60 }
61 }
62
63 /// The byte range covered by this span, usable to slice the original source text.
64 pub fn byte_range(&self) -> std::ops::Range<usize> {
65 self.start.byte..self.end.byte
66 }
67}
68
69impl fmt::Display for Span {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 write!(f, "{}-{}", self.start, self.end)
72 }
73}