Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ uzers = "0.12.1"
windows-sys = { version = "0.61.2", features = [
"Win32_System_Console",
"Win32_Foundation",
"Win32_Storage_FileSystem",
] }

[build-dependencies]
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ eza’s options are almost, but not quite, entirely unlike `ls`’s. Quick overv
- **-x**, **--across**: sort the grid across, rather than downwards
- **-F**, **--classify=(when)**: display type indicator by file names (always, auto, never)
- **--colo[u]r=(when)**: when to use terminal colours (always, auto, never)
- **--colo[u]r-scale=(field)**: highlight levels of `field` distinctly(all, age, size)
- **--colo[u]r-scale=(field)**: highlight levels of `field` distinctly (all, age, size)
- **--color-scale-mode=(mode)**: use gradient or fixed colors in --color-scale. valid options are `fixed` or `gradient`
- **--icons=(when)**: when to display icons (always, auto, never)
- **--hyperlink=(when)**: when to display entries as hyperlinks (always, auto, never)
Expand All @@ -122,6 +122,7 @@ eza’s options are almost, but not quite, entirely unlike `ls`’s. Quick overv
<summary>Click to expand</summary>

- **-a**, **--all**: show hidden and 'dot' files
- **--show-dotfiles**: show dot-prefixed files without showing other hidden files
- **-d**, **--treat-dirs-as-files**: list directories like regular files
- **-L**, **--level=(depth)**: limit the depth of recursion
- **-r**, **--reverse**: reverse the sort order
Expand Down
2 changes: 1 addition & 1 deletion completions/bash/eza
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ _eza() {
prev=${COMP_WORDS[COMP_CWORD-1]}

case "$prev" in
--help|-v|--version|--smart-group)
--help|-v|--version|--smart-group|--show-dotfiles)
return
;;

