gobject_ast/model/
source_location.rs1use std::fmt;
2
3use serde::{Serialize, Serializer};
4
5#[derive(Clone, Copy, Default)]
7pub struct SourceLocation {
8 pub line: usize,
9 pub column: usize,
10 pub start_byte: usize,
11 pub end_byte: usize,
12}
13
14impl fmt::Debug for SourceLocation {
15 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16 write!(f, "{}:{}", self.line, self.column)
17 }
18}
19
20impl Serialize for SourceLocation {
21 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
22 s.serialize_str(&format!("{}:{}", self.line, self.column))
23 }
24}
25
26impl SourceLocation {
27 pub fn new(line: usize, column: usize, start_byte: usize, end_byte: usize) -> Self {
28 Self {
29 line,
30 column,
31 start_byte,
32 end_byte,
33 }
34 }
35
36 pub fn as_str<'a>(&self, source: &'a [u8]) -> Option<&'a str> {
38 std::str::from_utf8(&source[self.start_byte..self.end_byte]).ok()
39 }
40
41 fn find_line_start(&self, source: &[u8]) -> usize {
43 let mut line_start = self.start_byte;
44 while line_start > 0 && source[line_start - 1] != b'\n' {
45 line_start -= 1;
46 }
47 line_start
48 }
49
50 pub fn find_line_bounds(&self, source: &[u8]) -> (usize, usize) {
55 let mut line_start = self.find_line_start(source);
57
58 if line_start > 0 {
60 let mut prev_line_start = line_start - 1; while prev_line_start > 0 && source[prev_line_start - 1] != b'\n' {
62 prev_line_start -= 1;
63 }
64
65 let prev_line = &source[prev_line_start..line_start - 1];
67 if prev_line.iter().all(|&b| b == b' ' || b == b'\t') {
68 line_start = prev_line_start;
69 }
70 }
71
72 let mut line_end = self.start_byte;
74 while line_end < source.len() && source[line_end] != b'\n' {
75 line_end += 1;
76 }
77 if line_end < source.len() && source[line_end] == b'\n' {
79 line_end += 1;
80 }
81
82 (line_start, line_end)
83 }
84
85 pub fn find_line_bounds_with_following_blank(&self, source: &[u8]) -> (usize, usize) {
89 let line_start = self.find_line_start(source);
91
92 let mut line_end = self.end_byte;
94 while line_end < source.len() && source[line_end] != b'\n' {
95 line_end += 1;
96 }
97 if line_end < source.len() {
98 line_end += 1; }
100
101 if line_end < source.len() {
103 let mut pos = line_end;
104 let mut is_blank = true;
105
106 while pos < source.len() && source[pos] != b'\n' {
107 if !source[pos].is_ascii_whitespace() {
108 is_blank = false;
109 break;
110 }
111 pos += 1;
112 }
113
114 if is_blank && pos < source.len() {
116 line_end = pos + 1; }
118 }
119
120 (line_start, line_end)
121 }
122
123 pub fn extract_line_indentation(&self, source: &[u8]) -> String {
126 let line_start = self.find_line_start(source);
127
128 let mut indent = String::new();
130 let mut i = line_start;
131 while i < source.len() && (source[i] == b' ' || source[i] == b'\t') {
132 indent.push(source[i] as char);
133 i += 1;
134 }
135
136 indent
137 }
138
139 pub fn extract_indentation(&self, source: &[u8]) -> String {
143 let line_start = self.find_line_start(source);
144
145 let mut indent = String::new();
148 for &byte in &source[line_start..self.start_byte] {
149 if byte == b' ' || byte == b'\t' {
150 indent.push(byte as char);
151 } else {
152 break;
153 }
154 }
155
156 indent
157 }
158
159 pub fn find_semicolon_end(&self, source: &[u8]) -> usize {
163 let mut pos = self.end_byte;
164 while pos < source.len() {
165 match source[pos] {
166 b';' => return pos + 1,
167 b' ' | b'\t' | b'\r' | b'\n' => pos += 1,
168 _ => break,
169 }
170 }
171 self.end_byte
172 }
173
174 pub fn find_braces_around(start: usize, source: &[u8]) -> (usize, usize) {
178 let mut brace_start = start;
180 while brace_start > 0 && source[brace_start - 1] != b'{' {
181 brace_start -= 1;
182 if start - brace_start > 100 {
183 break;
184 }
185 }
186 if brace_start > 0 && source[brace_start - 1] == b'{' {
187 brace_start -= 1;
188 }
189
190 let mut brace_end = brace_start + 1;
193 let mut depth = 1;
194 while brace_end < source.len() && depth > 0 {
195 if source[brace_end] == b'{' {
196 depth += 1;
197 } else if source[brace_end] == b'}' {
198 depth -= 1;
199 }
200 brace_end += 1;
201 }
202
203 (brace_start, brace_end)
204 }
205}