intelligent ctags powered by tree-sitter and lexical scope-graphs
at main 4.4 kB view raw
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}