git.delta.rocks / jrsonnet / refs/commits / 759175b8af18

difftreelog

feat add tracing format based on hi-doc

Yaroslav Bolyukin2024-02-20parent: #9ae683a.patch.diff
in: master

7 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -109,18 +109,6 @@
 checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
 
 [[package]]
-name = "ass-stroke"
-version = "0.1.0"
-source = "git+https://github.com/CertainLach/ass-stroke#e649d7ffb2beb4800143b7a5acfdae0ad3fb6d94"
-dependencies = [
- "num-traits",
- "rand 0.8.5",
- "random_color",
- "range-map",
- "smallvec",
-]
-
-[[package]]
 name = "autocfg"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -422,24 +410,13 @@
 
 [[package]]
 name = "getrandom"
-version = "0.1.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi 0.9.0+wasi-snapshot-preview1",
-]
-
-[[package]]
-name = "getrandom"
 version = "0.2.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
 dependencies = [
  "cfg-if",
  "libc",
- "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasi",
 ]
 
 [[package]]
@@ -471,6 +448,19 @@
 checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
 
 [[package]]
+name = "hi-doc"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "748c617f3021ee027bf6f94d54f9c28877467cb79c5847d0dd70c3a6db4da0fc"
+dependencies = [
+ "num-traits",
+ "rand",
+ "random_color",
+ "range-map",
+ "smallvec",
+]
+
+[[package]]
 name = "idna"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -545,9 +535,9 @@
 name = "jrsonnet"
 version = "0.5.0-pre95"
 dependencies = [
- "ass-stroke",
  "clap",
  "clap_complete",
+ "hi-doc",
  "jrsonnet-cli",
  "jrsonnet-evaluator",
  "jrsonnet-gcmodule",
@@ -578,6 +568,7 @@
  "bincode",
  "derivative",
  "hashbrown 0.14.3",
+ "hi-doc",
  "jrsonnet-gcmodule",
  "jrsonnet-interner",
  "jrsonnet-macros",
@@ -596,9 +587,9 @@
 name = "jrsonnet-fmt"
 version = "0.5.0-pre95"
 dependencies = [
- "ass-stroke",
  "clap",
  "dprint-core",
+ "hi-doc",
  "indoc",
  "insta",
  "jrsonnet-rowan-parser",
@@ -1059,20 +1050,6 @@
 checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
 dependencies = [
  "proc-macro2",
-]
-
-[[package]]
-name = "rand"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
-dependencies = [
- "getrandom 0.1.16",
- "libc",
- "rand_chacha 0.2.2",
- "rand_core 0.5.1",
- "rand_hc",
- "rand_pcg",
 ]
 
 [[package]]
@@ -1082,18 +1059,8 @@
 checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
 dependencies = [
  "libc",
- "rand_chacha 0.3.1",
- "rand_core 0.6.4",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
-dependencies = [
- "ppv-lite86",
- "rand_core 0.5.1",
+ "rand_chacha",
+ "rand_core",
 ]
 
 [[package]]
@@ -1103,16 +1070,7 @@
 checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
 dependencies = [
  "ppv-lite86",
- "rand_core 0.6.4",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
-dependencies = [
- "getrandom 0.1.16",
+ "rand_core",
 ]
 
 [[package]]
@@ -1121,34 +1079,16 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
 dependencies = [
- "getrandom 0.2.12",
-]
-
-[[package]]
-name = "rand_hc"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
-dependencies = [
- "rand_core 0.5.1",
-]
-
-[[package]]
-name = "rand_pcg"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
-dependencies = [
- "rand_core 0.5.1",
+ "getrandom",
 ]
 
 [[package]]
 name = "random_color"
-version = "0.6.1"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5f34bd6526786b2ce5141fd37a4084b5da1ebae74595b5b0d05482a7cef7181"
+checksum = "0085421bc527effa7ed6d46bac0a28734663c47abe03d80a5e78e441fad85196"
 dependencies = [
- "rand 0.7.3",
+ "rand",
 ]
 
 [[package]]
@@ -1581,12 +1521,6 @@
 version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
-
-[[package]]
-name = "wasi"
-version = "0.9.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
 
 [[package]]
 name = "wasi"
modifiedCargo.tomldiffbeforeafterboth
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,7 +16,7 @@
 jrsonnet-types = { path = "./crates/jrsonnet-types", version = "0.5.0-pre95" }
 
 jrsonnet-gcmodule = "0.3.6"
-ass-stroke = { git = "https://github.com/CertainLach/ass-stroke", version = "0.1.0" }
+hi-doc = "0.1.0"
 
 serde = "1.0.197"
 serde_json = "1.0.114"
modifiedcmds/jrsonnet-fmt/Cargo.tomldiffbeforeafterboth
--- a/cmds/jrsonnet-fmt/Cargo.toml
+++ b/cmds/jrsonnet-fmt/Cargo.toml
@@ -8,7 +8,7 @@
 jrsonnet-rowan-parser.workspace = true
 insta.workspace = true
 indoc.workspace = true
-ass-stroke.workspace = true
+hi-doc.workspace = true
 clap = { workspace = true, features = ["derive"] }
 tempfile.workspace = true
 thiserror.workspace = true
modifiedcmds/jrsonnet/Cargo.tomldiffbeforeafterboth
--- a/cmds/jrsonnet/Cargo.toml
+++ b/cmds/jrsonnet/Cargo.toml
@@ -58,4 +58,4 @@
 clap_complete.workspace = true
 serde_json.workspace = true
 serde = { workspace = true, features = ["derive"] }
-ass-stroke.workspace = true
+hi-doc.workspace = true
modifiedcrates/jrsonnet-cli/src/trace.rsdiffbeforeafterboth
--- a/crates/jrsonnet-cli/src/trace.rs
+++ b/crates/jrsonnet-cli/src/trace.rs
@@ -1,5 +1,7 @@
 use clap::{Parser, ValueEnum};
-use jrsonnet_evaluator::trace::{CompactFormat, ExplainingFormat, PathResolver, TraceFormat};
+use jrsonnet_evaluator::trace::{
+	AssStrokeFormat, CompactFormat, ExplainingFormat, PathResolver, TraceFormat,
+};
 
 #[derive(PartialEq, Eq, ValueEnum, Clone)]
 pub enum TraceFormatName {
@@ -7,6 +9,8 @@
 	Compact,
 	/// Display source code with attached trace annotations
 	Explaining,
+	/// Experimental trace formatting based on hi-doc library
+	HiDoc,
 }
 
 #[derive(Parser)]
@@ -38,6 +42,10 @@
 				resolver,
 				max_trace,
 			}),
+			TraceFormatName::HiDoc => Box::new(AssStrokeFormat {
+				resolver,
+				max_trace,
+			}),
 		};
 		format
 	}
