dua-cli-2.34.0/.cargo_vcs_info.json0000644000000001361046102023000124620ustar { "git": { "sha1": "19df299c07d83b6dbe48edd7e7cdf7e9d1afdc51" }, "path_in_vcs": "" }dua-cli-2.34.0/CHANGELOG.md000064400000000000000000007417241046102023000130600ustar 00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## 2.34.0 (2026-02-20) This upcoming release improves day-to-day usability with a new configuration file. For users, the main additions are: - A persistent configuration file for `dua` with keyboard settings under `[keys]`. - A new `dua config edit` command to open the configuration in `$EDITOR`. - Automatic creation of the configuration directory/file with sensible defaults when editing for the first time. Configuration defaults and behavior in this release: - `keys.esc_navigates_back` now defaults to `true`. This is a change from previous versions where it was `false` implicitly. You are welcome to contribute more settings as you see fit. ### Chore - Replace simplelog with fern and jiff for timestamped logging Note that this changes the log format from 04:41:37 [INFO] to [2026-02-06 05:41:32.146 +01:00 INFO src/main.rs:55] ### New Features - add `dua` configuration file, with setting for ESC going back only. ### Bug Fixes - outdated link to NixOS package search Channel 23.11 was for Nov. 2023. This update removes explicitly specifying a channel in the query, defaulting to the current latest stable NixOS nixpkgs channel (at the time of writing `25.11` ### Refactor - remove crosstermion and tui-react dependencies ### Commit Statistics - 17 commits contributed to the release over the course of 45 calendar days. - 45 days passed between releases. - 4 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Merge pull request #320 from tonisives/feat/disable-esc ([`9d2fac5`](https://github.com/Byron/dua-cli/commit/9d2fac55c30d6bb02dfe2961de6183b7b607d6d4)) - Prepare changelog for upcoming release ([`9496afe`](https://github.com/Byron/dua-cli/commit/9496afe47e6832152282b65b903177f4ad0e12e4)) - Refactor ([`f275703`](https://github.com/Byron/dua-cli/commit/f2757037548f9765e2c8b5ee132fe3417e00cce8)) - Apply suggestions from Copilot code review ([`fd3468b`](https://github.com/Byron/dua-cli/commit/fd3468bcb226eef12bd8050c7cfae32b18f7f673)) - Add `dua` configuration file, with setting for ESC going back only. ([`c72cb52`](https://github.com/Byron/dua-cli/commit/c72cb529a6191aa76d180d3dff1af2c2bd29e31c)) - Merge pull request #318 from Byron/copilot/remove-crosstermion-tui-react ([`7480277`](https://github.com/Byron/dua-cli/commit/74802778a45c8b2f108566c712e3dd733f6ac0a9)) - Remove crosstermion and tui-react dependencies ([`a1aaaa5`](https://github.com/Byron/dua-cli/commit/a1aaaa59a5a1e7b4cee7affdb0ff4fb2f3da4fc3)) - Merge pull request #317 from musicinmybrain/no-atty ([`6c0203c`](https://github.com/Byron/dua-cli/commit/6c0203c5d3c6744949de92749944c57cf61ad2fc)) - Replace atty with standard-library functionality (since Rust 1.70) ([`31aaa0c`](https://github.com/Byron/dua-cli/commit/31aaa0cde6807ffb8351d07b9aa0e4899a128f39)) - Merge pull request #315 from Byron/copilot/switch-time-crate-to-jiff ([`017e716`](https://github.com/Byron/dua-cli/commit/017e716c100dd1d2154efe43bf4f5f8f69b7ce8f)) - Refactor ([`60812a2`](https://github.com/Byron/dua-cli/commit/60812a27b67e72e0170e2a0d15ecb4313096dfcd)) - Replace simplelog with fern and jiff for timestamped logging ([`3dc120f`](https://github.com/Byron/dua-cli/commit/3dc120fcf193945546ad62f91ae7792c4830c151)) - Merge pull request #314 from Byron/dependabot/cargo/time-0.3.47 ([`2cb64fb`](https://github.com/Byron/dua-cli/commit/2cb64fb28c9dbc51ca5e283aac3c2225cf8dd1ec)) - Bump time from 0.3.44 to 0.3.47 ([`5980a79`](https://github.com/Byron/dua-cli/commit/5980a79157a04644b907a932f9f92cb3c693a324)) - Merge pull request #313 from Quoteme/patch-1 ([`abe15b2`](https://github.com/Byron/dua-cli/commit/abe15b21eb1276bdc2893385b63c397386be3129)) - Outdated link to NixOS package search ([`c7def68`](https://github.com/Byron/dua-cli/commit/c7def68283362fae9e34e98bcf0e3f69a9427bf9)) - Cargo fmt ([`d8db05a`](https://github.com/Byron/dua-cli/commit/d8db05a5ec65412aceea259247cc438d7db220f6))
## 2.33.0 (2026-01-05) ### New Features - Add environment variable support for all global arguments - `DUA_THREADS` → `--threads` ### Commit Statistics - 11 commits contributed to the release over the course of 64 calendar days. - 69 days passed between releases. - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.33.0 ([`1799773`](https://github.com/Byron/dua-cli/commit/179977342a3becfd6bcb9a75cdc21078ed13d7b5)) - Merge pull request #309 from Byron/copilot/add-env-support-global-arguments ([`72f149c`](https://github.com/Byron/dua-cli/commit/72f149ce0aa2c88bad71d22d46b864a38362e10a)) - Add environment variable support for all global arguments ([`85c7c72`](https://github.com/Byron/dua-cli/commit/85c7c7218cbb70b0626f430afd03ed819387e9e2)) - Merge pull request #307 from Byron/copilot/mark-global-arguments-in-clap ([`a2973a6`](https://github.com/Byron/dua-cli/commit/a2973a655e9c33f08d17dcecde1f6ef6827f1182)) - Mark shared arguments as global for general accessibility ([`2f720cf`](https://github.com/Byron/dua-cli/commit/2f720cf5610c215dc4fbb7cd270fe055fd403b42)) - Merge pull request #300 from drkane/drkane-patch-1 ([`8570c15`](https://github.com/Byron/dua-cli/commit/8570c1543e3cd0983725f6e1938bf3e73442678a)) - Add winget instructions to readme - fixes issue #282 ([`ec159b6`](https://github.com/Byron/dua-cli/commit/ec159b63fe522b8e49f5e89a22cf8a5fcf5db55f)) - Merge pull request #298 from Byron/updates ([`4bb7ebd`](https://github.com/Byron/dua-cli/commit/4bb7ebd7028f378b3dda6a439403a35f9ce44318)) - Cargo update ([`1a38653`](https://github.com/Byron/dua-cli/commit/1a386532a4b2523ecb81c5d876130227ebd8bea9)) - Cargo fmt ([`38d985e`](https://github.com/Byron/dua-cli/commit/38d985eebb9c9a791524b7f7835dde01271827a7)) - Upgrade the rustc version and switch to edition 2024 ([`ccd0b74`](https://github.com/Byron/dua-cli/commit/ccd0b74b92a21fef65b8ea94667100c71183ebe9))
DUA_FORMAT → --formatDUA_APPARENT_SIZE → --apparent-sizeDUA_COUNT_HARD_LINKS → --count-hard-linksDUA_STAY_ON_FILESYSTEM → --stay-on-filesystemDUA_IGNORE_DIRS → --ignore-dirsDUA_LOG_FILE → --log-fileAdded global = true to all arguments shared between aggregate and interactive subcommandsRemoved duplicate input fields from Interactive and Aggregate subcommandsUpdated main.rs to use opt.input instead of subcommand-specific inputGlobal arguments now work with both subcommands and can be specified before or after the subcommand ## 2.32.2 (2025-10-28) ### Bug Fixes - don't let 'q' quit instantly if it's still collecting files. ### Commit Statistics - 2 commits contributed to the release. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.32.2 ([`6e91054`](https://github.com/Byron/dua-cli/commit/6e91054b5236c567fdf4bf8b75f74c4934f2a6c6)) - Don't let 'q' quit instantly if it's still collecting files. ([`847af46`](https://github.com/Byron/dua-cli/commit/847af46ba643c53b8d5aa7a9a3abd9ff37032311))
## 2.32.1 (2025-10-28) 'q' to quit is now more usable as it will insta-quit if the traversal took less than 10s and if nothing is still marked for deletion. This makes it easy to use in 'quick-view' scenarios. ### Bug Fixes - instantly quit when no items marked for deletion ### Commit Statistics - 7 commits contributed to the release. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.32.1 ([`d55602a`](https://github.com/Byron/dua-cli/commit/d55602a515e9c888243fedbc2f07f54bb2d2cc1c)) - Prepare next release changelog ([`fb8571f`](https://github.com/Byron/dua-cli/commit/fb8571fec263a27a03700dacdf1d1f51e0e844e7)) - Merge pull request #297 from Byron/copilot/fix-instant-quit-on-q ([`938ae33`](https://github.com/Byron/dua-cli/commit/938ae33195498ab3451d83dac90eeb80302b0d12)) - Only quit immediately if the traversal didn't take too long. ([`7f27170`](https://github.com/Byron/dua-cli/commit/7f271701240d89799b3dd6a8f95cc613dd5c1340)) - Update dependencies ([`d0f66d6`](https://github.com/Byron/dua-cli/commit/d0f66d6dcb859c4a27d30dc74da60eda1b5fb758)) - Refactor ([`b710cb1`](https://github.com/Byron/dua-cli/commit/b710cb164615b6c68416ce8bb882e41ea12bd0df)) - Instantly quit when no items marked for deletion ([`d769de9`](https://github.com/Byron/dua-cli/commit/d769de92b7abc842dab45141750e809b1141ba26))
## 2.32.0 (2025-09-15) ### New Features - `Ctrl+f` in the glob prompt now toggles the mode from case-insensitive to sensitive. ### Commit Statistics - 5 commits contributed to the release over the course of 43 calendar days. - 43 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.32.0 ([`3f364c1`](https://github.com/Byron/dua-cli/commit/3f364c1c44a7d195eacda453d4da23c3c60fc632)) - Merge pull request #293 from Byron/copilot/fix-2a5bb691-5ca0-4cf5-af1c-895f4fcb1f06 ([`91bc45d`](https://github.com/Byron/dua-cli/commit/91bc45da799e7bd41d75f71a67091c6537de7ef1)) - `Ctrl+f` in the glob prompt now toggles the mode from case-insensitive to sensitive. ([`bbe368f`](https://github.com/Byron/dua-cli/commit/bbe368f3c33cf58625e0f2a24f198ee8a6f836a6)) - Implement case-sensitive glob search with '^f' shortcut ([`32ab50f`](https://github.com/Byron/dua-cli/commit/32ab50f5b91cb9e4b4e4fa342d6a36adc944c14e)) - See if the windows-2022 image will work for us. ([`7abf86a`](https://github.com/Byron/dua-cli/commit/7abf86a7c214452425bacb8290b0436119f795da))
## 2.31.0 (2025-08-02) This release prominently adds a prompt that shows before quitting the app. When you pressed esc or q, the status bar will show the prompt first. To really quit, you need to press esc or q again. You can also cancel the quit operation by pressing any key else. Meanwhile, ctrl-c still quits the app directly since it's a combination key. That way, `dua` will not cause users to accidentally quit the app when they only want to dismiss some other panels. It's especially frustrating if the scan took a long time ### New Features - prompt before quitting This release prominently adds a prompt that shows before quitting the app. When you pressed esc or q, the status bar will show the prompt first. To really quit, you need to press esc or q again. You can also cancel the quit operation by pressing any key else. Meanwhile, ctrl-c still quits the app directly since it's a combination key. That way, `dua` will not cause users to accidentally quit the app when they only want to dismiss some other panels. It's especially frustrating if the scan took a long time. ### Commit Statistics - 12 commits contributed to the release. - 83 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Thanks Clippy [Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.31.0 ([`5daa8d5`](https://github.com/Byron/dua-cli/commit/5daa8d5661eef1269c6f71fe0a20da9f3f1fefaf)) - Bump minor version and add changelog notes ([`d238dbb`](https://github.com/Byron/dua-cli/commit/d238dbb12b8491393a41ff5da425497f04c343d0)) - Update dependencies ([`39ca5e6`](https://github.com/Byron/dua-cli/commit/39ca5e616d28765a79a619015c4f259b82f1ed5f)) - Prompt before quitting ([`f3c9bf6`](https://github.com/Byron/dua-cli/commit/f3c9bf65b97ac029d444e32fe23f5976b0c480b2)) - Prompt user before quitting ([`b096939`](https://github.com/Byron/dua-cli/commit/b09693973a34152a15f2dd599ff48ffbd1e8965e)) - Re-introduce io::ErrorKind matching. ([`f93f120`](https://github.com/Byron/dua-cli/commit/f93f1205fa4fea33016a66645c8b5ec5c25a4f5c)) - Merge pull request #288 from fgimian/completions ([`1b7f535`](https://github.com/Byron/dua-cli/commit/1b7f535eb25be4fba4f64efb21efdd74895dbce0)) - Thanks clippy ([`f983e60`](https://github.com/Byron/dua-cli/commit/f983e6080371ed190ae1b3884e4034812d3d528c)) - Refactor ([`a0f78b2`](https://github.com/Byron/dua-cli/commit/a0f78b2a9d35097f65d3debb0eeffae8dc15e893)) - Add the ability to generate shell completions ([`e919541`](https://github.com/Byron/dua-cli/commit/e9195412c08e47fc518b69b57116754fa2fa5a3e)) - Merge pull request #285 from kianmeng/fix-typos ([`63b129b`](https://github.com/Byron/dua-cli/commit/63b129b1addbac7f4b238529875d88062ab68dfb)) - Fix typos ([`d9d643e`](https://github.com/Byron/dua-cli/commit/d9d643e63dc7996d88eb54a9dc8bafbf7198c69f))
## 2.30.1 (2025-05-10) In this release, the size of directories is also taken into consideration, for more realistic sizes similar to what `du` does. ### Commit Statistics - 7 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Thanks Clippy [Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.30.1 ([`ebf906a`](https://github.com/Byron/dua-cli/commit/ebf906af390c330aa5983ba0699127a6eb0e16d5)) - Prepare changelog for next release. ([`4ed0acf`](https://github.com/Byron/dua-cli/commit/4ed0acfe47836a7dd0dd2e22998c7ea227555fe2)) - Merge pull request #284 from joehasson/feat/include-directory-inodes-in-size-calculations ([`b5b411b`](https://github.com/Byron/dua-cli/commit/b5b411b2757d61ebdd64f2254cac002234ed1d5d)) - Include directory inode in directory size aggregation ([`a93b28e`](https://github.com/Byron/dua-cli/commit/a93b28ead02714bb80cda296e4b4ad2a1248ba0e)) - Merge pull request #283 from Byron/dependabot/cargo/crossbeam-channel-0.5.15 ([`ca6122f`](https://github.com/Byron/dua-cli/commit/ca6122f914d0626a5f51ff0986bcb6a1ff98e9ec)) - Thanks clippy ([`49bbd2c`](https://github.com/Byron/dua-cli/commit/49bbd2c05d091ef344feb83e6a25d825267025e7)) - Bump crossbeam-channel from 0.5.13 to 0.5.15 ([`af3f3fe`](https://github.com/Byron/dua-cli/commit/af3f3fed990be166595b0cb5133272d2091483e8))
## 2.30.0 (2025-01-27) ### New Features - allow sorting by name in interactive mode ### Bug Fixes - formatting in src/interactive/app/handlers.rs - on MacOS use only 3 threads by default. Otherwise, it would get very slow and the difference is enormous. 16 threads for example take 4.1s on a workload, whereas this only takes 550ms with 3 threads. ### Style - simplify some statements for readability ### Commit Statistics - 10 commits contributed to the release over the course of 55 calendar days. - 84 days passed between releases. - 4 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Thanks Clippy [Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.30.0 ([`b5377bc`](https://github.com/Byron/dua-cli/commit/b5377bcf07ced300ab1493ed969999ac58825e83)) - Merge pull request #275 from joehasson/feat/interactive-mode-sort-by-name ([`364f732`](https://github.com/Byron/dua-cli/commit/364f73206dc89277496486da6a6b462fb38e1262)) - Thanks clippy ([`092a6c5`](https://github.com/Byron/dua-cli/commit/092a6c53cdd0b01f4041f7a79c736b27a1c2a3ce)) - Allow sorting by name in interactive mode ([`73224e6`](https://github.com/Byron/dua-cli/commit/73224e63bc21d1ffa416b3e685a95c04afb72657)) - Merge pull request #274 from musicinmybrain/petgraph0.7 ([`14a276e`](https://github.com/Byron/dua-cli/commit/14a276eb513cec833f5137670ff55f1391d1b4d7)) - Update petgraph to 0.7 ([`b83a2f6`](https://github.com/Byron/dua-cli/commit/b83a2f6dc348f696d7f675e1266ecc2527382d8e)) - Merge pull request #271 from hamirmahal/style/simplify-some-statements-for-readability ([`3bc25bd`](https://github.com/Byron/dua-cli/commit/3bc25bd5e337bdebce706a89e0fe4227d9997b9a)) - Formatting in src/interactive/app/handlers.rs ([`0a4d09e`](https://github.com/Byron/dua-cli/commit/0a4d09eae898c80f8f81bbf8f8c652883d9424e7)) - Simplify some statements for readability ([`c1dc1b2`](https://github.com/Byron/dua-cli/commit/c1dc1b26735279e976d36597bfe45eb3557458fe)) - On MacOS use only 3 threads by default. ([`8933be4`](https://github.com/Byron/dua-cli/commit/8933be4fa8a801a7f79d994d735eee1105bd30ba))
## 2.29.4 (2024-11-03) ### Bug Fixes - enable "chrono" in `trash` crate This hopefully adds deletion dates to trashed files. ### Other - update actions/upload-artifact to v4 The release workflow failed because actions/upload-artifact@v1 doesn't work anymore. ### Commit Statistics - 4 commits contributed to the release. - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - 1 unique issue was worked on: [#268](https://github.com/Byron/dua-cli/issues/268) ### Commit Details
view details * **[#268](https://github.com/Byron/dua-cli/issues/268)** - Enable "chrono" in `trash` crate ([`4efb5d0`](https://github.com/Byron/dua-cli/commit/4efb5d0cd46c00f13d06dfcb13279f2c5d852d95)) * **Uncategorized** - Release dua-cli v2.29.4 ([`6386036`](https://github.com/Byron/dua-cli/commit/63860365d18e156656b7f00e1c99be93186b04b2)) - Merge pull request #267 from suzuki-shunsuke/chore-update-upload-artifact-v4 ([`904b3fc`](https://github.com/Byron/dua-cli/commit/904b3fce3a1df7a57c8564e57e65ed582d61ba44)) - Update actions/upload-artifact to v4 ([`44d25a6`](https://github.com/Byron/dua-cli/commit/44d25a64475ff861875fe97c4612356eb697f4bf))
## 2.29.3 (2024-11-03) ### Chore - upgrade `gix-glob` and `trash` ### Other - add x-cmd install steps Hi, I've added instructions on how to install dua using x-cmd to the README file. - [x-cmd](https://www.x-cmd.com/) is a **toolbox for Posix Shell**, offering a lightweight package manager built using shell and awk. ```sh x env use dua ``` - Auto submit new manifest to winget-pkgs ### Commit Statistics - 11 commits contributed to the release. - 3 commits were understood as [conventional](https://www.conventionalcommits.org). - 1 unique issue was worked on: [#265](https://github.com/Byron/dua-cli/issues/265) ### Commit Details
view details * **[#265](https://github.com/Byron/dua-cli/issues/265)** - Upgrade `gix-glob` and `trash` ([`25a6ad7`](https://github.com/Byron/dua-cli/commit/25a6ad73a6571bffe7fac56c61ff2e52ccda0b53)) * **Uncategorized** - Release dua-cli v2.29.3 ([`f5cb1ce`](https://github.com/Byron/dua-cli/commit/f5cb1ce4bab5c225bf8053229e86ab21b5f273e5)) - Merge pull request #266 from Byron/upgrades ([`297be49`](https://github.com/Byron/dua-cli/commit/297be49c4502ca05104693a8135ccf1f63b8a5c7)) - Merge pull request #261 from Byron/dependabot/github_actions/dot-github/workflows/actions/download-artifact-4.1.7 ([`ee55bf5`](https://github.com/Byron/dua-cli/commit/ee55bf584ffa3e7adf25f30190e091a54102959f)) - Merge pull request #260 from Byron/dependabot/cargo/gix-path-0.10.10 ([`4d859aa`](https://github.com/Byron/dua-cli/commit/4d859aac4fd95b2a3c12dbbc5bfaa414490d0316)) - Bump actions/download-artifact from 1 to 4.1.7 in /.github/workflows ([`57a67a5`](https://github.com/Byron/dua-cli/commit/57a67a59da48e042332fd7e8b6bd046c2155a391)) - Bump gix-path from 0.10.9 to 0.10.10 ([`4db9b9e`](https://github.com/Byron/dua-cli/commit/4db9b9e1269a562a93e6a94a641eed2498da9621)) - Merge pull request #259 from lunrenyi/patch-1 ([`b3fdc92`](https://github.com/Byron/dua-cli/commit/b3fdc923cfa5ef03a932aa4d7c994e322f212da3)) - Add x-cmd install steps ([`c66e585`](https://github.com/Byron/dua-cli/commit/c66e585ec73707d113d481ae2627187c9071539d)) - Merge pull request #256 from Dragon1573/issues/255 ([`3309e3b`](https://github.com/Byron/dua-cli/commit/3309e3b59f167002f883fb79e98e8326f2ba1055)) - Auto submit new manifest to winget-pkgs ([`fa203b1`](https://github.com/Byron/dua-cli/commit/fa203b1b955b896d989eb46e72f13fd5e6cd6120))
## 2.29.2 (2024-08-10) A maintenance release without user-facing changes. ### Commit Statistics - 3 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 2 unique issues were worked on: [#253](https://github.com/Byron/dua-cli/issues/253), [#254](https://github.com/Byron/dua-cli/issues/254) ### Commit Details
view details * **[#253](https://github.com/Byron/dua-cli/issues/253)** - Revert "avoid `Cargo.lock` in exported archives" ([`452b30f`](https://github.com/Byron/dua-cli/commit/452b30f0a7c2cc0b5c33cb7d12700fd18dd1e4e1)) * **[#254](https://github.com/Byron/dua-cli/issues/254)** - Prepare a new patch release to bring Cargo.lock back ([`dd2d7cd`](https://github.com/Byron/dua-cli/commit/dd2d7cda58c34d0ddf7af11c8b06b31f4c4ddd31)) * **Uncategorized** - Release dua-cli v2.29.2 ([`60ed763`](https://github.com/Byron/dua-cli/commit/60ed763e98620664c06eac5fd7972f407ae97503))
## 2.29.1 (2024-08-10) This is a maintenance release without user-facing changes. ### Bug Fixes - clippy warning ### Other - update version in install instructions ### Commit Statistics - 16 commits contributed to the release over the course of 126 calendar days. - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - 1 unique issue was worked on: [#253](https://github.com/Byron/dua-cli/issues/253) ### Thanks Clippy [Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. ### Commit Details
view details * **[#253](https://github.com/Byron/dua-cli/issues/253)** - Avoid `Cargo.lock` in exported archives ([`2ef583d`](https://github.com/Byron/dua-cli/commit/2ef583d0485941c9cbe91e85c2b62ead80cbb490)) * **Uncategorized** - Release dua-cli v2.29.1 ([`c82b3f9`](https://github.com/Byron/dua-cli/commit/c82b3f9cad2e84b4976c142faa7f7085d7cc20b7)) - Prepare changelog prior to release ([`9a27130`](https://github.com/Byron/dua-cli/commit/9a271309624bd01c1814e4058c859e3fdc2ffcd3)) - Update locked dependencies ([`319bdde`](https://github.com/Byron/dua-cli/commit/319bddec1812b4a732c8380208b5503f40841bbc)) - Merge branch 'olastor/main' ([`80c14a9`](https://github.com/Byron/dua-cli/commit/80c14a9cd28e5a18f5e9df517f6a3332d90e7c30)) - Thanks clippy ([`7ddbfbe`](https://github.com/Byron/dua-cli/commit/7ddbfbe37a56b845cc437e60509cb5bb6a89fe01)) - Update version in install instructions ([`f0b9a8e`](https://github.com/Byron/dua-cli/commit/f0b9a8e07b24d963116da4dfaa3338a4d4e8a3bf)) - Merge pull request #246 from matta/use-ratatui-terminal ([`ced3b4f`](https://github.com/Byron/dua-cli/commit/ced3b4f5e375278dbee52319eac8750b14eb328a)) - Update dependencies to fix CI ([`69a7cdd`](https://github.com/Byron/dua-cli/commit/69a7cdd11068b2e4053460b42d8a4959501a7799)) - Replace tui_react::Terminal with tui::Terminal ([`1350c2f`](https://github.com/Byron/dua-cli/commit/1350c2f5d7e7bd79909fe78584008385dec1b794)) - Merge pull request #247 from matta/fix-clippy ([`e3aff9d`](https://github.com/Byron/dua-cli/commit/e3aff9d987a09910b52dbce84c0de806d4233b04)) - Merge pull request #240 from denilsonsa/patch-1 ([`c1caa70`](https://github.com/Byron/dua-cli/commit/c1caa704cab61bf94abbf4de64f6cb890d1a1ea6)) - Clippy warning ([`46ebf14`](https://github.com/Byron/dua-cli/commit/46ebf149548f10c1b144f596aa715062787fd141)) - Added link to Filelight ([`e3883af`](https://github.com/Byron/dua-cli/commit/e3883af3f751a683b0ba208efc9127e0a07281e2)) - Merge pull request #235 from blinxen/main ([`66e0166`](https://github.com/Byron/dua-cli/commit/66e01667ddf6cc8da8a2387ef9d457aef63f42a5)) - Update gix-glob dependency to 0.16.2 ([`71a365e`](https://github.com/Byron/dua-cli/commit/71a365efadab4c8dffb4a0e10dcc282dd3f57516))
## 2.29.0 (2024-03-10) ### New Features - Add scrollbar to the main entries list. That way it's easier to grasp how long the list is, and how fast one is traversing is. ### Bug Fixes - avoid crashes when the terminal is resized to unusually small sizes. - mark-pane help bar now shows closest to the selected item. Previously this would only work in the first screen, but not when the list was long enough for scrolling. ### Commit Statistics - 19 commits contributed to the release. - 46 days passed between releases. - 3 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.29.0 ([`ab52733`](https://github.com/Byron/dua-cli/commit/ab5273334bd55e01adc5ded64432bb40eefc4053)) - Avoid crashes when the terminal is resized to unusually small sizes. ([`caa1e72`](https://github.com/Byron/dua-cli/commit/caa1e7261bad1b0e2b10628aa14c9d2b6868a14a)) - Mark-pane help bar now shows closest to the selected item. ([`24a6c29`](https://github.com/Byron/dua-cli/commit/24a6c29b3f48289cb6374aa66e84357edb5d0d54)) - Update to the latest versions of `tui-react` and `ratatui` ([`8ab4ee7`](https://github.com/Byron/dua-cli/commit/8ab4ee72423bba54402525b4ea4593f0c582261e)) - Fix possible overflow during substraction in mark pane ([`a94c7d3`](https://github.com/Byron/dua-cli/commit/a94c7d31ec152ff2427092054b99d8c4f3f74cfd)) - Add scrollbar for mark list ([`5fe858d`](https://github.com/Byron/dua-cli/commit/5fe858d771d286204d2ed911533869223ea20d2c)) - Add scrollbar to the main entries list. ([`0c511ff`](https://github.com/Byron/dua-cli/commit/0c511ffa0f15e16520353ff712f6bcc11318e379)) - Avoid iterating a potentially long list doubly ([`fd797e8`](https://github.com/Byron/dua-cli/commit/fd797e86787ca1675e0f0406828c06506b4b1a11)) - Add scrollbar for main list ([`120a08a`](https://github.com/Byron/dua-cli/commit/120a08aefeed9581f5d9110861b15ee0cbcd5831)) - Merge branch 'dev/pwach/ignore-vs-code' ([`b79fde4`](https://github.com/Byron/dua-cli/commit/b79fde47d07a712101ab97127fc3b23acd105b13)) - Remove user and platform specific files from `.gitignore` ([`30f28a7`](https://github.com/Byron/dua-cli/commit/30f28a7426ea4093a0205e02674bd43943130b88)) - Ignore .vscode directory (same as .idea) ([`27cbd21`](https://github.com/Byron/dua-cli/commit/27cbd2128c1b4213b8b2bd354e8205b2f8e1878d)) - Merge pull request #231 from gosuwachu/dev/pwach/fix-clippy ([`250fdc4`](https://github.com/Byron/dua-cli/commit/250fdc420e12634a195f23f461dda07c998cacea)) - Update dependencies ([`0086854`](https://github.com/Byron/dua-cli/commit/00868548eee4b57a5646aef0d9e0cf8cd6de8226)) - Fixes clippy error in rust 1.76 ([`85c00cd`](https://github.com/Byron/dua-cli/commit/85c00cd44f7e3dbd862c5d02a7f8310de7ead670)) - Merge pull request #229 from chessmango-forks/main ([`5052da9`](https://github.com/Byron/dua-cli/commit/5052da9567b7ba75ebba015171a70202a10d26ee)) - Different image obvi ([`f5ec49f`](https://github.com/Byron/dua-cli/commit/f5ec49f09e9699e2b5d538cd77c9facf236753b0)) - Strip arm64 bin ([`504ac52`](https://github.com/Byron/dua-cli/commit/504ac521afca3f0791d2ac2c02adffb34d1a2e34)) - Add aarch64 releases ([`a88baf1`](https://github.com/Byron/dua-cli/commit/a88baf1d9494118cca405aa2639656e1d05ba533))
## 2.28.0 (2024-01-23) ### New Features - add `dua i --no-entry-check` flag. With it, in interactive mode, entries will not be checked for presence. This can avoid laggy behaviour when switching between directories as `lstat` calls will not run, which can be slow on some filesystems. ### Commit Statistics - 4 commits contributed to the release. - 1 day passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 2 unique issues were worked on: [#226](https://github.com/Byron/dua-cli/issues/226), [#227](https://github.com/Byron/dua-cli/issues/227) ### Commit Details
view details * **[#226](https://github.com/Byron/dua-cli/issues/226)** - Make builds with rustc 1.72 work ([`600bee2`](https://github.com/Byron/dua-cli/commit/600bee234edd4e7922017c26927a6f135a02c335)) * **[#227](https://github.com/Byron/dua-cli/issues/227)** - Add `dua i --no-entry-check` flag. ([`78b9a8e`](https://github.com/Byron/dua-cli/commit/78b9a8e22568c902132ed98d32e223ff71eb7b06)) * **Uncategorized** - Release dua-cli v2.28.0 ([`984fd97`](https://github.com/Byron/dua-cli/commit/984fd979e18ffaa20ba35bca3b85dc47c404328c)) - Merge branch 'no-entry-check' ([`d837d72`](https://github.com/Byron/dua-cli/commit/d837d720e3b1e204043b8d89447db0d65ae000ba))
## 2.27.2 (2024-01-22) ### Bug Fixes - allow `/` (glob-mode) while scanning. This will possibly lead to incomplete results, but I find being able to use ones muscle-memory more important than preventing dealing with incomplete results. What happens to me is usually to type `/` followed by `target/` which tends to select all current entries for deletion. - don't check entry metadata while a scan is in progress Previously each time the UI refreshes, every 250ms, it display entries but also check their metadata to assure they exist. This could lead to performance loss when the displayed folder has a lot of entries. ### Commit Statistics - 4 commits contributed to the release. - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - 1 unique issue was worked on: [#223](https://github.com/Byron/dua-cli/issues/223) ### Commit Details
view details * **[#223](https://github.com/Byron/dua-cli/issues/223)** - Don't check entry metadata while a scan is in progress ([`c70ca81`](https://github.com/Byron/dua-cli/commit/c70ca81f007f925c7891340d0d0e763bcfc4114d)) * **Uncategorized** - Release dua-cli v2.27.2 ([`e512f31`](https://github.com/Byron/dua-cli/commit/e512f31df3aeba1410df5e250dd74569a48fdf66)) - Merge branch 'fix-overhead' ([`7a4b271`](https://github.com/Byron/dua-cli/commit/7a4b27153c2cb47caca87e28c5e178921c3a3fd9)) - Allow `/` (glob-mode) while scanning. ([`67c5bdb`](https://github.com/Byron/dua-cli/commit/67c5bdb74cfcf8cab647888afec26cd09ccf543a))
## 2.27.1 (2024-01-21) ### Bug Fixes - Explicit refreshes with 'r and 'R' now work with multiple root paths as will. This can happen in cases of `dua i root-a root-b` for instance. ### Commit Statistics - 8 commits contributed to the release. - 4 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.27.1 ([`346b944`](https://github.com/Byron/dua-cli/commit/346b944a45d4cec12f7689718893ebdef0f46546)) - Explicit refreshes with 'r and 'R' now work with multiple root paths as will. ([`f70d1a8`](https://github.com/Byron/dua-cli/commit/f70d1a8e6ace812a7949cd7d0299507b71306d48)) - Refactor ([`9d976d0`](https://github.com/Byron/dua-cli/commit/9d976d0d76fcf45d1e0672bc5c1533b000a46ebf)) - Cargo fmt ([`99b5443`](https://github.com/Byron/dua-cli/commit/99b5443f2f8821b0a285320c8ec3f982722cfff8)) - Tests for refresh & selection ([`dcff2ee`](https://github.com/Byron/dua-cli/commit/dcff2eebed4422f3103d99eac6bd91e56df327c6)) - Fix refresh with multiple input paths ([`65f6735`](https://github.com/Byron/dua-cli/commit/65f6735b7a0761b1371bcede86e9b46b9920bb5c)) - Test glob pane open/close ([`7efd77e`](https://github.com/Byron/dua-cli/commit/7efd77e6dd3d442f198ef50967ab50524ca22ffd)) - Tests for shwing/hiding additional columns ([`dbab511`](https://github.com/Byron/dua-cli/commit/dbab511ff68d8cc7d8e4906db3c2472dd8305b77))
## 2.27.0 (2024-01-17) ### New Features - Press `r` or `R` for refresh Lower-case `r` will refresh the currently selected entry, while upper-case `R` will refresh the entire displayed directory, and all entries in it. Further, what was called `item` is now called `entry` across the user-interface. - show and hide mtime and item count columns with 'M' and 'C' respectively ### Commit Statistics - 45 commits contributed to the release. - 11 days passed between releases. - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - 1 unique issue was worked on: [#96](https://github.com/Byron/dua-cli/issues/96) ### Commit Details
view details * **[#96](https://github.com/Byron/dua-cli/issues/96)** - Press `r` or `R` for refresh ([`bed351e`](https://github.com/Byron/dua-cli/commit/bed351ed2190e50e2932278b9b13b83c2969401b)) - Prepare for (R)efresh support ([`1812227`](https://github.com/Byron/dua-cli/commit/181222745ed50b7346bfd082473168634e01fa99)) * **Uncategorized** - Release dua-cli v2.27.0 ([`322eeb1`](https://github.com/Byron/dua-cli/commit/322eeb1aa07dacdc82e147bae64f8bfd4d758e1d)) - Refactor ([`18a725d`](https://github.com/Byron/dua-cli/commit/18a725dc5af97841afd06dcd4c8469e1d7ea873c)) - Make `Shift+r` do more than 'r' ([`f1fc13e`](https://github.com/Byron/dua-cli/commit/f1fc13ec8e2af583d0ce4eb541e260e9045c8cf2)) - Preserve selected element after refresh ([`99e5384`](https://github.com/Byron/dua-cli/commit/99e53849dd6096d05ab4962e1ed5440efcae83f3)) - Various updates based on the code review feedback: ([`c3d665d`](https://github.com/Byron/dua-cli/commit/c3d665d40264c819be66a5e290a87fb9f2007cf8)) - Cargo clippy & fmt ([`ad7abd8`](https://github.com/Byron/dua-cli/commit/ad7abd83261d5db6b59fbf9d55a24020c531f157)) - Fix tests ([`6b24912`](https://github.com/Byron/dua-cli/commit/6b2491200cbabb846f6566cb58eeb8b859a776e0)) - Exit glob mode if view root is the same as glob root ([`253f720`](https://github.com/Byron/dua-cli/commit/253f720ff81e675d071fd0da8562ddf8ed1626f8)) - Fix updating item count ([`13614a9`](https://github.com/Byron/dua-cli/commit/13614a9a8989df2dfd434e04a0d9ba132ee79244)) - Fixed tests ([`69f14af`](https://github.com/Byron/dua-cli/commit/69f14af5403dd17597cfaabf074bf158beabeda3)) - Remove debug comments ([`9f37e1c`](https://github.com/Byron/dua-cli/commit/9f37e1ca5e9635cb2ebd1c4d543d59340a5c77e8)) - Refresh all in view vs selected ([`06ee3ab`](https://github.com/Byron/dua-cli/commit/06ee3ab6e7b116c50aabe64c642ff128bbc2fb9a)) - Fix file count ([`eeae2bc`](https://github.com/Byron/dua-cli/commit/eeae2bc238871a5883624ced30a5ee43b4f8fdfb)) - Fix traversal stats ([`96ef242`](https://github.com/Byron/dua-cli/commit/96ef242d3b00dfb46800b179595114fecb62fa35)) - Moved traversal stats to separate type ([`969e64b`](https://github.com/Byron/dua-cli/commit/969e64bbde872d0598b1ebf6278f5d55e152f7b1)) - Traverse children vs parent & fix parent node size after refresh ([`226cbb8`](https://github.com/Byron/dua-cli/commit/226cbb8b2d6388ddd7a7e48fdac1a4db2ee75474)) - Add `R` to trigger a full refresh (PoC) ([`30d8dd5`](https://github.com/Byron/dua-cli/commit/30d8dd5fb54ef6db8b4444524407f15db25d7b02)) - Make WalkOptions available in State so it can re-use it for additional walks. ([`0ad90ba`](https://github.com/Byron/dua-cli/commit/0ad90ba23e59b98ccca198ce075e582c93d13c5c)) - Merge pull request #217 from Geezus42/patch-1 ([`85005ce`](https://github.com/Byron/dua-cli/commit/85005ce364b08066a76ab2a8743ce18b4662fa3c)) - Update README.md ([`e0ac3d1`](https://github.com/Byron/dua-cli/commit/e0ac3d1916b1e58bb6fd3619a7c7dbd4ce201e77)) - Merge branch 'show_columns' ([`1a54d95`](https://github.com/Byron/dua-cli/commit/1a54d95bd6e60bd5b071c772324c7a8540d250f6)) - Show and hide mtime and item count columns with 'M' and 'C' respectively ([`1544e8d`](https://github.com/Byron/dua-cli/commit/1544e8dffeacb55940deae2d06534d8a500765d4)) - Refactor ([`30da672`](https://github.com/Byron/dua-cli/commit/30da672a83c1063eb6f4c5483cb47f5d69c1dc35)) - Clippy ([`c4efba8`](https://github.com/Byron/dua-cli/commit/c4efba87179636afeb26e472353a029a4030086c)) - Fixed tests ([`d903ea6`](https://github.com/Byron/dua-cli/commit/d903ea67a4f77c9483aed7bda1ef6694ee4465da)) - Fmt ([`6c63bf5`](https://github.com/Byron/dua-cli/commit/6c63bf5a33ebb6b98516ca9a96796facfdab2277)) - Clippy ([`f74a40a`](https://github.com/Byron/dua-cli/commit/f74a40a7212bde94bae9ff0ee1947a5b1478fb93)) - New Traversal ([`9eaa961`](https://github.com/Byron/dua-cli/commit/9eaa96144bc72de6515c30fc32961a2807b247c7)) - Fmt ([`b3236dc`](https://github.com/Byron/dua-cli/commit/b3236dcb3db927f3709e9355b218f42327a66a99)) - Clippy ([`8aaa05a`](https://github.com/Byron/dua-cli/commit/8aaa05ada6169860cd083a24764bc2c5915b220b)) - Started fixing tests... ([`5abb9d7`](https://github.com/Byron/dua-cli/commit/5abb9d7e8d18799caa4a2f3823e06b77bdb27133)) - Remove commented out code ([`7378bd8`](https://github.com/Byron/dua-cli/commit/7378bd8bb1887379688eafe00a773521a7c32c9b)) - First working version ([`b52f66e`](https://github.com/Byron/dua-cli/commit/b52f66e4cd48bc670b1b98a4a713e280b63d9432)) - Cargo fmt ([`0cd5ea9`](https://github.com/Byron/dua-cli/commit/0cd5ea9612005ff724226ba502c2bea8ff4f0486)) - Update entries ([`bb511b5`](https://github.com/Byron/dua-cli/commit/bb511b538c7d75b02d598d495b307a83a11f53c0)) - Wip ([`51b67ff`](https://github.com/Byron/dua-cli/commit/51b67ff9d009a56272448d1fee1951f30b1de678)) - Clean-up init function ([`13c381b`](https://github.com/Byron/dua-cli/commit/13c381bebc6a64e553ec11793ec8880f868e712c)) - Move ByteFormat out of WalkOptions ([`e53036a`](https://github.com/Byron/dua-cli/commit/e53036ad84b71e1121588929fe4653a7ababbf67)) - Move AppState to separate file ([`feec3eb`](https://github.com/Byron/dua-cli/commit/feec3eb37d50c4b927ae3f948159693f134edf4b)) - Move TerminalApp to separate file ([`5123cf5`](https://github.com/Byron/dua-cli/commit/5123cf584ab68c0a2f491580289c7243e8651bfa)) - Scan disabled ([`cf3c507`](https://github.com/Byron/dua-cli/commit/cf3c507bb43221066acf96cde778b66bbd578669)) - Update demo ([`0e2e8c6`](https://github.com/Byron/dua-cli/commit/0e2e8c6c422a29ad25f055da8dd1611746827795)) - No Interactive enum ([`807916c`](https://github.com/Byron/dua-cli/commit/807916ced6e4ec195e0c3805181f3ccd78d69ce3))
## 2.26.0 (2024-01-05) ### New Features - responsive and buttery-smooth UI while scanning in interactive mode. Using `dua i` the GUI would populate and is fully usable even while the scan is in progress, which is fantastic when scanning big disks which can take several minutes. However, previously is was quite janky as the refresh loop was bound to receiving entries to process, which sometimes stalled for many seconds. Now the GUI refresh is uncoupled from receiving traversal entries, and it will update when the user presses a key or 250ms pass without any input, causing it to respond immediately. Thanks so much for contributing, [@unixzii](https://github.com/unixzii)! ### Commit Statistics - 4 commits contributed to the release. - 2 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 1 unique issue was worked on: [#209](https://github.com/Byron/dua-cli/issues/209) ### Commit Details
view details * **[#209](https://github.com/Byron/dua-cli/issues/209)** - Responsive and buttery-smooth UI while scanning in interactive mode. ([`3c8a31b`](https://github.com/Byron/dua-cli/commit/3c8a31b50da8230bb9268b857e00d0c90e8cb786)) * **Uncategorized** - Release dua-cli v2.26.0 ([`b19c3e0`](https://github.com/Byron/dua-cli/commit/b19c3e02b3f6a810a717235d9742466c8e1bf7d9)) - Refactor ([`0651cae`](https://github.com/Byron/dua-cli/commit/0651cae13b43104402ed9d90147ee8c63fe83b61)) - Optimize UI responsiveness during scanning state ([`983ba61`](https://github.com/Byron/dua-cli/commit/983ba6172604b83c2e4efad0f03273206a43c5db))
## 2.25.0 (2024-01-03) ### Chore - remove obsolete `tui-shared` feature ### New Features - add `--log-file` flag to keep track of some debug info, which includes panics. Previously, when `dua i` was used, panics would be hard to observe, if at all, as they would print to the alternate screen. Now, when the `--log-file dua.log` is specified, the panic will be emitted into the log file instead and thus won't be lost anymore. This may help with debugging in future. ### Bug Fixes - `--ignore-dirs` now work as expected. Previously they would need to be specified as relative to the traversal root, which was unintuitive and would lead to ignores not working for many. Even though this was done for performance to avoid canonicalization, we do now perform a more performance version of canonicalization so the overall performance should be acceptable nonetheless. Also note that ignored directories are now logged when using a `--log-file`. - consistent language across the application and improved style of the Help pane. Generally, what was called `entry` is now called `item`, consistently. ### Other - clarify that (and why) `termion` isn't supported anymore in README.md This was triggered by `crossterm` essentially breaking event handling on Windows, which is when I decided to just use the seemingly more powerful crossterm events natively. Overall, this made event handling more complex, but also allows users of `crosstermion` (the crate that actually dropped `termion` support) to write even more interactive applications without worrying about the always out-of-date intermediate layer. Interestingly, the `crosstermion` crate adds some useful features around event handling, but also optimizes build times thanks to `termion`, which is something that on my current machine I don't notice anymore, so the value of it diminished greatly. ### Commit Statistics - 14 commits contributed to the release over the course of 7 calendar days. - 7 days passed between releases. - 5 commits were understood as [conventional](https://www.conventionalcommits.org). - 2 unique issues were worked on: [#196](https://github.com/Byron/dua-cli/issues/196), [#208](https://github.com/Byron/dua-cli/issues/208) ### Commit Details
view details * **[#196](https://github.com/Byron/dua-cli/issues/196)** - `--ignore-dirs` now work as expected. ([`49f98f5`](https://github.com/Byron/dua-cli/commit/49f98f537bf0ac41a7b1992094103f6d36f135f8)) * **[#208](https://github.com/Byron/dua-cli/issues/208)** - Remove obsolete `tui-shared` feature ([`e992659`](https://github.com/Byron/dua-cli/commit/e992659db17f275b48e555afd6b18df737401f01)) - Clarify that (and why) `termion` isn't supported anymore in README.md ([`729e7e9`](https://github.com/Byron/dua-cli/commit/729e7e92410b138f2778ef70f0f59a439028ac29)) * **Uncategorized** - Release dua-cli v2.25.0 ([`ad7c77a`](https://github.com/Byron/dua-cli/commit/ad7c77ac8db663e7a870dd73e45159462c1cbe60)) - Use `gix-path` for more control and performance. ([`93f0f61`](https://github.com/Byron/dua-cli/commit/93f0f61b3042b933f099714e3a6d336497eb18ba)) - Refactor ([`7905b48`](https://github.com/Byron/dua-cli/commit/7905b48f2f9ca981a6c617ced3a151e79cab9739)) - Fix ignore dirs wip ([`e2d5a34`](https://github.com/Byron/dua-cli/commit/e2d5a34b5b6d8212b53d60ceea20324eba08cb2a)) - Merge branch 'logging' ([`196f0d6`](https://github.com/Byron/dua-cli/commit/196f0d62f32aacc2d393ef2929305a831a150520)) - Add `--log-file` flag to keep track of some debug info, which includes panics. ([`6fbe17f`](https://github.com/Byron/dua-cli/commit/6fbe17ff51360d62086aa265a0baa9288175cb84)) - Enforce Rust 2021 style ([`45d886a`](https://github.com/Byron/dua-cli/commit/45d886a6b2c194a5a68961b428f8db2c8daf06a8)) - Merge branch 'help-language-consistency' ([`0a0dfe6`](https://github.com/Byron/dua-cli/commit/0a0dfe65c4a7bd8851841edf488296966ba27bf0)) - Consistent language across the application and improved style of the Help pane. ([`20e85c1`](https://github.com/Byron/dua-cli/commit/20e85c1ebe7ce3a5254fe2675a52cb5d321f1e34)) - Option to enable debug logs ([`4482e1d`](https://github.com/Byron/dua-cli/commit/4482e1de9808a8d662b93b3af907b90000e9f1ae)) - Keep consistent language/punctuation/case throughout the app. ([`1e6db58`](https://github.com/Byron/dua-cli/commit/1e6db588723dbbc96bc2f083e915d08bdf1b4ddf))
## 2.24.2 (2023-12-26) ### Bug Fixes - avoid duplicate key input on windows. On Windows, key-states like press/release/repeat are made available separately, which means we should avoid responding to key-releases as it would incorrectly double the actual user inputs. ### Commit Statistics - 4 commits contributed to the release. - 1 day passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 1 unique issue was worked on: [#203](https://github.com/Byron/dua-cli/issues/203) ### Commit Details
view details * **[#203](https://github.com/Byron/dua-cli/issues/203)** - Avoid duplicate key input on windows. ([`b5b8aa2`](https://github.com/Byron/dua-cli/commit/b5b8aa26b648d8a034667bca8320ba7952a27780)) - Upgrade to latest verison of tui-crates and native crossterm events. ([`90b65d5`](https://github.com/Byron/dua-cli/commit/90b65d59f5dde888f81c42e3c812670929b1740a)) * **Uncategorized** - Release dua-cli v2.24.2 ([`c973826`](https://github.com/Byron/dua-cli/commit/c9738265c40598f0a79befc8dd7be0d47a9f8179)) - Merge branch 'tui-crates-upgrade' ([`edbb446`](https://github.com/Byron/dua-cli/commit/edbb446100405d16c19059d6ced096144f8bb54e))
## 2.24.1 (2023-12-25) ### Bug Fixes - keep checking for existance of entries outside of the glob top-level. The glob top-level is used to display all search results which means that there can be a lot of them, which would unnecessarily slow down the search operation. Previously it would never check for the existence of an entry in glob mode, but now it will do so outside of the top-level. ### Commit Statistics - 2 commits contributed to the release. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.24.1 ([`46fece5`](https://github.com/Byron/dua-cli/commit/46fece5f295a8fb6f90ff969741f79d7c736c140)) - Keep checking for existance of entries outside of the glob top-level. ([`8ae727e`](https://github.com/Byron/dua-cli/commit/8ae727e462b38541636c8e03d140953cad8f34cf))
## 2.24.0 (2023-12-24) This release adds long-awaited globbing support, just hit the `/` key to get started. You want to find the biggest `.git` directories? Just type `/.git/` and you are done. What about all target directories? Just write `target/` to the glob search prompt and it's done. What about all directories ending in `*.rs/`? Oh, by accident you typed `*.rs` and now there is a list of a quarter million of entries? No problem, it's near instant even with millions of files to search or hundreds of thousands to display. > Note that glob-mode can be exited only by pressing `ESC` when the glob prompt has focus. Special thanks go to [the contributor](https://github.com/gosuwachu) who made this feature happen, along with many other improvements. Now `dua` feels refreshed for 2024, and is much more versatile. Happy holidays! ### Commit Statistics - 30 commits contributed to the release. - 12 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 1 unique issue was worked on: [#197](https://github.com/Byron/dua-cli/issues/197) ### Thanks Clippy [Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. ### Commit Details
view details * **[#197](https://github.com/Byron/dua-cli/issues/197)** - EntryData size test passes on 32-bit ([`9123ee7`](https://github.com/Byron/dua-cli/commit/9123ee7e648fab654520c33df672c053d5797966)) * **Uncategorized** - Release dua-cli v2.24.0 ([`f7958cc`](https://github.com/Byron/dua-cli/commit/f7958ccb36ab6023857bc3cdfba9ef90fdfe0c99)) - Update dependencies ([`bc8c7a6`](https://github.com/Byron/dua-cli/commit/bc8c7a6bb0a96cc1562e02cf87182d13be6c264f)) - Upgrade owo-colors to v4.0 ([`141c56c`](https://github.com/Byron/dua-cli/commit/141c56c560b34f35e67a699c6e88bea0c0bef0ab)) - Update changelog prior to release; bump version ([`cfa8faa`](https://github.com/Byron/dua-cli/commit/cfa8faaf30a83b9517d5e10fd2702bd7a44ba1ad)) - Merge branch 'glob-review' ([`1c4d6a7`](https://github.com/Byron/dua-cli/commit/1c4d6a77c9f439782446d5d5f791fe9e809de0e7)) - Use `gix-glob` for matching; support for matching dirs only. ([`2e1858c`](https://github.com/Byron/dua-cli/commit/2e1858ca519fd2a6fbf4839a23abcf17588dcc32)) - Remove treeview abstraction in favor of something simpler ([`3804a1f`](https://github.com/Byron/dua-cli/commit/3804a1f8e70e1f64977d1fcac20d6541aa5956d7)) - Refactor glob widget ([`b945a1e`](https://github.com/Byron/dua-cli/commit/b945a1e2613b5b0b2eed85f7c9f34942ab3c4a29)) - More copy-on-write for entries ([`bc56664`](https://github.com/Byron/dua-cli/commit/bc566649e6941340c2bdbcd178ac73a6a6512f68)) - Refactor shortening ([`8fae939`](https://github.com/Byron/dua-cli/commit/8fae93966f916291bece3e5673ca83cefa702069)) - Thanks clippy ([`b431ec3`](https://github.com/Byron/dua-cli/commit/b431ec38f318a50a1b636e72ffed768e9ba1e4c5)) - Shorten long paths so that they fit on the screen ([`7660d64`](https://github.com/Byron/dua-cli/commit/7660d6497f3810856a65d203d2b6e97b708dc632)) - Show error message on empty search result ([`360a0d7`](https://github.com/Byron/dua-cli/commit/360a0d72302afb5b068525ef0cec18c21df1b46a)) - Glob most used keys ([`ff07f39`](https://github.com/Byron/dua-cli/commit/ff07f3935bc0a82e52bc169d2739a9bb603d86b8)) - Fix formatting ([`0a344fa`](https://github.com/Byron/dua-cli/commit/0a344fa063bdffe7165e8bab6b8a1b8adbac9dce)) - Fix cursor rendering ([`aaa27e8`](https://github.com/Byron/dua-cli/commit/aaa27e860508e564d82b43295baa4290b53eb87f)) - Small code review fixes ([`49aecb9`](https://github.com/Byron/dua-cli/commit/49aecb9245054446ac1b338ea1cc29831e72d5e0)) - Use appropriate tree view when listing entries ([`7244bac`](https://github.com/Byron/dua-cli/commit/7244bac0fc51697ed6be6597dee82a26da222c23)) - Replace EntryData in EntryDataBundle with individual properties ([`f3b5d00`](https://github.com/Byron/dua-cli/commit/f3b5d00549be57b5da03f3220057b887372ff254)) - Implements glob search mode ([`df6a02c`](https://github.com/Byron/dua-cli/commit/df6a02cd8fdbe693f507ab34a89227431d7c112e)) - Merge pull request #201 from Byron/dependabot/cargo/zerocopy-0.7.31 ([`b23e134`](https://github.com/Byron/dua-cli/commit/b23e13431dad1ed9efc6728f4c9ee8ab2254a42c)) - Bump zerocopy from 0.7.30 to 0.7.31 ([`3efc857`](https://github.com/Byron/dua-cli/commit/3efc85767a6f3274f6fe0f249554ec7af2c2500f)) - Merge branch 'add_missing_slash_in_root_dir' ([`9a15867`](https://github.com/Byron/dua-cli/commit/9a158676da9087cd734db6d401fcb98c0e98904c)) - Make clear why roots were special cased, and try to restore that behaviour. ([`94c008f`](https://github.com/Byron/dua-cli/commit/94c008fe8bd5ff836049f8d5d18478d41bfca9c3)) - Adds the missing '/' prefix for root directories ([`101a377`](https://github.com/Byron/dua-cli/commit/101a37761952f094a782fb34850c82070565125b)) - Merge branch 'app_state_init_refactor' ([`f23a57f`](https://github.com/Byron/dua-cli/commit/f23a57fa9c16276525c315c875729c9ef9920fdf)) - Minior refactor ([`6f09882`](https://github.com/Byron/dua-cli/commit/6f09882fddf8eddc0331671a3176b613d827d4e3)) - Refactors AppState initialization during app startup ([`238bc5f`](https://github.com/Byron/dua-cli/commit/238bc5f956d220f90197112c82ec71781cd0aa4d)) - Merge pull request #198 from cinerea0/fix-32bit-test ([`1b838f9`](https://github.com/Byron/dua-cli/commit/1b838f9a057782fd6f11d47d09ae3f77c6bf082d))
## 2.23.0 (2023-12-11) ### New Features - display the total count of entries-to-be-deleted in the mark pane. This allows to better estimate how much work will be needed to perform the deletion. For example, when marking 3 items for deletion, previously one would see `3 items marked`, but now one will see all items and sub-items, like `120k`items marked`, which reflects the work that will be done much more precisely. - Add total size to header bar and change to aggregate, human-readable item count. This changes the display from `(2034 items)` to `(2k items, 213 MB)`, providing an overview of the total amount of storage used along with the total amount of files on a particular hiearchy level. ### Bug Fixes - single files will not cause IO error Running `dua ` will once again provide size information about that filename. ### Commit Statistics - 17 commits contributed to the release. - 2 days passed between releases. - 3 commits were understood as [conventional](https://www.conventionalcommits.org). - 1 unique issue was worked on: [#194](https://github.com/Byron/dua-cli/issues/194) ### Commit Details
view details * **[#194](https://github.com/Byron/dua-cli/issues/194)** - Single files will not cause IO error ([`192460e`](https://github.com/Byron/dua-cli/commit/192460e5bc72781be1d238912c5d590bfed706cf)) * **Uncategorized** - Release dua-cli v2.23.0 ([`491b558`](https://github.com/Byron/dua-cli/commit/491b5587ca0e9d157b9a4f8907c35137d57983d5)) - Merge branch 'main_windows_render_refactor' ([`2da2e2e`](https://github.com/Byron/dua-cli/commit/2da2e2e7d264d19cc67ccee6bd8658f7a87901c1)) - Refactor ([`49772d1`](https://github.com/Byron/dua-cli/commit/49772d17dca72006e602f8707121b3378f948981)) - Display the total count of entries-to-be-deleted in the mark pane. ([`98d5b5a`](https://github.com/Byron/dua-cli/commit/98d5b5a2728e640f9d553648812df379c5534395)) - Refactor ([`81eadf8`](https://github.com/Byron/dua-cli/commit/81eadf8cdfcfa964401b5cf5d1e80cc21ec4441f)) - Calculates mark pane item count consistently with the rest of the app ([`2c69ea1`](https://github.com/Byron/dua-cli/commit/2c69ea1faf40499431616e632e02351a22bac249)) - Refactors MainWindow render to make it more readable ([`8740d4b`](https://github.com/Byron/dua-cli/commit/8740d4b332290b7fa661b157ed190df9f40ad349)) - Merge branch 'upgrades' ([`a9dd549`](https://github.com/Byron/dua-cli/commit/a9dd549dc85faf17ce211ff0ab5be4c9863440ed)) - Upgrade to latest crossterm; switch to `ratatui` from `tui` ([`af2aa61`](https://github.com/Byron/dua-cli/commit/af2aa61813578ecc9f6ccaba5e94049fc6ddf727)) - Update all dependencies ([`852ee28`](https://github.com/Byron/dua-cli/commit/852ee281ca89cb58cf404e8179d4e590f6da87b7)) - Merge branch 'total_item_count' ([`ba2efe4`](https://github.com/Byron/dua-cli/commit/ba2efe48f327c92c021879cded7651d83cf99cec)) - Add total size to header bar and change to aggregate, human-readable item count. ([`3241022`](https://github.com/Byron/dua-cli/commit/3241022a730dab89f13cbefbefdb583fd6a00994)) - Merge branch 'make_ready_pre_pr_checks' ([`606d60f`](https://github.com/Byron/dua-cli/commit/606d60fa96654e030d1f82331c54f3dfa45e06b3)) - Adjust names of `make fmt` and `make ready`; `fmt` now only checks ([`9135c18`](https://github.com/Byron/dua-cli/commit/9135c18e27a75b23921f9bba4281af9543017a66)) - Adds new target that runs all the checks (to be used before creating a PR) ([`7fbc136`](https://github.com/Byron/dua-cli/commit/7fbc136f8d61676a89cd19c6035ec02a8bd14147)) - Displays total item count ([`7b7bad5`](https://github.com/Byron/dua-cli/commit/7b7bad5564d0e87eea4b4bd2d32066063a13b554))
## 2.22.0 (2023-12-09) ### New Features - Press `c` to sort by count of entries in a directory. That way it's easy to spot places that have a lot of (possibly small) files, which otherwise would remain under the radar when sorting by size. ### Commit Statistics - 15 commits contributed to the release over the course of 3 calendar days. - 3 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.22.0 ([`949baf3`](https://github.com/Byron/dua-cli/commit/949baf39c53060d1e5ef6df572b1cdc43a8a5cce)) - Press `c` to sort by count of entries in a directory. ([`45ccb7c`](https://github.com/Byron/dua-cli/commit/45ccb7cb5a4765190ea6b8d02e0b29f63b1bd702)) - Assure sorting of entry-counts takes files into consideration. ([`8439ba7`](https://github.com/Byron/dua-cli/commit/8439ba703d7f16b2a8f5bd0348b63b26a5fbe689)) - Refactor ([`9fb3113`](https://github.com/Byron/dua-cli/commit/9fb3113d788ff746873bd67f6ed508ec1fcf1b02)) - Adds keybinding for 'c' to toggle sorting by number of items ([`8df0b4c`](https://github.com/Byron/dua-cli/commit/8df0b4c5dc5ee3f512f8812dff709a77cfb18f2f)) - Merge branch 'column_render' ([`bf4da4e`](https://github.com/Byron/dua-cli/commit/bf4da4e1c4444fb490f85516efc518bb238e1652)) - Run clippy locally just like on CI ([`645474c`](https://github.com/Byron/dua-cli/commit/645474cfc6de5456a9ae7c0b50ee0302ca950cd2)) - Refactor ([`bbcd308`](https://github.com/Byron/dua-cli/commit/bbcd30886f71fcb6e804d3f4170c5ae332c181ea)) - Fix visual changes ([`b8ad16b`](https://github.com/Byron/dua-cli/commit/b8ad16b493c29c56d94f6ec01a9dc790687a1bdb)) - Make clippy warnings fatal ([`1a46d8f`](https://github.com/Byron/dua-cli/commit/1a46d8f4ab64c78c6ff6495225872f28e58f309d)) - Refactors entries panel by moving code to separate functions ([`b5b6aba`](https://github.com/Byron/dua-cli/commit/b5b6abae35a5f205cd57e172c7aa4e9dd16d2053)) - Put release-build optimization back to level 3; remove windows GNU build. ([`917339f`](https://github.com/Byron/dua-cli/commit/917339ff02e52cc3d258a350f5cb078e152f439a)) - Change optimization level back to 0 for hopefully more stable release builds. ([`2dced34`](https://github.com/Byron/dua-cli/commit/2dced34aef9b7beba3201e6a8b24d9a10a7b9a16)) - Assure package-size check isn't fatal anymore ([`3e509db`](https://github.com/Byron/dua-cli/commit/3e509db11228b93e11e8a06895dcb7d167fc8399)) - Pacify the package size checkf or a while. ([`09fd59f`](https://github.com/Byron/dua-cli/commit/09fd59febbf7fefe93d064718d640290b2957b21))
## 2.21.0 (2023-12-06) ### New Features - With a single path provided as root, pretend it's the current working dir This makes it seem like the user started the directory walk directly in the given directory, which is more intuitive than the previous approach only showed the given directory as top-level directory. Note that this change only affects invocations like `dua ` or `dua i `. - press `m` to sort by modification date, ascending and descending. ### Bug Fixes - slightly faster (0.5ms) startup times of the binary on MacOS and maybe Linux. ### Commit Statistics - 14 commits contributed to the release over the course of 11 calendar days. - 14 days passed between releases. - 3 commits were understood as [conventional](https://www.conventionalcommits.org). - 5 unique issues were worked on: [#110](https://github.com/Byron/dua-cli/issues/110), [#141](https://github.com/Byron/dua-cli/issues/141), [#179](https://github.com/Byron/dua-cli/issues/179), [#185](https://github.com/Byron/dua-cli/issues/185), [#186](https://github.com/Byron/dua-cli/issues/186) ### Thanks Clippy [Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. ### Commit Details
view details * **[#110](https://github.com/Byron/dua-cli/issues/110)** - With a single path provided as root, pretend it's the current working dir ([`de4c2b3`](https://github.com/Byron/dua-cli/commit/de4c2b3bd368fd032319b606b84fa488299bc9e1)) - Assure `device_id` is taken from the final CWD ([`74e6d42`](https://github.com/Byron/dua-cli/commit/74e6d4222a7f70253f1d69eb8e7cf94114827852)) * **[#141](https://github.com/Byron/dua-cli/issues/141)** - Press `m` to sort by modification date, ascending and descending. ([`dd523e3`](https://github.com/Byron/dua-cli/commit/dd523e389bcc940a5d3e72099bb0c76f40371164)) * **[#179](https://github.com/Byron/dua-cli/issues/179)** - Press `m` to sort by modification date, ascending and descending. ([`dd523e3`](https://github.com/Byron/dua-cli/commit/dd523e389bcc940a5d3e72099bb0c76f40371164)) * **[#185](https://github.com/Byron/dua-cli/issues/185)** - Slightly faster (0.5ms) startup times of the binary on MacOS and maybe Linux. ([`72fd6d1`](https://github.com/Byron/dua-cli/commit/72fd6d1936efa508aeb63e729cf75739a49acdb4)) * **[#186](https://github.com/Byron/dua-cli/issues/186)** - Assure `device_id` is taken from the final CWD ([`74e6d42`](https://github.com/Byron/dua-cli/commit/74e6d4222a7f70253f1d69eb8e7cf94114827852)) * **Uncategorized** - Release dua-cli v2.21.0 ([`7e3e290`](https://github.com/Byron/dua-cli/commit/7e3e290940e3229efce69baabab7d169d8a6793a)) - Manually set the desired version as `cargo smart-release` fails to see that 2.20.3 is available ([`f5bd870`](https://github.com/Byron/dua-cli/commit/f5bd870621779711ef8ba03812f097716f52d349)) - Prepare changelog ([`6ff009a`](https://github.com/Byron/dua-cli/commit/6ff009a3082c2c4dbe90b8188bf943df83f596d0)) - Thanks clippy ([`0c4d31b`](https://github.com/Byron/dua-cli/commit/0c4d31b406b2c988af3f17fc79b0cf3d7364a910)) - Skip through single root directory ([`e9fb2fd`](https://github.com/Byron/dua-cli/commit/e9fb2fda3478fefa38bdb9d176380bae5545dbc6)) - Increase optimization level ([`3d270bd`](https://github.com/Byron/dua-cli/commit/3d270bd2bdd8e83486140c96d7e9c12988c93405)) - Fix tests on Windows ([`1b7457e`](https://github.com/Byron/dua-cli/commit/1b7457e0301db3029e1b4beb52acfb99fe408174)) - Hide mtime column by default, unless enabled ([`0f8377a`](https://github.com/Byron/dua-cli/commit/0f8377a450b02bad317eed59d1593007aa5c0bed)) - Adds keybinding 'm' to toggle sorting by modified time ([`2bd06be`](https://github.com/Byron/dua-cli/commit/2bd06be9ee5ad8e1a747544899b299a53a950940)) - Add test to assure memory consumption of EntryData doesn't change unexpectedly. ([`adebd00`](https://github.com/Byron/dua-cli/commit/adebd00daa409da67d2f252b966e2dba632acda3))
## 2.20.3 (2023-11-21) ### Bug Fixes - mark-pane now doesn't double-count sizes anymore. ### Commit Statistics - 3 commits contributed to the release. - 1 day passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.20.3 ([`bb41fd5`](https://github.com/Byron/dua-cli/commit/bb41fd55cc476008342be9238568eb8f32dd40c4)) - Mark-pane now doesn't double-count sizes anymore. ([`7ab0070`](https://github.com/Byron/dua-cli/commit/7ab0070dcfda573cfbdc8451ddba5fcf15067132)) - Fixes marking parent directory for deletion counts children twice ([`f7086cc`](https://github.com/Byron/dua-cli/commit/f7086cc0836bd091552a83d8faabf937fb4c6cf8))
## 2.20.2 (2023-11-20) ### Bug Fixes - alignment when in interactive mode and -f binary ### Commit Statistics - 9 commits contributed to the release. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 1 unique issue was worked on: [#177](https://github.com/Byron/dua-cli/issues/177) ### Commit Details
view details * **[#177](https://github.com/Byron/dua-cli/issues/177)** - Alignment when in interactive mode and -f binary ([`49c3e3d`](https://github.com/Byron/dua-cli/commit/49c3e3d02ad0c14c4123fe1a7fea1f2a5e7a990f)) * **Uncategorized** - Release dua-cli v2.20.2 ([`28fa9dd`](https://github.com/Byron/dua-cli/commit/28fa9ddd7ee30e228d1660dde95ad076e378fba7)) - Update dependencies ([`12fa54a`](https://github.com/Byron/dua-cli/commit/12fa54a5c6af7720b27cffcc4c89e0728ec4cfda)) - Upgrade journey-test expectations (doesn't run on CI for some reason) ([`5498040`](https://github.com/Byron/dua-cli/commit/54980406b72e9b633fec632e015da378e5d5a49d)) - Upgrade `itertools` ([`0c8b6f2`](https://github.com/Byron/dua-cli/commit/0c8b6f2465c48b554faaa06bf0438cfff9df8a7f)) - Upgrade `open` ([`192420e`](https://github.com/Byron/dua-cli/commit/192420ededd19779754d51d690ecdf7588d62441)) - Fixes alignment when in interactive mode and -f binary ([`b3bb851`](https://github.com/Byron/dua-cli/commit/b3bb85177d2fc4b299a9d82313832be96b34c3b6)) - Make clear which windows toolchain is used on CI ([`8c02612`](https://github.com/Byron/dua-cli/commit/8c02612887a49d72244327c9bf7940ff8fa507e6)) - Update all dependencies ([`1bbee14`](https://github.com/Byron/dua-cli/commit/1bbee14695866294771d9113d9bab4d369b6401b))
## 2.20.1 (2023-05-05) ### Bug Fixes - release definition to use a more recent ubuntu, to get linux binaries. Otherwise there are no linux runners who can satisfy the request, and they hang forever, instead of saying something useful. ### Commit Statistics - 2 commits contributed to the release. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 1 unique issue was worked on: [#160](https://github.com/Byron/dua-cli/issues/160) ### Commit Details
view details * **[#160](https://github.com/Byron/dua-cli/issues/160)** - Release definition to use a more recent ubuntu, to get linux binaries. ([`3e8509d`](https://github.com/Byron/dua-cli/commit/3e8509d31291cbcaa0501b5ec4abf7f26a226836)) * **Uncategorized** - Release dua-cli v2.20.1 ([`bf51db2`](https://github.com/Byron/dua-cli/commit/bf51db20de49dc1c240fcbbe1ddea3a4a6537873))
## 2.20.0 (2023-05-05) ### New Features - TUI now shows performance metrics while scanning and after. This is in preparation for the `moonwalk` upgrade. - improve CLI help provided with the `--format` flag. It's now possible to see what possible values are without reading a swath of text. Now the default is shown as well which is more important now that it changes depending on the platform. - use metric byte format only on MacOS. That way, on linux the binary format is used by default which is more common on that platform. ### Bug Fixes - Improve documentation for `Marked Items` pane to make clearer how to delete items. ### Commit Statistics - 14 commits contributed to the release. - 4 commits were understood as [conventional](https://www.conventionalcommits.org). - 3 unique issues were worked on: [#157](https://github.com/Byron/dua-cli/issues/157), [#33](https://github.com/Byron/dua-cli/issues/33), [#85](https://github.com/Byron/dua-cli/issues/85) ### Thanks Clippy [Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. ### Commit Details
view details * **[#157](https://github.com/Byron/dua-cli/issues/157)** - Share `cargo` invocation to help install on more platforms ([`7ef48ad`](https://github.com/Byron/dua-cli/commit/7ef48ad5f326dcdd43f9b5481bf66bfce7d65074)) * **[#33](https://github.com/Byron/dua-cli/issues/33)** - Improve documentation for `Marked Items` pane to make clearer how to delete items. ([`b61ec97`](https://github.com/Byron/dua-cli/commit/b61ec973b7437230183d6dabf361b0848519f5dc)) * **[#85](https://github.com/Byron/dua-cli/issues/85)** - Use metric byte format only on MacOS. ([`22f54dd`](https://github.com/Byron/dua-cli/commit/22f54dd7c0e83b55e0acc2fb1a10ab487bdeb9fb)) * **Uncategorized** - Release dua-cli v2.20.0 ([`9c07301`](https://github.com/Byron/dua-cli/commit/9c07301b5ee7cb290dd1df2297184d29fc43fd67)) - TUI now shows performance metrics while scanning and after. ([`13bfe45`](https://github.com/Byron/dua-cli/commit/13bfe4582f8cbf6f8f12e7ee8acaae710e8a87d2)) - Thanks clippy ([`565581f`](https://github.com/Byron/dua-cli/commit/565581fc11faf7512c27fe9095090f482a8d32f0)) - Simplify GUI refreshes by using a throttle ([`c921dc7`](https://github.com/Byron/dua-cli/commit/c921dc72d3008179e72df9d85f0e0c21c998e199)) - Generalize the throttle implementation to allow usagein UI ([`e03c560`](https://github.com/Byron/dua-cli/commit/e03c560e8b54e2e231d578e1d5e9dcd206d34216)) - Added additional clarification for deleting help files. ([`fcc8be9`](https://github.com/Byron/dua-cli/commit/fcc8be93bd8224c01216ed2136cbf7309470ca2f)) - Dependency update ([`032747d`](https://github.com/Byron/dua-cli/commit/032747d14587161dae1e4508799a232390ddfbae)) - Improve CLI help provided with the `--format` flag. ([`d0e85fe`](https://github.com/Byron/dua-cli/commit/d0e85fec1586a8937928472e361837ef21e40b14)) - Refactor ([`b474b81`](https://github.com/Byron/dua-cli/commit/b474b8146de6ce925098b08a1d6af62aa0c25f77)) - Use binary format by default (except on macOS) ([`3ccf204`](https://github.com/Byron/dua-cli/commit/3ccf204a18c784a7af7b6255173b332e0083c047)) - Merge pull request #147 from nyurik/patch-1 ([`658c676`](https://github.com/Byron/dua-cli/commit/658c676be779655165e5c5462873c8e828e710f2))
## 2.19.2 (2023-02-23) ### Bug Fixes - `-x` is applied to traversal as well. Previously `dua` would cross filesystems for traversal and simply not yield them, which somewhat defeated the purpose. Now it will avoid traversing into filesystem entries that are on a different filesystem, which should improve its performance visibly whenever multiple filesystems are involved. ### Other - don't recurse on cross-device filesystems Like it says in the title. Right now, if you pass `-x`, dua doesn't count files on other devices, but it still enumerates them. However, a good reason to use `-x` is if you have network mounts that are slow, so this fixes that. ### Commit Statistics - 5 commits contributed to the release. - 17 days passed between releases. - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.19.2 ([`aa08b81`](https://github.com/Byron/dua-cli/commit/aa08b8100a6c2fcbbbfe1d249d082cfa6161e9d0)) - `-x` is applied to traversal as well. ([`31dacad`](https://github.com/Byron/dua-cli/commit/31dacad6f723f379a2d12417d65177faccd67b76)) - Refactor ([`dbc9845`](https://github.com/Byron/dua-cli/commit/dbc9845c7d63d7c113f9f61b91da99ff0b249ad2)) - Update help.rs ([`c36c5b9`](https://github.com/Byron/dua-cli/commit/c36c5b968814e77c538efd0765894491dc150e95)) - Don't recurse on cross-device filesystems ([`fe956ca`](https://github.com/Byron/dua-cli/commit/fe956ca6f244613762bb48de79eac1f6fa399e1b))
## 2.19.1 (2023-02-05) ### Bug Fixes - redraw window while gathering metadata in interactive mode. This fixes a by now long-standing issue with interactive mode only updating when keys are pressed, but not automatically. ### Commit Statistics - 7 commits contributed to the release over the course of 52 calendar days. - 53 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 1 unique issue was worked on: [#143](https://github.com/Byron/dua-cli/issues/143) ### Commit Details
view details * **[#143](https://github.com/Byron/dua-cli/issues/143)** - Redraw window while gathering metadata in interactive mode. ([`fb5a39f`](https://github.com/Byron/dua-cli/commit/fb5a39ffb67fad80be0d2090efd34d259d439e98)) * **Uncategorized** - Release dua-cli v2.19.1 ([`e6c10c5`](https://github.com/Byron/dua-cli/commit/e6c10c5b311ad25d010f18d51f150d34bf62b815)) - Update dependencies ([`662e754`](https://github.com/Byron/dua-cli/commit/662e7541d32f3d5628bfa76e1caa5978caef8bb7)) - Draw window before processing events, fixes #143 ([`d957a61`](https://github.com/Byron/dua-cli/commit/d957a61ac79b990fa3cf470a9b500b6f390e3a18)) - Update dependencies ([`f7de1ab`](https://github.com/Byron/dua-cli/commit/f7de1abe9e023abfbc6c757b60085fa8e6ecb538)) - Create our own threadpool with minimal stack instead of using the global one. ([`7802985`](https://github.com/Byron/dua-cli/commit/78029853ba687cabd37adbbdf41b2ee480bbcbf8)) - Uprgade to latest `jwalk` version for more hang-safety ([`9bdf26a`](https://github.com/Byron/dua-cli/commit/9bdf26a7dbb7577ea10e0eac970c081a7bfa66a6))
## 2.19.0 (2022-12-13) ### New Features - Remove the handbrake on MacOS which can now deliver the expected performance. Previously it would limit itself to only using 4 threads as it would use a lot of time in user space. This has changed now, and the traversal itself is much more efficient (even though it could definitely be more efficient when comparing to `pdu`). In any case, counting performance should now greatly improve on M1 MacOS machines. ### Bug Fixes - resolve stalling issue of previous version. This way, this release is the working version of v2.8.1 . ### Commit Statistics - 3 commits contributed to the release. - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.19.0 ([`53a7d15`](https://github.com/Byron/dua-cli/commit/53a7d15a1e7bb0efb70264e9bebcb08cccfdb74a)) - Remove the handbrake on MacOS which can now deliver the expected performance. ([`f073375`](https://github.com/Byron/dua-cli/commit/f073375938f742db3259ec284c3c0d4a56fd0077)) - Resolve stalling issue of previous version. ([`d1cdfa1`](https://github.com/Byron/dua-cli/commit/d1cdfa1d682962deea5a0c48b90589becd6e19dc))
## 2.18.2 (2022-12-13) ### Bug Fixes - downgrade `jwalk` to 0.6 - the latest version does not actually iterate but instead keeps everything in memory. That's why `dua` didn't feel responsive anymore, was much slower and built up a lot of memory. ### Commit Statistics - 3 commits contributed to the release. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.18.2 ([`7633de4`](https://github.com/Byron/dua-cli/commit/7633de4956a5bd770b0db61f1e773b0cb6bfdfa8)) - Downgrade `jwalk` to 0.6 - the latest version does not actually iterate but instead keeps everything in memory. ([`3420dd4`](https://github.com/Byron/dua-cli/commit/3420dd4e14f3510662b58ae95ae7919ce0a98c95)) - Adjust maximum package size ([`8a4d8c2`](https://github.com/Byron/dua-cli/commit/8a4d8c27a8c94de6b62fb9d9bd5ba9031f9d6681))
## 2.18.1 (2022-12-13) Update all dependencies to the latest version. This most notably changes the look of the CLI to something without color by default thanks to the upgrade to `clap` 4. ### Chore - replace `colored` dependency with `owo-colors`. The latter provide zero-allocation coloring in the terminal and may improve compile times a little. ### Refactor - colored path printing; fix size column format ### Commit Statistics - 12 commits contributed to the release. - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Thanks Clippy [Clippy](https://github.com/rust-lang/rust-clippy) helped 2 times to make code idiomatic. ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.18.1 ([`58b53ff`](https://github.com/Byron/dua-cli/commit/58b53ff46274646833a0c07cf89d36301c0eb103)) - Prepare changelog prior to release ([`4f7915a`](https://github.com/Byron/dua-cli/commit/4f7915ac4226b98ca423cb2010a706379afe4cee)) - Upgrade to clap 4 ([`dd8b0ef`](https://github.com/Byron/dua-cli/commit/dd8b0ef8e12dfc8d7fb8f359f504c63034d60b9f)) - Upgrade sysinfo and make thread detection work for all Apple M series for now. ([`bbd5c67`](https://github.com/Byron/dua-cli/commit/bbd5c67342f9e5b509b0ab6e9ca2319c3c7605e2)) - Upgrade to trash v3.0 ([`bbd3a1c`](https://github.com/Byron/dua-cli/commit/bbd3a1ceaa15fb07c86ad9f4f5fcbaf991cb12af)) - Thanks clippy ([`82dc467`](https://github.com/Byron/dua-cli/commit/82dc4670bd9b3b93ae949022ecdc58ead79cf905)) - Update dependencies ([`0057c0d`](https://github.com/Byron/dua-cli/commit/0057c0d2ad0c1491ff1ffabc1aa5fea40539b942)) - Adjust journey-test expectations according to difference in color encoding. ([`b0bacad`](https://github.com/Byron/dua-cli/commit/b0bacadbeec4ed91bb7a4ab2d783ed0824173274)) - Replace `colored` dependency with `owo-colors`. ([`946806e`](https://github.com/Byron/dua-cli/commit/946806e7390799807361562b038fb12eeb2ddf11)) - Refactor ([`a734efb`](https://github.com/Byron/dua-cli/commit/a734efb7e332de6a3bb4911e72463e4f6fc342e1)) - Thanks clippy ([`44e19ee`](https://github.com/Byron/dua-cli/commit/44e19ee67924eb28b87698874d377a999cafceee)) - Colored path printing; fix size column format ([`d3fa946`](https://github.com/Byron/dua-cli/commit/d3fa946029ef44e5032762ff265180c23a629316))
## 2.18.0 (2022-09-12) ### Fixes - Remove a duplicate draw call which would have doubled the time it takes to refresh on user input. This might have been noticable when large amounts of files are displayed. ### Other - switch from colored to owo-colors owo-colors is well-maintained, zero-allocation, zero-dependencies crate for terminal colors. Also it works on any type that implements Display trait, not just on strings. ### New Features - Automatically resize if the terminal changes in size. ### Commit Statistics - 11 commits contributed to the release over the course of 54 calendar days. - 68 days passed between releases. - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - 1 unique issue was worked on: [#28](https://github.com/Byron/dua-cli/issues/28) ### Commit Details
view details * **[#28](https://github.com/Byron/dua-cli/issues/28)** - Automatically resize if the terminal changes in size. ([`28f5ac9`](https://github.com/Byron/dua-cli/commit/28f5ac90cc1ba7d668ae8a83eb5cd899294a8301)) * **Uncategorized** - Release dua-cli v2.18.0 ([`7fe68ea`](https://github.com/Byron/dua-cli/commit/7fe68ead0222467092f67d49855655faf6d61ee4)) - Update changelog ([`8dc45ab`](https://github.com/Byron/dua-cli/commit/8dc45abd15857cb11ab5567b83d507e4e3474b9e)) - Make sure the correct version of `crosstermion` is used ([`ed0bfc7`](https://github.com/Byron/dua-cli/commit/ed0bfc750a59d45fad04cb3a39b73e6f70512cee)) - Prepare changelog ([`50fd287`](https://github.com/Byron/dua-cli/commit/50fd2873257a17baa570d5f9826bcb0c83294059)) - Merge branch 'dep-upgrade' ([`20b7672`](https://github.com/Byron/dua-cli/commit/20b76721939b77dc6c9a86d3c5f4c22cc7f1cf65)) - Upgrade dependencies to tui 0.19/crossterm 0.25 ([`e35baea`](https://github.com/Byron/dua-cli/commit/e35baeaf25176e94ccc352b623f5cfd4b6b95b7b)) - Switch from colored to owo-colors ([`6a636d5`](https://github.com/Byron/dua-cli/commit/6a636d542594a76ef8b2faf2ec6347e4c8cb6b38)) - Add Apple M2 to default thread derivation ([`b5ec900`](https://github.com/Byron/dua-cli/commit/b5ec90042dec10fef8a35c27c2f7dcdb97b92293)) - 'Other' -> 'Pre-built binaries' for clarity ([`6bd4338`](https://github.com/Byron/dua-cli/commit/6bd433831850c2032674e440809ac86c0b8c6784)) - Add Scoop installation for Windows ([`8c67198`](https://github.com/Byron/dua-cli/commit/8c67198f6cc55bbc1a493f7a0e9fb5e9139d5ff3))
## 2.17.8 (2022-07-05) ### Bug Fixes - remove `chrono` from the dependency tree. This assures there is no possibility for undefined behaviour to to localtime support used by some of the `trash`-crate code otherwise. ### Commit Statistics - 4 commits contributed to the release. - 20 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.17.8 ([`a4de545`](https://github.com/Byron/dua-cli/commit/a4de54582b6eb98795a84b312d701953f28849ce)) - Speedup CI by adding a rust-cache ([`24df0b0`](https://github.com/Byron/dua-cli/commit/24df0b0fc24f5c6a4fe8a57a7023846309322d3f)) - Remove `chrono` from the dependency tree. ([`280d543`](https://github.com/Byron/dua-cli/commit/280d5436979f28c00b267d092e01c9675d3be7be)) - Dependency update ([`533b41d`](https://github.com/Byron/dua-cli/commit/533b41d22280450b883f6a2d340f5bb164e7221b))
## 2.17.7 (2022-06-14) ### Fixes - Improve readability of the currently visible path in light terminal color themes [(#129)](https://github.com/Byron/dua-cli/pull/129). ### Commit Statistics - 4 commits contributed to the release. - 2 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.17.7 ([`c0e3678`](https://github.com/Byron/dua-cli/commit/c0e3678c9f0eb61885c259b34355b4fd0ae0e3f3)) - Update changelog prior to release ([`d437ba5`](https://github.com/Byron/dua-cli/commit/d437ba59ea04a264c8f715248969d3f9daef7b87)) - Merge branch 'show-path' ([`1beb7d7`](https://github.com/Byron/dua-cli/commit/1beb7d7870a308e4829caada7ba3147326ffe0d4)) - Restyle for compatibility with 'light' color schemes ([`ed28cdb`](https://github.com/Byron/dua-cli/commit/ed28cdbe979cf1fa4a2eccfc3a851fd94f7f2695))
## 2.17.6 (2022-06-12) A maintenance release which should make the `ctrl + o` feature open files without blocking on linux thanks to an upgrade in the `open` crate which powers this feauture. ### Commit Statistics - 4 commits contributed to the release. - 29 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.17.6 ([`4105a50`](https://github.com/Byron/dua-cli/commit/4105a50a2ffb38ae37b3e1a49e4d3a345cc59fab)) - Update changelog prior to release ([`e20e9e0`](https://github.com/Byron/dua-cli/commit/e20e9e0bd3e3cd9525aa60655704df40bb8b448a)) - Upgrade 'open' to latest version ([`6806241`](https://github.com/Byron/dua-cli/commit/68062418a32e9e69c78c17e1b4c33703752a2a02)) - Dependency update ([`29a2abc`](https://github.com/Byron/dua-cli/commit/29a2abc33528ba9ddb8b62ad9dd98232bdf75aa9))
## 2.17.5 (2022-05-13) ### Bug Fixes - update to latest version of `trash` to improve trashing on linux See [their respective release](https://github.com/Byron/trash-rs/releases/tag/v2.1.2). ### Commit Statistics - 3 commits contributed to the release. - 1 day passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 2 unique issues were worked on: [#124](https://github.com/Byron/dua-cli/issues/124), [#127](https://github.com/Byron/dua-cli/issues/127) ### Commit Details
view details * **[#124](https://github.com/Byron/dua-cli/issues/124)** - Update to latest version of `trash` to improve trashing on linux ([`46a2871`](https://github.com/Byron/dua-cli/commit/46a2871dd81fd47dba550ddae2cfeed90d97189d)) * **[#127](https://github.com/Byron/dua-cli/issues/127)** - Fix installation instructions, for real this time ([`3c3355e`](https://github.com/Byron/dua-cli/commit/3c3355ed9bc12bbf5ae17b5fea6c58323426cff8)) * **Uncategorized** - Release dua-cli v2.17.5 ([`95fe11d`](https://github.com/Byron/dua-cli/commit/95fe11d8412b07e1143702aa269e90132cdddf99))
## 2.17.4 (2022-05-12) ### Bug Fixes - Show all possible information even if one input path could not be read. Previously it would fail entirely without printing anything useful but a relatively non-descript error message. - broken or non-existing root path will still print the valid results. Previously it would fail completely without printing anything. - Open interactive mode even if one of the input paths can't be read. Note that there can still be improvements in indicating which path failed. Also it will happily show an empty user interface in case all input paths are not readable. ### Commit Statistics - 6 commits contributed to the release. - 2 days passed between releases. - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - 1 unique issue was worked on: [#124](https://github.com/Byron/dua-cli/issues/124) ### Commit Details
view details * **[#124](https://github.com/Byron/dua-cli/issues/124)** - Update changelog prior to release ([`0348b7d`](https://github.com/Byron/dua-cli/commit/0348b7dedd99e079a73df5765bc3c4db4e1e6f07)) - Open interactive mode even if one of the input paths can't be read. ([`8742232`](https://github.com/Byron/dua-cli/commit/8742232a15c2bdd608c2e2c731a786c59c7d58dc)) - Broken or non-existing root path will still print the valid results. ([`75b3eed`](https://github.com/Byron/dua-cli/commit/75b3eed98f14d918f474f73caa3cdedd5af927ad)) - Record status quo ([`05e61a6`](https://github.com/Byron/dua-cli/commit/05e61a65e318694cfb2b98f9566bff817090d741)) * **Uncategorized** - Release dua-cli v2.17.4 ([`6ce80b1`](https://github.com/Byron/dua-cli/commit/6ce80b14e26d256c3d2936c32b64c1a80b684b6f)) - Merge branch 'broken-link-handling' ([`157b43c`](https://github.com/Byron/dua-cli/commit/157b43c2cb203c067c66f499a9fd849e5f0e811c))
## 2.17.3 (2022-05-10) ### Bug Fixes - dependency update; upgrade to trash v2.1.1 . The trash upgrade makes sure that trashed items on mount points on freedesktop are actually restorable. - broken or non-existing root path will still print the valid results. Previously it would fail completely without printing anything. ### Commit Statistics - 4 commits contributed to the release over the course of 3 calendar days. - 3 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 1 unique issue was worked on: [#123](https://github.com/Byron/dua-cli/issues/123) ### Commit Details
view details * **[#123](https://github.com/Byron/dua-cli/issues/123)** - Update readme to reflect the changes in install.sh ([`086d0b2`](https://github.com/Byron/dua-cli/commit/086d0b257cc7488132f8c5ea1b550f352e30e828)) * **Uncategorized** - Release dua-cli v2.17.3 ([`1f852ed`](https://github.com/Byron/dua-cli/commit/1f852ed5afd118d1f4804baf0574189f4d1f0b42)) - Dependency update; upgrade to trash v2.1.1 . ([`aa2646d`](https://github.com/Byron/dua-cli/commit/aa2646d5ae4d931ef15787a9723daa007add4a91)) - Fix cargo-diet check on CI ([`129c511`](https://github.com/Byron/dua-cli/commit/129c5114b15f1f644fa0c65266f13bed188ac161))
## 2.17.2 (2022-05-06) A maintenance release that updates all dependencies. Most notably, `trash-rs` includes a fix for properly moving files into the trash that required parent directories to be created. ### Commit Statistics - 4 commits contributed to the release over the course of 8 calendar days. - 46 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.17.2 ([`dd9f893`](https://github.com/Byron/dua-cli/commit/dd9f8933b75e052dbf3a13a9599061687690fcbe)) - Update changelog prior to release ([`70581b6`](https://github.com/Byron/dua-cli/commit/70581b6ff384309ddc56d2650c8fef1f41e88d28)) - Dependency update ([`8f3e157`](https://github.com/Byron/dua-cli/commit/8f3e157b86e7dd7c9669623aea03d7c74340d187)) - Update dependencies ([`d8eae6e`](https://github.com/Byron/dua-cli/commit/d8eae6e8cf788ea8d69b3e73e83027f2f0e44391))
## 2.17.1 (2022-03-20) ### Improvements to aggregate progress reporting Previously, aggregate mode progress reports were handled by an infinitely-looping thread carrying a 64-bit atomic of the current count, which it would print periodically. This resulted in #99 - breaking on platforms without 64-bit atomics, for which a feature was added to disable it. It also implied a race condition, where the "Enumerating ..." message could be printed after results had been gathered but before dua exited. Additionally, part of the status message could be left on the display if the first line of a report was too short to cover it. This commit should resolve these: - The 64-bit atomic counter is replaced with an 8-bit AtomicBool - All printing is controlled from the main thread - The first line is cleared prior to printing a report The only notable drawback I see with this approach is that progress reporting can sometimes be delayed, since the display is only evaluated for update during periods the aggregation loop makes progress. The practical difference appears relatively minor. Since this should resolve #99, the aggregate-scan-progress feature is removed. Special thanks to [@Freaky](https://github.com/Freaky) for the contribution! ### BREAKING change for package maintainers The `aggregate-scan-progress` feature was removed as it shouldn't be required anymore. ### Commit Statistics - 9 commits contributed to the release over the course of 55 calendar days. - 57 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.17.1 ([`48c4462`](https://github.com/Byron/dua-cli/commit/48c446294e8ac6b620a2b7fc7c15a4cf9f839452)) - Prepare changelog ([`fc1e10a`](https://github.com/Byron/dua-cli/commit/fc1e10a77da45d41c8243ddb07d7332ca8e23012)) - Improve aggregate progress reporting ([`7d83f96`](https://github.com/Byron/dua-cli/commit/7d83f965d620ccebeda9a7451cdbb2e40ed88c24)) - Update dependencies ([`9a1da6b`](https://github.com/Byron/dua-cli/commit/9a1da6bc4e964912a521b2f0de0bdf6124749ccd)) - Upgrade sysinfo ([`0b6b52f`](https://github.com/Byron/dua-cli/commit/0b6b52f02b72641a4954838fd9e2ea4fd0447e2d)) - Adjust to changes in clap ([`f9df024`](https://github.com/Byron/dua-cli/commit/f9df02420d7bd4e492c4a9130833fdf31e739909)) - Dependency update ([`0d9fbd3`](https://github.com/Byron/dua-cli/commit/0d9fbd386c51be1995aaee70d1a87a1217d9c550)) - Update clap to official release ([`b029dc5`](https://github.com/Byron/dua-cli/commit/b029dc5d190b23bf3e3fc95a3947f28f868e674e)) - Upgrade to TUI 0.17 ([`9ce96ac`](https://github.com/Byron/dua-cli/commit/9ce96ac7b89a1ee39cd85a7c18871309d5fe07af))
## 2.17.0 (2022-01-21) ### New Features - interactive mode learns 'toggle [a]ll' and 'remove [a]ll'. In the mark pane, the 'a' key will now toggle all entries. This is particularly interesting for selecting entries to exclude by hande and then invert the selection by toggling [a]ll. In the mark pane, toggling all with the 'a' key means removing all entries and closing the pane. ### Commit Statistics - 4 commits contributed to the release. - 12 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.17.0 ([`4025174`](https://github.com/Byron/dua-cli/commit/4025174e081c7820f8808262e67b96741bd44781)) - Interactive mode learns 'toggle [a]ll' and 'remove [a]ll'. ([`e268695`](https://github.com/Byron/dua-cli/commit/e2686952b4daf4c35303689c36bebc3dfe3faf29)) - Add documentation ([`6dbaa57`](https://github.com/Byron/dua-cli/commit/6dbaa570014f27b20ca719f5a092e768e4c8289d)) - Add `a` key to toggle marked status of all entries ([`15d0597`](https://github.com/Byron/dua-cli/commit/15d0597a51b166e022ba2d41c377d515a878c1a2))
## 2.16.0 (2022-01-09) ### New Features - Add `--ignore-dirs` option, with useful default on linux. On linux there are a few directories which shouldn't be traversed by default as they may cause hangs and blocking. With the new argument it's possible to specify absolute directories to not enter during traversal, with a default set to avoid problematic directories on linux right away. ### Bug Fixes - build on platforms without 64-bit atomics ### Commit Statistics - 9 commits contributed to the release over the course of 60 calendar days. - 74 days passed between releases. - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - 1 unique issue was worked on: [#116](https://github.com/Byron/dua-cli/issues/116) ### Commit Details
view details * **[#116](https://github.com/Byron/dua-cli/issues/116)** - Add `--ignore-dirs` option, with useful default on linux ([`26d6514`](https://github.com/Byron/dua-cli/commit/26d65145650cc3aac4ad540fdf04e95e139812e3)) * **Uncategorized** - Release dua-cli v2.16.0 ([`a132acb`](https://github.com/Byron/dua-cli/commit/a132acb8fa342e3f16b5f6a4bb31f5962a1f53c2)) - Update changelog ([`7abddbf`](https://github.com/Byron/dua-cli/commit/7abddbfc74e65ecaf3aa1f2cf7506daf3ddb4bd9)) - Build on platforms without 64-bit atomics ([`756ca54`](https://github.com/Byron/dua-cli/commit/756ca542a73575df581433fdd84cee8f4bef99b5)) - Release dua-cli v2.15.0 ([`4b71a56`](https://github.com/Byron/dua-cli/commit/4b71a56bc428663249b2f20dbf19507ad559967d)) - Update changelog ([`a226d1e`](https://github.com/Byron/dua-cli/commit/a226d1e8e4f0be2d9651950846424dda7e2c63b9)) - Upgrade clap ([`87d8c45`](https://github.com/Byron/dua-cli/commit/87d8c45b105722352f58b2020aaeaff62f3e00f6)) - Upgrade and update dependencies ([`269c650`](https://github.com/Byron/dua-cli/commit/269c650872b442e793604391cc5c94dc9fa592fc)) - Fix link to releases ([`c27da8b`](https://github.com/Byron/dua-cli/commit/c27da8b9bf3d2ea091ff9267d2e96df05a17bf05))
## 2.15.0 (2021-12-27) Make `dua` less prone to hanging by ignoring certain special directories on linux. ### New Features - Add `--ignore-dirs` option, with useful default on linux. On linux there are a few directories which shouldn't be traversed by default as they may cause hangs and blocking. With the new argument it's possible to specify absolute directories to not enter during traversal, with a default set to avoid problematic directories on linux right away. ## 2.14.11 (2021-10-26) ### Bug Fixes - `cargo install` without `--locked` should work now ### Commit Statistics - 5 commits contributed to the release. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 1 unique issue was worked on: [#111](https://github.com/Byron/dua-cli/issues/111) ### Commit Details
view details * **[#111](https://github.com/Byron/dua-cli/issues/111)** - Cargo install without --locked should work now ([`f26309c`](https://github.com/Byron/dua-cli/commit/f26309c91a271f1c2c32dfb55dbbb8c713f5e97d)) * **Uncategorized** - Release dua-cli v2.14.11 ([`7807c8a`](https://github.com/Byron/dua-cli/commit/7807c8aeef3953e4049f91fcc0597e4ff8018ed9)) - Adjust changelog ([`bd6a1fd`](https://github.com/Byron/dua-cli/commit/bd6a1fd6202a3d1cb0fd5b17bb858c04fd18235c)) - Thanks clippy ([`6cff8bc`](https://github.com/Byron/dua-cli/commit/6cff8bc4aea9ac0c93903fcf1357d29a3b9fea0b)) - Remove superfluous line in release.yml ([`a0625fc`](https://github.com/Byron/dua-cli/commit/a0625fc7070efbca360176aef1a522d2290da086))
## 2.14.10 (2021-10-26) ### Bug Fixes - see if releases work now with a different create-release action We are only interested in the upload_url, not in actually creating a release as smart-release does that already. ### Commit Statistics - 2 commits contributed to the release. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.14.10 ([`12e1ad8`](https://github.com/Byron/dua-cli/commit/12e1ad81f8e791b911520343540dfa39bcfc6ef2)) - See if releases work now with a different create-release action ([`e220eef`](https://github.com/Byron/dua-cli/commit/e220eef3f3fef4abed85807f8606b1c92527f950))
## 2.14.9 (2021-10-26) ### Bug Fixes - try to produce release binaries once more With smart-release, this is created automatically. ### Commit Statistics - 3 commits contributed to the release. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.14.9 ([`ea93ac3`](https://github.com/Byron/dua-cli/commit/ea93ac3efe09e043c6e6711abd0611a5d5af7228)) - Try to produce release binaries once more ([`d0c2c7c`](https://github.com/Byron/dua-cli/commit/d0c2c7cbac9b9dfa18a85a48098f1492c629bfd6)) - Update package size to match new changelog ([`9bfc2ea`](https://github.com/Byron/dua-cli/commit/9bfc2ea3040148c3c4e9dd03db3cc9a0b0e7eb0c))
## 2.14.8 (2021-10-26) ### Changed - auto-config support for Apple M1 Pro and Apple M1 Max ### Commit Statistics - 4 commits contributed to the release. - 38 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.14.8 ([`b9a9b3e`](https://github.com/Byron/dua-cli/commit/b9a9b3ec113430f44982e07c64bfbdde661779b6)) - Use `cargo changelog` ([`e0b8328`](https://github.com/Byron/dua-cli/commit/e0b8328bde652a02f1f764975a8bf4b2f3619e17)) - Cleanup changelog ([`c80b1c5`](https://github.com/Byron/dua-cli/commit/c80b1c5017f2679183d1dfc5edc6d379150fbe2a)) - Auto-config support for Apple M1 Pro and Apple M1 Max ([`49193f0`](https://github.com/Byron/dua-cli/commit/49193f0506946981bc056b29c3f09c94e30ac457))
## v2.14.7 (2021-09-18) - Fix deletion which broke with Rust 1.55, for those who are compiling the tool themselves. ### Commit Statistics - 3 commits contributed to the release. - 26 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.14.7 ([`07b934f`](https://github.com/Byron/dua-cli/commit/07b934f4e17e0b180d1734a810da3b533a29e43b)) - Prepare release ([`f5fd8c6`](https://github.com/Byron/dua-cli/commit/f5fd8c6bfa4fb3756b73e29fb53dd553b1c20710)) - Fix deletion process on Rust 1.55 ([`f45681a`](https://github.com/Byron/dua-cli/commit/f45681aa523fa6cc9d451ef46a8ce62f2ef99bf8))
## v2.14.6 (2021-08-22) - Support for arrow keys as well as Home & End. The help pane was updated to reflect these changes. - More readable information on how to delete or trash files in the mark pane. ### Commit Statistics - 8 commits contributed to the release over the course of 3 calendar days. - 5 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.14.6 ([`c148b77`](https://github.com/Byron/dua-cli/commit/c148b779e9eb1ef109fe9276fc378c9d7a553e37)) - Update change log ([`f48b181`](https://github.com/Byron/dua-cli/commit/f48b181d56d89c3028eb055c80bdf447fe65595d)) - Merge branch 'style' ([`5904630`](https://github.com/Byron/dua-cli/commit/5904630cfebd4e99bc4ee7a9c23550f85add41d4)) - Update changelog ([`58bcf90`](https://github.com/Byron/dua-cli/commit/58bcf90ffec21edea8327ba11b6bbc6fcf1440c1)) - Support Home/End and fix inconsistent help text ([`29017f6`](https://github.com/Byron/dua-cli/commit/29017f6f94003f58118ad7d1fded1d47f79349eb)) - Improve mark widget tip style ([`019e4cb`](https://github.com/Byron/dua-cli/commit/019e4cb65e6d6302e08692c446bac56fb3beee25)) - Format correctly ([`8977c17`](https://github.com/Byron/dua-cli/commit/8977c17bcb10373c33d695dd682781fd9590e4e7)) - Remove unnecessary line ([`d6bbb6d`](https://github.com/Byron/dua-cli/commit/d6bbb6dd91b5367f8bd1f8569d39dbb30b8f89a2))
## v2.14.5 (2021-08-16) - Fix installation via `cargo install dua-cli`. Please note that it might break again as it still depends on the unsable `clap-3 beta 4`. Even when pinning it breakage is possible as its dependencies itself aren't pinned. ### Commit Statistics - 5 commits contributed to the release over the course of 11 calendar days. - 11 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Release dua-cli v2.14.5 ([`b74388c`](https://github.com/Byron/dua-cli/commit/b74388c7f6bc5a759663b98c8fa95db1e0941691)) - Fix #102, bump patch level ([`3a6c654`](https://github.com/Byron/dua-cli/commit/3a6c654dc2939b5979c47d8fbd14932741f8d1d1)) - Add NetBSD installation instructions ([`9501d08`](https://github.com/Byron/dua-cli/commit/9501d087d03801568d36df5ebba03515c36e592a)) - Sysinfo upgrade ([`6827975`](https://github.com/Byron/dua-cli/commit/6827975b74e5cc66ffb7397e5fb3a144d287f1d5)) - Add aggregate-scan-progress feature to help with #99 ([`7429cb3`](https://github.com/Byron/dua-cli/commit/7429cb3d1139605abdf3efcb8a4d5cceb300be1b))
## v2.14.4 (2021-08-05) - upgrade depencies - upgrade to tui 0.16 ### Commit Statistics - 3 commits contributed to the release over the course of 6 calendar days. - 11 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Thanks Clippy [Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. ### Commit Details
view details * **Uncategorized** - (cargo-release) version 2.14.4 ([`3987e7c`](https://github.com/Byron/dua-cli/commit/3987e7c51b4b27fd4c95def42ce3e585dc46c7c6)) - Update dependencies; upgrade to tui-0.16 ([`80a40e5`](https://github.com/Byron/dua-cli/commit/80a40e583791caff575eea257ae7a38fadbc9542)) - Thanks clippy ([`4598d64`](https://github.com/Byron/dua-cli/commit/4598d64a1150967e48013091e044eae851de62f9))
## v2.14.3 (2021-07-25) - upgrade `open` crate to v2 ### Commit Statistics - 2 commits contributed to the release. - 11 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - (cargo-release) version 2.14.3 ([`8222d99`](https://github.com/Byron/dua-cli/commit/8222d993a3afd05e17566b6b30d349b6e4080e0d)) - Upgrade open to v2 ([`98c859c`](https://github.com/Byron/dua-cli/commit/98c859c71d9ee4be4c19bc436a494f035a241bc1))
## v2.14.2 (2021-07-14) - `Ctrl-T` to trash (instead of removal) is now an optional default feature, allowing it to be disabled on FreeBSD which isn't currently supported. - Update dependencies ### Commit Statistics - 10 commits contributed to the release. - 14 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - (cargo-release) version 2.14.2 ([`64a5589`](https://github.com/Byron/dua-cli/commit/64a5589ef93c03cfb0815e893250918dde6a9ea6)) - Update changelog ([`e037a96`](https://github.com/Byron/dua-cli/commit/e037a96682b816a1855578cd08bb90dd8e123570)) - Also run 'make check' on CI now that more feature toggles are added ([`9d2f969`](https://github.com/Byron/dua-cli/commit/9d2f969772306b35eab0b74cb792aac79d1d6af1)) - Merge branch 'optional-trash' ([`b12b98a`](https://github.com/Byron/dua-cli/commit/b12b98a07935c839a11af08cfa9dc872b5a127e8)) - Disable test that now starts failing on windows even though… ([`64175e0`](https://github.com/Byron/dua-cli/commit/64175e028965958d0c22f8ffe55cab2fc01f9fc8)) - Dependency upgrade: petgraph 0.6 ([`b4aeb14`](https://github.com/Byron/dua-cli/commit/b4aeb149cffae440560b54dcae6211eef51e85e4)) - Dependency update ([`163bd47`](https://github.com/Byron/dua-cli/commit/163bd4764c7b8d35eb8a49af8e96c61430621b20)) - Refactor ([`6894dd8`](https://github.com/Byron/dua-cli/commit/6894dd8db51cd6fe8a70ad0c906ef351dc0a720c)) - Add checking and testing of new feature toggle ([`ee680b9`](https://github.com/Byron/dua-cli/commit/ee680b9b82618a1d5ecab1fb2e431fe3ff64d130)) - Make the trash feature optional ([`1fdded1`](https://github.com/Byron/dua-cli/commit/1fdded129fe766729ac332fa881c0681c9495316))
## v2.14.1 (2021-06-30) - Pressing `ctrl+t` in the mark pane now trashes entries instead of deleting them. Not only does that make 'deletion' reversible but it makes removal of the entry faster in many cases as well. - updated dependencies ### Commit Statistics - 5 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - (cargo-release) version 2.14.1 ([`5ecd90f`](https://github.com/Byron/dua-cli/commit/5ecd90fb400c61649826d80c0d1348affd10087e)) - Upgrade sysinfo ([`e1b8a01`](https://github.com/Byron/dua-cli/commit/e1b8a01579e211c268356ea25c56cfb9391ca717)) - Prepare patch release ([`0bf969f`](https://github.com/Byron/dua-cli/commit/0bf969f7017f34e626ee892f24e7bacc62e0a5c5)) - Cargo fmt ([`97a9804`](https://github.com/Byron/dua-cli/commit/97a980436ab46693804ad0a361ab0388f34c8381)) - Dependency update ([`93cd08d`](https://github.com/Byron/dua-cli/commit/93cd08df930e7f5f5164bc2b9d0979a5794c05be))
## v2.14.0 (2021-06-30) ### Other - deduplicate code ### Commit Statistics - 7 commits contributed to the release. - 20 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Thanks Clippy [Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. ### Commit Details
view details * **Uncategorized** - (cargo-release) version 2.14.0 ([`bbc0719`](https://github.com/Byron/dua-cli/commit/bbc0719d489d0484e7f770129fad9839ed2cc5c9)) - Prep changelog ([`e7de79a`](https://github.com/Byron/dua-cli/commit/e7de79af3304ad9ed70cdf2e9fbe8ad4c765317a)) - Merge branch 'trash' ([`64d8dc8`](https://github.com/Byron/dua-cli/commit/64d8dc8b9baf0fd2e8942b1391f783fe8a7d4586)) - Thanks clippy ([`68bbb68`](https://github.com/Byron/dua-cli/commit/68bbb68ffd4887d2023a520e4dfc69b9d8edc736)) - Add mark pane prompt message for ctrl + t ([`af538bc`](https://github.com/Byron/dua-cli/commit/af538bc545c3b3b7c0a3d5541a1a80b0da536e5b)) - Deduplicate code ([`02dd1b7`](https://github.com/Byron/dua-cli/commit/02dd1b72c8fe741fb153094fdb08816f7f593c6f)) - Implement Ctrl+t move to trash ([`00fae90`](https://github.com/Byron/dua-cli/commit/00fae90e0dffc468c75bd362fa4220bc8650fb86))
## v2.13.1 (2021-06-09) - Allow usage of the feature introduced in v2.13 by writing the TUI to stderr instead of stdout. That way the output can be redirected. ### Other - deduplicate code ### Commit Statistics - 3 commits contributed to the release. - 1 day passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - (cargo-release) version 2.13.1 ([`5534cd7`](https://github.com/Byron/dua-cli/commit/5534cd7126eada8a040f00cd996295dfd42cb4c1)) - Prepare for version bump ([`d0150a8`](https://github.com/Byron/dua-cli/commit/d0150a8686b8265ca92a930b2d3676e1c89e2402)) - Show TUI on stderr to enable writing files to stdout ([`a93a642`](https://github.com/Byron/dua-cli/commit/a93a642765540d4010dc2fab90737cd39abaa32d))
## v2.13.0 (2021-06-08) - Print remaining marked paths upon exit on stdout. This may help to use `dua i` with other programs who want to process the marked paths on their own. ### Commit Statistics - 3 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - (cargo-release) version 2.13.0 ([`1bfcc63`](https://github.com/Byron/dua-cli/commit/1bfcc6306739f4dfbe076acdbe53bf59143e9245)) - Prepare release ([`140a656`](https://github.com/Byron/dua-cli/commit/140a6560b57aec819ba678e2f9c9a1d975c794af)) - Print marked items upon exit if these are left in the marked pane ([`017cbd7`](https://github.com/Byron/dua-cli/commit/017cbd7b4c3e57e1a98fbc595159be39bc97c708))
## v2.12.2 (2021-06-07) - Prepare for release of new Apple hardware and be more specific when auto-configuring the correct amount of threads. Instead an error message will be printed to inform that the given CPU brand isn't configurable yet. ### Commit Statistics - 6 commits contributed to the release over the course of 1 calendar day. - 7 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - (cargo-release) version 2.12.2 ([`c8d5650`](https://github.com/Byron/dua-cli/commit/c8d5650be77e000801b282c4c0a3861e710de6d8)) - Prepare new release ([`f45852a`](https://github.com/Byron/dua-cli/commit/f45852a5880fbcd9670f0de3643ea9614ec35de4)) - Set default processor count on Apple Silicon in a way that won't be totally wrong in future ([`fe9611a`](https://github.com/Byron/dua-cli/commit/fe9611a7fd9a1592cc1a4517948b4a32fba904c9)) - Refactor ([`c3c103e`](https://github.com/Byron/dua-cli/commit/c3c103eebd82fc729788694a9f3bfd4ded855cf8)) - Dependency update ([`1fb6bad`](https://github.com/Byron/dua-cli/commit/1fb6badaf653305618c62f7ba4f4332c1c1ab959)) - Refactor ([`115db26`](https://github.com/Byron/dua-cli/commit/115db26ab86fcb50dd14b12b64240b66bbac53f1))
## v2.12.1 (2021-05-30) - Fixed bug that would cause `dua` to unconditionally sleep for 1 second. This sleep was intended for a spawned thread, but it slipped into the main thread. ### Commit Statistics - 5 commits contributed to the release over the course of 1 calendar day. - 1 day passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - (cargo-release) version 2.12.1 ([`06377e5`](https://github.com/Byron/dua-cli/commit/06377e560488e16da185c68c2a0069fd4389fe59)) - Fix terrible bug causing an unnecessary wait in front of each invocation ([`ac604b3`](https://github.com/Byron/dua-cli/commit/ac604b35c0b80fa6b380cc395a95bf0a5d1d196d)) - Fix tests ([`dfb40a2`](https://github.com/Byron/dua-cli/commit/dfb40a20d1e697d2f3fc3a159febf9adb3a817b2)) - Only fetch metadata for files for a speedup ([`d381c6c`](https://github.com/Byron/dua-cli/commit/d381c6caed1fd404d7a11c1f581abdba749b7a20)) - Mildly optimize progress performance… ([`ffdb0c2`](https://github.com/Byron/dua-cli/commit/ffdb0c270f9c07a3518e2335ee77d7788bfc7793))
## v2.12.0 (2021-05-29) YANKED. - Add minimal progress for when `dua` invocations take longer than 1 second ### Commit Statistics - 5 commits contributed to the release. - 19 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Thanks Clippy [Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. ### Commit Details
view details * **Uncategorized** - (cargo-release) version 2.12.0 ([`939af68`](https://github.com/Byron/dua-cli/commit/939af68f2a50d67e1c85acac49b4047e3dcbe5a9)) - Only display progress on if stderr is a tty ([`a0d6288`](https://github.com/Byron/dua-cli/commit/a0d628898226e272e9f29137da148991e07f3641)) - Add simple progress to indicate something is happening on long `dua` runs ([`e68481f`](https://github.com/Byron/dua-cli/commit/e68481f3524d214b76d2895a10febc3a524c3256)) - Thanks clippy ([`78a68b1`](https://github.com/Byron/dua-cli/commit/78a68b1a9ed5d39d250c5478041e40425a198756)) - Add similar programs to README ([`60f4324`](https://github.com/Byron/dua-cli/commit/60f432417fe2adbbd54de7293f1c3ffcd45365f7))
## v2.11.3 (2021-05-09) - re-add arm builds - dependency updates (including tui 0.15) ### Commit Statistics - 4 commits contributed to the release. - 6 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - (cargo-release) version 2.11.3 ([`41f0e6d`](https://github.com/Byron/dua-cli/commit/41f0e6d37448535af0bf3ce504e62ec622a2dc74)) - Prepare releas ([`08eb0e2`](https://github.com/Byron/dua-cli/commit/08eb0e2034779bd0df7899f75cbd30531103cd9c)) - Dependency updates ([`25f0cb0`](https://github.com/Byron/dua-cli/commit/25f0cb08613be98b84845c49b345921e0a78342b)) - Re-add arm builds ([`a7db17d`](https://github.com/Byron/dua-cli/commit/a7db17de1528dedd6bcc083a28e575eb9be34885))
## v2.11.2 (2021-05-03) - dependency updates (including tui 0.15) ### Commit Statistics - 16 commits contributed to the release over the course of 40 calendar days. - 69 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Thanks Clippy [Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. ### Commit Details
view details * **Uncategorized** - Adjust release workflow to be less specific to ripgrep ([`4becf36`](https://github.com/Byron/dua-cli/commit/4becf36bb16054e9939fb48d45d57e1e7da1e603)) - Upgrade release workflow file from ripgrep ([`12a01f1`](https://github.com/Byron/dua-cli/commit/12a01f136b04fc633ffe09939343ce1cbc9cc886)) - (cargo-release) version 2.11.2 ([`1ffc52e`](https://github.com/Byron/dua-cli/commit/1ffc52e0a93150f3d0d488ceb515ce5f4caea816)) - Fix build (use the latest version of crosstermion, too) ([`b675446`](https://github.com/Byron/dua-cli/commit/b6754461bcb7bfbd1794986e41114f59738fa955)) - Remove tui-react, it now lives in https://github.com/Byron/tui-crates ([`1ddbeae`](https://github.com/Byron/dua-cli/commit/1ddbeae87dc0c23edf412405d6a08696bc703c1b)) - Prepare changelog for patch release ([`e16a3e4`](https://github.com/Byron/dua-cli/commit/e16a3e4908cdfed103c0c1d5e54c31f1c90d40df)) - [dua] actually upgrade to tui 0.15 ([`296b5a7`](https://github.com/Byron/dua-cli/commit/296b5a7172233b030a3995aa72c361873029bc65)) - [dua] upgrade to tui 0.15 ([`a9ce757`](https://github.com/Byron/dua-cli/commit/a9ce7578bcbc088c8b18e33de83860e10991bf85)) - [tui-react] upgrade tui to 0.15 ([`27fb521`](https://github.com/Byron/dua-cli/commit/27fb5214e8f2c4669faf093a2ca570da17deca37)) - Fix help menu typo ([`98d973f`](https://github.com/Byron/dua-cli/commit/98d973fdf1cea099bfe963e9b1736ab2cac08a35)) - Add installation instructions via homebrew ([`94b8cfb`](https://github.com/Byron/dua-cli/commit/94b8cfb9250da9f77f857b615a1461e748e04a27)) - Dependency update ([`3f335f0`](https://github.com/Byron/dua-cli/commit/3f335f033a10381a61918bc87c40d461d9c1de8a)) - Run actions on main ([`7f3c3a4`](https://github.com/Byron/dua-cli/commit/7f3c3a4facebcd6daf2c8532087204904adf38d0)) - Enable funding ([`6907724`](https://github.com/Byron/dua-cli/commit/6907724b1856466d9603fcab1b59450e6973aadb)) - New resolver using Rust 1.51 ([`1575ad2`](https://github.com/Byron/dua-cli/commit/1575ad2441c9e4ec034c4256237c7f22908eb875)) - Thanks clippy ([`59279d4`](https://github.com/Byron/dua-cli/commit/59279d464aac8c3985720d1d46b0a190b4443d2f))
## v2.11.1 (2021-02-22) - The `-x/--stay-on-filesystem` flag is now respected for multiple root paths, as in `dua -x path-FS1/ path-FS2/`, as such `dua` will stay in FS1 if the CWD is in FS1. ### Other - add MacPorts install instructions ### Commit Statistics - 5 commits contributed to the release over the course of 5 calendar days. - 6 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - (cargo-release) version 2.11.1 ([`2808ff6`](https://github.com/Byron/dua-cli/commit/2808ff645f421aa2b098e3245e76890edad7ce98)) - Update changelog ([`e5d3752`](https://github.com/Byron/dua-cli/commit/e5d3752c296a859711cf158f1f84a5829bcfa333)) - Respect 'stay_on_filesystem' when no input files are provided ([`33f81d6`](https://github.com/Byron/dua-cli/commit/33f81d6f56d1c324548a7b6d8a06bac168821516)) - Update dependencies ([`ae5c9b8`](https://github.com/Byron/dua-cli/commit/ae5c9b896b83b0841069908bc2220312591ed197)) - Add MacPorts install instructions ([`59315b7`](https://github.com/Byron/dua-cli/commit/59315b7c63b7328fa70bfe5fc43fdbe9dc5f92e7))
## v2.11.0 (2021-02-15) ### Features - Add binding capital 'H' to go to the top of any pane/list - Add binding capital 'G' to go to the bottom of any pane/list ### Fixes - Without user input during `dua i []` the top-most entry will remain selected. - Avoid stale frame at the end of traversal in interactive sessions when there is no user input. ### Commit Statistics - 6 commits contributed to the release. - 23 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Thanks Clippy [Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. ### Commit Details
view details * **Uncategorized** - (cargo-release) version 2.11.0 ([`3f4773f`](https://github.com/Byron/dua-cli/commit/3f4773feb937e461b3596fbf13ec28409efb4acc)) - Adjust changelog prior to release ([`ad7c779`](https://github.com/Byron/dua-cli/commit/ad7c7796ecea46557ab851eb15ed2a20fd1e2447)) - Enforce drawing once after traversal is done ([`ee73690`](https://github.com/Byron/dua-cli/commit/ee7369022611745ec9c55beddf1b907f13ed3559)) - Keep selecting the first element during iteration unless… ([`6d7b3cd`](https://github.com/Byron/dua-cli/commit/6d7b3cd062214f2cc66886d49d1a60406204abf3)) - Thanks clippy ([`6ca9e6c`](https://github.com/Byron/dua-cli/commit/6ca9e6ca52a4d4d32036df2914ee773ab313397b)) - Add bindings 'H' and 'G' to go to the top/bottom of any pane ([`8b606ac`](https://github.com/Byron/dua-cli/commit/8b606ac464ec5fa3979ab73fef4d29733d389760))
## v2.10.10 (2021-01-23) Fix --version flag. It looks like the latest BETAs of clap removed setting the version implicitly. ### Other - fix typo ### Commit Statistics - 4 commits contributed to the release over the course of 15 calendar days. - 15 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - (cargo-release) version 2.10.10 ([`8cc2f44`](https://github.com/Byron/dua-cli/commit/8cc2f44b4cd89cc046f1748f664d112d0278aa6d)) - Fix --version ([`1ba3c1c`](https://github.com/Byron/dua-cli/commit/1ba3c1cce9ae9419633f1e197b76c87649e9174a)) - Dependency update ([`8b602bd`](https://github.com/Byron/dua-cli/commit/8b602bd31fb172fb7f222e68d320787315fbcefb)) - Fix typo ([`9384cdb`](https://github.com/Byron/dua-cli/commit/9384cdb5b95e5260f46ccd23e7ca276304190a34))
## v2.10.9 (2021-01-07) Fix build. Now that `jwalk` was released in v0.6 with v0.5.2 yanked, `cargo install` will use the previous version v0.5.1 which does not fit the latest `dua` anymore. This is now fixed and hopefully permanently so thanks to using `jwalk` v0.6. ### Commit Statistics - 4 commits contributed to the release over the course of 3 calendar days. - 3 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - (cargo-release) version 2.10.9 ([`d5bd682`](https://github.com/Byron/dua-cli/commit/d5bd68259678f48b61608245c1444ffa297131bd)) - Fix jwalk, the other way around; related to #72 ([`0b0265d`](https://github.com/Byron/dua-cli/commit/0b0265df38adacb86d9b39986c251490eebfb232)) - Upgrade to tui 14 ([`27e65a2`](https://github.com/Byron/dua-cli/commit/27e65a2fc91b22cb5816864f51d1d3a3ce11a94a)) - Bump tui version to 0.14 ([`d32ab34`](https://github.com/Byron/dua-cli/commit/d32ab34e2b8521ddbbbaacd08d48b983cb792432))
## v2.10.8 (2021-01-04) Fix build. A breaking change in jwalk can cause builds to fail. This prevents the issue from spreading at least with dua-cli. ### Other - bump itertools 0.9.0 -> 0.10.0 ### Commit Statistics - 5 commits contributed to the release over the course of 18 calendar days. - 18 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - (cargo-release) version 2.10.8 ([`523a0c6`](https://github.com/Byron/dua-cli/commit/523a0c6f44f767115da631b85e479d5cedd75674)) - Update changelog ([`3cb794d`](https://github.com/Byron/dua-cli/commit/3cb794dc89ce13cf10632de13d1f8ec91646c537)) - Bump itertools 0.9.0 -> 0.10.0 ([`dc100c8`](https://github.com/Byron/dua-cli/commit/dc100c8b4a838c92f39d5a67da7eea06e7dec9af)) - Dependency update ([`420f1f6`](https://github.com/Byron/dua-cli/commit/420f1f677b77acd73729df19edf2849c65d8d33b)) - Increase crate size limit ([`041e218`](https://github.com/Byron/dua-cli/commit/041e218c47f77ea60e982a4e92209e5574cf6336))
## v0.14.0 (2021-01-04) ## v2.10.7 (2020-12-16) Better performance on Apple Silicon (M1). The IO subsystem on Apple Silicon is different and won't scale nicely just by using all amount of available cores. Instead it seems best to only use as many threads as performance cores are present on the system - otherwise the performance might actually get worse while using more power. On all other systems, the default number of threads did not change. **Please note that for optimial performance** one would need an arm build on MacOS, currently provided is only intel builds. ### Commit Statistics - 6 commits contributed to the release over the course of 9 calendar days. - 31 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Dependency update ([`019ec45`](https://github.com/Byron/dua-cli/commit/019ec459b853095aa322a2e297039eea5a5f5939)) - (cargo-release) version 2.10.7 ([`d1faaac`](https://github.com/Byron/dua-cli/commit/d1faaac20efd8eda07ff8564e834eae8062a5828)) - Prepare next release ([`20d9094`](https://github.com/Byron/dua-cli/commit/20d9094a6d604badc4e70c9d1f45bca65f35c849)) - Select better default thread count on Apple Silicon (M1) ([`a1cf012`](https://github.com/Byron/dua-cli/commit/a1cf012f36269d97953baac9288b2fc5551bc6a0)) - Hopefully fix release pipeline ([`7c40f95`](https://github.com/Byron/dua-cli/commit/7c40f95b4e05eacfbdb0e3267d443f4642c9f80b)) - Dependency update ([`848c3ed`](https://github.com/Byron/dua-cli/commit/848c3edc45ef645f8403673dfca9764f62ecb51e))
## v2.10.5 (2020-11-15) Dependency update. - upgrade to TUI v0.13.0 ### Commit Statistics - 3 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Bump patch level ([`a13e27b`](https://github.com/Byron/dua-cli/commit/a13e27be7d01f226baeabf04c1007f85d3e5b849)) - Custom usage to fix #71 ([`018b00d`](https://github.com/Byron/dua-cli/commit/018b00db339f9772922007e293567231164b330b)) - Switch from structup to clap 3 beta.2 ([`5782c4f`](https://github.com/Byron/dua-cli/commit/5782c4ff99b70ea101ed2f36711a456fd4e4e37b))
## v2.10.4 (2020-11-15) ### Commit Statistics - 8 commits contributed to the release over the course of 19 calendar days. - 30 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Patch bump ([`88753aa`](https://github.com/Byron/dua-cli/commit/88753aa6d6a7d23a7d4334b7913655009adfc079)) - Upgrade to tui 0.13 ([`98da03d`](https://github.com/Byron/dua-cli/commit/98da03d4db2edf8d4ab37d761ec166f467d4cab8)) - Update tui-react to tui v0.13 ([`2d11a19`](https://github.com/Byron/dua-cli/commit/2d11a191fbdccd3e16b6542743854151d4ebbc5d)) - Dependency update ([`daad381`](https://github.com/Byron/dua-cli/commit/daad3817e314b972294730c880536142521dee30)) - Show 'scanning' note even without entering a directory ([`8992625`](https://github.com/Byron/dua-cli/commit/8992625fe2bfc8ceb371a86733bb3900e4caf3d9)) - Update README to reflect only working installation methods ([`9a38f1f`](https://github.com/Byron/dua-cli/commit/9a38f1fc12a3326646e053b4700dd0a593ffbde8)) - Disable release-build test mode in preparation for merge ([`24f040a`](https://github.com/Byron/dua-cli/commit/24f040a27a3afbab63b439439afd65d53602dd5e)) - See if ARM works again ([`db47b37`](https://github.com/Byron/dua-cli/commit/db47b375db9ee8a94aec40d6c0ac430085f6bab1))
## v0.13.0 (2020-11-15) ## v0.0.1 (2020-10-26) ## v2.10.3 (2020-10-15) Dependency update. Should fix [this issue](https://github.com/Byron/dua-cli/issues/66) ### Commit Statistics - 9 commits contributed to the release over the course of 42 calendar days. - 79 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - (cargo-release) version 2.10.3 ([`c32322f`](https://github.com/Byron/dua-cli/commit/c32322f29a120712a75f95585e4d3a3d700c538b)) - Dependency update ([`6cb8209`](https://github.com/Byron/dua-cli/commit/6cb8209d48f0832b99f497c011c81d1e1a7c6a95)) - Dependency update ([`c7cdf36`](https://github.com/Byron/dua-cli/commit/c7cdf368a06797e8ca73a3c621a3e451883c0937)) - Provide alternative installation instructions for linux ([`53d31a7`](https://github.com/Byron/dua-cli/commit/53d31a76242dcf4b2395526beadbb34a48164c7e)) - Upgrade to latest version of tui ([`872bbbc`](https://github.com/Byron/dua-cli/commit/872bbbc0d630ce5ccf17a6847c6b12846f745997)) - Update to tui 0.12 ([`3e1b8c2`](https://github.com/Byron/dua-cli/commit/3e1b8c202638b5067f794f8d3687834eb3d4b450)) - Dependency update ([`9a877e2`](https://github.com/Byron/dua-cli/commit/9a877e2401b1d5f5751047867a7067fd7fdc473c)) - Dependency update ([`56a365b`](https://github.com/Byron/dua-cli/commit/56a365b5ee21f09bb80afb32d0184b150f16f4c2)) - Dependency update ([`dadb3fe`](https://github.com/Byron/dua-cli/commit/dadb3fe70d3bb15a5cc1f2e5d8d0307faaa9d702))
## v0.12.0 (2020-09-28) ## v2.10.2 (2020-07-27) Change light-grey color in command-line mode to Cyan to fix disappearing text. ### Commit Statistics - 3 commits contributed to the release. - 3 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Bump patch level ([`b38d234`](https://github.com/Byron/dua-cli/commit/b38d23483973595940d500310a89ec3f525895be)) - Refactor ([`cdc5ee3`](https://github.com/Byron/dua-cli/commit/cdc5ee36d2c7c6bc6ecc9676ebaa408066a9eb5a)) - Src, aggregate: fix colors for aggregate mode ([`4d2e839`](https://github.com/Byron/dua-cli/commit/4d2e83904fd66a3d480b5f50ad6fa2192d113a3f))
## v2.10.1 (2020-07-24) Change light-grey color in interactive mode to Cyan to fix disappearing text. See [this PR](https://github.com/Byron/dua-cli/pull/62) for reference. ### Commit Statistics - 4 commits contributed to the release. - 1 day passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - (cargo-release) version 2.10.1 ([`31c588e`](https://github.com/Byron/dua-cli/commit/31c588eaf30f34f2df23c3cc28ee8aebe5a01ca0)) - Update changelog ([`c939b2c`](https://github.com/Byron/dua-cli/commit/c939b2c9a1405a9f364a10c2f692267f0879e1df)) - Fix styling for folders (cyan=folders, not chagned - regular files) ([`2cc6916`](https://github.com/Byron/dua-cli/commit/2cc69169282a07a485992bf95969cf6f81981b08)) - Fix clippy warnings ([`292c4d3`](https://github.com/Byron/dua-cli/commit/292c4d30722592b3e5ab1d779b5502cb0d129999))
## v2.10.0 (2020-07-22) Minor improvements of looks; improved windows support. - previously in interactive mode on Windows, directory sizes would appear as 0 bytes in size. This is now fixed! ### Commit Statistics - 33 commits contributed to the release over the course of 14 calendar days. - 15 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Arm also has a problem now - ignore it for now ([`04b9e52`](https://github.com/Byron/dua-cli/commit/04b9e52b9edf5f1b0490e7a55ec99891cf404b46)) - And one more… ([`601eee2`](https://github.com/Byron/dua-cli/commit/601eee2219f6f135e65b5783e3180a82d8f316c0)) - Nigthly is definitely required for windows builds, let's hope that works ([`5b7696c`](https://github.com/Byron/dua-cli/commit/5b7696cb2c40a14a5deb26193d8d74212a01c141)) - Seems nightly is broken right now - stable it is everywhere ([`d7a7f9c`](https://github.com/Byron/dua-cli/commit/d7a7f9ccf810f90e80b4b04c0252ed8eab2b17e7)) - Try again to make things build on linux, argh! ([`f520072`](https://github.com/Byron/dua-cli/commit/f5200723e8cda73045be4a65c4bf11ad9a4a023d)) - Try to build on stable on arm (which fails otherwise now) ([`8efa046`](https://github.com/Byron/dua-cli/commit/8efa04659864c9260deca6515a6b0428cc4278ae)) - Minor style improvements to handle special case ([`69a2490`](https://github.com/Byron/dua-cli/commit/69a2490844d87c09cd5cc51da49e3cd87a03c35a)) - Avoid jump when cycling through byte visualization ([`4f91292`](https://github.com/Byron/dua-cli/commit/4f912929f213c00f6721995bfc5ee0b8879d80e9)) - (cargo-release) version 0.10.1 ([`b5d1a21`](https://github.com/Byron/dua-cli/commit/b5d1a21e50f2d64abeb79c9c108839c1fb27bb0e)) - Fix incorrect render area of tui-react list ([`3715b71`](https://github.com/Byron/dua-cli/commit/3715b714c83cdbbe7230d85ae87e5f93c07160e0)) - Fix mark pane ([`b4476ba`](https://github.com/Byron/dua-cli/commit/b4476bac270e2d1cdeb0f28bf7528d95b770a7e3)) - Help is back to normal ([`8c2a174`](https://github.com/Byron/dua-cli/commit/8c2a174ed31cfc6e7095cf1cf4dbc24bf38ea975)) - Help looks better now, but is far from 'normal' ([`29ee421`](https://github.com/Byron/dua-cli/commit/29ee421dd40666c53f659692a9a55cf8874cee1a)) - Switch to crosstermion 0.3 for tui 0.10 support ([`fd8c441`](https://github.com/Byron/dua-cli/commit/fd8c441af3739027b7959a21b530ddb4da455f73)) - Merge remote-tracking branch 'origin/master' ([`4812206`](https://github.com/Byron/dua-cli/commit/4812206eab68ea5588d93f9ea0589f9e772ee5ad)) - Use published version of tui-react ([`ed1f91b`](https://github.com/Byron/dua-cli/commit/ed1f91b42890998b255567f32e8049a842552937)) - Upgrade to tui 0.10 step one… ([`839b932`](https://github.com/Byron/dua-cli/commit/839b9323d93b9f562f6414cd66504b6d686c0224)) - Fix path construction of 'sample_02_tree' for test ([`5a36cd1`](https://github.com/Byron/dua-cli/commit/5a36cd18a31ca1fbdc62d4e594933a6327fe4e7d)) - Fix platform size difference of 'sample_01_tree' for test ([`62c5833`](https://github.com/Byron/dua-cli/commit/62c58330b41cb19adde1c7d2b08a5db251be3580)) - Tui-react now works with tui 10.0; tracks tui's version number now ([`773497c`](https://github.com/Byron/dua-cli/commit/773497cc48a406a069be84e14194d51484fdbec2)) - Re-enable test, disabled accidentally ([`48cbe09`](https://github.com/Byron/dua-cli/commit/48cbe0919da1dd6aa8c933b5d156e7f0ce5997a8)) - Update to colored 2.0 ([`72e776d`](https://github.com/Byron/dua-cli/commit/72e776d9a3668a81a9502e9560c06a2e500a37c8)) - Fix test on windows - it's breaking now since #53 is fixed ([`1207bdd`](https://github.com/Byron/dua-cli/commit/1207bdd582c75895354b639fb81006d97076da83)) - Dependency update ([`f7f2118`](https://github.com/Byron/dua-cli/commit/f7f211802edeff5c1981ab8bfe01517639f79e19)) - Don't pay extra on linux for helping with #53 ([`d18191d`](https://github.com/Byron/dua-cli/commit/d18191d8b19471eabc34526070bcc440edd72626)) - Use full path for obtaining the 'real size on disk' ([`22a13fb`](https://github.com/Byron/dua-cli/commit/22a13fbea06199151d5cdf2f3a0533984111e0b3)) - Speedup build times by not optimizing build dependencies ([`16e00de`](https://github.com/Byron/dua-cli/commit/16e00de6821675f8c4a0ed8500c2abfaa3af3bb0)) - Replace flume with just std::sync::mpsc ([`ba78ae4`](https://github.com/Byron/dua-cli/commit/ba78ae433d1ea905bf1efd751cec34901e509caa)) - Update dependencies ([`901d29d`](https://github.com/Byron/dua-cli/commit/901d29df066e8974b272c742ca4f9a9c7aa49dbc)) - Update dependencies ([`78448e6`](https://github.com/Byron/dua-cli/commit/78448e62bb50284a85fdf03b289049eecc1ee265)) - Patch bump tui-react ([`7fbd933`](https://github.com/Byron/dua-cli/commit/7fbd93302566b19427e2b9432abd2cd131651983)) - Calculate block width without going through graphemes ([`9702296`](https://github.com/Byron/dua-cli/commit/97022961a0d7f65c605f71f764b766b29866c4c7)) - Update dependencies ([`69edd7c`](https://github.com/Byron/dua-cli/commit/69edd7c1b109a443565c6fd9d2e23d2e030031dd))
## v0.10.1 (2020-07-22) ## v0.10.0 (2020-07-22) ## v0.4.1 (2020-07-10) ## v2.9.1 (2020-07-07) Globs for Windows; fixed handling of colors. - On widnows, `dua` will now expand glob patterns by itself as this capability is not implemented by shells `dua` can now run in. - A bug was discovered that could cause `dua a` invocation to now show paths behind their size in an incorrect attempt to not print with color. ### Commit Statistics - 5 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Bump patch level ([`42a5067`](https://github.com/Byron/dua-cli/commit/42a5067eacf10cfdca7b1d5df92748c9855fefa3)) - Merge branch 'rivy-fix.win' ([`edd0d74`](https://github.com/Byron/dua-cli/commit/edd0d74a12096f83c4b75ffd021c31dcbc269a46)) - Fix color handling (causing the text to disappear); fix tty detection ([`82d005b`](https://github.com/Byron/dua-cli/commit/82d005b9e3ed9ce8d4441c607ec160f2f0a48b1c)) - Add windows wildcard argument support (using `wild`) ([`2c73b4d`](https://github.com/Byron/dua-cli/commit/2c73b4d59603c12d31ded1a2f2ca9ef97a5ff0b3)) - Fix windows compiler warnings (unused_variables) ([`5a11216`](https://github.com/Byron/dua-cli/commit/5a11216b53af2644100fcfebe44b0b6eea2dbb78))
## v2.9.0 (2020-07-06) Full windows support! - On Windows, we will now build using `crossterm`, which was greatly facilitated by `crosstermion`. - On Unix systems, the backend is still `termion`. ### Commit Statistics - 20 commits contributed to the release over the course of 4 calendar days. - 4 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Cut new release: 2.9 ([`becae48`](https://github.com/Byron/dua-cli/commit/becae48c29aa2db036f097516959d60cc219bc03)) - Releases are working as expected ([`230bd1d`](https://github.com/Byron/dua-cli/commit/230bd1d338cae861f1390b4db0dc58c8ea1491d4)) - Skip one test on windows ([`fece423`](https://github.com/Byron/dua-cli/commit/fece4231cd24409b0772a820cee18c2922d45e5b)) - Fix release.yml ([`eac0702`](https://github.com/Byron/dua-cli/commit/eac07027c3e9baff2d73ebfa7cc3ce752c0a8303)) - Windows is nightly only right now ([`034c7ec`](https://github.com/Byron/dua-cli/commit/034c7ec6abbed58688d82a4e703fdb10864af58f)) - Setup main branch for release build testing ([`50eb08b`](https://github.com/Byron/dua-cli/commit/50eb08b1b23714ab43e9457b92ec799440a0bc37)) - Don't implicitly pull in termion! Kills windows build reliably… ([`d57cdca`](https://github.com/Byron/dua-cli/commit/d57cdca7e57c40e51fdaec760e92b111dc69ad0f)) - Inform about a certain decision related to tui backend support ([`676c6a9`](https://github.com/Byron/dua-cli/commit/676c6a99be6a604fa0508a8335e3a2f9dad206e7)) - Make interactive mode optional, allow selection of backend for windows, unix ([`464829e`](https://github.com/Byron/dua-cli/commit/464829e11f5d6d63019ec167e2e1b1b7c0061f0a)) - Add preliminary windows test for building ([`d0c362a`](https://github.com/Byron/dua-cli/commit/d0c362ae0f0f7ff4d49d899591c6cbb205e6b191)) - Completely rid ourselves of Termion to make backend selection possible ([`0e760d7`](https://github.com/Byron/dua-cli/commit/0e760d733108a7e3a2153b4cee03f33ef13e5cd4)) - Replace termion::color with colored ([`40e9eb1`](https://github.com/Byron/dua-cli/commit/40e9eb1d0e548dac3ec896d293291d1e439ba976)) - Termcolor spends 1200 lines on handlings buffers, and it's not liking plain io::Write ([`e867e58`](https://github.com/Byron/dua-cli/commit/e867e58ebd2febc66342f0337f08b75574b24e02)) - For a moment I thought 'colored' could be used, but… ([`86f16c3`](https://github.com/Byron/dua-cli/commit/86f16c3042d9f8ba400512c8f2916c3a40e2d1f8)) - Always use crossterm for now just to test if it works and… ([`3e0d4b0`](https://github.com/Byron/dua-cli/commit/3e0d4b022ff8d6ce5115894f3b6ad68f01ff370f)) - Use crosstermion to create a terminal with the corresponding backend ([`98f850a`](https://github.com/Byron/dua-cli/commit/98f850a1ccd30618620a7d78999899c24463238a)) - Allow case-insensitivity with byte format variants ([`4b59c36`](https://github.com/Byron/dua-cli/commit/4b59c36ca8c53e63dd74fc0b3179a4ed9de2f60d)) - Convert input handling to crosstermion ([`388a134`](https://github.com/Byron/dua-cli/commit/388a1347580df120cead11f98516ceb911373316)) - Show possible variants of byte formats ([`fddc8cb`](https://github.com/Byron/dua-cli/commit/fddc8cbcadb50a6ad2bf06e883fe751f3bca55b3)) - Put Freaky into the changelog :) ([`b46cd3a`](https://github.com/Byron/dua-cli/commit/b46cd3a4920155cffbaecaf1ec8efe0ec245c531))
## v2.8.2 (2020-07-02) - Switch back to `clap` from `argh` to support non-UTF-8 encoded paths to be passed to dua I hope that `argh` or an alternative will one day consider supporting os-strings, as it would in theory be an issue for anyone who passes paths to their command-line tool. ### Commit Statistics - 3 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Bump patch level ([`4b965d7`](https://github.com/Byron/dua-cli/commit/4b965d76f096815b75759064bbf635d35b701560)) - Make aliases visible in generated docs ([`531fbf1`](https://github.com/Byron/dua-cli/commit/531fbf1d5b4107cc54a426559e552d818e1d5735)) - Bring structopt back, argh doesn't support OsStrings ([`e32778b`](https://github.com/Byron/dua-cli/commit/e32778b00dd38bc2053d325453ec19f498b68a29))
## v2.8.1 (2020-07-02) - Switch from deprecated `failure` to `anyhow` to reduce compile times a little and binary size by 130kb. ### Commit Statistics - 2 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Bump patch level ([`10aecc0`](https://github.com/Byron/dua-cli/commit/10aecc0ce7d33afc1fdbe8ce88b1aa871f055cf8)) - Use 'anyhow' instead of 'failure' to simplify code and reduce bloat ([`af7a09c`](https://github.com/Byron/dua-cli/commit/af7a09c53faf9ebeeb8c0a15278b510738d1f34f))
## v2.8.0 (2020-07-02) - Switched from `clap` to `argh` for a 300kb reduction in binary size and 1 minute smaller compile times. ### Commit Statistics - 3 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Bump minor version ([`9ac025f`](https://github.com/Byron/dua-cli/commit/9ac025f7e546514581aaa96f96b8af476988d384)) - All tests work with argh (which really needs aliases) ([`03e9a2a`](https://github.com/Byron/dua-cli/commit/03e9a2ac143c269d2c44a6bd13a0da10ede8bf38)) - First version of options struct based on Argh ([`d787a9c`](https://github.com/Byron/dua-cli/commit/d787a9c5b8ccadae678c985b05ecc328d62df8f3))
## v2.7.0 (2020-07-02) - [Support for extremely large][issue-58], zeta byte scale, files or filesystem traversals. - [Fix possibly incorrect handling of hard links][pr-57] in traversals spanning multiple devices. Both changes were enabled by [@Freaky](https://github.com/Freaky) whom I hereby thank wholeheartedly :). ### Commit Statistics - 7 commits contributed to the release over the course of 29 calendar days. - 31 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Upgrade byte-unit to version 4 ([`8040d5c`](https://github.com/Byron/dua-cli/commit/8040d5c50df32b6b19b775a88bdc9616fbfe8980)) - Update dependencies ([`1d61587`](https://github.com/Byron/dua-cli/commit/1d61587ce0e783019e5f3cb2a8acdd8c5eb93cca)) - Fix unittests, at least to work locally on MacOS ([`1ce39f9`](https://github.com/Byron/dua-cli/commit/1ce39f9427b30adccf3e62751625b2296a333ca0)) - Cut a new minor release: 2.7 ([`841a9d5`](https://github.com/Byron/dua-cli/commit/841a9d55fe1c4d76276616eab17274a45391bdcb)) - Use u128 for byte sizes ([`1d8ba52`](https://github.com/Byron/dua-cli/commit/1d8ba524ac83a0c3b5e4146cf937ed75650f1e97)) - Fix inode filtering with multiple devices ([`c37ee44`](https://github.com/Byron/dua-cli/commit/c37ee449f32ed3af0fc222f669ae3f40859d8a39)) - Add more information about what it means to 'quit more quickly' ([`0ee7e06`](https://github.com/Byron/dua-cli/commit/0ee7e06589baace8fd453e67ac78db5ca3e1553d))
## v2.6.1 (2020-05-31) - quit without delay from interactive mode after `dua` was opened on huge directories trees. See [this commit](https://github.com/Byron/dua-cli/commit/91aade36c71e4e14167030b6ec8c3c13dcdc1b2b) for details. ### Commit Statistics - 27 commits contributed to the release over the course of 11 calendar days. - 26 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Bump patch level ([`5eae4e3`](https://github.com/Byron/dua-cli/commit/5eae4e32dd6c2e7d0714605cddda81bef32347c6)) - Avoid deallocation a potentially big hashmap ([`91aade3`](https://github.com/Byron/dua-cli/commit/91aade36c71e4e14167030b6ec8c3c13dcdc1b2b)) - Abort on panic for smaller binaries; update dependencies ([`31778d7`](https://github.com/Byron/dua-cli/commit/31778d7517cf27f5a5effccc7373b71833546098)) - Check package size limit in CI using cargo-diet ([`4dfb18f`](https://github.com/Byron/dua-cli/commit/4dfb18fe86cbe881b71de2db2faa43e8206e9a4f)) - Fix install script instructions ([`6d15037`](https://github.com/Byron/dua-cli/commit/6d1503759774510ca9509175efd5785b41b9482d)) - Optimize crate size with `cargo diet -r` ([`ca2dc43`](https://github.com/Byron/dua-cli/commit/ca2dc43b5aa1c0a2f025a697c9956f29d1bf0fe4)) - Remove unused files ([`bb40674`](https://github.com/Byron/dua-cli/commit/bb406748e2b7e6cc047ebb4f9262c2f5d51f8dbb)) - Add information about Windows installations ([`f0f20af`](https://github.com/Byron/dua-cli/commit/f0f20af237d7acddf4de3ae13673f44617728cf4)) - Disable test mode ([`8dbf7e6`](https://github.com/Byron/dua-cli/commit/8dbf7e6a8e512378949939c9613fef5417a602c8)) - See if all targets work! ([`002678e`](https://github.com/Byron/dua-cli/commit/002678e0a369802e8e245fa3ddacd2e2d7cc8eeb)) - Add windows-by-handle feature to lib.rs, where it probably has to be ([`cc1930a`](https://github.com/Byron/dua-cli/commit/cc1930ab6c387628cd1f2ba3499d64b7a523ad5f)) - Remove now unneeded specialized code to try checking out the repo ([`7318d07`](https://github.com/Byron/dua-cli/commit/7318d0774322a9ecfd958cafc6e2bfe48e1cfa79)) - Remove paths windows chokes on ([`82d2d51`](https://github.com/Byron/dua-cli/commit/82d2d51e5bf3398808d2dbce6c3964ce6c53660e)) - Try with manual sparse checkout :D ([`9935b3f`](https://github.com/Byron/dua-cli/commit/9935b3fdb9d901302019d7dbeb9d4c2060325359)) - No clone needed, can just checkout sparsely ([`62e6c3e`](https://github.com/Byron/dua-cli/commit/62e6c3ed2e9f45afe229872eafa7937617329840)) - Better checkout code, based on what the checkout action does ([`67ca691`](https://github.com/Byron/dua-cli/commit/67ca691b5a6afa0608a4dd3d5042229a18508ad8)) - Need debug info :D ([`cb3b636`](https://github.com/Byron/dua-cli/commit/cb3b636b249dd20ea216e601d7ca21adce36dfbe)) - Let's see what we actually checkout ([`20d194f`](https://github.com/Byron/dua-cli/commit/20d194f408a04fc21e9c58c38d22a577d87f594a)) - Job shouldn't fail if checkout fails - looks like sparse checkout works! ([`93ffeb1`](https://github.com/Byron/dua-cli/commit/93ffeb1bb70683f60d10eae9e0dd91fb4e4c8748)) - Try to get it cloned one more time ([`ff8482a`](https://github.com/Byron/dua-cli/commit/ff8482aea09a13ff24921b24e0849f4df858b429)) - Maybe continue-on-error makes failures successes? ([`cab78dd`](https://github.com/Byron/dua-cli/commit/cab78dd0fa0df3aa9f17915832a04f8b4ac44a33)) - Fix 'append file to other file' for windows; try again to trigger sparse checkout ([`904c484`](https://github.com/Byron/dua-cli/commit/904c48434befab6c54cc5e4c1d81c52f29988a82)) - Right, leading exclamation marks in yaml! ([`b351b1d`](https://github.com/Byron/dua-cli/commit/b351b1d776cc68859737d0380302abce86b3e003)) - Bump artifact version ([`b7220a8`](https://github.com/Byron/dua-cli/commit/b7220a8cb38c05a71b3e2f35e98b6b672c8d9479)) - Try to use a sparse checkeout if standard checkout fails ([`a37a66a`](https://github.com/Byron/dua-cli/commit/a37a66a51f12ace6f4aa5be0e04bfdf6246cffb4)) - Try windows release binaries ([`15b0b0b`](https://github.com/Byron/dua-cli/commit/15b0b0bfe33af3b74be69be631b22df666883922)) - Fix crossdev to support windows (as originally intended) ([`3884ea6`](https://github.com/Byron/dua-cli/commit/3884ea66d74a0a04beb24e7c12144ac8245d4b95))
## v2.6.0 (2020-05-04) - Use `x` to only mark entries for deletion, instead of toggling them. - Add `-x` | `--stay-on-filesystem` flag to force staying on the file system the root is on, similar to `-x` in the venerable `du` tool. ### Commit Statistics - 11 commits contributed to the release over the course of 22 calendar days. - 29 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Upgrade to tui 0.9 ([`42c541a`](https://github.com/Byron/dua-cli/commit/42c541ac1977cef5169981c5996820214da9c937)) - Update dependencies ([`a078086`](https://github.com/Byron/dua-cli/commit/a078086ce7fad108929afc7c8f24ab7c05b1be46)) - Add '-x' flag to not cross filesystems ([`9156cf7`](https://github.com/Byron/dua-cli/commit/9156cf7cac8f91a496f7383940f3ce6140ffe54c)) - Fix cargo fmt ([`a5988d0`](https://github.com/Byron/dua-cli/commit/a5988d091b437315a91accd21f6f1b61d21e2e9a)) - Add 'x' key to mark for deletion, without toggling ([`5cedded`](https://github.com/Byron/dua-cli/commit/5cedded25d10800805d6717381bf2981e270e23d)) - Mild refactor ([`5c1a04b`](https://github.com/Byron/dua-cli/commit/5c1a04bb108eefdb6e10294fef0681cf92ecbaad)) - Fix clippy lints ([`83804ad`](https://github.com/Byron/dua-cli/commit/83804adf605c2d1264b0fcafcdbf5f77023570ab)) - Link Rust badge to actions ([`9b3de55`](https://github.com/Byron/dua-cli/commit/9b3de5547d418697e7f094513e80dee4d00c21ff)) - Add fmt and clippy lints ([`bc4fe3a`](https://github.com/Byron/dua-cli/commit/bc4fe3aebf5a728a30dcd31c6b06d883c3c2a745)) - Bye bye travis, we had a really good time… ([`6d91259`](https://github.com/Byron/dua-cli/commit/6d91259c03591eb65c26a709d5906d98ea42b1ed)) - Update badges ([`66f2bf7`](https://github.com/Byron/dua-cli/commit/66f2bf7a223dbd80457df730a7f282b793a2f10e))
## v2.5.0 (2020-04-05) Much more nuanced percentage bars for a more precise visualization of space consumption. ### Commit Statistics - 8 commits contributed to the release over the course of 5 calendar days. - 6 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Bump minor ([`1027e9d`](https://github.com/Byron/dua-cli/commit/1027e9da425fda430b4be054a085d32972ef3c2d)) - Fix compile errors after porting commit ([`26b9569`](https://github.com/Byron/dua-cli/commit/26b9569472ffb300d7019dbed5524fdbf688c6b8)) - Add eighth sections to bar ([`82333ac`](https://github.com/Byron/dua-cli/commit/82333ac619e95a0635c20e9bc16b364b5f520e2d)) - Update asciinema video ([`6821adc`](https://github.com/Byron/dua-cli/commit/6821adca0f351411120c0c7f1c2b9f99f03040b8)) - Bump tui-react version to 0.3 ([`cad0beb`](https://github.com/Byron/dua-cli/commit/cad0beb5cf8735af20e74764eae6b9d120093b22)) - Minor bump for tui default features = false ([`b42a81d`](https://github.com/Byron/dua-cli/commit/b42a81dba70f272374a6683f0c430c3e1ab5ed5d)) - Disable default features for tui in tui-react ([`8467a49`](https://github.com/Byron/dua-cli/commit/8467a49796e56a874837dc810dc2e534ec03f0a3)) - Clippy ([`70b043a`](https://github.com/Byron/dua-cli/commit/70b043abfd4a5765b4966cff65a7b67c518528ef))
## v0.3.0 (2020-04-03) ## v2.4.1 (2020-03-30) Bugfix: Update currently visible entries when scanning. ### Commit Statistics - 7 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Bump patch ([`f3505ec`](https://github.com/Byron/dua-cli/commit/f3505ec9f67abd9d4ce51c3b91d3d1edc6003ee0)) - Update currently visible entries whenever we get the chance during scanning ([`8b3a32f`](https://github.com/Byron/dua-cli/commit/8b3a32f9d99a26ac62e150ae6a2cb5fa835a8055)) - Revert attempt to use tui-react's drawing… ([`fc0b814`](https://github.com/Byron/dua-cli/commit/fc0b814eab5d4157b3c09b34957c8a68e39d46d3)) - Revert "use tui-react to draw text…" ([`dff2c86`](https://github.com/Byron/dua-cli/commit/dff2c8637198f1b695d3ccf25a49566e55e38249)) - Cleanup ([`12fd993`](https://github.com/Byron/dua-cli/commit/12fd9936abfce74df3b5e3b005d7eff7e7d8204d)) - Use tui-react to draw text… ([`e8c00b7`](https://github.com/Byron/dua-cli/commit/e8c00b709fe1d4470d80e086ba615febba0dfd24)) - Remove roadmap, development is a bit more 'fluid' these days ([`0838d9e`](https://github.com/Byron/dua-cli/commit/0838d9ed97f6be0a5a080170c15605581e0088bb))
## v2.4.0 (2020-03-29) Full interaction during scanning phase; add inline-help for better UX. ### Commit Statistics - 29 commits contributed to the release over the course of 2 calendar days. - 2 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Bump minor version ([`4bea206`](https://github.com/Byron/dua-cli/commit/4bea206639aecd7c28bb399bc93ec9350b5da142)) - Don't try to shutdown keyinput thread to not lose input events ([`80979a1`](https://github.com/Byron/dua-cli/commit/80979a179f924af87a33fc81ccca055ce6df5636)) - First step towards support aync/channel based input events ([`e811eff`](https://github.com/Byron/dua-cli/commit/e811effe6424cd691260b07d1187d7c2d34ad4f1)) - Toggle help for entries and mark pane ([`7689016`](https://github.com/Byron/dua-cli/commit/7689016c537d054a519e4e61c577e30645537213)) - Navigation help for 'help' pane :D ([`d5ed498`](https://github.com/Byron/dua-cli/commit/d5ed498b592ff2b7f725163cae0c8426930c005c)) - Auto-help which follows through the panes ([`ac04d9e`](https://github.com/Byron/dua-cli/commit/ac04d9ed9992090cfaf0002c2da954fefd542241)) - Crossbeam channel is actually not needed in this case ([`a3cf6d6`](https://github.com/Byron/dua-cli/commit/a3cf6d6f3ea68d4cc91a433b4e3701e698f27009)) - Import plenty of utilities from prodash into tui-react ([`584cc98`](https://github.com/Byron/dua-cli/commit/584cc989cfdf37cd11a2e885e42ddabaccda7dec)) - Show 'scanning' message even without key presses. ([`1f1c0ce`](https://github.com/Byron/dua-cli/commit/1f1c0ce5171ec691152954d3169a266e760ea873)) - Allow initial scan to be interrupted properly… ([`277824b`](https://github.com/Byron/dua-cli/commit/277824b2aeedfa1f82fa2675f17e2498230b9fe7)) - Allow deletion of files while scanning, it should yield IOerrors only; improve 'scanning' message ([`8c3294e`](https://github.com/Byron/dua-cli/commit/8c3294e67c4a140be335816720d6c0e5d021319b)) - Fix crashbug - division by zero… ([`5f2bc2d`](https://github.com/Byron/dua-cli/commit/5f2bc2d38205cc66b7bb1805b5a1544e8ccfaae2)) - Now it's way more intuitive, and you can basically do everything… ([`164d885`](https://github.com/Byron/dua-cli/commit/164d8859ea0a1386dbd75a0a27dd0340e6605857)) - Better state handling when 'peeking' during traversal… ([`d7d9a8b`](https://github.com/Byron/dua-cli/commit/d7d9a8bdd55ce6fccdc51d238e55e769c314205c)) - Properly shutdown dua with quick-exit - solves all problems ([`437eb41`](https://github.com/Byron/dua-cli/commit/437eb41def66eedf4614902e42eb1d265967093c)) - Surprisingly complicated to get back to normal TTY without dropping the terminal… ([`13e5695`](https://github.com/Byron/dua-cli/commit/13e5695ea499d84f508748d120d282f55cb288f5)) - Now there could possibly be abortable and navigatable GUI while scanning… ([`0e25706`](https://github.com/Byron/dua-cli/commit/0e25706db7e25d53678b23548eddf5809a789ab4)) - Assure we keep display state changes ([`b556405`](https://github.com/Byron/dua-cli/commit/b5564057fd999a87a7e0f9470964d05595f12556)) - Remove now unused method ([`1ceb264`](https://github.com/Byron/dua-cli/commit/1ceb264ee9393b6adec68781100ee962ae8e3656)) - Phase one of refactoring nearly complete ([`758ea32`](https://github.com/Byron/dua-cli/commit/758ea32b90547c9f9c8f3135f3e7fa422111e44a)) - Also exit quickly when ctrl+c is pressed ([`00e7006`](https://github.com/Byron/dua-cli/commit/00e70066ea495af9464b9d12cfd8ef15a40c6584)) - On the way to separating traversal from application state ([`ede6224`](https://github.com/Byron/dua-cli/commit/ede622480acb4066ea864bae200ea89de46dbcdd)) - Revert "Asynchronous processing of keyboard events…" ([`81bd12a`](https://github.com/Byron/dua-cli/commit/81bd12a176666ca5dacdb651f2e7f2b017c41ff2)) - Another step towards isolating the event loop from needing to own the traversal tree… ([`733fac3`](https://github.com/Byron/dua-cli/commit/733fac38e2095fdc819b584958092381b9e2bc46)) - Asynchronous processing of keyboard events… ([`7f32fb9`](https://github.com/Byron/dua-cli/commit/7f32fb9a70dd9b7078ae4db8e465d6762336048a)) - Cleanup 'quick-hack' done in 2.3.9 - much better now ([`9824585`](https://github.com/Byron/dua-cli/commit/9824585960f09729c5547d60edaea5d97fdb595f)) - Fix tests by regenerating them - issue is that sym-links are not shown anymore. ([`6b90258`](https://github.com/Byron/dua-cli/commit/6b90258662810ce740f7f9ad44234e10f3367fc3)) - Add ArchLinux to README.md ([`a4abfd1`](https://github.com/Byron/dua-cli/commit/a4abfd11f679a479d9668d833cecfee0425bd22f)) - Merge remote-tracking branch 'origin/master' ([`f5a1ff2`](https://github.com/Byron/dua-cli/commit/f5a1ff2fbb3aeaf6a9afb730a39a8c8abea454c4))
## v0.2.2 (2020-03-29) ## v2.3.9 (2020-03-27) Do not follow symlinks unless it's the only root path to follow. This brutally fixes an issue where symbolics links are honored when they are placed in the current working directory, as internally `dua` will treat each cwd directory entry as individual root path. ### Commit Statistics - 2 commits contributed to the release. - 1 day passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Truly don't follow symlinks unless they are the only top-level path. ([`768cbce`](https://github.com/Byron/dua-cli/commit/768cbce3963be7d6ece448d56289223810d678ac)) - Update README.md ([`ac2fe84`](https://github.com/Byron/dua-cli/commit/ac2fe840b510c4f15a63135f124fb140db271848))
## v2.3.8 (2020-03-26) `dua interactive` (`dua i`) is now about twice as fast due to using all logical cores, not just physical ones. This is also the first release with github releases: https://github.com/Byron/dua-cli/releases/tag/v2.3.8 ### Commit Statistics - 16 commits contributed to the release. - 2 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - And don't forget to create a directory for artifacts… ([`2bbbb0b`](https://github.com/Byron/dua-cli/commit/2bbbb0b42371e0701af3b927fee129cd8be5a852)) - Revert "Azure repository is super instable, and often unavailable making this fail" ([`25ae12d`](https://github.com/Byron/dua-cli/commit/25ae12d5ac0a1dde4709cff6be948ab56fdf00d3)) - Azure repository is super instable, and often unavailable making this fail ([`e94f97d`](https://github.com/Byron/dua-cli/commit/e94f97d91f1021ef06b307c72ea6f6600cb1d375)) - Generalize release setup for easier copy-paste ([`ea05566`](https://github.com/Byron/dua-cli/commit/ea05566e9cf0f6248c32f304a5282a5d7a551ef4)) - Bump patch level ([`65ac16b`](https://github.com/Byron/dua-cli/commit/65ac16b377aa33d1064de2ebfaba51d6f95acb55)) - Adjust releases for master: run on tags only ([`e843eda`](https://github.com/Byron/dua-cli/commit/e843eda0266950bde0d39c9f1b1b8a08d16d9a44)) - Github releases! ([`8e8e011`](https://github.com/Byron/dua-cli/commit/8e8e0119441518062cc7612b360eca1beaf7143c)) - Considerably speed up dua interactive by allowing to use all (logical) cores ([`085ae37`](https://github.com/Byron/dua-cli/commit/085ae37d70bbd4328e046a47bc41c13e669eb562)) - Fix build instruction ([`b39f773`](https://github.com/Byron/dua-cli/commit/b39f7738d45b2627cddd4e026bde6342a7535ccf)) - Journey tests still fail, newline issues, ignore for now ([`49f3cb9`](https://github.com/Byron/dua-cli/commit/49f3cb9f161ac6898a0d4ad52501d2159421e68c)) - Adjust release.yml to hopefully suit dua ([`e3481bd`](https://github.com/Byron/dua-cli/commit/e3481bd3a4775898ca6233486fafaae599c51e6d)) - Use CHANGELOG instead of a huge section in README ([`4254d39`](https://github.com/Byron/dua-cli/commit/4254d3953654a60102ed2bc6e3e0fd57138038f1)) - Update journey tests hoping they yield the same results on CI ([`fefc52a`](https://github.com/Byron/dua-cli/commit/fefc52ab97cc19ccd85a9dc46175f4c3b3b1c91d)) - Now with the actual, unaltered release.yml, previous one was ci.yml ([`c32e65a`](https://github.com/Byron/dua-cli/commit/c32e65a4562f3e3c9ce7b39ebbe4bd54ba31da93)) - Oriignal release.yml from ripgrep, no alterations ([`17170fb`](https://github.com/Byron/dua-cli/commit/17170fb41c2962a468fde7c97cf863ea3e5a85a2)) - Create rust.yml ([`64d9524`](https://github.com/Byron/dua-cli/commit/64d95247edbd69bb6bf5dd976d2b43364535c107))
## v2.3.7 (2020-03-24) Upgrade to filesize 0.2.0 from 0.1.0; update dependency versions ### Other - Update Fedora instructions ### Commit Statistics - 3 commits contributed to the release over the course of 6 calendar days. - 8 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Updaet dependencies; bump version ([`7c8e387`](https://github.com/Byron/dua-cli/commit/7c8e3875018fc61b86588212d3812a81546b664e)) - Update to filesize v0.2 ([`cf902db`](https://github.com/Byron/dua-cli/commit/cf902dbc2cc7b80b2657cf2429db708cc71b6253)) - Update Fedora instructions ([`45d1ef3`](https://github.com/Byron/dua-cli/commit/45d1ef31181cd9b430d855a4fe23550ea97e685e))
## v2.3.6 (2020-03-16) Upgrade to jwalk 0.5 bringing better threading control and no symlink following during traversal ### Commit Statistics - 5 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Bump patch level ([`aa9e326`](https://github.com/Byron/dua-cli/commit/aa9e326d595ea83c3e22a3972a5f068937c47ba3)) - Potentially faster release binaries; smaller release binaries ([`4f468f4`](https://github.com/Byron/dua-cli/commit/4f468f4349c245d79f4da90e55649d9551af8da7)) - Now we are truly single-threaded when threads = 1 ([`b7ed2bb`](https://github.com/Byron/dua-cli/commit/b7ed2bbc957c416e8af08983bba46a4fe2a9553c)) - Add marker for future improvement : parallel deletion ([`394e261`](https://github.com/Byron/dua-cli/commit/394e2615d5fb2cbde9ddb076f1e4867a4161e05a)) - Jwalk 0.5 has landed - now we don't follow symlinks during traversal! ([`0d6116e`](https://github.com/Byron/dua-cli/commit/0d6116eea1e741bc8bc1fc6d04536c8242c5aa42))
## v2.3.5 (2020-03-15) Fast exit from interactive mode for a responsive exit; dependency updates (except jwalk) ### Commit Statistics - 2 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Bump patch level ([`5b696d4`](https://github.com/Byron/dua-cli/commit/5b696d46bf923f5eb0c7d7b3935e35695dc16318)) - Revert "Upgrade to jwalk 0.5; stop following symlinks during traversal" ([`d2fda42`](https://github.com/Byron/dua-cli/commit/d2fda42dca410a9319f3f08b24545cbd8b8f1f59))
## v2.3.4 (2020-03-15) YANKED - jwalk 0.5.0 wasn't used correctly which led to a performance regression ### Commit Statistics - 6 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Upgrade to jwalk 0.5; stop following symlinks during traversal ([`4990fa4`](https://github.com/Byron/dua-cli/commit/4990fa4202f2b687ee2476efe0a406fdfe23fd96)) - Minor update: itertools ([`e873656`](https://github.com/Byron/dua-cli/commit/e873656d53d4071f70e73514a96eaa4cbfd23fc4)) - Updated dependencies, again ([`80b43ca`](https://github.com/Byron/dua-cli/commit/80b43caf3bf46f6afea3deaf1b36f985a7025c19)) - Remove 32bit apple target, it's now unsupported ([`79cc463`](https://github.com/Byron/dua-cli/commit/79cc46322ff29130ab8b1f0061c805c7780119c3)) - Bump patch level; update dependencies ([`8241b80`](https://github.com/Byron/dua-cli/commit/8241b808988485e651d8336c812f8d3b5376934d)) - Adapt journey tests to changed signature ([`b26f8ff`](https://github.com/Byron/dua-cli/commit/b26f8ff07730c6d0ba21cd2db398539a1252bf7a))
## v2.3.3 (2020-03-14) YANKED - journey tests failed to changed method signature. ### Commit Statistics - 4 commits contributed to the release over the course of 18 calendar days. - 18 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Bump versio ([`d53fd50`](https://github.com/Byron/dua-cli/commit/d53fd5067daecd6e2e7affec917f594fd4e951c6)) - Exit the program directly to avoid latency ([`175de56`](https://github.com/Byron/dua-cli/commit/175de56ebe0aff01f7e67de9862d98ba0970feea)) - Add Fedora installation instructions ([`821a456`](https://github.com/Byron/dua-cli/commit/821a45642036597002db798238dc719849be6f56)) - Prevent continuous unit tests from triggering themselves ([`832e5cd`](https://github.com/Byron/dua-cli/commit/832e5cd99d2d08b9a504612b6af4aaf007c22f14))
## v2.3.2 (2020-02-25) Incude the license file in crate. ### Commit Statistics - 1 commit contributed to the release. - 2 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Add license file to TUI-react; include it in dua, update dependencies ([`96ff5ab`](https://github.com/Byron/dua-cli/commit/96ff5ab74a70dd908f5dd218077cd2382e08d9f1))
## v2.3.1 (2020-02-23) Include .md files in Crate, update dependencies. ### Commit Statistics - 2 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Dependency update, version bump ([`a37e68d`](https://github.com/Byron/dua-cli/commit/a37e68d7cd1c1884a0803bb05e1a333fec259ce3)) - (cargo-release) start next development iteration 2.3.1-alpha.0 ([`4298271`](https://github.com/Byron/dua-cli/commit/4298271100197a2dec7b6bee296f4395ba7fcdcd))
## v2.3.0 (2020-02-22) Show size on disk by default; Dependency Update. Thanks to [this PR](https://github.com/Byron/dua-cli/pull/37), hard links are now not counted anymore. The `-l` flag will count hard links as it did before. And of course, this has no noticable performance impact. ### Commit Statistics - 7 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Update readme in preparation for new release ([`2f6bb76`](https://github.com/Byron/dua-cli/commit/2f6bb76452b37b47f1f465d8c09ee72c4ed61f14)) - Rename 'count-links' to more descriptive 'count-hard-links' ([`db514fe`](https://github.com/Byron/dua-cli/commit/db514fe58c234ad312156814ba6f5ee7b7af0b60)) - Merge branch 'Freaky-hardlink-tracking' ([`a6a4cf3`](https://github.com/Byron/dua-cli/commit/a6a4cf3705ba764ca0862fd3faaf0f7df31ac28d)) - Remove short-comings from README, as they are not present anymore ([`93b9e12`](https://github.com/Byron/dua-cli/commit/93b9e12a1de090d1c07968144f6d21061e6de50a)) - Cargo fmt ([`ba7b071`](https://github.com/Byron/dua-cli/commit/ba7b071af53444cf33ed6a11aae02b34bc26c82b)) - Add hardlink tracking, and an option to disable it ([`5b52294`](https://github.com/Byron/dua-cli/commit/5b522946adb5bb71dd51068eee5f1136e6403b31)) - (cargo-release) start next development iteration 2.2.1-alpha.0 ([`0c86b89`](https://github.com/Byron/dua-cli/commit/0c86b894caf99d3bee319c5af6f1dcf754b44011))
## v2.2.0 (2020-02-22) Show size on disk by default; Dependency Update. Thanks to [this PR](https://github.com/Byron/dua-cli/pull/35), the old apparent size can be displayed with the `-A` flag, and the much more useful 'size on disk' is now shown by default. To my pleasant surprise, this does not seem to affect performance at all - everything stays speedy. ### Commit Statistics - 8 commits contributed to the release over the course of 20 calendar days. - 20 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Dependency update, cut release ([`f2793b9`](https://github.com/Byron/dua-cli/commit/f2793b913b80744b4696024cb5e90e7f4f4f4627)) - Merge branch 'Freaky-apparent-size' ([`4db48ce`](https://github.com/Byron/dua-cli/commit/4db48ce218f12e11bbf6727fab6fb58c142b1a33)) - Add support for real/apparent size ([`d86e1e0`](https://github.com/Byron/dua-cli/commit/d86e1e0f66ac8bd031233a6a54e2a1694acf1142)) - Upgrade tui-react ([`2495390`](https://github.com/Byron/dua-cli/commit/249539045e4dfb813723dff342c52a1ca92184ce)) - New release of tui-react ([`8aec8c7`](https://github.com/Byron/dua-cli/commit/8aec8c7c9879c0bf29e82b89aab9202e2d117698)) - Cargo update - will a better lock file fix this issue? ([`c1203ee`](https://github.com/Byron/dua-cli/commit/c1203ee8bede4ad7cd7daaf245d2bfc4ff11cae1)) - Fix installation instructions ([`e773e33`](https://github.com/Byron/dua-cli/commit/e773e339363e0855474b34c57044872931bd73a0)) - For now, only run unit-tests on CI ([`8809700`](https://github.com/Byron/dua-cli/commit/8809700d0902888b7ad012c183f9a6229d52a3b8))
## v2.1.13 (2020-02-01) Dependency Update; Github Releases. Binaries for Linux and MacOS are now available on GitHub Releases. ### Commit Statistics - 9 commits contributed to the release over the course of 87 calendar days. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Fix script paths; add badge ([`5bd7766`](https://github.com/Byron/dua-cli/commit/5bd77660635eb699a385ebc4fb483e8bb8a9ca22)) - Add installation note ([`30e7eeb`](https://github.com/Byron/dua-cli/commit/30e7eeb1965694508e8bffae4e3ea47c3cc7118b)) - Add travis support including releases ([`421072f`](https://github.com/Byron/dua-cli/commit/421072f09738756c1796809accf3d5e1890f807c)) - Update tui to 0.8 ([`d871bc0`](https://github.com/Byron/dua-cli/commit/d871bc044028edf6e1cdb4cdcb1c59176648c129)) - Update petgraph ([`4b2e72f`](https://github.com/Byron/dua-cli/commit/4b2e72f0a89b9f0930a894ef9ebf3e4af94464a0)) - Cargo-update + new Cargo.lock format ([`ecded30`](https://github.com/Byron/dua-cli/commit/ecded309bc695fa6f5596366694371f0e661d8e9)) - Nicer and leaner makefile ([`673975a`](https://github.com/Byron/dua-cli/commit/673975aba4f24d3cf6bb6f76863273c62bc4121c)) - Fix version in README ([`0fef32f`](https://github.com/Byron/dua-cli/commit/0fef32fc22a78bad0a4a1062249f2e54a2008e6f)) - Update all dependencies to latest version ([`543f7f3`](https://github.com/Byron/dua-cli/commit/543f7f3948c26250a8fc6ebf79a49f3ddfa3cb63))
## v2.1.12 (2019-10-23) More obvious highlighting of active panel. Depending on the terminal used, it might not have been obvious which panel was active. This might be confusing to new and current users. Now the color of the widget frame is changed to light gray, instead of remaining gray. ### Commit Statistics - 2 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Bump version ([`0627932`](https://github.com/Byron/dua-cli/commit/0627932c3c908b1d7ec48e728687a6eac7f291b7)) - Make sure borders are drawn more priminently on focus ([`70c8d44`](https://github.com/Byron/dua-cli/commit/70c8d44b8ac42170989aa2e892cf44f79b9ab4c2))
## v2.1.11 (2019-07-26) Finally fix symlink handling. `dua` will not follow symbolic links when deleting directories. Thank a ton, @vks! _Technical Notes_: Handling symbolic links properly is impossible without usage of `symlink_metadata()`. ### Commit Statistics - 4 commits contributed to the release. - 1 day passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Bump version to 2.2.0 ([`d614b47`](https://github.com/Byron/dua-cli/commit/d614b475dcb02690286218accec28c8b6ee5167c)) - Update dependencies ([`f205cec`](https://github.com/Byron/dua-cli/commit/f205cec7a6415ad85cefd69026c0f236839c9690)) - Don't follow symlinks when calculating size interactively ([`6b235de`](https://github.com/Byron/dua-cli/commit/6b235de6f43af0f7573275c2b205741f326fd4cf)) - Don't follow symlinks when deleting files recursively ([`e01f157`](https://github.com/Byron/dua-cli/commit/e01f157d708eb1cf5cdef0daff843eda98c5db76))
## v2.1.10 (2019-07-25) Compatibility with light terminals. - the TUI is now usable on light terminals, and highlighting is more consistent. Thank you, @vks! - Fixes misaligned columns when displaying '100.00%' alongside other rows by displaying `100.0%` instead. Thanks, @vks, for pointing it out. ### Commit Statistics - 7 commits contributed to the release over the course of 2 calendar days. - 3 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Prepare next release ([`4e500be`](https://github.com/Byron/dua-cli/commit/4e500beb8444f6d9fa31ab984551716fb480d7f5)) - A single decimal slot for percentages; Fixes #26 ([`44aa899`](https://github.com/Byron/dua-cli/commit/44aa8997e3b18214f7177f7c6cc36a25daafbf24)) - Update README for upcoming release ([`abefc91`](https://github.com/Byron/dua-cli/commit/abefc91fdfe2d7a168dce4b9bda8c9d0cc98e0dd)) - Run rustfmt; use debug_assert; rename function ([`fa7daf1`](https://github.com/Byron/dua-cli/commit/fa7daf1be9b67d70c3cde64cecdd4a76d2e8082b)) - Use same colors in mark pane as in entries pane ([`3baf7f3`](https://github.com/Byron/dua-cli/commit/3baf7f31b91c71ba0acb2be886a47ccbd2b295fb)) - Fix color scheme for light terminals ([`977e69f`](https://github.com/Byron/dua-cli/commit/977e69f9aafc54f9b2ed9ddb2eee5164e30b213c)) - Forbid unsafe everywhere ([`f4028ba`](https://github.com/Byron/dua-cli/commit/f4028baf655e2994459e55d62435de4456fee80f))
## v2.1.9 (2019-07-21) Improved handling of broken symlinks. - during symlink deletion, now broken symlinks will be deleted as expected. - always return to the previous terminal screen so the TUI doesn't stick to the current one. - display broken symlinks on the first level of iteration. ### Commit Statistics - 5 commits contributed to the release over the course of 6 calendar days. - 6 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Bump version ([`387cc1f`](https://github.com/Byron/dua-cli/commit/387cc1f86e5aec8a20a25ea71f74e948b110d2c6)) - Show broken symlinks on the first level of iteration ([`eb015d3`](https://github.com/Byron/dua-cli/commit/eb015d38cbe01ff6b04855ad94936cd8f59be4bc)) - Handle broken symlinks, they can now be deleted ([`978ddba`](https://github.com/Byron/dua-cli/commit/978ddbae31a3769162cfb0fb1b6c95d96701d774)) - Assure we flush stdout to switch back to the previous screen ([`8cdc2ea`](https://github.com/Byron/dua-cli/commit/8cdc2ea4decf7eceba3e01d67b64c41ab9ddcb26)) - Allow for pageup/down to work in selector pane (interactive mode) ([`cb2bbdf`](https://github.com/Byron/dua-cli/commit/cb2bbdfe616b38311ebe26e78999c69a4637a5dd))
## v2.1.8 (2019-07-14) Don't follow symbolic links when deleting directories. [A critical bug was discovered](https://github.com/Byron/dua-cli/issues/24) which would lead to deletion of unwanted `directories` as `dua` would follow symbolic links during traversal during deletion. Please note that symbolic links to files would be treated correctly, only removing the symbolic link. This is now fixed. ### Commit Statistics - 2 commits contributed to the release. - 10 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Bump patch level ([`22c7eb5`](https://github.com/Byron/dua-cli/commit/22c7eb5e34372b2883276bb7fc207df891f7df8e)) - Do not follow symbolic links when iterating directories! ([`560a76d`](https://github.com/Byron/dua-cli/commit/560a76d43fa44c4ebf9bdc51087647bb800bbe68))
## v2.1.7 (2019-07-03) Use latest version of open-rs. That way, pressing `shift + O` to open the currently selected file won't possibly spam the terminal with messages caused by the program used to find the system program to open the file. Fixes [#14](https://github.com/Byron/dua-cli/issues/14) ### Commit Statistics - 1 commit contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Fix Cargo.lock... again. 2.1.7 is 2.1.6 effectively ([`dd12ca7`](https://github.com/Byron/dua-cli/commit/dd12ca765b7c7726e718b64035dedd0c9b3d50a0))
## v2.1.6 (2019-07-03) ### Commit Statistics - 1 commit contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Bump patch; fixes #14 ([`473ac20`](https://github.com/Byron/dua-cli/commit/473ac20f5a03e95ed5fe02ced97231806282c09c))
## v2.1.5 (2019-07-03) - re-release with Cargo.lock ### Commit Statistics - 1 commit contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Fix inconsistent cargo.lock file; update all deps ([`03628c8`](https://github.com/Byron/dua-cli/commit/03628c86778c29ee27e78608401766fe92a7c683))
## v2.1.4 (2019-07-02) ### Commit Statistics - 4 commits contributed to the release over the course of 15 calendar days. - 15 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Prep for re-release ([`22947b7`](https://github.com/Byron/dua-cli/commit/22947b76ed438ca0282f8d8bf4edc54096f43df7)) - Add `Cargo.lock` because this is a binary ([`ebc9c6b`](https://github.com/Byron/dua-cli/commit/ebc9c6b4cebc4ced23707e0d6aab4b5fa70511fc)) - Add install instructions for voidlinux ([`d039285`](https://github.com/Byron/dua-cli/commit/d0392854ce811b559e4acaf0ea654c1922e9cd6a)) - Additional limitations related to symlinks and hardlinkes ([`532457e`](https://github.com/Byron/dua-cli/commit/532457e58b2b15439558bbf5bc2062c94d9bcdf7))
## v2.1.3 (2019-06-16) ### Commit Statistics - 3 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Patch release to get a working github release - no changes to code ([`fc9f3a1`](https://github.com/Byron/dua-cli/commit/fc9f3a167622fe5fd0ea2c9a9eb0c2630d6fd244)) - Make filename smaller; related to #10 ([`868499e`](https://github.com/Byron/dua-cli/commit/868499e0d5459ddc1b9dfb6edfa6cf41948b93a5)) - Inform about the dark-mode limitation ([`bb2162c`](https://github.com/Byron/dua-cli/commit/bb2162cc3e6fd189592028246acc48610c93f1c1))
## v2.1.2 (2019-06-16) Bug fixes and improvements. - Performance fix when showing folders with large amounts of files - Display of amount of entries per directory ### Commit Statistics - 1 commit contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Performance improvements ([`d9dcbd0`](https://github.com/Byron/dua-cli/commit/d9dcbd0f89c1267f272f3cd7e9f9dd69d0ae145b))
## v2.1.1 (2019-06-16) Bug fixes and improvements. - Better information about deletion progress - removal of windows support ### Commit Statistics - 2 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Reopen #2; removal of windows support ([`81dc53b`](https://github.com/Byron/dua-cli/commit/81dc53b0e6d7c292909610fba6fd030ed6b01917)) - Better progress display when deleting multiple items ([`d586703`](https://github.com/Byron/dua-cli/commit/d5867038aa8d1d216c146fe8d0a919352dce4855))
## v2.1.0 (2019-06-16) Bug fixes and improvements. - windows support (never actually worked), usage of crossterm is difficult thanks to completely different input handling. - additional key-bindings - auto-restore previous selection in each visited directory ### Commit Statistics - 6 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Bump version to 2.1.0 ([`a8f595f`](https://github.com/Byron/dua-cli/commit/a8f595f576f164fd13e59230370b310119599f43)) - Fix tests... really need CI if PRs keep coming ([`6578aa8`](https://github.com/Byron/dua-cli/commit/6578aa8ded3089e09f731115777413824dbc7f74)) - Auto-restore previously selected entries; quality of life! ([`52f40ca`](https://github.com/Byron/dua-cli/commit/52f40caf557c4dfdae169b39984dd6fda1f77474)) - Add 'h' and 'l' as alternative keybindings ([`251ea53`](https://github.com/Byron/dua-cli/commit/251ea53bbd5072a7e7315c610cbb59540f93c7a9)) - Fixes #2 - use crossterm instead of Termion ([`34274b1`](https://github.com/Byron/dua-cli/commit/34274b108957e8819395d4bc38a9456be5372a2a)) - One more limitation ([`b68900b`](https://github.com/Byron/dua-cli/commit/b68900b0d20ef5cf5b6302a5165a7ba0f9653540))
## v2.0.1 (2019-06-16) Bug fixes and improvements. - fix typo in title - better display of IO-Errors in aggregate mode ### Commit Statistics - 3 commits contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Fix typo in title ([`9526241`](https://github.com/Byron/dua-cli/commit/952624118bf3c293f23064e21828af00df9d132c)) - Error formatting suggestions ([`fba47e6`](https://github.com/Byron/dua-cli/commit/fba47e68757341b76b168ebf4d8b631a826712fc)) - Add a missing "n" to the header ([`49bc227`](https://github.com/Byron/dua-cli/commit/49bc227d9b5adfcf27c78eca763a28ce51f26211))
## v2.0.0 (2019-06-15) Interactive visualization of directory sizes with an option to queue their deletion. A sub-command bringing up a terminal user interface to allow drilling into directories, and clearing them out, all using the keyboard exclusively. ### Other - first test to fully verify deletion - Move parts of the tests into their own files - recursive deletion - tests can begin - simple recursive copy - deletion would like depth-first though ;) - Basic for test with writable directory Would have loved to use a crate with basic utilities, but there is no internet here :( - Make marker selection feel right - Nicer colors for warn window in selection - Warning window follows user selection - Fix handling of deleting the first index in the mark list - more prominent selection in mark pane - Rustic way of handling the mark panes disappearance - don't show warning if nothing is marked anymore this can happen if the user removes all entries. The pane stays open in this case, which is a little inconsistent, but not worth fixing as it's certainly not the common case. If it should be fixed, the 'key()' function should become consuming to possible delete the pane. - Actually hook up spacebar in mark pane - Make help window pretty again - Better handling of what is selected after removing a marked entry - Don't try to go down as marked items are removed ### Other Features - Single Unit Mode, see [reddit](https://www.reddit.com/r/rust/comments/bvjtan/introducing_dua_a_parallel_du_for_humans/epsroxg/) ### Commit Statistics - 234 commits contributed to the release. - 16 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Improve readme ([`5a6571e`](https://github.com/Byron/dua-cli/commit/5a6571e6563411b9803be31b292a13bc6ca62b58)) - Update to the latest asciinema recording ([`2748500`](https://github.com/Byron/dua-cli/commit/2748500e395c4845488d332a83b4c5eeec1c64cb)) - Handle symlinks in a rather brutal way. ([`209eecf`](https://github.com/Byron/dua-cli/commit/209eecf042761eba35be809ca22bc98af472acad)) - Fix journey-tests ([`854dc46`](https://github.com/Byron/dua-cli/commit/854dc46e1d99ce5c089369820351b9354707a300)) - Prepare 2.0 release ([`d18db06`](https://github.com/Byron/dua-cli/commit/d18db061b3da35e98eaf7d9f642a84c7df74233f)) - Pane is now displayed during deletion; keeps last item selected ([`86e593f`](https://github.com/Byron/dua-cli/commit/86e593f0baee79a973845e4c7dae1339d3e838df)) - This might be the first working version of deletion ([`08dfbb6`](https://github.com/Byron/dua-cli/commit/08dfbb633fe25cc922b898aaf367f26a08730d91)) - Update num entries and bytes total ([`48813ae`](https://github.com/Byron/dua-cli/commit/48813ae0a1c9316b4a7ad1669de2c44389026769)) - Usage of StableGraph fixes logic thus far ([`a3627c8`](https://github.com/Byron/dua-cli/commit/a3627c8d04b2a755a1e466745c84591ae8e9033b)) - Better separation of concerns when iterating marked items ([`0fb99e0`](https://github.com/Byron/dua-cli/commit/0fb99e00453da6d63cc01af64fdab8419314763b)) - First half-baked version of deletion within traversal tree ([`f8485c8`](https://github.com/Byron/dua-cli/commit/f8485c8d48fb231b113a6511ee4048712ccc27fc)) - Refactor ([`1ce57a2`](https://github.com/Byron/dua-cli/commit/1ce57a29c45ee9896bfc529a13875dbc3859812f)) - Refactor ([`afdbc1d`](https://github.com/Byron/dua-cli/commit/afdbc1dadcf6c1f1e6384f65b2cac5325a5bcf17)) - First rough version of the required pieces in MarkPane ([`f1bc4cd`](https://github.com/Byron/dua-cli/commit/f1bc4cd689b7db594ceef89aa31c48b4166d21a2)) - First sketch of the delete-draw-loop ([`60ba3e7`](https://github.com/Byron/dua-cli/commit/60ba3e7f5216030e7dd4a12355de6ac78999d8e1)) - First test to fully verify deletion ([`c67abae`](https://github.com/Byron/dua-cli/commit/c67abaec3c573dbfaf31be22693220a49a67b262)) - Move parts of the tests into their own files ([`a128eb4`](https://github.com/Byron/dua-cli/commit/a128eb4a6e675f148a203ac66de075ee0c0def1c)) - Somewhere over China: preparation for splitting tests into modules ([`82b0ced`](https://github.com/Byron/dua-cli/commit/82b0ced5c18ae8dbe3730434e2447a013bb35480)) - Somewhere over China: refactor deletion - now with error handling ([`406435b`](https://github.com/Byron/dua-cli/commit/406435beff334d8f0ad62560176774ede2771ecd)) - Somewhere over China: Let's not be quite so ignorant about errors during deletion ([`eb4f978`](https://github.com/Byron/dua-cli/commit/eb4f9780d69824b9ca389f42b2ec65077640cd54)) - Recursive deletion - tests can begin ([`ef8cf56`](https://github.com/Byron/dua-cli/commit/ef8cf5636f782024372f044af80f06ed030168b0)) - Simple recursive copy - deletion would like depth-first though ;) ([`dacb897`](https://github.com/Byron/dua-cli/commit/dacb897405c06f9468faa860e27f47d1d0e548bb)) - Basic for test with writable directory ([`51ce1ed`](https://github.com/Byron/dua-cli/commit/51ce1ed159d59c6e221af4df9a3f7da41b1820cb)) - Make marker selection feel right ([`6cbd486`](https://github.com/Byron/dua-cli/commit/6cbd4866b18de91d3702a55c45650615d67f5f30)) - Nicer colors for warn window in selection ([`7ad2130`](https://github.com/Byron/dua-cli/commit/7ad2130bada27098e2d24f06650873a53b159f87)) - Warning window follows user selection ([`49edb76`](https://github.com/Byron/dua-cli/commit/49edb7654ce3380bcde28630645af3740cf1a07a)) - Fix handling of deleting the first index in the mark list ([`984bf4f`](https://github.com/Byron/dua-cli/commit/984bf4fcce05cd5d495511123c2c3b6906b96f6d)) - More prominent selection in mark pane ([`b4a2e0e`](https://github.com/Byron/dua-cli/commit/b4a2e0ee8f267ee50f92433e826fa9e42ff618db)) - Rustic way of handling the mark panes disappearance ([`b4669c0`](https://github.com/Byron/dua-cli/commit/b4669c0214a1bc858cf437a65583af7e4b9ec277)) - Don't show warning if nothing is marked anymore ([`fcde457`](https://github.com/Byron/dua-cli/commit/fcde45752a9b86ed606b78f522f6b6dd0de25457)) - Actually hook up spacebar in mark pane ([`01dd8e2`](https://github.com/Byron/dua-cli/commit/01dd8e284224e42b59f317cd922d388f23def829)) - Make help window pretty again ([`d42573e`](https://github.com/Byron/dua-cli/commit/d42573e63a120c8c5a253b7be52f9c68fb72274b)) - Better handling of what is selected after removing a marked entry ([`c0aa567`](https://github.com/Byron/dua-cli/commit/c0aa567e81b54913df464c9b500fe7a20ada0ea5)) - Don't try to go down as marked items are removed ([`f9a9cdf`](https://github.com/Byron/dua-cli/commit/f9a9cdf9f827a5e08b1bcc6035f908fdb971c9fd)) - Fixed Up and Down key inputs and added Left and Right for Ascent and Descent navigation ([`eae992f`](https://github.com/Byron/dua-cli/commit/eae992fbf0b0f0adaf8feffcb0e4903deabc562e)) - First version of removing marked items from the list ([`3b71763`](https://github.com/Byron/dua-cli/commit/3b717634364647139388dffd0d68ce6c9729eee9)) - Only show hotkey for deletion when focus is on the mark pane ([`05ed8c4`](https://github.com/Byron/dua-cli/commit/05ed8c494a1201daa4daa1506455a52f8b2b5b8e)) - First version of help line which tells what to do to delete things ([`f34ceeb`](https://github.com/Byron/dua-cli/commit/f34ceeb91f41298278f4be62a053308946d41ea7)) - Mention a limitation I chose to forego ([`88ec5d5`](https://github.com/Byron/dua-cli/commit/88ec5d51980533a4942cf18fb60f525924dfb2bd)) - Add more unicode samples, along with a new limitations ([`f1cc234`](https://github.com/Byron/dua-cli/commit/f1cc234c3aa77f97e2b9281beed61ddb6b6e170b)) - Add difficult graphemes from... ([`07727c6`](https://github.com/Byron/dua-cli/commit/07727c6abd83d2f58cccf92d7cf85eebb96a1524)) - Add grapheme ladden files ([`3e8dad3`](https://github.com/Byron/dua-cli/commit/3e8dad38085c060d6bfbf298a989739a9f9159ab)) - Happier clippy ([`f83942b`](https://github.com/Byron/dua-cli/commit/f83942b40cd545ee7b6b18e091c273d27a8610a8)) - Grapheme handling when truncating long filenames ([`0994466`](https://github.com/Byron/dua-cli/commit/0994466c45e4a46769c6998d87cf532e80108af3)) - First prettier version of mark pane ([`28d84fc`](https://github.com/Byron/dua-cli/commit/28d84fc18f3efc7cfd4aa1728656998e652e934b)) - Proper scrolling in mark pane ([`6bd6556`](https://github.com/Byron/dua-cli/commit/6bd6556449daae40fdabedf64866b641785787f5)) - Merge pull request #8 from tsathishkumar/master ([`047e424`](https://github.com/Byron/dua-cli/commit/047e424d4fee8061b55a3253b8829ad1ffb84f0c)) - Happy clippy ([`3fc9beb`](https://github.com/Byron/dua-cli/commit/3fc9beb205a2ad5f1da00472a6bc1a94cc64e769)) - Assure we don't keep threads around unnecessarily in interactive mode ([`95685f1`](https://github.com/Byron/dua-cli/commit/95685f1387b74e2bbd7c1e67d383cd5861aa3451)) - Refactor ([`24e1e2c`](https://github.com/Byron/dua-cli/commit/24e1e2cc3345e6891ec12c821b425ebc91f41d8d)) - Move EntryMarkMap into Mark widget ([`141efd0`](https://github.com/Byron/dua-cli/commit/141efd025dabd0f94f7b195400900ccb2db9049a)) - Moved marked information from footer to title of mark pane ([`6cb2d92`](https://github.com/Byron/dua-cli/commit/6cb2d92aa41e179242bb926b965862d90f06df82)) - Maintain sorting even though we have a map - each render must allocate now ([`8d21dbb`](https://github.com/Byron/dua-cli/commit/8d21dbb3a44aeaf3989c25d9555559b34632f8c7)) - See how it is when sorting by alphabet ([`5cff69c`](https://github.com/Byron/dua-cli/commit/5cff69c47a5b92017e6b1c55a35fd97f08ab3181)) - Tests to verify focus handling works ([`65321d7`](https://github.com/Byron/dua-cli/commit/65321d786aa105f3f99ea43144f9f4b5a4ee4574)) - Fix tests - if there is no item, there is no pane ([`80f7a06`](https://github.com/Byron/dua-cli/commit/80f7a0629954d05c3397f80cd0f9a74ae0a3f002)) - Implement actual marker selection ([`6ba885e`](https://github.com/Byron/dua-cli/commit/6ba885e247b4d9d886b6867483c90b8dc0e5e7ae)) - Know about focus in marker pane ([`2dafff4`](https://github.com/Byron/dua-cli/commit/2dafff434f9e772d779ec71a2fd8de1e5d2780db)) - Simplify mark selection by making it based on position in list ([`beed74a`](https://github.com/Byron/dua-cli/commit/beed74aec250823aa01f33925f2a877414c5526c)) - Refactor ([`d319f0b`](https://github.com/Byron/dua-cli/commit/d319f0b3b293167b4dfef79fed25b305cd1309e1)) - Fix header highlight logic, quite literally ([`0a266d3`](https://github.com/Byron/dua-cli/commit/0a266d362a11ffd420806cc49ac6884815b0b915)) - Move ownership of marked entries to the MarkPane ([`9ffacd0`](https://github.com/Byron/dua-cli/commit/9ffacd03e256b45ecd40744e5507f37c30ae9b5e)) - Some experimentation with selection handling in the new pane ([`4c354f4`](https://github.com/Byron/dua-cli/commit/4c354f475bfe841f3797be0a3341212aeeaa60c8)) - A step towards more self-contained components ([`29c0cf3`](https://github.com/Byron/dua-cli/commit/29c0cf3c5a584764e060dd9f34592edbc8098562)) - Reactor help: move event handling closer to where it belongs ([`04f5324`](https://github.com/Byron/dua-cli/commit/04f5324b17efe4c7b62a0afc7d2b34304a9a4407)) - Refactor ([`4cde0f6`](https://github.com/Byron/dua-cli/commit/4cde0f6892f29a16694155ec25d94f4ce3c3d0c9)) - The first display of paths to be deleted! ([`b79b1ae`](https://github.com/Byron/dua-cli/commit/b79b1aee4ebe97034da0804f5d1dae2bfedd1210)) - Color header based on mark and pane focus state, for dramatic effect! ([`f54a5aa`](https://github.com/Byron/dua-cli/commit/f54a5aa7aef7f5a29131db485154607bedc4da23)) - The first incarnation of the mark window ([`98aa1df`](https://github.com/Byron/dua-cli/commit/98aa1df3e99be5543dbc7ade969de3373cc132ea)) - Fix issue with seeing nothing when trying to enter a file ([`96121b5`](https://github.com/Byron/dua-cli/commit/96121b55802e2ba038129cafafc48910e29a8a8f)) - Fix endless loop and infinite memory consumption due to... NAN!! ([`0718d2a`](https://github.com/Byron/dua-cli/commit/0718d2a2a1f8ac16f0bbd30b520a3804e09eab41)) - Let's not get ahead of ourselves ;) ([`399391a`](https://github.com/Byron/dua-cli/commit/399391a3d72ca099b30f7bc2c0468ce845c71798)) - Get rid of black percentage bars :D! ([`1f9cb8e`](https://github.com/Byron/dua-cli/commit/1f9cb8e8ad4f0908bf1ab068765ac9898b402328)) - Better help ([`3c76c0f`](https://github.com/Byron/dua-cli/commit/3c76c0f408a0bfe4eea271c5a77c4911c39c8eee)) - Inform about marked entries in the footer ([`dd898c6`](https://github.com/Byron/dua-cli/commit/dd898c6a3e045782970b8496e888adf661e382c2)) - Coloring for marked entries ([`22902a5`](https://github.com/Byron/dua-cli/commit/22902a5889ab36303aed53c0d2fe57a3be919474)) - Preparing for displaying the marked state in entries list ([`2f3f214`](https://github.com/Byron/dua-cli/commit/2f3f214e03de477ad05aa12a1ac2ba0775a36c14)) - Remove Widget trait from the Header ([`53add13`](https://github.com/Byron/dua-cli/commit/53add13094a39751158f8cae27988bcbee47d08d)) - Refactor ([`7bef597`](https://github.com/Byron/dua-cli/commit/7bef5974e86de825dcb0b3507df16a80b6986d88)) - Remove obsolete annotations ([`982446a`](https://github.com/Byron/dua-cli/commit/982446ad0ef9a475274c9a0f05a32147fcafd061)) - Version bump ([`64e4068`](https://github.com/Byron/dua-cli/commit/64e4068308c9f314fdc881b40c218a5b41c7686b)) - More hotkeys ([`eec9803`](https://github.com/Byron/dua-cli/commit/eec980374f7ada8c002d7f8d1663307552f801ab)) - Fix sorting; add some alternate keys ([`f2e4504`](https://github.com/Byron/dua-cli/commit/f2e45047015ec2c08777513a366db92af0ae3586)) - Clear screen at initialization ([`37ce7fe`](https://github.com/Byron/dua-cli/commit/37ce7fe923ad76e9c6b24a462b3cb258eef88607)) - Refactor ([`c33ae7c`](https://github.com/Byron/dua-cli/commit/c33ae7c7d9f538490346a8532e27c3dd6c4aa21d)) - Bump version ([`f512974`](https://github.com/Byron/dua-cli/commit/f512974d55577265f40dbf58053203a4b12152ad)) - Assure we see something while scanning - entries are now manually provided ([`2c1cb19`](https://github.com/Byron/dua-cli/commit/2c1cb19aeb89d25977bd9fa76b8572d7e7d942a7)) - Adjust release notes ([`9e6f62e`](https://github.com/Byron/dua-cli/commit/9e6f62e32259aa9be67402980b38f3c6133efa19)) - The block is now not needed anymore - we can just own simple props ([`42fb0cc`](https://github.com/Byron/dua-cli/commit/42fb0cccb10ce1084267b63b07a5a0a8bf84de99)) - Updated readmes ([`f59b32d`](https://github.com/Byron/dua-cli/commit/f59b32d344875bbfc584f259c2c2e74dbb254b08)) - Finally, everything was properly ported to tui-react ([`7549e82`](https://github.com/Byron/dua-cli/commit/7549e82fa1afc3fd87af6e42c13757a1c11994ea)) - Entries is now ReactEntries :) ([`ae679ed`](https://github.com/Byron/dua-cli/commit/ae679ed0daed2f2faf1bd8b4db922bdf450f738a)) - Add tui-react as library - it's proven (enough)... ([`3aa9b01`](https://github.com/Byron/dua-cli/commit/3aa9b0168425706b6bdfa4eb2b9335da24bc15fd)) - Make clear the Component is very a TopLevelComponent, very special! ([`80ae2ac`](https://github.com/Byron/dua-cli/commit/80ae2ac79c1525886c613452c835099eeae97c4d)) - FINALLY! It works, and is on the way to using tui-react ([`c5fd940`](https://github.com/Byron/dua-cli/commit/c5fd9402a19ea427375751c7dfe61153897a273f)) - What about simply not implementing the trait :D? Concrete types for the win! ([`180ebb7`](https://github.com/Byron/dua-cli/commit/180ebb77b28ad4ecb4bebc44173f8b3b9338dc41)) - Removed propsmut in the hope it will work then, but not quite (yet?) ([`f8b3a0b`](https://github.com/Byron/dua-cli/commit/f8b3a0b38aaffbf8f2d78cd9147545f3d905b63b)) - Revert "An attempt to make it better by removing BorrowMut... to no avail, but different error" ([`8059e8b`](https://github.com/Byron/dua-cli/commit/8059e8b8d292fc9ab1ec54a957c0531b7106711f)) - An attempt to make it better by removing BorrowMut... to no avail, but different error ([`b9c485a`](https://github.com/Byron/dua-cli/commit/b9c485a6e4fe629014ac1ddcc56bd2a78f7b7c66)) - The first attempt to actually use the ReactList - it's just insane... ([`4e1a326`](https://github.com/Byron/dua-cli/commit/4e1a32631874f49a048ba42b0deb5c6277118934)) - Add caveats of tui-react - they seem to be grave!! ([`bdec24f`](https://github.com/Byron/dua-cli/commit/bdec24f2d708baddd9602c3b9c841419425062c9)) - Extract react to directory ([`9cb8f4f`](https://github.com/Byron/dua-cli/commit/9cb8f4f40a2f8fc6e3f927f81459a4baafb25c31)) - An elegant solution to the Block rendering problem - it's not a component after all... ([`c799ac9`](https://github.com/Byron/dua-cli/commit/c799ac925fc79b218bf0ff7c6f37e81980e755c6)) - List compiles, but block still makes trouble ([`39938fb`](https://github.com/Byron/dua-cli/commit/39938fb193aeca619d9d37bb78b977f64182be05)) - Add react block for use in react-style components ([`b6004e2`](https://github.com/Byron/dua-cli/commit/b6004e24a96bfbfad2743418d2e2bf7647c78120)) - Support for mutable props - useful for iterators for example ([`b2f5187`](https://github.com/Byron/dua-cli/commit/b2f518764a28800ac911904f7b1e59daa08e6948)) - Add ReactFooter ([`9a5ffd2`](https://github.com/Byron/dua-cli/commit/9a5ffd238470b511c4818e917f55ba4dafaf212c)) - Help pane is now a component :) ([`c243521`](https://github.com/Byron/dua-cli/commit/c243521ea7466e9584ff0455f409b2a4160c4fb4)) - First moderately working step towards react-tui mode ([`3f3fe77`](https://github.com/Byron/dua-cli/commit/3f3fe77d1679f867928d70d8e844f0041d26bf35)) - Now it work, borrowmut was the problem ([`705f4b8`](https://github.com/Byron/dua-cli/commit/705f4b842175de7375058fff54455ba3204dffe0)) - First attempt to demo it... fail due to type inference issues? ([`717abd7`](https://github.com/Byron/dua-cli/commit/717abd71158166847c43bc60a2208345186994c4)) - First sketch of component ([`eebef81`](https://github.com/Byron/dua-cli/commit/eebef816f307d941e428a27e8871830b73c1cdae)) - Cleanup terminal ([`cb12e94`](https://github.com/Byron/dua-cli/commit/cb12e94cb9c2cad8007e1230f21f2e1380858835)) - Basis for react-like terminal implementation - that way we can have state ([`b3ebbfc`](https://github.com/Byron/dua-cli/commit/b3ebbfc1e76292a401e20595928815f83ab83373)) - Use entries from the state contained in the parent app ([`03d2ee3`](https://github.com/Byron/dua-cli/commit/03d2ee3e65abb7522dfe8a7802cebfb9b93cb44e)) - EntryDataBundle with all data we need: next - don't query during draw ([`8f3daee`](https://github.com/Byron/dua-cli/commit/8f3daee851d305d61d6efd39ce8c562f06a744a4)) - Step 1: we store entries as we enter/exit nodes ([`7483ddb`](https://github.com/Byron/dua-cli/commit/7483ddb97d754dea3415a4906082bcf0f85eb818)) - Sorted entries now fetches the Path as well, prep for entries refactoring ([`4a1220e`](https://github.com/Byron/dua-cli/commit/4a1220eabf30db015463312000be7a2574c6e582)) - Show missing files in red. Also reveals: we need to refactor entries... ([`cade6b1`](https://github.com/Byron/dua-cli/commit/cade6b1dab7d17f3f277ed288d9498a9b435f65a)) - Make app.rs into module directory, incl. further splits ([`e9a8614`](https://github.com/Byron/dua-cli/commit/e9a8614152b6f719cc748c377ffe863b19a50b7e)) - Move sorted_entries closer to where it is used ([`50438ef`](https://github.com/Byron/dua-cli/commit/50438ef584d5f2ade0a0501ebca151c99893580f)) - Move application tests closer to... the application. Nice! ([`b0a02d3`](https://github.com/Byron/dua-cli/commit/b0a02d30f97d15e0c6fc19e5f4f7b8c56500ff7a)) - Moved 'interactive' portion of code into binary - break unit tests for now ([`80f01db`](https://github.com/Byron/dua-cli/commit/80f01dbfcce5c5c6d482a47d9f04fd5a0f8e75c0)) - Fix tests - column width changes ([`c7ee6b5`](https://github.com/Byron/dua-cli/commit/c7ee6b53b49a8c9489aa07bd7d262ec1d2b76349)) - Typo :D ([`240cc7a`](https://github.com/Byron/dua-cli/commit/240cc7a2de6116c999b048445587d99d8a656e84)) - Use most verbose visualization by default after scanning ([`39ad2a8`](https://github.com/Byron/dua-cli/commit/39ad2a80997c62f2c02fcd8cede591c0e5d303c4)) - Smoother visualization cycle ([`fcdc355`](https://github.com/Byron/dua-cli/commit/fcdc355fd8ebb187d144f6e3160fc74e21a0df41)) - Add Percentage and Bar at the same time!!! :D ([`5bde50f`](https://github.com/Byron/dua-cli/commit/5bde50f3f034aa833a8ea916542213ad0d1f6b1e)) - Add long bar visualization ([`59ad2e6`](https://github.com/Byron/dua-cli/commit/59ad2e66a269703aa7dc76ecd0398df1105f286d)) - Let byte visualization control its own width ([`a765f23`](https://github.com/Byron/dua-cli/commit/a765f232c3ad76ba5f688353aa37f02c46b42ec8)) - Cycle through graph and bar options ([`b0ea97f`](https://github.com/Byron/dua-cli/commit/b0ea97f6afa62019792bf0fcd73368ae4b9fbd85)) - First Bar implementation ([`5551c01`](https://github.com/Byron/dua-cli/commit/5551c0107fbe8a4a0ca9226e37d488b1f3c62dc7)) - Support for changing the percentage display ([`097bce8`](https://github.com/Byron/dua-cli/commit/097bce870f4294e83f2062c4f80304004e8556a0)) - Add support for static byte units ([`a1ecbf0`](https://github.com/Byron/dua-cli/commit/a1ecbf0a1a68ca7bb9f4e372e89b66ac3a945264)) - Add a decent header line ([`9d430a2`](https://github.com/Byron/dua-cli/commit/9d430a23d950edabfbeca55ba4805c48dfde99a3)) - Reformat ([`c8914ab`](https://github.com/Byron/dua-cli/commit/c8914abc499682fc60fa1e88fdaabc1140d0be7f)) - Wow, help scrolling is finally working! ([`09373b2`](https://github.com/Byron/dua-cli/commit/09373b26b8f6da9a3a2407a54b0735d41a960278)) - Tried to keep count of lines, but failed... it's hard to avoid allocations ([`31a90d7`](https://github.com/Byron/dua-cli/commit/31a90d7748678448d41b025d65981097fec26af3)) - Scrolling for the help window ([`7219392`](https://github.com/Byron/dua-cli/commit/72193928f6ef957def962d304de465510fb09b93)) - Implement tab key ([`1d1c351`](https://github.com/Byron/dua-cli/commit/1d1c3516432500fcf77f41146ad0119a2d97014f)) - Refactor ([`9fcc4fe`](https://github.com/Byron/dua-cli/commit/9fcc4fee324bb28ccdb900113a1ee42177bdeb45)) - The reamining hotkeys explained ([`5ece6f7`](https://github.com/Byron/dua-cli/commit/5ece6f74eaa5cbfbc5205f4f7ad486e6ad6c410f)) - Ready for the next paragraph ([`2b2bd4e`](https://github.com/Byron/dua-cli/commit/2b2bd4ea9a848d5e79ad5cc630fd86b1df2c93fd)) - Don't quit hard when hitting 'q' ([`5d30eb6`](https://github.com/Byron/dua-cli/commit/5d30eb65f91bc5a6ef501cb7c4e2d242762a02ea)) - Help comes to live, slowly ([`286bfd4`](https://github.com/Byron/dua-cli/commit/286bfd4cb2e3416fda987ff8ea9a6b70397b9970)) - Divert input events depending on the focus ([`e522160`](https://github.com/Byron/dua-cli/commit/e522160a66a770d88371922b479fc1f3837022b7)) - Nicer focus tracking ([`622b163`](https://github.com/Byron/dua-cli/commit/622b1630087135c60414b7947a37b8a145e7031f)) - First simple focus tracking ([`c19df21`](https://github.com/Byron/dua-cli/commit/c19df218c6addbbcbae9feccdfed4a75693be260)) - First sketch on how help window could work ([`13dd5b2`](https://github.com/Byron/dua-cli/commit/13dd5b289c73aab5caa1d06e5580635e88ef81ad)) - Another limitation in readme ([`cab0ec2`](https://github.com/Byron/dua-cli/commit/cab0ec257356aea1cfc947cfed35b6ee6b9b8024)) - Mild refactoring ([`17fe6f8`](https://github.com/Byron/dua-cli/commit/17fe6f8bccd81a7c2e2f6f8b72a2576589089725)) - Pretty colors in interactive mode ([`b7de02e`](https://github.com/Byron/dua-cli/commit/b7de02e35cd18fc596541a6561fcd617013ec8ce)) - Save an allocation ([`017be14`](https://github.com/Byron/dua-cli/commit/017be1445de9dad942aba164b15b41d24d0866f8)) - First compiling version of paragraph list + entries ([`ce9df24`](https://github.com/Byron/dua-cli/commit/ce9df2498ae07a49f65b63c73838d3fc8b1e9ae6)) - Rename 'human*' formats to their non-prefixed counterpart ([`d13adea`](https://github.com/Byron/dua-cli/commit/d13adea1958081e430703be84829b3c03c5f3e26)) - Properly fix byte column width handling ([`a5c8e37`](https://github.com/Byron/dua-cli/commit/a5c8e37b970169913ab72ea691b89aeeeffad403)) - Refactor ([`7d451f9`](https://github.com/Byron/dua-cli/commit/7d451f968908549babd06e7858d7a5263b1737a3)) - Implement list with paragraphs ([`593b10f`](https://github.com/Byron/dua-cli/commit/593b10f2dba54e78093e51ebf8621e5bb88a8401)) - First sketch of 'better' list - support for paragraphs for each item ([`a5a7c06`](https://github.com/Byron/dua-cli/commit/a5a7c0606f33e125f375110ee06db828295b02e7)) - Continuous lines for entry items ([`0121a64`](https://github.com/Byron/dua-cli/commit/0121a648c4445f3cd807f53c6ba914cd8507e40d)) - Add 'make test' target, fix unit tests ([`2338e75`](https://github.com/Byron/dua-cli/commit/2338e751c40284fe49643767dd33be3230f63440)) - Fix byte formatting ([`2022a51`](https://github.com/Byron/dua-cli/commit/2022a51ce4960923fc5376d8d9b10185319c8c34)) - Prettier footer - one-line paragraphs for the win ([`9abc39b`](https://github.com/Byron/dua-cli/commit/9abc39ba9435ff994c0262417af9bd46abb76774)) - Better message handling ([`1dec5d4`](https://github.com/Byron/dua-cli/commit/1dec5d49faf04e60047b3823ca7b23b8b4b9499a)) - Move list scrolling code into list state ([`e3b0a25`](https://github.com/Byron/dua-cli/commit/e3b0a2585a110fecbfedb007e01b057deee3daaf)) - Proper entries list scrolling ([`3a10bfe`](https://github.com/Byron/dua-cli/commit/3a10bfef5b3611beb1ef778eb6fa46d7f7a62009)) - Now widgets can just update their drawstate at will ([`9247af6`](https://github.com/Byron/dua-cli/commit/9247af6d91bdd7bef2d9a49b27d09c0b7f77a8da)) - Since performance doesn't matter here, always update widget state ([`1d27826`](https://github.com/Byron/dua-cli/commit/1d27826999f4a60d17c0d2b9a76b604edd2aa343)) - A version with manual update and mutable widget state (even during draw) ([`156c842`](https://github.com/Byron/dua-cli/commit/156c84264e0d1a967e7c5039596e88282c38dbf0)) - Using utility types would work, but shows it's too enforcing ([`6f81e63`](https://github.com/Byron/dua-cli/commit/6f81e63c78999b03dfecaef73f6b2ce6f397c88a)) - Non-mutable widget state ([`971e235`](https://github.com/Byron/dua-cli/commit/971e235153f57dd87c763e8c0a07a3f79ad7375c)) - Sketch to see how mutable widget state would look like ([`7ce062f`](https://github.com/Byron/dua-cli/commit/7ce062f010508bac368f389f4cadd2f6cc44df62)) - Refactor ([`f6f6a7d`](https://github.com/Byron/dua-cli/commit/f6f6a7d4d7c8886236ddca4bfa3a7d7a7d4a3d9c)) - It shows that making the stateless GUI work with list scrolling... needs state ([`92c636c`](https://github.com/Byron/dua-cli/commit/92c636c0f0cd38c10f2f76b16c6d70c159909e1b)) - Ignore ds-store ([`1ff799e`](https://github.com/Byron/dua-cli/commit/1ff799e725c5cbdea33f952495211708482e2b73)) - Separate modules files for widgets ([`74dc7e0`](https://github.com/Byron/dua-cli/commit/74dc7e07813503c7c1c3d5ff0c6cd4b3f2d9ad01)) - First step towards modularizing widgets ([`fa9f68a`](https://github.com/Byron/dua-cli/commit/fa9f68aca5bdc9dd5555a0acd8f9249044cbec6a)) - Be sure to hide the cursor explicitly ([`2937b5d`](https://github.com/Byron/dua-cli/commit/2937b5d558c7c7aff00e8b08064ace3c4b77fc37)) - Page up and down in navigation ([`a2b4c9c`](https://github.com/Byron/dua-cli/commit/a2b4c9cc42f92af949ad6002aa85d87684e7437c)) - Removed support to change amount of storable nodes ([`2aad00a`](https://github.com/Byron/dua-cli/commit/2aad00a568b31120144a16e80965be0495cf036f)) - Add support for messages in the footer ([`b255e63`](https://github.com/Byron/dua-cli/commit/b255e63193cbb5e8e09c169334df2b2c35e2a5e7)) - The first version of list scrolling... works but funnily :D ([`6e21175`](https://github.com/Byron/dua-cli/commit/6e211754964fd9f1257be7fdeecc74b58543b120)) - Refactor ([`85726c7`](https://github.com/Byron/dua-cli/commit/85726c71cdc0f1f83db626accfe7b0991b6c6dcd)) - Refactor ([`5da79a5`](https://github.com/Byron/dua-cli/commit/5da79a52ccd25ae068b8f0c2ab4070d4529319c3)) - Add 'O' to open a folder or file using the default program ([`4f4ea1e`](https://github.com/Byron/dua-cli/commit/4f4ea1e9b3813062ebe87032339bd4bcd87ee3b4)) - Fix unit tests ([`bc80db2`](https://github.com/Byron/dua-cli/commit/bc80db2b3f026cc10f9a06f0db624d32c1bd807f)) - Improve title display, deal with relative paths ([`5b4d44c`](https://github.com/Byron/dua-cli/commit/5b4d44c0121db981a61a838db18a5e6ccf4660bf)) - Better title for entries, based on the paths your are in ([`74870ba`](https://github.com/Byron/dua-cli/commit/74870bae69ed9bfe34e75ef82e3d76bc6f98e160)) - Move 'traverse' module out of 'interactive' - it's unrelated ([`fb57ebd`](https://github.com/Byron/dua-cli/commit/fb57ebd0423775c4c9b757a2fad588f8baa5beec)) - Add 'u' key to go up one level ([`84b6f8c`](https://github.com/Byron/dua-cli/commit/84b6f8ce829e7a57604b4e983c91bc52a7299ac4)) - Show directories very similar to ncdu ([`74e5116`](https://github.com/Byron/dua-cli/commit/74e511631a7f05143e487584a4325fe65c774ba5)) - Add 'o' navigation ([`25ceae2`](https://github.com/Byron/dua-cli/commit/25ceae2779e3e20b4ff4ac3d6149410e5f851775)) - Add 'k' navigation key ([`748dfc3`](https://github.com/Byron/dua-cli/commit/748dfc353a7d8c7bbb6bbfb097bacec18b80e32a)) - Add 'j' key functionality for basic navigation ([`a76ad50`](https://github.com/Byron/dua-cli/commit/a76ad5009ac9177e1efb37130d1dcedb5df1e5de)) - Make working with nodes less cumbersome in unit tests ([`1cfb627`](https://github.com/Byron/dua-cli/commit/1cfb62722d25ee17109fd0073e3cd0ac6a022ffa)) - Compute percentage (at all), non-graphical for now ([`df0fe62`](https://github.com/Byron/dua-cli/commit/df0fe6279065ba060803e236a73336bdcf8fe4dd)) - Preliminary styling for selected entries ([`90f94f7`](https://github.com/Byron/dua-cli/commit/90f94f79ac54689c4af47ad31e1080da725cd7ed)) - Unify sorting to start dealing with selections ([`0b3e158`](https://github.com/Byron/dua-cli/commit/0b3e158085d68ba43dc3ac034ce4f0b5df9d61e8)) - Smaller release binaries! ([`b3dc836`](https://github.com/Byron/dua-cli/commit/b3dc836baa00e36c56f823e9e5b3e9118fdd8b30)) - Test for handling the root correctly in interactive mode ([`59a3001`](https://github.com/Byron/dua-cli/commit/59a3001012d5ff40d050a1abfc370aaa248d8f66)) - The first test for user input, yeah! ([`05c8ec1`](https://github.com/Byron/dua-cli/commit/05c8ec1a6e2ce9af3f55d75cb761cf3b66244bb8)) - Prepare for mutable state in application, even more :D ([`11147d8`](https://github.com/Byron/dua-cli/commit/11147d8e344435b95adaca68e5125836c0bf2ed9)) - Prepare for handling mutable application state ([`e48898b`](https://github.com/Byron/dua-cli/commit/e48898ba98312be9e77b2d5cc8a64a127ac59688)) - Sorting by size, descending, for entries ([`e8cb9dc`](https://github.com/Byron/dua-cli/commit/e8cb9dcda01d5dc073dfb8093f66bd13d5699105)) - Don't display '0' for total bytes while traversing ([`9720931`](https://github.com/Byron/dua-cli/commit/9720931800fd8e189c99cbf0cb01a31f23663744)) - Assure root size is properly computed ([`dcf3a26`](https://github.com/Byron/dua-cli/commit/dcf3a2651b79493964feb16d8a2148e851a7b4ca)) - Refactor ([`1f482aa`](https://github.com/Byron/dua-cli/commit/1f482aab49a9094234d422b3599858e909c3f164)) - Document reasoning for using termion everywhere ([`0cc49f5`](https://github.com/Byron/dua-cli/commit/0cc49f5cbbd383f57a2f628711cabf36a38de2c0)) - Separate Footer widget; refresh display before event loop ([`4112a9b`](https://github.com/Byron/dua-cli/commit/4112a9b971f36c69df8f8a07fdc2735edd862a45)) - Bytes formatting for interactive + footer ([`7eb8574`](https://github.com/Byron/dua-cli/commit/7eb857467c6d2603129edbaea636ef0d118fa064)) - Explicitly declare an init-window ([`b919c50`](https://github.com/Byron/dua-cli/commit/b919c501a249dcf626e390d496faf6d31a9e71ac)) - Minimal event handling to allow viewing the TUI ([`7f4fb35`](https://github.com/Byron/dua-cli/commit/7f4fb350903fe32f513ddc39ff62de2c1d663e0f)) - Pull out draw code into closure ([`4ec1d37`](https://github.com/Byron/dua-cli/commit/4ec1d37e01337ca22060e44dda36d71ffdc21146)) - Prepare decoupling ([`598a6b0`](https://github.com/Byron/dua-cli/commit/598a6b0ec9582cdec27285d25ab09d0efa0b7db0)) - Refactor ([`6cf44a1`](https://github.com/Byron/dua-cli/commit/6cf44a1658f4f34ffa295b49fbb4cc6cb7c75b9f)) - Move modules into their own files ([`2ce606f`](https://github.com/Byron/dua-cli/commit/2ce606f607fa967f94d49c5413c4b347e628e88e)) - First sketch of drawing code - it's quite neat and straightforward ([`24097bd`](https://github.com/Byron/dua-cli/commit/24097bd19ee53ca7a4a635e6ea63c3e3c63bdc2b)) - Infrastructure for screen updates while gathering data ([`7c2628e`](https://github.com/Byron/dua-cli/commit/7c2628eedaa0d8b1bbe4dc9fbb3fbdc72de34c13)) - Refactor - better, and it shows it's clearly two distinct things ([`2707445`](https://github.com/Byron/dua-cli/commit/2707445ec0fcfa42b4cb9e63114081bd43198742)) - Refactor - still ain't pretty, but it's good enough for now ([`d4918ba`](https://github.com/Byron/dua-cli/commit/d4918ba23cd0a73a7d5c5ec419777261b5a30228)) - Very hacky passing tests... let's refactor that! ([`59b2930`](https://github.com/Byron/dua-cli/commit/59b2930fb719954d793efa7bc586d61098d6ee21)) - Add another failing test ([`00952c6`](https://github.com/Byron/dua-cli/commit/00952c6aa7b585cd27712ab75fd854d8cec11fc4)) - And now it seems to work... not trusting it just yet ([`16833be`](https://github.com/Byron/dua-cli/commit/16833be086fe7c15b10e902ae309533dba5382d9)) - Now computation actually works - next up is handling of the root ([`e03dd10`](https://github.com/Byron/dua-cli/commit/e03dd10b5f9f5593d6791968e40e8454ca7ea102)) - Probably a bit closer to a correct implementation. ([`f0e53be`](https://github.com/Byron/dua-cli/commit/f0e53be0fe93c53269399b3c7c843266dcae5b88)) - Add test showing sizes don't work, and graph traversal neither :D ([`dec4afc`](https://github.com/Byron/dua-cli/commit/dec4afc358aa30521d564068b219eca129245782)) - Tree building works - next: sizes ([`5a7ee1b`](https://github.com/Byron/dua-cli/commit/5a7ee1bf881518b6cd33a1880fabd12aa53553bf)) - One step closer to the actual tree-building implementation ([`7c3743d`](https://github.com/Byron/dua-cli/commit/7c3743d601cce407024e65570d108867a6196893)) - First failing attempt to build a graph on demand ([`0774ecc`](https://github.com/Byron/dua-cli/commit/0774eccb72abfd800880cbc8490cb9899f1ab140)) - First failing test - even though just a guess :D ([`68569c6`](https://github.com/Byron/dua-cli/commit/68569c69f5fdeedddd45635e8eb6d0c255de53f4)) - Some more inspiration ([`396ab0b`](https://github.com/Byron/dua-cli/commit/396ab0b5adbb0a29c6b4db77b30893978752329e)) - First infrastructure for unit-level tests ([`1c53865`](https://github.com/Byron/dua-cli/commit/1c538654fba3caf7f7d601d6bf8a4af24faf19c8)) - Basic frame to support new interactive mode ([`6d82a72`](https://github.com/Byron/dua-cli/commit/6d82a724b0452e417e20cbe8a02e3bed647e9674)) - Highlight files with a different color ([`495ccbd`](https://github.com/Byron/dua-cli/commit/495ccbda25cb27dc912c07fbdb29651b83f32c68))
## v1.1.0 (2019-06-01) ### Commit Statistics - 1 commit contributed to the release. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Simplified handling of 'no paths given' case ([`ae0182f`](https://github.com/Byron/dua-cli/commit/ae0182f09c0e2c3c77298cb431421cbdc64c0fa8))
## 1.0.0 (2019-06-01) Simple CLI to list top-level directories similar to sn-sort, but faster and more tailored to getting an idea of where most space is used. ### Commit Statistics - 27 commits contributed to the release over the course of 3 calendar days. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages ### Commit Details
view details * **Uncategorized** - Add description to Cargo.toml ([`a53c2ac`](https://github.com/Byron/dua-cli/commit/a53c2acb65457df740f3605124b9e42d363897de)) - Better readme ([`e8a83e7`](https://github.com/Byron/dua-cli/commit/e8a83e779f694a8ba2a264a5def7add6d65b191c)) - Add asciicast ([`a66cf95`](https://github.com/Byron/dua-cli/commit/a66cf95bf57f477eae7a8ef307fd62a4df0da76d)) - Now with colored help ([`3798be8`](https://github.com/Byron/dua-cli/commit/3798be8a31902a74f4c0280d0d1def8d6bb74d10)) - Prepare for release ([`28079ec`](https://github.com/Byron/dua-cli/commit/28079ec7d976aef0eacd88e0090f05ad87219558)) - Create LICENSE ([`0678400`](https://github.com/Byron/dua-cli/commit/06784008779ceace1fabd55f271996e406f6502b)) - Udpate readme ([`0ae156e`](https://github.com/Byron/dua-cli/commit/0ae156e5a1b6e3f7be2c61cba2a882d8a8a933c4)) - Add minimal library documentation ([`310cd6a`](https://github.com/Byron/dua-cli/commit/310cd6af912cda7333496d5d5d80a68d6ea9b155)) - Support for colors. Using green, which might be invisible to some! ([`9d09499`](https://github.com/Byron/dua-cli/commit/9d0949933cb46d2e73c047b5f06201dbd75bca1d)) - Add simple statistics, just for fun! ([`498bcd0`](https://github.com/Byron/dua-cli/commit/498bcd0da4dc44d04634f2cabc245f4c46d2c46a)) - Sort by size in bytes by default; can be turned off for immediate feedback ([`f8c3ba2`](https://github.com/Byron/dua-cli/commit/f8c3ba29134af08ea7b70b4fe3951307c6be6e3a)) - Nicer formatting of numbers ([`e7da784`](https://github.com/Byron/dua-cli/commit/e7da7843ad7894a3560b4d70076a74798404da94)) - Make explicit that Sorting is disabled during aggregation; more spacing ([`9ba5a34`](https://github.com/Byron/dua-cli/commit/9ba5a348c67a898abb0ae648e686da48649a33df)) - Pull out all modules into files ([`8b2ef49`](https://github.com/Byron/dua-cli/commit/8b2ef49bf9f37d0e126fa68115175fe2cf82aaf5)) - Add --no-total option ([`961b743`](https://github.com/Byron/dua-cli/commit/961b743773da2a5112bd4ab70554c50b03ded3ad)) - Better error reporting ([`c1cbcf3`](https://github.com/Byron/dua-cli/commit/c1cbcf355755fbd1ca6124cdba3b8e361a7bebf2)) - Support for paths specification without subcommand ([`c50332c`](https://github.com/Byron/dua-cli/commit/c50332cead2688e40de192e1b47e50a662763a78)) - Compute the total if there are more than one paths ([`04ce0c9`](https://github.com/Byron/dua-cli/commit/04ce0c9312fb5e290d6fbaed8e9427bec3f3e1c6)) - Support for various byte formats ([`7dc718b`](https://github.com/Byron/dua-cli/commit/7dc718bd03f7f669638d87b4c5fee67700f045ca)) - Add byte formatting ([`6db07e2`](https://github.com/Byron/dua-cli/commit/6db07e2e69f7f674191311719054a245e8c8b886)) - By not counting directories, we get the correct amount of bytes ([`a19e3d7`](https://github.com/Byron/dua-cli/commit/a19e3d76fe559f59be467b4967156509e6f26715)) - Let's just say we compute the aggregate correctly ([`61ca52a`](https://github.com/Byron/dua-cli/commit/61ca52a2a8b23daffc3eea1fe8d71078e757a0d3)) - An attempt to abstract link size, but it's not required actually :D ([`04f50bd`](https://github.com/Byron/dua-cli/commit/04f50bdcdbe995e7d9952788eb4cc4f736299c39)) - First basic implementation of aggregation; symlinks are not handled yet ([`638be3c`](https://github.com/Byron/dua-cli/commit/638be3c8e7362b809c2c6558d630aa355349b1e8)) - The first failing test ([`449f964`](https://github.com/Byron/dua-cli/commit/449f964850feb89d8a179bbc8a45cea6580577eb)) - Mission statement and first tasks, to get started ([`247a3b9`](https://github.com/Byron/dua-cli/commit/247a3b9dc851237288fd243a9029afcec6453e5d)) - First instantiation of template ([`e9a4472`](https://github.com/Byron/dua-cli/commit/e9a447250ba9ffd10f94f6f7d970c6da141c185d))
## v2.10.6 Fix `dua -h` usage string. ## 1.2.0 The first usable, read-only interactive terminal user interface. That's that. We also use `tui-react`, something that makes it much more pleasant to handle the application and GUI state. dua-cli-2.34.0/Cargo.lock0000644000001333201046102023000104370ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "addr2line" version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] [[package]] name = "adler2" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "allocator-api2" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "android_system_properties" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ "libc", ] [[package]] name = "anstream" version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", "windows-sys 0.60.2", ] [[package]] name = "anyhow" version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backtrace" version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", "windows-link", ] [[package]] name = "bitflags" version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "bstr" version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" dependencies = [ "memchr", "regex-automata", "serde", ] [[package]] name = "bumpalo" version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "byte-unit" version = "4.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da78b32057b8fdfc352504708feeba7216dcd65a2c9ab02978cbd288d1279b6c" dependencies = [ "serde", "utf8-width", ] [[package]] name = "cassowary" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] name = "castaway" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" dependencies = [ "rustversion", ] [[package]] name = "cc" version = "1.2.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" dependencies = [ "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ "iana-time-zone", "num-traits", "windows-link", ] [[package]] name = "clap" version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", "clap_derive", ] [[package]] name = "clap_builder" version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", "clap_lex", "strsim", ] [[package]] name = "clap_complete" version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e602857739c5a4291dfa33b5a298aeac9006185229a700e5810a3ef7272d971" dependencies = [ "clap", ] [[package]] name = "clap_derive" version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck", "proc-macro2", "quote", "syn", ] [[package]] name = "clap_lex" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "colorchoice" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "compact_str" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" dependencies = [ "castaway", "cfg-if", "itoa", "ryu", "static_assertions", ] [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "crossbeam" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-epoch", "crossbeam-queue", "crossbeam-utils", ] [[package]] name = "crossbeam-channel" version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-queue" version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossterm" version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" dependencies = [ "bitflags", "crossterm_winapi", "libc", "mio", "parking_lot", "signal-hook", "signal-hook-mio", "winapi", ] [[package]] name = "crossterm_winapi" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" dependencies = [ "winapi", ] [[package]] name = "diff" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "dirs" version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", "redox_users", "windows-sys 0.61.2", ] [[package]] name = "dua-cli" version = "2.34.0" dependencies = [ "anyhow", "bstr", "byte-unit", "chrono", "clap", "clap_complete", "crossbeam", "crossterm", "dirs", "fern", "filesize", "gix-glob", "gix-path", "human_format", "itertools 0.14.0", "jiff", "jwalk", "log", "log-panics", "num_cpus", "once_cell", "open", "owo-colors", "petgraph", "pretty_assertions", "ratatui", "serde", "shlex", "toml", "trash", "unicode-segmentation", "unicode-width 0.2.2", "wild", ] [[package]] name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "fern" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4316185f709b23713e41e3195f90edef7fb00c3ed4adc79769cf09cc762a3b29" dependencies = [ "log", ] [[package]] name = "filesize" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12d741e2415d4e2e5bd1c1d00409d1a8865a57892c2d689b504365655d237d43" dependencies = [ "winapi", ] [[package]] name = "find-msvc-tools" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" [[package]] name = "fixedbitset" version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "foldhash" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "getrandom" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "gimli" version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "gix-features" version = "0.44.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa64593d1586135102307fb57fb3a9d3868b6b1f45a4da1352cce5070f8916a" dependencies = [ "gix-trace", "libc", ] [[package]] name = "gix-glob" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74254992150b0a88fdb3ad47635ab649512dff2cbbefca7916bb459894fc9d56" dependencies = [ "bitflags", "bstr", "gix-features", "gix-path", ] [[package]] name = "gix-path" version = "0.10.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0416b41cd00ff292af9b94b0660880c44bd2ed66828ddca9a2b333535cbb71b8" dependencies = [ "bstr", "gix-trace", "gix-validate", "home", "thiserror", ] [[package]] name = "gix-trace" version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d3f59a8de2934f6391b6b3a1a7654eae18961fcb9f9c843533fed34ad0f3457" [[package]] name = "gix-validate" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b1e63a5b516e970a594f870ed4571a8fdcb8a344e7bd407a20db8bd61dbfde4" dependencies = [ "bstr", "thiserror", ] [[package]] name = "glob" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "hashbrown" version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", "foldhash", ] [[package]] name = "hashbrown" version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "home" version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ "windows-sys 0.61.2", ] [[package]] name = "human_format" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c3b1f728c459d27b12448862017b96ad4767b1ec2ec5e6434e99f1577f085b8" [[package]] name = "iana-time-zone" version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "log", "wasm-bindgen", "windows-core 0.62.2", ] [[package]] name = "iana-time-zone-haiku" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ "cc", ] [[package]] name = "indexmap" version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown 0.16.0", ] [[package]] name = "is-docker" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" dependencies = [ "once_cell", ] [[package]] name = "is-wsl" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" dependencies = [ "is-docker", "once_cell", ] [[package]] name = "is_terminal_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] [[package]] name = "itertools" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itertools" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e67e8da4c49d6d9909fe03361f9b620f58898859f5c7aded68351e85e71ecf50" dependencies = [ "jiff-static", "jiff-tzdb-platform", "log", "portable-atomic", "portable-atomic-util", "serde_core", "windows-sys 0.61.2", ] [[package]] name = "jiff-static" version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0c84ee7f197eca9a86c6fd6cb771e55eb991632f15f2bc3ca6ec838929e6e78" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "jiff-tzdb" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68971ebff725b9e2ca27a601c5eb38a4c5d64422c4cbab0c535f248087eda5c2" [[package]] name = "jiff-tzdb-platform" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" dependencies = [ "jiff-tzdb", ] [[package]] name = "js-sys" version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", ] [[package]] name = "jwalk" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2735847566356cd2179a2a38264839308f7079fa96e6bd5a42d740460e003c56" dependencies = [ "crossbeam", "rayon", ] [[package]] name = "libc" version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libredox" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ "bitflags", "libc", ] [[package]] name = "lock_api" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ "scopeguard", ] [[package]] name = "log" version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "log-panics" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68f9dd8546191c1850ecf67d22f5ff00a935b890d0e84713159a55495cc2ac5f" dependencies = [ "backtrace", "log", ] [[package]] name = "lru" version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ "hashbrown 0.15.5", ] [[package]] name = "memchr" version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "miniz_oxide" version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", ] [[package]] name = "mio" version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", "wasi", "windows-sys 0.48.0", ] [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ "hermit-abi", "libc", ] [[package]] name = "objc2" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" dependencies = [ "objc2-encode", ] [[package]] name = "objc2-encode" version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" [[package]] name = "objc2-foundation" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ "bitflags", "objc2", ] [[package]] name = "object" version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] [[package]] name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "open" version = "5.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2483562e62ea94312f3576a7aca397306df7990b8d89033e18766744377ef95" dependencies = [ "is-wsl", "libc", "pathdiff", ] [[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "owo-colors" version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" [[package]] name = "parking_lot" version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", "windows-link", ] [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pathdiff" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "percent-encoding" version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "petgraph" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" dependencies = [ "fixedbitset", "hashbrown 0.15.5", "indexmap", "serde", ] [[package]] name = "portable-atomic" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5" dependencies = [ "portable-atomic", ] [[package]] name = "pretty_assertions" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" dependencies = [ "diff", "yansi", ] [[package]] name = "proc-macro2" version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] [[package]] name = "ratatui" version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f44c9e68fd46eda15c646fbb85e1040b657a58cdc8c98db1d97a55930d991eef" dependencies = [ "bitflags", "cassowary", "compact_str", "crossterm", "itertools 0.12.1", "lru", "paste", "stability", "strum", "unicode-segmentation", "unicode-truncate", "unicode-width 0.1.14", ] [[package]] name = "rayon" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", ] [[package]] name = "rayon-core" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", ] [[package]] name = "redox_syscall" version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags", ] [[package]] name = "redox_users" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom", "libredox", "thiserror", ] [[package]] name = "regex-automata" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" [[package]] name = "rustc-demangle" version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustversion" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", ] [[package]] name = "serde_core" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_spanned" version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook" version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" dependencies = [ "libc", "signal-hook-registry", ] [[package]] name = "signal-hook-mio" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" dependencies = [ "libc", "mio", "signal-hook", ] [[package]] name = "signal-hook-registry" version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" dependencies = [ "libc", ] [[package]] name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "stability" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac" dependencies = [ "quote", "syn", ] [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ "heck", "proc-macro2", "quote", "rustversion", "syn", ] [[package]] name = "syn" version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "thiserror" version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "toml" version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", "toml_datetime", "toml_edit", ] [[package]] name = "toml_datetime" version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", "toml_write", "winnow", ] [[package]] name = "toml_write" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "trash" version = "5.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9b93a14fcf658568eb11b3ac4cb406822e916e2c55cdebc421beeb0bd7c94d8" dependencies = [ "chrono", "libc", "log", "objc2", "objc2-foundation", "once_cell", "percent-encoding", "scopeguard", "urlencoding", "windows", ] [[package]] name = "unicode-ident" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-segmentation" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-truncate" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" dependencies = [ "itertools 0.13.0", "unicode-segmentation", "unicode-width 0.1.14", ] [[package]] name = "unicode-width" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-width" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "urlencoding" version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" [[package]] name = "utf8-width" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasm-bindgen" version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ "bumpalo", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] [[package]] name = "wild" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3131afc8c575281e1e80f36ed6a092aa502c08b18ed7524e86fbbb12bb410e1" dependencies = [ "glob", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132" dependencies = [ "windows-core 0.56.0", "windows-targets 0.52.6", ] [[package]] name = "windows-core" version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6" dependencies = [ "windows-implement 0.56.0", "windows-interface 0.56.0", "windows-result 0.1.2", "windows-targets 0.52.6", ] [[package]] name = "windows-core" version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement 0.60.2", "windows-interface 0.59.3", "windows-link", "windows-result 0.4.1", "windows-strings", ] [[package]] name = "windows-implement" version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "windows-implement" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "windows-interface" version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "windows-interface" version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-result" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-result" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ "windows-link", ] [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets 0.48.5", ] [[package]] name = "windows-sys" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ "windows-targets 0.53.5", ] [[package]] name = "windows-sys" version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ "windows-link", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] [[package]] name = "windows-targets" version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ "windows-link", "windows_aarch64_gnullvm 0.53.1", "windows_aarch64_msvc 0.53.1", "windows_i686_gnu 0.53.1", "windows_i686_gnullvm 0.53.1", "windows_i686_msvc 0.53.1", "windows_x86_64_gnu 0.53.1", "windows_x86_64_gnullvm 0.53.1", "windows_x86_64_msvc 0.53.1", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] [[package]] name = "yansi" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" dua-cli-2.34.0/Cargo.toml0000644000000062251046102023000104650ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2024" name = "dua-cli" version = "2.34.0" authors = ["Sebastian Thiel "] build = false include = [ "src/**/*", "Cargo.*", "LICENSE", "README.md", "CHANGELOG.md", "!**/tests/*", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "A tool to conveniently learn about the disk usage of directories, fast!" readme = "README.md" license = "MIT" repository = "https://github.com/Byron/dua-cli" [features] default = [ "tui-crossplatform", "trash-move", ] trash-move = ["trash"] tui-crossplatform = [ "crossterm", "tui", "open", "unicode-segmentation", "unicode-width", ] [lib] name = "dua" path = "src/lib.rs" [[bin]] name = "dua" path = "src/main.rs" [dependencies.anyhow] version = "1.0.31" [dependencies.bstr] version = "1.8.0" [dependencies.byte-unit] version = "4" [dependencies.chrono] version = "0.4.31" features = ["std"] default-features = false [dependencies.clap] version = "4.0.29" features = [ "derive", "env", ] [dependencies.clap_complete] version = "4.5.54" [dependencies.crossbeam] version = "0.8" [dependencies.crossterm] version = "0.27.0" optional = true [dependencies.dirs] version = "6" [dependencies.fern] version = "0.7.1" [dependencies.filesize] version = "0.2.0" [dependencies.gix-glob] version = "0.22.1" [dependencies.gix-path] version = "0.10.10" [dependencies.human_format] version = "1.0.3" [dependencies.itertools] version = "0.14.0" [dependencies.jiff] version = "0.2.18" [dependencies.jwalk] version = "0.8.1" [dependencies.log] version = "0.4.20" [dependencies.log-panics] version = "2" features = ["with-backtrace"] [dependencies.num_cpus] version = "1.10.0" [dependencies.once_cell] version = "1.19" [dependencies.open] version = "5.0" optional = true [dependencies.owo-colors] version = "4.0.0" [dependencies.petgraph] version = "0.8.3" [dependencies.serde] version = "1.0" features = ["derive"] [dependencies.shlex] version = "1.3.0" [dependencies.toml] version = "0.8" [dependencies.trash] version = "5.2.0" features = [ "coinit_apartmentthreaded", "chrono", ] optional = true default-features = false [dependencies.tui] version = "0.26.1" features = ["crossterm"] optional = true default-features = false package = "ratatui" [dependencies.unicode-segmentation] version = "1.3.0" optional = true [dependencies.unicode-width] version = "0.2.0" optional = true [dependencies.wild] version = "2.0.4" [dev-dependencies.pretty_assertions] version = "1.0.0" [lints.clippy] all = "deny" [profile.release] lto = "fat" panic = "abort" overflow-checks = false incremental = false [profile.release.build-override] opt-level = 3 dua-cli-2.34.0/Cargo.toml.orig000064400000000000000000000037531046102023000141270ustar 00000000000000[package] name = "dua-cli" version = "2.34.0" authors = ["Sebastian Thiel "] edition = "2024" repository = "https://github.com/Byron/dua-cli" readme = "README.md" description = "A tool to conveniently learn about the disk usage of directories, fast!" license = "MIT" include = [ "src/**/*", "Cargo.*", "LICENSE", "README.md", "CHANGELOG.md", "!**/tests/*", ] [features] default = ["tui-crossplatform", "trash-move"] tui-crossplatform = [ "crossterm", "tui", "open", "unicode-segmentation", "unicode-width", ] trash-move = ["trash"] [dependencies] clap = { version = "4.0.29", features = ["derive", "env"] } clap_complete = "4.5.54" jwalk = "0.8.1" byte-unit = "4" petgraph = "0.8.3" itertools = "0.14.0" num_cpus = "1.10.0" filesize = "0.2.0" anyhow = "1.0.31" trash = { version = "5.2.0", optional = true, default-features = false, features = [ "coinit_apartmentthreaded", "chrono" ] } chrono = { version = "0.4.31", default-features = false, features = ["std"] } # 'tui' related unicode-segmentation = { version = "1.3.0", optional = true } unicode-width = { version = "0.2.0", optional = true } crossterm = { version = "0.27.0", optional = true } tui = { package = "ratatui", version = "0.26.1", optional = true, default-features = false, features = [ "crossterm", ] } open = { version = "5.0", optional = true } wild = "2.0.4" owo-colors = "4.0.0" human_format = "1.0.3" once_cell = "1.19" gix-glob = "0.22.1" gix-path = "0.10.10" bstr = "1.8.0" fern = "0.7.1" jiff = "0.2.18" log = "0.4.20" log-panics = { version = "2", features = ["with-backtrace"] } crossbeam = "0.8" toml = "0.8" serde = { version = "1.0", features = ["derive"] } dirs = "6" shlex = "1.3.0" [[bin]] name = "dua" path = "src/main.rs" [lib] name = "dua" [profile.release] panic = 'abort' incremental = false overflow-checks = false lto = "fat" #codegen-units = 1 build-override = { opt-level = 3 } [dev-dependencies] pretty_assertions = "1.0.0" [lints.clippy] all = "deny" dua-cli-2.34.0/LICENSE000064400000000000000000000020601046102023000122330ustar 00000000000000MIT License Copyright (c) 2019 Sebastian Thiel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. dua-cli-2.34.0/README.md000064400000000000000000000171121046102023000125110ustar 00000000000000[![Rust](https://github.com/Byron/dua-cli/workflows/Rust/badge.svg)](https://github.com/byron/dua-cli/actions) [![Crates.io](https://img.shields.io/crates/v/dua-cli.svg)](https://crates.io/crates/dua-cli) [![Packaging status](https://repology.org/badge/tiny-repos/dua-cli.svg)](https://repology.org/project/dua-cli/badges) **dua** (-> _Disk Usage Analyzer_) is a tool to conveniently learn about the usage of disk space of a given directory. It's parallel by default and will max out your SSD, providing relevant information as fast as possible. Optionally delete superfluous data, and do so more quickly than `rm`. [![asciicast](https://asciinema.org/a/kDnXUOeqBxZVMoWuFNqzfpeey.svg)](https://asciinema.org/a/kDnXUOeqBxZVMoWuFNqzfpeey) ### Installation ### Binary Release #### MacOS ```sh curl -LSfs https://raw.githubusercontent.com/Byron/dua-cli/master/ci/install.sh | \ sh -s -- --git Byron/dua-cli --crate dua --tag v2.29.0 ``` #### MacOS via [MacPorts](https://www.macports.org): ```sh sudo port selfupdate sudo port install dua-cli ``` #### MacOS via [Homebrew](https://brew.sh) ```sh brew update brew install dua-cli ``` #### Linux Linux requires the target to be specified explicitly to obtain the MUSL build. ```sh curl -LSfs https://raw.githubusercontent.com/Byron/dua-cli/master/ci/install.sh | \ sh -s -- --git Byron/dua-cli --target x86_64-unknown-linux-musl --crate dua --tag v2.29.0 ``` #### Windows via [Scoop](https://scoop.sh/) ```sh scoop install dua ``` #### Windows via [WinGet](https://learn.microsoft.com/en-us/windows/package-manager/winget/) ```sh winget install Byron.dua-cli ``` #### Pre-built Binaries See the [releases section][releases] for manual installation of a binary, pre-built for many platforms. [releases]: https://github.com/Byron/dua-cli/releases #### Cargo Via `cargo`, which can be obtained using [rustup][rustup] For _Unix_… ``` cargo install dua-cli # And if you don't need a terminal user interface (most compatible) cargo install dua-cli --no-default-features # Compiles on most platforms, with terminal user interface cargo install dua-cli --no-default-features --features tui-crossplatform ``` For _Windows_, nightly features are currently required. ``` cargo +nightly install dua-cli ``` #### VoidLinux Via `xbps` on your VoidLinux system. ``` xbps-install dua-cli ``` #### Fedora Via `dnf` on your Fedora system. ``` sudo dnf install dua-cli ``` #### Arch Linux Via `pacman` on your ArchLinux system. ``` sudo pacman -S dua-cli ``` #### NixOS https://search.nixos.org/packages?query=dua Nix-shell (temporary) ``` nix-shell -p dua ``` NixOS configuration ``` environment.systemPackages = [ pkgs.dua ]; ``` #### NetBSD Via `pkgin` on your NetBSD system. ``` pkgin install dua-cli ``` Or, building from source ``` cd /usr/pkgsrc/sysutils/dua-cli make install ``` #### Windows You will find pre-built binaries for Windows in the [releases section][releases]. Alternatively, install via cargo as in ``` cargo +nightly install dua-cli ``` #### x-cmd [x-cmd](https://www.x-cmd.com/) is a **toolbox for Posix Shell**, offering a lightweight package manager built using shell and awk. ```sh x env use dua ``` - 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. ### Usage ```bash # count the space used in the current working directory dua # count the space used in all directories that are not hidden dua * # learn about additional functionality dua aggregate --help ``` ### Interactive Mode Launch into interactive mode with the `i` or `interactive` subcommand. Get help on keyboard shortcuts with `?`. Use this mode to explore, and/or to delete files and directories to release disk space. Please note that great care has been taken to prevent accidental deletions due to a multi-stage process, which makes this mode viable for exploration. ```bash dua i dua interactive ``` ### Configuration `dua` can read an optional configuration file from your OS-specific config directory: 1. Linux/Unix: `$XDG_CONFIG_HOME/dua-cli/config.toml` (or the platform default config dir) 2. macOS: `~/Library/Application Support/dua-cli/config.toml` 3. Windows: `%APPDATA%\dua-cli\config.toml` If the file is missing, defaults are used. Currently supported options: ```toml [keys] # If true, pressing in the main pane navigates to the parent directory. # If true (default), pressing in the main pane ascends to the parent directory. # If false, follows the default quit behavior. esc_navigates_back = true ``` ### Development Please note that all the following assumes a unix system. On Windows, the linux subsystem should do the job. #### Run tests ```bash make tests ``` #### Learn about other targets ``` make ``` #### But why is… #### …there only one available backend? `termion` was available previously. Maintaining both backends seemed more cumbersome than it's worth and add complexity I didn't like anymore. `termion` had its benefits, but I never liked that it seems to have dropped out of support. Thus `crossterm` is the only remaining backend and it's very actively developed. ### Acknowledgements Thanks to [jwalk][jwalk], all there was left to do is to write a command-line interface. As `jwalk` matures, **dua** should benefit instantly. ### Limitations - Does not show symbolic links at all if no path is provided when invoking `dua` - 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 are not a traversal root, but will not be followed. - Interactive mode only looks good in dark terminals (see [this issue](https://github.com/Byron/dua-cli/issues/13)) - _easy fix_: file names in main window are not truncated if too large. They are cut off on the right. - There are plenty of examples in `tests/fixtures` which don't render correctly in interactive mode. This can be due to graphemes not interpreted correctly. With Chinese characters for instance, column sizes are not correctly computed, leading to certain columns not being shown. In other cases, the terminal gets things wrong - I use alacritty, and with certain characters it performs worse than, say iTerm3. See https://github.com/minimaxir/big-list-of-naughty-strings/blob/master/blns.txt for the source. - In interactive mode, you will need about 60MB of memory for 1 million entries in the graph. - In interactive mode, the maximum amount of files is limited to 2^32 - 1 (`u32::max_value() - 1`) entries. - One node is used as to 'virtual' root - 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) - The limitation is imposed by the underlying [`petgraph`][petgraph] crate, which declares it as `unsafe` to use u64 for instance. - It's possibly _UB_ when that limit is reached, however, it was never observed either. ### Similar Programs - **CLI:** - `du` - [`dust`](https://github.com/bootandy/dust) - [`dutree`](https://github.com/nachoparker/dutree) - [`pdu`](https://github.com/KSXGitHub/parallel-disk-usage) - **TUI:** - [`ncdu`](https://dev.yorhel.nl/ncdu) - [`gdu`](https://github.com/dundee/gdu) - [`godu`](https://github.com/viktomas/godu) - **GUI:** - [GNOME's Disk Usage Analyzer, a.k.a. `baobab`](https://wiki.gnome.org/action/show/Apps/DiskUsageAnalyzer) - [Filelight](https://apps.kde.org/filelight/) [petgraph]: https://crates.io/crates/petgraph [rustup]: https://rustup.rs/ [jwalk]: https://crates.io/crates/jwalk [tui]: https://github.com/fdehau/tui-rs dua-cli-2.34.0/src/aggregate.rs000064400000000000000000000135671046102023000143270ustar 00000000000000use crate::{ByteFormat, InodeFilter, Throttle, WalkOptions, WalkResult, crossdev}; use anyhow::Result; use filesize::PathExt; use owo_colors::{AnsiColors as Color, OwoColorize}; use std::time::Duration; use std::{io, path::Path}; /// Aggregate the given `paths` and write information about them to `out` in a human-readable format. /// If `compute_total` is set, it will write an additional line with the total size across all given `paths`. /// If `sort_by_size_in_bytes` is set, we will sort all sizes (ascending) before outputting them. pub fn aggregate( mut out: impl io::Write, mut err: Option, walk_options: WalkOptions, compute_total: bool, sort_by_size_in_bytes: bool, byte_format: ByteFormat, paths: impl IntoIterator>, ) -> Result<(WalkResult, Statistics)> { let mut res = WalkResult::default(); let mut stats = Statistics { smallest_file_in_bytes: u128::MAX, ..Default::default() }; let mut total = 0; let mut num_roots = 0; let mut aggregates = Vec::new(); let mut inodes = InodeFilter::default(); let progress = Throttle::new(Duration::from_millis(100), Duration::from_secs(1).into()); for path in paths.into_iter() { num_roots += 1; let mut num_bytes = 0u128; let mut num_errors = 0u64; let device_id = match crossdev::init(path.as_ref()) { Ok(id) => id, Err(_) => { num_errors += 1; res.num_errors += 1; aggregates.push((path.as_ref().to_owned(), num_bytes, num_errors)); continue; } }; for entry in walk_options.iter_from_path(path.as_ref(), device_id, false) { stats.entries_traversed += 1; progress.throttled(|| { if let Some(err) = err.as_mut() { write!(err, "Enumerating {} items\r", stats.entries_traversed).ok(); } }); match entry { Ok(entry) => { let file_size = match entry.client_state { Some(Ok(ref m)) if (walk_options.count_hard_links || inodes.add(m)) && (walk_options.cross_filesystems || crossdev::is_same_device(device_id, m)) => { if walk_options.apparent_size { m.len() } else { entry.path().size_on_disk_fast(m).unwrap_or_else(|_| { num_errors += 1; 0 }) } } Some(Ok(_)) => 0, Some(Err(_)) => { num_errors += 1; 0 } None => 0, // ignore directory } as u128; stats.largest_file_in_bytes = stats.largest_file_in_bytes.max(file_size); stats.smallest_file_in_bytes = stats.smallest_file_in_bytes.min(file_size); num_bytes += file_size; } Err(_) => num_errors += 1, } } if let Some(err) = err.as_mut() { write!(err, "\x1b[2K\r").ok(); } if sort_by_size_in_bytes { aggregates.push((path.as_ref().to_owned(), num_bytes, num_errors)); } else { output_colored_path( &mut out, &path, num_bytes, num_errors, path_color_of(&path), byte_format, )?; } total += num_bytes; res.num_errors += num_errors; } if stats.entries_traversed == 0 { stats.smallest_file_in_bytes = 0; } if sort_by_size_in_bytes { aggregates.sort_by_key(|&(_, num_bytes, _)| num_bytes); for (path, num_bytes, num_errors) in aggregates.into_iter() { output_colored_path( &mut out, &path, num_bytes, num_errors, path_color_of(&path), byte_format, )?; } } if num_roots > 1 && compute_total { output_colored_path( &mut out, Path::new("total"), total, res.num_errors, None, byte_format, )?; } Ok((res, stats)) } fn path_color_of(path: impl AsRef) -> Option { (!path.as_ref().is_file()).then_some(Color::Cyan) } fn output_colored_path( out: &mut impl io::Write, path: impl AsRef, num_bytes: u128, num_errors: u64, path_color: Option, byte_format: ByteFormat, ) -> std::result::Result<(), io::Error> { let size = byte_format.display(num_bytes).to_string(); let size = size.green(); let size_width = byte_format.width(); let path = path.as_ref().display(); let errors = if num_errors != 0 { format!( " <{num_errors} IO Error{plural_s}>", plural_s = if num_errors > 1 { "s" } else { "" } ) } else { "".into() }; if let Some(color) = path_color { writeln!(out, "{size:>size_width$} {}{errors}", path.color(color)) } else { writeln!(out, "{size:>size_width$} {path}{errors}") } } /// Statistics obtained during a filesystem walk #[derive(Default, Debug)] pub struct Statistics { /// The amount of entries we have seen during filesystem traversal pub entries_traversed: u64, /// The size of the smallest file encountered in bytes pub smallest_file_in_bytes: u128, /// The size of the largest file encountered in bytes pub largest_file_in_bytes: u128, } dua-cli-2.34.0/src/common.rs000064400000000000000000000274471046102023000136730ustar 00000000000000use crate::crossdev; use crate::traverse::{EntryData, Tree, TreeIndex}; use byte_unit::{ByteUnit, n_gb_bytes, n_gib_bytes, n_mb_bytes, n_mib_bytes}; use std::collections::BTreeSet; use std::path::PathBuf; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::Duration; use std::{fmt, path::Path}; /// Return the entry at `node_idx` or panic if the index is invalid for `tree`. pub(crate) fn get_entry_or_panic(tree: &Tree, node_idx: TreeIndex) -> &EntryData { tree.node_weight(node_idx) .expect("node should always be retrievable with valid index") } pub(crate) fn get_size_or_panic(tree: &Tree, node_idx: TreeIndex) -> u128 { get_entry_or_panic(tree, node_idx).size } /// Specifies a way to format bytes #[derive(Clone, Copy)] pub enum ByteFormat { /// metric format, based on 1000. Metric, /// binary format, based on 1024 Binary, /// raw bytes, without additional formatting Bytes, /// only gigabytes without smart-unit GB, /// only gibibytes without smart-unit GiB, /// only megabytes without smart-unit MB, /// only mebibytes without smart-unit MiB, } impl ByteFormat { /// Return the content width (without unit suffix) needed to display values in this format. pub fn width(self) -> usize { use ByteFormat::*; match self { Metric => 10, Binary => 11, Bytes => 12, MiB | MB => 12, _ => 10, } } /// Return the full width (value plus unit and separator) used by this format. pub fn total_width(self) -> usize { use ByteFormat::*; const THE_SPACE_BETWEEN_UNIT_AND_NUMBER: usize = 1; self.width() + match self { Binary | MiB | GiB => 3, Metric | MB | GB => 2, Bytes => 1, } + THE_SPACE_BETWEEN_UNIT_AND_NUMBER } /// Create a display adapter for `bytes` using this format. pub fn display(self, bytes: u128) -> impl fmt::Display { ByteFormatDisplay { format: self, bytes, } } } /// A lightweight display adapter created by [`ByteFormat::display`]. struct ByteFormatDisplay { format: ByteFormat, bytes: u128, } impl fmt::Display for ByteFormatDisplay { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { use ByteFormat::*; use byte_unit::Byte; let format = match self.format { Bytes => return write!(f, "{} b", self.bytes), Binary => (true, None), Metric => (false, None), GB => (false, Some((n_gb_bytes!(1), ByteUnit::GB))), GiB => (false, Some((n_gib_bytes!(1), ByteUnit::GiB))), MB => (false, Some((n_mb_bytes!(1), ByteUnit::MB))), MiB => (false, Some((n_mib_bytes!(1), ByteUnit::MiB))), }; let b = match format { (_, Some((divisor, unit))) => Byte::from_unit(self.bytes as f64 / divisor as f64, unit) .expect("byte count > 0") .get_adjusted_unit(unit), (binary, None) => Byte::from_bytes(self.bytes).get_appropriate_unit(binary), } .format(2); let mut splits = b.split(' '); match (splits.next(), splits.next()) { (Some(bytes), Some(unit)) => write!( f, "{} {:>unit_width$}", bytes, unit, unit_width = match self.format { Binary => 3, Metric => 2, _ => 2, } ), _ => f.write_str(&b), } } } /// Identify the kind of sorting to apply during filesystem iteration #[derive(Clone)] pub enum TraversalSorting { /// Keep filesystem iteration order as provided by the walker. None, /// Sort entries alphabetically by file name during iteration. AlphabeticalByFileName, } /// Throttle access to an optional `io::Write` to the specified `Duration` #[derive(Debug)] pub(crate) struct Throttle { trigger: Arc, } impl Throttle { /// Create a new throttle that allows updates at most once per `duration`. /// /// If `initial_sleep` is set, the first update is delayed by that amount. pub(crate) fn new(duration: Duration, initial_sleep: Option) -> Self { let instance = Self { trigger: Default::default(), }; let trigger = Arc::downgrade(&instance.trigger); std::thread::spawn(move || { if let Some(duration) = initial_sleep { std::thread::sleep(duration) } while let Some(t) = trigger.upgrade() { t.store(true, Ordering::Relaxed); std::thread::sleep(duration); } }); instance } /// Execute `f` only if the throttle currently allows an update. pub(crate) fn throttled(&self, f: F) where F: FnOnce(), { if self.can_update() { f() } } /// Return `true` if we are not currently throttled. pub(crate) fn can_update(&self) -> bool { self.trigger.swap(false, Ordering::Relaxed) } } /// Configures a filesystem walk, including output and formatting options. #[derive(Clone)] pub struct WalkOptions { /// 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) /// for more information. pub threads: usize, /// If `true`, count every hard-link occurrence independently. pub count_hard_links: bool, /// If `true`, use apparent size (`metadata.len()`), not allocated blocks on disk. pub apparent_size: bool, /// Sorting mode applied by the filesystem walker. pub sorting: TraversalSorting, /// If `false`, traversal is constrained to the root filesystem/device. pub cross_filesystems: bool, /// Canonicalized directories to skip from traversal. pub ignore_dirs: BTreeSet, } type WalkDir = jwalk::WalkDirGeneric<((), Option>)>; impl WalkOptions { /// Create an iterator over `root` honoring this walk configuration. /// /// `root_device_id` is used to filter entries when `cross_filesystems == false`. /// If `skip_root` is `true`, the root directory itself is omitted from yielded entries. pub(crate) fn iter_from_path( &self, root: &Path, root_device_id: u64, skip_root: bool, ) -> WalkDir { let ignore_dirs = self.ignore_dirs.clone(); let cwd = std::env::current_dir().unwrap_or_else(|_| root.to_owned()); WalkDir::new(root) .follow_links(false) .min_depth(if skip_root { 1 } else { 0 }) .sort(match self.sorting { TraversalSorting::None => false, TraversalSorting::AlphabeticalByFileName => true, }) .skip_hidden(false) .process_read_dir({ let cross_filesystems = self.cross_filesystems; move |_, _, _, dir_entry_results| { dir_entry_results.iter_mut().for_each(|dir_entry_result| { if let Ok(dir_entry) = dir_entry_result { let metadata = dir_entry.metadata(); if dir_entry.file_type.is_dir() { let ok_for_fs = cross_filesystems || metadata .as_ref() .map(|m| crossdev::is_same_device(root_device_id, m)) .unwrap_or(true); if !ok_for_fs || ignore_directory(&dir_entry.path(), &ignore_dirs, &cwd) { dir_entry.read_children_path = None; } } dir_entry.client_state = Some(metadata); } }) } }) .parallelism(match self.threads { 0 => jwalk::Parallelism::RayonDefaultPool { busy_timeout: std::time::Duration::from_secs(1), }, 1 => jwalk::Parallelism::Serial, _ => jwalk::Parallelism::RayonExistingPool { pool: jwalk::rayon::ThreadPoolBuilder::new() .stack_size(128 * 1024) .num_threads(self.threads) .thread_name(|idx| format!("dua-fs-walk-{idx}")) .build() .expect("fields we set cannot fail") .into(), busy_timeout: None, }, }) } } /// Information we gather during a filesystem walk #[derive(Default)] pub struct WalkResult { /// The amount of io::errors we encountered. Can happen when fetching meta-data, or when reading the directory contents. pub num_errors: u64, } impl WalkResult { /// Convert traversal result into a process exit code. /// /// Returns `0` if no I/O errors occurred, otherwise `1`. pub fn to_exit_code(&self) -> i32 { i32::from(self.num_errors > 0) } } /// Canonicalize user-provided ignore directory paths. /// /// Non-canonicalizable paths are ignored. pub fn canonicalize_ignore_dirs(ignore_dirs: &[PathBuf]) -> BTreeSet { let dirs = ignore_dirs .iter() .map(gix_path::realpath) .filter_map(Result::ok) .collect(); log::info!("Ignoring canonicalized {dirs:?}"); dirs } fn ignore_directory(path: &Path, ignore_dirs: &BTreeSet, cwd: &Path) -> bool { if ignore_dirs.is_empty() { return false; } let path = gix_path::realpath_opts(path, cwd, 32); path.map(|path| { let ignored = ignore_dirs.contains(&path); if ignored { log::debug!("Ignored {path:?}"); } ignored }) .unwrap_or(false) } #[cfg(test)] mod tests { use super::*; #[test] fn test_ignore_directories() { let cwd = std::env::current_dir().unwrap(); #[cfg(unix)] let mut parameters = vec![ ("/usr", vec!["/usr"], true), ("/usr/local", vec!["/usr"], false), ("/smth", vec!["/usr"], false), ("/usr/local/..", vec!["/usr/local/.."], true), ("/usr", vec!["/usr/local/.."], true), ("/usr/local/share/../..", vec!["/usr"], true), ]; #[cfg(windows)] let mut parameters = vec![ ("C:\\Windows", vec!["C:\\Windows"], true), ("C:\\Windows\\System", vec!["C:\\Windows"], false), ("C:\\Smth", vec!["C:\\Windows"], false), ( "C:\\Windows\\System\\..", vec!["C:\\Windows\\System\\.."], true, ), ("C:\\Windows", vec!["C:\\Windows\\System\\.."], true), ( "C:\\Windows\\System\\Speech\\..\\..", vec!["C:\\Windows"], true, ), ]; parameters.extend([ ("src", vec!["src"], true), ("src/interactive", vec!["src"], false), ("src/interactive/..", vec!["src"], true), ]); for (path, ignore_dirs, expected_result) in parameters { let ignore_dirs = canonicalize_ignore_dirs( &ignore_dirs.into_iter().map(Into::into).collect::>(), ); assert_eq!( ignore_directory(path.as_ref(), &ignore_dirs, &cwd), expected_result, "result='{expected_result}' for path='{path}' and ignore_dir='{ignore_dirs:?}' " ); } } } dua-cli-2.34.0/src/config.rs000064400000000000000000000074371046102023000136450ustar 00000000000000use anyhow::{Context, Result, anyhow}; use serde::Deserialize; use std::path::PathBuf; /// Runtime configuration used by interactive and CLI components. /// /// The configuration file is optional. If it cannot be found, defaults are used. /// See [`Config::load`] for details on fallback and error behavior. /// /// Expected TOML structure: /// /// ```toml /// [keys] /// esc_navigates_back = true /// ``` #[derive(Debug, Default, Deserialize)] #[serde(default)] pub struct Config { /// Keybinding-related settings. pub keys: KeysConfig, } /// Keyboard interaction settings. #[derive(Debug, Deserialize)] #[serde(default)] pub struct KeysConfig { /// Changes `` behavior in the interactive UI. /// /// If `true`, pressing `` in the main pane ascends to the parent directory. /// If `false`, pressing `` follows the default quit behavior, as if `q` was pressed. /// /// Default: `true`. #[serde(default = "default_esc_navigates_back")] pub esc_navigates_back: bool, } fn default_esc_navigates_back() -> bool { true } impl Default for KeysConfig { fn default() -> Self { Self { esc_navigates_back: default_esc_navigates_back(), } } } impl Config { /// Load configuration from disk. /// /// Behavior: /// - If no platform configuration directory is available, returns defaults. /// - If the config file does not exist, returns defaults. /// - If the config file exists but cannot be read, returns an error with path context. /// - If TOML parsing fails, returns an error with path context. /// /// Unknown keys are ignored. Missing supported keys fall back to defaults. pub fn load() -> Result { let Ok(path) = Self::path() else { log::info!("Configuration path couldn't be determined. Using defaults."); return Ok(Config::default()); }; let contents = match std::fs::read_to_string(&path) { Ok(c) => c, Err(e) if e.kind() == std::io::ErrorKind::NotFound => { log::info!( "Configuration not loaded from {}: file not found. Using defaults.", path.display() ); return Ok(Config::default()); } Err(e) => { return Err(e) .with_context(|| format!("Failed to read config at {}", path.display())); } }; toml::from_str(&contents) .with_context(|| format!("Failed to parse config at {}", path.display())) } /// Default TOML content used when initializing a new configuration file. pub fn default_file_content() -> &'static str { concat!( "# dua-cli configuration\n", "#\n", "[keys]\n", "# If true, pressing in the main pane ascends to the parent directory.\n", "# If false, follows the default quit behavior.\n", "esc_navigates_back = true\n", ) } /// Return the expected configuration file location for the current platform. /// /// The path is: /// - Linux/Unix: `$XDG_CONFIG_HOME/dua-cli/config.toml` (or equivalent fallback) /// - Windows: `%APPDATA%\\dua-cli\\config.toml` /// - macOS: `~/Library/Application Support/dua-cli/config.toml` /// /// Returns an error if the platform config directory cannot be determined. pub fn path() -> Result { // Use the OS-specific configuration directory (e.g. $XDG_CONFIG_HOME, %APPDATA%, or // ~/Library/Application Support) as provided by the `dirs` crate. let config_dir = dirs::config_dir() .ok_or_else(|| anyhow!("platform config directory is unavailable"))?; Ok(config_dir.join("dua-cli").join("config.toml")) } } dua-cli-2.34.0/src/crossdev.rs000064400000000000000000000007761046102023000142270ustar 00000000000000use std::{io, path::Path}; #[cfg(unix)] pub fn init(path: &Path) -> io::Result { use std::os::unix::fs::MetadataExt; path.metadata().map(|m| m.dev()) } #[cfg(unix)] pub fn is_same_device(device_id: u64, meta: &std::fs::Metadata) -> bool { use std::os::unix::fs::MetadataExt; meta.dev() == device_id } #[cfg(not(unix))] pub fn is_same_device(_device_id: u64, _meta: &std::fs::Metadata) -> bool { true } #[cfg(not(unix))] pub fn init(_path: &Path) -> io::Result { Ok(0) } dua-cli-2.34.0/src/inodefilter.rs000064400000000000000000000050661046102023000147000ustar 00000000000000use std::collections::HashMap; /// Tracks seen `(device, inode)` pairs to avoid double-counting hard-linked files. #[derive(Debug, Default, Clone)] pub(crate) struct InodeFilter { inner: HashMap<(u64, u64), u64>, } impl InodeFilter { #[cfg(unix)] /// Register file metadata and return `true` if this link should be counted. pub(crate) fn add(&mut self, metadata: &std::fs::Metadata) -> bool { use std::os::unix::fs::MetadataExt; self.add_dev_inode((metadata.dev(), metadata.ino()), metadata.nlink()) } #[cfg(windows)] /// Register file metadata and return `true` if this link should be counted. pub(crate) fn add(&mut self, metadata: &std::fs::Metadata) -> bool { use std::os::windows::fs::MetadataExt; if let (Some(dev), Some(inode), Some(nlinks)) = ( metadata.volume_serial_number(), metadata.file_index(), metadata.number_of_links(), ) { self.add_dev_inode((dev as u64, inode), nlinks as u64) } else { true } } #[cfg(not(any(unix, windows)))] /// Register file metadata and return `true` if this link should be counted. pub(crate) fn add(&mut self, metadata: &std::fs::Metadata) -> bool { true } /// Register a `(device, inode)` with its hard-link count. /// /// Returns `true` for the first observation that should contribute to size/count, /// and `false` for subsequent links. pub(crate) fn add_dev_inode(&mut self, dev_inode: (u64, u64), nlinks: u64) -> bool { if nlinks <= 1 { return true; } match self.inner.get_mut(&dev_inode) { Some(1) => { self.inner.remove(&dev_inode); false } Some(count) => { *count -= 1; false } None => { self.inner.insert(dev_inode, nlinks - 1); true } } } } #[cfg(test)] mod tests { use super::*; #[test] fn it_filters_inodes() { let mut inodes = InodeFilter::default(); assert!(inodes.add_dev_inode((1, 1), 2)); assert!(inodes.add_dev_inode((2, 1), 2)); assert!(!inodes.add_dev_inode((1, 1), 2)); assert!(!inodes.add_dev_inode((2, 1), 2)); assert!(inodes.add_dev_inode((1, 1), 3)); assert!(!inodes.add_dev_inode((1, 1), 3)); assert!(!inodes.add_dev_inode((1, 1), 3)); assert!(inodes.add_dev_inode((1, 1), 1)); assert!(inodes.add_dev_inode((1, 1), 1)); } } dua-cli-2.34.0/src/interactive/app/bytevis.rs000064400000000000000000000065201046102023000171520ustar 00000000000000use dua::ByteFormat; use std::fmt; #[derive(Default, Clone, Copy)] pub enum ByteVisualization { Percentage, Bar, LongBar, #[default] PercentageAndBar, } pub struct DisplayByteVisualization { format: ByteVisualization, percentage: f32, } impl ByteVisualization { pub fn cycle(&mut self) { use ByteVisualization::*; *self = match self { Bar => LongBar, LongBar => PercentageAndBar, PercentageAndBar => Percentage, Percentage => Bar, } } pub fn display(self, percentage: f32) -> DisplayByteVisualization { DisplayByteVisualization { format: self, percentage, } } } impl fmt::Display for DisplayByteVisualization { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { use ByteVisualization::*; let Self { format, percentage } = self; let percentage = if percentage.is_nan() { 0.0 } else { *percentage }; const BAR_SIZE: usize = 10; match format { Percentage => Self::make_percentage(f, percentage), PercentageAndBar => { Self::make_percentage(f, percentage)?; f.write_str(" ")?; Self::make_bar(f, percentage, BAR_SIZE) } Bar => Self::make_bar(f, percentage, BAR_SIZE), LongBar => Self::make_bar(f, percentage, 19), } } } impl DisplayByteVisualization { fn make_bar( f: &mut fmt::Formatter<'_>, percentage: f32, length: usize, ) -> Result<(), fmt::Error> { // Print the filled part of the bar let block_length = (length as f32 * percentage).floor() as usize; for _ in 0..block_length { f.write_str(tui::symbols::block::FULL)?; } // Bar is done if full length is already used, continue working if not if block_length < length { let block_sections = [ " ", tui::symbols::block::ONE_EIGHTH, tui::symbols::block::ONE_QUARTER, tui::symbols::block::THREE_EIGHTHS, tui::symbols::block::HALF, tui::symbols::block::FIVE_EIGHTHS, tui::symbols::block::THREE_QUARTERS, tui::symbols::block::SEVEN_EIGHTHS, tui::symbols::block::FULL, ]; // Get the index based on how filled the remaining part is let index = (((length as f32 * percentage) - block_length as f32) * 8f32).round() as usize; f.write_str(block_sections[index])?; // Remainder of the bar should be empty for _ in 0..length - block_length - 1 { f.write_str(" ")?; } } Ok(()) } fn make_percentage(f: &mut fmt::Formatter<'_>, percentage: f32) -> Result<(), fmt::Error> { write!(f, " {:>5.01}% ", percentage * 100.0) } } /// Options to configure how we display things #[derive(Clone, Copy)] pub struct DisplayOptions { pub byte_format: ByteFormat, pub byte_vis: ByteVisualization, } impl DisplayOptions { pub fn new(byte_format: ByteFormat) -> Self { DisplayOptions { byte_format, byte_vis: ByteVisualization::default(), } } } dua-cli-2.34.0/src/interactive/app/common.rs000064400000000000000000000137401046102023000167570ustar 00000000000000use crate::interactive::path_of; use dua::traverse::{Tree, TreeIndex}; use itertools::Itertools; use petgraph::Direction; use std::time::SystemTime; use std::{cmp::Ordering, path::PathBuf}; use unicode_segmentation::UnicodeSegmentation; #[derive(Default, Debug, Copy, Clone, PartialOrd, PartialEq, Eq)] pub enum SortMode { #[default] SizeDescending, SizeAscending, MTimeDescending, MTimeAscending, CountDescending, CountAscending, NameDescending, NameAscending, } impl SortMode { pub fn toggle_size(&mut self) { use SortMode::*; *self = match self { SizeDescending => SizeAscending, SizeAscending => SizeDescending, _ => SizeDescending, } } pub fn toggle_mtime(&mut self) { use SortMode::*; *self = match self { MTimeAscending => MTimeDescending, MTimeDescending => MTimeAscending, _ => MTimeDescending, } } pub fn toggle_count(&mut self) { use SortMode::*; *self = match self { CountAscending => CountDescending, CountDescending => CountAscending, _ => CountDescending, } } pub fn toggle_name(&mut self) { use SortMode::*; *self = match self { NameAscending => NameDescending, NameDescending => NameAscending, _ => NameAscending, } } } pub struct EntryDataBundle { pub index: TreeIndex, pub name: PathBuf, pub size: u128, pub mtime: SystemTime, pub entry_count: Option, pub is_dir: bool, pub exists: bool, } pub enum EntryCheck { PossiblyCostlyLstat, Disabled, } impl EntryCheck { pub fn new(is_scanning: bool, allow_entry_check: bool) -> Self { if allow_entry_check && !is_scanning { EntryCheck::PossiblyCostlyLstat } else { EntryCheck::Disabled } } } /// Note that with `glob_root` present, we will not obtain metadata anymore as we might be seeing /// a lot of entries. That way, displaying 250k entries is no problem. pub fn sorted_entries( tree: &Tree, node_idx: TreeIndex, sorting: SortMode, glob_root: Option, check: EntryCheck, ) -> Vec { use SortMode::*; fn cmp_count(l: &EntryDataBundle, r: &EntryDataBundle) -> Ordering { l.entry_count .cmp(&r.entry_count) .then_with(|| l.name.cmp(&r.name)) } fn cmp_name(l: &EntryDataBundle, r: &EntryDataBundle) -> Ordering { if l.is_dir && !r.is_dir { Ordering::Less } else if !l.is_dir && r.is_dir { Ordering::Greater } else { l.name.cmp(&r.name) } } tree.neighbors_directed(node_idx, Direction::Outgoing) .filter_map(|idx| { tree.node_weight(idx).map(|entry| { let use_glob_path = glob_root.is_some_and(|glob_root| glob_root == node_idx); let (path, exists, is_dir) = { let path = path_of(tree, idx, glob_root); if matches!(check, EntryCheck::Disabled) || glob_root == Some(node_idx) { (path, true, entry.is_dir) } else { let meta = path.symlink_metadata(); (path, meta.is_ok(), meta.ok().is_some_and(|m| m.is_dir())) } }; EntryDataBundle { index: idx, name: if use_glob_path { path } else { entry.name.clone() }, size: entry.size, mtime: entry.mtime, entry_count: entry.entry_count, exists, is_dir, } }) }) .sorted_by(|l, r| match sorting { SizeDescending => r.size.cmp(&l.size), SizeAscending => l.size.cmp(&r.size), MTimeAscending => l.mtime.cmp(&r.mtime), MTimeDescending => r.mtime.cmp(&l.mtime), CountAscending => cmp_count(l, r), CountDescending => cmp_count(l, r).reverse(), NameAscending => cmp_name(l, r), NameDescending => cmp_name(l, r).reverse(), }) .collect() } pub fn fit_string_graphemes_with_ellipsis( s: impl Into, path_graphemes_count: usize, mut desired_graphemes: usize, ) -> (String, usize) { const ELLIPSIS: usize = 1; const MIN_GRAPHEMES_ON_SIDE: usize = 1; const MIN_LEN: usize = ELLIPSIS + MIN_GRAPHEMES_ON_SIDE; const USE_EXTENDED: bool = true; let s = s.into(); desired_graphemes = desired_graphemes.max(MIN_LEN); debug_assert!( path_graphemes_count == s.graphemes(USE_EXTENDED).count(), "input grapheme count is actually correct" ); let gc = path_graphemes_count; if gc <= desired_graphemes { return (s, gc); } let mut n = String::with_capacity(desired_graphemes); let to_be_removed = gc - desired_graphemes + ELLIPSIS; let gmi = s.graphemes(USE_EXTENDED); n.push('…'); n.extend(gmi.skip(to_be_removed)); (n, desired_graphemes) } #[cfg(test)] mod tests { use super::*; #[test] fn fit_string_inputs() { assert_eq!( ("aaa".into(), 3), fit_string_graphemes_with_ellipsis("aaa", 3, 4) ); assert_eq!( ("…a".to_string(), 2), fit_string_graphemes_with_ellipsis("abbbba", 6, 1), "even amount of chars, desired too small" ); assert_eq!( ("…ca".to_string(), 3), fit_string_graphemes_with_ellipsis("abbbbca", 7, 3), "uneven amount of chars, desired too small" ); assert_eq!( ("… a".to_string(), 3), fit_string_graphemes_with_ellipsis("a a", 6, 3), "spaces are counted as graphemes, too" ); } } dua-cli-2.34.0/src/interactive/app/eventloop.rs000064400000000000000000000560511046102023000175040ustar 00000000000000use crate::interactive::state::FilesystemScan; use crate::interactive::{ CursorDirection, CursorMode, DisplayOptions, EntryCheck, MarkEntryMode, app::navigation::Navigation, state::FocussedPane, widgets::{MainWindow, MainWindowProps, glob_search}, }; use anyhow::Result; use crossbeam::channel::Receiver; use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers}; use dua::{ Config, WalkResult, traverse::{BackgroundTraversal, EntryData, Traversal, TreeIndex}, }; use std::path::PathBuf; use tui::{Terminal, backend::Backend, buffer::Buffer, layout::Rect, widgets::Widget}; use super::state::{AppState, Cursor}; use super::tree_view::TreeView; impl AppState { pub fn navigation_mut(&mut self) -> &mut Navigation { self.glob_navigation .as_mut() .unwrap_or(&mut self.navigation) } pub fn navigation(&self) -> &Navigation { self.glob_navigation.as_ref().unwrap_or(&self.navigation) } pub fn draw( &mut self, window: &mut MainWindow, tree_view: &TreeView<'_>, display: DisplayOptions, terminal: &mut Terminal, config: &Config, ) -> Result<()> where B: Backend, { let props = MainWindowProps { current_path: tree_view.current_path(self.navigation().view_root), entries_traversed: self.stats.entries_traversed, total_bytes: tree_view.total_size(), start: self.stats.start, elapsed: self.stats.elapsed, display, state: self, config, }; let mut cursor = Cursor::default(); let result = draw_window(window, props, terminal, &mut cursor); if cursor.show { _ = terminal.show_cursor(); _ = terminal.set_cursor(cursor.x, cursor.y); } else { _ = terminal.hide_cursor(); } result } pub fn traverse(&mut self, traversal: &Traversal) -> Result<()> { let bg_traversal = BackgroundTraversal::start( traversal.root_index, &self.walk_options, self.root_paths.clone(), false, true, )?; self.navigation_mut().view_root = traversal.root_index; self.scan = Some(FilesystemScan { active_traversal: bg_traversal, previous_selection: None, }); Ok(()) } fn recompute_sizes_recursively(&mut self, traversal: &mut Traversal, node_index: TreeIndex) { let mut tree_view = self.tree_view(traversal); tree_view.recompute_sizes_recursively(node_index); } fn refresh_screen( &mut self, window: &mut MainWindow, traversal: &mut Traversal, display: &mut DisplayOptions, terminal: &mut Terminal, config: &Config, ) -> Result<()> where B: Backend, { let tree_view = self.tree_view(traversal); self.draw(window, &tree_view, *display, terminal, config)?; Ok(()) } /// This method ends once the user quits the application or there are no more inputs to process. pub fn process_events( &mut self, window: &mut MainWindow, traversal: &mut Traversal, display: &mut DisplayOptions, terminal: &mut Terminal, events: Receiver, config: &Config, ) -> Result where B: Backend, { self.refresh_screen(window, traversal, display, terminal, config)?; loop { if let Some(result) = self.process_event(window, traversal, display, terminal, &events, config)? { return Ok(result); } } } pub fn process_event( &mut self, window: &mut MainWindow, traversal: &mut Traversal, display: &mut DisplayOptions, terminal: &mut Terminal, events: &Receiver, config: &Config, ) -> Result> where B: Backend, { if let Some(FilesystemScan { active_traversal, previous_selection, }) = self.scan.as_mut() { crossbeam::select! { recv(events) -> event => { let Ok(event) = event else { return Ok(Some(WalkResult { num_errors: self.stats.io_errors })); }; let res = self.process_terminal_event( window, traversal, display, terminal, event, config, )?; if let Some(res) = res { return Ok(Some(res)); } }, recv(&active_traversal.event_rx) -> event => { let Ok(event) = event else { return Ok(None); }; if let Some(is_finished) = active_traversal.integrate_traversal_event(traversal, event) { self.stats = active_traversal.stats; let previous_selection = previous_selection.clone(); if is_finished { let root_index = active_traversal.root_idx; self.recompute_sizes_recursively(traversal, root_index); self.scan = None; traversal.cost = Some(traversal.start_time.elapsed()); } self.update_state_during_traversal(traversal, previous_selection.as_ref(), is_finished); self.refresh_screen(window, traversal, display, terminal, config)?; }; } } } else { let Ok(event) = events.recv() else { return Ok(Some(WalkResult { num_errors: self.stats.io_errors, })); }; let result = self.process_terminal_event(window, traversal, display, terminal, event, config)?; if let Some(processing_result) = result { return Ok(Some(processing_result)); } } Ok(None) } fn update_state_during_traversal( &mut self, traversal: &mut Traversal, previous_selection: Option<&(PathBuf, usize)>, is_finished: bool, ) { let tree_view = self.tree_view(traversal); self.entries = tree_view.sorted_entries( self.navigation().view_root, self.sorting, self.entry_check(), ); if !self.received_events { let previously_selected_entry = previous_selection.and_then(|(selected_name, selected_idx)| { self.entries .iter() .find(|e| e.name == *selected_name) .or_else(|| self.entries.get(*selected_idx)) }); if let Some(selected_entry) = previously_selected_entry { self.navigation_mut().selected = Some(selected_entry.index); } else if is_finished { self.navigation_mut().selected = self.entries.first().map(|b| b.index); } } self.reset_message(); // force "scanning" to appear } pub(crate) fn entry_check(&self) -> EntryCheck { EntryCheck::new(self.scan.is_some(), self.allow_entry_check) } fn process_terminal_event( &mut self, window: &mut MainWindow, traversal: &mut Traversal, display: &mut DisplayOptions, terminal: &mut Terminal, event: Event, config: &Config, ) -> Result> where B: Backend, { use FocussedPane::*; use crossterm::event::KeyCode::*; let key = match event { Event::Key(key) if key.kind != KeyEventKind::Release => { if key != refresh_key() { self.received_events = true; } key } Event::Resize(_, _) => refresh_key(), _ => return Ok(None), }; self.reset_message(); let glob_focussed = self.focussed == Glob; let mut tree_view = self.tree_view(traversal); let esc_navigates_back_in_main = config.keys.esc_navigates_back && key.code == Esc && self.focussed == Main; if esc_navigates_back_in_main { self.pending_exit = false; self.exit_node_with_traversal(&tree_view); } else { match (key.code, glob_focussed) { (Esc, _) | (Char('q'), false) => { if let Some(result) = self.handle_quit(&mut tree_view, window) { return Ok(Some(result?)); } } _ => { self.pending_exit = false; } } } let mut handled = true; match key.code { Tab => { self.cycle_focus(window); } Char('/') if !glob_focussed => { self.toggle_glob_search(window); } Char('?') if !glob_focussed => self.toggle_help_pane(window), Char('c') if key.modifiers.contains(KeyModifiers::CONTROL) && !glob_focussed => { return Ok(Some(WalkResult { num_errors: self.stats.io_errors, })); } _ => { handled = false; } } if !handled { match self.focussed { Mark => self.dispatch_to_mark_pane( key, window, &mut tree_view, *display, terminal, config, ), Help => { window .help_pane .as_mut() .expect("help pane") .process_events(key); } Glob => { let glob_pane = window.glob_pane.as_mut().expect("glob pane"); match key.code { Enter => self.search_glob_pattern( &mut tree_view, &glob_pane.input, glob_pane.case, ), _ => glob_pane.process_events(key), } } Main => match key.code { Char('O') => self.open_that(&tree_view), Char(' ') => self.mark_entry( CursorMode::KeepPosition, MarkEntryMode::Toggle, window, &tree_view, ), Char('x') => self.mark_entry( CursorMode::Advance, MarkEntryMode::MarkForDeletion, window, &tree_view, ), Char('a') => self.mark_all_entries(MarkEntryMode::Toggle, window, &tree_view), Char('o') | Char('l') | Enter | Right => { self.enter_node_with_traversal(&tree_view) } Char('r') => self.refresh(&mut tree_view, window, Refresh::Selected)?, Char('R') => self.refresh(&mut tree_view, window, Refresh::AllInView)?, Char('H') | Home => self.change_entry_selection(CursorDirection::ToTop), Char('G') | End => self.change_entry_selection(CursorDirection::ToBottom), PageUp => self.change_entry_selection(CursorDirection::PageUp), Char('u') if key.modifiers.contains(KeyModifiers::CONTROL) => { self.change_entry_selection(CursorDirection::PageUp) } Char('k') | Up => self.change_entry_selection(CursorDirection::Up), Char('j') | Down => self.change_entry_selection(CursorDirection::Down), PageDown => self.change_entry_selection(CursorDirection::PageDown), Char('d') if key.modifiers.contains(KeyModifiers::CONTROL) => { self.change_entry_selection(CursorDirection::PageDown) } Char('s') => self.cycle_sorting(&tree_view), Char('m') => self.cycle_mtime_sorting(&tree_view), Char('M') => self.toggle_mtime_column(), Char('c') => self.cycle_count_sorting(&tree_view), Char('C') => self.toggle_count_column(), Char('n') => self.cycle_name_sorting(&tree_view), Char('g') | Char('S') => display.byte_vis.cycle(), Char('d') => self.mark_entry( CursorMode::Advance, MarkEntryMode::Toggle, window, &tree_view, ), Char('u') | Char('h') | Backspace | Left => { self.exit_node_with_traversal(&tree_view) } _ => {} }, }; } self.draw(window, &tree_view, *display, terminal, config)?; Ok(None) } fn refresh( &mut self, tree: &mut TreeView<'_>, window: &mut MainWindow, what: Refresh, ) -> anyhow::Result<()> { // If another traversal is already running do not do anything. if self.scan.is_some() { self.message = Some("Traversal already running".into()); return Ok(()); } let previous_selection = self.navigation().selected.and_then(|sel_index| { tree.tree().node_weight(sel_index).map(|w| { ( w.name.clone(), self.entries .iter() .enumerate() .find_map(|(idx, e)| (e.index == sel_index).then_some(idx)) .expect("selected item is always in entries"), ) }) }); // If we are displaying the root of the glob search results then cancel the search. if let Some(glob_tree_root) = tree.glob_tree_root && glob_tree_root == self.navigation().view_root { self.quit_glob_mode(tree, window) } let (paths, remove_root_node, skip_root, use_root_path, index, parent_index) = match what { Refresh::Selected => { let Some(selected) = self.navigation().selected else { return Ok(()); }; let parent_index = tree .fs_parent_of(selected) .expect("there is always a parent to a selection"); let mut path = tree.path_of(selected); if path.to_str() == Some("") { path = PathBuf::from("."); } let (paths, use_root_path, skip_root) = if self.navigation().view_root == tree.traversal.root_index && self.root_paths.len() > 1 { (vec![path], true, false) } else { (vec![path], false, false) }; ( paths, true, skip_root, use_root_path, selected, parent_index, ) } Refresh::AllInView => { let (paths, use_root_path, skip_root) = if self.navigation().view_root == tree.traversal.root_index && self.root_paths.len() > 1 { (self.root_paths.clone(), true, false) } else { let mut path = tree.path_of(self.navigation().view_root); if path.to_str() == Some("") { path = PathBuf::from("."); } (vec![path], false, true) }; ( paths, false, skip_root, use_root_path, self.navigation().view_root, self.navigation().view_root, ) } }; tree.remove_entries(index, remove_root_node); tree.recompute_sizes_recursively(parent_index); self.entries = tree.sorted_entries( self.navigation().view_root, self.sorting, self.entry_check(), ); self.navigation_mut().selected = self.entries.first().map(|e| e.index); self.scan = Some(FilesystemScan { active_traversal: BackgroundTraversal::start( parent_index, &self.walk_options, paths, skip_root, use_root_path, )?, previous_selection, }); self.received_events = false; Ok(()) } fn tree_view<'a>(&mut self, traversal: &'a mut Traversal) -> TreeView<'a> { TreeView { traversal, glob_tree_root: self.glob_navigation.as_ref().map(|n| n.tree_root), } } fn search_glob_pattern( &mut self, tree_view: &mut TreeView<'_>, glob_pattern: &str, case: gix_glob::pattern::Case, ) { use FocussedPane::*; match glob_search( tree_view.tree(), self.navigation.view_root, glob_pattern, case, ) { Ok(matches) if matches.is_empty() => { self.message = Some("No match found".into()); } Ok(matches) => { if let Some(glob_source) = &self.glob_navigation { tree_view.tree_mut().remove_node(glob_source.tree_root); } let tree_root = tree_view.tree_mut().add_node(EntryData::default()); let glob_source = Navigation { tree_root, view_root: tree_root, selected: Some(tree_root), ..Default::default() }; self.glob_navigation = Some(glob_source); for idx in matches { tree_view.tree_mut().add_edge(tree_root, idx, ()); } let glob_tree_view = TreeView { traversal: tree_view.traversal, glob_tree_root: Some(tree_root), }; let new_entries = glob_tree_view.sorted_entries(tree_root, self.sorting, self.entry_check()); let new_entries = self .navigation_mut() .selected .map(|previously_selected| (previously_selected, new_entries)); self.enter_node(new_entries); self.focussed = Main; } Err(err) => self.message = Some(err.to_string()), } } fn handle_quit( &mut self, tree_view: &mut TreeView<'_>, window: &mut MainWindow, ) -> Option> { use FocussedPane::*; match self.focussed { Main => { if self.glob_navigation.is_some() { self.quit_glob_mode(tree_view, window); } else if window.mark_pane.is_none() && !tree_view.traversal.is_costly() { // If nothing is selected for deletion, quit instantly return Some(Ok(WalkResult { num_errors: self.stats.io_errors, })); } else if !self.pending_exit { self.pending_exit = true; } else { return Some(Ok(WalkResult { num_errors: self.stats.io_errors, })); } } Mark => self.focussed = Main, Help => { self.focussed = Main; window.help_pane = None } Glob => { self.quit_glob_mode(tree_view, window); } } None } fn quit_glob_mode(&mut self, tree_view: &mut TreeView<'_>, window: &mut MainWindow) { use FocussedPane::*; self.focussed = Main; if let Some(glob_source) = &self.glob_navigation { tree_view.tree_mut().remove_node(glob_source.tree_root); } self.glob_navigation = None; window.glob_pane = None; tree_view.glob_tree_root.take(); self.entries = tree_view.sorted_entries( self.navigation().view_root, self.sorting, self.entry_check(), ); } } enum Refresh { /// Refresh the directory currently in view AllInView, /// Refresh only the selected item Selected, } /// A [`Widget`] that renders by calling a function. /// /// The `FunctionWidget` struct holds a function that renders into a portion of /// a [`Buffer`] designated by a [`Rect`]. /// /// This widget can be used to create custom UI elements that are defined by a /// rendering function. and allows for rendering functions that do not implement /// the [`Widget`] trait. struct FunctionWidget where F: FnOnce(Rect, &mut Buffer), { render: F, } impl FunctionWidget where F: FnOnce(Rect, &mut Buffer), { /// Creates a new [`FunctionWidget`] with the given rendering function. /// /// The rendering function must have the signature `FnOnce(Rect, &mut /// Buffer)`, where: /// - [`Rect`] represents the available space for rendering. /// - [`Buffer`] is the buffer to write the rendered content to. /// /// The `FunctionWidget` can then be used to render the provided function in /// a user interface. fn new(function: F) -> FunctionWidget where F: FnOnce(Rect, &mut Buffer), { FunctionWidget { render: function } } } /// Implements the [`Widget`] trait for [`FunctionWidget`]. /// /// The implementation simply calls the provided render function with the given /// `Rect` and `Buffer`. impl Widget for FunctionWidget where F: FnOnce(Rect, &mut Buffer), { fn render(self, area: Rect, buf: &mut Buffer) { (self.render)(area, buf); } } pub fn draw_window( window: &mut MainWindow, props: MainWindowProps<'_>, terminal: &mut Terminal, cursor: &mut Cursor, ) -> Result<()> where B: Backend, { terminal.draw(|frame| { frame.render_widget( FunctionWidget::new(|area, buf| { window.render(props, area, buf, cursor); }), frame.size(), ); })?; Ok(()) } pub fn refresh_key() -> KeyEvent { KeyEvent::new(KeyCode::Char('\r'), KeyModifiers::ALT) } dua-cli-2.34.0/src/interactive/app/handlers.rs000064400000000000000000000363211046102023000172670ustar 00000000000000use crate::interactive::{ DisplayOptions, EntryDataBundle, app::tree_view::TreeView, widgets::{Column, GlobPane, HelpPane, MainWindow, MarkMode, MarkPane}, }; use crossterm::event::KeyEvent; use dua::Config; use dua::traverse::TreeIndex; use std::{fs, io, path::PathBuf}; use tui::{Terminal, backend::Backend}; use super::state::{AppState, FocussedPane::*}; #[derive(Copy, Clone)] pub enum CursorMode { Advance, KeepPosition, } #[derive(Copy, Clone)] pub enum MarkEntryMode { Toggle, MarkForDeletion, } pub enum CursorDirection { PageDown, Down, Up, PageUp, ToTop, ToBottom, } impl CursorDirection { pub fn move_cursor(&self, n: usize) -> usize { use CursorDirection::*; match self { ToTop => 0, ToBottom => usize::MAX, Down => n.saturating_add(1), Up => n.saturating_sub(1), PageDown => n.saturating_add(10), PageUp => n.saturating_sub(10), } } } impl AppState { pub fn open_that(&self, tree_view: &TreeView<'_>) { if let Some(idx) = self.navigation().selected { open::that(tree_view.path_of(idx)).ok(); } } pub fn exit_node_with_traversal(&mut self, tree_view: &TreeView<'_>) { let entries = self.entries_for_exit_node(tree_view); self.exit_node(entries); } fn entries_for_exit_node( &self, tree_view: &TreeView<'_>, ) -> Option<(TreeIndex, Vec)> { tree_view .view_parent_of(self.navigation().view_root) .map(|parent_idx| { ( parent_idx, tree_view.sorted_entries(parent_idx, self.sorting, self.entry_check()), ) }) } pub fn exit_node(&mut self, entries: Option<(TreeIndex, Vec)>) { match entries { Some((parent_idx, entries)) => { self.navigation_mut().exit_node(parent_idx, &entries); self.entries = entries; } None => self.message = Some("Top level reached".into()), } } fn entries_for_enter_node( &self, tree_view: &TreeView<'_>, ) -> Option<(TreeIndex, Vec)> { self.navigation().selected.map(|previously_selected| { ( previously_selected, tree_view.sorted_entries(previously_selected, self.sorting, self.entry_check()), ) }) } pub fn enter_node_with_traversal(&mut self, tree_view: &TreeView<'_>) { let new_entries = self.entries_for_enter_node(tree_view); self.enter_node(new_entries) } pub fn enter_node(&mut self, entries_at_selected: Option<(TreeIndex, Vec)>) { if let Some((previously_selected, new_entries)) = entries_at_selected { match self .navigation() .previously_selected_index(previously_selected, &new_entries) { Some(selected) => { self.navigation_mut() .enter_node(previously_selected, selected); self.entries = new_entries; } None => self.message = Some("Entry is a file or an empty directory".into()), } } } pub fn change_entry_selection(&mut self, direction: CursorDirection) { let next_index = self.navigation().next_index(direction, &self.entries); self.navigation_mut().select(next_index); } pub fn cycle_sorting(&mut self, tree_view: &TreeView<'_>) { self.sorting.toggle_size(); self.entries = tree_view.sorted_entries( self.navigation().view_root, self.sorting, self.entry_check(), ); } pub fn cycle_mtime_sorting(&mut self, tree_view: &TreeView<'_>) { self.sorting.toggle_mtime(); self.entries = tree_view.sorted_entries( self.navigation().view_root, self.sorting, self.entry_check(), ); } pub fn cycle_count_sorting(&mut self, tree_view: &TreeView<'_>) { self.sorting.toggle_count(); self.entries = tree_view.sorted_entries( self.navigation().view_root, self.sorting, self.entry_check(), ); } pub fn cycle_name_sorting(&mut self, tree_view: &TreeView<'_>) { self.sorting.toggle_name(); self.entries = tree_view.sorted_entries( self.navigation().view_root, self.sorting, self.entry_check(), ); } pub fn toggle_mtime_column(&mut self) { self.toggle_column(Column::MTime); } pub fn toggle_count_column(&mut self) { self.toggle_column(Column::Count); } fn toggle_column(&mut self, column: Column) { if self.show_columns.contains(&column) { self.show_columns.remove(&column); } else { self.show_columns.insert(column); } } pub fn toggle_glob_search(&mut self, window: &mut MainWindow) { self.focussed = match self.focussed { Main | Mark | Help => { window.glob_pane = Some(GlobPane::default()); Glob } Glob => unreachable!("BUG: glob pane must catch the input leading here"), } } pub fn reset_message(&mut self) { if self.scan.is_some() { self.message = Some("-> scanning <-".into()); } else { self.message = None; } } pub fn toggle_help_pane(&mut self, window: &mut MainWindow) { self.focussed = match self.focussed { Main | Mark | Glob => { window.help_pane = Some(HelpPane::default()); Help } Help => { window.help_pane = None; Main } } } pub fn cycle_focus(&mut self, window: &mut MainWindow) { if let Some(p) = window.mark_pane.as_mut() { p.set_focus(false) }; self.focussed = match ( self.focussed, &window.help_pane, &mut window.mark_pane, &mut window.glob_pane, ) { (Main, Some(_), _, _) => Help, (Help, _, Some(pane), _) => { pane.set_focus(true); Mark } (Help, _, _, Some(_)) => Glob, (Help, _, None, None) => Main, (Mark, _, _, Some(_)) => Glob, (Mark, _, _, _) => Main, (Main, None, None, None) => Main, (Main, None, Some(pane), _) => { pane.set_focus(true); Mark } (Main, None, None, Some(_)) => Glob, (Glob, _, _, _) => Main, }; } pub fn dispatch_to_mark_pane( &mut self, key: KeyEvent, window: &mut MainWindow, tree_view: &mut TreeView<'_>, display: DisplayOptions, terminal: &mut Terminal, config: &Config, ) where B: Backend, { let res = window.mark_pane.take().and_then(|p| p.process_events(key)); window.mark_pane = match res { Some((pane, mode)) => match mode { Some(MarkMode::Delete) => { self.message = Some("Deleting items...".to_string()); let mut entries_deleted = 0; let res = pane.iterate_deletable_items(|mut pane, entry_to_delete| { window.mark_pane = Some(pane); self.draw(window, tree_view, display, terminal, config).ok(); pane = window.mark_pane.take().expect("option to be filled"); match self.delete_entry(entry_to_delete, tree_view) { Ok(ed) => { entries_deleted += ed; self.message = Some(format!("Deleted {entries_deleted} items...")); Ok(pane) } Err(c) => Err((pane, c)), } }); self.message = None; res } #[cfg(feature = "trash-move")] Some(MarkMode::Trash) => { self.message = Some("Trashing items...".to_string()); let mut entries_trashed = 0; let res = pane.iterate_deletable_items(|mut pane, entry_to_trash| { window.mark_pane = Some(pane); self.draw(window, tree_view, display, terminal, config).ok(); pane = window.mark_pane.take().expect("option to be filled"); match self.trash_entry(entry_to_trash, tree_view) { Ok(ed) => { entries_trashed += ed; self.message = Some(format!("Trashed {entries_trashed} items...")); Ok(pane) } Err(c) => Err((pane, c)), } }); self.message = None; res } None => Some(pane), }, None => None, }; if window.mark_pane.is_none() { self.focussed = Main; } } pub fn delete_entry( &mut self, index: TreeIndex, tree_view: &mut TreeView<'_>, ) -> Result { let mut entries_deleted = 0; if tree_view.exists(index) { let path_to_delete = tree_view.path_of(index); delete_directory_recursively(path_to_delete)?; entries_deleted = self.delete_entries_in_traversal(index, tree_view); } Ok(entries_deleted) } #[cfg(feature = "trash-move")] pub fn trash_entry( &mut self, index: TreeIndex, tree_view: &mut TreeView<'_>, ) -> Result { let mut entries_deleted = 0; if tree_view.exists(index) { let path_to_delete = tree_view.path_of(index); if trash::delete(path_to_delete).is_err() { return Err(1); } entries_deleted = self.delete_entries_in_traversal(index, tree_view); } Ok(entries_deleted) } pub fn delete_entries_in_traversal( &mut self, index: TreeIndex, tree_view: &mut TreeView<'_>, ) -> usize { let parent_idx = tree_view .fs_parent_of(index) .expect("us being unable to delete the root index"); let entries_deleted = tree_view.remove_entries(index, true /* remove node at `index` */); if !tree_view.exists(self.navigation().view_root) { self.go_to_root(tree_view); } else { self.entries = tree_view.sorted_entries( self.navigation().view_root, self.sorting, self.entry_check(), ); } if self .navigation() .selected .and_then(|selected| self.entries.iter().find(|e| e.index == selected)) .is_none() { let idx = self.entries.first().map(|e| e.index); self.navigation_mut().select(idx); } tree_view.recompute_sizes_recursively(parent_idx); entries_deleted } pub fn go_to_root(&mut self, tree_view: &TreeView<'_>) { let root = self.navigation().tree_root; let entries = tree_view.sorted_entries(root, self.sorting, self.entry_check()); self.navigation_mut().exit_node(root, &entries); self.entries = entries; } pub fn glob_root(&self) -> Option { self.glob_navigation.as_ref().map(|e| e.tree_root) } fn mark_entry_by_index( &mut self, index: TreeIndex, mode: MarkEntryMode, window: &mut MainWindow, tree_view: &TreeView<'_>, ) { let is_dir = self .entries .iter() .find(|e| e.index == index) .unwrap() .is_dir; let should_toggle = match mode { MarkEntryMode::Toggle => true, MarkEntryMode::MarkForDeletion => false, }; if let Some(pane) = window.mark_pane.take() { window.mark_pane = pane.toggle_index(index, tree_view, is_dir, should_toggle); } else { window.mark_pane = MarkPane::default().toggle_index(index, tree_view, is_dir, should_toggle) } } pub fn mark_entry( &mut self, cursor: CursorMode, mode: MarkEntryMode, window: &mut MainWindow, tree_view: &TreeView<'_>, ) { if let Some(index) = self.navigation().selected { self.mark_entry_by_index(index, mode, window, tree_view); }; if let CursorMode::Advance = cursor { self.change_entry_selection(CursorDirection::Down) } } pub fn mark_all_entries( &mut self, mode: MarkEntryMode, window: &mut MainWindow, tree_view: &TreeView<'_>, ) { for index in self.entries.iter().map(|e| e.index).collect::>() { self.mark_entry_by_index(index, mode, window, tree_view); } } } fn into_error_count(res: Result<(), io::Error>) -> usize { match res.map_err(io_err_to_usize) { Ok(_) => 0, Err(c) => c, } } fn io_err_to_usize(err: io::Error) -> usize { if err.kind() == io::ErrorKind::NotFound { 0 } else { 1 } } // TODO: could use jwalk for this // see https://github.com/Byron/dua-cli/issues/43 fn delete_directory_recursively(path: PathBuf) -> Result<(), usize> { let mut files_or_dirs = vec![path]; let mut dirs = Vec::new(); let mut num_errors = 0; while let Some(path) = files_or_dirs.pop() { let assume_symlink_to_try_deletion = true; let is_symlink = path .symlink_metadata() .map(|m| m.file_type().is_symlink()) .unwrap_or(assume_symlink_to_try_deletion); if is_symlink { // do not follow symlinks num_errors += into_error_count(fs::remove_file(&path)); continue; } match fs::read_dir(&path) { Ok(iterator) => { dirs.push(path); for entry in iterator { match entry.map_err(io_err_to_usize) { Ok(entry) => files_or_dirs.push(entry.path()), Err(c) => num_errors += c, } } } Err(ref e) if e.kind() == io::ErrorKind::NotADirectory => { // try again with file deletion instead. num_errors += into_error_count(fs::remove_file(path)); continue; } Err(_) => { num_errors += 1; continue; } }; } for dir in dirs.into_iter().rev() { num_errors += into_error_count(fs::remove_dir(&dir).or_else(|_| fs::remove_file(dir))); } if num_errors == 0 { Ok(()) } else { Err(num_errors) } } dua-cli-2.34.0/src/interactive/app/input.rs000064400000000000000000000016411046102023000166230ustar 00000000000000use crossbeam::channel::Receiver; pub use crossterm::event::Event; enum Action { Continue, Result(Result), } fn continue_on_interrupt(result: Result) -> Action { match result { Ok(v) => Action::Result(Ok(v)), Err(err) if err.kind() == std::io::ErrorKind::Interrupted => Action::Continue, Err(err) => Action::Result(Err(err)), } } pub fn input_channel() -> Receiver { let (key_send, key_receive) = crossbeam::channel::bounded(0); std::thread::spawn(move || -> Result<(), std::io::Error> { loop { let event = match continue_on_interrupt(crossterm::event::read()) { Action::Continue => continue, Action::Result(res) => res?, }; if key_send.send(event).is_err() { break; } } Ok(()) }); key_receive } dua-cli-2.34.0/src/interactive/app/mod.rs000064400000000000000000000003371046102023000162440ustar 00000000000000mod bytevis; mod common; mod eventloop; mod handlers; pub mod input; mod navigation; pub mod state; pub mod terminal; pub mod tree_view; pub use bytevis::*; pub use common::*; pub use handlers::*; #[cfg(test)] mod tests; dua-cli-2.34.0/src/interactive/app/navigation.rs000064400000000000000000000043211046102023000176210ustar 00000000000000use dua::traverse::TreeIndex; use itertools::Itertools; use std::collections::BTreeMap; use super::{CursorDirection, EntryDataBundle}; #[derive(Default)] pub struct Navigation { pub tree_root: TreeIndex, pub view_root: TreeIndex, pub selected: Option, pub bookmarks: BTreeMap, } impl Navigation { pub fn previously_selected_index( &self, view_root: TreeIndex, entries: &[EntryDataBundle], ) -> Option { let idx = self .bookmarks .get(&view_root) .and_then(|selected| { entries .iter() .find_position(|b| b.index == *selected) .map(|(pos, _)| pos) }) .unwrap_or(0); entries.get(idx).map(|a| a.index) } pub fn enter_node(&mut self, previously_selected: TreeIndex, new_selected: TreeIndex) { let view_root = self.view_root; self.bookmarks.insert(view_root, previously_selected); self.view_root = previously_selected; self.selected = Some(new_selected); } pub fn exit_node(&mut self, parent_idx: TreeIndex, entries: &[EntryDataBundle]) { self.view_root = parent_idx; self.selected = self .bookmarks .get(&parent_idx) .copied() .or_else(|| entries.first().map(|b| b.index)); } pub fn next_index( &self, direction: CursorDirection, entries: &[EntryDataBundle], ) -> Option { let next_selected_pos = match self.selected { Some(ref selected) => entries .iter() .find_position(|b| b.index == *selected) .map(|(idx, _)| direction.move_cursor(idx)) .unwrap_or(0), None => 0, }; entries .get(next_selected_pos) .or_else(|| entries.last()) .map(|b| b.index) .or(self.selected) } pub fn select(&mut self, selected: Option) { self.selected = selected; if let Some(selected) = selected { self.bookmarks.insert(self.view_root, selected); } } } dua-cli-2.34.0/src/interactive/app/state.rs000064400000000000000000000037201046102023000166040ustar 00000000000000use std::collections::HashSet; use std::path::PathBuf; use dua::WalkOptions; use dua::traverse::{BackgroundTraversal, TraversalStats}; use crate::interactive::widgets::Column; use super::{EntryDataBundle, SortMode, navigation::Navigation}; #[derive(Default, Copy, Clone, PartialEq)] pub enum FocussedPane { #[default] Main, Help, Mark, Glob, } #[derive(Default)] pub struct Cursor { pub show: bool, pub x: u16, pub y: u16, } pub struct FilesystemScan { pub active_traversal: BackgroundTraversal, /// The selected item prior to starting the traversal, if available, based on its name or index into [`AppState::entries`]. pub previous_selection: Option<(PathBuf, usize)>, } pub struct AppState { pub navigation: Navigation, pub glob_navigation: Option, pub entries: Vec, pub sorting: SortMode, pub show_columns: HashSet, pub message: Option, pub focussed: FocussedPane, pub received_events: bool, pub scan: Option, pub stats: TraversalStats, pub walk_options: WalkOptions, /// The paths used in the initial traversal, at least 1. pub root_paths: Vec, /// If true, listed entries will be validated for presence when switching directories. pub allow_entry_check: bool, pub pending_exit: bool, } impl AppState { pub fn new(walk_options: WalkOptions, input: Vec) -> Self { AppState { navigation: Default::default(), glob_navigation: None, entries: vec![], sorting: Default::default(), show_columns: Default::default(), message: None, focussed: Default::default(), received_events: false, scan: None, stats: TraversalStats::default(), walk_options, root_paths: input, allow_entry_check: true, pending_exit: false, } } } dua-cli-2.34.0/src/interactive/app/terminal.rs000064400000000000000000000063371046102023000173060ustar 00000000000000use std::path::PathBuf; use crate::interactive::EntryCheck; use anyhow::Result; use crossbeam::channel::Receiver; use crossterm::event::Event; use dua::Config; #[cfg(test)] use dua::traverse::TraversalStats; use dua::{ByteFormat, WalkOptions, WalkResult, traverse::Traversal}; use tui::{Terminal, backend::Backend}; use crate::interactive::widgets::MainWindow; use super::{DisplayOptions, sorted_entries, state::AppState}; /// State and methods representing the interactive disk usage analyser for the terminal pub struct TerminalApp { pub config: Config, pub traversal: Traversal, #[cfg(test)] pub stats: TraversalStats, pub display: DisplayOptions, pub state: AppState, pub window: MainWindow, } impl TerminalApp { pub fn initialize( terminal: &mut Terminal, walk_options: WalkOptions, byte_format: ByteFormat, entry_check: bool, input: Vec, config: Config, ) -> Result where B: Backend, { terminal.hide_cursor()?; terminal.clear()?; let display = DisplayOptions::new(byte_format); let window = MainWindow::default(); let mut state = AppState::new(walk_options, input); state.allow_entry_check = entry_check; let traversal = Traversal::new(); #[cfg(test)] let stats = TraversalStats::default(); state.navigation_mut().view_root = traversal.root_index; state.entries = sorted_entries( &traversal.tree, state.navigation().view_root, state.sorting, state.glob_root(), EntryCheck::new(state.scan.is_some(), state.allow_entry_check), ); state.navigation_mut().selected = state.entries.first().map(|b| b.index); let app = TerminalApp { config, state, display, traversal, #[cfg(test)] stats, window, }; Ok(app) } pub fn traverse(&mut self) -> Result<()> { self.state.traverse(&self.traversal)?; Ok(()) } pub fn process_events( &mut self, terminal: &mut Terminal, events: Receiver, ) -> Result where B: Backend, { self.state.process_events( &mut self.window, &mut self.traversal, &mut self.display, terminal, events, &self.config, ) } } #[cfg(test)] mod tests { use super::*; use super::TerminalApp; impl TerminalApp { pub fn run_until_traversed( &mut self, terminal: &mut Terminal, events: Receiver, ) -> Result where B: Backend, { while self.state.scan.is_some() { self.state.process_event( &mut self.window, &mut self.traversal, &mut self.display, terminal, &events, &self.config, )?; } Ok(WalkResult { num_errors: self.stats.io_errors, }) } } } dua-cli-2.34.0/src/interactive/app/tree_view.rs000064400000000000000000000077631046102023000174700ustar 00000000000000use super::{EntryDataBundle, SortMode, sorted_entries}; use crate::interactive::{EntryCheck, path_of}; use dua::traverse::{EntryData, Traversal, Tree, TreeIndex}; use petgraph::{Direction, visit::Bfs}; use std::path::{Path, PathBuf}; pub struct TreeView<'a> { pub traversal: &'a mut Traversal, pub glob_tree_root: Option, } impl TreeView<'_> { pub fn tree(&self) -> &Tree { &self.traversal.tree } pub fn tree_mut(&mut self) -> &mut Tree { &mut self.traversal.tree } pub fn fs_parent_of(&self, idx: TreeIndex) -> Option { self.traversal .tree .neighbors_directed(idx, petgraph::Incoming) .find(|idx| match self.glob_tree_root { None => true, Some(glob_root) => *idx != glob_root, }) } pub fn view_parent_of(&self, idx: TreeIndex) -> Option { let mut iter = self .traversal .tree .neighbors_directed(idx, petgraph::Incoming); match self.glob_tree_root { None => iter.next(), Some(glob_root) => iter .clone() .find(|idx| *idx == glob_root) .or_else(|| iter.next()), } } pub fn path_of(&self, node_idx: TreeIndex) -> PathBuf { path_of(&self.traversal.tree, node_idx, self.glob_tree_root) } pub fn sorted_entries( &self, view_root: TreeIndex, sorting: SortMode, check: EntryCheck, ) -> Vec { sorted_entries( &self.traversal.tree, view_root, sorting, self.glob_tree_root, check, ) } pub fn current_path(&self, view_root: TreeIndex) -> String { current_path(&self.traversal.tree, view_root, self.glob_tree_root) } pub fn remove_entries(&mut self, root_index: TreeIndex, remove_root_node: bool) -> usize { let mut entries_deleted = 0; let mut bfs = Bfs::new(self.tree(), root_index); while let Some(nx) = bfs.next(&self.tree()) { if nx == root_index && !remove_root_node { continue; } self.tree_mut().remove_node(nx); entries_deleted += 1; } entries_deleted } pub fn exists(&self, idx: TreeIndex) -> bool { self.tree().node_weight(idx).is_some() } pub fn total_size(&self) -> u128 { self.tree() .neighbors_directed(self.traversal.root_index, Direction::Outgoing) .filter_map(|idx| self.tree().node_weight(idx).map(|w| w.size)) .sum() } pub fn recompute_sizes_recursively(&mut self, mut index: TreeIndex) { loop { let (size_of_children, item_count) = self .tree() .neighbors_directed(index, Direction::Outgoing) .filter_map(|idx| { self.tree() .node_weight(idx) .map(|w| (w.size, w.entry_count.unwrap_or(1))) }) .reduce(|a, b| (a.0 + b.0, a.1 + b.1)) .unwrap_or_default(); let node = self .traversal .tree .node_weight_mut(index) .expect("valid index"); node.size = size_of_children; node.entry_count = Some(item_count); match self.fs_parent_of(index) { None => break, Some(parent) => index = parent, } } } } fn current_path( tree: &petgraph::stable_graph::StableGraph, root: petgraph::stable_graph::NodeIndex, glob_root: Option, ) -> String { match path_of(tree, root, glob_root).to_string_lossy().to_string() { ref p if p.is_empty() => Path::new(".") .canonicalize() .map(|p| p.to_string_lossy().to_string()) .unwrap_or_else(|_| String::from(".")), p => p, } } dua-cli-2.34.0/src/interactive/mod.rs000064400000000000000000000023461046102023000154660ustar 00000000000000mod app; pub use app::*; pub mod widgets; mod utils { use dua::traverse::{Tree, TreeIndex}; use std::path::PathBuf; pub fn path_of(tree: &Tree, mut node_idx: TreeIndex, glob_root: Option) -> PathBuf { const THE_ROOT: usize = 1; let mut entries = Vec::new(); let mut iter = tree.neighbors_directed(node_idx, petgraph::Incoming); while let Some(parent_idx) = iter.next() { if let Some(glob_root) = glob_root && glob_root == parent_idx { continue; } entries.push( tree.node_weight(node_idx) .expect("node should always be retrievable with valid index"), ); node_idx = parent_idx; iter = tree.neighbors_directed(node_idx, petgraph::Incoming); } entries.push( tree.node_weight(node_idx) .expect("node should always be retrievable with valid index"), ); entries .iter() .rev() .skip(THE_ROOT) .fold(PathBuf::new(), |mut acc, entry| { acc.push(&entry.name); acc }) } } pub use utils::path_of; dua-cli-2.34.0/src/interactive/widgets/entries.rs000064400000000000000000000333331046102023000200260ustar 00000000000000use crate::interactive::widgets::COUNT; use crate::interactive::widgets::tui_ext::util::rect::line_bound; use crate::interactive::widgets::tui_ext::{ List, ListProps, draw_text_nowrap_fn, util::{block_width, rect}, }; use crate::interactive::{ DisplayOptions, EntryDataBundle, SortMode, widgets::{EntryMarkMap, entry_color}, }; use chrono::DateTime; use dua::traverse::TreeIndex; use itertools::Itertools; use std::borrow::{Borrow, Cow}; use std::collections::HashSet; use std::time::SystemTime; use tui::{ buffer::Buffer, layout::{Margin, Rect}, style::{Color, Modifier, Style}, text::Span, widgets::{Block, Borders, Scrollbar, ScrollbarOrientation, ScrollbarState, StatefulWidget}, }; use unicode_segmentation::UnicodeSegmentation; use unicode_width::UnicodeWidthStr; pub struct EntriesProps<'a> { pub current_path: String, pub display: DisplayOptions, pub selected: Option, pub entries: &'a [EntryDataBundle], pub marked: Option<&'a EntryMarkMap>, pub border_style: Style, pub is_focussed: bool, pub sort_mode: SortMode, pub show_columns: &'a HashSet, } #[derive(Default)] pub struct Entries { pub list: List, } impl Entries { pub fn render<'a>( &mut self, props: impl Borrow>, area: Rect, buf: &mut Buffer, ) { let EntriesProps { current_path, display, entries, selected, marked, border_style, is_focussed, sort_mode, show_columns, } = props.borrow(); let list = &mut self.list; let total: u128 = entries.iter().map(|b| b.size).sum(); let (recursive_item_count, item_size): (u64, u128) = entries .iter() .map(|f| (f.entry_count.unwrap_or(1), f.size)) .reduce(|a, b| (a.0 + b.0, a.1 + b.1)) .unwrap_or_default(); let title = title( current_path, entries.len(), recursive_item_count, *display, item_size, ); let title_block = title_block(&title, *border_style); let inner_area = title_block.inner(area); let entry_in_view = entry_in_view(*selected, entries); let props = ListProps { block: Some(title_block), entry_in_view, }; let mut scroll_offset = None; let lines = entries.iter().enumerate().map(|(idx, bundle)| { let node_idx = &bundle.index; let is_dir = &bundle.is_dir; let exists = &bundle.exists; let name = bundle.name.as_path(); let is_marked = marked.map(|m| m.contains_key(node_idx)).unwrap_or(false); let is_selected = selected == &Some(*node_idx); if is_selected { scroll_offset = Some(idx); } let fraction = bundle.size as f32 / total as f32; let text_style = style(is_selected, *is_focussed); let percentage_style = percentage_style(fraction, text_style); let mut columns = Vec::new(); if show_mtime_column(sort_mode, show_columns) { columns.push(mtime_column( bundle.mtime, column_style(Column::MTime, *sort_mode, text_style), )); } columns.push(bytes_column( *display, bundle.size, column_style(Column::Bytes, *sort_mode, text_style), )); columns.push(percentage_column(*display, fraction, percentage_style)); if show_count_column(sort_mode, show_columns) { columns.push(count_column( bundle.entry_count, column_style(Column::Count, *sort_mode, text_style), )); } let available_width = inner_area.width.saturating_sub( columns_with_separators(columns.clone(), percentage_style, true) .iter() .map(|f| f.width() as u16) .sum(), ) as usize; let name = shorten_input( name_with_prefix(name.to_string_lossy(), *is_dir), available_width, ); let style = name_style(is_marked, *exists, *is_dir, text_style); columns.push(name_column(name, area, style)); columns_with_separators(columns, percentage_style, false) }); let line_count = lines.len(); list.render(props, lines, area, buf); let scrollbar = Scrollbar::default() .orientation(ScrollbarOrientation::VerticalRight) .begin_symbol(None) .end_symbol(None); let mut scrollbar_state = ScrollbarState::new(line_count).position(scroll_offset.unwrap_or(list.offset)); scrollbar.render(area.inner(&Margin::new(0, 1)), buf, &mut scrollbar_state); if *is_focussed { let bound = draw_top_right_help(area, &title, buf); draw_bottom_right_help(bound, buf); } } } fn entry_in_view( selected: Option, entries: &[EntryDataBundle], ) -> Option { selected.map(|selected| { entries .iter() .find_position(|b| b.index == selected) .map(|(idx, _)| idx) .unwrap_or(0) }) } fn title_block(title: &str, border_style: Style) -> Block<'_> { Block::default() .title(title) .border_style(border_style) .borders(Borders::ALL) } fn title( current_path: &str, item_count: usize, recursive_item_count: u64, display: DisplayOptions, size: u128, ) -> String { format!( " {} ({item_count} visible, {} total, {}) ", current_path, COUNT.format(recursive_item_count as f64), display.byte_format.display(size) ) } fn draw_bottom_right_help(bound: Rect, buf: &mut Buffer) { let bound = line_bound(bound, bound.height.saturating_sub(1) as usize); let help_text = " mark-move = d | mark-toggle = space | toggle-all = a "; let help_text_block_width = block_width(help_text); if help_text_block_width <= bound.width { draw_text_nowrap_fn( rect::snap_to_right(bound, help_text_block_width), buf, help_text, |_, _, _| Style::default(), ); } } fn draw_top_right_help(area: Rect, title: &str, buf: &mut Buffer) -> Rect { let help_text = " . = o|.. = u ── ⇊ = Ctrl+d|↓ = j|⇈ = Ctrl+u|↑ = k "; let help_text_block_width = block_width(help_text); let bound = Rect { width: area.width.saturating_sub(1), ..area }; if block_width(title) + help_text_block_width <= bound.width { draw_text_nowrap_fn( rect::snap_to_right(bound, help_text_block_width), buf, help_text, |_, _, _| Style::default(), ); } bound } fn style(is_selected: bool, is_focussed: bool) -> Style { let mut style = Style::default(); if is_selected { style.add_modifier.insert(Modifier::REVERSED); } if is_focussed & is_selected { style.add_modifier.insert(Modifier::BOLD); } style } fn percentage_style(fraction: f32, style: Style) -> Style { let avoid_big_reversed_bar = fraction > 0.9; if avoid_big_reversed_bar { style.remove_modifier(Modifier::REVERSED) } else { style } } fn columns_with_separators( columns: Vec>, style: Style, insert_last_separator: bool, ) -> Vec> { let mut columns_with_separators = Vec::new(); let column_count = columns.len(); for (idx, column) in columns.into_iter().enumerate() { columns_with_separators.push(column); if insert_last_separator || idx != column_count - 1 { columns_with_separators.push(Span::styled(" | ", style)) } } columns_with_separators } fn mtime_column(entry_mtime: SystemTime, style: Style) -> Span<'static> { let datetime = DateTime::::from(entry_mtime); let formatted_time = datetime.format("%d/%m/%Y %H:%M:%S").to_string(); Span::styled(format!("{formatted_time:>20}"), style) } fn count_column(entry_count: Option, style: Style) -> Span<'static> { Span::styled( format!( "{:>4}", match entry_count { Some(count) => { COUNT.format(count as f64) } None => "".to_string(), } ), style, ) } fn name_column(name: Cow<'_, str>, area: Rect, style: Style) -> Span<'_> { Span::styled(fill_background_to_right(name, area.width), style) } fn fill_background_to_right(mut s: Cow<'_, str>, entire_width: u16) -> Cow<'_, str> { match (s.len(), entire_width as usize) { (x, y) if x >= y => s, (x, y) => { s.to_mut().extend(std::iter::repeat_n(' ', y - x)); s } } } fn name_with_prefix(mut name: Cow<'_, str>, is_dir: bool) -> Cow<'_, str> { let prefix = if is_dir { // Note that these names never happen on non-root items, so this is a root-item special case. // It was necessary since we can't trust the 'actual' root anymore as it might be the CWD or // `main()` cwd' into the one path that was provided by the user. // The idea was to keep explicit roots as specified without adjustment, which works with this // logic unless somebody provides `name` as is, then we will prefix it which is a little confusing. // Overall, this logic makes the folder display more consistent. if name == "." || name == ".." || name.starts_with('/') || name.starts_with("./") || name.starts_with("../") { None } else { Some("/") } } else { Some(" ") }; match prefix { None => name, Some(prefix) => { name.to_mut().insert_str(0, prefix); name } } } fn name_style(is_marked: bool, exists: bool, is_dir: bool, style: Style) -> Style { let fg = if !exists { // non-existing - always red! Some(Color::Red) } else { entry_color(style.fg, !is_dir, is_marked) }; Style { fg, ..style } } fn percentage_column(display: DisplayOptions, fraction: f32, style: Style) -> Span<'static> { Span::styled(format!("{}", display.byte_vis.display(fraction)), style) } fn bytes_column(display: DisplayOptions, entry_size: u128, style: Style) -> Span<'static> { Span::styled( format!( "{:>byte_column_width$}", display.byte_format.display(entry_size).to_string(), // we would have to impl alignment/padding ourselves otherwise... byte_column_width = display.byte_format.width() ), style, ) } #[derive(PartialEq, Eq, Hash)] pub enum Column { Bytes, MTime, Count, } fn column_style(column: Column, sort_mode: SortMode, style: Style) -> Style { Style { fg: match (sort_mode, column) { (SortMode::SizeAscending | SortMode::SizeDescending, Column::Bytes) | (SortMode::MTimeAscending | SortMode::MTimeDescending, Column::MTime) | (SortMode::CountAscending | SortMode::CountDescending, Column::Count) => { Color::Green.into() } _ => style.fg, }, ..style } } fn show_mtime_column(sort_mode: &SortMode, show_columns: &HashSet) -> bool { matches!( sort_mode, SortMode::MTimeAscending | SortMode::MTimeDescending ) || show_columns.contains(&Column::MTime) } fn show_count_column(sort_mode: &SortMode, show_columns: &HashSet) -> bool { matches!( sort_mode, SortMode::CountAscending | SortMode::CountDescending ) || show_columns.contains(&Column::Count) } /// Note that this implementation isn't correct as `width` is the amount of blocks to display, /// which is not what we are actually counting when adding graphemes to the output string. fn shorten_input(input: Cow<'_, str>, width: usize) -> Cow<'_, str> { const ELLIPSIS: char = '…'; const ELLIPSIS_LEN: usize = 1; const EXTENDED: bool = true; let total_count = input.width(); if total_count <= width { return input; } if ELLIPSIS_LEN > width { return Cow::Borrowed(""); } let graphemes_per_half = (width - ELLIPSIS_LEN) / 2; let mut out = String::with_capacity(width); let mut g = input.graphemes(EXTENDED); out.extend(g.by_ref().take(graphemes_per_half)); out.push(ELLIPSIS); out.extend(g.skip(total_count - graphemes_per_half * 2)); Cow::Owned(out) } #[cfg(test)] mod entries_test { use super::shorten_input; #[test] fn test_shorten_string_middle() { let numbers = "12345678"; let graphemes = "你好😁你好"; for (input, target_length, expected) in [ (numbers, 8, numbers), (numbers, 7, "123…678"), (numbers, 3, "1…8"), (numbers, 2, "…"), (numbers, 1, "…"), (numbers, 0, ""), // multi-block strings are handled incorrectly, but at least it doesn't crash. (graphemes, 0, ""), (graphemes, 1, "…"), (graphemes, 3, "你…"), (graphemes, 4, "你…"), (graphemes, 5, "你好…"), (graphemes, 6, "你好…"), (graphemes, 7, "你好😁…"), (graphemes, 8, "你好😁…"), (graphemes, 9, "你好😁你…"), (graphemes, 10, "你好😁你好"), ] { assert_eq!(shorten_input(input.into(), target_length), expected); } } } dua-cli-2.34.0/src/interactive/widgets/footer.rs000064400000000000000000000066701046102023000176570ustar 00000000000000use dua::ByteFormat; use std::borrow::Borrow; use tui::{ buffer::Buffer, layout::Rect, style::Modifier, style::{Color, Style}, text::{Line, Span, Text}, widgets::{Paragraph, Widget}, }; use crate::interactive::SortMode; pub struct Footer; pub struct FooterProps { pub total_bytes: u128, pub entries_traversed: u64, pub traversal_start: std::time::Instant, pub elapsed: Option, pub format: ByteFormat, pub message: Option, pub sort_mode: SortMode, pub pending_exit: bool, pub esc_navigates_back: bool, } impl Footer { pub fn render(&self, props: impl Borrow, area: Rect, buf: &mut Buffer) { let FooterProps { total_bytes, entries_traversed, elapsed, traversal_start, format, message, sort_mode, pending_exit, esc_navigates_back, } = props.borrow(); if *pending_exit { let exit_msg = if *esc_navigates_back { "Press q again to exit..." } else { "Press esc or q again to exit..." }; Paragraph::new(Text::from(exit_msg)) .style( Style::default() .fg(Color::Black) .bg(Color::Yellow) .add_modifier(Modifier::BOLD), ) .render(area, buf); return; } let spans = vec![ Span::from(format!( "Sort mode: {} Total disk usage: {} Processed {} entries {progress} ", match sort_mode { SortMode::SizeAscending => "size ascending", SortMode::SizeDescending => "size descending", SortMode::MTimeAscending => "modified ascending", SortMode::MTimeDescending => "modified descending", SortMode::CountAscending => "items ascending", SortMode::CountDescending => "items descending", SortMode::NameAscending => "name ascending", SortMode::NameDescending => "name descending", }, format.display(*total_bytes), entries_traversed, progress = match elapsed { Some(elapsed) => format!("in {:.02}s", elapsed.as_secs_f32()), None => { let elapsed = traversal_start.elapsed(); format!( "in {:.0}s ({:.0}/s)", elapsed.as_secs_f32(), *entries_traversed as f32 / elapsed.as_secs_f32() ) } } )) .into(), message.as_ref().map(|m| { Span::styled( m, Style { fg: Color::Red.into(), bg: Color::Reset.into(), add_modifier: Modifier::BOLD | Modifier::RAPID_BLINK, ..Style::default() }, ) }), ]; Paragraph::new(Text::from(Line::from( spans.into_iter().flatten().collect::>(), ))) .style(Style::default().add_modifier(Modifier::REVERSED)) .render(area, buf); } } dua-cli-2.34.0/src/interactive/widgets/glob.rs000064400000000000000000000175161046102023000173050ustar 00000000000000use crate::interactive::widgets::tui_ext::{ draw_text_nowrap_fn, util::{block_width, rect}, }; use anyhow::{Context, Result, anyhow}; use bstr::BString; use crossterm::event::{KeyEvent, KeyEventKind}; use dua::traverse::{Tree, TreeIndex}; use gix_glob::pattern::Case; use petgraph::Direction; use std::borrow::Borrow; use tui::{ buffer::Buffer, layout::Rect, style::Style, text::{Line, Span, Text}, widgets::{Block, Borders, Paragraph, Widget}, }; use unicode_segmentation::UnicodeSegmentation; use unicode_width::UnicodeWidthStr; use crate::interactive::state::Cursor; pub struct GlobPaneProps { pub border_style: Style, pub has_focus: bool, } pub struct GlobPane { pub input: String, /// The index of the grapheme the cursor currently points to. /// This hopefully rightfully assumes that a grapheme will be matching the block size on screen /// and is treated as 'one character'. If not, it will be off, which isn't the end of the world. // TODO: use `tui-textarea` for proper cursor handling, needs native crossterm events. cursor_grapheme_idx: usize, pub case: Case, } impl Default for GlobPane { fn default() -> Self { GlobPane { input: "".to_string(), cursor_grapheme_idx: 0, case: Case::Fold, } } } impl GlobPane { pub fn process_events(&mut self, key: KeyEvent) { use crossterm::event::KeyCode::*; use crossterm::event::KeyModifiers; if key.kind == KeyEventKind::Release { return; } match key.code { Char('f') if key.modifiers.contains(KeyModifiers::CONTROL) => { self.case = match self.case { Case::Sensitive => Case::Fold, Case::Fold => Case::Sensitive, }; } Char(to_insert) => { self.enter_char(to_insert); } Backspace => { self.delete_char(); } Left => { self.move_cursor_left(); } Right => { self.move_cursor_right(); } _ => {} }; } fn move_cursor_left(&mut self) { let cursor_moved_left = self.cursor_grapheme_idx.saturating_sub(1); self.cursor_grapheme_idx = self.clamp_cursor(cursor_moved_left); } fn move_cursor_right(&mut self) { let cursor_moved_right = self.cursor_grapheme_idx.saturating_add(1); self.cursor_grapheme_idx = self.clamp_cursor(cursor_moved_right); } fn enter_char(&mut self, new_char: char) { self.input.insert( self.input .graphemes(true) .take(self.cursor_grapheme_idx) .map(|g| g.len()) .sum::(), new_char, ); for _ in 0..new_char.to_string().graphemes(true).count() { self.move_cursor_right(); } } fn delete_char(&mut self) { if self.cursor_grapheme_idx == 0 { return; } let cur_idx = self.cursor_grapheme_idx; let before_char_to_delete = self.input.graphemes(true).take(cur_idx - 1); let after_char_to_delete = self.input.graphemes(true).skip(cur_idx); self.input = before_char_to_delete.chain(after_char_to_delete).collect(); self.move_cursor_left(); } fn clamp_cursor(&self, new_cursor_pos: usize) -> usize { new_cursor_pos.clamp(0, self.input.graphemes(true).count()) } pub fn render( &mut self, props: impl Borrow, area: Rect, buffer: &mut Buffer, cursor: &mut Cursor, ) { let GlobPaneProps { border_style, has_focus, } = props.borrow(); let title = match self.case { Case::Sensitive => "Git-Glob (case-sensitive)", Case::Fold => "Git-Glob (case-insensitive)", }; let block = Block::default() .title(title) .border_style(*border_style) .borders(Borders::ALL); let inner_block_area = block.inner(area); block.render(area, buffer); let spans = vec![Span::from(&self.input)]; Paragraph::new(Text::from(Line::from(spans))) .style(Style::default()) .render(margin_left_right(inner_block_area, 1), buffer); if *has_focus { draw_top_right_help(area, title, buffer); cursor.show = true; cursor.x = inner_block_area.x + self .input .graphemes(true) .take(self.cursor_grapheme_idx) .map(|g| g.width()) .sum::() as u16 + 1; cursor.y = inner_block_area.y; } else { cursor.show = false; } } } fn draw_top_right_help(area: Rect, title: &str, buf: &mut Buffer) -> Rect { let help_text = " search = enter | case = ^f | cancel = esc "; let help_text_block_width = block_width(help_text); let bound = Rect { width: area.width.saturating_sub(1), ..area }; if block_width(title) + help_text_block_width <= bound.width { draw_text_nowrap_fn( rect::snap_to_right(bound, help_text_block_width), buf, help_text, |_, _, _| Style::default(), ); } bound } fn margin_left_right(r: Rect, margin: u16) -> Rect { Rect { x: r.x + margin, y: r.y, width: r.width - 2 * margin, height: r.height, } } fn glob_search_neighbours( results: &mut Vec, tree: &Tree, root_index: TreeIndex, glob: &gix_glob::Pattern, path: &mut BString, case: Case, ) { for node_index in tree.neighbors_directed(root_index, Direction::Outgoing) { if let Some(node) = tree.node_weight(node_index) { let previous_len = path.len(); let basename_start = if path.is_empty() { None } else { path.push(b'/'); Some(previous_len + 1) }; path.extend_from_slice(gix_path::into_bstr(&node.name).as_ref()); if glob.matches_repo_relative_path( path.as_ref(), basename_start, Some(node.is_dir), case, gix_glob::wildmatch::Mode::NO_MATCH_SLASH_LITERAL, ) { results.push(node_index); } else { glob_search_neighbours(results, tree, node_index, glob, path, case); } path.truncate(previous_len); } } } pub fn glob_search( tree: &Tree, root_index: TreeIndex, glob: &str, case: gix_glob::pattern::Case, ) -> Result> { let glob = gix_glob::Pattern::from_bytes_without_negation(glob.as_bytes()) .with_context(|| anyhow!("Glob was empty or only whitespace"))?; let mut results = Vec::new(); let mut path = Default::default(); glob_search_neighbours(&mut results, tree, root_index, &glob, &mut path, case); Ok(results) } #[cfg(test)] mod tests { use super::*; use crossterm::event::{KeyCode, KeyEventKind, KeyEventState, KeyModifiers}; #[test] fn ctrl_f_key_types_into_input() { let mut glob_pane = GlobPane::default(); assert_eq!(glob_pane.input, ""); assert_eq!(glob_pane.case, Case::Fold); // default is case-insensitive let ctrl_f = KeyEvent { code: KeyCode::Char('f'), modifiers: KeyModifiers::CONTROL, kind: KeyEventKind::Press, state: KeyEventState::empty(), }; glob_pane.process_events(ctrl_f); assert_eq!(glob_pane.case, Case::Sensitive); glob_pane.process_events(ctrl_f); assert_eq!(glob_pane.case, Case::Fold); } } dua-cli-2.34.0/src/interactive/widgets/header.rs000064400000000000000000000027741046102023000176120ustar 00000000000000use tui::{ buffer::Buffer, layout::Rect, style::{Color, Modifier, Style}, text::{Line, Span, Text}, widgets::{Paragraph, Widget}, }; pub struct Header; impl Header { pub fn render(&self, bg_color: Color, area: Rect, buf: &mut Buffer) { let standard = Style { fg: Color::Black.into(), bg: bg_color.into(), ..Default::default() }; debug_assert_ne!(standard.bg, standard.fg); let modified = |text: &'static str, modifier| { Span::styled( text, Style { add_modifier: modifier, ..standard }, ) }; let bold = |text: &'static str| modified(text, Modifier::BOLD); let italic = |text: &'static str| modified(text, Modifier::UNDERLINED); let text = |text: &'static str| Span::styled(text, standard); let spans = vec![ bold(" D"), text("isk "), bold("U"), text("sage "), bold("A"), text("nalyzer v"), text(env!("CARGO_PKG_VERSION")), text(" "), italic("(press "), modified("?", Modifier::BOLD | Modifier::UNDERLINED), italic(" for help)"), ]; Paragraph::new(Text::from(Line::from(spans))) .style(Style { bg: bg_color.into(), ..Default::default() }) .render(area, buf); } } dua-cli-2.34.0/src/interactive/widgets/help.rs000064400000000000000000000237211046102023000173050ustar 00000000000000use crate::interactive::CursorDirection; use crate::interactive::widgets::tui_ext::{ draw_text_nowrap_fn, util::{block_width, rect}, }; pub use crossterm::event::KeyCode::*; use crossterm::event::{KeyEvent, KeyEventKind, KeyModifiers}; use std::{borrow::Borrow, cell::RefCell}; use tui::{ buffer::Buffer, layout::Rect, style::{Color, Modifier, Style}, text::{Line, Span, Text}, widgets::{Block, Borders, Paragraph, Widget}, }; #[derive(Default, Clone)] pub struct HelpPane { pub scroll: u16, } pub struct HelpPaneProps { pub border_style: Style, pub has_focus: bool, pub esc_navigates_back: bool, } fn margin(r: Rect, margin: u16) -> Rect { Rect { x: r.x + margin, y: r.y + margin, width: r.width - 2 * margin, height: r.height - 2 * margin, } } impl HelpPane { pub fn process_events(&mut self, key: KeyEvent) { if key.kind == KeyEventKind::Release { return; } match key.code { Char('H') => self.scroll_help(CursorDirection::ToTop), Char('G') => self.scroll_help(CursorDirection::ToBottom), Char('u') if key.modifiers.contains(KeyModifiers::CONTROL) => { self.scroll_help(CursorDirection::PageUp) } Char('d') if key.modifiers.contains(KeyModifiers::CONTROL) => { self.scroll_help(CursorDirection::PageDown) } PageUp => self.scroll_help(CursorDirection::PageUp), PageDown => self.scroll_help(CursorDirection::PageDown), Char('k') | Up => self.scroll_help(CursorDirection::Up), Char('j') | Down => self.scroll_help(CursorDirection::Down), _ => {} }; } fn scroll_help(&mut self, direction: CursorDirection) { self.scroll = direction.move_cursor(self.scroll as usize) as u16; } pub fn render(&mut self, props: impl Borrow, area: Rect, buf: &mut Buffer) { let esc_navigates_back = props.borrow().esc_navigates_back; let lines = { let lines = RefCell::new(Vec::>::with_capacity(30)); let add_newlines = |n| { for _ in 0..n { lines.borrow_mut().push(Line::from(Span::raw(""))) } }; let spacer = || add_newlines(2); let title = |name: &str| { lines.borrow_mut().push(Line::from(Span::styled( name.to_string(), Style { add_modifier: Modifier::BOLD | Modifier::UNDERLINED, ..Default::default() }, ))); add_newlines(1); }; let hotkey = |keys, description, other_line: Option<&str>| { let separator_size = 3; let column_size = 11 + separator_size; lines.borrow_mut().push(Line::from(vec![ Span::styled( format!( "{:>column_size$}", keys, column_size = column_size - separator_size ), Style { fg: Color::Green.into(), ..Default::default() }, ), Span::from(format!(" => {description}")), ])); if let Some(second_line) = other_line { lines.borrow_mut().push(Line::from(Span::from(format!( "{:>column_size$}{}", "", second_line, column_size = column_size + 1 )))); } }; title("Pane control"); { if esc_navigates_back { hotkey( "q", "Close the current pane. In main view, quit (may require confirmation).", None, ); hotkey( "", "Close the current pane.", Some("In main view, ascend to the parent directory."), ); } else { hotkey( "q/", "Close the current pane.", Some("Closes the program if no pane is open."), ); } hotkey( "", "Cycle between all open panes.", Some("Activate 'Marked Items' pane to delete selected files."), ); hotkey("?", "Show or hide this help pane.", None); spacer(); } title("Navigation"); { hotkey("j/", "Move down 1 entry.", None); hotkey("k/", "Move up 1 entry.", None); hotkey("o/l/", "Descent into the selected directory.", None); hotkey("", "^", None); hotkey( "u/h/", "Ascent one level into the parent directory.", None, ); hotkey("", "^", None); hotkey("Ctrl + d", "Move down 10 entries.", None); hotkey("", "^", None); hotkey("Ctrl + u", "Move up 10 entries.", None); hotkey("", "^", None); hotkey("H/", "Move to the top of the list.", None); hotkey("G/", "Move to the bottom of the list.", None); spacer(); } title("Display"); { hotkey("s", "Toggle sort by size descending/ascending.", None); hotkey( "m", "Toggle sort by modified time descending/ascending.", None, ); hotkey("M", "Show/hide modified time.", None); hotkey("c", "Toggle sort by entries descending/ascending.", None); hotkey("C", "Show/hide entry count.", None); hotkey("n", "Toggle sort by name ascending/descending.", None); hotkey( "g/S", "Cycle through percentage display and bar options.", None, ); spacer(); } title("Open/Mark/Search"); { hotkey( "Shift + o", "Open the selected entry with the associated program.", None, ); hotkey( "d", "Toggle the currently selected entry and move down.", None, ); hotkey( "x", "Mark the currently selected entry for deletion and move down.", None, ); hotkey("", "Toggle the currently selected entry.", None); hotkey("a", "Toggle all entries.", None); hotkey( "/", "Git-style glob search. Toggle case with 'I'.", Some("Search starts from the current directory."), ); hotkey("r", "Refresh only the selected entry.", None); hotkey("R", "Refresh all entries in the current view.", None); spacer(); } title("Mark entries pane"); { hotkey( "x/d/", "Remove the selected entry from the list.", None, ); hotkey("a", "Remove all entries from the list.", None); hotkey( "Ctrl + r", "Permanently delete all marked entries without prompt.", Some("This operation cannot be undone!"), ); #[cfg(feature = "trash-move")] hotkey( "Ctrl + t", "Move all marked entries to the trash bin.", Some("The entries can be restored from the trash bin."), ); spacer(); } title("Application control"); { hotkey( "Ctrl + c", "Close the application. No questions asked!", None, ); spacer(); } lines.into_inner() }; let HelpPaneProps { border_style, has_focus, .. } = props.borrow(); let title = "Help"; let block = Block::default() .title(title) .border_style(*border_style) .borders(Borders::ALL); let inner_block_area = block.inner(area); block.render(area, buf); if *has_focus { let help_text = " . = o|.. = u ── ⇊ = Ctrl+d|↓ = j|⇈ = Ctrl+u|↑ = k "; let help_text_block_width = block_width(help_text); let bound = Rect { width: area.width.saturating_sub(1), ..area }; if block_width(title) + help_text_block_width <= bound.width { draw_text_nowrap_fn( rect::snap_to_right(bound, help_text_block_width), buf, help_text, |_, _, _| Style::default(), ); } } let area = margin(inner_block_area, 1); self.scroll = self .scroll .min(lines.len().saturating_sub(area.height as usize) as u16); Paragraph::new(Text::from(lines)) .scroll((self.scroll, 0)) .render(area, buf); } } dua-cli-2.34.0/src/interactive/widgets/main.rs000064400000000000000000000146021046102023000172770ustar 00000000000000use crate::interactive::{ DisplayOptions, state::{AppState, Cursor, FocussedPane}, widgets::{ COLOR_MARKED, Entries, EntriesProps, Footer, FooterProps, GlobPane, GlobPaneProps, Header, HelpPane, HelpPaneProps, MarkPane, MarkPaneProps, }, }; use Constraint::*; use FocussedPane::*; use std::borrow::Borrow; use tui::buffer::Buffer; use tui::{ layout::{Constraint, Direction, Layout, Rect}, style::Modifier, style::{Color, Style}, }; pub struct MainWindowProps<'a> { pub current_path: String, pub entries_traversed: u64, pub total_bytes: u128, pub start: std::time::Instant, pub elapsed: Option, pub display: DisplayOptions, pub state: &'a AppState, pub config: &'a dua::Config, } #[derive(Default)] pub struct MainWindow { pub help_pane: Option, pub entries_pane: Entries, pub mark_pane: Option, pub glob_pane: Option, } impl MainWindow { pub fn render<'a>( &mut self, props: impl Borrow>, area: Rect, buffer: &mut Buffer, cursor: &mut Cursor, ) { let MainWindowProps { current_path, entries_traversed, total_bytes, start, elapsed, display, state, config, } = props.borrow(); let (entries_style, help_style, mark_style, glob_style) = pane_border_style(state.focussed); let (header_area, content_area, footer_area) = main_window_layout(area); let header_bg_color = header_background_color(self.is_anything_marked(), state.focussed); Header.render(header_bg_color, header_area, buffer); let (entries_area, help_pane, mark_pane) = { let (left_pane, right_pane) = content_layout(content_area); match (&mut self.help_pane, &mut self.mark_pane) { (Some(pane), None) => (left_pane, Some((right_pane, pane)), None), (None, Some(pane)) => (left_pane, None, Some((right_pane, pane))), (Some(help), Some(mark)) => { let (top_area, bottom_area) = right_pane_layout(right_pane); (left_pane, Some((top_area, help)), Some((bottom_area, mark))) } (None, None) => (content_area, None, None), } }; let (entries_area, glob_pane) = match &mut self.glob_pane { Some(glob_pane) => { let regions = Layout::default() .direction(Direction::Vertical) .constraints([Max(256), Length(3)].as_ref()) .split(entries_area); (regions[0], Some((regions[1], glob_pane))) } None => (entries_area, None), }; if let Some((mark_area, pane)) = mark_pane { let props = MarkPaneProps { border_style: mark_style, format: display.byte_format, }; pane.render(props, mark_area, buffer); } if let Some((help_area, pane)) = help_pane { let props = HelpPaneProps { border_style: help_style, has_focus: matches!(state.focussed, Help), esc_navigates_back: config.keys.esc_navigates_back, }; pane.render(props, help_area, buffer); } let marked = self.mark_pane.as_ref().map(|p| p.marked()); let props = EntriesProps { current_path: current_path.clone(), display: *display, entries: &state.entries, marked, selected: state.navigation().selected, border_style: entries_style, is_focussed: matches!(state.focussed, Main), sort_mode: state.sorting, show_columns: &state.show_columns, }; self.entries_pane.render(props, entries_area, buffer); if let Some((glob_area, pane)) = glob_pane { let props = GlobPaneProps { border_style: glob_style, has_focus: matches!(state.focussed, Glob), }; pane.render(props, glob_area, buffer, cursor); } Footer.render( FooterProps { total_bytes: *total_bytes, format: display.byte_format, entries_traversed: *entries_traversed, message: state.message.clone(), traversal_start: *start, elapsed: *elapsed, sort_mode: state.sorting, pending_exit: state.pending_exit, esc_navigates_back: config.keys.esc_navigates_back, }, footer_area, buffer, ); } fn is_anything_marked(&self) -> bool { self.mark_pane .as_ref() .map(|p| p.marked()) .is_none_or(|m| m.is_empty()) } } fn right_pane_layout(right_pane: Rect) -> (Rect, Rect) { let regions = Layout::default() .direction(Direction::Vertical) .constraints([Percentage(50), Percentage(50)].as_ref()) .split(right_pane); (regions[0], regions[1]) } fn content_layout(content_area: Rect) -> (Rect, Rect) { let regions = Layout::default() .direction(Direction::Horizontal) .constraints([Percentage(50), Percentage(50)].as_ref()) .split(content_area); (regions[0], regions[1]) } fn header_background_color(is_marked: bool, focused_pane: FocussedPane) -> Color { match (is_marked, focused_pane) { (false, Mark) => Color::LightRed, (false, _) => COLOR_MARKED, (_, _) => Color::White, } } fn main_window_layout(area: Rect) -> (Rect, Rect, Rect) { let regions = Layout::default() .direction(Direction::Vertical) .constraints([Length(1), Max(256), Length(1)].as_ref()) .split(area); (regions[0], regions[1], regions[2]) } fn pane_border_style(focused_pane: FocussedPane) -> (Style, Style, Style, Style) { let grey = Style { fg: Color::DarkGray.into(), bg: Color::Reset.into(), add_modifier: Modifier::empty(), ..Style::default() }; let bold = Style::default().add_modifier(Modifier::BOLD); match focused_pane { Main => (bold, grey, grey, grey), Help => (grey, bold, grey, grey), Mark => (grey, grey, bold, grey), Glob => (grey, grey, grey, bold), } } dua-cli-2.34.0/src/interactive/widgets/mark.rs000064400000000000000000000443201046102023000173050ustar 00000000000000use crate::interactive::widgets::COUNT; use crate::interactive::widgets::tui_ext::{ List, ListProps, draw_text_nowrap_fn, util::{block_width, rect, rect::line_bound}, }; use crate::interactive::{ CursorDirection, app::tree_view::TreeView, fit_string_graphemes_with_ellipsis, widgets::entry_color, }; use crossterm::event::{KeyEvent, KeyEventKind, KeyModifiers}; use dua::{ByteFormat, traverse::TreeIndex}; use itertools::Itertools; use std::{ borrow::Borrow, collections::{BTreeMap, btree_map::Entry}, path::PathBuf, }; use tui::{ buffer::Buffer, layout::{Constraint, Direction, Layout, Rect}, style::{Color, Modifier, Style}, text::{Line, Span, Text}, widgets::{ Block, Borders, Paragraph, Scrollbar, ScrollbarOrientation, ScrollbarState, StatefulWidget, Widget, }, }; use unicode_segmentation::UnicodeSegmentation; pub enum MarkMode { Delete, #[cfg(feature = "trash-move")] Trash, } pub type EntryMarkMap = BTreeMap; #[derive(Default)] pub struct EntryMark { pub size: u128, pub path: PathBuf, pub index: usize, pub num_errors_during_deletion: usize, pub is_dir: bool, pub entry_count: Option, } #[derive(Default)] pub struct MarkPane { selected: Option, marked: EntryMarkMap, list: List, has_focus: bool, last_sorting_index: usize, total_size: u128, item_count: u64, } pub struct MarkPaneProps { pub border_style: Style, pub format: ByteFormat, } impl MarkPane { #[cfg(test)] pub fn has_focus(&self) -> bool { self.has_focus } pub fn set_focus(&mut self, has_focus: bool) { self.has_focus = has_focus; if has_focus { self.selected = Some(self.marked.len().saturating_sub(1)); } else { self.selected = None } } pub fn toggle_index( mut self, index: TreeIndex, tree_view: &TreeView<'_>, is_dir: bool, toggle: bool, ) -> Option { match self.marked.entry(index) { Entry::Vacant(entry) => { if let Some(e) = tree_view.tree().node_weight(index) { let sorting_index = self.last_sorting_index + 1; self.last_sorting_index = sorting_index; entry.insert(EntryMark { size: e.size, path: tree_view.path_of(index), index: sorting_index, num_errors_during_deletion: 0, is_dir, entry_count: e.entry_count, }); } } Entry::Occupied(entry) => { if toggle { entry.remove(); } } }; if self.marked.is_empty() { None } else { (self.total_size, self.item_count) = calculate_size_and_count(&self.marked); Some(self) } } pub fn marked(&self) -> &EntryMarkMap { &self.marked } pub fn into_paths(self) -> impl Iterator { self.marked.into_values().map(|v| v.path) } pub fn process_events(mut self, key: KeyEvent) -> Option<(Self, Option)> { use crossterm::event::KeyCode::*; let action = None; if key.kind == KeyEventKind::Release { return Some((self, action)); } match key.code { Char('r') if key.modifiers.contains(KeyModifiers::CONTROL) => { return Some(self.prepare_deletion(MarkMode::Delete)); } #[cfg(feature = "trash-move")] Char('t') if key.modifiers.contains(KeyModifiers::CONTROL) => { return Some(self.prepare_deletion(MarkMode::Trash)); } Char('a') => return None, Char('H') => self.change_selection(CursorDirection::ToTop), Char('G') => self.change_selection(CursorDirection::ToBottom), PageUp => self.change_selection(CursorDirection::PageUp), Char('u') if key.modifiers.contains(KeyModifiers::CONTROL) => { self.change_selection(CursorDirection::PageUp) } Char('d') if key.modifiers.contains(KeyModifiers::CONTROL) => { self.change_selection(CursorDirection::PageDown) } PageDown => self.change_selection(CursorDirection::PageDown), Char('k') | Up => self.change_selection(CursorDirection::Up), Char('j') | Down => self.change_selection(CursorDirection::Down), Char('x') | Char('d') | Char(' ') => { return self.remove_selected().map(|s| (s, action)); } _ => {} }; Some((self, action)) } pub fn iterate_deletable_items( mut self, mut delete_fn: impl FnMut(Self, TreeIndex) -> Result, ) -> Option { loop { match self.next_entry_for_deletion() { Some(entry_to_delete) => match delete_fn(self, entry_to_delete) { Ok(pane) => { self = pane; match self.delete_entry() { Some(p) => self = p, None => return None, } } Err((pane, num_errors)) => { self = pane; self.set_error_on_marked_item(num_errors) } }, None => return Some(self), } } } fn next_entry_for_deletion(&mut self) -> Option { match self.selected.and_then(|selected| { self.tree_index_by_list_position(selected) .and_then(|idx| self.marked.get(&idx).map(|d| (selected, idx, d))) }) { Some((position, selected_index, data)) => match data.num_errors_during_deletion { 0 => Some(selected_index), _ => { self.selected = match position + 1 { p if p < self.marked.len() => Some(p), _ => Some(self.marked.len().saturating_sub(1)), }; self.tree_index_by_list_position(position + 1) } }, None => None, } } fn delete_entry(self) -> Option { self.remove_selected() } fn set_error_on_marked_item(&mut self, num_errors: usize) { if let Some(d) = self .selected .and_then(|s| self.tree_index_by_list_position(s)) .and_then(|p| self.marked.get_mut(&p)) { d.num_errors_during_deletion = num_errors; } } fn prepare_deletion(mut self, mark: MarkMode) -> (Self, Option) { for entry in self.marked.values_mut() { entry.num_errors_during_deletion = 0; } self.selected = Some(0); (self, Some(mark)) } fn remove_selected(mut self) -> Option { if let Some(mut selected) = self.selected { let idx = self.tree_index_by_list_position(selected); let se_len = self.marked.len(); if let Some(idx) = idx { self.marked.remove(&idx); let new_len = se_len.saturating_sub(1); if new_len == 0 { return None; } if new_len == selected { selected = selected.saturating_sub(1); } self.selected = Some(selected); } } Some(self) } fn tree_index_by_list_position(&mut self, selected: usize) -> Option { self.marked_sorted_by_index() .get(selected) .map(|(k, _)| *k.to_owned()) } fn marked_sorted_by_index(&self) -> Vec<(&TreeIndex, &EntryMark)> { self.marked .iter() .sorted_by_key(|(_, v)| &v.index) .collect() } fn change_selection(&mut self, direction: CursorDirection) { self.selected = self.selected.map(|selected| { direction .move_cursor(selected) .min(self.marked.len().saturating_sub(1)) }); } pub fn render(&mut self, props: impl Borrow, area: Rect, buf: &mut Buffer) { let MarkPaneProps { border_style, format, } = props.borrow(); let marked: &_ = &self.marked; let title = format!( "Marked {} items ({}) ", COUNT.format(self.item_count as f64), format.display(self.total_size) ); let selected = self.selected; let has_focus = self.has_focus; let entries = marked.values().sorted_by_key(|v| &v.index).enumerate().map( |(idx, v): (usize, &EntryMark)| { let base_style = match selected { Some(selected) if idx == selected => { let mut modifier = Modifier::REVERSED; if has_focus { modifier.insert(Modifier::BOLD); } Style { add_modifier: modifier, ..Default::default() } } _ => Style::default(), }; let (path, path_len) = { let path = format!( " {} {}", v.path.display(), if v.num_errors_during_deletion != 0 { format!("{} IO deletion errors", v.num_errors_during_deletion) } else { "".to_string() } ); let num_path_graphemes = path.graphemes(true).count(); match num_path_graphemes + format.total_width() { n if n > area.width as usize => { let desired_size = num_path_graphemes.saturating_sub(n - area.width as usize); fit_string_graphemes_with_ellipsis( path, num_path_graphemes, desired_size, ) } _ => (path, num_path_graphemes), } }; let fg_path = entry_color(None, !v.is_dir, true); let path = Span::styled( path, Style { fg: fg_path, ..base_style }, ); let bytes = Span::styled( format!( "{:>byte_column_width$} ", format.display(v.size).to_string(), // we would have to impl alignment/padding ourselves otherwise... byte_column_width = format.width() ), Style { fg: Color::Green.into(), ..base_style }, ); let spacer = Span::styled( format!( "{:-space$}", "", space = (area.width as usize) .saturating_sub(path_len) .saturating_sub(format.total_width()) ), Style { fg: fg_path, ..base_style }, ); vec![path, spacer, bytes] }, ); let entry_in_view = match self.selected { Some(s) => Some(s), None => { self.list.offset = 0; Some(marked.len().saturating_sub(1)) } }; let block = Block::default() .title(title.as_str()) .border_style(*border_style) .borders(Borders::ALL); let inner_area = block.inner(area); block.render(area, buf); let list_area = if self.has_focus { let (help_line_area, list_area) = { let help_at_bottom = selected.unwrap_or(0).saturating_sub(self.list.offset) >= inner_area.height.saturating_sub(1) as usize / 2; let constraints = { let mut c = vec![Constraint::Length(1), Constraint::Max(256)]; if help_at_bottom { c.reverse(); } c }; let regions = Layout::default() .direction(Direction::Vertical) .constraints(constraints) .split(inner_area); match help_at_bottom { true => (regions[1], regions[0]), false => (regions[0], regions[1]), } }; let default_style = Style { fg: Color::Black.into(), bg: Color::Yellow.into(), add_modifier: Modifier::BOLD, sub_modifier: Modifier::empty(), }; Paragraph::new(Text::from(Line::from(vec![ #[cfg(feature = "trash-move")] Span::styled( " Ctrl + t ", Style { fg: Color::White.into(), bg: Color::Black.into(), ..default_style }, ), #[cfg(feature = "trash-move")] Span::styled(" to trash or ", default_style), Span::styled( " Ctrl + r ", Style { fg: Color::LightRed.into(), bg: Color::Black.into(), add_modifier: default_style.add_modifier | Modifier::RAPID_BLINK, ..default_style }, ), Span::styled(" to delete without prompt", default_style), ]))) .style(default_style) .render(help_line_area, buf); list_area } else { inner_area }; let line_count = marked.len(); let props = ListProps { block: None, entry_in_view, }; self.list.render(props, entries, list_area, buf); let scrollbar = Scrollbar::default() .orientation(ScrollbarOrientation::VerticalRight) .begin_symbol(None) .end_symbol(None); let mut scrollbar_state = ScrollbarState::new(line_count).position(selected.unwrap_or(self.list.offset)); scrollbar.render( { let mut scrollbar_area = list_area; // The list has no blocks, so we need to increase // the render area for scrollbar to make sure it // will be drawn on the border. scrollbar_area.width += 1; scrollbar_area }, buf, &mut scrollbar_state, ); if has_focus { let help_text = " . = o|.. = u ── ⇊ = Ctrl+d|↓ = j|⇈ = Ctrl+u|↑ = k "; let help_text_block_width = block_width(help_text); let bound = Rect { width: area.width.saturating_sub(1), ..area }; if block_width(&title) + help_text_block_width <= bound.width { draw_text_nowrap_fn( rect::snap_to_right(bound, help_text_block_width), buf, help_text, |_, _, _| Style::default(), ); } let bound = line_bound(bound, bound.height.saturating_sub(1) as usize); let help_text = " mark-toggle = space,d | remove-all = a"; let help_text_block_width = block_width(help_text); if help_text_block_width <= bound.width { draw_text_nowrap_fn( rect::snap_to_right(bound, help_text_block_width), buf, help_text, |_, _, _| Style::default(), ); } } } } pub fn calculate_size_and_count(marked: &EntryMarkMap) -> (u128, u64) { let entries: Vec<&EntryMark> = marked .values() .sorted_by(|a, b| Ord::cmp(&a.path, &b.path)) .collect(); let mut size = 0u128; let mut item_count = 0u64; for (idx, entry) in entries.iter().enumerate() { let mut is_subdirectory = false; for other in &entries[0..idx] { if other.is_dir && entry.path.starts_with(&other.path) { is_subdirectory = true; break; } } if !is_subdirectory { size += entry.size; item_count += entry.entry_count.unwrap_or(1); } } (size, item_count) } #[cfg(test)] mod mark_pane_tests { use super::*; #[test] fn test_calculate_size() { let mut marked = EntryMarkMap::new(); marked.insert( TreeIndex::new(0), EntryMark { size: 2, path: PathBuf::from("root/test1"), ..Default::default() }, ); marked.insert( TreeIndex::new(1), EntryMark { size: 10, path: PathBuf::from("root"), is_dir: true, entry_count: Some(2), ..Default::default() }, ); marked.insert( TreeIndex::new(2), EntryMark { size: 5, path: PathBuf::from("root1"), ..Default::default() }, ); marked.insert( TreeIndex::new(3), EntryMark { size: 2, path: PathBuf::from("root/test2"), ..Default::default() }, ); assert_eq!(calculate_size_and_count(&marked), (15u128, 3u64)); } } dua-cli-2.34.0/src/interactive/widgets/mod.rs000064400000000000000000000015371046102023000171350ustar 00000000000000mod entries; mod footer; mod glob; mod header; mod help; mod main; mod mark; mod tui_ext; pub use entries::*; pub use footer::*; pub use glob::*; pub use header::*; pub use help::*; pub use main::*; pub use mark::*; use once_cell::sync::Lazy; use tui::style::Color; pub const COLOR_MARKED: Color = Color::Yellow; pub const COLOR_MARKED_DARK: Color = Color::Rgb(176, 126, 0); static COUNT: Lazy = Lazy::new(|| { let mut formatter = human_format::Formatter::new(); formatter.with_decimals(0).with_separator(""); formatter }); fn entry_color(fg: Option, is_file: bool, is_marked: bool) -> Option { match (is_file, is_marked) { (true, false) => fg, (true, true) => COLOR_MARKED_DARK.into(), (false, true) => COLOR_MARKED.into(), (false, false) => Color::Cyan.into(), } } dua-cli-2.34.0/src/interactive/widgets/tui_ext.rs000064400000000000000000000051231046102023000200320ustar 00000000000000use tui::{ buffer::Buffer, layout::Rect, style::Style, text::Line, widgets::{Block, ListItem, ListState}, }; use unicode_width::UnicodeWidthChar; use unicode_width::UnicodeWidthStr; #[derive(Default)] pub struct List { pub offset: usize, } pub struct ListProps<'a> { pub block: Option>, pub entry_in_view: Option, } impl List { pub fn render<'a>( &mut self, props: ListProps<'_>, entries: impl IntoIterator>>, area: Rect, buf: &mut Buffer, ) { let mut state = ListState::default().with_offset(self.offset); if let Some(selected) = props.entry_in_view { state.select(Some(selected)); } let mut list = tui::widgets::List::new( entries .into_iter() .map(|entry| ListItem::new(tui::text::Text::from(entry.into()))), ); if let Some(block) = props.block { list = list.block(block); } tui::widgets::StatefulWidget::render(list, area, buf, &mut state); self.offset = state.offset(); } } pub fn draw_text_nowrap_fn( area: Rect, buf: &mut Buffer, text: &str, mut style_fn: impl FnMut(usize, usize, char) -> Style, ) { let mut col = 0usize; for (x, ch) in text.chars().enumerate() { if col >= area.width as usize { break; } let cell = buf.get_mut(area.x.saturating_add(col as u16), area.y); cell.set_char(ch); let style = style_fn(x, 0, ch); cell.set_style(style); let width = UnicodeWidthChar::width(ch).unwrap_or(1); for continuation in 1..width { if col + continuation >= area.width as usize { break; } let cell = buf.get_mut(area.x.saturating_add((col + continuation) as u16), area.y); cell.set_char(' '); cell.set_style(style); } col += width; } } pub mod util { use super::*; pub fn block_width(text: &str) -> u16 { text.width() as u16 } pub mod rect { use super::*; pub fn snap_to_right(area: Rect, width: u16) -> Rect { Rect { x: area.x + area.width.saturating_sub(width), width: width.min(area.width), ..area } } pub fn line_bound(area: Rect, line: usize) -> Rect { Rect { y: area.y + (line as u16).min(area.height.saturating_sub(1)), height: 1, ..area } } } } dua-cli-2.34.0/src/lib.rs000064400000000000000000000010321046102023000131270ustar 00000000000000//! Public library API for `dua` core traversal and aggregation functionality. //! //! This crate powers the `dua` binary and can also be used as a library. #![cfg_attr(windows, feature(windows_by_handle))] #![forbid(unsafe_code)] #![deny(missing_docs)] mod aggregate; mod common; mod config; pub use config::Config; mod crossdev; mod inodefilter; /// Filesystem traversal, in-memory tree representation, and traversal events. pub mod traverse; pub use aggregate::aggregate; pub use common::*; pub(crate) use inodefilter::InodeFilter; dua-cli-2.34.0/src/main.rs000064400000000000000000000235171046102023000133210ustar 00000000000000#![forbid(rust_2018_idioms, unsafe_code)] use anyhow::{Context, Result, anyhow, bail}; use clap::{CommandFactory as _, Parser}; use dua::{TraversalSorting, canonicalize_ignore_dirs}; use log::info; use std::{ fs, io, io::{IsTerminal, Write}, path::{Path, PathBuf}, process, }; #[cfg(feature = "tui-crossplatform")] use crate::interactive::input::input_channel; #[cfg(feature = "tui-crossplatform")] use crate::interactive::terminal::TerminalApp; mod crossdev; #[cfg(feature = "tui-crossplatform")] mod interactive; mod options; fn stderr_if_tty() -> Option { let stderr = io::stderr(); if stderr.is_terminal() { Some(stderr) } else { None } } #[cfg(feature = "tui-crossplatform")] struct InteractiveTerminalGuard; #[cfg(feature = "tui-crossplatform")] impl Drop for InteractiveTerminalGuard { fn drop(&mut self) { crossterm::terminal::disable_raw_mode().ok(); crossterm::execute!(io::stderr(), crossterm::terminal::LeaveAlternateScreen).ok(); } } fn main() -> Result<()> { use options::Command::*; let opt: options::Args = options::Args::parse_from(wild::args_os()); if let Some(log_file) = &opt.log_file { log_panics::init(); let log_output = std::fs::OpenOptions::new() .create(true) .append(true) .open(log_file)?; fern::Dispatch::new() .level(log::LevelFilter::Debug) .format(|formatter_out, log_msg, log_rec| { let when = jiff::Zoned::now(); formatter_out.finish(format_args!( "[{} {} {}:{}] {}", when.strftime("%Y-%m-%d %H:%M:%S%.3f %:z"), log_rec.level(), log_rec.file().unwrap_or(""), log_rec.line().unwrap_or(0), log_msg )) }) .chain(log_output) .apply()?; info!("dua options={opt:#?}"); } let byte_format: dua::ByteFormat = opt.format.into(); let mut walk_options = dua::WalkOptions { threads: opt.threads, apparent_size: opt.apparent_size, count_hard_links: opt.count_hard_links, sorting: TraversalSorting::None, cross_filesystems: !opt.stay_on_filesystem, ignore_dirs: canonicalize_ignore_dirs(&opt.ignore_dirs), }; if walk_options.threads == 0 { // avoid using the global rayon pool, as it will keep a lot of threads alive after we are done. // Also means that we will spin up a bunch of threads per root path, instead of reusing them. walk_options.threads = num_cpus::get(); } let cross_filesystems = walk_options.cross_filesystems; let res = match opt.command { #[cfg(feature = "tui-crossplatform")] Some(Interactive { no_entry_check }) => { use anyhow::{Context, anyhow}; use crossterm::{ execute, terminal::{EnterAlternateScreen, enable_raw_mode}, }; use tui::{Terminal, backend::CrosstermBackend}; let config = dua::Config::load()?; let no_tty_msg = "Interactive mode requires a connected terminal"; if !io::stderr().is_terminal() { return Err(anyhow!(no_tty_msg)); } let mut stderr = io::stderr(); enable_raw_mode().with_context(|| no_tty_msg)?; execute!(stderr, EnterAlternateScreen).with_context(|| no_tty_msg)?; let terminal_guard = InteractiveTerminalGuard; let mut terminal = Terminal::new(CrosstermBackend::new(stderr)) .with_context(|| "Could not instantiate terminal")?; let keys_rx = input_channel(); let mut app = TerminalApp::initialize( &mut terminal, walk_options, byte_format, !no_entry_check, extract_paths_maybe_set_cwd(opt.input, cross_filesystems)?, config, )?; app.traverse()?; let res = app.process_events(&mut terminal, keys_rx); let res = res.map(|r| { ( r, app.window .mark_pane .take() .map(|marked| marked.into_paths()), ) }); // Leak app memory to avoid having to wait for the hashmap to deallocate, // which causes a noticeable delay shortly before the the program exits anyway. std::mem::forget(app); drop(terminal); drop(terminal_guard); io::stderr().flush().ok(); // Exit 'quickly' to avoid having to not have to deal with slightly different types in the other match branches std::process::exit( res.map(|(walk_result, paths)| { if let Some(paths) = paths { for path in paths { println!("{}", path.display()) } } walk_result.to_exit_code() }) .unwrap_or(0), ); } Some(Aggregate { no_total, no_sort, statistics, }) => { let stdout = io::stdout(); let stdout_locked = stdout.lock(); let (res, stats) = dua::aggregate( stdout_locked, stderr_if_tty(), walk_options, !no_total, !no_sort, byte_format, extract_paths_maybe_set_cwd(opt.input, cross_filesystems)?, )?; if statistics { writeln!(io::stderr(), "{stats:?}").ok(); } res } Some(Completions { shell }) => { let mut cmd = options::Args::command(); let dua = cmd.get_name().to_string(); clap_complete::generate(shell, &mut cmd, dua, &mut io::stdout()); return Ok(()); } Some(Config { command: options::ConfigCommand::Edit, }) => { edit_config()?; return Ok(()); } None => { let stdout = io::stdout(); let stdout_locked = stdout.lock(); dua::aggregate( stdout_locked, stderr_if_tty(), walk_options, true, true, byte_format, extract_paths_maybe_set_cwd(opt.input, cross_filesystems)?, )? .0 } }; process::exit(res.to_exit_code()); } fn extract_paths_maybe_set_cwd( mut paths: Vec, cross_filesystems: bool, ) -> Result, io::Error> { if paths.len() == 1 && paths[0].is_dir() { std::env::set_current_dir(&paths[0])?; paths.clear(); } let device_id = std::env::current_dir() .ok() .and_then(|cwd| crossdev::init(&cwd).ok()); if paths.is_empty() { cwd_dirlist().map(|paths| match device_id { Some(device_id) if !cross_filesystems => paths .into_iter() .filter(|p| match p.metadata() { Ok(meta) => crossdev::is_same_device(device_id, &meta), Err(_) => true, }) .collect(), _ => paths, }) } else { Ok(paths) } } fn cwd_dirlist() -> Result, io::Error> { let mut v: Vec<_> = fs::read_dir(".")? .filter_map(|e| { e.ok() .and_then(|e| e.path().strip_prefix(".").ok().map(ToOwned::to_owned)) }) .filter(|p| { if let Ok(meta) = p.symlink_metadata() && meta.file_type().is_symlink() { return false; }; true }) .collect(); v.sort(); Ok(v) } fn edit_config() -> Result<()> { let path = dua::Config::path()?; ensure_default_config_file(&path)?; let editor = std::env::var("EDITOR").map_err(|_| { anyhow!( "$EDITOR is not set or is illformed UTF8. Created default configuration at {}", path.display() ) })?; let Some(mut editor_parts) = shlex::split(&editor) else { return Err(anyhow!( "$EDITOR has invalid shell quoting. Created default configuration at {}", path.display() )); }; if editor_parts.is_empty() { bail!( "$EDITOR is empty. Created default configuration at {}", path.display() ) }; let editor_program = editor_parts.remove(0); let status = std::process::Command::new(&editor_program) .args(editor_parts) .arg(&path) .status() .with_context(|| { format!( "Failed to launch editor {editor_program:?} (from $EDITOR={editor:?}) for {}", path.display() ) })?; if status.success() { println!("Successfully edited '{}'", path.display()); return Ok(()); } Err(anyhow!( "Editor {editor_program:?} (from $EDITOR={editor:?}) exited with status {status} while editing {}", path.display() )) } fn ensure_default_config_file(path: &Path) -> Result<()> { if let Some(parent_dir) = path.parent() { fs::create_dir_all(parent_dir).with_context(|| { format!( "Could not create configuration directory {}", parent_dir.display() ) })?; } if !path.exists() { fs::write(path, dua::Config::default_file_content()).with_context(|| { format!( "Could not write default configuration to {}", path.display() ) })?; } Ok(()) } dua-cli-2.34.0/src/options.rs000064400000000000000000000114601046102023000140620ustar 00000000000000use clap_complete::Shell; use dua::ByteFormat as LibraryByteFormat; use std::path::PathBuf; #[derive(PartialEq, Eq, Debug, Clone, Copy, clap::ValueEnum)] pub enum ByteFormat { Metric, Binary, Bytes, GB, Gib, MB, Mib, } impl From for LibraryByteFormat { fn from(input: ByteFormat) -> Self { match input { ByteFormat::Metric => LibraryByteFormat::Metric, ByteFormat::Binary => LibraryByteFormat::Binary, ByteFormat::Bytes => LibraryByteFormat::Bytes, ByteFormat::GB => LibraryByteFormat::GB, ByteFormat::Gib => LibraryByteFormat::GiB, ByteFormat::MB => LibraryByteFormat::MB, ByteFormat::Mib => LibraryByteFormat::MiB, } } } fn dft_format() -> ByteFormat { if cfg!(target_vendor = "apple") { ByteFormat::Metric } else { ByteFormat::Binary } } /// For some reason, on MacOS, too many threads are bad and 3 is the best these days on M4. /// On M1 it was more like 4, but close enough. #[cfg(target_os = "macos")] const DEFAULT_THREADS: usize = 3; #[cfg(not(target_os = "macos"))] const DEFAULT_THREADS: usize = 0; /// A tool to learn about disk usage, fast! #[derive(Debug, clap::Parser)] #[clap(name = "dua", version)] #[clap(override_usage = "dua [FLAGS] [OPTIONS] [SUBCOMMAND] [INPUT]...")] pub struct Args { #[clap(subcommand)] pub command: Option, /// The amount of threads to use. Defaults to 0, indicating the amount of logical processors. /// Set to 1 to use only a single thread. #[clap(short = 't', long = "threads", default_value_t = DEFAULT_THREADS, global = true, env = "DUA_THREADS")] pub threads: usize, /// The format with which to print byte counts. #[clap( short = 'f', long, value_enum, default_value_t = dft_format(), ignore_case = true, global = true, env = "DUA_FORMAT", )] pub format: ByteFormat, /// Display apparent size instead of disk usage. #[clap(short = 'A', long, global = true, env = "DUA_APPARENT_SIZE")] pub apparent_size: bool, /// Count hard-linked files each time they are seen #[clap(short = 'l', long, global = true, env = "DUA_COUNT_HARD_LINKS")] pub count_hard_links: bool, /// If set, we will not cross filesystems or traverse mount points #[clap(short = 'x', long, global = true, env = "DUA_STAY_ON_FILESYSTEM")] pub stay_on_filesystem: bool, /// One or more absolute directories to ignore. Note that these are not ignored if they are passed as input path. /// /// Hence, they will only be ignored if they are eventually reached as part of the traversal. #[clap( long = "ignore-dirs", short = 'i', value_parser, global = true, env = "DUA_IGNORE_DIRS" )] #[cfg_attr(target_os = "linux", clap(default_values = &["/proc", "/dev", "/sys", "/run"]))] pub ignore_dirs: Vec, /// One or more input files or directories. If unset, we will use all entries in the current working directory. #[clap(value_parser, global = true)] pub input: Vec, /// Write a log file with debug information, including panics. #[clap(long, global = true, env = "DUA_LOG_FILE")] pub log_file: Option, } #[derive(Debug, clap::Subcommand)] pub enum Command { /// Launch the terminal user interface #[cfg(feature = "tui-crossplatform")] #[clap(name = "interactive", visible_alias = "i")] Interactive { /// Do not check entries for presence when listing a directory to avoid slugging performance on slow filesystems. #[clap(long, short = 'e')] no_entry_check: bool, }, /// Aggregate the consumed space of one or more directories or files #[clap(name = "aggregate", visible_alias = "a")] Aggregate { /// If set, print additional statistics about the file traversal to stderr #[clap(long = "stats")] statistics: bool, /// If set, paths will be printed in their order of occurrence on the command-line. /// Otherwise they are sorted by their size in bytes, ascending. #[clap(long)] no_sort: bool, /// If set, no total column will be computed for multiple inputs #[clap(long)] no_total: bool, }, /// Generate shell completions Completions { /// The shell to generate a completions-script for shell: Shell, }, /// Configuration related commands Config { /// Operation to perform on configuration. #[clap(subcommand)] command: ConfigCommand, }, } #[derive(Debug, clap::Subcommand)] pub enum ConfigCommand { /// Open the configuration file in `$EDITOR`. /// /// If the file does not exist, it will be created with default values first. Edit, } dua-cli-2.34.0/src/traverse.rs000064400000000000000000000476241046102023000142350ustar 00000000000000use crate::{Throttle, WalkOptions, crossdev, get_size_or_panic, inodefilter::InodeFilter}; use crossbeam::channel::Receiver; use filesize::PathExt; use petgraph::{Directed, Direction, graph::NodeIndex, stable_graph::StableGraph}; use std::time::Instant; use std::{ fmt, fs::Metadata, io, path::{Path, PathBuf}, sync::Arc, time::{Duration, SystemTime, UNIX_EPOCH}, }; /// Node index type used by the traversal tree graph. pub type TreeIndex = NodeIndex; /// Graph type used to represent traversed filesystem entries. pub type Tree = StableGraph; /// Data stored for each filesystem entry in the traversal tree. #[derive(Eq, PartialEq, Clone)] pub struct EntryData { /// The entry name relative to its parent. pub name: PathBuf, /// The entry's size in bytes. If it's a directory, the size is the aggregated file size of all children /// plus the size of the directory entry itself pub size: u128, /// Last modification time if available. pub mtime: SystemTime, /// Recursive entry count for directories, or `None` for files. pub entry_count: Option, /// If set, the item meta-data could not be obtained pub metadata_io_error: bool, /// `true` if the entry is a directory. pub is_dir: bool, } impl Default for EntryData { fn default() -> EntryData { EntryData { name: PathBuf::default(), size: u128::default(), mtime: UNIX_EPOCH, entry_count: None, metadata_io_error: bool::default(), is_dir: false, } } } impl fmt::Debug for EntryData { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("EntryData") .field("name", &self.name) .field("size", &self.size) .field("entry_count", &self.entry_count) // Skip mtime .field("metadata_io_error", &self.metadata_io_error) .finish() } } /// The result of the previous filesystem traversal #[derive(Debug)] pub struct Traversal { /// A tree representing the entire filestem traversal pub tree: Tree, /// The top-level node of the tree. pub root_index: TreeIndex, /// The time at which the instance was created, typically the start of the traversal. pub start_time: Instant, /// The time it cost to compute the traversal, when done. pub cost: Option, } impl Default for Traversal { fn default() -> Self { Self::new() } } impl Traversal { /// Create a new empty traversal with a synthetic root node. pub fn new() -> Self { let mut tree = Tree::new(); let root_index = tree.add_node(EntryData::default()); Self { tree, root_index, start_time: Instant::now(), cost: None, } } /// Recompute the recursive size of `node_index` from its direct children. pub(crate) fn recompute_node_size(&self, node_index: TreeIndex) -> u128 { self.tree .neighbors_directed(node_index, Direction::Outgoing) .map(|idx| get_size_or_panic(&self.tree, idx)) .sum() } /// Return `true` if this traversal is considered expensive to recompute. pub fn is_costly(&self) -> bool { self.cost.is_none_or(|d| d.as_secs_f32() > 10.0) } } /// Runtime statistics gathered while traversal is running. #[derive(Clone, Copy)] pub struct TraversalStats { /// Amount of files or directories we have seen during the filesystem traversal pub entries_traversed: u64, /// The time at which the traversal started. pub start: std::time::Instant, /// The amount of time it took to finish the traversal. Set only once done. pub elapsed: Option, /// Total amount of IO errors encountered when traversing the filesystem pub io_errors: u64, /// Total amount of bytes seen during the traversal pub total_bytes: Option, } impl Default for TraversalStats { fn default() -> Self { Self { entries_traversed: 0, start: std::time::Instant::now(), elapsed: None, io_errors: 0, total_bytes: None, } } } /// Accumulator used while rolling up directory information. #[derive(Default, Copy, Clone)] struct EntryInfo { /// Accumulated size in bytes. size: u128, /// Accumulated entry count if known. entries_count: Option, } impl EntryInfo { /// Add `other`'s `entries_count` into `self`, preserving `None` semantics. fn add_count(&mut self, other: &Self) { self.entries_count = match (self.entries_count, other.entries_count) { (Some(a), Some(b)) => Some(a + b), (None, Some(b)) => Some(b), (Some(a), None) => Some(a), (None, None) => None, }; } } /// Update `node_idx` with aggregated directory information. /// /// `node_own_size` is added on top of `EntryInfo::size`. fn set_entry_info_or_panic( tree: &mut Tree, node_idx: TreeIndex, node_own_size: u128, EntryInfo { size, entries_count, }: EntryInfo, ) { let node = tree .node_weight_mut(node_idx) .expect("node for parent index we just retrieved"); node.size = size + node_own_size; node.entry_count = entries_count.map(|n| n + 1); } /// Return the parent of `parent_node_idx` or panic if none exists. fn parent_or_panic(tree: &mut Tree, parent_node_idx: TreeIndex) -> TreeIndex { tree.neighbors_directed(parent_node_idx, Direction::Incoming) .next() .expect("every node in the iteration has a parent") } /// Pop one element from `v` or panic if `v` is empty. fn pop_or_panic(v: &mut Vec) -> T { v.pop().expect("sizes per level to be in sync with graph") } /// A single result emitted by the jwalk iterator. type TraversalEntry = Result>)>, jwalk::Error>; #[allow(clippy::large_enum_variant)] /// Events emitted by a background filesystem traversal. pub enum TraversalEvent { /// A discovered entry and its traversal context. Entry(TraversalEntry, Arc, u64), /// Traversal completed with additional I/O error count. Finished(u64), } /// An in-progress traversal which exposes newly obtained entries pub struct BackgroundTraversal { walk_options: WalkOptions, /// Tree node index that acts as root for this traversal integration. pub root_idx: TreeIndex, /// Running traversal statistics. pub stats: TraversalStats, previous_node_idx: TreeIndex, parent_node_idx: TreeIndex, directory_info_per_depth_level: Vec, current_directory_at_depth: EntryInfo, parent_node_size: u128, parent_node_size_per_depth_level: Vec, previous_node_size: u128, previous_depth: usize, inodes: InodeFilter, throttle: Option, skip_root: bool, use_root_path: bool, /// Receiver used to obtain traversal events from the worker thread. pub event_rx: Receiver, } impl BackgroundTraversal { /// Start a background thread to perform the actual tree walk, and dispatch the results /// as events to be received on [BackgroundTraversal::event_rx]. pub fn start( root_idx: TreeIndex, walk_options: &WalkOptions, input: Vec, skip_root: bool, use_root_path: bool, ) -> anyhow::Result { let (entry_tx, entry_rx) = crossbeam::channel::bounded(100); std::thread::Builder::new() .name("dua-fs-walk-dispatcher".to_string()) .spawn({ let walk_options = walk_options.clone(); let mut io_errors: u64 = 0; move || { for root_path in input.into_iter() { log::info!("Walking {root_path:?}"); let device_id = match crossdev::init(root_path.as_ref()) { Ok(id) => id, Err(_) => { io_errors += 1; continue; } }; let root_path = Arc::new(root_path); for entry in walk_options .iter_from_path(root_path.as_ref(), device_id, skip_root) .into_iter() { if entry_tx .send(TraversalEvent::Entry( entry, Arc::clone(&root_path), device_id, )) .is_err() { // The channel is closed, this means the user has // requested to quit the app. Abort the walking. return; } } } if entry_tx.send(TraversalEvent::Finished(io_errors)).is_err() { log::error!("Failed to send TraversalEvents::Finished event"); } } })?; Ok(Self { walk_options: walk_options.clone(), root_idx, stats: TraversalStats::default(), previous_node_idx: root_idx, parent_node_idx: root_idx, previous_node_size: 0, parent_node_size: 0, parent_node_size_per_depth_level: Vec::new(), directory_info_per_depth_level: Vec::new(), current_directory_at_depth: EntryInfo::default(), previous_depth: 0, inodes: InodeFilter::default(), throttle: Some(Throttle::new(Duration::from_millis(250), None)), skip_root, use_root_path, event_rx: entry_rx, }) } /// Integrate `event` into traversal `t` so its information is represented by it. /// This builds the traversal tree from a directory-walk. /// /// Returns /// * `Some(true)` if the traversal is finished /// * `Some(false)` if the caller may update its state after throttling kicked in /// * `None` - the event was written into the traversal, but there is nothing else to do pub fn integrate_traversal_event( &mut self, traversal: &mut Traversal, event: TraversalEvent, ) -> Option { match event { TraversalEvent::Entry(entry, root_path, device_id) => { self.stats.entries_traversed += 1; let mut data = EntryData::default(); match entry { Ok(mut entry) => { if self.skip_root { entry.depth -= 1; data.name = entry.file_name.into() } else { data.name = if entry.depth < 1 && self.use_root_path { (*root_path).clone() } else { entry.file_name.into() } } let mut file_size = 0u128; let mut mtime: SystemTime = UNIX_EPOCH; let mut file_count = 0u64; match &entry.client_state { Some(Ok(m)) => { if self.walk_options.count_hard_links || self.inodes.add(m) && (self.walk_options.cross_filesystems || crossdev::is_same_device(device_id, m)) { file_count = 1; if self.walk_options.apparent_size { file_size = m.len() as u128; } else { file_size = size_on_disk(&entry.parent_path, &data.name, m) .unwrap_or_else(|_| { self.stats.io_errors += 1; data.metadata_io_error = true; 0 }) as u128; } } else { data.entry_count = Some(0); data.is_dir = true; } match m.modified() { Ok(modified) => { mtime = modified; } Err(_) => { self.stats.io_errors += 1; data.metadata_io_error = true; } } } Some(Err(_)) => { self.stats.io_errors += 1; data.metadata_io_error = true; } None => {} } match (entry.depth, self.previous_depth) { (n, p) if n > p => { self.directory_info_per_depth_level .push(self.current_directory_at_depth); self.current_directory_at_depth = EntryInfo { size: file_size, entries_count: Some(file_count), }; self.parent_node_size_per_depth_level .push(self.previous_node_size); self.parent_node_idx = self.previous_node_idx; self.parent_node_size = self.previous_node_size; } (n, p) if n < p => { for _ in n..p { set_entry_info_or_panic( &mut traversal.tree, self.parent_node_idx, self.parent_node_size, self.current_directory_at_depth, ); let dir_info = pop_or_panic(&mut self.directory_info_per_depth_level); self.current_directory_at_depth.size += dir_info.size; self.current_directory_at_depth.add_count(&dir_info); self.parent_node_idx = parent_or_panic(&mut traversal.tree, self.parent_node_idx); self.parent_node_size = pop_or_panic(&mut self.parent_node_size_per_depth_level); } self.current_directory_at_depth.size += file_size; *self .current_directory_at_depth .entries_count .get_or_insert(0) += file_count; set_entry_info_or_panic( &mut traversal.tree, self.parent_node_idx, self.parent_node_size, self.current_directory_at_depth, ); } _ => { self.current_directory_at_depth.size += file_size; *self .current_directory_at_depth .entries_count .get_or_insert(0) += file_count; } }; data.mtime = mtime; data.size = file_size; let entry_index = traversal.tree.add_node(data); traversal .tree .add_edge(self.parent_node_idx, entry_index, ()); self.previous_node_idx = entry_index; self.previous_node_size = file_size; self.previous_depth = entry.depth; } Err(_) => { if self.previous_depth == 0 { data.name.clone_from(&(*root_path)); let entry_index = traversal.tree.add_node(data); traversal .tree .add_edge(self.parent_node_idx, entry_index, ()); } self.stats.io_errors += 1 } } if self.throttle.as_ref().is_some_and(|t| t.can_update()) { return Some(false); } } TraversalEvent::Finished(io_errors) => { self.stats.io_errors += io_errors; self.throttle = None; self.directory_info_per_depth_level .push(self.current_directory_at_depth); self.current_directory_at_depth = EntryInfo::default(); for _ in 0..self.previous_depth { let dir_info = pop_or_panic(&mut self.directory_info_per_depth_level); self.current_directory_at_depth.size += dir_info.size; self.current_directory_at_depth.add_count(&dir_info); set_entry_info_or_panic( &mut traversal.tree, self.parent_node_idx, self.parent_node_size, self.current_directory_at_depth, ); self.parent_node_idx = parent_or_panic(&mut traversal.tree, self.parent_node_idx); } let root_size = traversal.recompute_node_size(self.root_idx); set_entry_info_or_panic( &mut traversal.tree, self.root_idx, root_size, EntryInfo { size: root_size, entries_count: (self.stats.entries_traversed > 0) .then_some(self.stats.entries_traversed), }, ); self.stats.total_bytes = Some(root_size); self.stats.elapsed = Some(self.stats.start.elapsed()); return Some(true); } } None } } #[cfg(not(windows))] /// Return disk usage for `name` on Unix-like platforms. fn size_on_disk(_parent: &Path, name: &Path, meta: &Metadata) -> io::Result { name.size_on_disk_fast(meta) } #[cfg(windows)] /// Return disk usage for `name` on Windows platforms. fn size_on_disk(parent: &Path, name: &Path, meta: &Metadata) -> io::Result { parent.join(name).size_on_disk_fast(meta) } #[cfg(test)] mod tests { use super::*; #[test] fn size_of_entry_data() { assert!( std::mem::size_of::() <= 80, "the size of this ({}) should not exceed 80 as it affects overall memory consumption", std::mem::size_of::() ); } }