Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f275703

Browse files
committed
refactor
- more docs - pass Config instead of single value - use `serde` instead of manual `toml` handling - Add missing docs (as something very much unrelated) - print configuration location - add `dua config edit` - default ESC setting to true
1 parent fd3468b commit f275703

18 files changed

Lines changed: 407 additions & 108 deletions

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ log = "0.4.20"
6363
log-panics = { version = "2", features = ["with-backtrace"] }
6464
crossbeam = "0.8"
6565
toml = "0.8"
66+
serde = { version = "1.0", features = ["derive"] }
6667
dirs = "6"
68+
shlex = "1.3.0"
6769

6870
[[bin]]
6971
name = "dua"
@@ -82,3 +84,6 @@ build-override = { opt-level = 3 }
8284

8385
[dev-dependencies]
8486
pretty_assertions = "1.0.0"
87+
88+
[lints.clippy]
89+
all = "deny"

README.md

Lines changed: 62 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
### Installation
1010

11-
### Binary Release
11+
### Binary Release
1212

1313
#### MacOS
1414

@@ -18,12 +18,14 @@ curl -LSfs https://raw.githubusercontent.com/Byron/dua-cli/master/ci/install.sh
1818
```
1919

2020
#### MacOS via [MacPorts](https://www.macports.org):
21+
2122
```sh
2223
sudo port selfupdate
2324
sudo port install dua-cli
2425
```
2526

2627
#### MacOS via [Homebrew](https://brew.sh)
28+
2729
```sh
2830
brew update
2931
brew install dua-cli
@@ -39,11 +41,13 @@ curl -LSfs https://raw.githubusercontent.com/Byron/dua-cli/master/ci/install.sh
3941
```
4042

4143
#### Windows via [Scoop](https://scoop.sh/)
44+
4245
```sh
4346
scoop install dua
4447
```
4548

4649
#### Windows via [WinGet](https://learn.microsoft.com/en-us/windows/package-manager/winget/)
50+
4751
```sh
4852
winget install Byron.dua-cli
4953
```
@@ -55,9 +59,11 @@ See the [releases section][releases] for manual installation of a binary, pre-bu
5559
[releases]: https://github.com/Byron/dua-cli/releases
5660

5761
#### Cargo
62+
5863
Via `cargo`, which can be obtained using [rustup][rustup]
5964

6065
For _Unix_
66+
6167
```
6268
cargo install dua-cli
6369
@@ -69,32 +75,37 @@ cargo install dua-cli --no-default-features --features tui-crossplatform
6975
```
7076

7177
For _Windows_, nightly features are currently required.
78+
7279
```
7380
cargo +nightly install dua-cli
7481
```
7582

7683
#### VoidLinux
84+
7785
Via `xbps` on your VoidLinux system.
7886

7987
```
8088
xbps-install dua-cli
8189
```
8290

8391
#### Fedora
92+
8493
Via `dnf` on your Fedora system.
8594

8695
```
8796
sudo dnf install dua-cli
8897
```
8998

9099
#### Arch Linux
100+
91101
Via `pacman` on your ArchLinux system.
92102

93103
```
94104
sudo pacman -S dua-cli
95105
```
96106

97107
#### NixOS
108+
98109
https://search.nixos.org/packages?query=dua
99110

100111
Nix-shell (temporary)
@@ -112,6 +123,7 @@ NixOS configuration
112123
```
113124

114125
#### NetBSD
126+
115127
Via `pkgin` on your NetBSD system.
116128

117129
```
@@ -137,9 +149,11 @@ cargo +nightly install dua-cli
137149
#### x-cmd
138150

139151
[x-cmd](https://www.x-cmd.com/) is a **toolbox for Posix Shell**, offering a lightweight package manager built using shell and awk.
152+
140153
```sh
141154
x env use dua
142155
```
156+
143157
- Additionally, the [`x dua ...`](https://www.x-cmd.com/pkg/dua#dua) command is available, which automatically installs `dua` without affecting the environment, such as not modifying the `PATH` variable.
144158

145159
### Usage
@@ -167,6 +181,26 @@ dua i
167181
dua interactive
168182
```
169183