Expand Down
1 change: 1 addition & 0 deletions completions/fish/eza.fish
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ complete -c eza -l group-directories-last -d "Sort directories after other files
complete -c eza -l git-ignore -d "Ignore files mentioned in '.gitignore'"
complete -c eza -s a -l all -d "Show hidden and 'dot' files. Use this twice to also show the '.' and '..' directories"
complete -c eza -s A -l almost-all -d "Equivalent to --all; included for compatibility with `ls -A`"
complete -c eza -l show-dotfiles -d "Show dot-prefixed files without showing other hidden files"
complete -c eza -s d -l treat-dirs-as-files -d "List directories like regular files"
complete -c eza -s L -l level -d "Limit the depth of recursion" -x -a "1 2 3 4 5 6 7 8 9"
complete -c eza -s w -l width -d "Limits column output of grid, 0 implies auto-width"
Expand Down
1 change: 1 addition & 0 deletions completions/nush/eza.nu
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export extern "eza" [
--git-ignore # Ignore files mentioned in '.gitignore'
--all(-a) # Show hidden and 'dot' files. Use this twice to also show the '.' and '..' directories
--almost-all(-A) # Equivalent to --all; included for compatibility with `ls -A`
--show-dotfiles # Show dot-prefixed files without showing other hidden files
--treat-dirs-as-files(-d) # List directories like regular files
--level(-L): string # Limit the depth of recursion
--width(-w) # Limits column output of grid, 0 implies auto-width
Expand Down
1 change: 1 addition & 0 deletions completions/pwsh/_eza.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ Register-ArgumentCompleter -Native -CommandName 'eza' -ScriptBlock {
[CompletionResult]::new('--all' ,'filter' , [CompletionResultType]::ParameterName, 'show hidden and ''dot'' files. Use this twice to also show the ''.'' and ''..'' directories')
# [CompletionResult]::new('-A' ,'filter' , [CompletionResultType]::ParameterName, 'equivalent to --all; included for compatibility with `ls -A`')
# [CompletionResult]::new('--almost-all' ,'filter' , [CompletionResultType]::ParameterName, 'equivalent to --all; included for compatibility with `ls -A`')
[CompletionResult]::new('--show-dotfiles' ,'filter' , [CompletionResultType]::ParameterName, 'show dot-prefixed files without showing other hidden files')
# [CompletionResult]::new('-d' ,'filter' , [CompletionResultType]::ParameterName, 'list directories as files; don''t list their contents')
[CompletionResult]::new('--treat-dirs-as-files' ,'filter' , [CompletionResultType]::ParameterName, 'list directories as files; don''t list their contents')
# [CompletionResult]::new('-D' ,'filter' , [CompletionResultType]::ParameterName, 'list only directories')
Expand Down
3 changes: 3 additions & 0 deletions man/eza.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ Use this twice to also show the ‘`.`’ and ‘`..`’ directories.
`-A`, `--almost-all`
: Equivalent to --all; included for compatibility with `ls -A`.

`--show-dotfiles`
: Show dot-prefixed files without showing other hidden files.

`-d`, `--treat-dirs-as-files`
: This flag, inherited from `ls`, changes how `eza` handles directory arguments.

Expand Down
79 changes: 78 additions & 1 deletion src/fs/dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ impl Dir {
inner: self.contents.iter(),
dir: self,
dotfiles: dots.shows_dotfiles(),
#[cfg(windows)]
windows_hidden: dots.shows_windows_hidden(),
dots: dots.dots(),
git,
git_ignoring,
Expand Down Expand Up @@ -122,6 +124,10 @@ pub struct Files<'dir, 'ig> {
/// Whether to include dotfiles in the list.
dotfiles: bool,

#[cfg(windows)]
/// Whether Windows hidden-attribute entries should be visible.
windows_hidden: bool,

/// Whether the `.` or `..` directories should be produced first, before
/// any files have been listed.
dots: DotsNext,
Expand Down Expand Up @@ -184,7 +190,7 @@ impl<'dir> Files<'dir, '_> {
// Windows has its own concept of hidden files, when dotfiles are
// hidden Windows hidden files should also be filtered out
#[cfg(windows)]
if !self.dotfiles && file.attributes().map_or(false, |a| a.hidden) {
if !self.windows_hidden && file.attributes().is_some_and(|a| a.hidden) {
continue;
}

Expand Down Expand Up @@ -244,6 +250,9 @@ pub enum DotFilter {
/// Show files and dotfiles, but hide `.` and `..`.
Dotfiles,

/// Show dotfiles by name only, but keep platform hidden-attribute files hidden.
DotfilesByName,

/// Just show files, hiding anything beginning with a dot.
#[default]
JustFiles,
Expand All @@ -255,16 +264,84 @@ impl DotFilter {
match self {
Self::JustFiles => false,
Self::Dotfiles => true,
Self::DotfilesByName => true,
Self::DotfilesAndDots => true,
}
}

#[cfg(windows)]
/// Whether this filter should reveal Windows hidden-attribute entries.
fn shows_windows_hidden(self) -> bool {
cfg!(windows) && matches!(self, Self::Dotfiles | Self::DotfilesAndDots)
}

/// Whether this filter should add dot directories to a listing.
fn dots(self) -> DotsNext {
match self {
Self::JustFiles => DotsNext::Files,
Self::Dotfiles => DotsNext::Files,
Self::DotfilesByName => DotsNext::Files,
Self::DotfilesAndDots => DotsNext::Dot,
}
}
}

#[cfg(all(test, windows))]
mod tests {
use super::*;
use std::fs;
use std::os::windows::ffi::OsStrExt;
use std::path::Path;
use std::time::{SystemTime, UNIX_EPOCH};
use windows_sys::Win32::Storage::FileSystem::{
FILE_ATTRIBUTE_HIDDEN, GetFileAttributesW, SetFileAttributesW,
};

fn unique_temp_dir() -> std::path::PathBuf {
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("time went backwards")
.as_nanos();
let path = std::env::temp_dir().join(format!("eza-show-dotfiles-{nanos}"));
fs::create_dir_all(&path).expect("failed to create temp dir");
path
}

fn set_hidden(path: &Path) {
let wide = path
.as_os_str()
.encode_wide()
.chain(std::iter::once(0))
.collect::<Vec<_>>();
unsafe {
let attrs = GetFileAttributesW(wide.as_ptr());
assert_ne!(attrs, u32::MAX);
assert_ne!(
SetFileAttributesW(wide.as_ptr(), attrs | FILE_ATTRIBUTE_HIDDEN),
0
);
}
}

#[test]
fn show_dotfiles_does_not_show_windows_hidden_attributes() {
let path = unique_temp_dir();
fs::write(path.join(".dotfile"), "").unwrap();
fs::write(path.join("_underscore"), "").unwrap();
fs::write(path.join("hidden.txt"), "").unwrap();
set_hidden(&path.join("hidden.txt"));

let dir = Dir::read_dir(path.clone()).unwrap();

let names: Vec<_> = dir
.files(DotFilter::DotfilesByName, None, false, false, false)
.map(|file| file.name)
.collect();

assert!(names.contains(&".dotfile".to_string()));
assert!(names.contains(&"_underscore".to_string()));
assert!(!names.contains(&"hidden.txt".to_string()));

let _ = fs::remove_dir_all(path);
}
}
31 changes: 25 additions & 6 deletions src/options/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,17 @@ impl DotFilter {
pub fn deduce(matches: &ArgMatches, strict: bool) -> Result<Self, OptionsError> {
let all_count = matches.get_count("all");
let has_almost_all = matches.get_flag("almost-all");
let show_dotfiles = matches.get_flag("show-dotfiles");

match (all_count, has_almost_all) {
(0, false) => Ok(Self::JustFiles),
if has_almost_all {
return Ok(Self::Dotfiles);
}

// either a single --all or at least one --almost-all is given
(1, _) | (0, true) => Ok(Self::Dotfiles),
// more than one --all
(c, _) => {
match all_count {
0 if show_dotfiles => Ok(Self::DotfilesByName),
0 => Ok(Self::JustFiles),
1 => Ok(Self::Dotfiles),
c => {
if matches.get_flag("tree") {
Err(OptionsError::TreeAllAll)
} else if strict && c > 2 {
Expand Down Expand Up @@ -250,6 +253,22 @@ mod tests {
);
}

#[test]
fn deduce_dot_filter_show_dotfiles() {
assert_eq!(
DotFilter::deduce(&mock_cli(vec!["--show-dotfiles"]), false),
Ok(DotFilter::DotfilesByName)
);
}

#[test]
fn deduce_dot_filter_show_dotfiles_and_all() {
assert_eq!(
DotFilter::deduce(&mock_cli(vec!["--show-dotfiles", "--all"]), false),
Ok(DotFilter::Dotfiles)
);
}

#[test]
fn deduce_sort_field_default() {
assert_eq!(
Expand Down
1 change: 1 addition & 0 deletions src/options/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ pub fn get_command() -> clap::Command {
.next_help_heading("FILTERING OPTIONS")
.arg(arg!(-a --all... "show hidden files. Use this twice to also show the '.' and '..' directories"))
.arg(arg!(-A --"almost-all" "equivalent to --all; included for compatibility with `ls -A`"))
.arg(arg!(--"show-dotfiles" "show dot-prefixed files without showing other hidden files"))
.arg(arg!(-d --"treat-dirs-as-files" "treat directories as files; don't list their contents")
.alias("list-dirs") // TODO: compat alias to remove (above flag published in v0.23.4 / 2025-10-03)
.conflicts_with_all(["recurse", "tree"]))
Expand Down
1 change: 1 addition & 0 deletions tests/ptests/ptest_2439b7d68089135b.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ DISPLAY OPTIONS:
FILTERING OPTIONS:
-a, --all... show hidden files. Use this twice to also show the '.' and '..' directories
-A, --almost-all equivalent to --all; included for compatibility with `ls -A`
--show-dotfiles show dot-prefixed files without showing other hidden files
-d, --treat-dirs-as-files treat directories as files; don't list their contents
-D, --only-dirs list only directories
-f, --only-files list only files
Expand Down
Loading