1use serde::{Deserialize, Serialize};
2use tree_sitter_graph::graph::Value;
3
4use std::cmp::{Ord, Ordering};
5
6/// A singular position in a text document
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
8pub struct Point {
9 /// The byte index
10 pub byte: usize,
11
12 /// 0-indexed line number
13 pub line: usize,
14
15 /// Position within the line
16 pub column: usize,
17}
18
19impl PartialOrd for Point {
20 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
21 Some(self.cmp(other))
22 }
23}
24
25impl Ord for Point {
26 fn cmp(&self, other: &Self) -> Ordering {
27 self.byte.cmp(&other.byte)
28 }
29}
30
31impl Point {
32 pub fn new(byte: usize, line: usize, column: usize) -> Self {
33 Self { byte, line, column }
34 }
35
36 pub fn from_byte(byte: usize, line_end_indices: &[u32]) -> Self {
37 let line = line_end_indices
38 .iter()
39 .position(|&line_end_byte| (line_end_byte as usize) > byte)
40 .unwrap_or(0);
41
42 let column = line
43 .checked_sub(1)
44 .and_then(|idx| line_end_indices.get(idx))
45 .map(|&prev_line_end| byte.saturating_sub(prev_line_end as usize))
46 .unwrap_or(byte);
47
48 Self::new(byte, line, column)
49 }
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
53pub struct TextRange {
54 pub start: Point,
55 pub end: Point,
56}
57
58impl PartialOrd for TextRange {
59 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
60 Some(self.cmp(other))
61 }
62}
63
64impl Ord for TextRange {
65 fn cmp(&self, other: &Self) -> Ordering {
66 let compare_start_byte = self.start.byte.cmp(&other.start.byte);
67 let compare_size = self.size().cmp(&other.size());
68
69 compare_start_byte.then(compare_size)
70 }
71}
72
73impl TextRange {
74 pub fn new(start: Point, end: Point) -> Self {
75 assert!(start <= end);
76 Self { start, end }
77 }
78
79 pub fn contains(&self, other: &TextRange) -> bool {
80 // (self.start ... [other.start ... other.end] ... self.end)
81 self.start <= other.start && other.end <= self.end
82 }
83
84 pub fn contains_strict(&self, other: TextRange) -> bool {
85 // (self.start ... (other.start ... other.end) ... self.end)
86 self.start < other.start && other.end < self.end
87 }
88
89 pub fn size(&self) -> usize {
90 self.end.byte.saturating_sub(self.start.byte)
91 }
92
93 pub fn from_byte_range(range: std::ops::Range<usize>, line_end_indices: &[u32]) -> Self {
94 let start = Point::from_byte(range.start, line_end_indices);
95 let end = Point::from_byte(range.end, line_end_indices);
96 Self::new(start, end)
97 }
98}
99
100impl From<tree_sitter::Range> for TextRange {
101 fn from(r: tree_sitter::Range) -> Self {
102 Self {
103 start: Point {
104 byte: r.start_byte,
105 line: r.start_point.row,
106 column: r.start_point.column,
107 },
108 end: Point {
109 byte: r.end_byte,
110 line: r.end_point.row,
111 column: r.end_point.column,
112 },
113 }
114 }
115}
116
117impl From<TextRange> for std::ops::Range<usize> {
118 fn from(r: TextRange) -> std::ops::Range<usize> {
119 r.start.byte..r.end.byte
120 }
121}
122
123pub fn value_to_range(value: &Value) -> tree_sitter::Range {
124 let range = value.as_list().unwrap();
125 let start = range[0].as_list().unwrap();
126 let end = range[1].as_list().unwrap();
127 tree_sitter::Range {
128 start_byte: start[0].as_integer().unwrap() as usize,
129 start_point: tree_sitter::Point {
130 row: start[1].as_integer().unwrap() as usize,
131 column: start[2].as_integer().unwrap() as usize,
132 },
133 end_byte: end[0].as_integer().unwrap() as usize,
134 end_point: tree_sitter::Point {
135 row: end[1].as_integer().unwrap() as usize,
136 column: end[2].as_integer().unwrap() as usize,
137 },
138 }
139}
140
141pub fn range_to_value(value: &tree_sitter::Range) -> Value {
142 let start = Value::from(vec![
143 Value::from(value.start_byte as u32),
144 Value::from(value.start_point.row as u32),
145 Value::from(value.start_point.column as u32),
146 ]);
147 let end = Value::from(vec![
148 Value::from(value.end_byte as u32),
149 Value::from(value.end_point.row as u32),
150 Value::from(value.end_point.column as u32),
151 ]);
152 Value::from(vec![start, end])
153}