184+
### Configuration
185+
186+
`dua` can read an optional configuration file from your OS-specific config directory:
187+
188+
1. Linux/Unix: `$XDG_CONFIG_HOME/dua-cli/config.toml` (or the platform default config dir)
189+
2. macOS: `~/Library/Application Support/dua-cli/config.toml`
190+
3. Windows: `%APPDATA%\dua-cli\config.toml`
191+
192+
If the file is missing, defaults are used.
193+
194+
Currently supported options:
195+
196+
```toml
197+
[keys]
198+
# If true, pressing <Esc> in the main pane navigates to the parent directory.
199+
# If true (default), pressing <Esc> in the main pane ascends to the parent directory.
200+
# If false, <Esc> follows the default quit behavior.
201+
esc_navigates_back = true
202+
```
203+
170204
### Development
171205

172206
Please note that all the following assumes a unix system. On Windows, the linux subsystem should do the job.
@@ -197,39 +231,39 @@ Thanks to [jwalk][jwalk], all there was left to do is to write a command-line in
197231

198232
### Limitations
199233

200-
* Does not show symbolic links at all if no path is provided when invoking `dua`
201-
* in an effort to skip symbolic links, for now there are pruned and are not used as a root. Symbolic links will be shown if they
234+
- Does not show symbolic links at all if no path is provided when invoking `dua`
235+
- in an effort to skip symbolic links, for now there are pruned and are not used as a root. Symbolic links will be shown if they
202236
are not a traversal root, but will not be followed.
203-
* Interactive mode only looks good in dark terminals (see [this issue](https://github.com/Byron/dua-cli/issues/13))
204-
* _easy fix_: file names in main window are not truncated if too large. They are cut off on the right.
205-
* There are plenty of examples in `tests/fixtures` which don't render correctly in interactive mode.
237+
- Interactive mode only looks good in dark terminals (see [this issue](https://github.com/Byron/dua-cli/issues/13))
238+
- _easy fix_: file names in main window are not truncated if too large. They are cut off on the right.
239+
- There are plenty of examples in `tests/fixtures` which don't render correctly in interactive mode.
206240
This can be due to graphemes not interpreted correctly. With Chinese characters for instance,
207241
column sizes are not correctly computed, leading to certain columns not being shown.
208242
In other cases, the terminal gets things wrong - I use alacritty, and with certain characters it
209243
performs worse than, say iTerm3.
210244
See https://github.com/minimaxir/big-list-of-naughty-strings/blob/master/blns.txt for the source.
211-
* In interactive mode, you will need about 60MB of memory for 1 million entries in the graph.
212-
* In interactive mode, the maximum amount of files is limited to 2^32 - 1 (`u32::max_value() - 1`) entries.
213-
* One node is used as to 'virtual' root
214-
* The actual amount of nodes stored might be lower, as there might be more edges than nodes, which are also limited by a `u32` (I guess)
215-
* The limitation is imposed by the underlying [`petgraph`][petgraph] crate, which declares it as `unsafe` to use u64 for instance.
216-
* It's possibly *UB* when that limit is reached, however, it was never observed either.
217-
218-
### Similar Programs
219-
220-
* **CLI:**
221-
* `du`
222-
* [`dust`](https://github.com/bootandy/dust)
223-
* [`dutree`](https://github.com/nachoparker/dutree)
224-
* [`pdu`](https://github.com/KSXGitHub/parallel-disk-usage)
225-
* **TUI:**
226-
* [`ncdu`](https://dev.yorhel.nl/ncdu)
227-
* [`gdu`](https://github.com/dundee/gdu)
228-
* [`godu`](https://github.com/viktomas/godu)
229-
* **GUI:**
230-
* [GNOME's Disk Usage Analyzer, a.k.a. `baobab`](https://wiki.gnome.org/action/show/Apps/DiskUsageAnalyzer)
231-
* [Filelight](https://apps.kde.org/filelight/)
232-
245+
- In interactive mode, you will need about 60MB of memory for 1 million entries in the graph.
246+
- In interactive mode, the maximum amount of files is limited to 2^32 - 1 (`u32::max_value() - 1`) entries.
247+
- One node is used as to 'virtual' root
248+
- The actual amount of nodes stored might be lower, as there might be more edges than nodes, which are also limited by a `u32` (I guess)
249+
- The limitation is imposed by the underlying [`petgraph`][petgraph] crate, which declares it as `unsafe` to use u64 for instance.
250+
- It's possibly _UB_ when that limit is reached, however, it was never observed either.
251+
252+
### Similar Programs
253+
254+
- **CLI:**
255+
- `du`
256+
- [`dust`](https://github.com/bootandy/dust)
257+
- [`dutree`](https://github.com/nachoparker/dutree)
258+
- [`pdu`](https://github.com/KSXGitHub/parallel-disk-usage)
259+
- **TUI:**
260+
- [`ncdu`](https://dev.yorhel.nl/ncdu)
261+
- [`gdu`](https://github.com/dundee/gdu)
262+
- [`godu`](https://github.com/viktomas/godu)
263+
- **GUI:**
264+
- [GNOME's Disk Usage Analyzer, a.k.a. `baobab`](https://wiki.gnome.org/action/show/Apps/DiskUsageAnalyzer)
265+
- [Filelight](https://apps.kde.org/filelight/)
266+
233267
[petgraph]: https://crates.io/crates/petgraph
234268
[rustup]: https://rustup.rs/
235269
[jwalk]: https://crates.io/crates/jwalk

src/common.rs

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ use std::sync::atomic::{AtomicBool, Ordering};
88
use std::time::Duration;
99
use std::{fmt, path::Path};
1010

11-
pub fn get_entry_or_panic(tree: &Tree, node_idx: TreeIndex) -> &EntryData {
11+
/// Return the entry at `node_idx` or panic if the index is invalid for `tree`.
12+
pub(crate) fn get_entry_or_panic(tree: &Tree, node_idx: TreeIndex) -> &EntryData {
1213
tree.node_weight(node_idx)
1314
.expect("node should always be retrievable with valid index")
1415
}
@@ -37,6 +38,7 @@ pub enum ByteFormat {
3738
}
3839

3940
impl ByteFormat {
41+
/// Return the content width (without unit suffix) needed to display values in this format.
4042
pub fn width(self) -> usize {
4143
use ByteFormat::*;
4244
match self {
@@ -47,6 +49,7 @@ impl ByteFormat {
4749
_ => 10,
4850
}
4951
}
52+
/// Return the full width (value plus unit and separator) used by this format.
5053
pub fn total_width(self) -> usize {
5154
use ByteFormat::*;
5255
const THE_SPACE_BETWEEN_UNIT_AND_NUMBER: usize = 1;
@@ -59,15 +62,17 @@ impl ByteFormat {
5962
}
6063
+ THE_SPACE_BETWEEN_UNIT_AND_NUMBER
6164
}
62-
pub fn display(self, bytes: u128) -> ByteFormatDisplay {
65+
/// Create a display adapter for `bytes` using this format.
66+
pub fn display(self, bytes: u128) -> impl fmt::Display {
6367
ByteFormatDisplay {
6468
format: self,
6569
bytes,
6670
}
6771
}
6872
}
6973

70-
pub struct ByteFormatDisplay {
74+
/// A lightweight display adapter created by [`ByteFormat::display`].
75+
struct ByteFormatDisplay {
7176
format: ByteFormat,
7277
bytes: u128,
7378
}
@@ -115,18 +120,23 @@ impl fmt::Display for ByteFormatDisplay {
115120
/// Identify the kind of sorting to apply during filesystem iteration
116121
#[derive(Clone)]
117122
pub enum TraversalSorting {
123+
/// Keep filesystem iteration order as provided by the walker.
118124
None,
125+
/// Sort entries alphabetically by file name during iteration.
119126
AlphabeticalByFileName,
120127
}
121128

122129
/// Throttle access to an optional `io::Write` to the specified `Duration`
123130
#[derive(Debug)]
124-
pub struct Throttle {
131+
pub(crate) struct Throttle {
125132
trigger: Arc<AtomicBool>,
126133
}
127134

128135
impl Throttle {
129-
pub fn new(duration: Duration, initial_sleep: Option<Duration>) -> Self {
136+
/// Create a new throttle that allows updates at most once per `duration`.
137+
///
138+
/// If `initial_sleep` is set, the first update is delayed by that amount.
139+
pub(crate) fn new(duration: Duration, initial_sleep: Option<Duration>) -> Self {
130140
let instance = Self {
131141
trigger: Default::default(),
132142
};
@@ -145,7 +155,8 @@ impl Throttle {
145155
instance
146156
}
147157

148-
pub fn throttled<F>(&self, f: F)
158+
/// Execute `f` only if the throttle currently allows an update.
159+
pub(crate) fn throttled<F>(&self, f: F)
149160
where
150161
F: FnOnce(),
151162
{
@@ -155,7 +166,7 @@ impl Throttle {
155166
}
156167

157168
/// Return `true` if we are not currently throttled.
158-
pub fn can_update(&self) -> bool {
169+
pub(crate) fn can_update(&self) -> bool {
159170
self.trigger.swap(false, Ordering::Relaxed)
160171
}
161172
}
@@ -166,17 +177,31 @@ pub struct WalkOptions {
166177
/// The amount of threads to use. Refer to [`WalkDir::num_threads()`](https://docs.rs/jwalk/0.4.0/jwalk/struct.WalkDir.html#method.num_threads)
167178
/// for more information.
168179
pub threads: usize,
180+
/// If `true`, count every hard-link occurrence independently.
169181
pub count_hard_links: bool,
182+
/// If `true`, use apparent size (`metadata.len()`), not allocated blocks on disk.
170183
pub apparent_size: bool,
184+
/// Sorting mode applied by the filesystem walker.
171185
pub sorting: TraversalSorting,
186+
/// If `false`, traversal is constrained to the root filesystem/device.
172187
pub cross_filesystems: bool,
188+
/// Canonicalized directories to skip from traversal.
173189
pub ignore_dirs: BTreeSet<PathBuf>,
174190
}
175191

176192
type WalkDir = jwalk::WalkDirGeneric<((), Option<Result<std::fs::Metadata, jwalk::Error>>)>;
177193

178194
impl WalkOptions {
179-
pub fn iter_from_path(&self, root: &Path, root_device_id: u64, skip_root: bool) -> WalkDir {
195+
/// Create an iterator over `root` honoring this walk configuration.
196+
///
197+
/// `root_device_id` is used to filter entries when `cross_filesystems == false`.
198+
/// If `skip_root` is `true`, the root directory itself is omitted from yielded entries.
199+
pub(crate) fn iter_from_path(
200+
&self,
201+
root: &Path,
202+
root_device_id: u64,
203+
skip_root: bool,
204+
) -> WalkDir {
180205
let ignore_dirs = self.ignore_dirs.clone();
181206
let cwd = std::env::current_dir().unwrap_or_else(|_| root.to_owned());
182207
WalkDir::new(root)
@@ -239,11 +264,17 @@ pub struct WalkResult {
239264
}
240265

241266
impl WalkResult {
267+
/// Convert traversal result into a process exit code.
268+
///
269+
/// Returns `0` if no I/O errors occurred, otherwise `1`.
242270
pub fn to_exit_code(&self) -> i32 {
243271
i32::from(self.num_errors > 0)
244272
}
245273
}
246274

275+
/// Canonicalize user-provided ignore directory paths.
276+
///
277+
/// Non-canonicalizable paths are ignored.
247278
pub fn canonicalize_ignore_dirs(ignore_dirs: &[PathBuf]) -> BTreeSet<PathBuf> {
248279
let dirs = ignore_dirs
249280
.iter()

0 commit comments

Comments
 (0)