git.delta.rocks / jrsonnet / refs/commits / 1e7463d0e79e

difftreelog

feat show only source code slice on error

Лач2020-06-06parent: #a69298f.patch.diff
in: master

2 files changed

addedcmds/jsonnet/src/location.rsdiffbeforeafterboth
--- /dev/null
+++ b/cmds/jsonnet/src/location.rs
@@ -0,0 +1,99 @@
+#[derive(Clone, PartialEq, Debug)]
+pub struct CodeLocation {
+	pub line: usize,
+	pub column: usize,
+
+	pub line_start_offset: usize,
+	pub line_end_offset: usize,
+}
+
+pub fn offset_to_location(file: &str, offsets: &[usize]) -> Vec<CodeLocation> {
+	if offsets.is_empty() {
+		return vec![];
+	}
+	let mut line = 1;
+	let mut column = 0;
+	let max_offset = *offsets.iter().max().unwrap();
+
+	let mut offset_map = offsets
+		.iter()
+		.enumerate()
+		.map(|(pos, offset)| (*offset, pos))
+		.collect::<Vec<_>>();
+	offset_map.sort_by_key(|v| v.0);
+	offset_map.reverse();
+
+	let mut out = vec![
+		CodeLocation {
+			column: 0,
+			line: 0,
+			line_start_offset: 0,
+			line_end_offset: 0
+		};
+		offsets.len()
+	];
+	let mut with_no_known_line_ending = vec![];
+	let mut this_line_offset = 0;
+	for (pos, ch) in file.chars().enumerate() {
+		column += 1;
+		match offset_map.last() {
+			Some(x) if x.0 == pos => {
+				let out_idx = x.1;
+				with_no_known_line_ending.push(out_idx);
+				out[out_idx].line = line;
+				out[out_idx].column = column;
+				out[out_idx].line_start_offset = this_line_offset + 1;
+				offset_map.pop();
+			}
+			_ => {}
+		}
+		if ch == '\n' {
+			line += 1;
+			column = 0;
+
+			for idx in with_no_known_line_ending.drain(..) {
+				out[idx].line_end_offset = pos;
+			}
+			this_line_offset = pos;
+
+			if pos == max_offset + 1 {
+				break;
+			}
+		}
+	}
+	let file_end = file.chars().count();
+	for idx in with_no_known_line_ending {
+		out[idx].line_end_offset = file_end;
+	}
+
+	out
+}
+
+#[cfg(test)]
+pub mod tests {
+	use super::{offset_to_location, CodeLocation};
+
+	#[test]
+	fn test() {
+		assert_eq!(
+			offset_to_location(
+				"hello world\n_______________________________________________________",
+				&[0, 14]
+			),
+			vec![
+				CodeLocation {
+					line: 1,
+					column: 1,
+					line_start_offset: 0,
+					line_end_offset: 11
+				},
+				CodeLocation {
+					line: 2,
+					column: 3,
+					line_start_offset: 11,
+					line_end_offset: 67
+				}
+			]
+		)
+	}
+}
modifiedcmds/jsonnet/src/main.rsdiffbeforeafterboth
1pub mod location;
2
1use clap::Clap;3use clap::Clap;
2use jsonnet_evaluator::{EvaluationState, LocError, StackTrace, Val};4use jsonnet_evaluator::{EvaluationState, LocError, StackTrace, Val};
5use location::{offset_to_location, CodeLocation};
3use std::env::current_dir;6use std::env::current_dir;
4use std::str::FromStr;7use std::str::FromStr;
58
145 print_trace(&(err.1), evaluator, &opts);148 print_trace(&(err.1), evaluator, &opts);
146}149}
147150
148fn line_columns(file: &str, offsets: &[usize]) -> Vec<(usize, usize)> {151fn print_trace(trace: &StackTrace, evaluator: EvaluationState, opts: &Opts) {
152 use annotate_snippets::{
153 display_list::{DisplayList, FormatOptions},
154 snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},
155 };
156 for item in trace.0.iter() {
157 let desc = &item.1;
149 if offsets.is_empty() {158 if (item.0).1.is_none() {
150 return vec![];159 continue;
151 }160 }
152 let mut line = 0;
153 let mut column = 0;
154 let max_offset = *offsets.iter().max().unwrap();161 let source = (item.0).1.clone().unwrap();
155
156 let mut offset_map = offsets162 let code = evaluator.get_source(&source.0);
157 .iter()
158 .enumerate()
159 .map(|(pos, offset)| (*offset, pos))
160 .collect::<Vec<_>>();
161 offset_map.sort_by_key(|v| v.0);163 if code.is_none() {
164 continue;
165 }
162 offset_map.reverse();166 let code = code.unwrap();
163
164 let mut out = vec![(0usize, 0usize); offsets.len()];167 let start_end = offset_to_location(&code, &[source.1, source.2]);
168 if opts.trace_format == TraceFormat::Custom {
169 let source_fragment: String = code
170 .chars()
165 for (pos, ch) in (0..max_offset + 1).zip(file.chars()) {171 .skip(start_end[0].line_start_offset)
166 column += 1;172 .take(start_end[1].line_end_offset - start_end[0].line_start_offset)
173 .collect();
174 let snippet = Snippet {
175 opt: FormatOptions {
176 color: true,
167 if offset_map.last().unwrap().0 == pos {177 ..Default::default()
178 },
179 title: Some(Annotation {
180 label: Some(&item.1),
181 id: None,
182 annotation_type: AnnotationType::Error,
183 }),
184 footer: vec![],
185 slices: vec![Slice {
186 source: &source_fragment,
187 line_start: start_end[0].line,
188 origin: Some(&source.0.to_str().unwrap()),
189 fold: false,
190 annotations: vec![SourceAnnotation {
191 label: desc,
192 annotation_type: AnnotationType::Error,
193 range: (
194 source.1 - start_end[0].line_start_offset,
195 source.2 - start_end[0].line_start_offset,
196 ),
197 }],
198 }],
199 };
200
168 out[offset_map.last().unwrap().1] = (line, column);201 let dl = DisplayList::from(snippet);
169 offset_map.pop();202 println!("{}", dl);
170 }
171 if ch == '\n' {203 } else {
172 line += 1;204 print_jsonnet_pair(
205 source.0.to_str().unwrap(),
173 column = 0;206 &start_end[0],
207 &start_end[1],
208 opts.trace_format == TraceFormat::GoJsonnet,
209 );
174 }210 }
175 }
176
177 out
178}211 }
212}
179213
180fn print_trace(trace: &StackTrace, evaluator: EvaluationState, opts: &Opts) {214fn print_jsonnet_pair(file: &str, start: &CodeLocation, end: &CodeLocation, is_go: bool) {
181 use annotate_snippets::{
182 display_list::{DisplayList, FormatOptions},
183 snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},
221
222 let dl = DisplayList::from(snippet);
223 println!("{}", dl);
224 } else {
225 if opts.trace_format == TraceFormat::CppJsonnet {215 if is_go {
226 print!(" ");216 print!(" ");
227 } else {217 } else {
228 print!(" ");218 print!(" ");
229 }219 }
230 print!("{}:", source.0.to_str().unwrap());220 print!("{}:", file);
231 if start_end[0].0 == start_end[1].0 {221 if start.line == end.line {
232 // IDK why, but this is the behavior original jsonnet shows222 // IDK why, but this is the behavior original jsonnet cpp impl shows
233 if start_end[0].1 == start_end[1].1223 if start.column == end.column || !is_go && start.column + 1 == end.column {
234 || opts.trace_format == TraceFormat::CppJsonnet
235 && start_end[0].1 + 1 == start_end[1].1
236 {
237 println!("{}:{}", start_end[0].0 + 1, start_end[0].1)224 println!("{}:{}", start.line, end.column)
238 } else {225 } else {
239 println!(226 println!("{}:{}-{}", start.line, start.column, end.column);
240 "{}:{}-{}",
241 start_end[0].0 + 1,
242 start_end[0].1,
243 start_end[1].1
244 );
245 }227 }
246 } else {228 } else {
247 println!(229 println!(
248 "({}:{})-({}:{})",230 "({}:{})-({}:{})",
249 start_end[0].0 + 1,231 start.line, end.column, start.line, end.column
250 start_end[0].1,
251 start_end[1].0 + 1,
252 start_end[1].1
253 );232 );
254 }233 }
255 }234}
256 }
257}
258235