diff --git a/src/config.rs b/src/config.rs index d6284f6..95bba4a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -57,6 +57,14 @@ impl Config { Ok(content) } + pub fn derive(cwd: &std::path::Path) -> Result { + if let Some(path) = find_project_file(cwd.to_owned(), "typos.toml") { + Self::from_file(&path) + } else { + Ok(Default::default()) + } + } + pub fn update(&mut self, source: &dyn ConfigSource) { if let Some(source) = source.ignore_hidden() { self.ignore_hidden = Some(source); @@ -138,3 +146,17 @@ impl ConfigSource for Config { self.ignore_parent } } + +fn find_project_file(dir: std::path::PathBuf, name: &str) -> Option { + let mut file_path = dir; + file_path.push(name); + while !file_path.exists() { + file_path.pop(); // filename + let hit_bottom = !file_path.pop(); + if hit_bottom { + return None; + } + file_path.push(name); + } + Some(file_path) +} diff --git a/src/main.rs b/src/main.rs index ffef65b..29add46 100644 --- a/src/main.rs +++ b/src/main.rs @@ -46,6 +46,10 @@ struct Options { /// Custom config file custom_config: Option, + #[structopt(long = "isolated")] + /// Ignore implicit configuration files. + isolated: bool, + #[structopt(long, raw(overrides_with = r#""check-filenames""#))] /// Skip verifying spelling in file names. no_check_filenames: bool, @@ -255,13 +259,6 @@ pub fn get_logging(level: log::Level) -> env_logger::Builder { fn run() -> Result { let options = Options::from_args().infer(); - let mut config = config::Config::default(); - if let Some(path) = options.custom_config.as_ref() { - let custom = config::Config::from_file(path)?; - config.update(&custom); - } - config.update(&options); - let mut builder = get_logging(options.verbose.log_level()); builder.init(); @@ -282,30 +279,47 @@ fn run() -> Result { .binary(binary) .build(&dictionary, &parser); - let first_path = &options - .path - .get(0) - .expect("arg parsing enforces at least one"); - let mut walk = ignore::WalkBuilder::new(first_path); - for path in &options.path[1..] { - walk.add(path); + let mut config = config::Config::default(); + if let Some(path) = options.custom_config.as_ref() { + let custom = config::Config::from_file(path)?; + config.update(&custom); } - walk.hidden(config.ignore_hidden()) - .ignore(config.ignore_dot()) - .git_global(config.ignore_global()) - .git_ignore(config.ignore_vcs()) - .git_exclude(config.ignore_vcs()) - .parents(config.ignore_parent()); + let config = config; + let mut typos_found = false; - for entry in walk.build() { - let entry = entry?; - if entry.file_type().map(|t| t.is_file()).unwrap_or(true) { - let explicit = entry.depth() == 0; - if checks.check_filename(entry.path(), options.format.report())? { - typos_found = true; - } - if checks.check_file(entry.path(), explicit, options.format.report())? { - typos_found = true; + for path in options.path.iter() { + let path = path.canonicalize()?; + let cwd = if path.is_file() { + path.parent().unwrap() + } else { + path.as_path() + }; + + let mut config = config.clone(); + if !options.isolated { + let derived = config::Config::derive(cwd)?; + config.update(&derived); + } + config.update(&options); + let config = config; + + let mut walk = ignore::WalkBuilder::new(path); + walk.hidden(config.ignore_hidden()) + .ignore(config.ignore_dot()) + .git_global(config.ignore_global()) + .git_ignore(config.ignore_vcs()) + .git_exclude(config.ignore_vcs()) + .parents(config.ignore_parent()); + for entry in walk.build() { + let entry = entry?; + if entry.file_type().map(|t| t.is_file()).unwrap_or(true) { + let explicit = entry.depth() == 0; + if checks.check_filename(entry.path(), options.format.report())? { + typos_found = true; + } + if checks.check_file(entry.path(), explicit, options.format.report())? { + typos_found = true; + } } } }