use app::create_app;
use atty;
use output::Printer;
use regex::Regex;
use std::sync::Arc;
pub struct Config {
pub expression: Regex,
pub replacement: String,
pub force: bool,
pub backup: bool,
pub dirs: bool,
pub dump: bool,
pub mode: RunMode,
pub printer: Printer,
pub limit: usize,
}
impl Config {
pub fn new() -> Result<Arc<Config>, String> {
let config = match parse_arguments() {
Ok(config) => config,
Err(err) => return Err(err),
};
Ok(Arc::new(config))
}
}
pub enum RunMode {
Simple(Vec<String>),
Recursive {
paths: Vec<String>,
max_depth: Option<usize>,
hidden: bool,
},
FromFile {
path: String,
undo: bool,
},
}
fn parse_arguments() -> Result<Config, String> {
let app = create_app();
let matches = app.get_matches();
let printer = if matches.is_present("silent") {
Printer::silent()
} else {
match matches.value_of("color").unwrap_or("auto") {
"always" => Printer::color(),
"never" => Printer::no_color(),
"auto" | _ => detect_output_color(),
}
};
let expression = match Regex::new(matches.value_of("EXPRESSION").unwrap_or_default()) {
Ok(expr) => expr,
Err(err) => {
return Err(format!(
"{}Bad expression provided\n\n{}",
printer.colors.error.paint("Error: "),
printer.colors.error.paint(err.to_string())
));
}
};
let replacement = String::from(matches.value_of("REPLACEMENT").unwrap_or_default());
let input_paths: Vec<String> = matches
.values_of("PATH(S)")
.unwrap_or_default()
.map(String::from)
.collect();
let mode = if matches.is_present("from-file") {
let submatches = match matches.subcommand_matches("from-file") {
Some(matches) => matches,
None => {
return Err(format!(
"{}Empty from-file subcommand provided\n\n",
printer.colors.error.paint("Error: ")
))
}
};
RunMode::FromFile {
path: String::from(submatches.value_of("DUMPFILE").unwrap_or_default()),
undo: submatches.is_present("undo"),
}
} else if matches.is_present("recursive") {
let max_depth = if matches.is_present("max-depth") {
Some(
matches
.value_of("max-depth")
.unwrap_or_default()
.parse::<usize>()
.unwrap_or_default(),
)
} else {
None
};
RunMode::Recursive {
paths: input_paths,
max_depth,
hidden: matches.is_present("hidden"),
}
} else {
RunMode::Simple(input_paths)
};
let dump = if matches.is_present("force") {
!matches.is_present("no-dump")
} else {
matches.is_present("dump")
};
let limit = matches
.value_of("replace-limit")
.unwrap_or_default()
.parse::<usize>()
.unwrap_or_default();
Ok(Config {
expression,
replacement,
force: matches.is_present("force"),
backup: matches.is_present("backup"),
dirs: matches.is_present("include-dirs"),
dump,
mode,
printer,
limit,
})
}
fn detect_output_color() -> Printer {
if atty::is(atty::Stream::Stdout) {
#[cfg(not(windows))]
{
Printer::color()
}
#[cfg(windows)]
{
use ansi_term;
match ansi_term::enable_ansi_support() {
Ok(_) => Printer::color(),
Err(_) => Printer::no_color(),
}
}
} else {
Printer::no_color()
}
}