use std::{path::PathBuf, sync::LazyLock};
use clap::{Args, CommandFactory, Parser, Subcommand, error::ErrorKind};
#[derive(Parser)]
#[command(
name = "typstyle",
about = "Beautiful and reliable typst code formatter",
author, version, long_version(LONG_VERSION.as_str())
)]
pub struct CliArguments {
#[command(subcommand)]
pub command: Option<Command>,
pub input: Vec<PathBuf>,
#[arg(short, long, default_value_t = false, conflicts_with_all = ["check", "diff"])]
pub inplace: bool,
#[arg(long, default_value_t = false, global = true, conflicts_with = "diff")]
pub check: bool,
#[arg(long, default_value_t = false, global = true, conflicts_with = "check")]
pub diff: bool,
#[command(flatten, next_help_heading = "Format Configuration")]
pub style: StyleArgs,
#[command(flatten, next_help_heading = "Debug Options")]
pub debug: DebugArgs,
#[command(flatten, next_help_heading = "Log Levels")]
pub log_level: LogLevelArgs,
}
impl CliArguments {
pub fn validate_input(&self) {
if self.command.is_none() && self.inplace && self.input.is_empty() {
let mut cmd = Self::command();
cmd.error(
ErrorKind::ValueValidation,
"cannot perform in-place formatting without at least one file being presented",
)
.exit();
}
}
}
#[derive(Subcommand)]
pub enum Command {
#[cfg(feature = "completion")]
#[command(hide = true)]
Completions {
#[arg(value_enum)]
shell: clap_complete::Shell,
},
}
#[derive(Args)]
pub struct StyleArgs {
#[arg(
short = 'l',
long,
visible_short_alias = 'c',
visible_alias = "column",
default_value_t = 80,
global = true
)]
pub line_width: usize,
#[arg(
short = 't',
long,
visible_alias = "tab-width",
default_value_t = 2,
global = true
)]
pub indent_width: usize,
#[arg(long, default_value_t = false, global = true)]
pub no_reorder_import_items: bool,
#[arg(long, default_value_t = false, global = true)]
pub wrap_text: bool,
}
#[derive(Args)]
pub struct DebugArgs {
#[arg(short, long, default_value_t = false)]
pub ast: bool,
#[arg(short, long, default_value_t = false)]
pub pretty_doc: bool,
#[arg(long, default_value_t = false)]
pub timing: bool,
}
#[derive(Args)]
pub struct LogLevelArgs {
#[arg(short, long, global = true, group = "verbosity")]
pub verbose: bool,
#[arg(short, long, global = true, group = "verbosity")]
pub quiet: bool,
}
static NONE: &str = "None";
static LONG_VERSION: LazyLock<String> = LazyLock::new(|| {
format!(
"
Version: {}
Build Timestamp: {}
Build Git Describe: {}
Commit SHA: {}
Commit Date: {}
Commit Branch: {}
Cargo Target Triple: {}
",
env!("CARGO_PKG_VERSION"),
env!("VERGEN_BUILD_TIMESTAMP"),
option_env!("VERGEN_GIT_DESCRIBE").unwrap_or(NONE),
option_env!("VERGEN_GIT_SHA").unwrap_or(NONE),
option_env!("VERGEN_GIT_COMMIT_TIMESTAMP").unwrap_or(NONE),
option_env!("VERGEN_GIT_BRANCH").unwrap_or(NONE),
env!("VERGEN_CARGO_TARGET_TRIPLE"),
)
});