use clap::{ArgEnum, StructOpt};
use std::path::PathBuf;
use stylua_lib::{CallParenType, CollapseSimpleStatement, IndentType, LineEndings, QuoteStyle};
lazy_static::lazy_static! {
static ref NUM_CPUS: String = num_cpus::get().to_string();
}
#[derive(StructOpt, Debug)]
#[structopt(name = "stylua", about = "A utility to format Lua code", version)]
pub struct Opt {
#[structopt(long = "config-path", short = 'f', parse(from_os_str))]
pub config_path: Option<PathBuf>,
#[structopt(long = "stdin-filepath", parse(from_os_str))]
pub stdin_filepath: Option<PathBuf>,
#[structopt(short, long)]
pub search_parent_directories: bool,
#[structopt(short, long)]
pub check: bool,
#[structopt(long, arg_enum, ignore_case = true, default_value_t = OutputFormat::Standard)]
pub output_format: OutputFormat,
#[structopt(long)]
pub verify: bool,
#[structopt(short, long)]
pub verbose: bool,
#[structopt(long, ignore_case = true, default_value_t = Color::Auto, arg_enum)]
pub color: Color,
#[structopt(short, long)]
pub glob: Option<Vec<String>>,
#[structopt(long, default_value = &NUM_CPUS)]
pub num_threads: usize,
#[structopt(long)]
pub range_start: Option<usize>,
#[structopt(long)]
pub range_end: Option<usize>,
#[structopt(flatten, next_help_heading = "FORMATTING OPTIONS")]
pub format_opts: FormatOpts,
#[structopt(parse(from_os_str))]
pub files: Vec<PathBuf>,
#[structopt(short, long)]
pub allow_hidden: bool,
}
#[derive(ArgEnum, Clone, Copy, Debug, PartialEq, Eq)]
#[clap(rename_all = "PascalCase")]
pub enum Color {
Always,
Auto,
Never,
}
impl Color {
pub fn should_use_color(&self) -> bool {
match self {
Color::Always => true,
Color::Never => false,
Color::Auto => {
let terminal = console::Term::stdout();
let features = terminal.features();
features.is_attended() && features.colors_supported()
}
}
}
pub fn should_use_color_stderr(&self) -> bool {
match self {
Color::Always => true,
Color::Never => false,
Color::Auto => {
let terminal = console::Term::stderr();
let features = terminal.features();
features.is_attended() && features.colors_supported()
}
}
}
}
#[derive(ArgEnum, Clone, Copy, Debug)]
#[clap(rename_all = "PascalCase")]
pub enum OutputFormat {
Standard,
Unified,
Json,
Summary,
}
#[derive(StructOpt, Debug)]
pub struct FormatOpts {
#[structopt(long)]
pub column_width: Option<usize>,
#[structopt(long, arg_enum, ignore_case = true)]
pub line_endings: Option<ArgLineEndings>,
#[structopt(long, arg_enum, ignore_case = true)]
pub indent_type: Option<ArgIndentType>,
#[structopt(long)]
pub indent_width: Option<usize>,
#[structopt(long, arg_enum, ignore_case = true)]
pub quote_style: Option<ArgQuoteStyle>,
#[structopt(long, arg_enum, ignore_case = true)]
pub call_parentheses: Option<ArgCallParenType>,
#[structopt(long, arg_enum, ignore_case = true)]
pub collapse_simple_statement: Option<ArgCollapseSimpleStatement>,
}
macro_rules! convert_enum {
($from:tt, $arg:tt, { $($enum_name:ident,)+ }) => {
#[derive(ArgEnum, Clone, Copy, Debug)]
#[clap(rename_all = "PascalCase")]
pub enum $arg {
$(
$enum_name,
)+
}
impl From<$arg> for $from {
fn from(other: $arg) -> $from {
match other {
$(
$arg::$enum_name => $from::$enum_name,
)+
}
}
}
impl From<$from> for $arg {
fn from(other: $from) -> $arg {
match other {
$(
$from::$enum_name => $arg::$enum_name,
)+
}
}
}
};
}
convert_enum!(LineEndings, ArgLineEndings, {
Unix,
Windows,
});
convert_enum!(IndentType, ArgIndentType, {
Tabs,
Spaces,
});
convert_enum!(QuoteStyle, ArgQuoteStyle, {
AutoPreferDouble,
AutoPreferSingle,
ForceDouble,
ForceSingle,
});
convert_enum!(CallParenType, ArgCallParenType, {
Always,
NoSingleString,
NoSingleTable,
None,
});
convert_enum!(CollapseSimpleStatement, ArgCollapseSimpleStatement, {
Never,
FunctionOnly,
ConditionalOnly,
Always,
});
#[cfg(test)]
mod tests {
use super::Opt;
use clap::IntoApp;
#[test]
fn verify_opt() {
Opt::command().debug_assert()
}
}