jrsonnet_evaluator/trace/
location.rs

1#[derive(Clone, PartialEq, Debug)]
2pub struct CodeLocation {
3	pub offset: usize,
4
5	pub line: usize,
6	pub column: usize,
7
8	pub line_start_offset: usize,
9	pub line_end_offset: usize,
10}
11
12pub fn offset_to_location(file: &str, offsets: &[usize]) -> Vec<CodeLocation> {
13	if offsets.is_empty() {
14		return vec![];
15	}
16	let mut line = 1;
17	let mut column = 1;
18	let max_offset = *offsets.iter().max().unwrap();
19
20	let mut offset_map = offsets
21		.iter()
22		.enumerate()
23		.map(|(pos, offset)| (*offset, pos))
24		.collect::<Vec<_>>();
25	offset_map.sort_by_key(|v| v.0);
26	offset_map.reverse();
27
28	let mut out = vec![
29		CodeLocation {
30			offset: 0,
31			column: 0,
32			line: 0,
33			line_start_offset: 0,
34			line_end_offset: 0
35		};
36		offsets.len()
37	];
38	let mut with_no_known_line_ending = vec![];
39	let mut this_line_offset = 0;
40	for (pos, ch) in file
41		.chars()
42		.enumerate()
43		.chain(std::iter::once((file.len(), ' ')))
44	{
45		column += 1;
46		match offset_map.last() {
47			Some(x) if x.0 == pos => {
48				let out_idx = x.1;
49				with_no_known_line_ending.push(out_idx);
50				out[out_idx].offset = pos;
51				out[out_idx].line = line;
52				out[out_idx].column = column;
53				out[out_idx].line_start_offset = this_line_offset;
54				offset_map.pop();
55			}
56			_ => {}
57		}
58		if ch == '\n' {
59			line += 1;
60			column = 1;
61
62			for idx in with_no_known_line_ending.drain(..) {
63				out[idx].line_end_offset = pos;
64			}
65			this_line_offset = pos + 1;
66
67			if pos == max_offset + 1 {
68				break;
69			}
70		}
71	}
72	let file_end = file.chars().count();
73	for idx in with_no_known_line_ending {
74		out[idx].line_end_offset = file_end;
75	}
76
77	out
78}
79
80#[cfg(test)]
81pub mod tests {
82	use super::{offset_to_location, CodeLocation};
83
84	#[test]
85	fn test() {
86		assert_eq!(
87			offset_to_location(
88				"hello world\n_______________________________________________________",
89				&[0, 14]
90			),
91			vec![
92				CodeLocation {
93					offset: 0,
94					line: 1,
95					column: 2,
96					line_start_offset: 0,
97					line_end_offset: 11,
98				},
99				CodeLocation {
100					offset: 14,
101					line: 2,
102					column: 4,
103					line_start_offset: 12,
104					line_end_offset: 67
105				}
106			]
107		)
108	}
109}