git.delta.rocks / jrsonnet / refs/commits / d5d04bbaa62b

difftreelog

fix incorrect expression suffix handling in rowan parser

ytytztwvYaroslav Bolyukin2026-02-10parent: #bfc3583.patch.diff
in: master

31 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -704,10 +704,12 @@
 dependencies = [
  "anyhow",
  "drop_bomb",
+ "hi-doc",
  "indoc",
  "insta",
  "logos",
  "rowan",
+ "strip-ansi-escapes",
  "thiserror",
 ]
 
@@ -1318,6 +1320,15 @@
 checksum = "2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520"
 
 [[package]]
+name = "strip-ansi-escapes"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025"
+dependencies = [
+ "vte",
+]
+
+[[package]]
 name = "strsim"
 version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1471,6 +1482,15 @@
 checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
 
 [[package]]
+name = "vte"
+version = "0.14.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
 name = "wasip2"
 version = "1.0.2+wasi-0.2.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
modifiedcrates/jrsonnet-formatter/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-formatter/src/lib.rs
+++ b/crates/jrsonnet-formatter/src/lib.rs
@@ -685,7 +685,7 @@
 	fn print(&self, out: &mut PrintItems) {
 		match self {
 			Self::ExprBinary(b) => {
-				p!(out, {b.lhs_work()} str(" ") {b.binary_operator()} str(" ") {b.rhs_work()});
+				p!(out, {b.lhs()} str(" ") {b.binary_operator()} str(" ") {b.rhs()});
 			}
 			Self::ExprUnary(u) => p!(out, {u.unary_operator()} {u.rhs()}),
 			// Self::ExprSlice(s) => {
addedcrates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__self_super.snapdiffbeforeafterboth
--- /dev/null
+++ b/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__self_super.snap
@@ -0,0 +1,13 @@
+---
+source: crates/jrsonnet-formatter/src/tests.rs
+expression: "reformat(indoc!(\"\n\t\t\tlocal base = {\n\t\t\t  foo: 'bar',\n\t\t\t  method():: self.foo,\n\t\t\t};\n\n\t\t\tbase {\n\t\t\t  foo: super.foo + '-extended',\n\t\t\t  result: self.method(),\n\t\t\t}\n\t\t\"))"
+---
+local base = {
+	foo: 'bar',
+	method(
+	):: self.foo,
+};
+base {
+	foo: super.foo + '-extended',
+	result: self.method(),
+}
modifiedcrates/jrsonnet-formatter/src/tests.rsdiffbeforeafterboth
--- a/crates/jrsonnet-formatter/src/tests.rs
+++ b/crates/jrsonnet-formatter/src/tests.rs
@@ -148,3 +148,20 @@
 		"
 	)));
 }
+
+#[test]
+fn self_super() {
+	insta::assert_snapshot!(reformat(indoc!(
+		"
+			local base = {
+			  foo: 'bar',
+			  method():: self.foo,
+			};
+
+			base {
+			  foo: super.foo + '-extended',
+			  result: self.method(),
+			}
+		"
+	)));
+}
modifiedcrates/jrsonnet-rowan-parser/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/Cargo.toml
+++ b/crates/jrsonnet-rowan-parser/Cargo.toml
@@ -12,6 +12,7 @@
 [dependencies]
 anyhow.workspace = true
 drop_bomb.workspace = true
+hi-doc.workspace = true
 indoc.workspace = true
 logos.workspace = true
 rowan.workspace = true
@@ -21,3 +22,4 @@
 indoc.workspace = true
 insta.workspace = true
 anyhow.workspace = true
+strip-ansi-escapes = "0.2.1"
modifiedcrates/jrsonnet-rowan-parser/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/lib.rs
+++ b/crates/jrsonnet-rowan-parser/src/lib.rs
@@ -47,17 +47,6 @@
 		parse.errors,
 	)
 }
