Add documentation

This commit is contained in:
Austen Adler 2024-09-03 23:25:22 -04:00
parent 466e14bcc9
commit 204dfec1dd

View File

@ -20,7 +20,9 @@ struct Cli {
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]
enum Command { enum Command {
#[clap(about = "Format a single file or stdin")]
Fmt(FmtArgs), Fmt(FmtArgs),
#[clap(about = "Watch a file or directory for changes")]
Watch(WatchArgs), Watch(WatchArgs),
} }
@ -28,31 +30,36 @@ enum Command {
struct WatchArgs { struct WatchArgs {
path: PathBuf, path: PathBuf,
#[clap(short = 'e', long = "extension", default_values = ["jsonc", "jsoncc"])] #[clap(short = 'e', long = "extension", default_values = ["jsonc", "jsoncc"], help = "File extensions to track")]
extensions: Vec<OsString>, extensions: Vec<OsString>,
#[clap(short = 'r', long = "recursive")] #[clap(short = 'r', long = "recursive", help = "Recursively search files")]
recursive: bool, recursive: bool,
#[clap(short = 'I', long = "inplace")] #[clap(short = 'I', long = "inplace", help = "Replace each file inplace")]
inplace: bool, inplace: bool,
} }
#[derive(Args, Debug)] #[derive(Args, Debug)]
struct FmtArgs { struct FmtArgs {
// #[clap(short = 'i', long = "input")] // #[clap(short = 'i', long = "input")]
input: PathBuf, #[clap(help = "Input file, or `-` for stdin")]
input: Option<PathBuf>,
#[clap(short = 'o', long = "output")] #[clap(
short = 'o',
long = "output",
help = "Output file; will be stdout if no output is specified"
)]
output: Option<PathBuf>, output: Option<PathBuf>,
#[clap(short = 'O', long = "json-output")] #[clap(short = 'O', long = "json-output", help = "Output file for json")]
json_output: Option<PathBuf>, json_output: Option<PathBuf>,
#[clap(short = 'c', long = "compact")] #[clap(short = 'c', long = "compact", help = "Compact json format")]
compact: bool, compact: bool,
#[clap(short = 'I', long = "inplace")] #[clap(short = 'I', long = "inplace", help = "Replace file contents inplace")]
inplace: bool, inplace: bool,
} }
@ -60,7 +67,9 @@ impl FmtArgs {
/// Where should we format Jsonc output to? /// Where should we format Jsonc output to?
fn jsonc_output(&self) -> Option<JsoncOutput> { fn jsonc_output(&self) -> Option<JsoncOutput> {
if self.inplace { if self.inplace {
Some(JsoncOutput::File(&self.input)) Some(JsoncOutput::File(self.input.as_ref().expect(
"Argument parsing error -- input was empty, but --inplace was specified",
)))
} else if let Some(ref output_file) = &self.output { } else if let Some(ref output_file) = &self.output {
Some(JsoncOutput::File(output_file)) Some(JsoncOutput::File(output_file))
} else if self.json_output.is_some() { } else if self.json_output.is_some() {
@ -81,8 +90,6 @@ enum JsoncOutput<'a> {
fn main() -> Result<()> { fn main() -> Result<()> {
let options = Cli::parse(); let options = Cli::parse();
eprintln!("Options: {options:?}");
match options.command { match options.command {
Command::Fmt(a) => { Command::Fmt(a) => {
// TODO: Figure out how to validate this in clap Parser // TODO: Figure out how to validate this in clap Parser
@ -93,7 +100,7 @@ fn main() -> Result<()> {
bail!("Cannot format --inplace when --output is specified"); bail!("Cannot format --inplace when --output is specified");
} }
format_single_file( format_single_file(
&a.input, a.input.as_ref(),
a.jsonc_output().as_ref(), a.jsonc_output().as_ref(),
a.json_output.as_ref(), a.json_output.as_ref(),
a.compact, a.compact,
@ -106,21 +113,25 @@ fn main() -> Result<()> {
} }
fn format_single_file( fn format_single_file(
input: impl AsRef<Path>, input: Option<impl AsRef<Path>>,
jsonc_output: Option<&JsoncOutput>, jsonc_output: Option<&JsoncOutput>,
json_output: Option<impl AsRef<Path>>, json_output: Option<impl AsRef<Path>>,
json_compact: bool, json_compact: bool,
) -> Result<()> { ) -> Result<()> {
let input_str = fs::read_to_string(&input).context("Reading input")?; let input_str = if let Some(input_filename) = input {
fs::read_to_string(&input_filename).context("Reading input")?
} else {
std::io::read_to_string(std::io::stdin()).context("Reading stdin")?
};
// First, format jsonc // First, format jsonc
if let Some(jsonc_output) = jsonc_output { if let Some(jsonc_output) = jsonc_output {
let output = fjson::to_jsonc(&input_str).context("Formatting to jsonc")?; let output = fjson::to_jsonc(&input_str).context("Parsing jsonc")?;
match jsonc_output { match jsonc_output {
JsoncOutput::Stdout => print!("{output}"), JsoncOutput::Stdout => print!("{output}"),
JsoncOutput::File(output_file) => AtomicFile::new(output_file, AllowOverwrite) JsoncOutput::File(output_file) => AtomicFile::new(output_file, AllowOverwrite)
.write(|f| f.write_all(&output.as_bytes())) .write(|f| f.write_all(output.as_bytes()))
.context("Writing jsonc output")?, .context("Writing jsonc output")?,
} }
} }
@ -133,9 +144,13 @@ fn format_single_file(
fjson::to_json_compact(&input_str).context("Formatting to json") fjson::to_json_compact(&input_str).context("Formatting to json")
}?; }?;
AtomicFile::new(json_output_file, AllowOverwrite) if json_output_file.as_ref().as_os_str() == "-" {
.write(|f| f.write_all(&output.as_bytes())) print!("{output}");
.context("Writing jsonc output")?; } else {
AtomicFile::new(json_output_file, AllowOverwrite)
.write(|f| f.write_all(output.as_bytes()))
.context("Writing jsonc output")?;
}
} }
Ok(()) Ok(())
@ -181,7 +196,7 @@ fn watch(args: &WatchArgs) -> Result<()> {
if !(args if !(args
.extensions .extensions
.iter() .iter()
.any(|ext| (&path).extension() == Some(ext)) .any(|ext| path.extension() == Some(ext))
|| args.extensions.is_empty()) || args.extensions.is_empty())
{ {
// This extension doesn't match their requested extensions // This extension doesn't match their requested extensions
@ -196,7 +211,7 @@ fn watch(args: &WatchArgs) -> Result<()> {
eprintln!("Got result: {path:#?}"); eprintln!("Got result: {path:#?}");
match format_single_file( match format_single_file(
&path, Some(&path),
Some(&JsoncOutput::File(&path)), Some(&JsoncOutput::File(&path)),
None::<&Path>, None::<&Path>,
false, false,