This release packs an incredibly useful new sub-command called dua clean [--depth N],
to automatically and efficiently find typical build products that you may want to delete,
for Rust and Zig and Node for now.
Also, when deleting entries, the TUI does not block anymore, but shows the decreasing number
of bytes as files are deleted, until the marked entry finally disappers. The TUI can still be
used then, albeit in read-only mode.
Oh, and it also got faster on macOS when there are folders with a lot of files, when it will
switch aways from bulk-reads to multi-threaded stat calls instead, which in my case led to
a 2.5x speedup.
New Features
-
add Git-aware dua clean and background deletion
This commit was mostly rubber-stamped, but tested for a week or so before that.
By now it's fair to accept thatduais in "tool that needs to work, without
needing to be very familiar with how it works" territory, while I still look
at the code at least but without the requirement to understand it all.Add
dua clean [--depth N] [DIRECTORY]...to discover disposable build
artifacts and caches, size accepted candidates, and offer them in a dedicated
cleanup hub. Keep the TUI responsive during scanning, deletion, and trashing.Discovery and safety
- Search directory entries and types before collecting size metadata. Recognize
Node dependencies, Python caches and virtual environments, Cargo build output,
and Zig caches and output. Require project markers for ambiguous names. - In Git repositories, require expendable ignore matches and reject tracked
contents, conflict stages, gitlinks, and sparse ancestors. Consult HEAD when
the index is absent and reject candidates when validation fails. - Reject nested repositories, case variants of Git markers, unreadable contents,
excluded descendants, and disallowed filesystem boundaries. - Feed discovered roots into dua-core's running walker within the configured
thread budget. Bound active candidates and publish each independently after
sizing and validation; commit hardlink/APFS accounting only on acceptance. - Search without a depth limit by default;
--depthbounds discovery. Support
traversal filters and--once, with no snapshot import/export or parent
scanning in clean mode.
Cleanup hub and browsing
- Title the hub with its input directories, group siblings and contained
candidates, and keep rows in largest-first order as scan results arrive. - Open groups as scoped views of existing candidate nodes. Reuse ordinary
sorting, glob search, annotations, navigation, and marking within the group;
keep group membership and controls local to the hub. - Group marks target actual candidates. Complete partial marks and toggle fully
marked groups off, preserving the real parent and unrelated contents. - Refresh recorded candidates without widening their deletion scope. Revalidate
whole candidates with their original discovery roots, restore browser/search
positions, and clear stale marks before tree indices are reused.
Background deletion
- Run deletion and trash work off the main thread, updating remaining bytes in
the tree, mark pane, and progress message about once per second. - Allow navigation, search, sorting, pane controls, and suspend/resume while
freezing marks and blocking further filesystem actions until the batch ends. - Preserve bounded filesystem concurrency, parallel file removal, and removal
of child directories before parents. Batch tree updates using scanned sizes
without double-counting overlapping marks or completed subtrees. - Keep failed entries with their remaining sizes and errors. On quit, cancel
pending work, apply in-flight results, and join workers. On event-loop failure,
cancel and disconnect events before joining. Trash progress advances when
each native trash call returns.
- Search directory entries and types before collecting size metadata. Recognize
-
minimize right-hand panels with ]
A very quick review, but one that showed that the GUI probably shouldn't get more complicated.
Or else it would be batter with more of a layout system than what it has now - manual layout.Behavior
Add a configurable
toggle_right_panesaction, defaulting to], that
minimizes or restores the shared Help and Marked sidebar. Minimized panes
display their translated names vertically with a blank column on each side:
three columns for single-width labels and four for double-width labels.
The main list uses the remaining terminal width.- Keep Help and Marked stacked when both exist, preserving their contents.
- Return focus to the main list on collapse and skip minimized panes with
Tab. Restoring with]keeps focus in the main list;?restores and
focuses Help without resetting its scroll position. - Keep marks and quit protection intact. Do not dispatch deletion actions
to a minimized Mark pane, and preserve literal brackets in search input. - Retain the minimized preference for the session, including while marking
more entries or temporarily having no right-hand panes. With no panes,
]is a no-op and the sidebar consumes no space. - Advertise
toggle-collapse = ]on the bottom border of each unfocused,
expanded Help or Mark pane, using the configured key and translated label.
Hide the hint during search input, when disabled, or when it cannot fit
between the border corners.
-
add directory_suffix option for directory markers
Keep the ncdu-style leading slash by default and render a trailing slash when
directory_suffix = truein the configuration. -
localize the interactive interface
Translate the remaining interactive panes, status messages, progress text,
prompts, errors, and notifications for every supported locale. Detect the
session language once and keep application, command, key, path, unit, Git-Glob,
and mtime names unchanged, while using compact locale-specific action labels
where they fit better. -
add German help translation
Add de locale detection and a complete German translation for the interactive
help pane, with documentation.Regression coverage verifies de_DE.UTF-8 and de selection plus English fallback for de_DE.ISO-8859-1.
-
add Simplified Chinese help translation
Add zh locale detection and a complete Simplified Chinese translation for the interactive help pane, with documentation.Regression coverage verifies zh_CN.UTF-8 and zh selection plus English fallback for zh_CN.GB18030.
Validated with: cargo test interactive::widgets::i18n::tests
-
add Korean help translation
Add Korean locale detection and a complete Korean translation for the interactive help pane. Generalize the existing UTF-8 locale parser so supported language codes share one path, while preserving English fallback for non-UTF-8 locales.\n\nRegression: ko_KR.UTF-8 and ko now select Korean; ko_KR.EUC-KR falls back to English.\n\nValidated with: cargo test interactive::widgets::i18n::tests -
repaint screen with Ctrl-L
Interactive sessions had no way to recover when terminal contents were corrupted
because unchanged frames produce no backend writes.Add a configurable Ctrl-L repaint action. It clears the backend directly
to avoid Terminal::clear's cursor-position query racing the input thread,
invalidates Ratatui's cached frame, and redraws through the normal event path. -
configure flamegraph SVG rendering
- Add palette, width, minimum-frame-width, title, and inverted-layout flags.
- Label generated graphs in disk-usage terms with byte counts and paths.
- Validate rendering arguments and exercise them in parser and end-to-end tests.
-
add
stacksandflamegraphcommandsSummary
- Promote folded output previously at
dua aggregate --stacksto the first-classdua stackscommand - Add
dua flamegraph, backed by Inferno, with temporary opening by default and--outputfor file-only output. - Keep
aggregate --stackas a hidden compatibility path and limit the new commands to relevant traversal flags.
- Promote folded output previously at
Bug Fixes
-
prevent deletion during scans
Deleting a directory while a scan was active could leave queued traversal
events referring to removed nodes, aborting dua i with InvalidIndex.Reject delete and trash actions while a scan is active, retaining marked
entries and showing "Traversal already running" so the user can retry
afterward. Deletion already blocks the event loop, preventing new scans
until it finishes. -
keep Traditional Chinese locales in English
Restrict the Simplified Chinese help table to bare zh, zh_CN, zh_SG, and zh_Hans while retaining English fallback for zh_TW, zh_HK, zh_MO, and zh_Hant.This addresses the post-commit review finding for 7b5e8e4.
Validated with: cargo test interactive::widgets::i18n::tests
Performance
-
parallelize I/O-bound macOS directory scans
This was an issue I encountered on APFS, a directory created by rustc with
more than 1m files in it. In that case, bulk reading is slow (while efficient),
and it turned out to be better to detect this and switch over to stat-based traversal.While looking at the filesystem probing code more closely (and how it's not dependent
on CPU performance by differntiating wall time from kernel time), I basically
rubber-stamped all the other code. Too much to look at, too foreign by now.
But it did look cleaned up, so 👍.The reported target-directory scan left one worker waiting inside
getattrlistbulkat about 15% of a CPU core. Native directory collection also
held an entire parent directory before publishing entries and child jobs.Probe at most two initial bulk buffers before publishing them. Compare
calling-thread user and kernel CPU time with elapsed time, and select the
existing parallel stat queue when both refills spend more time waiting than
executing. Reopen through ordinary enumeration only after that decision,
discarding the unpublished probe to avoid mixed cursors or duplicate entries.
Keep bulk reads when the probe is CPU-bound. The initial probe deliberately
does not adapt to later cache changes.Share streaming native traversal between ordering modes, preserve parent
ordering and APFS metadata, and bound queued metadata jobs by processing
new batches inline when the queue fills.Regression coverage checks scale-independent timing decisions, bounded
probing and metadata backlogs, streamed child jobs, parent ordering, and
stat/native parity for clones, resource forks, hard links and symlinks.
The timing test failed against the provisional fixed latency policy; the
queue-bound test failed without backpressure. -
preallocate snapshot v2 imports
Snapshot V2 prefixes the record stream with the total node count and native
path-name bytes. Interactive imports use them for exact reservations while V1
remains readable and declared requirements are validated.~/devbenchmarkdua i --import SNAPSHOT --once, release builds; one frozen V1 traversal converted to V2 for identical contents.Metric V1 V2 Change Median peak RSS (5 runs) 369,868,800 B 230,473,728 B -37.7% Mean wall time (20 runs) 430.5 ± 1.8 ms 438.1 ± 2.8 ms +1.8% Compressed snapshot size 38,215,358 B 38,215,404 B +46 B
Performance (BREAKING)
-
avoid unnecessary metadata during deletion
Deletion needs entry types, but every walk collected full sizes, timestamps,
allocation information, and file identities. AddOptions::skip_metadataand
use directory-entry types without extra metadata lookups when available.
macOS and Windows use standard enumeration for this mode; Windows roots
query only attribute/tag information. Keep the native metadata readers for
ordinary scans and preserve Windows verbatim-path handling.Drop per-entry deletion byte accounting. Successful removals use the existing
scanned total; partial failures retain entry/error counts and display unknown
bytes instead of collecting metadata solely for that notification.Local macOS/APFS release medians showed 0-11.5% lower deletion time, with
wide-directory traversal up to 40% shorter; gains vary with tree shape.
Commit Statistics
- 26 commits contributed to the release over the course of 13 calendar days.
- 13 days passed between releases.
- 15 commits were understood as conventional.
- 1 unique issue was worked on: #392
Commit Details
view details
- #392
- Repaint screen with Ctrl-L (8a656e8)
- Uncategorized
- Merge pull request #399 from Byron/dua-clean (ed276c2)
- Add Git-aware dua clean and background deletion (0661576)
- Merge pull request #401 from Byron/faster-bulk-traversal (46b8556)
- Parallelize I/O-bound macOS directory scans (249bdf3)
- Merge pull request #400 from Byron/hide-panels (93c0ca3)
- Minimize right-hand panels with ] (b15735b)
- Merge pull request #398 from Byron/fix-panic (6e81dcf)
- Prevent deletion during scans (73f27e8)
- Merge pull request #397 from Byron/speed-up-deletions (97211e6)
- Avoid unnecessary metadata during deletion (f643c74)
- Merge pull request #396 from Byron/fix-directory-display (115f7bb)
- Add directory_suffix option for directory markers (38d30db)
- Merge pull request #394 from Byron/languages (74f88f0)
- Localize the interactive interface (c1f5dda)
- Add German help translation (5b5e83f)
- Keep Traditional Chinese locales in English (4979276)
- Add Simplified Chinese help translation (7b5e8e4)
- Add Korean help translation (793ab72)
- Merge pull request #393 from Byron/repaint (8a7dfb8)
- Merge pull request #391 from Byron/flamegraph (48109fe)
- Configure flamegraph SVG rendering (3876367)
- Add
stacksandflamegraphcommands (6f797d6) - Merge pull request #390 from Byron/snapshot-v2 (ebf4cff)
- Preallocate snapshot v2 imports (de6c3c3)
- Merge pull request #385 from Byron/io-format (3343158)