git.delta.rocks / jrsonnet / refs/commits / 0c7230b6eb21

difftreelog

fix(fmt) multi-line ArgsDesc

nxklpotmYaroslav Bolyukin2026-02-08parent: #36e84a6.patch.diff
in: master

8 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -644,6 +644,8 @@
 dependencies = [
  "dprint-core",
  "hi-doc",
+ "indoc",
+ "insta",
  "jrsonnet-rowan-parser",
 ]
 
modifiedcmds/jrsonnet-fmt/src/main.rsdiffbeforeafterboth
--- a/cmds/jrsonnet-fmt/src/main.rs
+++ b/cmds/jrsonnet-fmt/src/main.rs
@@ -1,4 +1,9 @@
-use std::{fs, io};
+use std::{
+	fs,
+	io::{self, Write as _},
+	path::PathBuf,
+	process,
+};
 
 use clap::Parser;
 use jrsonnet_formatter::{format, FormatOptions};
modifiedcrates/jrsonnet-formatter/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-formatter/Cargo.toml
+++ b/crates/jrsonnet-formatter/Cargo.toml
@@ -9,6 +9,8 @@
 [dependencies]
 dprint-core.workspace = true
 hi-doc.workspace = true
+indoc.workspace = true
+insta.workspace = true
 jrsonnet-rowan-parser.workspace = true
 
 [lints]
