git.delta.rocks / jrsonnet / refs/commits / 1820422c7290

difftreelog

source

crates/jrsonnet-trace/src/lib.rs4.2 KiBsourcehistory
1use jrsonnet_evaluator::{trace::CodeLocation, EvaluationState, LocError};2use std::path::PathBuf;34/// How paths should be displayed5pub enum PathResolver {6	/// Only filename will be shown7	FileName,8	/// Absolute path of file9	Absolute,10	/// Relative path from base directory11	Relative(PathBuf),12}1314impl PathResolver {15	pub fn resolve(&self, from: &PathBuf) -> String {16		match self {17			PathResolver::FileName => from.file_name().unwrap().to_string_lossy().into_owned(),18			PathResolver::Absolute => from.to_string_lossy().into_owned(),19			PathResolver::Relative(base) => {20				if from.is_relative() {21					return from.to_string_lossy().into_owned();22				}23				pathdiff::diff_paths(from, base)24					.unwrap()25					.to_string_lossy()26					.into_owned()27			}28		}29	}30}3132/// Implements trace to string pretty-printing33pub trait TraceFormat {34	fn write_trace(35		&self,36		out: &mut dyn std::io::Write,37		evaluation_state: &EvaluationState,38		error: &LocError,39	) -> Result<(), std::io::Error>;40	fn print_trace(41		&self,42		evaluation_state: &EvaluationState,43		error: &LocError,44	) -> Result<(), std::io::Error> {45		self.write_trace(&mut std::io::stdout(), evaluation_state, error)46	}47}4849fn print_code_location(50	out: &mut impl std::fmt::Write,51	start: &CodeLocation,52	end: &CodeLocation,53) -> Result<(), std::fmt::Error> {54	if start.line == end.line {55		if start.column == end.column {56			write!(out, "{}:{}", start.line, end.column - 1)?;57		} else {58			write!(out, "{}:{}-{}", start.line, start.column - 1, end.column)?;59		}60	} else {61		write!(62			out,63			"{}:{}-{}:{}",64			start.line,65			end.column - 1,66			start.line,67			end.column68		)?;69	}70	Ok(())71}7273/// vanilla jsonnet like formatting74pub struct CompactFormat {75	pub resolver: PathResolver,76}7778impl TraceFormat for CompactFormat {79	fn write_trace(80		&self,81		out: &mut dyn std::io::Write,82		evaluation_state: &EvaluationState,83		error: &LocError,84	) -> Result<(), std::io::Error> {85		writeln!(out, "{:?}", error.0)?;86		let file_names = (error.1)87			.088			.iter()89			.map(|el| {90				let resolved_path = self.resolver.resolve(&(el.0).0);91				// TODO: Process all trace elements first92				let location =93					evaluation_state.map_source_locations(&(el.0).0, &[(el.0).1, (el.0).2]);94				(resolved_path, location)95			})96			.map(|(mut n, location)| {97				use std::fmt::Write;98				write!(n, ":").unwrap();99				print_code_location(&mut n, &location[0], &location[1]).unwrap();100				n101			})102			.collect::<Vec<_>>();103		let align = file_names.iter().map(|e| e.len()).max().unwrap_or(0);104		for (i, (el, file)) in (error.1).0.iter().zip(file_names).enumerate() {105			if i != 0 {106				writeln!(out)?;107			}108			write!(out, "{:<w$}: {}", file, el.1, w = align)?;109		}110		Ok(())111	}112}113114/// rustc-like trace displaying115pub struct ExplainingFormat {116	pub resolver: PathResolver,117}118impl TraceFormat for ExplainingFormat {119	fn write_trace(120		&self,121		out: &mut dyn std::io::Write,122		evaluation_state: &EvaluationState,123		error: &LocError,124	) -> Result<(), std::io::Error> {125		use annotate_snippets::{126			display_list::{DisplayList, FormatOptions},127			snippet::{AnnotationType, Slice, Snippet, SourceAnnotation},128		};129		writeln!(out, "{:?}", error.0)?;130		let trace = &error.1;131		for item in trace.0.iter() {132			let desc = &item.1;133			let source = item.0.clone();134			let start_end = evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);135136			let source_fragment: String = evaluation_state137				.get_source(&source.0)138				.unwrap()139				.chars()140				.skip(start_end[0].line_start_offset)141				.take(start_end[1].line_end_offset - start_end[0].line_start_offset)142				.collect();143144			let origin = self.resolver.resolve(&source.0);145			let snippet = Snippet {146				opt: FormatOptions {147					color: true,148					..Default::default()149				},150				title: None,151				footer: vec![],152				slices: vec![Slice {153					source: &source_fragment,154					line_start: start_end[0].line,155					origin: Some(&origin),156					fold: false,157					annotations: vec![SourceAnnotation {158						label: desc,159						annotation_type: AnnotationType::Error,160						range: (161							source.1 - start_end[0].line_start_offset,162							source.2 - start_end[0].line_start_offset,163						),164					}],165				}],166			};167168			let dl = DisplayList::from(snippet);169			writeln!(out, "{}", dl)?;170		}171		Ok(())172	}173}