git.delta.rocks / jrsonnet / refs/commits / 9d883c6db8a3

difftreelog

source

crates/jrsonnet-evaluator/src/trace/mod.rs5.0 KiBsourcehistory
1mod location;23use crate::{EvaluationState, LocError};4pub use location::*;5use std::path::PathBuf;67/// How paths should be displayed8pub enum PathResolver {9	/// Only filename will be shown10	FileName,11	/// Absolute path of file12	Absolute,13	/// Relative path from base directory14	Relative(PathBuf),15}1617impl PathResolver {18	pub fn resolve(&self, from: &PathBuf) -> String {19		match self {20			PathResolver::FileName => from.file_name().unwrap().to_string_lossy().into_owned(),21			PathResolver::Absolute => from.to_string_lossy().into_owned(),22			PathResolver::Relative(base) => {23				if from.is_relative() {24					return from.to_string_lossy().into_owned();25				}26				pathdiff::diff_paths(from, base)27					.unwrap()28					.to_string_lossy()29					.into_owned()30			}31		}32	}33}3435/// Implements trace to string pretty-printing36pub trait TraceFormat {37	fn write_trace(38		&self,39		out: &mut dyn std::fmt::Write,40		evaluation_state: &EvaluationState,41		error: &LocError,42	) -> Result<(), std::fmt::Error>;43	// fn print_trace(44	// 	&self,45	// 	evaluation_state: &EvaluationState,46	// 	error: &LocError,47	// ) -> Result<(), std::fmt::Error> {48	// 	self.write_trace(&mut std::fmt::stdout(), evaluation_state, error)49	// }50}5152fn print_code_location(53	out: &mut impl std::fmt::Write,54	start: &CodeLocation,55	end: &CodeLocation,56) -> Result<(), std::fmt::Error> {57	if start.line == end.line {58		if start.column == end.column {59			write!(out, "{}:{}", start.line, end.column - 1)?;60		} else {61			write!(out, "{}:{}-{}", start.line, start.column - 1, end.column)?;62		}63	} else {64		write!(65			out,66			"{}:{}-{}:{}",67			start.line,68			end.column - 1,69			start.line,70			end.column71		)?;72	}73	Ok(())74}7576/// vanilla jsonnet like formatting77pub struct CompactFormat {78	pub resolver: PathResolver,79	pub padding: usize,80}8182impl TraceFormat for CompactFormat {83	fn write_trace(84		&self,85		out: &mut dyn std::fmt::Write,86		evaluation_state: &EvaluationState,87		error: &LocError,88	) -> Result<(), std::fmt::Error> {89		writeln!(out, "{:?}", error.0)?;90		let file_names = (error.1)91			.092			.iter()93			.map(|el| {94				let resolved_path = self.resolver.resolve(&el.location.0);95				// TODO: Process all trace elements first96				let location = evaluation_state97					.map_source_locations(&el.location.0, &[el.location.1, el.location.2]);98				(resolved_path, location)99			})100			.map(|(mut n, location)| {101				use std::fmt::Write;102				write!(n, ":").unwrap();103				print_code_location(&mut n, &location[0], &location[1]).unwrap();104				n105			})106			.collect::<Vec<_>>();107		let align = file_names.iter().map(|e| e.len()).max().unwrap_or(0);108		for (i, (el, file)) in (error.1).0.iter().zip(file_names).enumerate() {109			if i != 0 {110				writeln!(out)?;111			}112			write!(113				out,114				"{:<p$}{:<w$}: {}",115				"",116				file,117				el.desc,118				p = self.padding,119				w = align120			)?;121		}122		Ok(())123	}124}125126pub struct JSFormat;127impl TraceFormat for JSFormat {128	fn write_trace(129		&self,130		out: &mut dyn std::fmt::Write,131		evaluation_state: &EvaluationState,132		error: &LocError,133	) -> Result<(), std::fmt::Error> {134		writeln!(out, "{:?}", error.0)?;135		for (i, item) in (error.1).0.iter().enumerate() {136			if i != 0 {137				writeln!(out)?;138			}139			let desc = &item.desc;140			let source = item.location.clone();141			let start_end = evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);142143			write!(144				out,145				"    at {} ({}:{}:{})",146				desc,147				source.0.to_str().unwrap(),148				start_end[0].line,149				start_end[0].column,150			)?;151		}152		Ok(())153	}154}155156/// rustc-like trace displaying157#[cfg(feature = "explaining-traces")]158pub struct ExplainingFormat {159	pub resolver: PathResolver,160}161#[cfg(feature = "explaining-traces")]162impl TraceFormat for ExplainingFormat {163	fn write_trace(164		&self,165		out: &mut dyn std::fmt::Write,166		evaluation_state: &EvaluationState,167		error: &LocError,168	) -> Result<(), std::fmt::Error> {169		use annotate_snippets::{170			display_list::{DisplayList, FormatOptions},171			snippet::{AnnotationType, Slice, Snippet, SourceAnnotation},172		};173		writeln!(out, "{:?}", error.0)?;174		let trace = &error.1;175		for item in trace.0.iter() {176			let desc = &item.desc;177			let source = item.location.clone();178			let start_end = evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);179180			let source_fragment: String = evaluation_state181				.get_source(&source.0)182				.unwrap()183				.chars()184				.skip(start_end[0].line_start_offset)185				.take(start_end[1].line_end_offset - start_end[0].line_start_offset)186				.collect();187188			let origin = self.resolver.resolve(&source.0);189			let snippet = Snippet {190				opt: FormatOptions {191					color: true,192					..Default::default()193				},194				title: None,195				footer: vec![],196				slices: vec![Slice {197					source: &source_fragment,198					line_start: start_end[0].line,199					origin: Some(&origin),200					fold: false,201					annotations: vec![SourceAnnotation {202						label: desc,203						annotation_type: AnnotationType::Error,204						range: (205							source.1 - start_end[0].line_start_offset,206							source.2 - start_end[0].line_start_offset,207						),208					}],209				}],210			};211212			let dl = DisplayList::from(snippet);213			writeln!(out, "{}", dl)?;214		}215		Ok(())216	}217}