modifiedcrates/jrsonnet-formatter/src/lib.rsdiffbeforeafterboth
before · crates/jrsonnet-formatter/src/lib.rs
1use std::{any::type_name, rc::Rc};23use children::{children_between, trivia_before};4use dprint_core::formatting::{5	condition_helpers::is_multiple_lines, condition_resolvers::true_resolver,6	ConditionResolverContext, LineNumber, PrintItems, PrintOptions,7};8use hi_doc::{Formatting, SnippetBuilder};9use jrsonnet_rowan_parser::{10	nodes::{11		Arg, ArgsDesc, Assertion, BinaryOperator, Bind, CompSpec, Destruct, DestructArrayPart,12		DestructRest, Expr, ExprBase, FieldName, ForSpec, IfSpec, ImportKind, Literal, Member,13		Name, Number, ObjBody, ObjLocal, ParamsDesc, SliceDesc, SourceFile, Stmt, Suffix, Text,14		UnaryOperator, Visibility,15	},16	AstNode, AstToken as _, SyntaxToken,17};1819use crate::{20	children::trivia_after,21	comments::{format_comments, CommentLocation},22};2324mod children;25mod comments;26#[cfg(test)]27mod tests;2829pub trait Printable {30	fn print(&self, out: &mut PrintItems);31}3233macro_rules! pi {34	(@i; $($t:tt)*) => {{35		#[allow(unused_mut)]36		let mut o = dprint_core::formatting::PrintItems::new();37		pi!(@s; o: $($t)*);38		o39	}};40	(@s; $o:ident: str($e:expr $(,)?) $($t:tt)*) => {{41		$o.push_string($e.to_owned());42		pi!(@s; $o: $($t)*);43	}};44	(@s; $o:ident: string($e:expr $(,)?) $($t:tt)*) => {{45		$o.push_string($e);46		pi!(@s; $o: $($t)*);47	}};48	(@s; $o:ident: nl $($t:tt)*) => {{49		$o.push_signal(dprint_core::formatting::Signal::NewLine);50		pi!(@s; $o: $($t)*);51	}};52	(@s; $o:ident: tab $($t:tt)*) => {{53		$o.push_signal(dprint_core::formatting::Signal::Tab);54		pi!(@s; $o: $($t)*);55	}};56	(@s; $o:ident: >i $($t:tt)*) => {{57		$o.push_signal(dprint_core::formatting::Signal::StartIndent);58		pi!(@s; $o: $($t)*);59	}};60	(@s; $o:ident: <i $($t:tt)*) => {{61		$o.push_signal(dprint_core::formatting::Signal::FinishIndent);62		pi!(@s; $o: $($t)*);63	}};64	(@s; $o:ident: info($v:expr) $($t:tt)*) => {{65		$o.push_info($v);66		pi!(@s; $o: $($t)*);67	}};68	(@s; $o:ident: if($s:literal, $cond:expr, $($i:tt)*) $($t:tt)*) => {{69		$o.push_condition(dprint_core::formatting::conditions::if_true(70			$s,71			$cond.clone(),72			{73				let mut o = PrintItems::new();74				p!(o, $($i)*);75				o76			},77		));78		pi!(@s; $o: $($t)*);79	}};80	(@s; $o:ident: if_else($s:literal, $cond:expr, $($i:tt)*)($($e:tt)+) $($t:tt)*) => {{81		$o.push_condition(dprint_core::formatting::conditions::if_true_or(82			$s,83			$cond.clone(),84			{85				let mut o = PrintItems::new();86				p!(o, $($i)*);87				o88			},89			{90				let mut o = PrintItems::new();91				p!(o, $($e)*);92				o93			},94		));95		pi!(@s; $o: $($t)*);96	}};97	(@s; $o:ident: if_not($s:literal, $cond:expr, $($e:tt)*) $($t:tt)*) => {{98		$o.push_condition(dprint_core::formatting::conditions::if_true_or(99			$s,100			$cond.clone(),101			{102				let o = PrintItems::new();103				o104			},105			{106				let mut o = PrintItems::new();107				p!(o, $($e)*);108				o109			},110		));111		pi!(@s; $o: $($t)*);112	}};113	(@s; $o:ident: {$expr:expr} $($t:tt)*) => {{114		$expr.print($o);115		pi!(@s; $o: $($t)*);116	}};117	(@s; $o:ident: items($expr:expr) $($t:tt)*) => {{118		$o.extend($expr);119		pi!(@s; $o: $($t)*);120	}};121	(@s; $o:ident: if ($e:expr)($($then:tt)*) $($t:tt)*) => {{122		if $e {123			pi!(@s; $o: $($then)*);124		}125		pi!(@s; $o: $($t)*);126	}};127	(@s; $o:ident: ifelse ($e:expr)($($then:tt)*)($($else:tt)*) $($t:tt)*) => {{128		if $e {129			pi!(@s; $o: $($then)*);130		} else {131			pi!(@s; $o: $($else)*);132		}133		pi!(@s; $o: $($t)*);134	}};135	(@s; $i:ident:) => {}136}137macro_rules! p {138	($o:ident, $($t:tt)*) => {139		pi!(@s; $o: $($t)*)140	};141}142pub(crate) use p;143pub(crate) use pi;144145impl<P> Printable for Option<P>146where147	P: Printable,148{149	fn print(&self, out: &mut PrintItems) {150		if let Some(v) = self {151			v.print(out);152		} else {153			p!(154				out,155				string(format!(156					"/*missing {}*/",157					type_name::<P>().replace("jrsonnet_rowan_parser::generated::nodes::", "")158				),)159			);160		}161	}162}163164impl Printable for SyntaxToken {165	fn print(&self, out: &mut PrintItems) {166		p!(out, string(self.to_string()));167	}168}169170impl Printable for Text {171	fn print(&self, out: &mut PrintItems) {172		p!(out, string(format!("{}", self)));173	}174}175impl Printable for Number {176	fn print(&self, out: &mut PrintItems) {177		p!(out, string(format!("{}", self)));178	}179}180181impl Printable for Name {182	fn print(&self, out: &mut PrintItems) {183		p!(out, { self.ident_lit() });184	}185}186187impl Printable for DestructRest {188	fn print(&self, out: &mut PrintItems) {189		p!(out, str("..."));190		if let Some(name) = self.into() {191			p!(out, { name });192		}193	}194}195196impl Printable for Destruct {197	fn print(&self, out: &mut PrintItems) {198		match self {199			Self::DestructFull(f) => {200				p!(out, { f.name() });201			}202			Self::DestructSkip(_) => p!(out, str("?")),203			Self::DestructArray(a) => {204				p!(out, str("[") >i nl);205				for el in a.destruct_array_parts() {206					match el {207						DestructArrayPart::DestructArrayElement(e) => {208							p!(out, {e.destruct()} str(",") nl);209						}210						DestructArrayPart::DestructRest(d) => {211							p!(out, {d} str(",") nl);212						}213					}214				}215				p!(out, <i str("]"));216			}217			Self::DestructObject(o) => {218				p!(out, str("{") >i nl);219				for item in o.destruct_object_fields() {220					p!(out, { item.field() });221					if let Some(des) = item.destruct() {222						p!(out, str(": ") {des});223					}224					if let Some(def) = item.expr() {225						p!(out, str(" = ") {def});226					}227					p!(out, str(",") nl);228				}229				if let Some(rest) = o.destruct_rest() {230					p!(out, {rest} nl);231				}232				p!(out, <i str("}"));233			}234		}235	}236}237238impl Printable for FieldName {239	fn print(&self, out: &mut PrintItems) {240		match self {241			Self::FieldNameFixed(f) => {242				if let Some(id) = f.id() {243					p!(out, { id });244				} else if let Some(str) = f.text() {245					p!(out, { str });246				} else {247					p!(out, str("/*missing FieldName*/"));248				}249			}250			Self::FieldNameDynamic(d) => {251				p!(out, str("[") {d.expr()} str("]"));252			}253		}254	}255}256257impl Printable for Visibility {258	fn print(&self, out: &mut PrintItems) {259		p!(out, string(self.to_string()));260	}261}262263impl Printable for ObjLocal {264	fn print(&self, out: &mut PrintItems) {265		p!(out, str("local ") {self.bind()});266	}267}268269impl Printable for Assertion {270	fn print(&self, out: &mut PrintItems) {271		p!(out, str("assert ") {self.condition()});272		if self.colon_token().is_some() || self.message().is_some() {273			p!(out, str(": ") {self.message()});274		}275	}276}277278impl Printable for ParamsDesc {279	fn print(&self, out: &mut PrintItems) {280		p!(out, str("(") >i nl);281		for param in self.params() {282			p!(out, { param.destruct() });283			if param.assign_token().is_some() || param.expr().is_some() {284				p!(out, str(" = ") {param.expr()});285			}286			p!(out, str(",") nl);287		}288		p!(out, <i str(")"));289	}290}291impl Printable for ArgsDesc {292	fn print(&self, out: &mut PrintItems) {293		let start = LineNumber::new("start");294		let end = LineNumber::new("end");295		let multi_line = Rc::new(move |condition_context: &mut ConditionResolverContext| {296			is_multiple_lines(condition_context, start, end).map(|v| !v)297		});298		p!(out, str("(") info(start) if("start args", multi_line, >i nl));299		let (children, end_comments) = children_between::<Arg>(300			self.syntax().clone(),301			self.l_paren_token().map(Into::into).as_ref(),302			self.r_paren_token().map(Into::into).as_ref(),303			None,304		);305		let mut args = children.into_iter().peekable();306		while let Some(ele) = args.next() {307			if ele.should_start_with_newline {308				p!(out, nl);309			}310			format_comments(&ele.before_trivia, CommentLocation::AboveItem, out);311			let arg = ele.value;312			if arg.name().is_some() || arg.assign_token().is_some() {313				p!(out, {arg.name()} str(" = "));314			}315			let comma_between = if args.peek().is_some() {316				true_resolver()317			} else {318				multi_line.clone()319			};320			p!(out, {arg.expr()} if("arg comma", comma_between, str(",") if_not("between args", multi_line, str(" "))));321			format_comments(&ele.inline_trivia, CommentLocation::ItemInline, out);322			p!(out, if("between args", multi_line, nl));323		}324		if end_comments.should_start_with_newline {325			p!(out, nl);326		}327		format_comments(&end_comments.trivia, CommentLocation::EndOfItems, out);328		p!(out, if("end args", multi_line, <i info(end)) str(")"));329	}330}331impl Printable for SliceDesc {332	fn print(&self, out: &mut PrintItems) {333		p!(out, str("["));334		if self.from().is_some() {335			p!(out, { self.from() });336		}337		p!(out, str(":"));338		if self.end().is_some() {339			p!(out, { self.end().map(|e| e.expr()) });340		}341		// Keep only one : in case if we don't need step342		if self.step().is_some() {343			p!(out, str(":") {self.step().map(|e|e.expr())});344		}345		p!(out, str("]"));346	}347}348349impl Printable for Member {350	fn print(&self, out: &mut PrintItems) {351		match self {352			Self::MemberBindStmt(b) => {353				p!(out, { b.obj_local() });354			}355			Self::MemberAssertStmt(ass) => {356				p!(out, { ass.assertion() });357			}358			Self::MemberFieldNormal(n) => {359				p!(out, {n.field_name()} if(n.plus_token().is_some())({n.plus_token()}) {n.visibility()} str(" ") {n.expr()});360			}361			Self::MemberFieldMethod(m) => {362				p!(out, {m.field_name()} {m.params_desc()} {m.visibility()} str(" ") {m.expr()});363			}364		}365	}366}367368impl Printable for ObjBody {369	fn print(&self, out: &mut PrintItems) {370		match self {371			Self::ObjBodyComp(l) => {372				let (children, mut end_comments) = children_between::<Member>(373					l.syntax().clone(),374					l.l_brace_token().map(Into::into).as_ref(),375					Some(376						&(l.comp_specs()377							.next()378							.expect("at least one spec is defined")379							.syntax()380							.clone())381						.into(),382					),383					None,384				);385				let trailing_for_comp = end_comments.extract_trailing();386				p!(out, str("{") >i nl);387				for mem in children {388					if mem.should_start_with_newline {389						p!(out, nl);390					}391					format_comments(&mem.before_trivia, CommentLocation::AboveItem, out);392					p!(out, {mem.value} str(","));393					format_comments(&mem.inline_trivia, CommentLocation::ItemInline, out);394					p!(out, nl);395				}396397				if end_comments.should_start_with_newline {398					p!(out, nl);399				}400				format_comments(&end_comments.trivia, CommentLocation::EndOfItems, out);401402				let (compspecs, end_comments) = children_between::<CompSpec>(403					l.syntax().clone(),404					l.member_comps()405						.last()406						.map(|m| m.syntax().clone())407						.map(Into::into)408						.or_else(|| l.l_brace_token().map(Into::into))409						.as_ref(),410					l.r_brace_token().map(Into::into).as_ref(),411					Some(trailing_for_comp),412				);413				for mem in compspecs {414					if mem.should_start_with_newline {415						p!(out, nl);416					}417					format_comments(&mem.before_trivia, CommentLocation::AboveItem, out);418					p!(out, { mem.value });419					format_comments(&mem.inline_trivia, CommentLocation::ItemInline, out);420				}421				if end_comments.should_start_with_newline {422					p!(out, nl);423				}424				format_comments(&end_comments.trivia, CommentLocation::EndOfItems, out);425426				p!(out, nl <i str("}"));427			}428			Self::ObjBodyMemberList(l) => {429				let (children, end_comments) = children_between::<Member>(430					l.syntax().clone(),431					l.l_brace_token().map(Into::into).as_ref(),432					l.r_brace_token().map(Into::into).as_ref(),433					None,434				);435				if children.is_empty() && end_comments.is_empty() {436					p!(out, str("{ }"));437					return;438				}439				p!(out, str("{") >i nl);440				for (i, mem) in children.into_iter().enumerate() {441					if mem.should_start_with_newline && i != 0 {442						p!(out, nl);443					}444					format_comments(&mem.before_trivia, CommentLocation::AboveItem, out);445					p!(out, {mem.value} str(","));446					format_comments(&mem.inline_trivia, CommentLocation::ItemInline, out);447					p!(out, nl);448				}449450				if end_comments.should_start_with_newline {451					p!(out, nl);452				}453				format_comments(&end_comments.trivia, CommentLocation::EndOfItems, out);454				p!(out, <i str("}"));455			}456		}457	}458}459impl Printable for UnaryOperator {460	fn print(&self, out: &mut PrintItems) {461		p!(out, string(self.text().to_string()));462	}463}464impl Printable for BinaryOperator {465	fn print(&self, out: &mut PrintItems) {466		p!(out, string(self.text().to_string()));467	}468}469impl Printable for Bind {470	fn print(&self, out: &mut PrintItems) {471		match self {472			Self::BindDestruct(d) => {473				p!(out, {d.into()} str(" = ") {d.value()});474			}475			Self::BindFunction(f) => {476				p!(out, {f.name()} {f.params()} str(" = ") {f.value()});477			}478		}479	}480}481impl Printable for Literal {482	fn print(&self, out: &mut PrintItems) {483		p!(out, string(self.syntax().to_string()));484	}485}486impl Printable for ImportKind {487	fn print(&self, out: &mut PrintItems) {488		p!(out, string(self.syntax().to_string()));489	}490}491impl Printable for ForSpec {492	fn print(&self, out: &mut PrintItems) {493		p!(out, str("for ") {self.bind()} str(" in ") {self.expr()});494	}495}496impl Printable for IfSpec {497	fn print(&self, out: &mut PrintItems) {498		p!(out, str("if ") {self.expr()});499	}500}501impl Printable for CompSpec {502	fn print(&self, out: &mut PrintItems) {503		match self {504			Self::ForSpec(f) => f.print(out),505			Self::IfSpec(i) => i.print(out),506		}507	}508}509impl Printable for Expr {510	fn print(&self, out: &mut PrintItems) {511		let (stmts, _ending) = children_between::<Stmt>(512			self.syntax().clone(),513			None,514			self.expr_base()515				.as_ref()516				.map(ExprBase::syntax)517				.cloned()518				.map(Into::into)519				.as_ref(),520			None,521		);522		for stmt in stmts {523			p!(out, { stmt.value });524		}525		p!(out, { self.expr_base() });526		let (suffixes, _ending) = children_between::<Suffix>(527			self.syntax().clone(),528			self.expr_base()529				.as_ref()530				.map(ExprBase::syntax)531				.cloned()532				.map(Into::into)533				.as_ref(),534			None,535			None,536		);537		for suffix in suffixes {538			p!(out, { suffix.value });539		}540	}541}542impl Printable for Suffix {543	fn print(&self, out: &mut PrintItems) {544		match self {545			Self::SuffixIndex(i) => {546				if i.question_mark_token().is_some() {547					p!(out, str("?"));548				}549				p!(out, str(".") {i.index()});550			}551			Self::SuffixIndexExpr(e) => {552				if e.question_mark_token().is_some() {553					p!(out, str(".?"));554				}555				p!(out, str("[") {e.index()} str("]"));556			}557			Self::SuffixSlice(d) => {558				p!(out, { d.slice_desc() });559			}560			Self::SuffixApply(a) => {561				p!(out, { a.args_desc() });562			}563		}564	}565}566impl Printable for Stmt {567	fn print(&self, out: &mut PrintItems) {568		match self {569			Self::StmtLocal(l) => {570				let (binds, end_comments) = children_between::<Bind>(571					l.syntax().clone(),572					l.local_kw_token().map(Into::into).as_ref(),573					l.semi_token().map(Into::into).as_ref(),574					None,575				);576				if binds.len() == 1 {577					let bind = &binds[0];578					format_comments(&bind.before_trivia, CommentLocation::AboveItem, out);579					p!(out, str("local ") {bind.value});580				// TODO: keep end_comments, child.inline_trivia somehow, force multiple locals formatting in case of presence?581				} else {582					p!(out,str("local") >i nl);583					for bind in binds {584						if bind.should_start_with_newline {585							p!(out, nl);586						}587						format_comments(&bind.before_trivia, CommentLocation::AboveItem, out);588						p!(out, {bind.value} str(","));589						format_comments(&bind.inline_trivia, CommentLocation::ItemInline, out);590						p!(out, nl);591					}592					if end_comments.should_start_with_newline {593						p!(out, nl);594					}595					format_comments(&end_comments.trivia, CommentLocation::EndOfItems, out);596					p!(out,<i);597				}598				p!(out,str(";") nl);599			}600			Self::StmtAssert(a) => {601				p!(out, {a.assertion()} str(";") nl);602			}603		}604	}605}606impl Printable for ExprBase {607	fn print(&self, out: &mut PrintItems) {608		match self {609			Self::ExprBinary(b) => {610				p!(out, {b.lhs_work()} str(" ") {b.binary_operator()} str(" ") {b.rhs_work()});611			}612			Self::ExprUnary(u) => p!(out, {u.unary_operator()} {u.rhs()}),613			// Self::ExprSlice(s) => {614			// 	p!(new: {s.expr()} {s.slice_desc()})615			// }616			// Self::ExprIndex(i) => {617			// 	p!(new: {i.expr()} str(".") {i.index()})618			// }619			// Self::ExprIndexExpr(i) => p!(new: {i.base()} str("[") {i.index()} str("]")),620			// Self::ExprApply(a) => {621			// 	let mut pi = p!(new: {a.expr()} {a.args_desc()});622			// 	if a.tailstrict_kw_token().is_some() {623			// 		p!(out,str(" tailstrict"));624			// 	}625			// 	pi626			// }627			Self::ExprObjExtend(ex) => {628				p!(out, {ex.lhs_work()} str(" ") {ex.rhs_work()});629			}630			Self::ExprParened(p) => {631				p!(out, str("(") {p.expr()} str(")"));632			}633			Self::ExprString(s) => p!(out, { s.text() }),634			Self::ExprNumber(n) => p!(out, { n.number() }),635			Self::ExprArray(a) => {636				p!(out, str("[") >i nl);637				for el in a.exprs() {638					p!(out, {el} str(",") nl);639				}640				p!(out, <i str("]"));641			}642			Self::ExprObject(obj) => {643				p!(out, { obj.obj_body() });644			}645			Self::ExprArrayComp(arr) => {646				p!(out, str("[") {arr.expr()});647				for spec in arr.comp_specs() {648					p!(out, str(" ") {spec});649				}650				p!(out, str("]"));651			}652			Self::ExprImport(v) => {653				p!(out, {v.import_kind()} str(" ") {v.text()});654			}655			Self::ExprVar(n) => p!(out, { n.name() }),656			// Self::ExprLocal(l) => {657			// }658			Self::ExprIfThenElse(ite) => {659				p!(out, str("if ") {ite.cond()} str(" then ") {ite.then().map(|t| t.expr())});660				if ite.else_kw_token().is_some() || ite.else_().is_some() {661					p!(out, str(" else ") {ite.else_().map(|t| t.expr())});662				}663			}664			Self::ExprFunction(f) => p!(out, str("function") {f.params_desc()} nl {f.expr()}),665			// Self::ExprAssert(a) => p!(new: {a.assertion()} str("; ") {a.expr()}),666			Self::ExprError(e) => p!(out, str("error ") {e.expr()}),667			Self::ExprLiteral(l) => {668				p!(out, { l.literal() });669			}670		}671	}672}673674impl Printable for SourceFile {675	fn print(&self, out: &mut PrintItems) {676		let before = trivia_before(677			self.syntax().clone(),678			self.expr()679				.map(|e| e.syntax().clone())680				.map(Into::into)681				.as_ref(),682		);683		let after = trivia_after(684			self.syntax().clone(),685			self.expr()686				.map(|e| e.syntax().clone())687				.map(Into::into)688				.as_ref(),689		);690		format_comments(&before, CommentLocation::AboveItem, out);691		p!(out, {self.expr()} nl);692		format_comments(&after, CommentLocation::EndOfItems, out);693	}694}695696pub struct FormatOptions {697	// 0 for hard tabs698	pub indent: u8,699}700pub fn format(input: &str, opts: &FormatOptions) -> Result<String, SnippetBuilder> {701	let (parsed, errors) = jrsonnet_rowan_parser::parse(input);702	if !errors.is_empty() {703		let mut builder = hi_doc::SnippetBuilder::new(input);704		for error in errors {705			builder706				.error(hi_doc::Text::fragment(707					format!("{:?}", error.error),708					Formatting::default(),709				))710				.range(711					error.range.start().into()712						..=(usize::from(error.range.end()) - 1).max(error.range.start().into()),713				)714				.build();715		}716		// let snippet = builder.build();717		return Err(builder);718		// It is possible to recover from this failure, but the output may be broken, as formatter is free to skip719		// ERROR rowan nodes.720		// Recovery needs to be enabled for LSP, though.721	}722	Ok(dprint_core::formatting::format(723		|| {724			let mut out = PrintItems::new();725			parsed.print(&mut out);726			out727		},728		PrintOptions {729			indent_width: if opts.indent == 0 {730				// Reasonable max length for both 2 and 4 space sized tabs.731				3732			} else {733				opts.indent734			},735			max_width: 100,736			use_tabs: opts.indent == 0,737			new_line_text: "\n",738		},739	))740}
deletedcrates/jrsonnet-formatter/src/snapshots/jrsonnet_fmt__tests__complex_comments_snapshot.snapdiffbeforeafterboth
--- a/crates/jrsonnet-formatter/src/snapshots/jrsonnet_fmt__tests__complex_comments_snapshot.snap
+++ /dev/null
@@ -1,53 +0,0 @@
----
-source: cmds/jrsonnet-fmt/src/tests.rs
-expression: "reformat(indoc!(\"{\n\t\t  comments: {\n\t\t\t_: '',\n\t\t\t//     Plain comment\n\t\t\ta: '',\n\n\t\t\t#    Plain comment with empty line before\n\t\t\tb: '',\n\t\t\t/*Single-line multiline comment\n\n\t\t\t*/\n\t\t\tc: '',\n\n\t\t\t/**Single-line multiline doc comment\n\n\t\t\t*/\n\t\t\tc: '',\n\n\t\t\t/**Multiline doc\n\t\t\tComment\n\t\t\t*/\n\t\t\tc: '',\n\n\t\t\t/*\n\n\tMulti-line\n\n\tcomment\n\t\t\t*/\n\t\t\td: '',\n\n\t\t\te: '', // Inline comment\n\n\t\t\tk: '',\n\n\t\t\t// Text after everything\n\t\t  },\n\t\t  comments2: {\n\t\t\tk: '',\n\t\t\t// Text after everything, but no newline above\n\t\t  },\n          spacing: {\n            a: '',\n\n            b: '',\n          },\n          noSpacing: {\n            a: '',\n            b: '',\n          },\n        }\"))"
----
-{
-	comments: {
-		_: '',
-		// Plain comment
-		a: '',
-
-		# Plain comment with empty line before
-		b: '',
-		/* Single-line multiline comment */
-		c: '',
-
-		/**
-		 * Single-line multiline doc comment
-		 */
-		c: '',
-
-		/**
-		 * Multiline doc
-		 * Comment
-		 */
-		c: '',
-
-		/*
-		Multi-line
-
-		comment
-		*/
-		d: '',
-
-		e: '', // Inline comment
-
-		k: '',
-
-		// Text after everything
-	},
-	comments2: {
-		k: '',
-		// Text after everything, but no newline above
-	},
-	spacing: {
-		a: '',
-
-		b: '',
-	},
-	noSpacing: {
-		a: '',
-		b: '',
-	},
-}
addedcrates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__args.snapdiffbeforeafterboth
--- /dev/null
+++ b/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__args.snap
@@ -0,0 +1,36 @@
+---
+source: crates/jrsonnet-formatter/src/tests.rs
+expression: "reformat(indoc!(\"\n\t\t\t{\n\t\t\t\tshort: aaa(1,2,3,4,5),\n\t\t\t\tlong: bbb(123123123123123123123,12312312321123123123,123123123123312123123,123123123123123123312,123123123123312321123),\n\t\t\t\tshort_in_long: bbb(aaa(1,2,3,4,5), 123123123123123123123,12312312321123123123,123123123123312123123,123123123123123123312,123123123123312321123),\n\t\t\t\tlong_in_short: aaa(1,2,3,4,5,bbb(123123123123123123123,12312312321123123123,123123123123312123123,123123123123123123312,123123123123312321123)),\n\t\t\t}\n\t\t\"))"
+---
+{
+	short: aaa(1, 2, 3, 4, 5),
+	long: bbb(
+		123123123123123123123,
+		12312312321123123123,
+		123123123123312123123,
+		123123123123123123312,
+		123123123123312321123,
+	),
+	short_in_long: bbb(
+		aaa(1, 2, 3, 4, 5),
+		123123123123123123123,
+		12312312321123123123,
+		123123123123312123123,
+		123123123123123123312,
+		123123123123312321123,
+	),
+	long_in_short: aaa(
+		1,
+		2,
+		3,
+		4,
+		5,
+		bbb(
+			123123123123123123123,
+			12312312321123123123,
+			123123123123312123123,
+			123123123123123123312,
+			123123123123312321123,
+		),
+	),
+}
addedcrates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__complex_comments.snapdiffbeforeafterboth
--- /dev/null
+++ b/crates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__complex_comments.snap
@@ -0,0 +1,53 @@
+---
+source: crates/jrsonnet-formatter/src/tests.rs
+expression: "reformat(indoc!(\"{\n\t\t  comments: {\n\t\t\t_: '',\n\t\t\t//     Plain comment\n\t\t\ta: '',\n\n\t\t\t#    Plain comment with empty line before\n\t\t\tb: '',\n\t\t\t/*Single-line multiline comment\n\n\t\t\t*/\n\t\t\tc: '',\n\n\t\t\t/**Single-line multiline doc comment\n\n\t\t\t*/\n\t\t\tc: '',\n\n\t\t\t/**Multiline doc\n\t\t\tComment\n\t\t\t*/\n\t\t\tc: '',\n\n\t\t\t/*\n\n\tMulti-line\n\n\tcomment\n\t\t\t*/\n\t\t\td: '',\n\n\t\t\te: '', // Inline comment\n\n\t\t\tk: '',\n\n\t\t\t// Text after everything\n\t\t  },\n\t\t  comments2: {\n\t\t\tk: '',\n\t\t\t// Text after everything, but no newline above\n\t\t  },\n          spacing: {\n            a: '',\n\n            b: '',\n          },\n          noSpacing: {\n            a: '',\n            b: '',\n          },\n        }\"))"
+---
+{
+	comments: {
+		_: '',
+		// Plain comment
+		a: '',
+
+		# Plain comment with empty line before
+		b: '',
+		/* Single-line multiline comment */
+		c: '',
+
+		/**
+		 * Single-line multiline doc comment
+		 */
+		c: '',
+
+		/**
+		 * Multiline doc
+		 * Comment
+		 */
+		c: '',
+
+		/*
+		Multi-line
+
+		comment
+		*/
+		d: '',
+
+		e: '', // Inline comment
+
+		k: '',
+
+		// Text after everything
+	},
+	comments2: {
+		k: '',
+		// Text after everything, but no newline above
+	},
+	spacing: {
+		a: '',
+
+		b: '',
+	},
+	noSpacing: {
+		a: '',
+		b: '',
+	},
+}
modifiedcrates/jrsonnet-formatter/src/tests.rsdiffbeforeafterboth
--- a/crates/jrsonnet-formatter/src/tests.rs
+++ b/crates/jrsonnet-formatter/src/tests.rs
@@ -22,7 +22,7 @@
 }
 
 #[test]
-fn complex_comments_snapshot() {
+fn complex_comments() {
 	insta::assert_snapshot!(reformat(indoc!(
 		"{
 		  comments: {
@@ -77,3 +77,17 @@
         }"
 	)));
 }
+
+#[test]
+fn args() {
+	insta::assert_snapshot!(reformat(indoc!(
+		"
+			{
+				short: aaa(1,2,3,4,5),
+				long: bbb(123123123123123123123,12312312321123123123,123123123123312123123,123123123123123123312,123123123123312321123),
+				short_in_long: bbb(aaa(1,2,3,4,5), 123123123123123123123,12312312321123123123,123123123123312123123,123123123123123123312,123123123123312321123),
+				long_in_short: aaa(1,2,3,4,5,bbb(123123123123123123123,12312312321123123123,123123123123312123123,123123123123123123312,123123123123312321123)),
+			}
+		"
+	)));
+}