2019-01-23 09:33:51 -05:00
|
|
|
// 2015-edition macros.
|
|
|
|
#[macro_use]
|
|
|
|
extern crate clap;
|
|
|
|
|
2019-07-19 23:45:41 -04:00
|
|
|
use std::io::Write;
|
2019-10-25 18:37:09 -04:00
|
|
|
use std::sync::atomic;
|
2019-07-19 23:45:41 -04:00
|
|
|
|
2019-01-22 17:01:33 -05:00
|
|
|
use structopt::StructOpt;
|
|
|
|
|
2020-03-23 21:33:59 -04:00
|
|
|
mod args;
|
2020-03-23 21:37:06 -04:00
|
|
|
mod checks;
|
2019-08-07 10:40:06 -04:00
|
|
|
mod config;
|
2019-10-28 12:31:16 -04:00
|
|
|
mod dict;
|
2020-03-24 07:11:31 -04:00
|
|
|
mod replace;
|
2019-08-07 10:40:06 -04:00
|
|
|
|
2020-03-23 21:38:11 -04:00
|
|
|
fn main() {
|
2020-10-28 21:47:16 -04:00
|
|
|
let code = match run() {
|
|
|
|
Ok(code) => code,
|
|
|
|
Err(err) => {
|
|
|
|
eprintln!("{}", err);
|
|
|
|
1
|
|
|
|
}
|
|
|
|
};
|
2020-03-23 21:38:11 -04:00
|
|
|
std::process::exit(code);
|
2019-07-19 23:45:41 -04:00
|
|
|
}
|
|
|
|
|
2019-10-29 13:36:50 -04:00
|
|
|
fn run() -> Result<i32, anyhow::Error> {
|
2020-03-23 21:33:59 -04:00
|
|
|
let args = args::Args::from_args();
|
2019-01-22 17:01:33 -05:00
|
|
|
|
2019-10-17 22:49:26 -04:00
|
|
|
init_logging(args.verbose.log_level());
|
2019-07-19 23:45:41 -04:00
|
|
|
|
2020-03-21 15:33:51 -04:00
|
|
|
let config = if let Some(path) = args.custom_config.as_ref() {
|
|
|
|
config::Config::from_file(path)?
|
|
|
|
} else {
|
|
|
|
config::Config::default()
|
|
|
|
};
|
2019-08-07 11:16:57 -04:00
|
|
|
|
2019-07-22 16:33:39 -04:00
|
|
|
let mut typos_found = false;
|
2019-10-26 22:31:10 -04:00
|
|
|
let mut errors_found = false;
|
2019-08-07 12:09:01 -04:00
|
|
|
for path in args.path.iter() {
|
2019-08-07 11:16:57 -04:00
|
|
|
let path = path.canonicalize()?;
|
|
|
|
let cwd = if path.is_file() {
|
|
|
|
path.parent().unwrap()
|
|
|
|
} else {
|
|
|
|
path.as_path()
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut config = config.clone();
|
2019-08-07 12:09:01 -04:00
|
|
|
if !args.isolated {
|
2019-08-07 11:16:57 -04:00
|
|
|
let derived = config::Config::derive(cwd)?;
|
|
|
|
config.update(&derived);
|
|
|
|
}
|
2019-08-07 12:09:01 -04:00
|
|
|
config.update(&args.config);
|
2019-08-08 09:22:46 -04:00
|
|
|
config.default.update(&args.overrides);
|
2019-08-07 11:16:57 -04:00
|
|
|
let config = config;
|
|
|
|
|
2019-08-07 18:14:29 -04:00
|
|
|
let parser = typos::tokens::ParserBuilder::new()
|
2019-08-08 09:22:46 -04:00
|
|
|
.ignore_hex(config.default.ignore_hex())
|
2019-11-02 11:15:51 -04:00
|
|
|
.leading_digits(config.default.identifier_leading_digits())
|
|
|
|
.leading_chars(config.default.identifier_leading_chars().to_owned())
|
2019-08-08 09:37:06 -04:00
|
|
|
.include_digits(config.default.identifier_include_digits())
|
|
|
|
.include_chars(config.default.identifier_include_chars().to_owned())
|
2019-08-07 18:14:29 -04:00
|
|
|
.build();
|
|
|
|
|
2020-05-27 21:46:41 -04:00
|
|
|
let dictionary = crate::dict::BuiltIn::new(config.default.locale());
|
2020-09-02 21:12:49 -04:00
|
|
|
let mut dictionary = crate::dict::Override::new(dictionary);
|
2020-10-24 22:17:16 -04:00
|
|
|
dictionary.identifiers(config.default.extend_identifiers());
|
|
|
|
dictionary.words(config.default.extend_words());
|
2019-11-14 22:09:56 -05:00
|
|
|
|
2019-10-30 09:26:59 -04:00
|
|
|
let mut settings = typos::checks::TyposSettings::new();
|
|
|
|
settings
|
2019-08-08 09:22:46 -04:00
|
|
|
.check_filenames(config.default.check_filename())
|
|
|
|
.check_files(config.default.check_file())
|
2019-10-30 09:26:59 -04:00
|
|
|
.binary(config.files.binary());
|
2019-08-07 18:14:29 -04:00
|
|
|
|
2020-03-23 20:03:15 -04:00
|
|
|
let threads = if path.is_file() { 1 } else { args.threads };
|
|
|
|
let single_threaded = threads == 1;
|
|
|
|
|
2019-08-07 11:16:57 -04:00
|
|
|
let mut walk = ignore::WalkBuilder::new(path);
|
2019-10-25 18:34:21 -04:00
|
|
|
walk.threads(args.threads)
|
|
|
|
.hidden(config.files.ignore_hidden())
|
2019-08-07 12:05:19 -04:00
|
|
|
.ignore(config.files.ignore_dot())
|
|
|
|
.git_global(config.files.ignore_global())
|
|
|
|
.git_ignore(config.files.ignore_vcs())
|
|
|
|
.git_exclude(config.files.ignore_vcs())
|
|
|
|
.parents(config.files.ignore_parent());
|
2020-03-23 19:31:15 -04:00
|
|
|
|
2020-03-24 07:11:31 -04:00
|
|
|
let mut reporter = args.format.reporter();
|
|
|
|
let replace_reporter = replace::Replace::new(reporter);
|
|
|
|
if args.write_changes {
|
|
|
|
reporter = &replace_reporter;
|
|
|
|
}
|
2020-03-23 19:31:15 -04:00
|
|
|
|
2019-10-30 09:26:59 -04:00
|
|
|
if args.files {
|
2019-10-25 18:37:09 -04:00
|
|
|
if single_threaded {
|
|
|
|
for entry in walk.build() {
|
|
|
|
match entry {
|
|
|
|
Ok(entry) => {
|
|
|
|
let msg = typos::report::File::new(entry.path());
|
2020-03-23 19:31:15 -04:00
|
|
|
reporter.report(msg.into());
|
2019-10-25 18:37:09 -04:00
|
|
|
}
|
|
|
|
Err(err) => {
|
|
|
|
let msg = typos::report::Error::new(err.to_string());
|
2020-03-23 19:31:15 -04:00
|
|
|
reporter.report(msg.into());
|
2019-10-25 18:37:09 -04:00
|
|
|
errors_found = true
|
|
|
|
}
|
2019-10-30 09:26:59 -04:00
|
|
|
}
|
|
|
|
}
|
2019-10-25 18:37:09 -04:00
|
|
|
} else {
|
|
|
|
let atomic_errors = atomic::AtomicBool::new(errors_found);
|
|
|
|
walk.build_parallel().run(|| {
|
|
|
|
Box::new(|entry: Result<ignore::DirEntry, ignore::Error>| {
|
|
|
|
match entry {
|
|
|
|
Ok(entry) => {
|
|
|
|
let msg = typos::report::File::new(entry.path());
|
2020-03-23 19:31:15 -04:00
|
|
|
reporter.report(msg.into());
|
2019-10-25 18:37:09 -04:00
|
|
|
}
|
|
|
|
Err(err) => {
|
|
|
|
let msg = typos::report::Error::new(err.to_string());
|
2020-03-23 19:31:15 -04:00
|
|
|
reporter.report(msg.into());
|
2019-10-25 18:37:09 -04:00
|
|
|
atomic_errors.store(true, atomic::Ordering::Relaxed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ignore::WalkState::Continue
|
|
|
|
})
|
|
|
|
});
|
|
|
|
errors_found = atomic_errors.into_inner();
|
2019-10-30 09:26:59 -04:00
|
|
|
}
|
2020-03-23 19:39:45 -04:00
|
|
|
} else {
|
|
|
|
let (identifier_parser, word_parser, checks);
|
2020-11-10 07:01:01 -05:00
|
|
|
let selected_checks: &dyn typos::checks::Check = if args.identifiers {
|
2020-03-23 19:39:45 -04:00
|
|
|
identifier_parser = settings.build_identifier_parser();
|
|
|
|
&identifier_parser
|
|
|
|
} else if args.words {
|
|
|
|
word_parser = settings.build_word_parser();
|
|
|
|
&word_parser
|
2019-10-25 18:37:09 -04:00
|
|
|
} else {
|
2020-11-10 07:01:01 -05:00
|
|
|
checks = settings.build_typos();
|
2020-03-23 19:39:45 -04:00
|
|
|
&checks
|
2019-10-25 18:37:09 -04:00
|
|
|
};
|
2020-03-23 19:39:45 -04:00
|
|
|
|
2019-10-25 18:37:09 -04:00
|
|
|
let (cur_typos, cur_errors) = if single_threaded {
|
2020-03-23 21:37:06 -04:00
|
|
|
checks::check_path(
|
2020-03-23 19:39:45 -04:00
|
|
|
walk.build(),
|
|
|
|
selected_checks,
|
2019-10-25 18:37:09 -04:00
|
|
|
&parser,
|
|
|
|
&dictionary,
|
2020-03-23 19:31:15 -04:00
|
|
|
reporter,
|
2019-10-25 18:37:09 -04:00
|
|
|
)
|
|
|
|
} else {
|
2020-03-23 21:37:06 -04:00
|
|
|
checks::check_path_parallel(
|
2019-10-25 18:37:09 -04:00
|
|
|
walk.build_parallel(),
|
2020-03-23 19:39:45 -04:00
|
|
|
selected_checks,
|
2019-10-25 18:37:09 -04:00
|
|
|
&parser,
|
|
|
|
&dictionary,
|
2020-03-23 19:31:15 -04:00
|
|
|
reporter,
|
2019-10-25 18:37:09 -04:00
|
|
|
)
|
|
|
|
};
|
2019-11-15 09:48:07 -05:00
|
|
|
if cur_typos {
|
|
|
|
typos_found = true;
|
|
|
|
}
|
|
|
|
if cur_errors {
|
|
|
|
errors_found = true;
|
2019-07-22 16:33:39 -04:00
|
|
|
}
|
2019-01-22 17:01:33 -05:00
|
|
|
}
|
2020-03-24 07:11:31 -04:00
|
|
|
|
|
|
|
if args.write_changes {
|
|
|
|
replace_reporter.write()?;
|
|
|
|
}
|
2019-01-22 17:01:33 -05:00
|
|
|
}
|
|
|
|
|
2019-10-26 22:31:10 -04:00
|
|
|
if errors_found {
|
|
|
|
Ok(2)
|
|
|
|
} else if typos_found {
|
2019-07-22 16:33:39 -04:00
|
|
|
Ok(1)
|
|
|
|
} else {
|
|
|
|
Ok(0)
|
|
|
|
}
|
2019-01-22 17:01:33 -05:00
|
|
|
}
|
|
|
|
|
2020-03-23 21:38:11 -04:00
|
|
|
fn init_logging(level: Option<log::Level>) {
|
|
|
|
if let Some(level) = level {
|
|
|
|
let mut builder = env_logger::Builder::new();
|
|
|
|
|
|
|
|
builder.filter(None, level.to_level_filter());
|
|
|
|
|
|
|
|
if level == log::LevelFilter::Trace {
|
|
|
|
builder.format_timestamp_secs();
|
|
|
|
} else {
|
|
|
|
builder.format(|f, record| {
|
|
|
|
writeln!(
|
|
|
|
f,
|
|
|
|
"[{}] {}",
|
|
|
|
record.level().to_string().to_lowercase(),
|
|
|
|
record.args()
|
|
|
|
)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
builder.init();
|
|
|
|
}
|
2019-01-22 17:01:33 -05:00
|
|
|
}
|