diff --git a/src/config.rs b/src/config.rs index 5a4ab8973..675f61341 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,7 +1,13 @@ use std::io::Read; pub trait ConfigSource { - fn walk(&self) -> Option<&dyn WalkSource>; + fn walk(&self) -> Option<&dyn WalkSource> { + None + } + + fn default(&self) -> Option<&dyn FileSource> { + None + } } pub trait WalkSource { @@ -41,11 +47,29 @@ pub trait WalkSource { } } +pub trait FileSource { + /// Verifying spelling in file names. + fn check_filename(&self) -> Option { + None + } + + /// Verifying spelling in filess. + fn check_file(&self) -> Option { + None + } + + /// Do not check identifiers that appear to be hexadecimal values + fn ignore_hex(&self) -> Option { + None + } +} + #[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)] #[serde(deny_unknown_fields, default)] #[serde(rename_all = "kebab-case")] pub struct Config { pub files: Walk, + pub default: FileConfig, } impl Config { @@ -73,6 +97,9 @@ impl Config { if let Some(walk) = source.walk() { self.files.update(walk); } + if let Some(default) = source.default() { + self.default.update(default); + } } } @@ -193,6 +220,55 @@ impl WalkSource for Walk { } } +#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)] +#[serde(deny_unknown_fields, default)] +#[serde(rename_all = "kebab-case")] +pub struct FileConfig { + pub check_filename: Option, + pub check_file: Option, + pub ignore_hex: Option, +} + +impl FileConfig { + pub fn update(&mut self, source: &dyn FileSource) { + if let Some(source) = source.check_filename() { + self.check_filename = Some(source); + } + if let Some(source) = source.check_file() { + self.check_file = Some(source); + } + if let Some(source) = source.ignore_hex() { + self.ignore_hex = Some(source); + } + } + + pub fn check_filename(&self) -> bool { + self.check_filename.unwrap_or(true) + } + + pub fn check_file(&self) -> bool { + self.check_file.unwrap_or(true) + } + + pub fn ignore_hex(&self) -> bool { + self.ignore_hex.unwrap_or(true) + } +} + +impl FileSource for FileConfig { + fn check_filename(&self) -> Option { + self.check_filename + } + + fn check_file(&self) -> Option { + self.check_file + } + + fn ignore_hex(&self) -> Option { + self.ignore_hex + } +} + fn find_project_file(dir: std::path::PathBuf, name: &str) -> Option { let mut file_path = dir; file_path.push(name); diff --git a/src/main.rs b/src/main.rs index 43f32187c..a49f32d89 100644 --- a/src/main.rs +++ b/src/main.rs @@ -50,31 +50,8 @@ struct Args { /// Ignore implicit configuration files. isolated: bool, - #[structopt(long, raw(overrides_with = r#""check-filenames""#))] - /// Skip verifying spelling in file names. - no_check_filenames: bool, - #[structopt( - long, - raw(overrides_with = r#""no-check-filenames""#), - raw(hidden = "true") - )] - check_filenames: bool, - - #[structopt(long, raw(overrides_with = r#""check-files""#))] - /// Skip verifying spelling in filess. - no_check_files: bool, - #[structopt( - long, - raw(overrides_with = r#""no-check-files""#), - raw(hidden = "true") - )] - check_files: bool, - - #[structopt(long, raw(overrides_with = r#""hex""#))] - /// Don't try to detect that an identifier looks like hex - no_hex: bool, - #[structopt(long, raw(overrides_with = r#""no-hex""#), raw(hidden = "true"))] - hex: bool, + #[structopt(flatten)] + overrides: FileArgs, #[structopt( long = "format", @@ -94,33 +71,6 @@ impl Args { pub fn infer(self) -> Self { self } - - pub fn check_files(&self) -> Option { - 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"), - } - } - - pub fn check_filenames(&self) -> Option { - 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"), - } - } - - pub fn ignore_hex(&self) -> Option { - match (self.no_hex, self.hex) { - (true, false) => Some(false), - (false, true) => Some(true), - (false, false) => None, - (_, _) => unreachable!("StructOpt should make this impossible"), - } - } } #[derive(Debug, StructOpt)] @@ -255,6 +205,65 @@ impl config::WalkSource for WalkArgs { } } +#[derive(Debug, StructOpt)] +#[structopt(rename_all = "kebab-case")] +pub struct FileArgs { + #[structopt(long, raw(overrides_with = r#""check-filenames""#))] + /// Skip verifying spelling in file names. + no_check_filenames: bool, + #[structopt( + long, + raw(overrides_with = r#""no-check-filenames""#), + raw(hidden = "true") + )] + check_filenames: bool, + + #[structopt(long, raw(overrides_with = r#""check-files""#))] + /// Skip verifying spelling in filess. + no_check_files: bool, + #[structopt( + long, + raw(overrides_with = r#""no-check-files""#), + raw(hidden = "true") + )] + check_files: bool, + + #[structopt(long, raw(overrides_with = r#""hex""#))] + /// Don't try to detect that an identifier looks like hex + no_hex: bool, + #[structopt(long, raw(overrides_with = r#""no-hex""#), raw(hidden = "true"))] + hex: bool, +} + +impl config::FileSource for FileArgs { + fn check_filename(&self) -> Option { + 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 { + 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 { + match (self.hex, self.no_hex) { + (true, false) => Some(true), + (false, true) => Some(false), + (false, false) => None, + (_, _) => unreachable!("StructOpt should make this impossible"), + } + } +} + pub fn get_logging(level: log::Level) -> env_logger::Builder { let mut builder = env_logger::Builder::new(); @@ -304,17 +313,18 @@ fn run() -> Result { config.update(&derived); } config.update(&args.config); + config.default.update(&args.overrides); let config = config; let dictionary = typos::BuiltIn::new(); let parser = typos::tokens::ParserBuilder::new() - .ignore_hex(args.ignore_hex().unwrap_or(true)) + .ignore_hex(config.default.ignore_hex()) .build(); let checks = typos::checks::CheckSettings::new() - .check_filenames(args.check_filenames().unwrap_or(true)) - .check_files(args.check_files().unwrap_or(true)) + .check_filenames(config.default.check_filename()) + .check_files(config.default.check_file()) .binary(config.files.binary()) .build(&dictionary, &parser);