modifiedcrates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/Cargo.toml
+++ b/crates/jrsonnet-evaluator/Cargo.toml
@@ -10,7 +10,7 @@
 [features]
 default = ["explaining-traces"]
 # Rustc-like trace visualization
-explaining-traces = ["annotate-snippets"]
+explaining-traces = ["annotate-snippets", "hi-doc"]
 # Allows library authors to throw custom errors
 anyhow-error = ["anyhow"]
 # Adds ability to build import closure in async
@@ -54,6 +54,8 @@
 bincode = { workspace = true, optional = true }
 # Explaining traces
 annotate-snippets = { workspace = true, optional = true }
+# Better explaining traces
+hi-doc = { workspace = true, optional = true }
 # Bigint
 num-bigint = { workspace = true, features = ["serde"], optional = true }
 derivative.workspace = true
modifiedcrates/jrsonnet-evaluator/src/trace/mod.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/trace/mod.rs
1use std::{2	any::Any,3	path::{Path, PathBuf},4};56use jrsonnet_gcmodule::Trace;7use jrsonnet_parser::{CodeLocation, Source};89use crate::{error::ErrorKind, Error};1011/// The way paths should be displayed12#[derive(Clone, Trace)]13pub enum PathResolver {14	/// Only filename15	FileName,16	/// Absolute path17	Absolute,18	/// Path relative to base directory19	Relative(PathBuf),20}2122impl PathResolver {23	/// Will return `Self::Relative(cwd)`, or `Self::Absolute` on cwd failure24	pub fn new_cwd_fallback() -> Self {25		std::env::current_dir().map_or(Self::Absolute, Self::Relative)26	}27	pub fn resolve(&self, from: &Path) -> String {28		match self {29			Self::FileName => from30				.file_name()31				.expect("file name exists")32				.to_string_lossy()33				.into_owned(),34			Self::Absolute => from.to_string_lossy().into_owned(),35			Self::Relative(base) => {36				if from.is_relative() {37					return from.to_string_lossy().into_owned();38				}39				pathdiff::diff_paths(from, base)40					.expect("base is absolute")41					.to_string_lossy()42					.into_owned()43			}44		}45	}46}4748/// Implements pretty-printing of traces49#[allow(clippy::module_name_repetitions)]50pub trait TraceFormat: Trace {51	fn write_trace(52		&self,53		out: &mut dyn std::fmt::Write,54		error: &Error,55	) -> Result<(), std::fmt::Error>;56	fn format(&self, error: &Error) -> Result<String, std::fmt::Error> {57		let mut out = String::new();58		self.write_trace(&mut out, error)?;59		Ok(out)60	}61	fn as_any(&self) -> &dyn Any;62	fn as_any_mut(&mut self) -> &mut dyn Any;63}6465fn print_code_location(66	out: &mut impl std::fmt::Write,67	start: &CodeLocation,68	end: &CodeLocation,69) -> Result<(), std::fmt::Error> {70	if start.line == end.line {71		if start.column == end.column {72			write!(out, "{}:{}", start.line, end.column.saturating_sub(1))?;73		} else {74			write!(out, "{}:{}-{}", start.line, start.column - 1, end.column)?;75		}76	} else {77		write!(78			out,79			"{}:{}-{}:{}",80			start.line,81			end.column.saturating_sub(1),82			start.line,83			end.column84		)?;85	}86	Ok(())87}8889/// vanilla-like jsonnet formatting90#[derive(Trace)]91pub struct CompactFormat {92	pub resolver: PathResolver,93	pub max_trace: usize,94	pub padding: usize,95}96impl Default for CompactFormat {97	fn default() -> Self {98		Self {99			resolver: PathResolver::Absolute,100			max_trace: 20,101			padding: 4,102		}103	}104}105106impl TraceFormat for CompactFormat {107	fn write_trace(108		&self,109		out: &mut dyn std::fmt::Write,110		error: &Error,111	) -> Result<(), std::fmt::Error> {112		write!(out, "{}", error.error())?;113		if let ErrorKind::ImportSyntaxError { path, error } = error.error() {114			use std::fmt::Write;115116			writeln!(out)?;117			let mut n = path.source_path().path().map_or_else(118				|| path.source_path().to_string(),119				|r| self.resolver.resolve(r),120			);121			let mut offset = error.location.offset;122			let is_eof = if offset >= path.code().len() {123				offset = path.code().len().saturating_sub(1);124				true125			} else {126				false127			};128			let mut location = path129				.map_source_locations(&[offset as u32])130				.into_iter()131				.next()132				.unwrap();133			if is_eof {134				location.column += 1;135			}136137			write!(n, ":").unwrap();138			print_code_location(&mut n, &location, &location).unwrap();139			write!(out, "{:<p$}{n}", "", p = self.padding)?;140		}141		let file_names = error142			.trace()143			.0144			.iter()145			.map(|el| &el.location)146			.map(|location| {147				use std::fmt::Write;148				#[allow(clippy::option_if_let_else)]149				if let Some(location) = location {150					let mut resolved_path = match location.0.source_path().path() {151						Some(r) => self.resolver.resolve(r),152						None => location.0.source_path().to_string(),153					};154					// TODO: Process all trace elements first155					let location = location.0.map_source_locations(&[location.1, location.2]);156					write!(resolved_path, ":").unwrap();157					print_code_location(&mut resolved_path, &location[0], &location[1]).unwrap();158					write!(resolved_path, ":").unwrap();159					Some(resolved_path)160				} else {161					None162				}163			})164			.collect::<Vec<_>>();165		let align = file_names166			.iter()167			.flatten()168			.map(String::len)169			.max()170			.unwrap_or(0);171		for (el, file) in error.trace().0.iter().zip(file_names) {172			writeln!(out)?;173			if let Some(file) = file {174				write!(175					out,176					"{:<p$}{:<w$} {}",177					"",178					file,179					el.desc,180					p = self.padding,181					w = align182				)?;183			} else {184				write!(out, "{:<p$}{}", "", el.desc, p = self.padding,)?;185			}186		}187		Ok(())188	}189190	fn as_any(&self) -> &dyn Any {191		self192	}193194	fn as_any_mut(&mut self) -> &mut dyn Any {195		self196	}197}198199#[derive(Trace)]200pub struct JsFormat {201	pub max_trace: usize,202}203impl TraceFormat for JsFormat {204	fn write_trace(205		&self,206		out: &mut dyn std::fmt::Write,207		error: &Error,208	) -> Result<(), std::fmt::Error> {209		write!(out, "{}", error.error())?;210		for item in &error.trace().0 {211			writeln!(out)?;212			let desc = &item.desc;213			if let Some(source) = &item.location {214				let start_end = source.0.map_source_locations(&[source.1, source.2]);215				let resolved_path = source.0.source_path().path().map_or_else(216					|| source.0.source_path().to_string(),217					|r| r.display().to_string(),218				);219220				write!(221					out,222					"    at {} ({}:{}:{})",223					desc, resolved_path, start_end[0].line, start_end[0].column,224				)?;225			} else {226				write!(out, "    during {desc}")?;227			}228		}229		Ok(())230	}231232	fn as_any(&self) -> &dyn Any {233		self234	}235236	fn as_any_mut(&mut self) -> &mut dyn Any {237		self238	}239}240241/// rustc-like trace displaying242#[cfg(feature = "explaining-traces")]243#[derive(Trace)]244pub struct ExplainingFormat {245	pub resolver: PathResolver,246	pub max_trace: usize,247}248#[cfg(feature = "explaining-traces")]249impl TraceFormat for ExplainingFormat {250	fn write_trace(251		&self,252		out: &mut dyn std::fmt::Write,253		error: &Error,254	) -> Result<(), std::fmt::Error> {255		write!(out, "{}", error.error())?;256		if let ErrorKind::ImportSyntaxError { path, error } = error.error() {257			writeln!(out)?;258			let offset = error.location.offset;259			let location = path260				.map_source_locations(&[offset as u32])261				.into_iter()262				.next()263				.unwrap();264			let mut end_location = location;265			end_location.offset += 1;266267			self.print_snippet(268				out,269				path.code(),270				path,271				&location,272				&end_location,273				"syntax error",274			)?;275		}276		let trace = &error.trace();277		for item in &trace.0 {278			writeln!(out)?;279			let desc = &item.desc;280			if let Some(source) = &item.location {281				let start_end = source.0.map_source_locations(&[source.1, source.2]);282				self.print_snippet(283					out,284					source.0.code(),285					&source.0,286					&start_end[0],287					&start_end[1],288					desc,289				)?;290			} else {291				write!(out, "{desc}")?;292			}293		}294		Ok(())295	}296297	fn as_any(&self) -> &dyn Any {298		self299	}300301	fn as_any_mut(&mut self) -> &mut dyn Any {302		self303	}304}305306impl ExplainingFormat {307	fn print_snippet(308		&self,309		out: &mut dyn std::fmt::Write,310		source: &str,311		origin: &Source,312		start: &CodeLocation,313		end: &CodeLocation,314		desc: &str,315	) -> Result<(), std::fmt::Error> {316		use annotate_snippets::{317			// DisplayList, FormatOptions,318			AnnotationType,319			Renderer,320			Slice,321			Snippet,322			SourceAnnotation,323		};324325		let source_fragment: String = source326			.chars()327			.skip(start.line_start_offset)328			.take(end.line_end_offset - end.line_start_offset)329			.collect();330331		let origin = origin.source_path().path().map_or_else(332			|| origin.source_path().to_string(),333			|r| self.resolver.resolve(r),334		);335		let snippet = Snippet {336			// opt: FormatOptions {337			// 	color: true,338			// 	..FormatOptions::default()339			// },340			title: None,341			footer: vec![],342			slices: vec![Slice {343				source: &source_fragment,344				line_start: start.line,345				origin: Some(&origin),346				fold: false,347				annotations: vec![SourceAnnotation {348					label: desc,349					annotation_type: AnnotationType::Error,350					range: (351						start.offset - start.line_start_offset,352						(end.offset.saturating_sub(start.line_start_offset))353							.min(source_fragment.len()),354					),355				}],356			}],357		};358359		let renderer = Renderer::styled();360		let dl = renderer.render(snippet);361		write!(out, "{dl}")?;362363		Ok(())364	}365}