git.delta.rocks / jrsonnet / refs/commits / 7da68eaa8a4d

difftreelog

source

cmds/jrsonnet-fmt/src/main.rs3.1 KiBsourcehistory
1use std::{2	fs,3	io::{self, Write as _},4	path::PathBuf,5	process,6};78use clap::Parser;9use jrsonnet_formatter::{format, FormatOptions};1011#[derive(Parser)]12#[allow(clippy::struct_excessive_bools)]13struct Opts {14	/// Treat input as code, reformat it instead of reading file.15	#[clap(long, short = 'e')]16	exec: bool,17	/// Path to be reformatted if `--exec` if unset, otherwise code itself.18	input: String,19	/// Replace code with formatted in-place, instead of printing it to stdout.20	/// Only applicable if `--exec` is unset.21	#[clap(long, short = 'i')]22	in_place: bool,2324	/// Exit with error if formatted does not match input25	#[arg(long)]26	test: bool,27	/// Number of spaces to indent with28	#[arg(long, default_value = "2")]29	indent: u8,30	/// Force hard tab for indentation31	#[arg(long)]32	hard_tabs: bool,3334	/// Debug option: how many times to call reformatting in case of unstable dprint output resolution.35	///36	/// 0 for not retrying to reformat.37	#[arg(long, default_value = "0")]38	conv_limit: usize,39}4041#[derive(thiserror::Error, Debug)]42enum Error {43	#[error("--in-place is incompatible with --exec")]44	InPlaceExec,45	#[error("io: {0}")]46	Io(#[from] io::Error),47	#[error("persist: {0}")]48	Persist(#[from] tempfile::PersistError),49	#[error("parsing failed, refusing to reformat corrupted input")]50	Parse,51}5253fn main_result() -> Result<(), Error> {54	eprintln!("jrsonnet-fmt is a prototype of a jsonnet code formatter, do not expect it to produce meaningful results right now.");55	eprintln!("It is not expected for its output to match other implementations, it will be completly separate implementation with maybe different name.");56	let mut opts = Opts::parse();57	let input = if opts.exec {58		if opts.in_place {59			return Err(Error::InPlaceExec);60		}61		opts.input.clone()62	} else {63		fs::read_to_string(&opts.input)?64	};6566	if opts.indent == 0 {67		// Sane default.68		// TODO: Implement actual guessing.69		opts.hard_tabs = true;70	}7172	let mut iteration = 0;73	let mut formatted = input.clone();74	let mut convergence_tmp;75	// https://github.com/dprint/dprint/pull/42376	loop {77		let reformatted = match format(78			&formatted,79			&FormatOptions {80				indent: if opts.indent == 0 || opts.hard_tabs {81					082				} else {83					opts.indent84				},85			},86		) {87			Ok(v) => v,88			Err(e) => {89				let snippet = e.build();90				let ansi = hi_doc::source_to_ansi(&snippet);91				eprintln!("{ansi}");92				return Err(Error::Parse);93			}94		};95		convergence_tmp = reformatted.trim().to_owned();96		if formatted == convergence_tmp {97			break;98		}99		formatted = convergence_tmp;100		if opts.conv_limit == 0 {101			break;102		}103		iteration += 1;104		assert!(iteration <= opts.conv_limit, "formatting not converged");105	}106	formatted.push('\n');107	if opts.test && formatted != input {108		process::exit(1);109	}110	if opts.in_place {111		let path = PathBuf::from(opts.input);112		let mut temp = tempfile::NamedTempFile::new_in(path.parent().expect(113			"not failed during read, this path is not a directory, and there is a parent",114		))?;115		temp.write_all(formatted.as_bytes())?;116		temp.flush()?;117		temp.persist(&path)?;118	} else {119		print!("{formatted}");120	}121	Ok(())122}123124fn main() {125	if let Err(e) = main_result() {126		eprintln!("{e}");127		process::exit(1);128	}129}