From f11c3fc899b2f9857116b7769620c15d58fd6399 Mon Sep 17 00:00:00 2001
From: KP64
Date: Thu, 27 Apr 2023 19:36:32 +0200
Subject: [PATCH 01/14] refactor: :recycle: removal of "Glob" booleans through
addition of Glob Enum.
The Glob enum has been introduced in order to get rid of duplicated settings. This makes the Checking of the provided arguments easier in source code since Enums are Exhaustive. This comes at a minimal usage friendliness degradation since now it would be needed to specify "--glob insensitive" instead of "--iglob". Even then I think it is worth it :3
---
src/main.rs | 13 ++-------
src/render/context/mod.rs | 46 ++++++++++++++++++++------------
src/render/tree/display/theme.rs | 6 +++--
src/render/tree/mod.rs | 41 ++++++++++++----------------
src/render/tree/node/mod.rs | 16 ++++++++---
src/tty/windows.rs | 5 ++--
6 files changed, 66 insertions(+), 61 deletions(-)
diff --git a/src/main.rs b/src/main.rs
index aace35df..8dcabacd 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -23,7 +23,7 @@ use render::{
Tree,
},
};
-use std::{io::stdout, process::ExitCode};
+use std::{error::Error, io::stdout};
/// Operations to wrangle ANSI escaped strings.
mod ansi;
@@ -43,16 +43,7 @@ mod tty;
/// Common utilities across all modules.
mod utils;
-fn main() -> ExitCode {
- if let Err(e) = run() {
- eprintln!("{e}");
- return ExitCode::FAILURE;
- }
-
- ExitCode::SUCCESS
-}
-
-fn run() -> Result<(), Box> {
+fn main() -> Result<(), Box> {
let ctx = Context::init()?;
if let Some(shell) = ctx.completions {
diff --git a/src/render/context/mod.rs b/src/render/context/mod.rs
index 78e0af66..5f7c06fe 100644
--- a/src/render/context/mod.rs
+++ b/src/render/context/mod.rs
@@ -52,6 +52,19 @@ pub enum Coloring {
/// Turn on colorization always
Forced,
}
+
+#[derive(Clone, Copy, Debug, clap::ValueEnum, PartialEq, Eq, Default)]
+pub enum Glob {
+ // Disables glob based searching
+ #[default]
+ None,
+
+ /// Enables glob based searching
+ Sensitive,
+
+ /// Enables case-insensitive glob based searching
+ Insensitive,
+}
/// Defines the CLI.
#[derive(Parser, Debug)]
#[command(name = "erdtree")]
@@ -114,12 +127,8 @@ pub struct Context {
pub pattern: Option,
/// Enables glob based searching
- #[arg(long, requires = "pattern")]
- pub glob: bool,
-
- /// Enables case-insensitive glob based searching
- #[arg(long, requires = "pattern")]
- pub iglob: bool,
+ #[arg(long, requires = "pattern", value_enum, default_value_t = Glob::default())]
+ pub glob: Glob,
/// Restrict regex or glob search to a particular file-type
#[arg(short = 't', long, requires = "pattern", value_enum)]
@@ -220,6 +229,15 @@ impl Context {
/// Initializes [Context], optionally reading in the configuration file to override defaults.
/// Arguments provided will take precedence over config.
pub fn init() -> Result {
+ trait IntoVecOfStr {
+ fn as_vec_of_str(&self) -> Vec<&str>;
+ }
+ impl IntoVecOfStr for ArgMatches {
+ fn as_vec_of_str(&self) -> Vec<&str> {
+ self.ids().map(Id::as_str).collect()
+ }
+ }
+
let user_args = Self::command().args_override_self(true).get_matches();
let no_config = user_args
@@ -244,16 +262,13 @@ impl Context {
// user arguments.
let mut args = vec![OsString::from("--")];
- let mut ids = user_args.ids().map(Id::as_str).collect::>();
+ let mut ids = user_args.as_vec_of_str();
- ids.extend(config_args.ids().map(Id::as_str).collect::>());
+ ids.extend(config_args.as_vec_of_str());
ids = crate::utils::uniq(ids);
- for id in ids {
- if id == "Context" {
- continue;
- }
+ for id in ids.into_iter().filter(|&id| id != "Context") {
if id == "dir" {
if let Ok(Some(raw)) = user_args.try_get_raw(id) {
let raw_args = raw.map(OsStr::to_owned).collect::>();
@@ -394,11 +409,8 @@ impl Context {
let mut negated_glob = false;
- let overrides = if !self.glob && !self.iglob {
- // Shouldn't really ever be hit but placing here as a safeguard.
- return Err(Error::EmptyGlob);
- } else {
- if self.iglob {
+ let overrides = {
+ if self.glob == Glob::Insensitive {
builder.case_insensitive(true)?;
}
diff --git a/src/render/tree/display/theme.rs b/src/render/tree/display/theme.rs
index 3df91c43..f8b04de6 100644
--- a/src/render/tree/display/theme.rs
+++ b/src/render/tree/display/theme.rs
@@ -3,15 +3,17 @@ use crate::render::{
tree::Node,
};
+type Theme = Box &'static ThemesMap>;
+
/// Returns a closure that retrieves the regular theme.
-pub fn regular_theme_getter() -> Box &'static ThemesMap> {
+pub fn regular_theme_getter() -> Theme {
Box::new(|_node: &Node| styles::get_tree_theme().unwrap())
}
/// Returns a closure that can smartly determine when a symlink is being followed and when it is
/// not being followed. When a symlink is being followed, all of its descendents should have tree
/// branches that are colored differently.
-pub fn link_theme_getter() -> Box &'static ThemesMap> {
+pub fn link_theme_getter() -> Theme {
let mut link_depth = None;
Box::new(move |node: &Node| {
diff --git a/src/render/tree/mod.rs b/src/render/tree/mod.rs
index 9104c4b9..ee835c79 100644
--- a/src/render/tree/mod.rs
+++ b/src/render/tree/mod.rs
@@ -1,7 +1,7 @@
use crate::{
fs::inode::Inode,
render::{
- context::{file, output::ColumnProperties, Context},
+ context::{self, file, output::ColumnProperties, Context},
disk_usage::file_size::FileSize,
styles,
},
@@ -282,19 +282,14 @@ where
/// Function to remove empty directories.
fn prune_directories(root_id_id: NodeId, tree: &mut Arena) {
- let mut to_prune = vec![];
-
- for node_id in root_id_id.descendants(tree).skip(1) {
- let node = tree[node_id].get();
-
- if !node.is_dir() {
- continue;
- }
-
- if node_id.children(tree).count() == 0 {
- to_prune.push(node_id);
- }
- }
+ let to_prune = root_id_id
+ .descendants(tree)
+ .skip(1)
+ .map(|node_id| (node_id, tree[node_id].get()))
+ .filter(|(_, node)| node.is_dir())
+ .map(|(node_id, _)| node_id)
+ .filter(|node_id| node_id.children(tree).count() == 0)
+ .collect::>();
if to_prune.is_empty() {
return;
@@ -309,13 +304,11 @@ where
/// Filter for only directories.
fn filter_directories(root_id: NodeId, tree: &mut Arena) {
- let mut to_detach = vec![];
-
- for descendant_id in root_id.descendants(tree).skip(1) {
- if !tree[descendant_id].get().is_dir() {
- to_detach.push(descendant_id);
- }
- }
+ let to_detach = root_id
+ .descendants(tree)
+ .skip(1)
+ .filter(|&descendant_id| !tree[descendant_id].get().is_dir())
+ .collect::>();
for descendant_id in to_detach {
descendant_id.detach(tree);
@@ -405,10 +398,10 @@ impl TryFrom<&Context> for WalkParallel {
.threads(ctx.threads);
if ctx.pattern.is_some() {
- if ctx.glob || ctx.iglob {
- builder.filter_entry(ctx.glob_predicate()?);
- } else {
+ if ctx.glob == context::Glob::None {
builder.filter_entry(ctx.regex_predicate()?);
+ } else {
+ builder.filter_entry(ctx.glob_predicate()?);
}
}
diff --git a/src/render/tree/node/mod.rs b/src/render/tree/node/mod.rs
index 521d21d7..a346c0b5 100644
--- a/src/render/tree/node/mod.rs
+++ b/src/render/tree/node/mod.rs
@@ -128,13 +128,21 @@ impl Node {
}
/// Returns the underlying `ino` of the [`DirEntry`].
- pub fn ino(&self) -> Option {
- self.inode.map(|inode| inode.ino)
+ pub const fn ino(&self) -> Option {
+ if let Some(inode) = self.inode {
+ Some(inode.ino)
+ } else {
+ None
+ }
}
/// Returns the underlying `nlink` of the [`DirEntry`].
- pub fn nlink(&self) -> Option {
- self.inode.map(|inode| inode.nlink)
+ pub const fn nlink(&self) -> Option {
+ if let Some(inode) = self.inode {
+ Some(inode.nlink)
+ } else {
+ None
+ }
}
/// Returns `true` if node is a directory.
diff --git a/src/tty/windows.rs b/src/tty/windows.rs
index fb793e3e..796236b2 100644
--- a/src/tty/windows.rs
+++ b/src/tty/windows.rs
@@ -26,8 +26,7 @@ pub(super) unsafe fn win_width() -> Option {
};
(GetConsoleScreenBufferInfo(stdout_handle, &mut console_data) != 0)
- .then(|| console_data.srWindow.Right - console_data.srWindow.Left + 1)
+ .then_some(console_data.srWindow.Right - console_data.srWindow.Left + 1)
.map(usize::try_from)
- .map(Result::ok)
- .flatten()
+ .and_then(Result::ok)
}
From 40833f32fde2784deaa90b9f03381093b0ac6544 Mon Sep 17 00:00:00 2001
From: KP64
Date: Thu, 27 Apr 2023 19:44:13 +0200
Subject: [PATCH 02/14] Update all Tests to the new "Glob" Usage
---
src/render/tree/mod.rs | 11 ++++++-----
tests/glob.rs | 11 +++++++----
tests/prune.rs | 9 ++++++++-
3 files changed, 21 insertions(+), 10 deletions(-)
diff --git a/src/render/tree/mod.rs b/src/render/tree/mod.rs
index ee835c79..146eb006 100644
--- a/src/render/tree/mod.rs
+++ b/src/render/tree/mod.rs
@@ -398,11 +398,12 @@ impl TryFrom<&Context> for WalkParallel {
.threads(ctx.threads);
if ctx.pattern.is_some() {
- if ctx.glob == context::Glob::None {
- builder.filter_entry(ctx.regex_predicate()?);
- } else {
- builder.filter_entry(ctx.glob_predicate()?);
- }
+ match ctx.glob {
+ context::Glob::None => builder.filter_entry(ctx.regex_predicate()?),
+ context::Glob::Sensitive | context::Glob::Insensitive => {
+ builder.filter_entry(ctx.glob_predicate()?)
+ }
+ };
}
Ok(builder.build_parallel())
diff --git a/tests/glob.rs b/tests/glob.rs
index ff370aa3..a1b7f740 100644
--- a/tests/glob.rs
+++ b/tests/glob.rs
@@ -5,7 +5,7 @@ mod utils;
#[test]
fn glob() {
assert_eq!(
- utils::run_cmd(&["--glob", "--pattern", "*.txt", "tests/data"]),
+ utils::run_cmd(&["--glob", "sensitive", "--pattern", "*.txt", "tests/data"]),
indoc!(
"100 B ┌─ nylarlathotep.txt
161 B ├─ nemesis.txt
@@ -24,7 +24,7 @@ fn glob() {
#[test]
fn glob_negative() {
assert_eq!(
- utils::run_cmd(&["--glob", "--pattern", "!*.txt", "tests/data"]),
+ utils::run_cmd(&["--glob", "sensitive", "--pattern", "!*.txt", "tests/data"]),
indoc!(
"143 B ┌─ cassildas_song.md
143 B ┌─ the_yellow_king
@@ -38,7 +38,7 @@ fn glob_negative() {
#[test]
fn glob_case_insensitive() {
assert_eq!(
- utils::run_cmd(&["--iglob", "--pattern", "*.TXT", "tests/data"]),
+ utils::run_cmd(&["--glob", "insensitive", "--pattern", "*.TXT", "tests/data"]),
indoc!(
"100 B ┌─ nylarlathotep.txt
161 B ├─ nemesis.txt
@@ -59,6 +59,7 @@ fn glob_with_filetype() {
assert_eq!(
utils::run_cmd(&[
"--glob",
+ "sensitive",
"--pattern",
"dream*",
"--file-type",
@@ -80,6 +81,7 @@ fn negated_glob_with_filetype() {
assert_eq!(
utils::run_cmd(&[
"--glob",
+ "sensitive",
"--pattern",
"!dream*",
"--file-type",
@@ -106,6 +108,7 @@ fn negated_glob_with_filetype() {
fn glob_empty_set_dir() {
utils::run_cmd(&[
"--glob",
+ "sensitive",
"--pattern",
"*.txt",
"--file-type",
@@ -117,5 +120,5 @@ fn glob_empty_set_dir() {
#[test]
#[should_panic]
fn glob_empty_set_file() {
- utils::run_cmd(&["--glob", "--pattern", "*weewoo*", "tests/data"]);
+ utils::run_cmd(&["--glob", "sensitive", "--pattern", "*weewoo*", "tests/data"]);
}
diff --git a/tests/prune.rs b/tests/prune.rs
index 139d87df..96cc0637 100644
--- a/tests/prune.rs
+++ b/tests/prune.rs
@@ -5,7 +5,14 @@ mod utils;
#[test]
fn prune() {
assert_eq!(
- utils::run_cmd(&["--glob", "--pattern", "*.txt", "--prune", "tests/data"]),
+ utils::run_cmd(&[
+ "--glob",
+ "sensitive",
+ "--pattern",
+ "*.txt",
+ "--prune",
+ "tests/data"
+ ]),
indoc!(
"100 B ┌─ nylarlathotep.txt
161 B ├─ nemesis.txt
From 53db7f5043955f21454a0dfe3b12b2d3ed076186 Mon Sep 17 00:00:00 2001
From: KP64
Date: Thu, 27 Apr 2023 19:57:09 +0200
Subject: [PATCH 03/14] chore: :memo: Update README for new Globbing
---
README.md | 176 ++++++++++++++++++++++++++++--------------------------
1 file changed, 91 insertions(+), 85 deletions(-)
diff --git a/README.md b/README.md
index 0edecf4f..c12840b8 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,7 @@
[![Crates.io](https://img.shields.io/crates/d/erdtree)](https://crates.io/crates/erdtree)
`erdtree` is a modern, cross-platform, and multi-threaded filesystem and disk-usage analysis tool. The following are some feature highlights:
+
* Respects hidden file and gitignore rules by default.
* Supports regular expressions and glob based searching by file-type.
* Supports Unix-based file permissions (Unix systems only).
@@ -24,36 +25,36 @@ You can think of `erdtree` as a combination of `du`, `tree`, `find`, and `ls`.
* [Usage](#usage)
* [Installation](#installation)
* [Documentation](#documentation)
- - [Configuration file](#configuration-file)
- - [Hardlinks](#hardlinks)
- - [Symlinks](#symlinks)
- - [Disk usage](#disk-usage)
- - [Flat view](#flat-view)
- - [gitignore](#gitignore)
- - [Hidden files](#hidden-files)
- - [Icons](#icons)
- - [Maximum depth](#maximum-depth)
- - [Pruning empty directories](#pruning-empty-directories)
- - [Sorting](#sorting)
- - [Directories only](#directories-only)
- - [Permissions](#permissions)
- - [Regular expressions and globbing](#regular-expressions-and-globbing)
- - [Truncating output](#truncating-output)
- - [Redirecting output and colorization](#redirecting-output-and-colorization)
- - [Parallelism](#parallelism)
- - [Completions](#completions)
+ * [Configuration file](#configuration-file)
+ * [Hardlinks](#hardlinks)
+ * [Symlinks](#symlinks)
+ * [Disk usage](#disk-usage)
+ * [Flat view](#flat-view)
+ * [gitignore](#gitignore)
+ * [Hidden files](#hidden-files)
+ * [Icons](#icons)
+ * [Maximum depth](#maximum-depth)
+ * [Pruning empty directories](#pruning-empty-directories)
+ * [Sorting](#sorting)
+ * [Directories only](#directories-only)
+ * [Permissions](#permissions)
+ * [Regular expressions and globbing](#regular-expressions-and-globbing)
+ * [Truncating output](#truncating-output)
+ * [Redirecting output and colorization](#redirecting-output-and-colorization)
+ * [Parallelism](#parallelism)
+ * [Completions](#completions)
* [Comparisons against similar programs](#comparisons-against-similar-programs)
- - [exa](#exa)
- - [dua](#dua)
- - [dust](#dust)
- - [fd](#fd)
+ * [exa](#exa)
+ * [dua](#dua)
+ * [dust](#dust)
+ * [fd](#fd)
* [Rules for contributing](#rules-for-contributing)
* [Security policy](#security-policy)
* [Questions you might have](#questions-you-might-have)
## Usage
-```
+```txt
erdtree (erd) is a cross-platform multi-threaded filesystem and disk usage analysis tool.
Usage: erd [OPTIONS] [DIR]
@@ -73,9 +74,8 @@ Options:
--octal Show permissions in numeric octal format instead of symbolic
--time
The columns shown in the order of left to right are:
- * inode number
- * [permissions](https://en.wikipedia.org/wiki/File-system_permissions#Notation_of_traditional_Unix_permissions)
- * The number of hardlinks of the underlying inode
- * The number of blocks allocated to that particular file
- * The date the file was last modified (or created or last accessed)
+
+* inode number
+* [permissions](https://en.wikipedia.org/wiki/File-system_permissions#Notation_of_traditional_Unix_permissions)
+* The number of hardlinks of the underlying inode
+* The number of blocks allocated to that particular file
+* The date the file was last modified (or created or last accessed)
File permissions are currently not supported for Windows but will be sometime in the near future.
@@ -384,10 +389,9 @@ attributes will not be supported.
Searching for a particular file using a regular expression or glob is supported using the following:
-```
--p, --pattern Regular expression (or glob if '--glob' or '--iglob' is used) used to match files
- --glob Enables glob based searching
- --iglob Enables case-insensitive glob based searching
+```txt
+-p, --pattern Regular expression (or glob if '--glob' is used) used to match files
+ --glob Enables glob based searching [default: none] [possible values: none, sensitive, insensitive]
-t, --file-type Restrict regex or glob search to a particular file-type [possible values: file, dir, link]
```
@@ -399,8 +403,9 @@ Lastly, when applying a regular expression or glob to directories, off its desce
If you desire to only show directories you may use `--dirs-only`.
References:
- * [Globbing rules](https://git-scm.com/docs/gitignore#_pattern_format)
- * [Regular expressions](https://docs.rs/regex/latest/regex/#syntax)
+
+* [Globbing rules](https://git-scm.com/docs/gitignore#_pattern_format)
+* [Regular expressions](https://docs.rs/regex/latest/regex/#syntax)
### Truncating output
@@ -412,7 +417,7 @@ In instances where the output does not fit the terminal emulator's window, the o
In these situations the following may be used:
-```
+```txt
--truncate Truncate output to fit terminal emulator window
```
@@ -423,14 +428,15 @@ In these situations the following may be used:
### Redirecting output and colorization
If you wish to force a colorless output the following may be used:
-```
+
+```txt
-C none Print plainly without ANSI escapes
```
Colorization is also turned off if the output is redirected to something that is not a tty. If you wish to preserve the ANSI escape sequences (e.g.
preserve the colors as in the case of piping) the following may be used:
-```
+```txt
-C, forced Turn on colorization always
```
@@ -446,7 +452,7 @@ preserve the colors as in the case of piping) the following may be used:
The amount of threads used by `erdtree` can be adjusted with the following:
-```
+```txt
-T, --threads Number of threads to use [default: 3]
```
@@ -467,9 +473,9 @@ For empirical data on the subject checkout [this article](https://pkolaczk.githu
`--completions` is used to generate auto-completions for common shells so that the `tab` key can attempt to complete your command or give you hints; where you place the output highly depends on your shell as well as your setup. In my environment where I use `zshell` with `oh-my-zsh`, I would install completions like so:
-```
-$ et --completions zsh > ~/.oh-my-zsh/completions/_erd
-$ source ~/.zshrc
+```sh
+et --completions zsh > ~/.oh-my-zsh/completions/_erd
+source ~/.zshrc
```
## Rules for contributing
@@ -535,4 +541,4 @@ _Q: Why is there no mention of this project being blazingly fast or written in R
A: Okay fine. `erdtree` is written in Rust and is blazingly fast.
-
+![failed to load picture](https://i.redd.it/t7ns9qtb5gh81.jpg)
From 395539d8bcc80599f28b4e75642e125f7cf34847 Mon Sep 17 00:00:00 2001
From: KP64
Date: Mon, 1 May 2023 11:27:07 +0200
Subject: [PATCH 04/14] Relocating The `AsVecOfStr` trait and Impl to Top Level
---
src/render/context/mod.rs | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/src/render/context/mod.rs b/src/render/context/mod.rs
index 5f7c06fe..bdc87487 100644
--- a/src/render/context/mod.rs
+++ b/src/render/context/mod.rs
@@ -224,20 +224,21 @@ pub struct Context {
#[clap(skip)]
pub window_width: Option,
}
+
+trait AsVecOfStr {
+ fn as_vec_of_str(&self) -> Vec<&str>;
+}
+impl AsVecOfStr for ArgMatches {
+ fn as_vec_of_str(&self) -> Vec<&str> {
+ self.ids().map(Id::as_str).collect()
+ }
+}
+
type Predicate = Result bool + Send + Sync + 'static>, Error>;
impl Context {
/// Initializes [Context], optionally reading in the configuration file to override defaults.
/// Arguments provided will take precedence over config.
pub fn init() -> Result {
- trait IntoVecOfStr {
- fn as_vec_of_str(&self) -> Vec<&str>;
- }
- impl IntoVecOfStr for ArgMatches {
- fn as_vec_of_str(&self) -> Vec<&str> {
- self.ids().map(Id::as_str).collect()
- }
- }
-
let user_args = Self::command().args_override_self(true).get_matches();
let no_config = user_args
From 037e67d1e3627776bbb53c29d1aff0c5c473ba48 Mon Sep 17 00:00:00 2001
From: KP64
Date: Mon, 1 May 2023 11:30:56 +0200
Subject: [PATCH 05/14] Removal of unneded explicit 'Enum::default()' call.
---
src/render/context/mod.rs | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/render/context/mod.rs b/src/render/context/mod.rs
index bdc87487..28dae882 100644
--- a/src/render/context/mod.rs
+++ b/src/render/context/mod.rs
@@ -76,11 +76,11 @@ pub struct Context {
dir: Option,
/// Coloring of the Output
- #[arg(short = 'C', long, value_enum, default_value_t = Coloring::default())]
+ #[arg(short = 'C', long, value_enum, default_value_t)]
pub color: Coloring,
/// Print physical or logical file size
- #[arg(short, long, value_enum, default_value_t = DiskUsage::default())]
+ #[arg(short, long, value_enum, default_value_t)]
pub disk_usage: DiskUsage,
/// Follow symlinks
@@ -127,7 +127,7 @@ pub struct Context {
pub pattern: Option,
/// Enables glob based searching
- #[arg(long, requires = "pattern", value_enum, default_value_t = Glob::default())]
+ #[arg(long, requires = "pattern", value_enum, default_value_t)]
pub glob: Glob,
/// Restrict regex or glob search to a particular file-type
@@ -139,7 +139,7 @@ pub struct Context {
pub prune: bool,
/// Sort-order to display directory content
- #[arg(short, long, value_enum, default_value_t = sort::Type::default())]
+ #[arg(short, long, value_enum, default_value_t)]
pub sort: sort::Type,
/// Sort directories above files
From 55783ff7957a1e42c6d06dfd84682188b74b2cec Mon Sep 17 00:00:00 2001
From: KP64
Date: Mon, 1 May 2023 16:03:10 +0200
Subject: [PATCH 06/14] feat: :sparkles: New Comparators for more sorting
methods.
While Fixing #158 I've gone ahead and implemented other sorting methods in advance.
#158
---
src/render/context/sort.rs | 20 +++++-
src/render/tree/node/cmp.rs | 122 +++++++++++++++++++++++++++++-------
2 files changed, 118 insertions(+), 24 deletions(-)
diff --git a/src/render/context/sort.rs b/src/render/context/sort.rs
index 937f2e98..79aab23d 100644
--- a/src/render/context/sort.rs
+++ b/src/render/context/sort.rs
@@ -3,13 +3,29 @@ use clap::ValueEnum;
/// Order in which to print nodes.
#[derive(Copy, Clone, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord, Default)]
pub enum Type {
- /// Sort entries by file name
+ /// Sort entries by file name in lexicographical order.
Name,
+ /// Sort entries by file name in reversed lexicographical order.
+ NameRev,
/// Sort entries by size smallest to largest, top to bottom
#[default]
Size,
-
/// Sort entries by size largest to smallest, bottom to top
SizeRev,
+
+ /// Sort entries by newer to older Accessing Date
+ Access,
+ /// Sort entries by older to newer Accessing Date
+ AccessRev,
+
+ /// Sort entries by newer to older Creation Date
+ Creation,
+ /// Sort entries by older to newer Creation Date
+ CreationRev,
+
+ /// Sort entries by newer to older Alteration Date
+ Modification,
+ /// Sort entries by older to newer Alteration Date
+ ModificationRev,
}
diff --git a/src/render/tree/node/cmp.rs b/src/render/tree/node/cmp.rs
index 4a69ca8f..eba5452b 100644
--- a/src/render/tree/node/cmp.rs
+++ b/src/render/tree/node/cmp.rs
@@ -16,15 +16,6 @@ pub fn comparator(ctx: &Context) -> Box {
base_comparator(sort_type)
}
-/// Grabs the comparator for two non-dir type [Node]s.
-fn base_comparator(sort_type: sort::Type) -> Box {
- match sort_type {
- sort::Type::Name => Box::new(name_comparator),
- sort::Type::Size => Box::new(size_comparator),
- sort::Type::SizeRev => Box::new(size_rev_comparator),
- }
-}
-
/// Orders directories first. Provides a fallback if inputs are not directories.
fn dir_comparator(a: &Node, b: &Node, fallback: impl Fn(&Node, &Node) -> Ordering) -> Ordering {
match (a.is_dir(), b.is_dir()) {
@@ -34,22 +25,109 @@ fn dir_comparator(a: &Node, b: &Node, fallback: impl Fn(&Node, &Node) -> Orderin
}
}
-/// Comparator that sorts [Node]s by size, smallest to largest.
-fn size_rev_comparator(a: &Node, b: &Node) -> Ordering {
- let a_size = a.file_size().map_or(0, |fs| fs.bytes);
- let b_size = b.file_size().map_or(0, |fs| fs.bytes);
+/// Grabs the comparator for two non-dir type [Node]s.
+fn base_comparator(sort_type: sort::Type) -> Box {
+ Box::new(match sort_type {
+ sort::Type::Name => naming::comparator,
+ sort::Type::NameRev => naming::rev_comparator,
+
+ sort::Type::Size => sizing::comparator,
+ sort::Type::SizeRev => sizing::rev_comparator,
+
+ sort::Type::Access => time_stamping::accessed::comparator,
+ sort::Type::AccessRev => time_stamping::accessed::rev_comparator,
+
+ sort::Type::Creation => time_stamping::created::comparator,
+ sort::Type::CreationRev => time_stamping::created::rev_comparator,
+
+ sort::Type::Modification => time_stamping::modified::comparator,
+ sort::Type::ModificationRev => time_stamping::modified::rev_comparator,
+ })
+}
+
+mod time_stamping {
+ pub mod accessed {
+ use crate::render::tree::node::Node;
+ use core::cmp::Ordering;
+ use std::time::SystemTime;
+
+ /// Comparator that sorts [Node]s by Last Access timestamp, newer to older.
+ pub fn comparator(a: &Node, b: &Node) -> Ordering {
+ let a_stamp = a.accessed().unwrap_or_else(SystemTime::now);
+ let b_stamp = b.accessed().unwrap_or_else(SystemTime::now);
+ a_stamp.cmp(&b_stamp)
+ }
+
+ /// Comparator that sorts [Node]s by Access timestamp, older to newer.
+ pub fn rev_comparator(a: &Node, b: &Node) -> Ordering {
+ comparator(b, a)
+ }
+ }
+
+ pub mod created {
+ use crate::render::tree::node::Node;
+ use core::cmp::Ordering;
+ use std::time::SystemTime;
+
+ /// Comparator that sorts [Node]s by Creation timestamp, newer to older.
+ pub fn comparator(a: &Node, b: &Node) -> Ordering {
+ let a_stamp = a.created().unwrap_or_else(SystemTime::now);
+ let b_stamp = b.created().unwrap_or_else(SystemTime::now);
+ a_stamp.cmp(&b_stamp)
+ }
+
+ /// Comparator that sorts [Node]s by Creation timestamp, older to newer.
+ pub fn rev_comparator(a: &Node, b: &Node) -> Ordering {
+ comparator(b, a)
+ }
+ }
+
+ pub mod modified {
+ use crate::render::tree::node::Node;
+ use core::cmp::Ordering;
+ use std::time::SystemTime;
- a_size.cmp(&b_size)
+ /// Comparator that sorts [Node]s by Alteration timestamp, newer to older.
+ pub fn comparator(a: &Node, b: &Node) -> Ordering {
+ let a_stamp = a.modified().unwrap_or_else(SystemTime::now);
+ let b_stamp = b.modified().unwrap_or_else(SystemTime::now);
+ a_stamp.cmp(&b_stamp)
+ }
+
+ /// Comparator that sorts [Node]s by Alteration timestamp, older to newer.
+ pub fn rev_comparator(a: &Node, b: &Node) -> Ordering {
+ comparator(b, a)
+ }
+ }
}
-/// Comparator that sorts [Node]s by size, largest to smallest.
-fn size_comparator(a: &Node, b: &Node) -> Ordering {
- let a_size = a.file_size().map_or(0, |fs| fs.bytes);
- let b_size = b.file_size().map_or(0, |fs| fs.bytes);
- b_size.cmp(&a_size)
+mod sizing {
+ use crate::render::tree::node::Node;
+ use core::cmp::Ordering;
+
+ /// Comparator that sorts [Node]s by size, largest to smallest.
+ pub fn comparator(a: &Node, b: &Node) -> Ordering {
+ let a_size = a.file_size().map_or(0, |fs| fs.bytes);
+ let b_size = b.file_size().map_or(0, |fs| fs.bytes);
+ b_size.cmp(&a_size)
+ }
+ /// Comparator that sorts [Node]s by size, smallest to largest.
+ pub fn rev_comparator(a: &Node, b: &Node) -> Ordering {
+ comparator(b, a)
+ }
}
-/// Comparator based on [Node] file names.
-fn name_comparator(a: &Node, b: &Node) -> Ordering {
- a.file_name().cmp(b.file_name())
+mod naming {
+ use crate::render::tree::node::Node;
+ use core::cmp::Ordering;
+
+ /// Comparator based on [Node] file names in lexicographical order.
+ pub fn comparator(a: &Node, b: &Node) -> Ordering {
+ a.file_name().cmp(b.file_name())
+ }
+
+ /// Comparator based on [Node] file names in reversed lexicographical order.
+ pub fn rev_comparator(a: &Node, b: &Node) -> Ordering {
+ comparator(b, a)
+ }
}
From 29d037b950c835d1cb5c55836ffade75ccceaa0a Mon Sep 17 00:00:00 2001
From: KP64
Date: Mon, 1 May 2023 16:21:18 +0200
Subject: [PATCH 07/14] chore: Added package.categories for the Project
---
Cargo.toml | 1 +
src/main.rs | 4 +++-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/Cargo.toml b/Cargo.toml
index 93aef450..19605a72 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,6 +7,7 @@ description = """
erdtree (erd) is a cross-platform multi-threaded filesystem and disk usage
analysis tool that respects gitignore and hidden file rules.
"""
+categories = ["command-line-utilities"]
documentation = "https://github.com/solidiquis/erdtree"
homepage = "https://github.com/solidiquis/erdtree"
repository = "https://github.com/solidiquis/erdtree"
diff --git a/src/main.rs b/src/main.rs
index 8dcabacd..e0b37f56 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,7 +7,8 @@
clippy::complexity,
clippy::perf,
clippy::pedantic,
- clippy::nursery
+ clippy::nursery,
+ clippy::cargo
)]
#![allow(
clippy::struct_excessive_bools,
@@ -15,6 +16,7 @@
clippy::cast_sign_loss,
clippy::cast_possible_truncation
)]
+
use clap::CommandFactory;
use render::{
context::Context,
From ed24c1afa6feac724a26cea2a9c31303fdda5b36 Mon Sep 17 00:00:00 2001
From: KP64
Date: Mon, 1 May 2023 16:37:09 +0200
Subject: [PATCH 08/14] refactor: :recycle: "command" relies on Cargo.toml
The command macros for the Context struct now use the Cargo.toml values of the packages, since they are the same. The will be no need to change the "version" in both, the mod.rs and the Cargo.toml file, when the version is bumped up.
---
src/render/context/mod.rs | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/render/context/mod.rs b/src/render/context/mod.rs
index 28dae882..5fe1c035 100644
--- a/src/render/context/mod.rs
+++ b/src/render/context/mod.rs
@@ -67,10 +67,11 @@ pub enum Glob {
}
/// Defines the CLI.
#[derive(Parser, Debug)]
-#[command(name = "erdtree")]
-#[command(author = "Benjamin Nguyen. ")]
-#[command(version = "2.0.0")]
-#[command(about = "erdtree (erd) is a cross-platform multi-threaded filesystem and disk usage analysis tool.", long_about = None)]
+#[command(name = env!("CARGO_PKG_NAME", "The Package Name is missing!"))]
+#[command(author = env!("CARGO_PKG_AUTHORS", "The Author of the Package is missing!"))]
+#[command(version = env!("CARGO_PKG_VERSION_MAJOR", "The Package version is missing!"))]
+#[command(about = "erdtree (erd) is a cross-platform multi-threaded filesystem and disk usage analysis tool.",
+ long_about = env!("CARGO_PKG_DESCRIPTION", "The Long Package Description is missing!"))]
pub struct Context {
/// Directory to traverse; defaults to current working directory
dir: Option,
From cf2a75c1f321246f2e4f48fca64eef299e7b28eb Mon Sep 17 00:00:00 2001
From: KP64
Date: Mon, 1 May 2023 16:59:55 +0200
Subject: [PATCH 09/14] refactor: :recycle: Remove Glob Enum and add "--glob" +
"--iglob" together into a group
---
src/render/context/mod.rs | 21 ++++++---------------
src/render/tree/mod.rs | 13 ++++++-------
2 files changed, 12 insertions(+), 22 deletions(-)
diff --git a/src/render/context/mod.rs b/src/render/context/mod.rs
index 5fe1c035..480f0d10 100644
--- a/src/render/context/mod.rs
+++ b/src/render/context/mod.rs
@@ -53,18 +53,6 @@ pub enum Coloring {
Forced,
}
-#[derive(Clone, Copy, Debug, clap::ValueEnum, PartialEq, Eq, Default)]
-pub enum Glob {
- // Disables glob based searching
- #[default]
- None,
-
- /// Enables glob based searching
- Sensitive,
-
- /// Enables case-insensitive glob based searching
- Insensitive,
-}
/// Defines the CLI.
#[derive(Parser, Debug)]
#[command(name = env!("CARGO_PKG_NAME", "The Package Name is missing!"))]
@@ -128,8 +116,11 @@ pub struct Context {
pub pattern: Option,
/// Enables glob based searching
- #[arg(long, requires = "pattern", value_enum, default_value_t)]
- pub glob: Glob,
+ #[arg(group = "searching", long, requires = "pattern")]
+ pub glob: bool,
+
+ #[arg(group = "searching", long, requires = "pattern")]
+ pub iglob: bool,
/// Restrict regex or glob search to a particular file-type
#[arg(short = 't', long, requires = "pattern", value_enum)]
@@ -412,7 +403,7 @@ impl Context {
let mut negated_glob = false;
let overrides = {
- if self.glob == Glob::Insensitive {
+ if self.iglob {
builder.case_insensitive(true)?;
}
diff --git a/src/render/tree/mod.rs b/src/render/tree/mod.rs
index 146eb006..34f745e6 100644
--- a/src/render/tree/mod.rs
+++ b/src/render/tree/mod.rs
@@ -1,7 +1,7 @@
use crate::{
fs::inode::Inode,
render::{
- context::{self, file, output::ColumnProperties, Context},
+ context::{file, output::ColumnProperties, Context},
disk_usage::file_size::FileSize,
styles,
},
@@ -398,12 +398,11 @@ impl TryFrom<&Context> for WalkParallel {
.threads(ctx.threads);
if ctx.pattern.is_some() {
- match ctx.glob {
- context::Glob::None => builder.filter_entry(ctx.regex_predicate()?),
- context::Glob::Sensitive | context::Glob::Insensitive => {
- builder.filter_entry(ctx.glob_predicate()?)
- }
- };
+ if ctx.glob || ctx.iglob {
+ builder.filter_entry(ctx.glob_predicate()?);
+ } else {
+ builder.filter_entry(ctx.regex_predicate()?);
+ }
}
Ok(builder.build_parallel())
From 3bb2e0ef8429bbb48e5b0d9f40fd591ace4af8c3 Mon Sep 17 00:00:00 2001
From: KP64
Date: Mon, 1 May 2023 17:06:43 +0200
Subject: [PATCH 10/14] test: :white_check_mark: Reverted Testing to state
before the introduction of the Glob Enum
---
tests/glob.rs | 11 ++++-------
tests/prune.rs | 9 +--------
2 files changed, 5 insertions(+), 15 deletions(-)
diff --git a/tests/glob.rs b/tests/glob.rs
index a1b7f740..ff370aa3 100644
--- a/tests/glob.rs
+++ b/tests/glob.rs
@@ -5,7 +5,7 @@ mod utils;
#[test]
fn glob() {
assert_eq!(
- utils::run_cmd(&["--glob", "sensitive", "--pattern", "*.txt", "tests/data"]),
+ utils::run_cmd(&["--glob", "--pattern", "*.txt", "tests/data"]),
indoc!(
"100 B ┌─ nylarlathotep.txt
161 B ├─ nemesis.txt
@@ -24,7 +24,7 @@ fn glob() {
#[test]
fn glob_negative() {
assert_eq!(
- utils::run_cmd(&["--glob", "sensitive", "--pattern", "!*.txt", "tests/data"]),
+ utils::run_cmd(&["--glob", "--pattern", "!*.txt", "tests/data"]),
indoc!(
"143 B ┌─ cassildas_song.md
143 B ┌─ the_yellow_king
@@ -38,7 +38,7 @@ fn glob_negative() {
#[test]
fn glob_case_insensitive() {
assert_eq!(
- utils::run_cmd(&["--glob", "insensitive", "--pattern", "*.TXT", "tests/data"]),
+ utils::run_cmd(&["--iglob", "--pattern", "*.TXT", "tests/data"]),
indoc!(
"100 B ┌─ nylarlathotep.txt
161 B ├─ nemesis.txt
@@ -59,7 +59,6 @@ fn glob_with_filetype() {
assert_eq!(
utils::run_cmd(&[
"--glob",
- "sensitive",
"--pattern",
"dream*",
"--file-type",
@@ -81,7 +80,6 @@ fn negated_glob_with_filetype() {
assert_eq!(
utils::run_cmd(&[
"--glob",
- "sensitive",
"--pattern",
"!dream*",
"--file-type",
@@ -108,7 +106,6 @@ fn negated_glob_with_filetype() {
fn glob_empty_set_dir() {
utils::run_cmd(&[
"--glob",
- "sensitive",
"--pattern",
"*.txt",
"--file-type",
@@ -120,5 +117,5 @@ fn glob_empty_set_dir() {
#[test]
#[should_panic]
fn glob_empty_set_file() {
- utils::run_cmd(&["--glob", "sensitive", "--pattern", "*weewoo*", "tests/data"]);
+ utils::run_cmd(&["--glob", "--pattern", "*weewoo*", "tests/data"]);
}
diff --git a/tests/prune.rs b/tests/prune.rs
index 96cc0637..139d87df 100644
--- a/tests/prune.rs
+++ b/tests/prune.rs
@@ -5,14 +5,7 @@ mod utils;
#[test]
fn prune() {
assert_eq!(
- utils::run_cmd(&[
- "--glob",
- "sensitive",
- "--pattern",
- "*.txt",
- "--prune",
- "tests/data"
- ]),
+ utils::run_cmd(&["--glob", "--pattern", "*.txt", "--prune", "tests/data"]),
indoc!(
"100 B ┌─ nylarlathotep.txt
161 B ├─ nemesis.txt
From e6e9d0d27de1a6c872dc5c084b5dabd4249c0009 Mon Sep 17 00:00:00 2001
From: KP64
Date: Mon, 1 May 2023 17:21:46 +0200
Subject: [PATCH 11/14] Revert README
---
README.md | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index d8197480..44d234a5 100644
--- a/README.md
+++ b/README.md
@@ -74,8 +74,9 @@ Options:
--octal Show permissions in numeric octal format instead of symbolic
--time Which kind of timestamp to use; modified by default [possible values: created, accessed, modified]
-L, --level Maximum depth to display
- -p, --pattern Regular expression (or glob if '--glob' is used) used to match files
- --glob Enables glob based searching [default: none] [possible values: none, sensitive, insensitive]
+ -p, --pattern Regular expression (or glob if '--glob' or '--iglob' is used) used to match files
+ --glob Enables glob based searching
+ --iglob Enables case-insensitive glob based searching
-t, --file-type Restrict regex or glob search to a particular file-type [possible values: file, dir, link]
-P, --prune Remove empty directories from output
-s, --sort Sort-order to display directory content [default: size] [possible values: name, size, size-rev]
From cf52314195788715bb2d5a0e5b7528e17fcd8e2b Mon Sep 17 00:00:00 2001
From: KP64
Date: Mon, 1 May 2023 17:25:01 +0200
Subject: [PATCH 12/14] First Merge Conflict Fix
---
README.md | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index 44d234a5..9fe4a2cf 100644
--- a/README.md
+++ b/README.md
@@ -167,11 +167,12 @@ If `erdtree`'s out-of-the-box defaults don't meet your specific requirements, yo
`erdtree` will look for a configuration file in any of these locations:
-* `$ERDTREE_CONFIG_PATH`
-* `$XDG_CONFIG_HOME/erdtree/.erdtreerc`
-* `$XDG_CONFIG_HOME/.erdtreerc`
-* `$HOME/.config/erdtree/.erdtreerc`
-* `$HOME/.erdtreerc`
+On Linux/Mac/Unix-like:
+- `$ERDTREE_CONFIG_PATH`
+- `$XDG_CONFIG_HOME/erdtree/.erdtreerc`
+- `$XDG_CONFIG_HOME/.erdtreerc`
+- `$HOME/.config/erdtree/.erdtreerc`
+- `$HOME/.erdtreerc`
The format of a config file is as follows:
From f9db2d60355dd8f928d9d065eea0657ab9411861 Mon Sep 17 00:00:00 2001
From: KP64
Date: Mon, 1 May 2023 17:26:48 +0200
Subject: [PATCH 13/14] Second Conflict Fix
---
README.md | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 9fe4a2cf..2ad01827 100644
--- a/README.md
+++ b/README.md
@@ -347,7 +347,15 @@ Various sorting methods are provided:
To ensure that directories appear before all other file-types:
```txt
---dirs-first Sort directories above files
+--dir-order
+ Sort directories before or after all other file types
+
+ [default: none]
+
+ Possible values:
+ - none: Directories are ordered as if they were regular nodes
+ - first: Sort directories above files
+ - last: Sort directories below files
```
### Directories only
From adee56f39d0da89fa934055bc0ac51409f108d6a Mon Sep 17 00:00:00 2001
From: KP64
Date: Mon, 1 May 2023 17:31:36 +0200
Subject: [PATCH 14/14] Fix README
---
README.md | 177 +++++++++++++++++++++++++++---------------------------
1 file changed, 88 insertions(+), 89 deletions(-)
diff --git a/README.md b/README.md
index 2ad01827..6810d927 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,6 @@
[![Crates.io](https://img.shields.io/crates/d/erdtree)](https://crates.io/crates/erdtree)
`erdtree` is a modern, cross-platform, and multi-threaded filesystem and disk-usage analysis tool. The following are some feature highlights:
-
* Respects hidden file and gitignore rules by default.
* Supports regular expressions and glob based searching by file-type.
* Supports Unix-based file permissions (Unix systems only).
@@ -25,36 +24,36 @@ You can think of `erdtree` as a combination of `du`, `tree`, `find`, and `ls`.
* [Usage](#usage)
* [Installation](#installation)
* [Documentation](#documentation)
- * [Configuration file](#configuration-file)
- * [Hardlinks](#hardlinks)
- * [Symlinks](#symlinks)
- * [Disk usage](#disk-usage)
- * [Flat view](#flat-view)
- * [gitignore](#gitignore)
- * [Hidden files](#hidden-files)
- * [Icons](#icons)
- * [Maximum depth](#maximum-depth)
- * [Pruning empty directories](#pruning-empty-directories)
- * [Sorting](#sorting)
- * [Directories only](#directories-only)
- * [Permissions](#permissions)
- * [Regular expressions and globbing](#regular-expressions-and-globbing)
- * [Truncating output](#truncating-output)
- * [Redirecting output and colorization](#redirecting-output-and-colorization)
- * [Parallelism](#parallelism)
- * [Completions](#completions)
+ - [Configuration file](#configuration-file)
+ - [Hardlinks](#hardlinks)
+ - [Symlinks](#symlinks)
+ - [Disk usage](#disk-usage)
+ - [Flat view](#flat-view)
+ - [gitignore](#gitignore)
+ - [Hidden files](#hidden-files)
+ - [Icons](#icons)
+ - [Maximum depth](#maximum-depth)
+ - [Pruning empty directories](#pruning-empty-directories)
+ - [Sorting](#sorting)
+ - [Directories only](#directories-only)
+ - [Permissions](#permissions)
+ - [Regular expressions and globbing](#regular-expressions-and-globbing)
+ - [Truncating output](#truncating-output)
+ - [Redirecting output and colorization](#redirecting-output-and-colorization)
+ - [Parallelism](#parallelism)
+ - [Completions](#completions)
* [Comparisons against similar programs](#comparisons-against-similar-programs)
- * [exa](#exa)
- * [dua](#dua)
- * [dust](#dust)
- * [fd](#fd)
+ - [exa](#exa)
+ - [dua](#dua)
+ - [dust](#dust)
+ - [fd](#fd)
* [Rules for contributing](#rules-for-contributing)
* [Security policy](#security-policy)
* [Questions you might have](#questions-you-might-have)
## Usage
-```txt
+```
erdtree (erd) is a cross-platform multi-threaded filesystem and disk usage analysis tool.
Usage: erd [OPTIONS] [DIR]
@@ -63,7 +62,7 @@ Arguments:
[DIR] Directory to traverse; defaults to current working directory
Options:
- -C, --color Output Coloring [default: auto] [possible values: none, auto, forced]
+ -C, --color Mode of coloring output [default: auto] [possible values: none, auto, forced]
-d, --disk-usage Print physical or logical file size [default: physical] [possible values: logical, physical]
-f, --follow Follow symlinks
-F, --flat Print disk usage information in plain format without the ASCII tree
@@ -80,7 +79,7 @@ Options:
-t, --file-type Restrict regex or glob search to a particular file-type [possible values: file, dir, link]
-P, --prune Remove empty directories from output
-s, --sort Sort-order to display directory content [default: size] [possible values: name, size, size-rev]
- --dirs-first Sort directories above files
+ --dir-order Sort directories before or after all other file types [default: none] [possible values: none, first, last]
-T, --threads Number of threads to use [default: 3]
-u, --unit Report disk usage in binary or SI units [default: bin] [possible values: bin, si]
-., --hidden Show hidden files
@@ -97,7 +96,7 @@ Options:
Of all the above arguments, the following are not yet available on Windows but will be in the near future:
-```txt
+```
-l, --long Show extended metadata and attributes
--octal Show permissions in numeric octal format instead of symbolic
--time Which kind of timestamp to use; modified by default [possible values: created, accessed, modified]
@@ -109,40 +108,40 @@ Of all the above arguments, the following are not yet available on Windows but w
Make sure you have [Rust and its toolchain](https://www.rust-lang.org/tools/install) installed.
-```sh
-cargo install erdtree
+```
+$ cargo install erdtree
```
### crates.io (Windows)
The Windows version relies on some experimental features in order to properly support hard-link detection. If you want to build from `crates.io` you'll first need to install the nightly toolchain before installing `erdtree`:
-```sh
-rustup toolchain install nightly-2023-03-05
+```
+$ rustup toolchain install nightly-2023-03-05
```
Thereafter:
-```sh
-cargo +nightly-2023-03-05 install erdtree
+```
+$ cargo +nightly-2023-03-05 install erdtree
```
### Homebrew-core
-```sh
-brew install erdtree
+```
+$ brew install erdtree
```
### Scoop
-```sh
-scoop install erdtree
+```
+$ scoop install erdtree
```
### NetBSD
-```sh
-pkgin install erdtree
+```
+$ pkgin install erdtree
```
### Releases
@@ -153,8 +152,8 @@ Binaries for common architectures can be downloaded from latest releases.
If you'd like the latest features that are on `master` but aren't yet included as part of a release:
-```sh
-cargo install --git https://github.com/solidiquis/erdtree --branch master
+```
+$ cargo install --git https://github.com/solidiquis/erdtree --branch master
```
Other means of installation to come.
@@ -174,16 +173,19 @@ On Linux/Mac/Unix-like:
- `$HOME/.config/erdtree/.erdtreerc`
- `$HOME/.erdtreerc`
-The format of a config file is as follows:
+On Windows:
+- `$ERDTREE_CONFIG_PATH`
+- `%APPDATA%/erdtree/.erdtreerc`
-* Every line is an `erdtree` option/argument.
-* Lines starting with `#` are considered comments and are thus ignored.
+The format of a config file is as follows:
+- Every line is an `erdtree` option/argument.
+- Lines starting with `#` are considered comments and are thus ignored.
Arguments passed to `erdtree` take precedence. If you have a config that you would like to ignore without deleting you can use `--no-config`.
Here is an example of a valid configuration file:
-```txt
+```
# Long argument
--icons
--human
@@ -204,12 +206,13 @@ If multiple hardlinks that point to the same inode are in the same file-tree, al
### Symlinks
-```txt
+```
-f, --follow Follow symlinks
```
-Symlinks will never be counted towards the total disk usage. When a symlink to a directory is followed all of the box-drawing characters of its descendants will
-be painted in a different color for better visual feedback:
+Symlinks when followed will have their targets (and descendants) counted towards total disk usage, otherwise the size of the symlink itself will be reported.
+If a symlink's target happens to be in the same file-tree as the symlink itself, the target and its descendants will not be double-counted towards the total disk-usage.
+When a symlink to a directory is followed all of the box-drawing characters of its descendants will be painted in a different color for better visual feedback:
@@ -219,17 +222,17 @@ be painted in a different color for better visual feedback:
Disk usage is reported in total amount of bytes by default but can output in a human readable format using:
-```txt
+```
-H, --human Print disk usage in human-readable format
```
-#### Regular format
+#### Regular format:
-#### Human-readable format
+#### Human-readable format:
@@ -237,26 +240,26 @@ Disk usage is reported in total amount of bytes by default but can output in a h
Additionally, disk usage is reported using binary prefixes by default (e.g. `1 KiB = 1024 B`) but SI prefixes can be used as well (`1 KB = 1000 B`) using:
-```txt
+```
-u, --unit Report disk usage in binary or SI units [default: bin] [possible values: bin, si]
```
Furthermore, physical size which takes into account compression, sparse files, and actual blocks allocated to a particular file are used by default.
Logical size which just reports the total number of bytes in a file may also be used.
-```txt
+```
-d, --disk-usage Print physical or logical file size [default: physical] [possible values: logical, physical]
```
Lastly, if you'd like to omit disk usage from the output:
-```txt
+```
--suppress-size Omit disk usage from output
```
### Flat view
-```txt
+```
-F, --flat Print disk usage information in plain format without the ASCII tree
```
@@ -267,20 +270,18 @@ For a more traditional `du`-like view without the ASCII tree, use `-F, --flat`.
#### Human readable disk usage
-
#### Human readable and long view
-
### gitignore
-```txt
+```
-i, --no-ignore Do not respect .gitignore files
```
@@ -291,7 +292,7 @@ If `.gitignore` is respected any file that is ignored will not be included in th
### Hidden files
-```txt
+```
-., --hidden Show hidden files
--no-git Disable traversal of .git directory when traversing hidden files
```
@@ -303,7 +304,7 @@ If hidden files are ignored it will not be included in the total disk usage.
### Icons
-```txt
+```
-I, --icons Display file icons
```
@@ -321,7 +322,7 @@ this means that the font you are using doesn't include the relevant glyphs. To r
Directories are fully traversed by default. To limit the maximum depth:
-```txt
+```
-L, --level Maximum depth to display
```
@@ -331,7 +332,7 @@ Limiting the maximum depth to display will not affect the total disk usage repor
Sometimes empty directories may appear in the output. To remove them:
-```txt
+```
-P, --prune Remove empty directories from output
```
@@ -339,14 +340,14 @@ Sometimes empty directories may appear in the output. To remove them:
Various sorting methods are provided:
-```txt
+```
-s, --sort Sort-order to display directory content [default: size] [possible values: name, size, size-rev]
- --dirs-first Sort directories above files
+ --dir-order Sort directories before or after all other file types [default: none] [possible values: none, first, last]
```
-To ensure that directories appear before all other file-types:
+To add extra granularity to how directories are sorted relative to other file-types, use `--dir-order`:
-```txt
+```
--dir-order
Sort directories before or after all other file types
@@ -362,7 +363,7 @@ To ensure that directories appear before all other file-types:
You output only directories with:
-```txt
+```
--dirs-only Only print directories
```
@@ -372,7 +373,7 @@ This will not affect total disk usage.
Unix file permissions as well as metadata associated with directory entries can be shown using the following:
-```txt
+```
-l, --long Show extended metadata and attributes
--octal Show permissions in numeric octal format instead of symbolic
--time Which kind of timestamp to use; modified by default [possible values: created, accessed, modified]
@@ -383,12 +384,11 @@ Unix file permissions as well as metadata associated with directory entries can
The columns shown in the order of left to right are:
-
-* inode number
-* [permissions](https://en.wikipedia.org/wiki/File-system_permissions#Notation_of_traditional_Unix_permissions)
-* The number of hardlinks of the underlying inode
-* The number of blocks allocated to that particular file
-* The date the file was last modified (or created or last accessed)
+ * inode number
+ * [permissions](https://en.wikipedia.org/wiki/File-system_permissions#Notation_of_traditional_Unix_permissions)
+ * The number of hardlinks of the underlying inode
+ * The number of blocks allocated to that particular file
+ * The date the file was last modified (or created or last accessed)
File permissions are currently not supported for Windows but will be sometime in the near future.
@@ -399,9 +399,10 @@ attributes will not be supported.
Searching for a particular file using a regular expression or glob is supported using the following:
-```txt
--p, --pattern Regular expression (or glob if '--glob' is used) used to match files
- --glob Enables glob based searching [default: none] [possible values: none, sensitive, insensitive]
+```
+-p, --pattern Regular expression (or glob if '--glob' or '--iglob' is used) used to match files
+ --glob Enables glob based searching
+ --iglob Enables case-insensitive glob based searching
-t, --file-type Restrict regex or glob search to a particular file-type [possible values: file, dir, link]
```
@@ -413,9 +414,8 @@ Lastly, when applying a regular expression or glob to directories, off its desce
If you desire to only show directories you may use `--dirs-only`.
References:
-
-* [Globbing rules](https://git-scm.com/docs/gitignore#_pattern_format)
-* [Regular expressions](https://docs.rs/regex/latest/regex/#syntax)
+ * [Globbing rules](https://git-scm.com/docs/gitignore#_pattern_format)
+ * [Regular expressions](https://docs.rs/regex/latest/regex/#syntax)
### Truncating output
@@ -427,7 +427,7 @@ In instances where the output does not fit the terminal emulator's window, the o
In these situations the following may be used:
-```txt
+```
--truncate Truncate output to fit terminal emulator window
```
@@ -438,15 +438,14 @@ In these situations the following may be used:
### Redirecting output and colorization
If you wish to force a colorless output the following may be used:
-
-```txt
+```
-C none Print plainly without ANSI escapes
```
Colorization is also turned off if the output is redirected to something that is not a tty. If you wish to preserve the ANSI escape sequences (e.g.
preserve the colors as in the case of piping) the following may be used:
-```txt
+```
-C, forced Turn on colorization always
```
@@ -462,7 +461,7 @@ preserve the colors as in the case of piping) the following may be used:
The amount of threads used by `erdtree` can be adjusted with the following:
-```txt
+```
-T, --threads Number of threads to use [default: 3]
```
@@ -483,9 +482,9 @@ For empirical data on the subject checkout [this article](https://pkolaczk.githu
`--completions` is used to generate auto-completions for common shells so that the `tab` key can attempt to complete your command or give you hints; where you place the output highly depends on your shell as well as your setup. In my environment where I use `zshell` with `oh-my-zsh`, I would install completions like so:
-```sh
-et --completions zsh > ~/.oh-my-zsh/completions/_erd
-source ~/.zshrc
+```
+$ et --completions zsh > ~/.oh-my-zsh/completions/_erd
+$ source ~/.zshrc
```
## Rules for contributing
@@ -551,4 +550,4 @@ _Q: Why is there no mention of this project being blazingly fast or written in R
A: Okay fine. `erdtree` is written in Rust and is blazingly fast.
-![failed to load picture](https://i.redd.it/t7ns9qtb5gh81.jpg)
+