use crate::cli::*;
use crate::config::*;
use crate::logging::*;
use crate::Log;
use colored::Colorize;
use log::Level;
use log::LevelFilter;
use merge::Merge;
use std::fmt;
use std::path::PathBuf;
#[derive(Debug)]
pub struct Args {
pub check: bool,
pub print: bool,
pub wrap: bool,
pub wraplen: u8,
pub wrapmin: u8,
pub tabsize: u8,
pub tabchar: TabChar,
pub stdin: bool,
pub config: Option<PathBuf>,
pub lists: Vec<String>,
pub verbosity: LevelFilter,
pub arguments: bool,
pub files: Vec<String>,
}
#[derive(Clone, Debug, Merge)]
#[allow(clippy::missing_docs_in_private_items)]
pub struct OptionArgs {
pub check: Option<bool>,
pub print: Option<bool>,
pub wrap: Option<bool>,
pub wraplen: Option<u8>,
pub wrapmin: Option<u8>,
pub tabsize: Option<u8>,
pub tabchar: Option<TabChar>,
pub stdin: Option<bool>,
pub config: Option<PathBuf>,
pub noconfig: Option<bool>,
#[merge(strategy = merge::vec::append)]
pub lists: Vec<String>,
pub verbosity: Option<LevelFilter>,
pub arguments: Option<bool>,
#[merge(strategy = merge::vec::append)]
pub files: Vec<String>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[allow(clippy::missing_docs_in_private_items)]
pub enum TabChar {
Tab,
Space,
}
impl fmt::Display for TabChar {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Tab => write!(f, "tab"),
Self::Space => write!(f, "space"),
}
}
}
impl Default for OptionArgs {
fn default() -> Self {
Self {
check: Some(false),
print: Some(false),
wrap: Some(true),
wraplen: Some(80),
wrapmin: Some(70),
tabsize: Some(2),
tabchar: Some(TabChar::Space),
stdin: Some(false),
config: None,
noconfig: Some(false),
lists: vec![
"itemize",
"enumerate",
"description",
"inlineroman",
"inventory",
]
.into_iter()
.map(std::borrow::ToOwned::to_owned)
.collect(),
verbosity: Some(LevelFilter::Warn),
arguments: Some(false),
files: vec![],
}
}
}
pub fn get_args() -> Args {
let mut args = get_cli_args();
let config_args = get_config_args(&args);
if let Some(c) = config_args {
args.merge(c);
}
args.merge(OptionArgs::default());
Args::from(args)
}
impl Args {
fn from(args: OptionArgs) -> Self {
Self {
check: args.check.unwrap(),
print: args.print.unwrap(),
wrap: args.wrap.unwrap(),
wraplen: args.wraplen.unwrap(),
wrapmin: args.wrapmin.unwrap(),
tabsize: args.tabsize.unwrap(),
tabchar: args.tabchar.unwrap(),
stdin: args.stdin.unwrap(),
config: args.config,
lists: args.lists,
verbosity: args.verbosity.unwrap(),
arguments: args.arguments.unwrap(),
files: args.files,
}
}
pub fn resolve(&mut self, logs: &mut Vec<Log>) -> u8 {
let mut exit_code = 0;
self.print |= self.stdin;
self.wrapmin = if self.wraplen >= 50 {
self.wraplen - 10
} else {
self.wraplen
};
if !self.stdin && self.files.is_empty() {
record_file_log(
logs,
Level::Error,
"",
"No files specified. Provide filenames or pass --stdin.",
);
exit_code = 1;
}
if self.stdin && !self.files.is_empty() {
record_file_log(
logs,
Level::Error,
"",
"Do not provide file name(s) when using --stdin.",
);
exit_code = 1;
}
self.lists.dedup();
self.files.dedup();
if self.arguments {
println!("{self}");
std::process::exit(0);
}
exit_code
}
}
impl Default for Args {
fn default() -> Self {
Self::from(OptionArgs::default())
}
}
fn display_arg_line(
f: &mut fmt::Formatter,
name: &str,
value: &str,
) -> fmt::Result {
let width = 20;
let name_fmt = format!("{}{}", name.bold(), ":");
write!(f, "\n {name_fmt:<width$} {value}")?;
Ok(())
}
impl fmt::Display for Args {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", "tex-fmt".magenta().bold())?;
display_arg_line(f, "check", &self.check.to_string())?;
display_arg_line(f, "print", &self.print.to_string())?;
display_arg_line(f, "wrap", &self.wrap.to_string())?;
display_arg_line(f, "wraplen", &self.wraplen.to_string())?;
display_arg_line(f, "wrapmin", &self.wrapmin.to_string())?;
display_arg_line(f, "tabsize", &self.tabsize.to_string())?;
display_arg_line(f, "tabchar", &self.tabchar.to_string())?;
display_arg_line(f, "stdin", &self.stdin.to_string())?;
match &self.config {
None => display_arg_line(f, "config", "None")?,
Some(c) => display_arg_line(f, "config", &c.display().to_string())?,
}
display_arg_line(
f,
"verbosity",
&self.verbosity.to_string().to_lowercase(),
)?;
if !self.lists.is_empty() {
display_arg_line(f, "lists", &self.lists[0])?;
for file in &self.lists[1..] {
write!(
f,
"\n {:<width$} {}",
"".bold().to_string(),
file,
width = 20
)?;
}
}
if !self.files.is_empty() {
display_arg_line(f, "files", &self.files[0])?;
for file in &self.files[1..] {
write!(
f,
"\n {:<width$} {}",
"".bold().to_string(),
file,
width = 20
)?;
}
}
Ok(())
}
}