-impl ExprBinary {
-	pub fn lhs_work(&self) -> Option<Expr> {
-		support::child(self.syntax())
-	}
-	pub fn rhs_work(&self) -> Option<Expr> {
-		let mut children = support::children(self.syntax());
-		// skip lhs
-		children.next()?;
-		children.next()
-	}
-}
 impl ExprObjExtend {
 	pub fn lhs_work(&self) -> Option<Expr> {
 		support::child(self.syntax())
modifiedcrates/jrsonnet-rowan-parser/src/marker.rsdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/marker.rs
+++ b/crates/jrsonnet-rowan-parser/src/marker.rs
@@ -140,8 +140,15 @@
 
 		new_m
 	}
-	/// Create new node around existing marker, not counting anything that comes after it
-	fn wrap_raw(self, p: &mut Parser, kind: SyntaxKind, error: Option<SyntaxError>) -> Self {
+	/// Create new node around existing marker
+	/// If previous_pos is set - the wrapping node would not include everything that happened between wrapped node end and the current position of the parser
+	fn wrap_raw(
+		self,
+		p: &mut Parser,
+		kind: SyntaxKind,
+		error: Option<SyntaxError>,
+		previous_pos: bool,
+	) -> Self {
 		let new_m = p.start();
 		match &mut p.events[self.start_event_idx] {
 			Event::Start { forward_parent, .. } => {
@@ -154,30 +161,33 @@
 
 		let completed = new_m.complete_raw(p, kind, error);
 
-		match &mut p.events[self.finish_event_idx] {
-			Event::Finish {
-				wrapper,
-				error: _error,
-			} => {
-				*wrapper = Some(
-					NonZeroUsize::new(completed.finish_event_idx - self.finish_event_idx)
-						.expect("!= 0"),
-				);
+		if previous_pos {
+			match &mut p.events[self.finish_event_idx] {
+				Event::Finish {
+					wrapper,
+					error: _error,
+				} => {
+					*wrapper = Some(
+						NonZeroUsize::new(completed.finish_event_idx - self.finish_event_idx)
+							.expect("!= 0"),
+					);
+				}
+				_ => unreachable!(),
 			}
-			_ => unreachable!(),
 		}
 		completed
 	}
-	pub fn wrap(self, p: &mut Parser, kind: SyntaxKind) -> Self {
-		self.wrap_raw(p, kind, None)
+	pub fn wrap(self, p: &mut Parser, kind: SyntaxKind, previous_pos: bool) -> Self {
+		self.wrap_raw(p, kind, None, previous_pos)
 	}
-	pub fn wrap_error(self, p: &mut Parser, msg: impl AsRef<str>) -> Self {
+	pub fn wrap_error(self, p: &mut Parser, msg: impl AsRef<str>, previous_pos: bool) -> Self {
 		self.wrap_raw(
 			p,
 			SyntaxKind::ERROR_CUSTOM,
 			Some(SyntaxError::Custom {
 				error: msg.as_ref().to_owned(),
 			}),
+			previous_pos,
 		)
 	}
 }
modifiedcrates/jrsonnet-rowan-parser/src/parser.rsdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/parser.rs
+++ b/crates/jrsonnet-rowan-parser/src/parser.rs
@@ -45,6 +45,18 @@
 		error: String,
 	},
 }
+impl fmt::Display for SyntaxError {
+	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+		match self {
+			SyntaxError::Unexpected { expected, found } => {
+				write!(f, "unexpected {found:?}, expecting {expected}")
+			}
+			SyntaxError::Missing { expected } => write!(f, "missing {expected}"),
+			SyntaxError::Custom { error } => write!(f, "{error}"),
+			SyntaxError::Hint { error } => write!(f, "{error}"),
+		}
+	}
+}
 
 #[derive(Debug)]
 pub struct LocatedSyntaxError {
@@ -316,12 +328,14 @@
 			break;
 		}
 
+		let m = lhs.wrap(p, EXPR, false);
+
 		// Object apply is not a real operator, we dont have something to bump
 		if op != BinaryOperatorKind::MetaObjectApply {
 			p.bump();
 		}
 
-		let m = lhs.wrap(p, EXPR).precede(p);
+		let m = m.precede(p);
 		let parsed_rhs = expr_binding_power(p, right_binding_power)
 			.map(|v| v.precede(p).complete(p, EXPR))
 			.is_ok();
@@ -491,12 +505,13 @@
 			errored.wrap_error(
 				p,
 				"compspec may only be used if there is only one object element",
+				true,
 			);
 		}
 		m.complete(p, OBJ_BODY_MEMBER_LIST);
 	} else if !compspecs.is_empty() {
 		for errored in asserts {
-			errored.wrap_error(p, "asserts can't be used in object comprehensions");
+			errored.wrap_error(p, "asserts can't be used in object comprehensions", true);
 		}
 		m.complete(p, OBJ_BODY_COMP);
 	} else {
@@ -569,7 +584,7 @@
 	}
 
 	for errored in unnamed_after_named {
-		errored.wrap_error(p, "can't use positional arguments after named");
+		errored.wrap_error(p, "can't use positional arguments after named", true);
 	}
 
 	m.complete(p, ARGS_DESC);
@@ -615,6 +630,7 @@
 			spec.wrap_error(
 				p,
 				"compspec may only be used if there is only one array element",
+				true,
 			);
 		}
 
@@ -639,20 +655,20 @@
 		p.bump();
 		// End
 		if !p.at(T![']']) {
-			expr(p).wrap(p, SLICE_DESC_END);
+			expr(p).wrap(p, SLICE_DESC_END, true);
 		}
 		if p.at(T![:]) {
 			p.bump();
 			// Step
 			if !p.at(T![']']) {
-				expr(p).wrap(p, SLICE_DESC_STEP);
+				expr(p).wrap(p, SLICE_DESC_STEP, true);
 			}
 		}
 	} else if p.at(T![::]) {
 		p.bump();
 		// End
 		if !p.at(T![']']) {
-			expr(p).wrap(p, SLICE_DESC_END);
+			expr(p).wrap(p, SLICE_DESC_END, true);
 		}
 	} else {
 		// It was not a slice
@@ -865,10 +881,10 @@
 		p.bump();
 		expr(p);
 		p.expect(T![then]);
-		expr(p).wrap(p, TRUE_EXPR);
+		expr(p).wrap(p, TRUE_EXPR, true);
 		if p.at(T![else]) {
 			p.bump();
-			expr(p).wrap(p, FALSE_EXPR);
+			expr(p).wrap(p, FALSE_EXPR, true);
 		}
 		m.complete(p, EXPR_IF_THEN_ELSE)
 	} else if p.at(T!['[']) {
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_incompatible_with_multiple_elems.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_incompatible_with_multiple_elems.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_incompatible_with_multiple_elems.snap
@@ -49,9 +49,5 @@
 ===
 LocatedSyntaxError { error: Custom { error: "compspec may only be used if there is only one array element" }, range: 3..21 }
 ===
-  x syntax error
-   ,----
- 1 | [a for a in [1, 2, 3], b]
-   :    ^^^^^^^^^|^^^^^^^^
-   :             `-- compspec may only be used if there is only one array element
-   `----
+   ·    ╭──────────────────── compspec may only be used if there is only one array element
+1  │ [a for a in [1, 2, 3], b]
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_incompatible_with_multiple_elems_w.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_incompatible_with_multiple_elems_w.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_incompatible_with_multiple_elems_w.snap
@@ -56,9 +56,5 @@
 ===
 LocatedSyntaxError { error: Custom { error: "compspec may only be used if there is only one array element" }, range: 7..25 }
 ===
-  x syntax error
-   ,----
- 1 | [a, b, for a in [1, 2, 3], c]
-   :        ^^^^^^^^^|^^^^^^^^
-   :                 `-- compspec may only be used if there is only one array element
-   `----
+   ·        ╭──────────────────── compspec may only be used if there is only one array element
+1  │ [a, b, for a in [1, 2, 3], c]
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_no_elems.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_no_elems.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_no_elems.snap
@@ -39,9 +39,5 @@
 ===
 LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 1..1 }
 ===
