use ignore::WalkBuilder;
use std::path::{Path, PathBuf};
pub const SKIP_DIR_NAMES: &[&str] = &[
"target",
"node_modules",
".git",
"dist",
"build",
"__pycache__",
".venv",
"venv",
".turbo",
".next",
];
pub fn configure_workspace_walk(builder: &mut WalkBuilder, respect_gitignore: bool) {
builder
.hidden(false)
.follow_links(false)
.require_git(false)
.git_ignore(respect_gitignore)
.git_global(respect_gitignore)
.ignore(respect_gitignore)
.parents(respect_gitignore)
.filter_entry(|entry| {
if entry.file_type().is_some_and(|ft| ft.is_dir()) {
let name = entry.file_name().to_string_lossy();
return !SKIP_DIR_NAMES.contains(&name.as_ref());
}
true
});
}
pub fn collect_workspace_files(root: &Path, respect_gitignore: bool) -> Vec<PathBuf> {
if root.is_file() {
return vec![root.to_path_buf()];
}
if !root.is_dir() {
return Vec::new();
}
let mut builder = WalkBuilder::new(root);
configure_workspace_walk(&mut builder, respect_gitignore);
let walker = builder.build();
let mut files = Vec::new();
for entry in walker.flatten() {
if entry.file_type().is_some_and(|ft| ft.is_file()) {
files.push(entry.into_path());
}
}
files
}
pub fn is_probably_binary(path: &Path) -> bool {
use std::io::Read;
const SNIFF_LEN: usize = 8 * 1024;
let Ok(mut file) = std::fs::File::open(path) else {
return true;
};
let mut buf = [0u8; SNIFF_LEN];
let Ok(n) = file.read(&mut buf) else {
return true;
};
let head = &buf[..n];
if head.starts_with(&[0xFF, 0xFE]) || head.starts_with(&[0xFE, 0xFF]) || head.starts_with(&[0xEF, 0xBB, 0xBF])
{
return false;
}
head.contains(&0)
}