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;
|
|
|
|
|
2019-08-07 10:40:06 -04:00
|
|
|
mod config;
|
2019-10-28 12:31:16 -04:00
|
|
|
mod dict;
|
2019-08-07 10:40:06 -04:00
|
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-23 19:21:29 -04:00
|
|
|
const PRINT_SILENT: typos::report::PrintSilent = typos::report::PrintSilent;
|
|
|
|
const PRINT_BRIEF: typos::report::PrintBrief = typos::report::PrintBrief;
|
|
|
|
const PRINT_LONG: typos::report::PrintLong = typos::report::PrintLong;
|
|
|
|
const PRINT_JSON: typos::report::PrintJson = typos::report::PrintJson;
|
|
|
|
|
2019-01-23 09:33:51 -05:00
|
|
|
impl Format {
|
2020-03-23 19:21:29 -04:00
|
|
|
fn reporter(self) -> &'static dyn typos::report::Report {
|
2019-01-23 09:33:51 -05:00
|
|
|
match self {
|
2020-03-23 19:21:29 -04:00
|
|
|
Format::Silent => &PRINT_SILENT,
|
|
|
|
Format::Brief => &PRINT_BRIEF,
|
|
|
|
Format::Long => &PRINT_LONG,
|
|
|
|
Format::Json => &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)]
|
2019-07-10 09:21:02 -04:00
|
|
|
#[structopt(rename_all = "kebab-case")]
|
2019-10-30 13:02:02 -04:00
|
|
|
#[structopt(
|
|
|
|
setting = structopt::clap::AppSettings::UnifiedHelpMessage,
|
|
|
|
setting = structopt::clap::AppSettings::DeriveDisplayOrder,
|
|
|
|
setting = structopt::clap::AppSettings::DontCollapseArgsInUsage
|
|
|
|
)]
|
2019-08-07 12:09:01 -04:00
|
|
|
struct Args {
|
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-08-07 10:55:17 -04:00
|
|
|
#[structopt(short = "c", long = "config")]
|
|
|
|
/// Custom config file
|
2019-08-07 11:05:06 -04:00
|
|
|
custom_config: Option<std::path::PathBuf>,
|
2019-08-07 10:55:17 -04:00
|
|
|
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long)]
|
2019-08-07 11:16:57 -04:00
|
|
|
/// Ignore implicit configuration files.
|
|
|
|
isolated: bool,
|
|
|
|
|
2019-10-30 09:26:59 -04:00
|
|
|
#[structopt(long)]
|
|
|
|
/// Print each file that would be spellchecked.
|
|
|
|
files: bool,
|
|
|
|
|
|
|
|
#[structopt(long)]
|
|
|
|
/// Print each identifier that would be spellchecked.
|
|
|
|
identifiers: bool,
|
|
|
|
|
|
|
|
#[structopt(long)]
|
|
|
|
/// Print each word that would be spellchecked.
|
|
|
|
words: bool,
|
|
|
|
|
2019-08-08 09:22:46 -04:00
|
|
|
#[structopt(flatten)]
|
|
|
|
overrides: FileArgs,
|
2019-07-13 21:24:27 -04:00
|
|
|
|
2019-06-14 08:43:21 -04:00
|
|
|
#[structopt(
|
2019-10-17 22:49:26 -04:00
|
|
|
long,
|
|
|
|
possible_values(&Format::variants()),
|
|
|
|
case_insensitive(true),
|
|
|
|
default_value("long")
|
2019-06-14 08:43:21 -04:00
|
|
|
)]
|
2019-01-23 09:33:51 -05:00
|
|
|
pub format: Format,
|
|
|
|
|
2019-10-25 18:34:21 -04:00
|
|
|
#[structopt(short = "j", long = "threads", default_value = "0")]
|
|
|
|
/// The approximate number of threads to use.
|
|
|
|
threads: usize,
|
|
|
|
|
2019-08-07 12:05:19 -04:00
|
|
|
#[structopt(flatten)]
|
|
|
|
config: ConfigArgs,
|
2019-07-19 23:45:41 -04:00
|
|
|
|
|
|
|
#[structopt(flatten)]
|
|
|
|
verbose: clap_verbosity_flag::Verbosity,
|
2019-01-22 17:01:33 -05:00
|
|
|
}
|
|
|
|
|
2019-10-25 18:34:21 -04:00
|
|
|
impl Args {
|
|
|
|
pub fn infer(mut self) -> Self {
|
|
|
|
if self.path.len() == 1 && self.path[0].is_file() {
|
|
|
|
self.threads = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-08 09:31:50 -04:00
|
|
|
#[derive(Debug, StructOpt)]
|
|
|
|
#[structopt(rename_all = "kebab-case")]
|
|
|
|
pub struct FileArgs {
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("check-filenames"))]
|
2019-08-08 09:31:50 -04:00
|
|
|
/// Skip verifying spelling in file names.
|
|
|
|
no_check_filenames: bool,
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("no-check-filenames"), hidden(true))]
|
2019-08-08 09:31:50 -04:00
|
|
|
check_filenames: bool,
|
|
|
|
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("check-files"))]
|
2019-08-08 09:31:50 -04:00
|
|
|
/// Skip verifying spelling in filess.
|
|
|
|
no_check_files: bool,
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("no-check-files"), hidden(true))]
|
2019-08-08 09:31:50 -04:00
|
|
|
check_files: bool,
|
|
|
|
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("hex"))]
|
2019-08-08 09:31:50 -04:00
|
|
|
/// Don't try to detect that an identifier looks like hex
|
|
|
|
no_hex: bool,
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("no-hex"), hidden(true))]
|
2019-08-08 09:31:50 -04:00
|
|
|
hex: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl config::FileSource for FileArgs {
|
|
|
|
fn check_filename(&self) -> Option<bool> {
|
|
|
|
match (self.check_filenames, self.no_check_filenames) {
|
|
|
|
(true, false) => Some(true),
|
|
|
|
(false, true) => Some(false),
|
|
|
|
(false, false) => None,
|
|
|
|
(_, _) => unreachable!("StructOpt should make this impossible"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_file(&self) -> Option<bool> {
|
|
|
|
match (self.check_files, self.no_check_files) {
|
|
|
|
(true, false) => Some(true),
|
|
|
|
(false, true) => Some(false),
|
|
|
|
(false, false) => None,
|
|
|
|
(_, _) => unreachable!("StructOpt should make this impossible"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn ignore_hex(&self) -> Option<bool> {
|
|
|
|
match (self.hex, self.no_hex) {
|
|
|
|
(true, false) => Some(true),
|
|
|
|
(false, true) => Some(false),
|
|
|
|
(false, false) => None,
|
|
|
|
(_, _) => unreachable!("StructOpt should make this impossible"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-07 12:05:19 -04:00
|
|
|
#[derive(Debug, StructOpt)]
|
|
|
|
#[structopt(rename_all = "kebab-case")]
|
|
|
|
struct ConfigArgs {
|
|
|
|
#[structopt(flatten)]
|
|
|
|
walk: WalkArgs,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl config::ConfigSource for ConfigArgs {
|
|
|
|
fn walk(&self) -> Option<&dyn config::WalkSource> {
|
|
|
|
Some(&self.walk)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, StructOpt)]
|
|
|
|
#[structopt(rename_all = "kebab-case")]
|
|
|
|
struct WalkArgs {
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("no-binary"))]
|
2019-08-07 18:14:29 -04:00
|
|
|
/// Search binary files.
|
|
|
|
binary: bool,
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("binary"), hidden(true))]
|
2019-08-07 18:14:29 -04:00
|
|
|
no_binary: bool,
|
|
|
|
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("no-hidden"))]
|
2019-08-07 12:05:19 -04:00
|
|
|
/// Search hidden files and directories.
|
|
|
|
hidden: bool,
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("hidden"), hidden(true))]
|
2019-08-07 12:05:19 -04:00
|
|
|
no_hidden: bool,
|
|
|
|
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("ignore"))]
|
2019-08-07 12:05:19 -04:00
|
|
|
/// Don't respect ignore files.
|
|
|
|
no_ignore: bool,
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("no-ignore"), hidden(true))]
|
2019-08-07 12:05:19 -04:00
|
|
|
ignore: bool,
|
|
|
|
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("ignore-dot"))]
|
2019-08-07 12:05:19 -04:00
|
|
|
/// Don't respect .ignore files.
|
|
|
|
no_ignore_dot: bool,
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("no-ignore-dot"), hidden(true))]
|
2019-08-07 12:05:19 -04:00
|
|
|
ignore_dot: bool,
|
|
|
|
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("ignore-global"))]
|
2019-08-07 12:05:19 -04:00
|
|
|
/// Don't respect global ignore files.
|
|
|
|
no_ignore_global: bool,
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("no-ignore-global"), hidden(true))]
|
2019-08-07 12:05:19 -04:00
|
|
|
ignore_global: bool,
|
|
|
|
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("ignore-parent"))]
|
2019-08-07 12:05:19 -04:00
|
|
|
/// Don't respect ignore files in parent directories.
|
|
|
|
no_ignore_parent: bool,
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("no-ignore-parent"), hidden(true))]
|
2019-08-07 12:05:19 -04:00
|
|
|
ignore_parent: bool,
|
|
|
|
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("ignore-vcs"))]
|
2019-08-07 12:05:19 -04:00
|
|
|
/// Don't respect ignore files in vcs directories.
|
|
|
|
no_ignore_vcs: bool,
|
2019-10-17 22:49:26 -04:00
|
|
|
#[structopt(long, overrides_with("no-ignore-vcs"), hidden(true))]
|
2019-08-07 12:05:19 -04:00
|
|
|
ignore_vcs: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl config::WalkSource for WalkArgs {
|
2019-08-07 18:14:29 -04:00
|
|
|
fn binary(&self) -> Option<bool> {
|
|
|
|
match (self.binary, self.no_binary) {
|
|
|
|
(true, false) => Some(true),
|
|
|
|
(false, true) => Some(false),
|
|
|
|
(false, false) => None,
|
|
|
|
(_, _) => unreachable!("StructOpt should make this impossible"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-07 10:40:06 -04:00
|
|
|
fn ignore_hidden(&self) -> Option<bool> {
|
2019-07-10 09:21:02 -04:00
|
|
|
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
|
|
|
|
2019-08-07 10:40:06 -04:00
|
|
|
fn ignore_files(&self) -> Option<bool> {
|
|
|
|
match (self.no_ignore, self.ignore) {
|
2019-07-10 22:12:14 -04:00
|
|
|
(true, false) => Some(false),
|
|
|
|
(false, true) => Some(true),
|
2019-07-11 23:56:27 -04:00
|
|
|
(false, false) => None,
|
|
|
|
(_, _) => unreachable!("StructOpt should make this impossible"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-07 10:40:06 -04:00
|
|
|
fn ignore_dot(&self) -> Option<bool> {
|
|
|
|
match (self.no_ignore_dot, self.ignore_dot) {
|
2019-07-12 23:36:32 -04:00
|
|
|
(true, false) => Some(false),
|
|
|
|
(false, true) => Some(true),
|
|
|
|
(false, false) => None,
|
|
|
|
(_, _) => unreachable!("StructOpt should make this impossible"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-07 10:40:06 -04:00
|
|
|
fn ignore_vcs(&self) -> Option<bool> {
|
|
|
|
match (self.no_ignore_vcs, self.ignore_vcs) {
|
2019-07-12 23:39:38 -04:00
|
|
|
(true, false) => Some(false),
|
|
|
|
(false, true) => Some(true),
|
|
|
|
(false, false) => None,
|
|
|
|
(_, _) => unreachable!("StructOpt should make this impossible"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-07 10:40:06 -04:00
|
|
|
fn ignore_global(&self) -> Option<bool> {
|
|
|
|
match (self.no_ignore_global, self.ignore_global) {
|
2019-07-12 23:43:18 -04:00
|
|
|
(true, false) => Some(false),
|
|
|
|
(false, true) => Some(true),
|
|
|
|
(false, false) => None,
|
|
|
|
(_, _) => unreachable!("StructOpt should make this impossible"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-07 10:40:06 -04:00
|
|
|
fn ignore_parent(&self) -> Option<bool> {
|
|
|
|
match (self.no_ignore_parent, self.ignore_parent) {
|
2019-07-11 23:56:27 -04:00
|
|
|
(true, false) => Some(false),
|
|
|
|
(false, true) => Some(true),
|
2019-07-10 22:12:14 -04:00
|
|
|
(false, false) => None,
|
|
|
|
(_, _) => unreachable!("StructOpt should make this impossible"),
|
|
|
|
}
|
|
|
|
}
|
2019-01-22 17:01:33 -05:00
|
|
|
}
|
|
|
|
|
2019-10-25 18:37:09 -04:00
|
|
|
trait Checks: Send + Sync {
|
2019-10-30 09:26:59 -04:00
|
|
|
fn check_filename(
|
|
|
|
&self,
|
|
|
|
path: &std::path::Path,
|
2019-11-14 22:09:56 -05:00
|
|
|
parser: &typos::tokens::Parser,
|
|
|
|
dictionary: &dyn typos::Dictionary,
|
2020-03-23 19:21:29 -04:00
|
|
|
report: &dyn typos::report::Report,
|
2019-10-30 09:26:59 -04:00
|
|
|
) -> Result<bool, typos::Error>;
|
|
|
|
|
|
|
|
fn check_file(
|
|
|
|
&self,
|
|
|
|
path: &std::path::Path,
|
|
|
|
explicit: bool,
|
2019-11-14 22:09:56 -05:00
|
|
|
parser: &typos::tokens::Parser,
|
|
|
|
dictionary: &dyn typos::Dictionary,
|
2020-03-23 19:21:29 -04:00
|
|
|
report: &dyn typos::report::Report,
|
2019-10-30 09:26:59 -04:00
|
|
|
) -> Result<bool, typos::Error>;
|
|
|
|
}
|
|
|
|
|
2019-11-14 22:09:56 -05:00
|
|
|
impl<'p> Checks for typos::checks::ParseIdentifiers {
|
2019-10-30 09:26:59 -04:00
|
|
|
fn check_filename(
|
|
|
|
&self,
|
|
|
|
path: &std::path::Path,
|
2019-11-14 22:09:56 -05:00
|
|
|
parser: &typos::tokens::Parser,
|
|
|
|
_dictionary: &dyn typos::Dictionary,
|
2020-03-23 19:21:29 -04:00
|
|
|
report: &dyn typos::report::Report,
|
2019-10-30 09:26:59 -04:00
|
|
|
) -> Result<bool, typos::Error> {
|
2019-11-14 22:09:56 -05:00
|
|
|
self.check_filename(path, parser, report)
|
2019-10-30 09:26:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn check_file(
|
|
|
|
&self,
|
|
|
|
path: &std::path::Path,
|
|
|
|
explicit: bool,
|
2019-11-14 22:09:56 -05:00
|
|
|
parser: &typos::tokens::Parser,
|
|
|
|
_dictionary: &dyn typos::Dictionary,
|
2020-03-23 19:21:29 -04:00
|
|
|
report: &dyn typos::report::Report,
|
2019-10-30 09:26:59 -04:00
|
|
|
) -> Result<bool, typos::Error> {
|
2019-11-14 22:09:56 -05:00
|
|
|
self.check_file(path, explicit, parser, report)
|
2019-10-30 09:26:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-14 22:09:56 -05:00
|
|
|
impl<'p> Checks for typos::checks::ParseWords {
|
2019-10-30 09:26:59 -04:00
|
|
|
fn check_filename(
|
|
|
|
&self,
|
|
|
|
path: &std::path::Path,
|
2019-11-14 22:09:56 -05:00
|
|
|
parser: &typos::tokens::Parser,
|
|
|
|
_dictionary: &dyn typos::Dictionary,
|
2020-03-23 19:21:29 -04:00
|
|
|
report: &dyn typos::report::Report,
|
2019-10-30 09:26:59 -04:00
|
|
|
) -> Result<bool, typos::Error> {
|
2019-11-14 22:09:56 -05:00
|
|
|
self.check_filename(path, parser, report)
|
2019-10-30 09:26:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn check_file(
|
|
|
|
&self,
|
|
|
|
path: &std::path::Path,
|
|
|
|
explicit: bool,
|
2019-11-14 22:09:56 -05:00
|
|
|
parser: &typos::tokens::Parser,
|
|
|
|
_dictionary: &dyn typos::Dictionary,
|
2020-03-23 19:21:29 -04:00
|
|
|
report: &dyn typos::report::Report,
|
2019-10-30 09:26:59 -04:00
|
|
|
) -> Result<bool, typos::Error> {
|
2019-11-14 22:09:56 -05:00
|
|
|
self.check_file(path, explicit, parser, report)
|
2019-10-30 09:26:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-14 22:09:56 -05:00
|
|
|
impl<'d, 'p> Checks for typos::checks::Checks {
|
2019-10-30 09:26:59 -04:00
|
|
|
fn check_filename(
|
|
|
|
&self,
|
|
|
|
path: &std::path::Path,
|
2019-11-14 22:09:56 -05:00
|
|
|
parser: &typos::tokens::Parser,
|
|
|
|
dictionary: &dyn typos::Dictionary,
|
2020-03-23 19:21:29 -04:00
|
|
|
report: &dyn typos::report::Report,
|
2019-10-30 09:26:59 -04:00
|
|
|
) -> Result<bool, typos::Error> {
|
2019-11-14 22:09:56 -05:00
|
|
|
self.check_filename(path, parser, dictionary, report)
|
2019-10-30 09:26:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn check_file(
|
|
|
|
&self,
|
|
|
|
path: &std::path::Path,
|
|
|
|
explicit: bool,
|
2019-11-14 22:09:56 -05:00
|
|
|
parser: &typos::tokens::Parser,
|
|
|
|
dictionary: &dyn typos::Dictionary,
|
2020-03-23 19:21:29 -04:00
|
|
|
report: &dyn typos::report::Report,
|
2019-10-30 09:26:59 -04:00
|
|
|
) -> Result<bool, typos::Error> {
|
2019-11-14 22:09:56 -05:00
|
|
|
self.check_file(path, explicit, parser, dictionary, report)
|
2019-10-30 09:26:59 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn init_logging(level: Option<log::Level>) {
|
2019-10-17 22:49:26 -04:00
|
|
|
if let Some(level) = level {
|
|
|
|
let mut builder = env_logger::Builder::new();
|
|
|
|
|
|
|
|
builder.filter(None, level.to_level_filter());
|
|
|
|
|
|
|
|
if level == log::LevelFilter::Trace {
|
2019-12-02 11:50:06 -05:00
|
|
|
builder.format_timestamp_secs();
|
2019-10-17 22:49:26 -04:00
|
|
|
} else {
|
|
|
|
builder.format(|f, record| {
|
|
|
|
writeln!(
|
|
|
|
f,
|
|
|
|
"[{}] {}",
|
|
|
|
record.level().to_string().to_lowercase(),
|
|
|
|
record.args()
|
|
|
|
)
|
|
|
|
});
|
|
|
|
}
|
2019-07-19 23:45:41 -04:00
|
|
|
|
2019-10-17 22:49:26 -04:00
|
|
|
builder.init();
|
|
|
|
}
|
2019-07-19 23:45:41 -04:00
|
|
|
}
|
|
|
|
|
2019-11-15 09:48:07 -05:00
|
|
|
fn check_path(
|
2019-12-02 11:50:06 -05:00
|
|
|
walk: ignore::Walk,
|
2019-11-15 09:48:07 -05:00
|
|
|
checks: &dyn Checks,
|
|
|
|
parser: &typos::tokens::Parser,
|
|
|
|
dictionary: &dyn typos::Dictionary,
|
2020-03-23 19:31:15 -04:00
|
|
|
reporter: &dyn typos::report::Report,
|
2019-10-25 18:37:09 -04:00
|
|
|
) -> (bool, bool) {
|
2019-11-15 09:48:07 -05:00
|
|
|
let mut typos_found = false;
|
|
|
|
let mut errors_found = false;
|
|
|
|
|
|
|
|
for entry in walk {
|
2020-03-23 19:31:15 -04:00
|
|
|
match check_entry(entry, checks, parser, dictionary, reporter) {
|
2019-11-15 09:48:07 -05:00
|
|
|
Ok(true) => typos_found = true,
|
|
|
|
Err(err) => {
|
|
|
|
let msg = typos::report::Error::new(err.to_string());
|
2020-03-23 19:31:15 -04:00
|
|
|
reporter.report(msg.into());
|
2019-11-15 09:48:07 -05:00
|
|
|
errors_found = true
|
|
|
|
}
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-25 18:37:09 -04:00
|
|
|
(typos_found, errors_found)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_path_parallel(
|
|
|
|
walk: ignore::WalkParallel,
|
|
|
|
checks: &dyn Checks,
|
|
|
|
parser: &typos::tokens::Parser,
|
|
|
|
dictionary: &dyn typos::Dictionary,
|
2020-03-23 19:31:15 -04:00
|
|
|
reporter: &dyn typos::report::Report,
|
2019-10-25 18:37:09 -04:00
|
|
|
) -> (bool, bool) {
|
|
|
|
let typos_found = atomic::AtomicBool::new(false);
|
|
|
|
let errors_found = atomic::AtomicBool::new(false);
|
|
|
|
|
|
|
|
walk.run(|| {
|
|
|
|
Box::new(|entry: Result<ignore::DirEntry, ignore::Error>| {
|
2020-03-23 19:31:15 -04:00
|
|
|
match check_entry(entry, checks, parser, dictionary, reporter) {
|
2019-10-25 18:37:09 -04:00
|
|
|
Ok(true) => typos_found.store(true, atomic::Ordering::Relaxed),
|
|
|
|
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.store(true, atomic::Ordering::Relaxed);
|
|
|
|
}
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
ignore::WalkState::Continue
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
|
|
|
(typos_found.into_inner(), errors_found.into_inner())
|
2019-11-15 09:48:07 -05:00
|
|
|
}
|
|
|
|
|
2019-10-26 22:31:10 -04:00
|
|
|
fn check_entry(
|
|
|
|
entry: Result<ignore::DirEntry, ignore::Error>,
|
2019-10-30 09:26:59 -04:00
|
|
|
checks: &dyn Checks,
|
2019-11-14 22:09:56 -05:00
|
|
|
parser: &typos::tokens::Parser,
|
|
|
|
dictionary: &dyn typos::Dictionary,
|
2020-03-23 19:31:15 -04:00
|
|
|
reporter: &dyn typos::report::Report,
|
2019-10-29 13:36:50 -04:00
|
|
|
) -> Result<bool, anyhow::Error> {
|
2019-10-26 22:31:10 -04:00
|
|
|
let mut typos_found = false;
|
|
|
|
|
|
|
|
let entry = entry?;
|
|
|
|
if entry.file_type().map(|t| t.is_file()).unwrap_or(true) {
|
|
|
|
let explicit = entry.depth() == 0;
|
2020-03-23 19:31:15 -04:00
|
|
|
if checks.check_filename(entry.path(), parser, dictionary, reporter)? {
|
2019-10-26 22:31:10 -04:00
|
|
|
typos_found = true;
|
|
|
|
}
|
2020-03-23 19:31:15 -04:00
|
|
|
if checks.check_file(entry.path(), explicit, parser, dictionary, reporter)? {
|
2019-10-26 22:31:10 -04:00
|
|
|
typos_found = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(typos_found)
|
|
|
|
}
|
|
|
|
|
2019-10-29 13:36:50 -04:00
|
|
|
fn run() -> Result<i32, anyhow::Error> {
|
2019-10-25 18:34:21 -04:00
|
|
|
let args = Args::from_args().infer();
|
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();
|
|
|
|
|
2019-11-14 22:09:56 -05:00
|
|
|
let dictionary = crate::dict::BuiltIn::new();
|
|
|
|
|
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
|
|
|
|
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
|
|
|
|
|
|
|
let reporter = args.format.reporter();
|
|
|
|
|
2019-10-25 18:37:09 -04:00
|
|
|
let single_threaded = args.threads == 1;
|
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
|
|
|
}
|
|
|
|
} else if args.identifiers {
|
2019-11-14 22:09:56 -05:00
|
|
|
let checks = settings.build_identifier_parser();
|
2019-10-25 18:37:09 -04:00
|
|
|
let (cur_typos, cur_errors) = if single_threaded {
|
2020-03-23 19:31:15 -04:00
|
|
|
check_path(walk.build(), &checks, &parser, &dictionary, reporter)
|
2019-10-25 18:37:09 -04:00
|
|
|
} else {
|
|
|
|
check_path_parallel(
|
|
|
|
walk.build_parallel(),
|
|
|
|
&checks,
|
|
|
|
&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-10-30 09:26:59 -04:00
|
|
|
}
|
|
|
|
} else if args.words {
|
2019-11-14 22:09:56 -05:00
|
|
|
let checks = settings.build_word_parser();
|
2019-10-25 18:37:09 -04:00
|
|
|
let (cur_typos, cur_errors) = if single_threaded {
|
2020-03-23 19:31:15 -04:00
|
|
|
check_path(walk.build(), &checks, &parser, &dictionary, reporter)
|
2019-10-25 18:37:09 -04:00
|
|
|
} else {
|
|
|
|
check_path_parallel(
|
|
|
|
walk.build_parallel(),
|
|
|
|
&checks,
|
|
|
|
&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-10-30 09:26:59 -04:00
|
|
|
}
|
|
|
|
} else {
|
2019-11-14 22:09:56 -05:00
|
|
|
let checks = settings.build_checks();
|
2019-10-25 18:37:09 -04:00
|
|
|
let (cur_typos, cur_errors) = if single_threaded {
|
2020-03-23 19:31:15 -04:00
|
|
|
check_path(walk.build(), &checks, &parser, &dictionary, reporter)
|
2019-10-25 18:37:09 -04:00
|
|
|
} else {
|
|
|
|
check_path_parallel(
|
|
|
|
walk.build_parallel(),
|
|
|
|
&checks,
|
|
|
|
&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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
2019-07-22 16:33:39 -04:00
|
|
|
let code = run().unwrap();
|
|
|
|
std::process::exit(code);
|
2019-01-22 17:01:33 -05:00
|
|
|
}
|