-  x syntax error
-   ,----
- 1 | [for a in [1, 2, 3]]
-   :  ^
-   :  `-- missing expression
-   `----
+   ·  ╭── missing expression
+1  │ [for a in [1, 2, 3]]
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__continue_after_total_failure.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__continue_after_total_failure.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__continue_after_total_failure.snap
@@ -64,14 +64,9 @@
 LocatedSyntaxError { error: Unexpected { expected: Unnamed(SyntaxKindSet([L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA, QUESTION_MARK])), found: IDENT }, range: 14..23 }
 LocatedSyntaxError { error: Custom { error: "unexpected tokens after end" }, range: 29..67 }
 ===
-  x syntax error
-   ,-[1:15]
- 1 | ,-> local intr = $intrinsic(test);
-   : |                 ^^^^|^^^^
-   : |                     `-- expected L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA or QUESTION_MARK, found IDENT
- 2 | |
- 3 | |   local a = 1, b = 2, c = a + b;
- 4 | |
- 5 | |-> [c]
-   : `---- unexpected tokens after end
-   `----
+   ·                 ╭─────────── unexpected IDENT, expecting L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA or QUESTION_MARK
+1  │ ╭─local intr = $intrinsic(test);
+2  │ │
+3  │ │ local a = 1, b = 2, c = a + b;
+4  │ │
+5  │ ╰─[c]   🢒 unexpected tokens after end
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__empty.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__empty.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__empty.snap
@@ -9,9 +9,5 @@
 ===
 LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 1..1 }
 ===
-  x syntax error
-   ,----
- 1 |
-   :  ^
-   :  `-- missing expression
-   `----
+   ·  ╭── missing expression
+1  │
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function_error_body.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function_error_body.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function_error_body.snap
@@ -25,9 +25,5 @@
 ===
 LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 15..15 }
 ===
-  x syntax error
-   ,----
- 1 | function(a, b)
-   :                ^
-   :                `-- missing expression
-   `----
+   ·                ╭── missing expression
+1  │ function(a, b)
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function_error_no_value.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function_error_no_value.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function_error_no_value.snap
@@ -42,9 +42,5 @@
 ===
 LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 16..16 }
 ===
-  x syntax error
-   ,----
- 1 | function(a, b = ) a + b
-   :                 ^
-   :                 `-- missing expression
-   `----
+   ·                 ╭── missing expression
+1  │ function(a, b = ) a + b
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function_error_rparen.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function_error_rparen.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function_error_rparen.snap
@@ -26,10 +26,6 @@
 LocatedSyntaxError { error: Missing { expected: Unnamed(SyntaxKindSet([R_PAREN, COMMA, ASSIGN])) }, range: 14..14 }
 LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 14..14 }
 ===
-  x syntax error
-   ,----
- 1 | function(a, b
-   :               ^^
-   :               |`-- missing expression
-   :               `-- missing R_PAREN, COMMA or ASSIGN
-   `----
+   ·               ╭── missing R_PAREN, COMMA or ASSIGN
+1  │ function(a, b
+   ·               ╰── missing expression
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__local_no_value_recovery.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__local_no_value_recovery.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__local_no_value_recovery.snap
@@ -39,11 +39,8 @@
 LocatedSyntaxError { error: Missing { expected: Unnamed(SyntaxKindSet([L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA, QUESTION_MARK])) }, range: 25..25 }
 LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 25..25 }
 ===
