use std::ffi::OsString;
use std::path::{Path, PathBuf};
use ignore::gitignore::{Gitignore, GitignoreBuilder};
use crate::commands::init::model::HiddenKind;
#[derive(Debug, Clone)]
pub struct GitignoreMatcher {
local: Gitignore,
global: Gitignore,
}
impl GitignoreMatcher {
#[must_use]
pub fn new(cwd_host: &Path) -> Self {
let mut builder = GitignoreBuilder::new(cwd_host);
let _ = builder.add(cwd_host.join(".gitignore"));
let local = builder.build().unwrap_or_else(|_| Gitignore::empty());
let (global, _) = Gitignore::global();
Self { local, global }
}
#[must_use]
pub fn is_ignored(&self, host_path: &Path, is_dir: bool) -> bool {
self.local.matched(host_path, is_dir).is_ignore()
|| self.global.matched(host_path, is_dir).is_ignore()
}
}
pub(super) fn classify_hidden(
name: &OsString,
host_path: &Path,
gitignore: &GitignoreMatcher,
) -> HiddenKind {
if gitignore.is_ignored(host_path, true) {
return HiddenKind::Gitignored;
}
if is_hidden_name(name) {
return HiddenKind::Dotfile;
}
HiddenKind::Visible
}
fn is_hidden_name(name: &OsString) -> bool {
let bytes = name.as_encoded_bytes();
bytes.first().copied() == Some(b'.')
}
pub(super) fn host_join(cwd_host_root: &Path, workspace_absolute: &Path) -> PathBuf {
let stripped = workspace_absolute
.strip_prefix("/")
.unwrap_or(workspace_absolute);
if stripped.as_os_str().is_empty() {
cwd_host_root.to_path_buf()
} else {
cwd_host_root.join(stripped)
}
}