use crate::{
cancellation::{CancellationFlag, Outcome},
disk_path::{DiskPath, WikiDirectory},
};
use ignore::{WalkBuilder, overrides::OverrideBuilder};
use std::path::Path;
pub fn wiki_tree_walker(wiki_directory: &Path) -> Result<WalkBuilder, ignore::Error> {
let mut overrides = OverrideBuilder::new(wiki_directory);
overrides
.add("!.git/")
.expect("The static .git override should be valid.")
.add("!.hg/")
.expect("The static .hg override should be valid.");
let overrides = overrides.build()?;
let mut walker_builder = WalkBuilder::new(wiki_directory);
walker_builder
.current_dir(wiki_directory)
.follow_links(true)
.hidden(false)
.parents(false)
.require_git(false)
.overrides(overrides);
Ok(walker_builder)
}
#[derive(Debug, Eq, PartialEq)]
pub enum Visibility {
Visible,
Empty,
Ignored,
}
pub fn visibility(
wiki_directory: &WikiDirectory,
target: &DiskPath,
cancellation: &CancellationFlag,
) -> Outcome<Result<Visibility, ignore::Error>> {
let mut walker_builder = match wiki_tree_walker(wiki_directory.path()) {
Ok(walker_builder) => walker_builder,
Err(error) => return Outcome::Completed(Err(error)),
};
walker_builder.filter_entry({
let wiki_directory = wiki_directory.clone();
let target = target.clone();
move |entry| {
let path = wiki_directory.entry_path(entry);
target.starts_with(&path) || path.starts_with(&target)
}
});
let mut reached = false;
for entry in walker_builder.build().flatten() {
if cancellation.is_cancelled() {
return Outcome::Cancelled;
}
let path = wiki_directory.entry_path(&entry);
if path == *target {
reached = true;
}
if path.starts_with(target) && entry.file_type().is_some_and(|t| t.is_file()) {
return Outcome::Completed(Ok(Visibility::Visible));
}
}
Outcome::Completed(Ok(if reached {
Visibility::Empty
} else {
Visibility::Ignored
}))
}