-  x syntax error
-   ,-[3:3]
- 2 | local b = 3;
- 3 | 1
-   :   ^^
-   :   |`-- missing expression
-   :   `-- missing L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA or QUESTION_MARK
-   `----
+1  │ local a =
+2  │ local b = 3;
+   ·   ╭── missing L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA or QUESTION_MARK
+3  │ 1
+   ·   ╰── missing expression
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__local_novalue.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__local_novalue.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__local_novalue.snap
@@ -23,11 +23,7 @@
 LocatedSyntaxError { error: Missing { expected: Unnamed(SyntaxKindSet([SEMI, COMMA])) }, range: 10..10 }
 LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 10..10 }
 ===
-  x syntax error
-   ,----
- 1 | local a =
-   :           ^^^
-   :           `-- missing expression
-   :           |`-- missing SEMI or COMMA
-   :           `-- missing expression
-   `----
+   ·           ╭── missing SEMI or COMMA
+   ·           ┟── missing expression
+1  │ local a =
+   ·           ╰── missing expression
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__named_before_positional.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__named_before_positional.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__named_before_positional.snap
@@ -68,11 +68,7 @@
 LocatedSyntaxError { error: Custom { error: "can't use positional arguments after named" }, range: 16..17 }
 LocatedSyntaxError { error: Custom { error: "can't use positional arguments after named" }, range: 27..28 }
 ===
-  x syntax error
-   ,----
- 1 | a(1, 2, b=4, 3, 5, k = 12, 6)
-   :              |  |          |
-   :              |  |          `-- can't use positional arguments after named
-   :              |  `-- can't use positional arguments after named
-   :              `-- can't use positional arguments after named
-   `----
+   ·              ╭────── can't use positional arguments after named
+   ·              │  ╭─── can't use positional arguments after named
+1  │ a(1, 2, b=4, 3, 5, k = 12, 6)
+   ·                            ╰─── can't use positional arguments after named
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_lhs.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_lhs.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_lhs.snap
@@ -14,10 +14,6 @@
 LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 0..0 }
 LocatedSyntaxError { error: Custom { error: "unexpected tokens after end" }, range: 0..3 }
 ===
-  x syntax error
-   ,----
- 1 | + 2
-   : ^^|
-   : | `-- unexpected tokens after end
-   : `-- missing expression
-   `----
+   · ╭── missing expression
+1  │ + 2
+   · ╰───── unexpected tokens after end
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_operator.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_operator.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_operator.snap
@@ -13,9 +13,5 @@
 ===
 LocatedSyntaxError { error: Custom { error: "unexpected tokens after end" }, range: 2..3 }
 ===
