diff --git a/Cargo.lock b/Cargo.lock index 97c2b8d3a..529884ff0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -921,6 +921,22 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "ignore" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata 0.4.5", + "same-file", + "walkdir", + "winapi-util", +] + [[package]] name = "indexmap" version = "1.9.3" @@ -2201,6 +2217,7 @@ dependencies = [ "futures", "glob", "hex", + "ignore", "itertools", "lsp-async-stub", "once_cell", diff --git a/crates/taplo-cli/Cargo.toml b/crates/taplo-cli/Cargo.toml index b419ddbb9..8f466bd53 100644 --- a/crates/taplo-cli/Cargo.toml +++ b/crates/taplo-cli/Cargo.toml @@ -25,6 +25,7 @@ codespan-reporting = "0.11.1" futures = "0.3" glob = "0.3" hex = "0.4" +ignore = "0.4.22" itertools = "0.10.3" once_cell = "1.4" regex = "1.4" diff --git a/crates/taplo-cli/src/commands/format.rs b/crates/taplo-cli/src/commands/format.rs index 08941735d..8071d0525 100644 --- a/crates/taplo-cli/src/commands/format.rs +++ b/crates/taplo-cli/src/commands/format.rs @@ -214,7 +214,7 @@ impl Taplo { .ok_or_else(|| anyhow!("could not figure the current working directory"))?; let files = self - .collect_files(&cwd, &config, mem::take(&mut cmd.files).into_iter()) + .files_iter(&cwd, &config, mem::take(&mut cmd.files).into_iter()) .await?; let mut result = Ok(()); diff --git a/crates/taplo-cli/src/commands/lint.rs b/crates/taplo-cli/src/commands/lint.rs index 003843058..d1801787b 100644 --- a/crates/taplo-cli/src/commands/lint.rs +++ b/crates/taplo-cli/src/commands/lint.rs @@ -77,7 +77,7 @@ impl Taplo { .ok_or_else(|| anyhow!("could not figure the current working directory"))?; let files = self - .collect_files(&cwd, &config, cmd.files.into_iter()) + .files_iter(&cwd, &config, cmd.files.into_iter()) .await?; let mut result = Ok(()); diff --git a/crates/taplo-cli/src/commands/lsp.rs b/crates/taplo-cli/src/commands/lsp.rs index 1b7d8f38c..bb7c11458 100644 --- a/crates/taplo-cli/src/commands/lsp.rs +++ b/crates/taplo-cli/src/commands/lsp.rs @@ -1,6 +1,9 @@ use taplo_common::environment::{native::NativeEnvironment, Environment}; -use crate::{args::{LspCommand, LspCommandIo}, Taplo}; +use crate::{ + args::{LspCommand, LspCommandIo}, + Taplo, +}; impl Taplo { pub async fn execute_lsp(&mut self, cmd: LspCommand) -> Result<(), anyhow::Error> { diff --git a/crates/taplo-cli/src/lib.rs b/crates/taplo-cli/src/lib.rs index b1f283748..fc717b6f7 100644 --- a/crates/taplo-cli/src/lib.rs +++ b/crates/taplo-cli/src/lib.rs @@ -1,6 +1,5 @@ use anyhow::{anyhow, Context}; use args::GeneralArgs; -use itertools::Itertools; use std::{ path::{Path, PathBuf}, str, @@ -12,6 +11,8 @@ pub mod args; pub mod commands; pub mod printing; +pub type EntryIter<'a, F> = std::iter::FilterMap; + pub struct Taplo { env: E, colors: bool, @@ -84,17 +85,25 @@ impl Taplo { } #[tracing::instrument(skip_all, fields(?cwd))] - async fn collect_files( + async fn files_iter( &self, cwd: &Path, config: &Config, arg_patterns: impl Iterator, - ) -> Result, anyhow::Error> { + ) -> Result< + EntryIter<'_, Box) -> Option>>, + anyhow::Error, + > { + tracing::trace!("Nomarlizing patterns to absolute ones..."); + let mut patterns: Vec = arg_patterns .map(|pat| { if !self.env.is_absolute(Path::new(&pat)) { - cwd.join(&pat).normalize().to_string_lossy().into_owned() + let pat = cwd.join(&pat).normalize().to_string_lossy().into_owned(); + tracing::debug!("Arg(abs) {} ", &pat); + pat } else { + tracing::debug!("Arg(rel) {} ", &pat); pat } }) @@ -111,33 +120,67 @@ impl Taplo { }; }; - let patterns = patterns - .into_iter() - .unique() - .map(|p| glob::Pattern::new(&p).map(|_| p)) - .collect::, _>>()?; - - let files = patterns - .into_iter() - .map(|pat| self.env.glob_files_normalized(&pat)) - .collect::, _>>() - .into_iter() - .flatten() - .flatten() - .collect::>(); - - let total = files.len(); + tracing::trace!("Compiled patterns"); - let files = files - .into_iter() - .filter(|path| config.is_included(path)) - .collect::>(); + let mut skip_patterns = vec![]; + let mut keep_patterns = vec![]; - let excluded = total - files.len(); - - tracing::info!(total, excluded, "found files"); + let opts = glob::MatchOptions { + case_sensitive: true, + ..Default::default() + }; - Ok(files) + let cwd = cwd.to_path_buf(); + + let mut bldr = ignore::WalkBuilder::new(&cwd); + bldr.git_ignore(true) + .git_exclude(true) + .git_global(true) + .ignore(true) + .hidden(false) + .same_file_system(true); + + for skip_pattern in config.exclude.iter().cloned().flatten() { + if let Ok(pat) = glob::Pattern::new(&skip_pattern) { + tracing::trace!("Compiling pattern: {skip_pattern}"); + skip_patterns.push(pat.clone()); + bldr.filter_entry(move |entry| !pat.matches_path_with(entry.path(), opts)); + } + } + for keep_pattern in config + .include + .iter() + .cloned() + .flatten() + .map(|x| x.to_owned()) + .chain(patterns.into_iter()) + { + if let Ok(pat) = glob::Pattern::new(&keep_pattern) { + tracing::trace!("Compiling pattern: {pat}"); + keep_patterns.push(pat.clone()); + bldr.filter_entry(move |entry| pat.matches_path_with(entry.path(), opts)); + } + } + let walker = bldr.build(); + + Ok(walker.filter_map(Box::new( + move |entry: Result| -> Option { + let entry = entry.ok()?; + debug_assert!(!skip_patterns + .iter() + .any(|pat| pat.matches_path_with(entry.path(), opts.clone()))); + debug_assert!(keep_patterns + .iter() + .any(|pat| pat.matches_path_with(entry.path(), opts))); + if entry.path() == cwd { + None + } else { + let p = entry.path().to_path_buf(); + tracing::debug!("Path passed filters: {}", p.display()); + Some(p) + } + }, + ))) } } diff --git a/crates/taplo-lsp/src/world.rs b/crates/taplo-lsp/src/world.rs index fc413ac2d..b8c4b3b6a 100644 --- a/crates/taplo-lsp/src/world.rs +++ b/crates/taplo-lsp/src/world.rs @@ -246,8 +246,9 @@ impl WorkspaceState { }; if let Some(config_path) = config_path { - tracing::info!(path = ?config_path, "using config file"); - self.taplo_config = toml::from_str(str::from_utf8(&env.read_file(&config_path).await?)?)?; + tracing::debug!(path = ?config_path, "using config file"); + self.taplo_config = + toml::from_str(str::from_utf8(&env.read_file(&config_path).await?)?)?; } } diff --git a/crates/taplo/src/formatter/mod.rs b/crates/taplo/src/formatter/mod.rs index 091b9e5b7..d659de118 100644 --- a/crates/taplo/src/formatter/mod.rs +++ b/crates/taplo/src/formatter/mod.rs @@ -681,7 +681,9 @@ fn add_entries( entry.value.clear(); if let Some(c) = value.trailing_comment() { - debug_assert!(entry.comment.is_none() || entry.comment.clone().unwrap() == c); + debug_assert!( + entry.comment.is_none() || entry.comment.clone().unwrap() == c + ); entry.comment = Some(c); }