use std::path::{Path, PathBuf};
use ignore::gitignore::{Gitignore, GitignoreBuilder};
use ignore::WalkBuilder;
use crate::core::config::Config;
#[must_use]
pub fn walk_standalone_docs(root: &Path, cfg: &Config) -> Vec<PathBuf> {
let standalone = &cfg.features.docs.standalone;
let Some(include) = build_matcher(root, &standalone.include) else {
return Vec::new();
};
let exclude = build_matcher(root, &standalone.exclude);
let project_excludes = build_matcher(root, &cfg.exclude_lines());
let mut out: Vec<PathBuf> = Vec::new();
for entry in WalkBuilder::new(root)
.require_git(false)
.build()
.filter_map(Result::ok)
{
if !entry.file_type().is_some_and(|ft| ft.is_file()) {
continue;
}
let abs = entry.into_path();
let rel = match abs.strip_prefix(root) {
Ok(p) => p.to_path_buf(),
Err(_) => continue,
};
if !is_match(&include, &rel) {
continue;
}
if let Some(ex) = exclude.as_ref() {
if is_match(ex, &rel) {
continue;
}
}
if let Some(ex) = project_excludes.as_ref() {
if is_match(ex, &rel) {
continue;
}
}
out.push(rel);
}
out.sort();
out
}
pub(super) fn build_matcher(root: &Path, lines: &[String]) -> Option<Gitignore> {
if lines.is_empty() {
return None;
}
let mut builder = GitignoreBuilder::new(root);
for line in lines {
let _ = builder.add_line(None, line);
}
builder.build().ok()
}
pub(super) fn is_match(gi: &Gitignore, rel: &Path) -> bool {
gi.matched_path_or_any_parents(rel, false)
.is_ignore()
}