-  x syntax error
-   ,----
- 1 | 2 2
-   :   |
-   :   `-- unexpected tokens after end
-   `----
+   ·   ╭─── unexpected tokens after end
+1  │ 2 2
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_rhs.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_rhs.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_rhs.snap
@@ -16,9 +16,5 @@
 ===
 LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 4..4 }
 ===
-  x syntax error
-   ,----
- 1 | a +
-   :     ^
-   :     `-- missing expression
-   `----
+   ·     ╭── missing expression
+1  │ a +
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_incompatible_with_asserts.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_incompatible_with_asserts.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_incompatible_with_asserts.snap
@@ -56,9 +56,5 @@
 ===
 LocatedSyntaxError { error: Custom { error: "asserts can't be used in object comprehensions" }, range: 1..9 }
 ===
-  x syntax error
-   ,----
- 1 | {assert 1, a: 1 for a in [1,2,3]}
-   :  ^^^^|^^^
-   :      `-- asserts can't be used in object comprehensions
-   `----
+   ·  ╭────────── asserts can't be used in object comprehensions
+1  │ {assert 1, a: 1 for a in [1,2,3]}
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_incompatible_with_multiple_elems.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_incompatible_with_multiple_elems.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_incompatible_with_multiple_elems.snap
@@ -58,9 +58,5 @@
 ===
 LocatedSyntaxError { error: Custom { error: "compspec may only be used if there is only one object element" }, range: 5..23 }
 ===
-  x syntax error
-   ,----
- 1 | {a:1 for a in [1, 2, 3], b:1}
-   :      ^^^^^^^^^|^^^^^^^^
-   :               `-- compspec may only be used if there is only one object element
-   `----
+   ·      ╭──────────────────── compspec may only be used if there is only one object element
+1  │ {a:1 for a in [1, 2, 3], b:1}
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_incompatible_with_multiple_elems_w.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_incompatible_with_multiple_elems_w.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_incompatible_with_multiple_elems_w.snap
@@ -69,9 +69,5 @@
 ===
 LocatedSyntaxError { error: Custom { error: "compspec may only be used if there is only one object element" }, range: 11..29 }
 ===
-  x syntax error
-   ,----
- 1 | {a:1, b:1, for a in [1, 2, 3], c:1}
-   :            ^^^^^^^^^|^^^^^^^^
-   :                     `-- compspec may only be used if there is only one object element
-   `----
+   ·            ╭──────────────────── compspec may only be used if there is only one object element
+1  │ {a:1, b:1, for a in [1, 2, 3], c:1}
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_no_elems.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_no_elems.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_no_elems.snap
@@ -39,9 +39,5 @@
 ===
 LocatedSyntaxError { error: Missing { expected: Named("field definition") }, range: 1..1 }
 ===
-  x syntax error
-   ,----
- 1 | {for a in [1, 2, 3]}
-   :  ^
-   :  `-- missing field definition
-   `----
+   ·  ╭── missing field definition
+1  │ {for a in [1, 2, 3]}
deletedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__stdlib.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__super_nesting.snapdiffbeforeafterboth
--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__super_nesting.snap
@@ -0,0 +1,25 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "super.a + super.b\n"
+---
+SOURCE_FILE@0..18
+  EXPR@0..17
+    EXPR_BINARY@0..17
+      EXPR@0..7
+        EXPR_LITERAL@0..5
+          SUPER_KW@0..5 "super"
+        SUFFIX_INDEX@5..7
+          DOT@5..6 "."
+          NAME@6..7
+            IDENT@6..7 "a"
+      WHITESPACE@7..8 " "
+      PLUS@8..9 "+"
+      WHITESPACE@9..10 " "
+      EXPR@10..17
+        EXPR_LITERAL@10..15
+          SUPER_KW@10..15 "super"
+        SUFFIX_INDEX@15..17
+          DOT@15..16 "."
+          NAME@16..17
+            IDENT@16..17 "b"
+  WHITESPACE@17..18 "\n"
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__unexpected_destruct.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__unexpected_destruct.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__unexpected_destruct.snap
@@ -25,10 +25,6 @@
 ===
 LocatedSyntaxError { error: Unexpected { expected: Named("destruction specifier"), found: MUL }, range: 6..7 }
 ===
