Release next version
This commit is contained in:
parent
26e710d248
commit
ea1d77a208
76
Cargo.lock
generated
76
Cargo.lock
generated
@ -57,12 +57,6 @@ version = "1.0.86"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "arrayvec"
|
|
||||||
version = "0.7.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atomicwrites"
|
name = "atomicwrites"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
@ -123,7 +117,7 @@ dependencies = [
|
|||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 2.0.75",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -153,6 +147,17 @@ version = "0.8.20"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derivative"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
@ -181,15 +186,6 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fjson"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b9749dc2b27a3c20c7a10a40dff21369bcc7ed67e52b9e3d5858a1b6cd44cb5d"
|
|
||||||
dependencies = [
|
|
||||||
"arrayvec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fsevent-sys"
|
name = "fsevent-sys"
|
||||||
version = "4.1.0"
|
version = "4.1.0"
|
||||||
@ -239,8 +235,11 @@ dependencies = [
|
|||||||
"atomicwrites",
|
"atomicwrites",
|
||||||
"clap",
|
"clap",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"fjson",
|
"derivative",
|
||||||
|
"memchr",
|
||||||
"notify-debouncer-mini",
|
"notify-debouncer-mini",
|
||||||
|
"oxidized-json-checker",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -292,6 +291,12 @@ version = "0.4.22"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.8.11"
|
version = "0.8.11"
|
||||||
@ -340,6 +345,12 @@ version = "1.19.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "oxidized-json-checker"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "938464aebf563f48ab86d1cfc0e2df952985c0b814d3108f41d1b85e7f5b0dac"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.86"
|
version = "1.0.86"
|
||||||
@ -395,6 +406,17 @@ version = "0.11.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.109"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.75"
|
version = "2.0.75"
|
||||||
@ -419,6 +441,26 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "1.0.63"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "1.0.63"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.75",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.12"
|
version = "1.0.12"
|
||||||
|
10
Cargo.toml
10
Cargo.toml
@ -8,5 +8,13 @@ anyhow = "1.0.86"
|
|||||||
atomicwrites = "0.4.3"
|
atomicwrites = "0.4.3"
|
||||||
clap = { version = "4.5.16", features = ["derive"] }
|
clap = { version = "4.5.16", features = ["derive"] }
|
||||||
crossbeam-channel = "0.5.13"
|
crossbeam-channel = "0.5.13"
|
||||||
fjson = "0.3.1"
|
derivative = "2.2.0"
|
||||||
|
# fjson = {path="./fjson/"}
|
||||||
|
# fjson = "0.3.1"
|
||||||
|
memchr = "2.7.4"
|
||||||
notify-debouncer-mini = "0.4.1"
|
notify-debouncer-mini = "0.4.1"
|
||||||
|
oxidized-json-checker = "0.3.2"
|
||||||
|
thiserror = "1.0.63"
|
||||||
|
|
||||||
|
# [profile.release]
|
||||||
|
# debug = 2
|
||||||
|
2
src/lib.rs
Normal file
2
src/lib.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod parser;
|
||||||
|
pub mod indentor;
|
247
src/main.rs
247
src/main.rs
@ -1,167 +1,257 @@
|
|||||||
|
mod indentor;
|
||||||
|
mod parser;
|
||||||
|
|
||||||
use anyhow::{bail, Context, Error, Result};
|
use anyhow::{bail, Context, Error, Result};
|
||||||
use atomicwrites::{AtomicFile, OverwriteBehavior::AllowOverwrite};
|
use atomicwrites::{AtomicFile, OverwriteBehavior::AllowOverwrite};
|
||||||
use clap::{Args, Parser, Subcommand};
|
use clap::{Args, Parser, Subcommand};
|
||||||
use crossbeam_channel::{Receiver, Sender};
|
use crossbeam_channel::{Receiver, Sender};
|
||||||
use notify_debouncer_mini::{new_debouncer, notify::*, DebounceEventResult};
|
use notify_debouncer_mini::{new_debouncer, notify::*, DebounceEventResult};
|
||||||
|
use parser::Mode;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
|
convert::Infallible,
|
||||||
ffi::OsString,
|
ffi::OsString,
|
||||||
fs,
|
fs::File,
|
||||||
io::Write,
|
io::{BufRead, BufReader, BufWriter},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
str::FromStr,
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
|
#[clap(help = "Input file, or `-` for stdin", default_value = "-")]
|
||||||
|
input: IoArg,
|
||||||
|
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
command: Command,
|
command: Option<Command>,
|
||||||
|
|
||||||
|
#[command(flatten)]
|
||||||
|
fmt_args: FmtArgs,
|
||||||
|
|
||||||
|
#[clap(
|
||||||
|
short = 'o',
|
||||||
|
long = "jsoncc-output",
|
||||||
|
help = "Output file; will be stdout if no output is specified"
|
||||||
|
)]
|
||||||
|
output: Option<IoArg>,
|
||||||
|
|
||||||
|
#[clap(short = 'O', long = "json-output", help = "Output file for json")]
|
||||||
|
json_output: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand, Debug)]
|
#[derive(Subcommand, Debug)]
|
||||||
enum Command {
|
enum Command {
|
||||||
#[clap(about = "Format a single file or stdin")]
|
// #[clap(about = "Format a single file or stdin")]
|
||||||
Fmt(FmtArgs),
|
// Fmt(FmtArgs),
|
||||||
#[clap(about = "Watch a file or directory for changes")]
|
#[clap(about = "Watch a file or directory for changes")]
|
||||||
Watch(WatchArgs),
|
Watch(WatchArgs),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args, Debug)]
|
#[derive(Args, Debug)]
|
||||||
struct WatchArgs {
|
struct WatchArgs {
|
||||||
path: PathBuf,
|
// path: PathBuf,
|
||||||
|
|
||||||
#[clap(short = 'e', long = "extension", default_values = ["jsonc", "jsoncc"], help = "File extensions to track")]
|
#[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", help = "Recursively search files")]
|
#[clap(short = 'r', long = "recursive", help = "Recursively search files")]
|
||||||
recursive: bool,
|
recursive: bool,
|
||||||
|
// #[clap(short = 'I', long = "inplace", help = "Replace each file inplace")]
|
||||||
#[clap(short = 'I', long = "inplace", help = "Replace each file inplace")]
|
// inplace: bool,
|
||||||
inplace: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args, Debug)]
|
#[derive(Args, Debug, Clone)]
|
||||||
struct FmtArgs {
|
struct FmtArgs {
|
||||||
// #[clap(short = 'i', long = "input")]
|
|
||||||
#[clap(help = "Input file, or `-` for stdin")]
|
|
||||||
input: Option<PathBuf>,
|
|
||||||
|
|
||||||
#[clap(
|
#[clap(
|
||||||
short = 'o',
|
short = 'c',
|
||||||
long = "output",
|
long = "compact",
|
||||||
help = "Output file; will be stdout if no output is specified"
|
help = "Compact json format",
|
||||||
|
conflicts_with = "output"
|
||||||
)]
|
)]
|
||||||
output: Option<PathBuf>,
|
|
||||||
|
|
||||||
#[clap(short = 'O', long = "json-output", help = "Output file for json")]
|
|
||||||
json_output: Option<PathBuf>,
|
|
||||||
|
|
||||||
#[clap(short = 'c', long = "compact", help = "Compact json format")]
|
|
||||||
compact: bool,
|
compact: bool,
|
||||||
|
|
||||||
#[clap(short = 'I', long = "inplace", help = "Replace file contents inplace")]
|
#[clap(
|
||||||
|
short = 'I',
|
||||||
|
long = "inplace",
|
||||||
|
help = "Replace file contents inplace",
|
||||||
|
requires = "input"
|
||||||
|
)]
|
||||||
inplace: bool,
|
inplace: bool,
|
||||||
|
|
||||||
|
#[clap(short = 'V', long = "validate", help = "Validate input is valid")]
|
||||||
|
validate: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FmtArgs {
|
impl Cli {
|
||||||
/// 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<IoArgRef<'_>> {
|
||||||
if self.inplace {
|
if self.fmt_args.inplace {
|
||||||
Some(JsoncOutput::File(self.input.as_ref().expect(
|
if !matches!(self.input, IoArg::File(_)) {
|
||||||
"Argument parsing error -- input was empty, but --inplace was specified",
|
panic!("--inplace was specified, but input is not a file");
|
||||||
)))
|
}
|
||||||
} else if let Some(ref output_file) = &self.output {
|
|
||||||
Some(if output_file.as_os_str() == "-" {
|
Some(self.input.as_output())
|
||||||
JsoncOutput::Stdout
|
} else if self.output.is_some() {
|
||||||
} else {
|
self.output.as_ref().map(IoArg::as_output)
|
||||||
JsoncOutput::File(output_file)
|
|
||||||
})
|
|
||||||
} else if self.json_output.is_some() {
|
} else if self.json_output.is_some() {
|
||||||
// We don't want to output jsonc anywhere if they don't specify -o and they do specify -O
|
// We don't want to output jsonc anywhere if they don't specify -o and they do specify -O
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
// If they don't have any output specified, default to stdout
|
// If they don't have any output specified, default to stdout
|
||||||
Some(JsoncOutput::Stdout)
|
Some(IoArgRef::Stdio)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum JsoncOutput<'a> {
|
/// An argument that represents a file or stdin/stdout
|
||||||
Stdout,
|
#[derive(Debug, Clone)]
|
||||||
|
enum IoArg {
|
||||||
|
Stdio,
|
||||||
|
File(PathBuf),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for IoArg {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Stdio
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for IoArg {
|
||||||
|
type Err = Infallible;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||||
|
if s == "-" {
|
||||||
|
Ok(Self::Stdio)
|
||||||
|
} else {
|
||||||
|
PathBuf::from_str(s).map(Self::File)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IoArg {
|
||||||
|
fn as_output(&self) -> IoArgRef {
|
||||||
|
match self {
|
||||||
|
Self::Stdio => IoArgRef::Stdio,
|
||||||
|
Self::File(f) => IoArgRef::File(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl<'a> AsRef<Output<'a>> for IoArg {
|
||||||
|
// fn as_ref<'b>(&'b self) -> &'b Output<'a> {
|
||||||
|
// match self {
|
||||||
|
// IoArg::Stdio => &Output::Stdio,
|
||||||
|
// IoArg::File(f) => &Output::File(f),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum IoArgRef<'a> {
|
||||||
|
Stdio,
|
||||||
File(&'a Path),
|
File(&'a Path),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let options = Cli::parse();
|
let cli = Cli::parse();
|
||||||
|
|
||||||
match options.command {
|
match &cli.command {
|
||||||
Command::Fmt(a) => {
|
None => {
|
||||||
// TODO: Figure out how to validate this in clap Parser
|
// TODO: Figure out how to validate this in clap Parser
|
||||||
if a.compact && a.json_output.is_none() {
|
if cli.fmt_args.compact && cli.json_output.is_none() {
|
||||||
bail!("Cannot compact format jsonc. Specify --json-output if you want to use --compact");
|
bail!("Cannot compact format jsonc. Specify --json-output if you want to use --compact");
|
||||||
}
|
}
|
||||||
if a.inplace && a.output.is_some() {
|
if cli.fmt_args.inplace && cli.output.is_some() {
|
||||||
bail!("Cannot format --inplace when --output is specified");
|
bail!("Cannot format --inplace when --output is specified");
|
||||||
}
|
}
|
||||||
format_single_file(
|
format_single_file(
|
||||||
a.input.as_ref(),
|
&cli.input.as_output(),
|
||||||
a.jsonc_output().as_ref(),
|
cli.jsonc_output().as_ref(),
|
||||||
a.json_output.as_ref(),
|
cli.json_output.as_ref(),
|
||||||
a.compact,
|
&cli.fmt_args,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
Command::Watch(a) => watch(&a)?,
|
Some(Command::Watch(a)) => watch(&cli, a)?,
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Accept a [`FmtArgs`]
|
||||||
fn format_single_file(
|
fn format_single_file(
|
||||||
input: Option<impl AsRef<Path>>,
|
input: &IoArgRef,
|
||||||
jsonc_output: Option<&JsoncOutput>,
|
jsonc_output: Option<&IoArgRef>,
|
||||||
json_output: Option<impl AsRef<Path>>,
|
json_output: Option<impl AsRef<Path>>,
|
||||||
json_compact: bool,
|
fmt_args: &FmtArgs,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let input_str = if let Some(input_filename) = input {
|
let mut input: Box<dyn BufRead> = if let IoArgRef::File(input_filename) = input {
|
||||||
fs::read_to_string(&input_filename).context("Reading input")?
|
Box::new(BufReader::new(
|
||||||
|
File::open(input_filename).context("Reading input")?,
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
std::io::read_to_string(std::io::stdin()).context("Reading stdin")?
|
Box::new(BufReader::new(std::io::stdin().lock()))
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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("Parsing jsonc")?;
|
|
||||||
|
|
||||||
match jsonc_output {
|
match jsonc_output {
|
||||||
JsoncOutput::Stdout => print!("{output}"),
|
IoArgRef::Stdio => parser::Parser::new(
|
||||||
JsoncOutput::File(output_file) => AtomicFile::new(output_file, AllowOverwrite)
|
parser::Mode::Jsoncc,
|
||||||
.write(|f| f.write_all(output.as_bytes()))
|
&mut input,
|
||||||
.context("Writing jsonc output")?,
|
BufWriter::new(std::io::stdout()),
|
||||||
|
)
|
||||||
|
.format_buf()
|
||||||
|
.context("Formatting file")?,
|
||||||
|
IoArgRef::File(output_file) => AtomicFile::new(output_file, AllowOverwrite)
|
||||||
|
.write(|f| {
|
||||||
|
parser::Parser::new(parser::Mode::CompactJson, &mut input, BufWriter::new(f))
|
||||||
|
.format_buf()
|
||||||
|
})
|
||||||
|
.context("Formatting file")?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format json next
|
// Format json next
|
||||||
if let Some(ref json_output_file) = json_output {
|
if let Some(ref json_output_file) = json_output {
|
||||||
let output = if json_compact {
|
let mode = if fmt_args.compact {
|
||||||
fjson::to_json_compact(&input_str).context("Formatting to json")
|
Mode::CompactJson
|
||||||
} else {
|
} else {
|
||||||
fjson::to_json(&input_str).context("Formatting to json")
|
Mode::Json
|
||||||
}?;
|
};
|
||||||
|
|
||||||
if json_output_file.as_ref().as_os_str() == "-" {
|
if json_output_file.as_ref().as_os_str() == "-" {
|
||||||
print!("{output}");
|
parser::Parser::new(mode, &mut input, BufWriter::new(std::io::stdout()))
|
||||||
|
.format_buf()
|
||||||
|
.context("Formatting file")?
|
||||||
} else {
|
} else {
|
||||||
AtomicFile::new(json_output_file, AllowOverwrite)
|
AtomicFile::new(json_output_file, AllowOverwrite)
|
||||||
.write(|f| f.write_all(output.as_bytes()))
|
.write(|f| parser::Parser::new(mode, &mut input, BufWriter::new(f)).format_buf())
|
||||||
.context("Writing jsonc output")?;
|
.context("Writing json output")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate - Just duplicate code here. If they want to validate, it adds a little extra cost anyway
|
||||||
|
// Reformatting is probably not a big cost
|
||||||
|
if fmt_args.validate {
|
||||||
|
// TODO: Not
|
||||||
|
let mut buf = vec![];
|
||||||
|
parser::Parser::new(Mode::CompactJson, &mut input, BufWriter::new(&mut buf))
|
||||||
|
.format_buf()
|
||||||
|
.context("Formatting file")?;
|
||||||
|
|
||||||
|
oxidized_json_checker::validate(&buf[..])?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn watch(args: &WatchArgs) -> Result<()> {
|
fn watch(cli: &Cli, args: &WatchArgs) -> Result<()> {
|
||||||
let is_watching_file = args.path.is_file();
|
// The path to watch
|
||||||
|
let IoArg::File(ref watch_path) = cli.input else {
|
||||||
|
panic!("Input must be specified")
|
||||||
|
};
|
||||||
|
// True if we are watching only a single file
|
||||||
|
let is_watching_file = watch_path.is_file();
|
||||||
|
|
||||||
let (terminate_tx, terminate_rx): (Sender<Result<PathBuf>>, Receiver<Result<PathBuf>>) =
|
let (terminate_tx, terminate_rx): (Sender<Result<PathBuf>>, Receiver<Result<PathBuf>>) =
|
||||||
crossbeam_channel::bounded(100);
|
crossbeam_channel::bounded(100);
|
||||||
@ -186,7 +276,7 @@ fn watch(args: &WatchArgs) -> Result<()> {
|
|||||||
.watcher()
|
.watcher()
|
||||||
// TODO: Make this recursive or not
|
// TODO: Make this recursive or not
|
||||||
.watch(
|
.watch(
|
||||||
&args.path,
|
watch_path,
|
||||||
if args.recursive {
|
if args.recursive {
|
||||||
RecursiveMode::Recursive
|
RecursiveMode::Recursive
|
||||||
} else {
|
} else {
|
||||||
@ -198,7 +288,7 @@ fn watch(args: &WatchArgs) -> Result<()> {
|
|||||||
// Keep track of files that have just been formatted
|
// Keep track of files that have just been formatted
|
||||||
let mut just_formatted = HashSet::new();
|
let mut just_formatted = HashSet::new();
|
||||||
|
|
||||||
eprintln!("Watching {:?}", args.path);
|
eprintln!("Watching {:?}", watch_path);
|
||||||
|
|
||||||
while let Ok(evt) = terminate_rx.recv() {
|
while let Ok(evt) = terminate_rx.recv() {
|
||||||
match evt {
|
match evt {
|
||||||
@ -221,10 +311,10 @@ fn watch(args: &WatchArgs) -> Result<()> {
|
|||||||
eprintln!("Got result: {path:#?}");
|
eprintln!("Got result: {path:#?}");
|
||||||
|
|
||||||
match format_single_file(
|
match format_single_file(
|
||||||
Some(&path),
|
&IoArgRef::File(&path),
|
||||||
Some(&JsoncOutput::File(&path)),
|
Some(&IoArgRef::File(&path)),
|
||||||
None::<&Path>,
|
None::<&Path>,
|
||||||
false,
|
&cli.fmt_args,
|
||||||
) {
|
) {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
eprintln!("Formatted file {:?}", path);
|
eprintln!("Formatted file {:?}", path);
|
||||||
@ -234,12 +324,11 @@ fn watch(args: &WatchArgs) -> Result<()> {
|
|||||||
// This is because on formatting, the file is unlinked, so we lose our watch
|
// This is because on formatting, the file is unlinked, so we lose our watch
|
||||||
debouncer
|
debouncer
|
||||||
.watcher()
|
.watcher()
|
||||||
// TODO: Make this recursive or not
|
.watch(&path, RecursiveMode::NonRecursive)
|
||||||
.watch(&args.path, RecursiveMode::NonRecursive)
|
|
||||||
.context("Adding watch to debouncer")?;
|
.context("Adding watch to debouncer")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, we don't want to trigger anything for this file, so we ignore it next time
|
// We don't want to trigger anything for this file, so we ignore it next time
|
||||||
just_formatted.insert(path);
|
just_formatted.insert(path);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
1154
src/parser.rs
Normal file
1154
src/parser.rs
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user