ignore: refactor is_hidden

This does the more sensible thing of putting the implementation within
the routine instead of repeating the docs.

We also rename this routine since we're going to want a path variant for
incremental checking.
This commit is contained in:
Andrew Gallant committed 2026-07-17 09:10:32 -04:00
1 parent c035d23c26
commit 626b8951ac
2 files changed
+50 -45

No files matched your search

+2 -2
View File
@@ -25,7 +25,7 @@ use std::{
use crate::{
gitignore::{self, Gitignore, GitignoreBuilder},
overrides::{self, Override},
pathutil::{is_hidden, strip_prefix},
pathutil::{is_hidden_entry, strip_prefix},
types::{self, Types},
walk::DirEntry,
{Error, Match, PartialErrorBuilder},
@@ -487,7 +487,7 @@ impl Ignore {
dent: &DirEntry,
) -> Match<IgnoreMatch<'a>> {
let m = self.matched(dent.path(), dent.is_dir());
if m.is_none() && self.inner.opts.hidden && is_hidden(dent) {
if m.is_none() && self.inner.opts.hidden && is_hidden_entry(dent) {
return Match::Ignore(IgnoreMatch::hidden());
}
m
+48 -43
View File
@@ -2,58 +2,63 @@ use std::{ffi::OsStr, path::Path};
use crate::walk::DirEntry;
/// Returns true if and only if this entry is considered to be hidden.
/// Returns true if and only if this directory entry is considered to be
/// hidden.
///
/// This only returns true if the base name of the path starts with a `.`.
/// # Platform behavior
///
/// On Unix, this implements a more optimized check.
#[cfg(unix)]
pub(crate) fn is_hidden(dent: &DirEntry) -> bool {
use std::os::unix::ffi::OsStrExt;
if let Some(name) = file_name(dent.path()) {
name.as_bytes().get(0) == Some(&b'.')
} else {
false
}
}
/// Returns true if and only if this entry is considered to be hidden.
/// ## Windows
///
/// On Windows, this returns true if one of the following is true:
/// This returns true if one of the following is true:
///
/// * The base name of the path starts with a `.`.
/// * The file attributes have the `HIDDEN` property set.
#[cfg(windows)]
pub(crate) fn is_hidden(dent: &DirEntry) -> bool {
use std::os::windows::fs::MetadataExt;
use winapi_util::file;
// This looks like we're doing an extra stat call, but on Windows, the
// directory traverser reuses the metadata retrieved from each directory
// entry and stores it on the DirEntry itself. So this is "free."
if let Ok(md) = dent.metadata() {
if file::is_hidden(md.file_attributes() as u64) {
return true;
}
}
if let Some(name) = file_name(dent.path()) {
name.to_str().map(|s| s.starts_with(".")).unwrap_or(false)
} else {
false
}
}
/// Returns true if and only if this entry is considered to be hidden.
///
/// ## All other platforms
///
/// This only returns true if the base name of the path starts with a `.`.
#[cfg(not(any(unix, windows)))]
pub(crate) fn is_hidden(dent: &DirEntry) -> bool {
if let Some(name) = file_name(dent.path()) {
name.to_str().map(|s| s.starts_with(".")).unwrap_or(false)
} else {
false
pub(crate) fn is_hidden_entry(dent: &DirEntry) -> bool {
#[cfg(unix)]
fn imp(dent: &DirEntry) -> bool {
use std::os::unix::ffi::OsStrExt;
if let Some(name) = file_name(dent.path()) {
name.as_bytes().get(0) == Some(&b'.')
} else {
false
}
}
#[cfg(windows)]
fn imp(dent: &DirEntry) -> bool {
use std::os::windows::fs::MetadataExt;
use winapi_util::file;
// This looks like we're doing an extra stat call, but on Windows, the
// directory traverser reuses the metadata retrieved from each directory
// entry and stores it on the DirEntry itself. So this is "free."
if let Ok(md) = dent.metadata() {
if file::is_hidden(md.file_attributes() as u64) {
return true;
}
}
if let Some(name) = file_name(dent.path()) {
name.to_str().map(|s| s.starts_with(".")).unwrap_or(false)
} else {
false
}
}
#[cfg(not(any(unix, windows)))]
fn imp(dent: &DirEntry) -> bool {
if let Some(name) = file_name(dent.path()) {
name.to_str().map(|s| s.starts_with(".")).unwrap_or(false)
} else {
false
}
}
imp(dent)
}
/// Strip `prefix` from the `path` and return the remainder.