use std::collections::BTreeSet;
use dua::traverse::TreeIndex;
use gix::ignore::Kind;
use super::{EntryDataBundle, tree_view::TreeView};
pub fn gitignored_entries(
tree_view: &TreeView<'_>,
view_root: TreeIndex,
entries: &[EntryDataBundle],
) -> BTreeSet<TreeIndex> {
use std::path::{Path, PathBuf};
fn absolute_path(path: PathBuf, cwd: &Path) -> PathBuf {
if path.is_absolute() {
path
} else {
cwd.join(path)
}
}
fn mode(entry: &EntryDataBundle) -> gix::index::entry::Mode {
if entry.is_dir {
gix::index::entry::Mode::DIR
} else {
gix::index::entry::Mode::FILE
}
}
fn open_options(trust: gix::sec::Trust) -> gix::open::Options {
use gix::sec::trust::DefaultForLevel;
gix::open::Options::default_for_level(trust)
.config_overrides(["gitoxide.parsePrecious=true"])
}
let current_path = tree_view.path_of(view_root);
let current_path = if current_path.as_os_str().is_empty() {
Path::new(".").to_owned()
} else {
current_path
};
let trust_map = gix::sec::trust::Mapping {
full: open_options(gix::sec::Trust::Full),
reduced: open_options(gix::sec::Trust::Reduced),
};
let Ok(repo) =
gix::ThreadSafeRepository::discover_opts(¤t_path, Default::default(), trust_map)
else {
return BTreeSet::new();
};
let repo = repo.to_thread_local();
let Ok(cwd) = std::env::current_dir() else {
return BTreeSet::new();
};
let Some(workdir) = repo.workdir() else {
return BTreeSet::new();
};
let workdir = absolute_path(workdir.to_owned(), &cwd);
let Ok(index) = repo.index_or_empty() else {
return BTreeSet::new();
};
let Ok(mut excludes) = repo.excludes(
&index,
None,
gix::worktree::stack::state::ignore::Source::WorktreeThenIdMappingIfNotSkipped,
) else {
return BTreeSet::new();
};
entries
.iter()
.filter_map(|entry| {
let path = absolute_path(tree_view.path_of(entry.index), &cwd);
let relative_path = path.strip_prefix(&workdir).ok()?;
let platform = excludes.at_path(relative_path, Some(mode(entry))).ok()?;
platform
.excluded_kind()
.is_some_and(|kind| matches!(kind, Kind::Expendable))
.then_some(entry.index)
})
.collect()
}