chore(cli): Migrate to Derive API

Change the definition of CLI from the Builder API to the Derive API.
This commit is contained in:
Shun Sakai
2025-05-15 21:11:41 +09:00
committed by andy.boot
parent 6a14d7e8b3
commit 702f0f0fe9
12 changed files with 514 additions and 538 deletions

19
Cargo.lock generated
View File

@@ -178,6 +178,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive",
] ]
[[package]] [[package]]
@@ -201,6 +202,18 @@ dependencies = [
"clap", "clap",
] ]
[[package]]
name = "clap_derive"
version = "4.5.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "clap_lex" name = "clap_lex"
version = "0.7.4" version = "0.7.4"
@@ -390,6 +403,12 @@ dependencies = [
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.3.9" version = "0.3.9"

View File

@@ -28,7 +28,7 @@ strip = true
[dependencies] [dependencies]
ansi_term = "0.12" ansi_term = "0.12"
clap = "4.4" clap = { version = "4.4", features = ["derive"] }
lscolors = "0.13" lscolors = "0.13"
terminal_size = "0.2" terminal_size = "0.2"
unicode-width = "0.1" unicode-width = "0.1"
@@ -56,7 +56,7 @@ assert_cmd = "2"
tempfile = "=3" tempfile = "=3"
[build-dependencies] [build-dependencies]
clap = "4.4" clap = { version = "4.4", features = ["derive"] }
clap_complete = "4.4" clap_complete = "4.4"
clap_mangen = "0.2" clap_mangen = "0.2"

View File

@@ -1,3 +1,4 @@
use clap::CommandFactory;
use clap_complete::{generate_to, shells::*}; use clap_complete::{generate_to, shells::*};
use clap_mangen::Man; use clap_mangen::Man;
use std::fs::File; use std::fs::File;
@@ -9,7 +10,7 @@ include!("src/cli.rs");
fn main() -> Result<(), Error> { fn main() -> Result<(), Error> {
let outdir = "completions"; let outdir = "completions";
let app_name = "dust"; let app_name = "dust";
let mut cmd = build_cli(); let mut cmd = Cli::command();
generate_to(Bash, &mut cmd, app_name, outdir)?; generate_to(Bash, &mut cmd, app_name, outdir)?;
generate_to(Zsh, &mut cmd, app_name, outdir)?; generate_to(Zsh, &mut cmd, app_name, outdir)?;

View File

@@ -17,8 +17,8 @@ _dust() {
_arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \
'-d+[Depth to show]:DEPTH:_default' \ '-d+[Depth to show]:DEPTH:_default' \
'--depth=[Depth to show]:DEPTH:_default' \ '--depth=[Depth to show]:DEPTH:_default' \
'-T+[Number of threads to use]: :_default' \ '-T+[Number of threads to use]:THREADS:_default' \
'--threads=[Number of threads to use]: :_default' \ '--threads=[Number of threads to use]:THREADS:_default' \
'--config=[Specify a config file to use]:FILE:_files' \ '--config=[Specify a config file to use]:FILE:_files' \
'-n+[Number of lines of output to show. (Default is terminal_height - 10)]:NUMBER:_default' \ '-n+[Number of lines of output to show. (Default is terminal_height - 10)]:NUMBER:_default' \
'--number-of-lines=[Number of lines of output to show. (Default is terminal_height - 10)]:NUMBER:_default' \ '--number-of-lines=[Number of lines of output to show. (Default is terminal_height - 10)]:NUMBER:_default' \
@@ -28,26 +28,48 @@ _dust() {
'--ignore-all-in-file=[Exclude any file or directory with a regex matching that listed in this file, the file entries will be added to the ignore regexs provided by --invert_filter]:FILE:_files' \ '--ignore-all-in-file=[Exclude any file or directory with a regex matching that listed in this file, the file entries will be added to the ignore regexs provided by --invert_filter]:FILE:_files' \
'-z+[Minimum size file to include in output]:MIN_SIZE:_default' \ '-z+[Minimum size file to include in output]:MIN_SIZE:_default' \
'--min-size=[Minimum size file to include in output]:MIN_SIZE:_default' \ '--min-size=[Minimum size file to include in output]:MIN_SIZE:_default' \
'(-e --filter -t --file-types)*-v+[Exclude filepaths matching this regex. To ignore png files type\: -v "\\.png\$" ]:REGEX:_default' \ '(-e --filter -t --file-types)*-v+[Exclude filepaths matching this regex. To ignore png files type\: -v "\\.png\$"]:REGEX:_default' \
'(-e --filter -t --file-types)*--invert-filter=[Exclude filepaths matching this regex. To ignore png files type\: -v "\\.png\$" ]:REGEX:_default' \ '(-e --filter -t --file-types)*--invert-filter=[Exclude filepaths matching this regex. To ignore png files type\: -v "\\.png\$"]:REGEX:_default' \
'(-t --file-types)*-e+[Only include filepaths matching this regex. For png files type\: -e "\\.png\$" ]:REGEX:_default' \ '(-t --file-types)*-e+[Only include filepaths matching this regex. For png files type\: -e "\\.png\$"]:REGEX:_default' \
'(-t --file-types)*--filter=[Only include filepaths matching this regex. For png files type\: -e "\\.png\$" ]:REGEX:_default' \ '(-t --file-types)*--filter=[Only include filepaths matching this regex. For png files type\: -e "\\.png\$"]:REGEX:_default' \
'-w+[Specify width of output overriding the auto detection of terminal width]:WIDTH:_default' \ '-w+[Specify width of output overriding the auto detection of terminal width]:WIDTH:_default' \
'--terminal-width=[Specify width of output overriding the auto detection of terminal width]:WIDTH:_default' \ '--terminal-width=[Specify width of output overriding the auto detection of terminal width]:WIDTH:_default' \
'-o+[Changes output display size. si will print sizes in powers of 1000. b k m g t kb mb gb tb will print the whole tree in that size.]:FORMAT:(si b k m g t kb mb gb tb)' \ '-o+[Changes output display size. si will print sizes in powers of 1000. b k m g t kb mb gb tb will print the whole tree in that size]:FORMAT:((si\:"SI prefix (powers of 1000)"
'--output-format=[Changes output display size. si will print sizes in powers of 1000. b k m g t kb mb gb tb will print the whole tree in that size.]:FORMAT:(si b k m g t kb mb gb tb)' \ b\:"byte (B)"
k\:"kibibyte (KiB)"
m\:"mebibyte (MiB)"
g\:"gibibyte (GiB)"
t\:"tebibyte (TiB)"
kb\:"kilobyte (kB)"
mb\:"megabyte (MB)"
gb\:"gigabyte (GB)"
tb\:"terabyte (TB)"))' \
'--output-format=[Changes output display size. si will print sizes in powers of 1000. b k m g t kb mb gb tb will print the whole tree in that size]:FORMAT:((si\:"SI prefix (powers of 1000)"
b\:"byte (B)"
k\:"kibibyte (KiB)"
m\:"mebibyte (MiB)"
g\:"gibibyte (GiB)"
t\:"tebibyte (TiB)"
kb\:"kilobyte (kB)"
mb\:"megabyte (MB)"
gb\:"gigabyte (GB)"
tb\:"terabyte (TB)"))' \
'-S+[Specify memory to use as stack size - use if you see\: '\''fatal runtime error\: stack overflow'\'' (default low memory=1048576, high memory=1073741824)]:STACK_SIZE:_default' \ '-S+[Specify memory to use as stack size - use if you see\: '\''fatal runtime error\: stack overflow'\'' (default low memory=1048576, high memory=1073741824)]:STACK_SIZE:_default' \
'--stack-size=[Specify memory to use as stack size - use if you see\: '\''fatal runtime error\: stack overflow'\'' (default low memory=1048576, high memory=1073741824)]:STACK_SIZE:_default' \ '--stack-size=[Specify memory to use as stack size - use if you see\: '\''fatal runtime error\: stack overflow'\'' (default low memory=1048576, high memory=1073741824)]:STACK_SIZE:_default' \
'-M+[+/-n matches files modified more/less than n days ago , and n matches files modified exactly n days ago, days are rounded down.That is +n => (−∞, curr(n+1)), n => \[curr(n+1), currn), and -n => (𝑐𝑢𝑟𝑟𝑛, +∞)]: :_default' \ '-M+[+/-n matches files modified more/less than n days ago , and n matches files modified exactly n days ago, days are rounded down.That is +n => (−∞, curr(n+1)), n => \[curr(n+1), currn), and -n => (𝑐𝑢𝑟𝑟𝑛, +∞)]:MTIME:_default' \
'--mtime=[+/-n matches files modified more/less than n days ago , and n matches files modified exactly n days ago, days are rounded down.That is +n => (−∞, curr(n+1)), n => \[curr(n+1), currn), and -n => (𝑐𝑢𝑟𝑟𝑛, +∞)]: :_default' \ '--mtime=[+/-n matches files modified more/less than n days ago , and n matches files modified exactly n days ago, days are rounded down.That is +n => (−∞, curr(n+1)), n => \[curr(n+1), currn), and -n => (𝑐𝑢𝑟𝑟𝑛, +∞)]:MTIME:_default' \
'-A+[just like -mtime, but based on file access time]: :_default' \ '-A+[just like -mtime, but based on file access time]:ATIME:_default' \
'--atime=[just like -mtime, but based on file access time]: :_default' \ '--atime=[just like -mtime, but based on file access time]:ATIME:_default' \
'-y+[just like -mtime, but based on file change time]: :_default' \ '-y+[just like -mtime, but based on file change time]:CTIME:_default' \
'--ctime=[just like -mtime, but based on file change time]: :_default' \ '--ctime=[just like -mtime, but based on file change time]:CTIME:_default' \
'--files0-from=[run dust on NUL-terminated file names specified in file; if argument is -, then read names from standard input]: :_files' \ '--files0-from=[run dust on NUL-terminated file names specified in file; if argument is -, then read names from standard input]:FILES0_FROM:_files' \
'*--collapse=[Keep these directories collapsed]: :_files' \ '*--collapse=[Keep these directories collapsed]:COLLAPSE:_files' \
'-m+[Directory '\''size'\'' is max filetime of child files instead of disk size. while a/c/m for last accessed/changed/modified time]: :(a c m)' \ '-m+[Directory '\''size'\'' is max filetime of child files instead of disk size. while a/c/m for last accessed/changed/modified time]:FILETIME:((a\:"last accessed time"
'--filetime=[Directory '\''size'\'' is max filetime of child files instead of disk size. while a/c/m for last accessed/changed/modified time]: :(a c m)' \ c\:"last changed time"
m\:"last modified time"))' \
'--filetime=[Directory '\''size'\'' is max filetime of child files instead of disk size. while a/c/m for last accessed/changed/modified time]:FILETIME:((a\:"last accessed time"
c\:"last changed time"
m\:"last modified time"))' \
'-p[Subdirectories will not have their path shortened]' \ '-p[Subdirectories will not have their path shortened]' \
'--full-paths[Subdirectories will not have their path shortened]' \ '--full-paths[Subdirectories will not have their path shortened]' \
'-L[dereference sym links - Treat sym links as directories and go into them]' \ '-L[dereference sym links - Treat sym links as directories and go into them]' \
@@ -75,20 +97,20 @@ _dust() {
'--ignore-hidden[Do not display hidden files]' \ '--ignore-hidden[Do not display hidden files]' \
'(-d --depth -D --only-dir)-t[show only these file types]' \ '(-d --depth -D --only-dir)-t[show only these file types]' \
'(-d --depth -D --only-dir)--file-types[show only these file types]' \ '(-d --depth -D --only-dir)--file-types[show only these file types]' \
'-P[Disable the progress indication.]' \ '-P[Disable the progress indication]' \
'--no-progress[Disable the progress indication.]' \ '--no-progress[Disable the progress indication]' \
'--print-errors[Print path with errors.]' \ '--print-errors[Print path with errors]' \
'(-F --only-file -t --file-types)-D[Only directories will be displayed.]' \ '(-F --only-file -t --file-types)-D[Only directories will be displayed]' \
'(-F --only-file -t --file-types)--only-dir[Only directories will be displayed.]' \ '(-F --only-file -t --file-types)--only-dir[Only directories will be displayed]' \
'(-D --only-dir)-F[Only files will be displayed. (Finds your largest files)]' \ '(-D --only-dir)-F[Only files will be displayed. (Finds your largest files)]' \
'(-D --only-dir)--only-file[Only files will be displayed. (Finds your largest files)]' \ '(-D --only-dir)--only-file[Only files will be displayed. (Finds your largest files)]' \
'-j[Output the directory tree as json to the current directory]' \ '-j[Output the directory tree as json to the current directory]' \
'--output-json[Output the directory tree as json to the current directory]' \ '--output-json[Output the directory tree as json to the current directory]' \
'-h[Print help]' \ '-h[Print help (see more with '\''--help'\'')]' \
'--help[Print help]' \ '--help[Print help (see more with '\''--help'\'')]' \
'-V[Print version]' \ '-V[Print version]' \
'--version[Print version]' \ '--version[Print version]' \
'*::params:_files' \ '*::params -- Input files or directories:_files' \
&& ret=0 && ret=0
} }

