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

difftreelog

source

cmds/jrsonnet-fmt/src/main.rs3.1 KiBsourcehistory
1use std::{fs, io};23use clap::Parser;4use jrsonnet_formatter::{format, FormatOptions};56#[derive(Parser)]7#[allow(clippy::struct_excessive_bools)]8struct Opts {9	/// Treat input as code, reformat it instead of reading file.10	#[clap(long, short = 'e')]11	exec: bool,12	/// Path to be reformatted if `--exec` if unset, otherwise code itself.13	input: String,14	/// Replace code with formatted in-place, instead of printing it to stdout.15	/// Only applicable if `--exec` is unset.16	#[clap(long, short = 'i')]17	in_place: bool,1819	/// Exit with error if formatted does not match input20	#[arg(long)]21	test: bool,22	/// Number of spaces to indent with23	#[arg(long, default_value = "2")]24	indent: u8,25	/// Force hard tab for indentation26	#[arg(long)]27	hard_tabs: bool,2829	/// Debug option: how many times to call reformatting in case of unstable dprint output resolution.30	///31	/// 0 for not retrying to reformat.32	#[arg(long, default_value = "0")]33	conv_limit: usize,34}3536#[derive(thiserror::Error, Debug)]37enum Error {38	#[error("--in-place is incompatible with --exec")]39	InPlaceExec,40	#[error("io: {0}")]41	Io(#[from] io::Error),42	#[error("persist: {0}")]43	Persist(#[from] tempfile::PersistError),44	#[error("parsing failed, refusing to reformat corrupted input")]45	Parse,46}4748fn main_result() -> Result<(), Error> {49	eprintln!("jrsonnet-fmt is a prototype of a jsonnet code formatter, do not expect it to produce meaningful results right now.");50	eprintln!("It is not expected for its output to match other implementations, it will be completly separate implementation with maybe different name.");51	let mut opts = Opts::parse();52	let input = if opts.exec {53		if opts.in_place {54			return Err(Error::InPlaceExec);55		}56		opts.input.clone()57	} else {58		fs::read_to_string(&opts.input)?59	};6061	if opts.indent == 0 {62		// Sane default.63		// TODO: Implement actual guessing.64		opts.hard_tabs = true;65	}6667	let mut iteration = 0;68	let mut formatted = input.clone();69	let mut convergence_tmp;70	// https://github.com/dprint/dprint/pull/42371	loop {72		let reformatted = match format(73			&formatted,74			&FormatOptions {75				indent: if opts.indent == 0 || opts.hard_tabs {76					077				} else {78					opts.indent79				},80			},81		) {82			Ok(v) => v,83			Err(e) => {84				let snippet = e.build();85				let ansi = hi_doc::source_to_ansi(&snippet);86				eprintln!("{ansi}");87				return Err(Error::Parse);88			}89		};90		convergence_tmp = reformatted.trim().to_owned();91		if formatted == convergence_tmp {92			break;93		}94		formatted = convergence_tmp;95		if opts.conv_limit == 0 {96			break;97		}98		iteration += 1;99		assert!(iteration <= opts.conv_limit, "formatting not converged");100	}101	formatted.push('\n');102	if opts.test && formatted != input {103		process::exit(1);104	}105	if opts.in_place {106		let path = PathBuf::from(opts.input);107		let mut temp = tempfile::NamedTempFile::new_in(path.parent().expect(108			"not failed during read, this path is not a directory, and there is a parent",109		))?;110		temp.write_all(formatted.as_bytes())?;111		temp.flush()?;112		temp.persist(&path)?;113	} else {114		print!("{formatted}");115	}116	Ok(())117}118119fn main() {120	if let Err(e) = main_result() {121		eprintln!("{e}");122		process::exit(1);123	}124}