typos/src/main.rs

123 lines
3.2 KiB
Rust
Raw Normal View History

2019-01-23 09:33:51 -05:00
// 2015-edition macros.
#[macro_use]
extern crate clap;
2019-01-22 17:01:33 -05:00
use structopt::StructOpt;
2019-06-14 08:43:21 -04:00
arg_enum! {
2019-01-23 09:33:51 -05:00
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum Format {
Silent,
Brief,
Long,
Json,
}
}
impl Format {
2019-07-03 21:22:36 -04:00
fn report(self) -> typos::report::Report {
2019-01-23 09:33:51 -05:00
match self {
2019-07-03 21:22:36 -04:00
Format::Silent => typos::report::print_silent,
Format::Brief => typos::report::print_brief,
Format::Long => typos::report::print_long,
Format::Json => typos::report::print_json,
2019-01-23 09:33:51 -05:00
}
}
}
impl Default for Format {
fn default() -> Self {
Format::Long
}
}
2019-01-22 17:01:33 -05:00
#[derive(Debug, StructOpt)]
#[structopt(rename_all = "kebab-case")]
2019-01-22 17:01:33 -05:00
struct Options {
2019-01-23 09:34:05 -05:00
#[structopt(parse(from_os_str), default_value = ".")]
2019-01-22 17:01:33 -05:00
/// Paths to check
path: Vec<std::path::PathBuf>,
2019-06-14 08:43:21 -04:00
#[structopt(
long = "format",
raw(possible_values = "&Format::variants()", case_insensitive = "true"),
default_value = "long"
)]
2019-01-23 09:33:51 -05:00
pub format: Format,
2019-06-14 08:43:21 -04:00
#[structopt(short = "j", long = "threads", default_value = "0")]
2019-01-22 17:01:33 -05:00
/// The approximate number of threads to use.
threads: usize,
#[structopt(long, raw(overrides_with = r#""no-hidden""#))]
/// Search hidden files and directories.
hidden: bool,
#[structopt(long, raw(overrides_with = r#""hidden""#), raw(hidden = "true"))]
no_hidden: bool,
2019-07-10 22:12:14 -04:00
#[structopt(long, raw(overrides_with = r#""ignore-dot""#))]
/// Don't respect .ignore files.
no_ignore_dot: bool,
#[structopt(long, raw(overrides_with = r#""no-ignore-dot""#), raw(hidden = "true"))]
ignore_dot: bool,
2019-01-22 17:01:33 -05:00
}
impl Options {
pub fn infer(mut self) -> Self {
2019-06-14 08:51:22 -04:00
if self.path.len() == 1 && self.path[0].is_file() {
self.threads = 1;
2019-01-22 17:01:33 -05:00
}
self
}
pub fn ignore_hidden(&self) -> Option<bool> {
match (self.hidden, self.no_hidden) {
(true, false) => Some(false),
(false, true) => Some(true),
(false, false) => None,
(_, _) => unreachable!("StructOpt should make this impossible"),
}
}
2019-07-10 22:12:14 -04:00
pub fn ignore_dot(&self) -> Option<bool> {
match (self.no_ignore_dot, self.ignore_dot) {
(true, false) => Some(false),
(false, true) => Some(true),
(false, false) => None,
(_, _) => unreachable!("StructOpt should make this impossible"),
}
}
2019-01-22 17:01:33 -05:00
}
fn run() -> Result<(), failure::Error> {
let options = Options::from_args().infer();
2019-07-03 21:22:36 -04:00
let dictionary = typos::Dictionary::new();
2019-01-22 17:01:33 -05:00
2019-06-14 08:43:21 -04:00
let first_path = &options
.path
.get(0)
.expect("arg parsing enforces at least one");
2019-01-22 17:01:33 -05:00
let mut walk = ignore::WalkBuilder::new(first_path);
for path in &options.path[1..] {
walk.add(path);
}
walk.threads(options.threads)
2019-07-10 22:12:14 -04:00
.hidden(options.ignore_hidden().unwrap_or(true))
.ignore(options.ignore_dot().unwrap_or(true));
2019-01-22 17:01:33 -05:00
// TODO Add build_parallel for options.threads != 1
for entry in walk.build() {
let entry = entry?;
if entry.file_type().map(|t| t.is_file()).unwrap_or(true) {
2019-07-03 21:22:36 -04:00
typos::process_file(entry.path(), &dictionary, options.format.report())?;
2019-01-22 17:01:33 -05:00
}
}
Ok(())
}
fn main() {
run().unwrap();
}