View File

@@ -34,14 +34,14 @@ Register-ArgumentCompleter -Native -CommandName 'dust' -ScriptBlock {
[CompletionResult]::new('--ignore-all-in-file', '--ignore-all-in-file', [CompletionResultType]::ParameterName, 'Exclude any file or directory with a regex matching that listed in this file, the file entries will be added to the ignore regexs provided by --invert_filter') [CompletionResult]::new('--ignore-all-in-file', '--ignore-all-in-file', [CompletionResultType]::ParameterName, 'Exclude any file or directory with a regex matching that listed in this file, the file entries will be added to the ignore regexs provided by --invert_filter')
[CompletionResult]::new('-z', '-z', [CompletionResultType]::ParameterName, 'Minimum size file to include in output') [CompletionResult]::new('-z', '-z', [CompletionResultType]::ParameterName, 'Minimum size file to include in output')
[CompletionResult]::new('--min-size', '--min-size', [CompletionResultType]::ParameterName, 'Minimum size file to include in output') [CompletionResult]::new('--min-size', '--min-size', [CompletionResultType]::ParameterName, 'Minimum size file to include in output')
[CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'Exclude filepaths matching this regex. To ignore png files type: -v "\.png$" ') [CompletionResult]::new('-v', '-v', [CompletionResultType]::ParameterName, 'Exclude filepaths matching this regex. To ignore png files type: -v "\.png$"')
[CompletionResult]::new('--invert-filter', '--invert-filter', [CompletionResultType]::ParameterName, 'Exclude filepaths matching this regex. To ignore png files type: -v "\.png$" ') [CompletionResult]::new('--invert-filter', '--invert-filter', [CompletionResultType]::ParameterName, 'Exclude filepaths matching this regex. To ignore png files type: -v "\.png$"')
[CompletionResult]::new('-e', '-e', [CompletionResultType]::ParameterName, 'Only include filepaths matching this regex. For png files type: -e "\.png$" ') [CompletionResult]::new('-e', '-e', [CompletionResultType]::ParameterName, 'Only include filepaths matching this regex. For png files type: -e "\.png$"')
[CompletionResult]::new('--filter', '--filter', [CompletionResultType]::ParameterName, 'Only include filepaths matching this regex. For png files type: -e "\.png$" ') [CompletionResult]::new('--filter', '--filter', [CompletionResultType]::ParameterName, 'Only include filepaths matching this regex. For png files type: -e "\.png$"')
[CompletionResult]::new('-w', '-w', [CompletionResultType]::ParameterName, 'Specify width of output overriding the auto detection of terminal width') [CompletionResult]::new('-w', '-w', [CompletionResultType]::ParameterName, 'Specify width of output overriding the auto detection of terminal width')
[CompletionResult]::new('--terminal-width', '--terminal-width', [CompletionResultType]::ParameterName, 'Specify width of output overriding the auto detection of terminal width') [CompletionResult]::new('--terminal-width', '--terminal-width', [CompletionResultType]::ParameterName, 'Specify width of output overriding the auto detection of terminal width')
[CompletionResult]::new('-o', '-o', [CompletionResultType]::ParameterName, 'Changes output display size. si will print sizes in powers of 1000. b k m g t kb mb gb tb will print the whole tree in that size.') [CompletionResult]::new('-o', '-o', [CompletionResultType]::ParameterName, 'Changes output display size. si will print sizes in powers of 1000. b k m g t kb mb gb tb will print the whole tree in that size')
[CompletionResult]::new('--output-format', '--output-format', [CompletionResultType]::ParameterName, 'Changes output display size. si will print sizes in powers of 1000. b k m g t kb mb gb tb will print the whole tree in that size.') [CompletionResult]::new('--output-format', '--output-format', [CompletionResultType]::ParameterName, 'Changes output display size. si will print sizes in powers of 1000. b k m g t kb mb gb tb will print the whole tree in that size')
[CompletionResult]::new('-S', '-S ', [CompletionResultType]::ParameterName, 'Specify memory to use as stack size - use if you see: ''fatal runtime error: stack overflow'' (default low memory=1048576, high memory=1073741824)') [CompletionResult]::new('-S', '-S ', [CompletionResultType]::ParameterName, 'Specify memory to use as stack size - use if you see: ''fatal runtime error: stack overflow'' (default low memory=1048576, high memory=1073741824)')
[CompletionResult]::new('--stack-size', '--stack-size', [CompletionResultType]::ParameterName, 'Specify memory to use as stack size - use if you see: ''fatal runtime error: stack overflow'' (default low memory=1048576, high memory=1073741824)') [CompletionResult]::new('--stack-size', '--stack-size', [CompletionResultType]::ParameterName, 'Specify memory to use as stack size - use if you see: ''fatal runtime error: stack overflow'' (default low memory=1048576, high memory=1073741824)')
[CompletionResult]::new('-M', '-M ', [CompletionResultType]::ParameterName, '+/-n matches files modified more/less than n days ago , and n matches files modified exactly n days ago, days are rounded down.That is +n => (−∞, curr(n+1)), n => [curr(n+1), currn), and -n => (𝑐𝑢𝑟𝑟𝑛, +∞)') [CompletionResult]::new('-M', '-M ', [CompletionResultType]::ParameterName, '+/-n matches files modified more/less than n days ago , and n matches files modified exactly n days ago, days are rounded down.That is +n => (−∞, curr(n+1)), n => [curr(n+1), currn), and -n => (𝑐𝑢𝑟𝑟𝑛, +∞)')
@@ -81,17 +81,17 @@ Register-ArgumentCompleter -Native -CommandName 'dust' -ScriptBlock {
[CompletionResult]::new('--ignore-hidden', '--ignore-hidden', [CompletionResultType]::ParameterName, 'Do not display hidden files') [CompletionResult]::new('--ignore-hidden', '--ignore-hidden', [CompletionResultType]::ParameterName, 'Do not display hidden files')
[CompletionResult]::new('-t', '-t', [CompletionResultType]::ParameterName, 'show only these file types') [CompletionResult]::new('-t', '-t', [CompletionResultType]::ParameterName, 'show only these file types')
[CompletionResult]::new('--file-types', '--file-types', [CompletionResultType]::ParameterName, 'show only these file types') [CompletionResult]::new('--file-types', '--file-types', [CompletionResultType]::ParameterName, 'show only these file types')
[CompletionResult]::new('-P', '-P ', [CompletionResultType]::ParameterName, 'Disable the progress indication.') [CompletionResult]::new('-P', '-P ', [CompletionResultType]::ParameterName, 'Disable the progress indication')
[CompletionResult]::new('--no-progress', '--no-progress', [CompletionResultType]::ParameterName, 'Disable the progress indication.') [CompletionResult]::new('--no-progress', '--no-progress', [CompletionResultType]::ParameterName, 'Disable the progress indication')
[CompletionResult]::new('--print-errors', '--print-errors', [CompletionResultType]::ParameterName, 'Print path with errors.') [CompletionResult]::new('--print-errors', '--print-errors', [CompletionResultType]::ParameterName, 'Print path with errors')
[CompletionResult]::new('-D', '-D ', [CompletionResultType]::ParameterName, 'Only directories will be displayed.') [CompletionResult]::new('-D', '-D ', [CompletionResultType]::ParameterName, 'Only directories will be displayed')
[CompletionResult]::new('--only-dir', '--only-dir', [CompletionResultType]::ParameterName, 'Only directories will be displayed.') [CompletionResult]::new('--only-dir', '--only-dir', [CompletionResultType]::ParameterName, 'Only directories will be displayed')
[CompletionResult]::new('-F', '-F ', [CompletionResultType]::ParameterName, 'Only files will be displayed. (Finds your largest files)') [CompletionResult]::new('-F', '-F ', [CompletionResultType]::ParameterName, 'Only files will be displayed. (Finds your largest files)')
[CompletionResult]::new('--only-file', '--only-file', [CompletionResultType]::ParameterName, 'Only files will be displayed. (Finds your largest files)') [CompletionResult]::new('--only-file', '--only-file', [CompletionResultType]::ParameterName, 'Only files will be displayed. (Finds your largest files)')
[CompletionResult]::new('-j', '-j', [CompletionResultType]::ParameterName, 'Output the directory tree as json to the current directory') [CompletionResult]::new('-j', '-j', [CompletionResultType]::ParameterName, 'Output the directory tree as json to the current directory')
[CompletionResult]::new('--output-json', '--output-json', [CompletionResultType]::ParameterName, 'Output the directory tree as json to the current directory') [CompletionResult]::new('--output-json', '--output-json', [CompletionResultType]::ParameterName, 'Output the directory tree as json to the current directory')
[CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help') [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
[CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help') [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
[CompletionResult]::new('-V', '-V ', [CompletionResultType]::ParameterName, 'Print version') [CompletionResult]::new('-V', '-V ', [CompletionResultType]::ParameterName, 'Print version')
[CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version') [CompletionResult]::new('--version', '--version', [CompletionResultType]::ParameterName, 'Print version')
break break

View File

@@ -31,14 +31,14 @@ set edit:completion:arg-completer[dust] = {|@words|
cand --ignore-all-in-file 'Exclude any file or directory with a regex matching that listed in this file, the file entries will be added to the ignore regexs provided by --invert_filter' cand --ignore-all-in-file 'Exclude any file or directory with a regex matching that listed in this file, the file entries will be added to the ignore regexs provided by --invert_filter'
cand -z 'Minimum size file to include in output' cand -z 'Minimum size file to include in output'
cand --min-size 'Minimum size file to include in output' cand --min-size 'Minimum size file to include in output'
cand -v 'Exclude filepaths matching this regex. To ignore png files type: -v "\.png$" ' cand -v 'Exclude filepaths matching this regex. To ignore png files type: -v "\.png$"'
cand --invert-filter 'Exclude filepaths matching this regex. To ignore png files type: -v "\.png$" ' cand --invert-filter 'Exclude filepaths matching this regex. To ignore png files type: -v "\.png$"'
cand -e 'Only include filepaths matching this regex. For png files type: -e "\.png$" ' cand -e 'Only include filepaths matching this regex. For png files type: -e "\.png$"'
cand --filter 'Only include filepaths matching this regex. For png files type: -e "\.png$" ' cand --filter 'Only include filepaths matching this regex. For png files type: -e "\.png$"'
cand -w 'Specify width of output overriding the auto detection of terminal width' cand -w 'Specify width of output overriding the auto detection of terminal width'
cand --terminal-width 'Specify width of output overriding the auto detection of terminal width' cand --terminal-width 'Specify width of output overriding the auto detection of terminal width'
cand -o 'Changes output display size. si will print sizes in powers of 1000. b k m g t kb mb gb tb will print the whole tree in that size.' cand -o 'Changes output display size. si will print sizes in powers of 1000. b k m g t kb mb gb tb will print the whole tree in that size'
cand --output-format 'Changes output display size. si will print sizes in powers of 1000. b k m g t kb mb gb tb will print the whole tree in that size.' cand --output-format 'Changes output display size. si will print sizes in powers of 1000. b k m g t kb mb gb tb will print the whole tree in that size'
cand -S 'Specify memory to use as stack size - use if you see: ''fatal runtime error: stack overflow'' (default low memory=1048576, high memory=1073741824)' cand -S 'Specify memory to use as stack size - use if you see: ''fatal runtime error: stack overflow'' (default low memory=1048576, high memory=1073741824)'
cand --stack-size 'Specify memory to use as stack size - use if you see: ''fatal runtime error: stack overflow'' (default low memory=1048576, high memory=1073741824)' cand --stack-size 'Specify memory to use as stack size - use if you see: ''fatal runtime error: stack overflow'' (default low memory=1048576, high memory=1073741824)'
cand -M '+/-n matches files modified more/less than n days ago , and n matches files modified exactly n days ago, days are rounded down.That is +n => (−∞, curr(n+1)), n => [curr(n+1), currn), and -n => (𝑐𝑢𝑟𝑟𝑛, +∞)' cand -M '+/-n matches files modified more/less than n days ago , and n matches files modified exactly n days ago, days are rounded down.That is +n => (−∞, curr(n+1)), n => [curr(n+1), currn), and -n => (𝑐𝑢𝑟𝑟𝑛, +∞)'
@@ -78,17 +78,17 @@ set edit:completion:arg-completer[dust] = {|@words|
cand --ignore-hidden 'Do not display hidden files' cand --ignore-hidden 'Do not display hidden files'
cand -t 'show only these file types' cand -t 'show only these file types'
cand --file-types 'show only these file types' cand --file-types 'show only these file types'
cand -P 'Disable the progress indication.' cand -P 'Disable the progress indication'
cand --no-progress 'Disable the progress indication.' cand --no-progress 'Disable the progress indication'
cand --print-errors 'Print path with errors.' cand --print-errors 'Print path with errors'
cand -D 'Only directories will be displayed.' cand -D 'Only directories will be displayed'
cand --only-dir 'Only directories will be displayed.' cand --only-dir 'Only directories will be displayed'
cand -F 'Only files will be displayed. (Finds your largest files)' cand -F 'Only files will be displayed. (Finds your largest files)'
cand --only-file 'Only files will be displayed. (Finds your largest files)' cand --only-file 'Only files will be displayed. (Finds your largest files)'
cand -j 'Output the directory tree as json to the current directory' cand -j 'Output the directory tree as json to the current directory'
cand --output-json 'Output the directory tree as json to the current directory' cand --output-json 'Output the directory tree as json to the current directory'
cand -h 'Print help' cand -h 'Print help (see more with ''--help'')'
cand --help 'Print help' cand --help 'Print help (see more with ''--help'')'
cand -V 'Print version' cand -V 'Print version'
cand --version 'Print version' cand --version 'Print version'
} }

View File

@@ -5,28 +5,28 @@ complete -c dust -s n -l number-of-lines -d 'Number of lines of output to show.
complete -c dust -s X -l ignore-directory -d 'Exclude any file or directory with this path' -r -F complete -c dust -s X -l ignore-directory -d 'Exclude any file or directory with this path' -r -F
complete -c dust -s I -l ignore-all-in-file -d 'Exclude any file or directory with a regex matching that listed in this file, the file entries will be added to the ignore regexs provided by --invert_filter' -r -F complete -c dust -s I -l ignore-all-in-file -d 'Exclude any file or directory with a regex matching that listed in this file, the file entries will be added to the ignore regexs provided by --invert_filter' -r -F
complete -c dust -s z -l min-size -d 'Minimum size file to include in output' -r complete -c dust -s z -l min-size -d 'Minimum size file to include in output' -r
complete -c dust -s v -l invert-filter -d 'Exclude filepaths matching this regex. To ignore png files type: -v "\\.png$" ' -r complete -c dust -s v -l invert-filter -d 'Exclude filepaths matching this regex. To ignore png files type: -v "\\.png$"' -r
complete -c dust -s e -l filter -d 'Only include filepaths matching this regex. For png files type: -e "\\.png$" ' -r complete -c dust -s e -l filter -d 'Only include filepaths matching this regex. For png files type: -e "\\.png$"' -r
complete -c dust -s w -l terminal-width -d 'Specify width of output overriding the auto detection of terminal width' -r complete -c dust -s w -l terminal-width -d 'Specify width of output overriding the auto detection of terminal width' -r
complete -c dust -s o -l output-format -d 'Changes output display size. si will print sizes in powers of 1000. b k m g t kb mb gb tb will print the whole tree in that size.' -r -f -a "si\t'' complete -c dust -s o -l output-format -d 'Changes output display size. si will print sizes in powers of 1000. b k m g t kb mb gb tb will print the whole tree in that size' -r -f -a "si\t'SI prefix (powers of 1000)'
b\t'' b\t'byte (B)'
k\t'' k\t'kibibyte (KiB)'
m\t'' m\t'mebibyte (MiB)'
g\t'' g\t'gibibyte (GiB)'
t\t'' t\t'tebibyte (TiB)'
kb\t'' kb\t'kilobyte (kB)'
mb\t'' mb\t'megabyte (MB)'
gb\t'' gb\t'gigabyte (GB)'
tb\t''" tb\t'terabyte (TB)'"
complete -c dust -s S -l stack-size -d 'Specify memory to use as stack size - use if you see: \'fatal runtime error: stack overflow\' (default low memory=1048576, high memory=1073741824)' -r complete -c dust -s S -l stack-size -d 'Specify memory to use as stack size - use if you see: \'fatal runtime error: stack overflow\' (default low memory=1048576, high memory=1073741824)' -r
complete -c dust -s M -l mtime -d '+/-n matches files modified more/less than n days ago , and n matches files modified exactly n days ago, days are rounded down.That is +n => (−∞, curr(n+1)), n => [curr(n+1), currn), and -n => (𝑐𝑢𝑟𝑟𝑛, +∞)' -r complete -c dust -s M -l mtime -d '+/-n matches files modified more/less than n days ago , and n matches files modified exactly n days ago, days are rounded down.That is +n => (−∞, curr(n+1)), n => [curr(n+1), currn), and -n => (𝑐𝑢𝑟𝑟𝑛, +∞)' -r
complete -c dust -s A -l atime -d 'just like -mtime, but based on file access time' -r complete -c dust -s A -l atime -d 'just like -mtime, but based on file access time' -r
complete -c dust -s y -l ctime -d 'just like -mtime, but based on file change time' -r complete -c dust -s y -l ctime -d 'just like -mtime, but based on file change time' -r
complete -c dust -l files0-from -d 'run dust on NUL-terminated file names specified in file; if argument is -, then read names from standard input' -r -F complete -c dust -l files0-from -d 'run dust on NUL-terminated file names specified in file; if argument is -, then read names from standard input' -r -F
complete -c dust -l collapse -d 'Keep these directories collapsed' -r -F complete -c dust -l collapse -d 'Keep these directories collapsed' -r -F
complete -c dust -s m -l filetime -d 'Directory \'size\' is max filetime of child files instead of disk size. while a/c/m for last accessed/changed/modified time' -r -f -a "a\t'' complete -c dust -s m -l filetime -d 'Directory \'size\' is max filetime of child files instead of disk size. while a/c/m for last accessed/changed/modified time' -r -f -a "a\t'last accessed time'
c\t'' c\t'last changed time'
m\t''" m\t'last modified time'"
complete -c dust -s p -l full-paths -d 'Subdirectories will not have their path shortened' complete -c dust -s p -l full-paths -d 'Subdirectories will not have their path shortened'
complete -c dust -s L -l dereference-links -d 'dereference sym links - Treat sym links as directories and go into them' complete -c dust -s L -l dereference-links -d 'dereference sym links - Treat sym links as directories and go into them'
complete -c dust -s x -l limit-filesystem -d 'Only count the files and directories on the same filesystem as the supplied directory' complete -c dust -s x -l limit-filesystem -d 'Only count the files and directories on the same filesystem as the supplied directory'
@@ -41,10 +41,10 @@ complete -c dust -l skip-total -d 'No total row will be displayed'
complete -c dust -s f -l filecount -d 'Directory \'size\' is number of child files instead of disk size' complete -c dust -s f -l filecount -d 'Directory \'size\' is number of child files instead of disk size'
complete -c dust -s i -l ignore-hidden -d 'Do not display hidden files' complete -c dust -s i -l ignore-hidden -d 'Do not display hidden files'
complete -c dust -s t -l file-types -d 'show only these file types' complete -c dust -s t -l file-types -d 'show only these file types'
complete -c dust -s P -l no-progress -d 'Disable the progress indication.' complete -c dust -s P -l no-progress -d 'Disable the progress indication'
complete -c dust -l print-errors -d 'Print path with errors.' complete -c dust -l print-errors -d 'Print path with errors'
complete -c dust -s D -l only-dir -d 'Only directories will be displayed.' complete -c dust -s D -l only-dir -d 'Only directories will be displayed'
complete -c dust -s F -l only-file -d 'Only files will be displayed. (Finds your largest files)' complete -c dust -s F -l only-file -d 'Only files will be displayed. (Finds your largest files)'
complete -c dust -s j -l output-json -d 'Output the directory tree as json to the current directory' complete -c dust -s j -l output-json -d 'Output the directory tree as json to the current directory'
complete -c dust -s h -l help -d 'Print help' complete -c dust -s h -l help -d 'Print help (see more with \'--help\')'
complete -c dust -s V -l version -d 'Print version' complete -c dust -s V -l version -d 'Print version'

View File

@@ -12,7 +12,7 @@ Like du but more intuitive
\fB\-d\fR, \fB\-\-depth\fR=\fIDEPTH\fR \fB\-d\fR, \fB\-\-depth\fR=\fIDEPTH\fR
Depth to show Depth to show
.TP .TP
\fB\-T\fR, \fB\-\-threads\fR \fB\-T\fR, \fB\-\-threads\fR=\fITHREADS\fR
Number of threads to use Number of threads to use
.TP .TP
\fB\-\-config\fR=\fIFILE\fR \fB\-\-config\fR=\fIFILE\fR
@@ -70,10 +70,10 @@ Directory \*(Aqsize\*(Aq is number of child files instead of disk size
Do not display hidden files Do not display hidden files
.TP .TP
\fB\-v\fR, \fB\-\-invert\-filter\fR=\fIREGEX\fR \fB\-v\fR, \fB\-\-invert\-filter\fR=\fIREGEX\fR
Exclude filepaths matching this regex. To ignore png files type: \-v "\\.png$" Exclude filepaths matching this regex. To ignore png files type: \-v "\\.png$"
.TP .TP
\fB\-e\fR, \fB\-\-filter\fR=\fIREGEX\fR \fB\-e\fR, \fB\-\-filter\fR=\fIREGEX\fR
Only include filepaths matching this regex. For png files type: \-e "\\.png$" Only include filepaths matching this regex. For png files type: \-e "\\.png$"
.TP .TP
\fB\-t\fR, \fB\-\-file\-types\fR \fB\-t\fR, \fB\-\-file\-types\fR
show only these file types show only these file types
@@ -82,23 +82,45 @@ show only these file types
Specify width of output overriding the auto detection of terminal width Specify width of output overriding the auto detection of terminal width
.TP .TP
\fB\-P\fR, \fB\-\-no\-progress\fR \fB\-P\fR, \fB\-\-no\-progress\fR
Disable the progress indication. Disable the progress indication
.TP .TP
\fB\-\-print\-errors\fR \fB\-\-print\-errors\fR
Print path with errors. Print path with errors
.TP .TP
\fB\-D\fR, \fB\-\-only\-dir\fR \fB\-D\fR, \fB\-\-only\-dir\fR
Only directories will be displayed. Only directories will be displayed
.TP .TP
\fB\-F\fR, \fB\-\-only\-file\fR \fB\-F\fR, \fB\-\-only\-file\fR
Only files will be displayed. (Finds your largest files) Only files will be displayed. (Finds your largest files)
.TP .TP
\fB\-o\fR, \fB\-\-output\-format\fR=\fIFORMAT\fR \fB\-o\fR, \fB\-\-output\-format\fR=\fIFORMAT\fR
Changes output display size. si will print sizes in powers of 1000. b k m g t kb mb gb tb will print the whole tree in that size. Changes output display size. si will print sizes in powers of 1000. b k m g t kb mb gb tb will print the whole tree in that size
.br .br
.br .br
[\fIpossible values: \fRsi, b, k, m, g, t, kb, mb, gb, tb] \fIPossible values:\fR
.RS 14
.IP \(bu 2
si: SI prefix (powers of 1000)
.IP \(bu 2
b: byte (B)
.IP \(bu 2
k: kibibyte (KiB)
.IP \(bu 2
m: mebibyte (MiB)
.IP \(bu 2
g: gibibyte (GiB)
.IP \(bu 2
t: tebibyte (TiB)
.IP \(bu 2
kb: kilobyte (kB)
.IP \(bu 2
mb: megabyte (MB)
.IP \(bu 2
gb: gigabyte (GB)
.IP \(bu 2
tb: terabyte (TB)
.RE
.TP .TP
\fB\-S\fR, \fB\-\-stack\-size\fR=\fISTACK_SIZE\fR \fB\-S\fR, \fB\-\-stack\-size\fR=\fISTACK_SIZE\fR
Specify memory to use as stack size \- use if you see: \*(Aqfatal runtime error: stack overflow\*(Aq (default low memory=1048576, high memory=1073741824) Specify memory to use as stack size \- use if you see: \*(Aqfatal runtime error: stack overflow\*(Aq (default low memory=1048576, high memory=1073741824)
@@ -106,35 +128,43 @@ Specify memory to use as stack size \- use if you see: \*(Aqfatal runtime error:
\fB\-j\fR, \fB\-\-output\-json\fR \fB\-j\fR, \fB\-\-output\-json\fR
Output the directory tree as json to the current directory Output the directory tree as json to the current directory
.TP .TP
\fB\-M\fR, \fB\-\-mtime\fR \fB\-M\fR, \fB\-\-mtime\fR=\fIMTIME\fR
+/\-n matches files modified more/less than n days ago , and n matches files modified exactly n days ago, days are rounded down.That is +n => (−∞, curr(n+1)), n => [curr(n+1), currn), and \-n => (𝑐𝑢𝑟𝑟𝑛, +∞) +/\-n matches files modified more/less than n days ago , and n matches files modified exactly n days ago, days are rounded down.That is +n => (−∞, curr(n+1)), n => [curr(n+1), currn), and \-n => (𝑐𝑢𝑟𝑟𝑛, +∞)
.TP .TP
\fB\-A\fR, \fB\-\-atime\fR \fB\-A\fR, \fB\-\-atime\fR=\fIATIME\fR
just like \-mtime, but based on file access time just like \-mtime, but based on file access time
.TP .TP
\fB\-y\fR, \fB\-\-ctime\fR \fB\-y\fR, \fB\-\-ctime\fR=\fICTIME\fR
just like \-mtime, but based on file change time just like \-mtime, but based on file change time
.TP .TP
\fB\-\-files0\-from\fR \fB\-\-files0\-from\fR=\fIFILES0_FROM\fR
run dust on NUL\-terminated file names specified in file; if argument is \-, then read names from standard input run dust on NUL\-terminated file names specified in file; if argument is \-, then read names from standard input
.TP .TP
\fB\-\-collapse\fR \fB\-\-collapse\fR=\fICOLLAPSE\fR
Keep these directories collapsed Keep these directories collapsed
.TP .TP
\fB\-m\fR, \fB\-\-filetime\fR \fB\-m\fR, \fB\-\-filetime\fR=\fIFILETIME\fR
Directory \*(Aqsize\*(Aq is max filetime of child files instead of disk size. while a/c/m for last accessed/changed/modified time Directory \*(Aqsize\*(Aq is max filetime of child files instead of disk size. while a/c/m for last accessed/changed/modified time
.br .br
.br .br
[\fIpossible values: \fRa, c, m] \fIPossible values:\fR
.RS 14
.IP \(bu 2
a: last accessed time
.IP \(bu 2
c: last changed time
.IP \(bu 2
m: last modified time
.RE
.TP .TP
\fB\-h\fR, \fB\-\-help\fR \fB\-h\fR, \fB\-\-help\fR
Print help Print help (see a summary with \*(Aq\-h\*(Aq)
.TP .TP
\fB\-V\fR, \fB\-\-version\fR \fB\-V\fR, \fB\-\-version\fR
Print version Print version
.TP .TP
[\fIPATH\fR] [\fIPATH\fR]
Input files or directories
.SH VERSION .SH VERSION
v1.2.0 v1.2.0

View File

@@ -1,326 +1,258 @@
use clap::{Arg, Command, builder::PossibleValue, value_parser}; use std::fmt;
use clap::{Parser, ValueEnum, ValueHint};
// For single thread mode set this variable on your command line: // For single thread mode set this variable on your command line:
// export RAYON_NUM_THREADS=1 // export RAYON_NUM_THREADS=1
pub fn build_cli() -> Command { /// Like du but more intuitive
Command::new("Dust") #[derive(Debug, Parser)]
.about("Like du but more intuitive") #[command(name("Dust"), version)]
.version(env!("CARGO_PKG_VERSION")) pub struct Cli {
.arg( /// Depth to show
Arg::new("depth") #[arg(short, long)]
.short('d') pub depth: Option<usize>,
.long("depth")
.value_name("DEPTH") /// Number of threads to use
.value_parser(value_parser!(usize)) #[arg(short('T'), long)]
.help("Depth to show") pub threads: Option<usize>,
.num_args(1)
) /// Specify a config file to use
.arg( #[arg(long, value_name("FILE"), value_hint(ValueHint::FilePath))]
Arg::new("threads") pub config: Option<String>,
.short('T')
.long("threads") /// Number of lines of output to show. (Default is terminal_height - 10)
.value_parser(value_parser!(usize)) #[arg(short, long, value_name("NUMBER"))]
.help("Number of threads to use") pub number_of_lines: Option<usize>,
.num_args(1)
) /// Subdirectories will not have their path shortened
.arg( #[arg(short('p'), long)]
Arg::new("config") pub full_paths: bool,
.long("config")
.help("Specify a config file to use") /// Exclude any file or directory with this path
.value_name("FILE") #[arg(short('X'), long, value_name("PATH"), value_hint(ValueHint::AnyPath))]
.value_hint(clap::ValueHint::FilePath) pub ignore_directory: Option<Vec<String>>,
.value_parser(value_parser!(String))
.num_args(1) /// Exclude any file or directory with a regex matching that listed in this
) /// file, the file entries will be added to the ignore regexs provided by
.arg( /// --invert_filter
Arg::new("number_of_lines") #[arg(short('I'), long, value_name("FILE"), value_hint(ValueHint::FilePath))]
.short('n') pub ignore_all_in_file: Option<String>,
.long("number-of-lines")
.value_name("NUMBER") /// dereference sym links - Treat sym links as directories and go into them
.value_parser(value_parser!(usize)) #[arg(short('L'), long)]
.help("Number of lines of output to show. (Default is terminal_height - 10)") pub dereference_links: bool,
.num_args(1)
) /// Only count the files and directories on the same filesystem as the
.arg( /// supplied directory
Arg::new("display_full_paths") #[arg(short('x'), long)]
.short('p') pub limit_filesystem: bool,
.long("full-paths")
.action(clap::ArgAction::SetTrue) /// Use file length instead of blocks
.help("Subdirectories will not have their path shortened"), #[arg(short('s'), long)]
) pub apparent_size: bool,
.arg(
Arg::new("ignore_directory") /// Print tree upside down (biggest highest)
.short('X') #[arg(short, long)]
.long("ignore-directory") pub reverse: bool,
.value_name("PATH")
.value_hint(clap::ValueHint::AnyPath) /// No colors will be printed (Useful for commands like: watch)
.action(clap::ArgAction::Append) #[arg(short('c'), long)]
.help("Exclude any file or directory with this path"), pub no_colors: bool,
)
.arg( /// Force colors print
Arg::new("ignore_all_in_file") #[arg(short('C'), long)]
.short('I') pub force_colors: bool,
.long("ignore-all-in-file")
.value_name("FILE") /// No percent bars or percentages will be displayed
.value_hint(clap::ValueHint::FilePath) #[arg(short('b'), long)]
.value_parser(value_parser!(String)) pub no_percent_bars: bool,
.help("Exclude any file or directory with a regex matching that listed in this file, the file entries will be added to the ignore regexs provided by --invert_filter"),
) /// percent bars moved to right side of screen
.arg( #[arg(short('B'), long)]
Arg::new("dereference_links") pub bars_on_right: bool,
.short('L')
.long("dereference-links") /// Minimum size file to include in output
.action(clap::ArgAction::SetTrue) #[arg(short('z'), long)]
.help("dereference sym links - Treat sym links as directories and go into them"), pub min_size: Option<String>,
)
.arg( /// For screen readers. Removes bars. Adds new column: depth level (May want
Arg::new("limit_filesystem") /// to use -p too for full path)
.short('x') #[arg(short('R'), long)]
.long("limit-filesystem") pub screen_reader: bool,
.action(clap::ArgAction::SetTrue)
.help("Only count the files and directories on the same filesystem as the supplied directory"), /// No total row will be displayed
) #[arg(long)]
.arg( pub skip_total: bool,
Arg::new("display_apparent_size")
.short('s') /// Directory 'size' is number of child files instead of disk size
.long("apparent-size") #[arg(short, long)]
.action(clap::ArgAction::SetTrue) pub filecount: bool,
.help("Use file length instead of blocks"),
) /// Do not display hidden files
.arg( // Do not use 'h' this is used by 'help'
Arg::new("reverse") #[arg(short, long)]
.short('r') pub ignore_hidden: bool,
.long("reverse")
.action(clap::ArgAction::SetTrue) /// Exclude filepaths matching this regex. To ignore png files type: -v
.help("Print tree upside down (biggest highest)"), /// "\.png$"
) #[arg(
.arg( short('v'),
Arg::new("no_colors") long,
.short('c') value_name("REGEX"),
.long("no-colors") conflicts_with("filter"),
.action(clap::ArgAction::SetTrue) conflicts_with("file_types")
.help("No colors will be printed (Useful for commands like: watch)"), )]
) pub invert_filter: Option<Vec<String>>,
.arg(
Arg::new("force_colors") /// Only include filepaths matching this regex. For png files type: -e
.short('C') /// "\.png$"
.long("force-colors") #[arg(short('e'), long, value_name("REGEX"), conflicts_with("file_types"))]
.action(clap::ArgAction::SetTrue) pub filter: Option<Vec<String>>,
.help("Force colors print"),
) /// show only these file types
.arg( #[arg(short('t'), long, conflicts_with("depth"), conflicts_with("only_dir"))]
Arg::new("no_bars") pub file_types: bool,
.short('b')
.long("no-percent-bars") /// Specify width of output overriding the auto detection of terminal width
.action(clap::ArgAction::SetTrue) #[arg(short('w'), long, value_name("WIDTH"))]
.help("No percent bars or percentages will be displayed"), pub terminal_width: Option<usize>,
)
.arg( /// Disable the progress indication.
Arg::new("bars_on_right") #[arg(short('P'), long)]
.short('B') pub no_progress: bool,
.long("bars-on-right")
.action(clap::ArgAction::SetTrue) /// Print path with errors.
.help("percent bars moved to right side of screen"), #[arg(long)]
) pub print_errors: bool,
.arg(
Arg::new("min_size") /// Only directories will be displayed.
.short('z') #[arg(
.long("min-size") short('D'),
.value_name("MIN_SIZE") long,
.num_args(1) conflicts_with("only_file"),
.help("Minimum size file to include in output"), conflicts_with("file_types")
) )]
.arg( pub only_dir: bool,
Arg::new("screen_reader")
.short('R') /// Only files will be displayed. (Finds your largest files)
.long("screen-reader") #[arg(short('F'), long, conflicts_with("only_dir"))]
.action(clap::ArgAction::SetTrue) pub only_file: bool,
.help("For screen readers. Removes bars. Adds new column: depth level (May want to use -p too for full path)"),
) /// Changes output display size. si will print sizes in powers of 1000. b k
.arg( /// m g t kb mb gb tb will print the whole tree in that size.
Arg::new("skip_total") #[arg(short, long, value_enum, value_name("FORMAT"), ignore_case(true))]
.long("skip-total") pub output_format: Option<OutputFormat>,
.action(clap::ArgAction::SetTrue)
.help("No total row will be displayed"), /// Specify memory to use as stack size - use if you see: 'fatal runtime
) /// error: stack overflow' (default low memory=1048576, high
.arg( /// memory=1073741824)
Arg::new("by_filecount") #[arg(short('S'), long)]
.short('f') pub stack_size: Option<usize>,
.long("filecount")
.action(clap::ArgAction::SetTrue) /// Input files or directories.
.help("Directory 'size' is number of child files instead of disk size"), #[arg(value_name("PATH"), value_hint(ValueHint::AnyPath))]
) pub params: Option<Vec<String>>,
.arg(
Arg::new("ignore_hidden") /// Output the directory tree as json to the current directory
.short('i') // Do not use 'h' this is used by 'help' #[arg(short('j'), long)]
.long("ignore-hidden") pub output_json: bool,
.action(clap::ArgAction::SetTrue)
.help("Do not display hidden files"), /// +/-n matches files modified more/less than n days ago , and n matches
) /// files modified exactly n days ago, days are rounded down.That is +n =>
.arg( /// (−∞, curr(n+1)), n => [curr(n+1), currn), and -n => (𝑐𝑢𝑟𝑟𝑛, +∞)
Arg::new("invert_filter") #[arg(short('M'), long, allow_hyphen_values(true))]
.short('v') pub mtime: Option<String>,
.long("invert-filter")
.value_name("REGEX") /// just like -mtime, but based on file access time
.action(clap::ArgAction::Append) #[arg(short('A'), long, allow_hyphen_values(true))]
.conflicts_with("filter") pub atime: Option<String>,
.conflicts_with("types")
.help("Exclude filepaths matching this regex. To ignore png files type: -v \"\\.png$\" "), /// just like -mtime, but based on file change time
) #[arg(short('y'), long, allow_hyphen_values(true))]
.arg( pub ctime: Option<String>,
Arg::new("filter")
.short('e') /// run dust on NUL-terminated file names specified in file; if argument is
.long("filter") /// -, then read names from standard input
.value_name("REGEX") #[arg(long, value_hint(ValueHint::AnyPath))]
.action(clap::ArgAction::Append) pub files0_from: Option<String>,
.conflicts_with("types")
.help("Only include filepaths matching this regex. For png files type: -e \"\\.png$\" "), /// Keep these directories collapsed
) #[arg(long, value_hint(ValueHint::AnyPath))]
.arg( pub collapse: Option<Vec<String>>,
Arg::new("types")
.short('t') /// Directory 'size' is max filetime of child files instead of disk size.
.long("file-types") /// while a/c/m for last accessed/changed/modified time
.conflicts_with("depth") #[arg(short('m'), long, value_enum)]
.conflicts_with("only_dir") pub filetime: Option<FileTime>,
.action(clap::ArgAction::SetTrue) }
.help("show only these file types"),
) #[derive(Clone, Copy, Debug, ValueEnum)]
.arg( #[value(rename_all = "lower")]
Arg::new("width") pub enum OutputFormat {
.short('w') /// SI prefix (powers of 1000)
.long("terminal-width") SI,
.value_name("WIDTH")
.value_parser(value_parser!(usize)) /// byte (B)
.num_args(1) B,
.help("Specify width of output overriding the auto detection of terminal width"),
) /// kibibyte (KiB)
.arg( #[value(name = "k", alias("kib"))]
Arg::new("disable_progress") KiB,
.short('P')
.long("no-progress") /// mebibyte (MiB)
.action(clap::ArgAction::SetTrue) #[value(name = "m", alias("mib"))]
.help("Disable the progress indication."), MiB,
)
.arg( /// gibibyte (GiB)
Arg::new("print_errors") #[value(name = "g", alias("gib"))]
.long("print-errors") GiB,
.action(clap::ArgAction::SetTrue)
.help("Print path with errors."), /// tebibyte (TiB)
) #[value(name = "t", alias("tib"))]
.arg( TiB,
Arg::new("only_dir")
.short('D') /// kilobyte (kB)
.long("only-dir") KB,
.conflicts_with("only_file")
.conflicts_with("types") /// megabyte (MB)
.action(clap::ArgAction::SetTrue) MB,
.help("Only directories will be displayed."),
) /// gigabyte (GB)
.arg( GB,
Arg::new("only_file")
.short('F') /// terabyte (TB)
.long("only-file") TB,
.conflicts_with("only_dir") }
.action(clap::ArgAction::SetTrue)
.help("Only files will be displayed. (Finds your largest files)"), impl fmt::Display for OutputFormat {
) fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
.arg( match self {
Arg::new("output_format") Self::SI => write!(f, "si"),
.short('o') Self::B => write!(f, "b"),
.long("output-format") Self::KiB => write!(f, "k"),
.value_name("FORMAT") Self::MiB => write!(f, "m"),
.value_parser([ Self::GiB => write!(f, "g"),
PossibleValue::new("si"), Self::TiB => write!(f, "t"),
PossibleValue::new("b"), Self::KB => write!(f, "kb"),
PossibleValue::new("k").alias("kib"), Self::MB => write!(f, "mb"),
PossibleValue::new("m").alias("mib"), Self::GB => write!(f, "gb"),
PossibleValue::new("g").alias("gib"), Self::TB => write!(f, "tb"),
PossibleValue::new("t").alias("tib"), }
PossibleValue::new("kb"), }
PossibleValue::new("mb"), }
PossibleValue::new("gb"),
PossibleValue::new("tb"), #[derive(Clone, Copy, Debug, ValueEnum)]
]) pub enum FileTime {
.ignore_case(true) /// last accessed time
.help("Changes output display size. si will print sizes in powers of 1000. b k m g t kb mb gb tb will print the whole tree in that size.") #[value(name = "a", alias("accessed"))]
) Accessed,
.arg(
Arg::new("stack_size") /// last changed time
.short('S') #[value(name = "c", alias("changed"))]
.long("stack-size") Changed,
.value_name("STACK_SIZE")
.value_parser(value_parser!(usize)) /// last modified time
.num_args(1) #[value(name = "m", alias("modified"))]
.help("Specify memory to use as stack size - use if you see: 'fatal runtime error: stack overflow' (default low memory=1048576, high memory=1073741824)"), Modified,
)
.arg(
Arg::new("params")
.value_name("PATH")
.value_hint(clap::ValueHint::AnyPath)
.value_parser(value_parser!(String))
.num_args(1..)
)
.arg(
Arg::new("output_json")
.short('j')
.long("output-json")
.action(clap::ArgAction::SetTrue)
.help("Output the directory tree as json to the current directory"),
)
.arg(
Arg::new("mtime")
.short('M')
.long("mtime")
.num_args(1)
.allow_hyphen_values(true)
.value_parser(value_parser!(String))
.help("+/-n matches files modified more/less than n days ago , and n matches files modified exactly n days ago, days are rounded down.That is +n => (−∞, curr(n+1)), n => [curr(n+1), currn), and -n => (𝑐𝑢𝑟𝑟𝑛, +∞)")
)
.arg(
Arg::new("atime")
.short('A')
.long("atime")
.num_args(1)
.allow_hyphen_values(true)
.value_parser(value_parser!(String))
.help("just like -mtime, but based on file access time")
)
.arg(
Arg::new("ctime")
.short('y')
.long("ctime")
.num_args(1)
.allow_hyphen_values(true)
.value_parser(value_parser!(String))
.help("just like -mtime, but based on file change time")
)
.arg(
Arg::new("files0_from")
.long("files0-from")
.value_hint(clap::ValueHint::AnyPath)
.value_parser(value_parser!(String))
.num_args(1)
.help("run dust on NUL-terminated file names specified in file; if argument is -, then read names from standard input"),
)
.arg(
Arg::new("collapse")
.long("collapse")
.value_hint(clap::ValueHint::AnyPath)
.value_parser(value_parser!(String))
.action(clap::ArgAction::Append)
.help("Keep these directories collapsed"),
)
.arg(
Arg::new("filetime")
.short('m')
.long("filetime")
.num_args(1)
.value_parser([
PossibleValue::new("a").alias("accessed"),
PossibleValue::new("c").alias("changed"),
PossibleValue::new("m").alias("modified"),
])
.help("Directory 'size' is max filetime of child files instead of disk size. while a/c/m for last accessed/changed/modified time"),
)
} }

View File

@@ -1,12 +1,12 @@
use crate::node::FileTime; use crate::node::FileTime;
use chrono::{Local, TimeZone}; use chrono::{Local, TimeZone};
use clap::ArgMatches;
use config_file::FromConfigFile; use config_file::FromConfigFile;
use regex::Regex; use regex::Regex;
use serde::Deserialize; use serde::Deserialize;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use crate::cli::Cli;
use crate::dir_walker::Operator; use crate::dir_walker::Operator;
use crate::display::get_number_format; use crate::display::get_number_format;
@@ -39,77 +39,68 @@ pub struct Config {
} }
impl Config { impl Config {
pub fn get_files_from(&self, options: &ArgMatches) -> Option<String> { pub fn get_files_from(&self, options: &Cli) -> Option<String> {
let from_file = options.get_one::<String>("files0_from"); let from_file = &options.files0_from;
match from_file { match from_file {
None => self.files0_from.as_ref().map(|x| x.to_string()), None => self.files0_from.as_ref().map(|x| x.to_string()),
Some(x) => Some(x.to_string()), Some(x) => Some(x.to_string()),
} }
} }
pub fn get_no_colors(&self, options: &ArgMatches) -> bool { pub fn get_no_colors(&self, options: &Cli) -> bool {
Some(true) == self.no_colors || options.get_flag("no_colors") Some(true) == self.no_colors || options.no_colors
} }
pub fn get_force_colors(&self, options: &ArgMatches) -> bool { pub fn get_force_colors(&self, options: &Cli) -> bool {
Some(true) == self.force_colors || options.get_flag("force_colors") Some(true) == self.force_colors || options.force_colors
} }
pub fn get_disable_progress(&self, options: &ArgMatches) -> bool { pub fn get_disable_progress(&self, options: &Cli) -> bool {
Some(true) == self.disable_progress || options.get_flag("disable_progress") Some(true) == self.disable_progress || options.no_progress
} }
pub fn get_apparent_size(&self, options: &ArgMatches) -> bool { pub fn get_apparent_size(&self, options: &Cli) -> bool {
Some(true) == self.display_apparent_size || options.get_flag("display_apparent_size") Some(true) == self.display_apparent_size || options.apparent_size
} }
pub fn get_ignore_hidden(&self, options: &ArgMatches) -> bool { pub fn get_ignore_hidden(&self, options: &Cli) -> bool {
Some(true) == self.ignore_hidden || options.get_flag("ignore_hidden") Some(true) == self.ignore_hidden || options.ignore_hidden
} }
pub fn get_full_paths(&self, options: &ArgMatches) -> bool { pub fn get_full_paths(&self, options: &Cli) -> bool {
Some(true) == self.display_full_paths || options.get_flag("display_full_paths") Some(true) == self.display_full_paths || options.full_paths
} }
pub fn get_reverse(&self, options: &ArgMatches) -> bool { pub fn get_reverse(&self, options: &Cli) -> bool {
Some(true) == self.reverse || options.get_flag("reverse") Some(true) == self.reverse || options.reverse
} }
pub fn get_no_bars(&self, options: &ArgMatches) -> bool { pub fn get_no_bars(&self, options: &Cli) -> bool {
Some(true) == self.no_bars || options.get_flag("no_bars") Some(true) == self.no_bars || options.no_percent_bars
} }
pub fn get_output_format(&self, options: &ArgMatches) -> String { pub fn get_output_format(&self, options: &Cli) -> String {
let out_fmt = options.get_one::<String>("output_format"); let out_fmt = options.output_format;
(match out_fmt { (match out_fmt {
None => match &self.output_format { None => match &self.output_format {
None => "".to_string(), None => "".to_string(),
Some(x) => x.to_string(), Some(x) => x.to_string(),
}, },
Some(x) => x.into(), Some(x) => x.to_string(),
}) })
.to_lowercase() .to_lowercase()
} }
pub fn get_filetime(&self, options: &ArgMatches) -> Option<FileTime> { pub fn get_filetime(&self, options: &Cli) -> Option<FileTime> {
let out_fmt = options.get_one::<String>("filetime"); options.filetime.map(FileTime::from)
match out_fmt {
None => None,
Some(x) => match x.as_str() {
"m" | "modified" => Some(FileTime::Modified),
"a" | "accessed" => Some(FileTime::Accessed),
"c" | "changed" => Some(FileTime::Changed),
_ => unreachable!(),
},
}
} }
pub fn get_skip_total(&self, options: &ArgMatches) -> bool { pub fn get_skip_total(&self, options: &Cli) -> bool {
Some(true) == self.skip_total || options.get_flag("skip_total") Some(true) == self.skip_total || options.skip_total
} }
pub fn get_screen_reader(&self, options: &ArgMatches) -> bool { pub fn get_screen_reader(&self, options: &Cli) -> bool {
Some(true) == self.screen_reader || options.get_flag("screen_reader") Some(true) == self.screen_reader || options.screen_reader
} }
pub fn get_depth(&self, options: &ArgMatches) -> usize { pub fn get_depth(&self, options: &Cli) -> usize {
if let Some(v) = options.get_one::<usize>("depth") { if let Some(v) = options.depth {
return *v; return v;
} }
self.depth.unwrap_or(usize::MAX) self.depth.unwrap_or(usize::MAX)
} }
pub fn get_min_size(&self, options: &ArgMatches) -> Option<usize> { pub fn get_min_size(&self, options: &Cli) -> Option<usize> {
let size_from_param = options.get_one::<String>("min_size"); let size_from_param = options.min_size.as_ref();
self._get_min_size(size_from_param) self._get_min_size(size_from_param)
} }
fn _get_min_size(&self, min_size: Option<&String>) -> Option<usize> { fn _get_min_size(&self, min_size: Option<&String>) -> Option<usize> {
@@ -123,58 +114,49 @@ impl Config {
size_from_param size_from_param
} }
} }
pub fn get_only_dir(&self, options: &ArgMatches) -> bool { pub fn get_only_dir(&self, options: &Cli) -> bool {
Some(true) == self.only_dir || options.get_flag("only_dir") Some(true) == self.only_dir || options.only_dir
} }
pub fn get_print_errors(&self, options: &ArgMatches) -> bool { pub fn get_print_errors(&self, options: &Cli) -> bool {
Some(true) == self.print_errors || options.get_flag("print_errors") Some(true) == self.print_errors || options.print_errors
} }
pub fn get_only_file(&self, options: &ArgMatches) -> bool { pub fn get_only_file(&self, options: &Cli) -> bool {
Some(true) == self.only_file || options.get_flag("only_file") Some(true) == self.only_file || options.only_file
} }
pub fn get_bars_on_right(&self, options: &ArgMatches) -> bool { pub fn get_bars_on_right(&self, options: &Cli) -> bool {
Some(true) == self.bars_on_right || options.get_flag("bars_on_right") Some(true) == self.bars_on_right || options.bars_on_right
} }
pub fn get_custom_stack_size(&self, options: &ArgMatches) -> Option<usize> { pub fn get_custom_stack_size(&self, options: &Cli) -> Option<usize> {
let from_cmd_line = options.get_one::<usize>("stack_size"); let from_cmd_line = options.stack_size;
if from_cmd_line.is_none() { if from_cmd_line.is_none() {
self.stack_size self.stack_size
} else { } else {
from_cmd_line.copied() from_cmd_line
} }
} }
pub fn get_threads(&self, options: &ArgMatches) -> Option<usize> { pub fn get_threads(&self, options: &Cli) -> Option<usize> {
let from_cmd_line = options.get_one::<usize>("threads"); let from_cmd_line = options.threads;
if from_cmd_line.is_none() { if from_cmd_line.is_none() {
self.threads self.threads
} else { } else {
from_cmd_line.copied() from_cmd_line
} }
} }
pub fn get_output_json(&self, options: &ArgMatches) -> bool { pub fn get_output_json(&self, options: &Cli) -> bool {
Some(true) == self.output_json || options.get_flag("output_json") Some(true) == self.output_json || options.output_json
} }
pub fn get_modified_time_operator(&self, options: &ArgMatches) -> Option<(Operator, i64)> { pub fn get_modified_time_operator(&self, options: &Cli) -> Option<(Operator, i64)> {
get_filter_time_operator( get_filter_time_operator(options.mtime.as_ref(), get_current_date_epoch_seconds())
options.get_one::<String>("mtime"),
get_current_date_epoch_seconds(),
)
} }
pub fn get_accessed_time_operator(&self, options: &ArgMatches) -> Option<(Operator, i64)> { pub fn get_accessed_time_operator(&self, options: &Cli) -> Option<(Operator, i64)> {
get_filter_time_operator( get_filter_time_operator(options.atime.as_ref(), get_current_date_epoch_seconds())
options.get_one::<String>("atime"),
get_current_date_epoch_seconds(),
)
} }
pub fn get_changed_time_operator(&self, options: &ArgMatches) -> Option<(Operator, i64)> { pub fn get_changed_time_operator(&self, options: &Cli) -> Option<(Operator, i64)> {
get_filter_time_operator( get_filter_time_operator(options.ctime.as_ref(), get_current_date_epoch_seconds())
options.get_one::<String>("ctime"),
get_current_date_epoch_seconds(),
)
} }
} }
@@ -250,10 +232,10 @@ fn get_config_locations(base: &Path) -> Vec<PathBuf> {
] ]
} }
pub fn get_config(conf_path: Option<String>) -> Config { pub fn get_config(conf_path: Option<&String>) -> Config {
match conf_path { match conf_path {
Some(path_str) => { Some(path_str) => {
let path = Path::new(&path_str); let path = Path::new(path_str);
if path.exists() { if path.exists() {
match Config::from_config_file(path) { match Config::from_config_file(path) {
Ok(config) => return config, Ok(config) => return config,
@@ -287,8 +269,7 @@ mod tests {
#[allow(unused_imports)] #[allow(unused_imports)]
use super::*; use super::*;
use chrono::{Datelike, Timelike}; use chrono::{Datelike, Timelike};
use clap::builder::PossibleValue; use clap::Parser;
use clap::{Arg, ArgMatches, Command, value_parser};
#[test] #[test]
fn test_get_current_date_epoch_seconds() { fn test_get_current_date_epoch_seconds() {
@@ -357,15 +338,8 @@ mod tests {
assert_eq!(c.get_depth(&args), 5); assert_eq!(c.get_depth(&args), 5);
} }
fn get_args(args: Vec<&str>) -> ArgMatches { fn get_args(args: Vec<&str>) -> Cli {
Command::new("Dust") Cli::parse_from(args)
.arg(
Arg::new("depth")
.long("depth")
.num_args(1)
.value_parser(value_parser!(usize)),
)
.get_matches_from(args)
} }
#[test] #[test]
@@ -403,20 +377,7 @@ mod tests {
assert_eq!(c.get_filetime(&args), Some(FileTime::Changed)); assert_eq!(c.get_filetime(&args), Some(FileTime::Changed));
} }
fn get_filetime_args(args: Vec<&str>) -> ArgMatches { fn get_filetime_args(args: Vec<&str>) -> Cli {
Command::new("Dust") Cli::parse_from(args)
.arg(
Arg::new("filetime")
.short('m')
.long("filetime")
.num_args(1)
.value_parser([
PossibleValue::new("a").alias("accessed"),
PossibleValue::new("c").alias("changed"),
PossibleValue::new("m").alias("modified"),
])
.help("Directory 'size' is max filetime of child files instead of disk size. while a/c/m for accessed/changed/modified time"),
)
.get_matches_from(args)
} }
} }

View File

@@ -10,9 +10,9 @@ mod platform;
mod progress; mod progress;
mod utils; mod utils;
use crate::cli::build_cli; use crate::cli::Cli;
use crate::progress::RuntimeErrors; use crate::progress::RuntimeErrors;
use clap::parser::ValuesRef; use clap::Parser;
use dir_walker::WalkData; use dir_walker::WalkData;
use display::InitialDisplayData; use display::InitialDisplayData;
use filter::AggregateData; use filter::AggregateData;
@@ -98,9 +98,10 @@ fn get_width_of_terminal() -> usize {
.unwrap_or(DEFAULT_TERMINAL_WIDTH) .unwrap_or(DEFAULT_TERMINAL_WIDTH)
} }
fn get_regex_value(maybe_value: Option<ValuesRef<String>>) -> Vec<Regex> { fn get_regex_value(maybe_value: Option<&Vec<String>>) -> Vec<Regex> {
maybe_value maybe_value
.unwrap_or_default() .unwrap_or(&Vec::new())
.iter()
.map(|reg| { .map(|reg| {
Regex::new(reg).unwrap_or_else(|err| { Regex::new(reg).unwrap_or_else(|err| {
eprintln!("Ignoring bad value for regex {err:?}"); eprintln!("Ignoring bad value for regex {err:?}");
@@ -111,8 +112,8 @@ fn get_regex_value(maybe_value: Option<ValuesRef<String>>) -> Vec<Regex> {
} }
fn main() { fn main() {
let options = build_cli().get_matches(); let options = Cli::parse();
let config = get_config(options.get_one::<String>("config").cloned()); let config = get_config(options.config.as_ref());
let errors = RuntimeErrors::default(); let errors = RuntimeErrors::default();
let error_listen_for_ctrlc = Arc::new(Mutex::new(errors)); let error_listen_for_ctrlc = Arc::new(Mutex::new(errors));
@@ -148,19 +149,19 @@ fn main() {
} }
} }
} }
None => match options.get_many::<String>("params") { None => match options.params {
Some(values) => values.cloned().collect(), Some(ref values) => values.clone(),
None => vec![".".to_owned()], None => vec![".".to_owned()],
}, },
}; };
let summarize_file_types = options.get_flag("types"); let summarize_file_types = options.file_types;
let filter_regexs = get_regex_value(options.get_many("filter")); let filter_regexs = get_regex_value(options.filter.as_ref());
let invert_filter_regexs = get_regex_value(options.get_many("invert_filter")); let invert_filter_regexs = get_regex_value(options.invert_filter.as_ref());
let terminal_width: usize = match options.get_one::<usize>("width") { let terminal_width: usize = match options.terminal_width {
Some(&val) => val, Some(val) => val,
None => get_width_of_terminal(), None => get_width_of_terminal(),
}; };
@@ -169,8 +170,8 @@ fn main() {
// If depth is set, then we set the default number_of_lines to be max // If depth is set, then we set the default number_of_lines to be max
// instead of screen height // instead of screen height
let number_of_lines = match options.get_one::<usize>("number_of_lines") { let number_of_lines = match options.number_of_lines {
Some(&val) => val, Some(val) => val,
None => { None => {
if depth != usize::MAX { if depth != usize::MAX {
usize::MAX usize::MAX
@@ -185,17 +186,17 @@ fn main() {
config.get_force_colors(&options), config.get_force_colors(&options),
); );
let ignore_directories = match options.get_many::<String>("ignore_directory") { let ignore_directories = match options.ignore_directory {
Some(values) => values Some(ref values) => values
.map(|v| v.as_str()) .iter()
.map(PathBuf::from) .map(PathBuf::from)
.map(canonicalize_absolute_path) .map(canonicalize_absolute_path)
.collect::<Vec<PathBuf>>(), .collect::<Vec<PathBuf>>(),
None => vec![], None => vec![],
}; };
let ignore_from_file_result = match options.get_one::<String>("ignore_all_in_file") { let ignore_from_file_result = match options.ignore_all_in_file {
Some(val) => read_to_string(val) Some(ref val) => read_to_string(val)
.unwrap() .unwrap()
.lines() .lines()
.map(Regex::new) .map(Regex::new)
@@ -212,10 +213,10 @@ fn main() {
.chain(ignore_from_file) .chain(ignore_from_file)
.collect::<Vec<Regex>>(); .collect::<Vec<Regex>>();
let by_filecount = options.get_flag("by_filecount"); let by_filecount = options.filecount;
let by_filetime = config.get_filetime(&options); let by_filetime = config.get_filetime(&options);
let limit_filesystem = options.get_flag("limit_filesystem"); let limit_filesystem = options.limit_filesystem;
let follow_links = options.get_flag("dereference_links"); let follow_links = options.dereference_links;
let allowed_filesystems = limit_filesystem let allowed_filesystems = limit_filesystem
.then(|| get_filesystem_devices(&target_dirs, follow_links)) .then(|| get_filesystem_devices(&target_dirs, follow_links))
@@ -236,8 +237,8 @@ fn main() {
indicator.spawn(output_format.clone()) indicator.spawn(output_format.clone())
} }
let keep_collapsed: HashSet<PathBuf> = match options.get_many::<String>("collapse") { let keep_collapsed: HashSet<PathBuf> = match options.collapse {
Some(collapse) => { Some(ref collapse) => {
let mut combined_dirs = HashSet::new(); let mut combined_dirs = HashSet::new();
for collapse_dir in collapse { for collapse_dir in collapse {
for target_dir in target_dirs.iter() { for target_dir in target_dirs.iter() {

View File

@@ -23,6 +23,16 @@ pub enum FileTime {
Changed, Changed,
} }
impl From<crate::cli::FileTime> for FileTime {
fn from(time: crate::cli::FileTime) -> Self {
match time {
crate::cli::FileTime::Modified => Self::Modified,
crate::cli::FileTime::Accessed => Self::Accessed,
crate::cli::FileTime::Changed => Self::Changed,
}
}
}
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn build_node( pub fn build_node(
dir: PathBuf, dir: PathBuf,