-  x syntax error
-   ,-[1:7]
- 1 | local * = 1;
-   :       |
-   :       `-- expected destruction specifier, found MUL
- 2 | a
-   `----
+   ·       ╭─── unexpected MUL, expecting destruction specifier
+1  │ local * = 1;
+2  │ a
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__wrong_field_end.snapdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__wrong_field_end.snap
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__wrong_field_end.snap
@@ -38,14 +38,9 @@
 LocatedSyntaxError { error: Unexpected { expected: Named("comma"), found: SEMI }, range: 7..8 }
 LocatedSyntaxError { error: Unexpected { expected: Named("comma"), found: SEMI }, range: 14..15 }
 ===
-  x syntax error
-   ,-[2:6]
- 1 | {
- 2 |     a: 1;
-   :         |
-   :         `-- expected comma, found SEMI
- 3 |     b: 2;
-   :         |
-   :         `-- expected comma, found SEMI
- 4 | }
-   `----
+1  │ {
+   ·         ╭─── unexpected SEMI, expecting comma
+2  │     a: 1;
+   ·         ╭─── unexpected SEMI, expecting comma
+3  │     b: 2;
+4  │ }
modifiedcrates/jrsonnet-rowan-parser/src/tests.rsdiffbeforeafterboth
--- a/crates/jrsonnet-rowan-parser/src/tests.rs
+++ b/crates/jrsonnet-rowan-parser/src/tests.rs
@@ -1,49 +1,11 @@
 // `never`
-#![cfg(any())]
+#![cfg(test)]
 
-use miette::{
-	Diagnostic, GraphicalReportHandler, GraphicalTheme, LabeledSpan, ThemeCharacters, ThemeStyles,
-};
+use hi_doc::{Formatting, SnippetBuilder, Text};
 use thiserror::Error;
 
 use crate::{parse, AstNode};
-
-#[derive(Debug, Error)]
-#[error("syntax error")]
-struct MyDiagnostic {
-	code: String,
-	spans: Vec<LabeledSpan>,
-}
-impl Diagnostic for MyDiagnostic {
-	fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
-		None
-	}
-
-	fn severity(&self) -> Option<miette::Severity> {
-		None
-	}
-
-	fn help<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
-		None
-	}
-
-	fn url<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
-		None
-	}
 
-	fn source_code(&self) -> Option<&dyn miette::SourceCode> {
-		Some(&self.code)
-	}
-
-	fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
-		Some(Box::new(self.spans.clone().into_iter()))
-	}
-
-	fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
-		None
-	}
-}
-
 fn process(text: &str) -> String {
 	use std::fmt::Write;
 	let mut out = String::new();
@@ -63,20 +25,21 @@
 		}
 		code += " ";
 
-		let diag = MyDiagnostic {
-			code,
-			spans: errors.into_iter().map(|e| e.into()).collect(),
-		};
+		let mut s = SnippetBuilder::new(code);
 
-		let handler = GraphicalReportHandler::new_themed(GraphicalTheme {
-			characters: ThemeCharacters::ascii(),
-			styles: ThemeStyles::none(),
-		});
+		for error in errors {
+			s.error(Text::fragment(
+				format!("{}", error.error),
+				Formatting::default(),
+			))
+			.range(error.range.start().into()..=error.range.end().into())
+			.build();
+		}
 
 		writeln!(out, "===").unwrap();
-		handler
-			.render_report(&mut out, &diag)
-			.expect("fmt error?..");
+		let ansi = hi_doc::source_to_ansi(&s.build());
+		let text = strip_ansi_escapes::strip_str(&ansi);
+		out.push_str(&text);
 	}
 	out.split('\n')
 		.map(|s| s.trim_end().to_string())
@@ -237,14 +200,12 @@
 
 		[c]
 	"#
+
+	super_nesting => r#"
+		super.a + super.b
+	"#
 );
 
-#[test]
-fn stdlib() {
-	let src = include_str!("../../jrsonnet-stdlib/src/std.jsonnet");
-	let result = process(src);
-	insta::assert_snapshot!("stdlib", result, src);
-}
 #[test]
 fn eval_simple() {
 	let src = "local a = 1, b = 2; a + local c = 1; c";