Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 87 additions & 7 deletions src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,16 @@ pub struct SetupCommand {
impl CommandConfiguration {
pub fn matches_exts_or_filenames(&self, path: &Path) -> bool {
if let Some(filename) = path.file_name() {
let filename = filename.to_string_lossy().to_lowercase();
for ext in &self.file_extensions {
if filename.ends_with(ext) {
return true;
}
}
self.file_names.iter().any(|name| name == &filename)
// match case insensitively, which is what dprint does
let filename = filename.to_string_lossy();
self
.file_extensions
.iter()
.any(|ext| ends_with_ignore_case(&filename, ext))
|| self
.file_names
.iter()
.any(|name| eq_ignore_case(&filename, name))
} else {
false
}
Expand Down Expand Up @@ -451,6 +454,21 @@ fn compute_cache_key_files_hash(cache_key_file_hashes: &[String]) -> Option<Stri
Some(format!("{:x}", hasher.finalize()))
}

fn eq_ignore_case(a: &str, b: &str) -> bool {
a.chars()
.flat_map(char::to_lowercase)
.eq(b.chars().flat_map(char::to_lowercase))
}

fn ends_with_ignore_case(text: &str, suffix: &str) -> bool {
let mut text_chars = text.chars().rev().flat_map(|c| c.to_lowercase().rev());
suffix
.chars()
.rev()
.flat_map(|c| c.to_lowercase().rev())
.all(|c| text_chars.next() == Some(c))
}

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -459,6 +477,68 @@ mod tests {
use pretty_assertions::assert_eq;
use serde_json::json;

#[test]
fn matches_exts_and_file_names_case_insensitively() {
let unresolved_config = r#"{
"commands": [{
"command": "command",
"exts": ["PS1", "sh"],
"fileNames": ["Makefile", "justfile"]
}]
}"#;
let unresolved_config = serde_json::from_str(unresolved_config).unwrap();
let result = Configuration::resolve(unresolved_config, &Default::default());
assert!(result.diagnostics.is_empty());
let command = &result.config.commands[0];
for path in [
"/dir/file.ps1",
"/dir/file.PS1",
"/dir/file.sh",
"/dir/file.SH",
"/dir/Makefile",
"/dir/makefile",
"/dir/justfile",
"/dir/Justfile",
] {
assert!(
command.matches_exts_or_filenames(Path::new(path)),
"{}",
path
);
}
for path in [
"/dir/file.txt",
"/dir/other",
"/dir/makefile.txt",
"/dir/sh",
"/dir/s1",
"/dir/akefile",
"/dir/amakefile",
] {
assert!(
!command.matches_exts_or_filenames(Path::new(path)),
"{}",
path
);
}
}

#[test]
fn ignore_case_comparisons() {
assert!(eq_ignore_case("Makefile", "makefile"));
assert!(eq_ignore_case("\u{00c9}t\u{00e9}", "\u{00e9}T\u{00c9}"));
assert!(eq_ignore_case("", ""));
assert!(!eq_ignore_case("makefile", "makefil"));
assert!(!eq_ignore_case("makefile", "makefiles"));

assert!(ends_with_ignore_case("file.PS1", ".ps1"));
assert!(ends_with_ignore_case("file.\u{00c9}", ".\u{00e9}"));
assert!(ends_with_ignore_case(".ps1", ".PS1"));
assert!(ends_with_ignore_case("file", ""));
assert!(!ends_with_ignore_case("ps1", ".ps1"));
assert!(!ends_with_ignore_case("file.ps1x", ".ps1"));
}

#[test]
fn handle_global_config() {
let mut global_config = ConfigKeyMap::from([
Expand Down
Loading