mirror of
https://github.com/lsd-rs/lsd
synced 2024-12-13 13:42:34 +00:00
Add ability to configure default options with file
# Conflicts: # Cargo.lock # Cargo.toml # README.md # src/app.rs # src/core.rs # src/display.rs # src/flags.rs # src/meta/mod.rs # src/sort.rs # tests/integration.rs
This commit is contained in:
parent
5fea5cda09
commit
55a96a114d
27 changed files with 4176 additions and 747 deletions
592
Cargo.lock
generated
592
Cargo.lock
generated
|
@ -2,664 +2,730 @@
|
|||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.10"
|
||||
version = "0.7.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86"
|
||||
dependencies = [
|
||||
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
dependencies = [
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
||||
|
||||
[[package]]
|
||||
name = "assert_cmd"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c88b9ca26f9c16ec830350d309397e74ee9abdfd8eb1f71cb6ecc71a3fc818da"
|
||||
dependencies = [
|
||||
"doc-comment 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"predicates 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"predicates-tree 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"doc-comment",
|
||||
"predicates",
|
||||
"predicates-core",
|
||||
"predicates-tree",
|
||||
"wait-timeout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "assert_fs"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04dabd011e19821a348abb0dec7b7fda959cd6b3477c474395b958b291942b0e"
|
||||
dependencies = [
|
||||
"doc-comment 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"globwalk 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"predicates 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"predicates-tree 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"doc-comment",
|
||||
"globwalk",
|
||||
"predicates",
|
||||
"predicates-core",
|
||||
"predicates-tree",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "blake2b_simd"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"constant_time_eq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "0.2.12"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931"
|
||||
dependencies = [
|
||||
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.11"
|
||||
version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b"
|
||||
dependencies = [
|
||||
"num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono-humanize"
|
||||
version = "0.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb2ff48a655fe8d2dae9a39e66af7fd8ff32a879e8c4e27422c25596a8b5e90d"
|
||||
dependencies = [
|
||||
"chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.0"
|
||||
version = "2.33.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||
dependencies = [
|
||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ansi_term 0.11.0",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim",
|
||||
"term_size",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.4.2"
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "difference"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "3.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "142995ed02755914747cc6ca76fc7e4583cd18578746716d0508ea6ed558b9ff"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "doc-comment"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||
|
||||
[[package]]
|
||||
name = "float-cmp"
|
||||
version = "0.6.0"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4"
|
||||
dependencies = [
|
||||
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.6"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.14"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.9.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "globset"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ad1da430bd7281dde2576f44c84cc3f0f7b475e7202cd503042dff01a8c8120"
|
||||
dependencies = [
|
||||
"aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bstr 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"aho-corasick",
|
||||
"bstr",
|
||||
"fnv",
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "globwalk"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9db17aec586697a93219b19726b5b68307eba92898c34b170857343fe67c99d"
|
||||
dependencies = [
|
||||
"ignore 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ignore",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.10"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c30f6d0bc6b00693347368a67d41b58f2fb851215ff1da49e90fe2c5c667151"
|
||||
dependencies = [
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "human-sort"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "140a09c9305e6d5e557e2ed7cbc68e05765a7d4213975b87cb04920689cc6219"
|
||||
|
||||
[[package]]
|
||||
name = "ignore"
|
||||
version = "0.4.14"
|
||||
version = "0.4.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22dcbf2a4a289528dbef21686354904e1c694ac642610a9bff9e7df730d9ec72"
|
||||
dependencies = [
|
||||
"crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"globset 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-util 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils",
|
||||
"globset",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"memchr",
|
||||
"regex",
|
||||
"same-file",
|
||||
"thread_local",
|
||||
"walkdir",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.68"
|
||||
version = "0.2.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235"
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.8"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lscolors"
|
||||
version = "0.7.0"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d24b894c45c9da468621cdd615a5a79ee5e5523dd4f75c76ebc03d458940c16e"
|
||||
dependencies = [
|
||||
"ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ansi_term 0.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lsd"
|
||||
version = "0.18.0"
|
||||
dependencies = [
|
||||
"ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"assert_cmd 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"assert_fs 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono-humanize 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"globset 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"human-sort 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lscolors 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"predicates 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term_grid 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"terminal_size 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"users 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wild 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ansi_term 0.12.1",
|
||||
"assert_cmd",
|
||||
"assert_fs",
|
||||
"chrono-humanize",
|
||||
"clap",
|
||||
"dirs",
|
||||
"globset",
|
||||
"human-sort",
|
||||
"libc",
|
||||
"lscolors",
|
||||
"predicates",
|
||||
"tempfile",
|
||||
"term_grid",
|
||||
"terminal_size",
|
||||
"time",
|
||||
"unicode-width",
|
||||
"users",
|
||||
"version_check",
|
||||
"wild",
|
||||
"winapi",
|
||||
"xdg",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "maybe-uninit"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||
|
||||
[[package]]
|
||||
name = "normalize-line-endings"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.42"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.11"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.6"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20"
|
||||
|
||||
[[package]]
|
||||
name = "predicates"
|
||||
version = "1.0.4"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96bfead12e90dccead362d62bb2c90a5f6fc4584963645bc7f71a735e0b0735a"
|
||||
dependencies = [
|
||||
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"float-cmp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"normalize-line-endings 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"difference",
|
||||
"float-cmp",
|
||||
"normalize-line-endings",
|
||||
"predicates-core",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "predicates-core"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06075c3a3e92559ff8929e7a280684489ea27fe44805174c3ebd9328dcb37178"
|
||||
|
||||
[[package]]
|
||||
name = "predicates-tree"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e63c4859013b38a76eca2414c64911fba30def9e3202ac461a2d22831220124"
|
||||
dependencies = [
|
||||
"predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"treeline 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"predicates-core",
|
||||
"treeline",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"getrandom",
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_hc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
dependencies = [
|
||||
"getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
dependencies = [
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.56"
|
||||
version = "0.1.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
"rust-argon2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.3.6"
|
||||
version = "1.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
|
||||
dependencies = [
|
||||
"aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
"thread_local",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.17"
|
||||
version = "0.6.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.2"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-argon2"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"blake2b_simd",
|
||||
"constant_time_eq",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"rand",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "term_grid"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "230d3e804faaed5a39b08319efb797783df2fd9671b39b7596490cb486d702cf"
|
||||
dependencies = [
|
||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "term_size"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.1.12"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a14cd9f8c72704232f0bfc8455c0e861f0ad4eb60cc9ec8a170e231414c1e13"
|
||||
dependencies = [
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term_size",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
|
||||
dependencies = [
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.42"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||
dependencies = [
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "treeline"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.7"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||
|
||||
[[package]]
|
||||
name = "users"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa4227e95324a443c9fcb06e03d4d85e91aabe9a5a02aa818688b6918b6af486"
|
||||
dependencies = [
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.1"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||
|
||||
[[package]]
|
||||
name = "wait-timeout"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
|
||||
dependencies = [
|
||||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
|
||||
dependencies = [
|
||||
"same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-util 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"same-file",
|
||||
"winapi",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "wild"
|
||||
version = "2.0.2"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "035793abb854745033f01a07647a79831eba29ec0be377205f2a25b0aa830020"
|
||||
dependencies = [
|
||||
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.8"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[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-util"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"
|
||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
"checksum assert_cmd 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c88b9ca26f9c16ec830350d309397e74ee9abdfd8eb1f71cb6ecc71a3fc818da"
|
||||
"checksum assert_fs 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "04dabd011e19821a348abb0dec7b7fda959cd6b3477c474395b958b291942b0e"
|
||||
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
"checksum bstr 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "2889e6d50f394968c8bf4240dc3f2a7eb4680844d27308f798229ac9d4725f41"
|
||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
"checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2"
|
||||
"checksum chrono-humanize 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2ff48a655fe8d2dae9a39e66af7fd8ff32a879e8c4e27422c25596a8b5e90d"
|
||||
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||
"checksum crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061"
|
||||
"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
|
||||
"checksum doc-comment 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||
"checksum float-cmp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da62c4f1b81918835a8c6a484a397775fff5953fe83529afd51b05f5c6a6617d"
|
||||
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
||||
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||
"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
"checksum globset 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7ad1da430bd7281dde2576f44c84cc3f0f7b475e7202cd503042dff01a8c8120"
|
||||
"checksum globwalk 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d9db17aec586697a93219b19726b5b68307eba92898c34b170857343fe67c99d"
|
||||
"checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e"
|
||||
"checksum human-sort 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "140a09c9305e6d5e557e2ed7cbc68e05765a7d4213975b87cb04920689cc6219"
|
||||
"checksum ignore 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ddf60d063dbe6b75388eec66cfc07781167ae3d34a09e0c433e6c5de0511f7fb"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0"
|
||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
"checksum lscolors 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f77452267149eac960ded529fe5f5460ddf792845a1d71b5d0cfcee5642e47e"
|
||||
"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||
"checksum normalize-line-endings 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
|
||||
"checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
|
||||
"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
|
||||
"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
|
||||
"checksum predicates 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "347a1b6f0b21e636bc9872fb60b83b8e185f6f5516298b8238699f7f9a531030"
|
||||
"checksum predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "06075c3a3e92559ff8929e7a280684489ea27fe44805174c3ebd9328dcb37178"
|
||||
"checksum predicates-tree 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8e63c4859013b38a76eca2414c64911fba30def9e3202ac461a2d22831220124"
|
||||
"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
||||
"checksum regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3"
|
||||
"checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
|
||||
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
|
||||
"checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||
"checksum term_grid 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "230d3e804faaed5a39b08319efb797783df2fd9671b39b7596490cb486d702cf"
|
||||
"checksum term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327"
|
||||
"checksum terminal_size 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "8038f95fc7a6f351163f4b964af631bd26c9e828f7db085f2a84aca56f70d13b"
|
||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
|
||||
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
|
||||
"checksum treeline 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
|
||||
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
||||
"checksum users 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aa4227e95324a443c9fcb06e03d4d85e91aabe9a5a02aa818688b6918b6af486"
|
||||
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||
"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
|
||||
"checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
|
||||
"checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
|
||||
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
"checksum wild 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "97d34fecce28871e5c0e059deae21ef7f7d13b98a5964b24c58b3735c8052fc8"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-util 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fa515c5163a99cc82bab70fd3bfdd36d827be85de63737b40fcef2ce084a436e"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
[[package]]
|
||||
name = "xdg"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a66b7c2281ebde13cf4391d70d4c7e5946c3c25e72a7b859ca8f677dcd0b0c61"
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
|
|
@ -22,7 +22,9 @@ time = "0.1.*"
|
|||
|
||||
[dependencies]
|
||||
ansi_term = "0.12.*"
|
||||
dirs = "3.0.*"
|
||||
libc = "0.2.*"
|
||||
human-sort = "0.2.2"
|
||||
term_grid = "0.1.*"
|
||||
terminal_size = "0.1.*"
|
||||
time = "0.1.*"
|
||||
|
@ -31,7 +33,8 @@ unicode-width = "0.1.*"
|
|||
lscolors = "0.7"
|
||||
wild = "2.0.*"
|
||||
globset = "0.4.*"
|
||||
human-sort = "0.2.2"
|
||||
xdg = "2.1.*"
|
||||
yaml-rust = "0.4.*"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
users = "0.10.*"
|
||||
|
|
141
README.md
141
README.md
|
@ -11,7 +11,8 @@
|
|||
- [Description](#description)
|
||||
- [Screenshot](#screenshot)
|
||||
- [Installation](#installation)
|
||||
- [Configurations](#configurations)
|
||||
- [Configuration](#configuration)
|
||||
- [External Configurations](#external-configurations)
|
||||
* [Required](#required)
|
||||
* [Optional](#optional)
|
||||
- [F.A.Q.](#faq)
|
||||
|
@ -120,7 +121,143 @@ cargo install --git https://github.com/Peltoche/lsd.git --branch master
|
|||
|
||||
The [release page](https://github.com/Peltoche/lsd/releases) includes precompiled binaries for Linux and macOS.
|
||||
|
||||
## Configurations
|
||||
## Configuration
|
||||
|
||||
`lsd` can be configured with a configuration file to set the default options.
|
||||
Right now this only supports setting options that can be passed via the command
|
||||
line options as well.
|
||||
|
||||
### Config file location
|
||||
|
||||
#### Non-Windows
|
||||
|
||||
On non-Windows systems `lsd` follows the
|
||||
[XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html)
|
||||
convention for the location of the configuration file. The configuration dir
|
||||
`lsd` uses is itself named `lsd`. In that directory it looks first for a file
|
||||
called `config.yaml` and if it can't find one, a file named `config.yml`.
|
||||
For most people it should be enough to put their config file at
|
||||
`~/.config/lsd/config.yaml`.
|
||||
|
||||
#### Windows
|
||||
|
||||
On Windows systems `lsd` only looks for the two files in one location:
|
||||
`%APPDATA%\lsd\`
|
||||
|
||||
### Config file content
|
||||
|
||||
This is an example config file with the default values and some additional
|
||||
remarks.
|
||||
```yaml
|
||||
# == Classic ==
|
||||
# This is a shorthand to override some of the options to be backwards compatible
|
||||
# with `ls`. It affects the "color"->"when", "sorting"->"dir-grouping", "date"
|
||||
# and "icons"->"when" options.
|
||||
# Possible values: false, true
|
||||
classic: false
|
||||
|
||||
# == Blocks ==
|
||||
# This specifies the columns and their order when using the long and the tree
|
||||
# layout.
|
||||
# Possible values: permission, user, group, size, size_value, date, name, inode
|
||||
blocks:
|
||||
- permission
|
||||
- user
|
||||
- group
|
||||
- size
|
||||
- date
|
||||
- name
|
||||
|
||||
# == Color ==
|
||||
# This has various color options. (Will be expanded in the future.)
|
||||
color:
|
||||
# When to colorize the output.
|
||||
# When "classic" is set, this is set to "never".
|
||||
# Possible values: never, auto, always
|
||||
when: auto
|
||||
|
||||
# == Date ==
|
||||
# This specifies the date format for the date column. The freeform format
|
||||
# accepts an strftime like string.
|
||||
# When "classic" is set, this is set to "date".
|
||||
# Possible values: date, relative, +<date_format>
|
||||
date: date
|
||||
|
||||
# == Dereference ==
|
||||
# Whether to dereference symbolic links.
|
||||
# Possible values: false, true
|
||||
dereference: false
|
||||
|
||||
# == Display ==
|
||||
# What items to display. Do not specify this for the default behavior.
|
||||
# Possible values: all, almost-all, directory-only
|
||||
# display: all
|
||||
|
||||
# == Icons ==
|
||||
icons:
|
||||
# When to use icons.
|
||||
# When "classic" is set, this is set to "never".
|
||||
# Possible values: always, auto, never
|
||||
when: auto
|
||||
# Which icon theme to use.
|
||||
# Possible values: fancy, unicode
|
||||
theme: fancy
|
||||
|
||||
# == Ignore Globs ==
|
||||
# A list of globs to ignore when listing.
|
||||
# ignore-globs:
|
||||
# - .git
|
||||
|
||||
# == Indicators ==
|
||||
# Whether to add indicator characters to certain listed files.
|
||||
# Possible values: false, true
|
||||
indicators: false
|
||||
|
||||
# == Layout ==
|
||||
# Which layout to use. "oneline" might be a bit confusing here and should be
|
||||
# called "one-per-line". It might be changed in the future.
|
||||
# Possible values: grid, tree, oneline
|
||||
layout: grid
|
||||
|
||||
# == Recursion ==
|
||||
recursion:
|
||||
# Whether to enable recursion.
|
||||
# Possible values: false, true
|
||||
enabled: false
|
||||
# How deep the recursion should go. This has to be a positive integer. Leave
|
||||
# it unspecified for (virtually) infinite.
|
||||
# depth: 3
|
||||
|
||||
# == Size ==
|
||||
# Specifies the format of the size column.
|
||||
# Possible values: default, short, bytes
|
||||
size: default
|
||||
|
||||
# == Sorting ==
|
||||
sorting:
|
||||
# Specify what to sort by.
|
||||
# Possible values: extension, name, time, size, version
|
||||
column: name
|
||||
# Whether to reverse the sorting.
|
||||
# Possible values: false, true
|
||||
reverse: false
|
||||
# Whether to group directories together and where.
|
||||
# When "classic" is set, this is set to "none".
|
||||
# Possible values: first, last, none
|
||||
dir-grouping: none
|
||||
|
||||
# == No Symlink ==
|
||||
# Whether to omit showing symlink targets
|
||||
# Possible values: false, true
|
||||
no-symlink: false
|
||||
|
||||
# == Total size ==
|
||||
# Whether to display the total size of directories.
|
||||
# Possible values: false, true
|
||||
total-size: false
|
||||
```
|
||||
|
||||
## External Configurations
|
||||
|
||||
### Required
|
||||
|
||||
|
|
|
@ -67,6 +67,11 @@ pub fn build() -> App<'static, 'static> {
|
|||
.multiple(true)
|
||||
.help("Display extended file metadata as a table"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("no-config")
|
||||
.long("no-config")
|
||||
.help("Do not read a configuration file"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("oneline")
|
||||
.short("1")
|
||||
|
@ -173,6 +178,7 @@ pub fn build() -> App<'static, 'static> {
|
|||
.arg(
|
||||
Arg::with_name("versionsort")
|
||||
.short("v")
|
||||
.long("versionsort")
|
||||
.multiple(true)
|
||||
.overrides_with("timesort")
|
||||
.overrides_with("sizesort")
|
||||
|
@ -261,7 +267,7 @@ fn validate_date_argument(arg: String) -> Result<(), String> {
|
|||
}
|
||||
}
|
||||
|
||||
fn validate_time_format(formatter: &str) -> Result<(), time::ParseError> {
|
||||
pub fn validate_time_format(formatter: &str) -> Result<(), time::ParseError> {
|
||||
let mut chars = formatter.chars();
|
||||
loop {
|
||||
match chars.next() {
|
||||
|
|
175
src/config_file.rs
Normal file
175
src/config_file.rs
Normal file
|
@ -0,0 +1,175 @@
|
|||
///! This module provides methods to handle the program's config files and operations related to
|
||||
///! this.
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::print_error;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
use xdg::BaseDirectories;
|
||||
use yaml_rust::{Yaml, YamlLoader};
|
||||
|
||||
const CONF_DIR: &str = "lsd";
|
||||
const CONF_FILE_NAME: &str = "config";
|
||||
const YAML_LONG_EXT: &str = "yaml";
|
||||
const YAML_SHORT_EXT: &str = "yml";
|
||||
|
||||
/// A struct to hold an optional file path [String] and an optional [Yaml], and provides methods
|
||||
/// around error handling in a config file.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Config {
|
||||
pub file: Option<String>,
|
||||
pub yaml: Option<Yaml>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// This constructs a Config struct without a file [String] and without a [Yaml].
|
||||
pub fn with_none() -> Self {
|
||||
Self {
|
||||
file: None,
|
||||
yaml: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// This constructs a Config struct with a passed file [String] and without a [Yaml].
|
||||
pub fn with_file(file: String) -> Self {
|
||||
Self {
|
||||
file: Some(file),
|
||||
yaml: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// This constructs a Config struct with a passed [Yaml] and without a file [String].
|
||||
#[cfg(test)]
|
||||
pub fn with_yaml(yaml: Yaml) -> Self {
|
||||
Self {
|
||||
file: None,
|
||||
yaml: Some(yaml),
|
||||
}
|
||||
}
|
||||
|
||||
/// This tries to read a configuration file like in the XDG_BASE_DIRS specification and returns
|
||||
/// the contents of the YAML config file.
|
||||
pub fn read_config() -> Self {
|
||||
let config_file_long_path;
|
||||
let config_file_short_path;
|
||||
match Self::config_file_paths() {
|
||||
Some((long, short)) => {
|
||||
config_file_long_path = long;
|
||||
config_file_short_path = short;
|
||||
}
|
||||
_ => return Self::with_none(),
|
||||
}
|
||||
|
||||
let mut out_config;
|
||||
let mut config_file;
|
||||
match File::open(&config_file_long_path) {
|
||||
Ok(result) => {
|
||||
config_file = result;
|
||||
out_config = Self::with_file(config_file_long_path.as_path().display().to_string());
|
||||
}
|
||||
Err(_) => match File::open(&config_file_short_path) {
|
||||
Ok(result) => {
|
||||
config_file = result;
|
||||
out_config =
|
||||
Self::with_file(config_file_short_path.as_path().display().to_string());
|
||||
}
|
||||
Err(_) => return Self::with_none(),
|
||||
},
|
||||
}
|
||||
|
||||
let mut config_content = String::new();
|
||||
if let Err(error) = config_file.read_to_string(&mut config_content) {
|
||||
print_error!("Found a config file, but could not read it: {}", error);
|
||||
return out_config;
|
||||
}
|
||||
|
||||
match YamlLoader::load_from_str(&config_content) {
|
||||
Ok(result) => {
|
||||
if !result.is_empty() {
|
||||
out_config.yaml = Some(result[0].clone());
|
||||
}
|
||||
out_config
|
||||
}
|
||||
Err(error) => {
|
||||
print_error!("Error parsing config: {}\n", error);
|
||||
out_config
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This provides two paths for a configuration file (the first with the long yaml extension,
|
||||
/// the second with the short yml extension), according to the XDG_BASE_DIRS specification.
|
||||
#[cfg(not(windows))]
|
||||
pub fn config_file_paths() -> Option<(PathBuf, PathBuf)> {
|
||||
let base_dirs;
|
||||
match BaseDirectories::with_prefix(CONF_DIR) {
|
||||
Ok(result) => base_dirs = result,
|
||||
_ => return None,
|
||||
}
|
||||
|
||||
let config_file_long_path;
|
||||
match base_dirs.place_config_file([CONF_FILE_NAME, YAML_LONG_EXT].join(".")) {
|
||||
Ok(result) => config_file_long_path = result,
|
||||
_ => return None,
|
||||
}
|
||||
|
||||
let config_file_short_path;
|
||||
match base_dirs.place_config_file([CONF_FILE_NAME, YAML_SHORT_EXT].join(".")) {
|
||||
Ok(result) => config_file_short_path = result,
|
||||
_ => return None,
|
||||
}
|
||||
|
||||
Some((config_file_long_path, config_file_short_path))
|
||||
}
|
||||
|
||||
/// This provides two paths for a configuration file (the first with the long yaml extension,
|
||||
/// the second with the short yml extension) inside the %APPDATA% directory.
|
||||
#[cfg(windows)]
|
||||
pub fn config_file_paths() -> Option<(PathBuf, PathBuf)> {
|
||||
let mut config_file_long_path;
|
||||
match dirs::config_dir() {
|
||||
Some(path) => config_file_long_path = path,
|
||||
_ => return None,
|
||||
}
|
||||
|
||||
config_file_long_path.push(CONF_DIR);
|
||||
let mut config_file_short_path = config_file_long_path.clone();
|
||||
|
||||
config_file_long_path.push([CONF_FILE_NAME, YAML_LONG_EXT].join("."));
|
||||
config_file_short_path.push([CONF_FILE_NAME, YAML_SHORT_EXT].join("."));
|
||||
|
||||
Some((config_file_long_path, config_file_short_path))
|
||||
}
|
||||
|
||||
/// Returns whether the Config has a [Yaml].
|
||||
pub fn has_yaml(&self) -> bool {
|
||||
self.yaml.is_some()
|
||||
}
|
||||
|
||||
/// This prints the provided warning message to stderr, prepending the executable name and the
|
||||
/// configuration file path that likely caused the warning.
|
||||
pub fn print_warning(&self, message: &str) {
|
||||
print_error!(
|
||||
"lsd: {} - {}\n",
|
||||
self.file.as_ref().unwrap_or(&String::from("")),
|
||||
message
|
||||
);
|
||||
}
|
||||
|
||||
/// This prints a predetermined warning message to stderr, warning about an invalid value for a
|
||||
/// configuration element.
|
||||
pub fn print_invalid_value_warning(&self, name: &str, value: &str) {
|
||||
self.print_warning(&format!("Not a valid {} value: {}", name, value));
|
||||
}
|
||||
|
||||
/// This prints a predetermined warning message to stderr, warning about a wrong [Yaml] data
|
||||
/// type for a configuration value.
|
||||
pub fn print_wrong_type_warning(&self, name: &str, type_name: &str) {
|
||||
self.print_warning(&format!(
|
||||
"The {} config value has to be a {}.",
|
||||
name, type_name
|
||||
));
|
||||
}
|
||||
}
|
20
src/core.rs
20
src/core.rs
|
@ -1,6 +1,6 @@
|
|||
use crate::color::{self, Colors};
|
||||
use crate::display;
|
||||
use crate::flags::{Display, Flags, IconTheme, Layout, SortOrder, WhenFlag};
|
||||
use crate::flags::{ColorOption, Display, Flags, IconOption, IconTheme, Layout, SortOrder};
|
||||
use crate::icon::{self, Icons};
|
||||
use crate::meta::Meta;
|
||||
use crate::{print_error, print_output, sort};
|
||||
|
@ -40,13 +40,13 @@ impl Core {
|
|||
|
||||
let mut inner_flags = flags.clone();
|
||||
|
||||
let color_theme = match (tty_available && console_color_ok, flags.color) {
|
||||
(_, WhenFlag::Never) | (false, WhenFlag::Auto) => color::Theme::NoColor,
|
||||
let color_theme = match (tty_available && console_color_ok, flags.color.when) {
|
||||
(_, ColorOption::Never) | (false, ColorOption::Auto) => color::Theme::NoColor,
|
||||
_ => color::Theme::Default,
|
||||
};
|
||||
|
||||
let icon_theme = match (tty_available, flags.icon, flags.icon_theme) {
|
||||
(_, WhenFlag::Never, _) | (false, WhenFlag::Auto, _) => icon::Theme::NoIcon,
|
||||
let icon_theme = match (tty_available, flags.icons.when, flags.icons.theme) {
|
||||
(_, IconOption::Never, _) | (false, IconOption::Auto, _) => icon::Theme::NoIcon,
|
||||
(_, _, IconTheme::Fancy) => icon::Theme::Fancy,
|
||||
(_, _, IconTheme::Unicode) => icon::Theme::Unicode,
|
||||
};
|
||||
|
@ -80,13 +80,13 @@ impl Core {
|
|||
fn fetch(&self, paths: Vec<PathBuf>) -> Vec<Meta> {
|
||||
let mut meta_list = Vec::with_capacity(paths.len());
|
||||
let depth = match self.flags.layout {
|
||||
Layout::Tree { .. } => self.flags.recursion_depth,
|
||||
_ if self.flags.recursive => self.flags.recursion_depth,
|
||||
Layout::Tree { .. } => self.flags.recursion.depth,
|
||||
_ if self.flags.recursion.enabled => self.flags.recursion.depth,
|
||||
_ => 1,
|
||||
};
|
||||
|
||||
for path in paths {
|
||||
let mut meta = match Meta::from_path(&path, self.flags.dereference) {
|
||||
let mut meta = match Meta::from_path(&path, self.flags.dereference.0) {
|
||||
Ok(meta) => meta,
|
||||
Err(err) => {
|
||||
print_error!("lsd: {}: {}\n", path.display(), err);
|
||||
|
@ -95,7 +95,7 @@ impl Core {
|
|||
};
|
||||
|
||||
match self.flags.display {
|
||||
Display::DisplayDirectoryItself => {
|
||||
Display::DirectoryItself => {
|
||||
meta_list.push(meta);
|
||||
}
|
||||
_ => {
|
||||
|
@ -112,7 +112,7 @@ impl Core {
|
|||
}
|
||||
};
|
||||
}
|
||||
if self.flags.total_size {
|
||||
if self.flags.total_size.0 {
|
||||
for meta in &mut meta_list.iter_mut() {
|
||||
meta.calculate_total_size();
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ fn inner_display_grid(
|
|||
// The first iteration (depth == 0) corresponds to the inputs given by the
|
||||
// user. We defer displaying directories given by the user unless we've been
|
||||
// asked to display the directory itself (rather than its contents).
|
||||
let skip_dirs = (depth == 0) && (flags.display != Display::DisplayDirectoryItself);
|
||||
let skip_dirs = (depth == 0) && (flags.display != Display::DirectoryItself);
|
||||
|
||||
// print the files first.
|
||||
for meta in metas {
|
||||
|
@ -107,7 +107,7 @@ fn inner_display_grid(
|
|||
output += &grid.fit_into_columns(1).to_string();
|
||||
}
|
||||
} else {
|
||||
output += &grid.fit_into_columns(flags.blocks.len()).to_string();
|
||||
output += &grid.fit_into_columns(flags.blocks.0.len()).to_string();
|
||||
}
|
||||
|
||||
let should_display_folder_path = should_display_folder_path(depth, &metas, &flags);
|
||||
|
@ -174,7 +174,7 @@ fn inner_display_tree(
|
|||
}
|
||||
}
|
||||
|
||||
let content = grid.fit_into_columns(flags.blocks.len()).to_string();
|
||||
let content = grid.fit_into_columns(flags.blocks.0.len()).to_string();
|
||||
let mut lines = content.lines();
|
||||
|
||||
for (idx, meta) in metas.iter().enumerate() {
|
||||
|
@ -254,7 +254,7 @@ fn get_output<'a>(
|
|||
padding_rules: &HashMap<Block, usize>,
|
||||
) -> Vec<ANSIString<'a>> {
|
||||
let mut strings: Vec<ANSIString> = Vec::new();
|
||||
for block in flags.blocks.iter() {
|
||||
for block in flags.blocks.0.iter() {
|
||||
match block {
|
||||
Block::INode => strings.push(meta.inode.render(colors)),
|
||||
Block::Permission => {
|
||||
|
@ -276,7 +276,7 @@ fn get_output<'a>(
|
|||
Block::Date => strings.push(meta.date.render(colors, &flags)),
|
||||
Block::Name => {
|
||||
let s: String =
|
||||
if flags.no_symlink || flags.dereference || flags.layout == Layout::Grid {
|
||||
if flags.no_symlink.0 || flags.dereference.0 || flags.layout == Layout::Grid {
|
||||
ANSIStrings(&[
|
||||
meta.name.render(colors, icons, &display_option),
|
||||
meta.indicator.render(&flags),
|
||||
|
@ -332,7 +332,7 @@ fn detect_size_lengths(metas: &[Meta], flags: &Flags) -> usize {
|
|||
fn get_padding_rules(metas: &[Meta], flags: &Flags) -> HashMap<Block, usize> {
|
||||
let mut padding_rules: HashMap<Block, usize> = HashMap::new();
|
||||
|
||||
if flags.blocks.contains(&Block::Size) {
|
||||
if flags.blocks.0.contains(&Block::Size) {
|
||||
let size_val = detect_size_lengths(&metas, &flags);
|
||||
|
||||
padding_rules.insert(Block::SizeValue, size_val);
|
||||
|
|
530
src/flags.rs
530
src/flags.rs
|
@ -1,441 +1,127 @@
|
|||
use clap::{ArgMatches, Error, ErrorKind};
|
||||
use globset::{Glob, GlobSet, GlobSetBuilder};
|
||||
use std::iter::Iterator;
|
||||
pub mod blocks;
|
||||
pub mod color;
|
||||
pub mod date;
|
||||
pub mod dereference;
|
||||
pub mod display;
|
||||
pub mod icons;
|
||||
pub mod ignore_globs;
|
||||
pub mod indicators;
|
||||
pub mod layout;
|
||||
pub mod recursion;
|
||||
pub mod size;
|
||||
pub mod sorting;
|
||||
pub mod symlinks;
|
||||
pub mod total_size;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub use blocks::Block;
|
||||
pub use blocks::Blocks;
|
||||
pub use color::Color;
|
||||
pub use color::ColorOption;
|
||||
pub use date::DateFlag;
|
||||
pub use dereference::Dereference;
|
||||
pub use display::Display;
|
||||
pub use icons::IconOption;
|
||||
pub use icons::IconTheme;
|
||||
pub use icons::Icons;
|
||||
pub use ignore_globs::IgnoreGlobs;
|
||||
pub use indicators::Indicators;
|
||||
pub use layout::Layout;
|
||||
pub use recursion::Recursion;
|
||||
pub use size::SizeFlag;
|
||||
pub use sorting::DirGrouping;
|
||||
pub use sorting::SortColumn;
|
||||
pub use sorting::SortOrder;
|
||||
pub use sorting::Sorting;
|
||||
pub use symlinks::NoSymlink;
|
||||
pub use total_size::TotalSize;
|
||||
|
||||
use crate::config_file::Config;
|
||||
|
||||
use clap::{ArgMatches, Error};
|
||||
|
||||
#[cfg(doc)]
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
/// A struct to hold all set configuration flags for the application.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Flags {
|
||||
pub display: Display,
|
||||
pub layout: Layout,
|
||||
pub display_indicators: bool,
|
||||
pub recursive: bool,
|
||||
pub sort_by: SortFlag,
|
||||
pub sort_order: SortOrder,
|
||||
pub directory_order: DirOrderFlag,
|
||||
pub size: SizeFlag,
|
||||
pub blocks: Blocks,
|
||||
pub color: Color,
|
||||
pub date: DateFlag,
|
||||
pub color: WhenFlag,
|
||||
pub icon: WhenFlag,
|
||||
pub icon_theme: IconTheme,
|
||||
pub inode: bool,
|
||||
pub recursion_depth: usize,
|
||||
pub blocks: Vec<Block>,
|
||||
pub no_symlink: bool,
|
||||
pub total_size: bool,
|
||||
pub ignore_globs: GlobSet,
|
||||
pub dereference: bool,
|
||||
pub dereference: Dereference,
|
||||
pub display: Display,
|
||||
pub display_indicators: Indicators,
|
||||
pub icons: Icons,
|
||||
pub ignore_globs: IgnoreGlobs,
|
||||
pub layout: Layout,
|
||||
pub no_symlink: NoSymlink,
|
||||
pub recursion: Recursion,
|
||||
pub size: SizeFlag,
|
||||
pub sorting: Sorting,
|
||||
pub total_size: TotalSize,
|
||||
}
|
||||
|
||||
impl Flags {
|
||||
pub fn from_matches(matches: &ArgMatches) -> Result<Self, Error> {
|
||||
let classic_mode = matches.is_present("classic");
|
||||
let color_inputs: Vec<&str> = matches.values_of("color").unwrap().collect();
|
||||
let icon_inputs: Vec<&str> = matches.values_of("icon").unwrap().collect();
|
||||
let icon_theme_inputs: Vec<&str> = matches.values_of("icon-theme").unwrap().collect();
|
||||
let size_inputs: Vec<&str> = matches.values_of("size").unwrap().collect();
|
||||
let date_inputs: Vec<&str> = matches.values_of("date").unwrap().collect();
|
||||
let dir_order_inputs: Vec<&str> = matches.values_of("group-dirs").unwrap().collect();
|
||||
let ignore_globs_inputs: Vec<&str> = matches.values_of("ignore-glob").unwrap().collect();
|
||||
let dereference = matches.is_present("dereference");
|
||||
// inode set layout to oneline and blocks to inode,name
|
||||
let inode = matches.is_present("inode");
|
||||
let blocks_inputs: Vec<&str> = if let Some(blocks) = matches.values_of("blocks") {
|
||||
blocks.collect()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
let display = if matches.is_present("all") {
|
||||
Display::DisplayAll
|
||||
} else if matches.is_present("almost-all") {
|
||||
Display::DisplayAlmostAll
|
||||
} else if matches.is_present("directory-only") {
|
||||
Display::DisplayDirectoryItself
|
||||
} else {
|
||||
Display::DisplayOnlyVisible
|
||||
};
|
||||
|
||||
let sort_by = if matches.is_present("timesort") {
|
||||
SortFlag::Time
|
||||
} else if matches.is_present("sizesort") {
|
||||
SortFlag::Size
|
||||
} else if matches.is_present("extensionsort") {
|
||||
SortFlag::Extension
|
||||
} else if matches.is_present("versionsort") {
|
||||
SortFlag::Version
|
||||
} else {
|
||||
SortFlag::Name
|
||||
};
|
||||
|
||||
let sort_order = if matches.is_present("reverse") {
|
||||
SortOrder::Reverse
|
||||
} else {
|
||||
SortOrder::Default
|
||||
};
|
||||
|
||||
let layout = if matches.is_present("tree") {
|
||||
Layout::Tree
|
||||
} else if matches.is_present("long")
|
||||
|| matches.is_present("oneline")
|
||||
|| blocks_inputs.len() > 1
|
||||
|| inode
|
||||
{
|
||||
Layout::OneLine
|
||||
} else {
|
||||
Layout::Grid
|
||||
};
|
||||
|
||||
let recursive = matches.is_present("recursive");
|
||||
let recursion_input = matches.values_of("depth").and_then(Iterator::last);
|
||||
let recursion_depth = match recursion_input {
|
||||
Some(str) if recursive || layout == Layout::Tree => match str.parse::<usize>() {
|
||||
Ok(val) => val,
|
||||
Err(_) => {
|
||||
return Err(Error::with_description(
|
||||
"The argument '--depth' requires a valid positive number",
|
||||
ErrorKind::ValueValidation,
|
||||
));
|
||||
}
|
||||
},
|
||||
Some(_) => {
|
||||
return Err(Error::with_description(
|
||||
"The argument '--depth' requires '--tree' or '--recursive'",
|
||||
ErrorKind::MissingRequiredArgument,
|
||||
));
|
||||
}
|
||||
None => usize::max_value(),
|
||||
};
|
||||
|
||||
let mut blocks: Vec<Block> = if !blocks_inputs.is_empty() {
|
||||
blocks_inputs.into_iter().map(Block::from).collect()
|
||||
} else if matches.is_present("long") {
|
||||
vec![
|
||||
Block::Permission,
|
||||
Block::User,
|
||||
Block::Group,
|
||||
Block::Size,
|
||||
Block::Date,
|
||||
Block::Name,
|
||||
]
|
||||
} else {
|
||||
vec![Block::Name]
|
||||
};
|
||||
|
||||
// Add inode as first column if with inode flag
|
||||
if inode && !blocks.contains(&Block::INode) {
|
||||
blocks.insert(0, Block::INode);
|
||||
}
|
||||
|
||||
let mut ignore_globs_builder = GlobSetBuilder::new();
|
||||
for pattern in ignore_globs_inputs {
|
||||
let glob = match Glob::new(pattern) {
|
||||
Ok(g) => g,
|
||||
Err(e) => {
|
||||
return Err(Error::with_description(
|
||||
&e.to_string(),
|
||||
ErrorKind::ValueValidation,
|
||||
));
|
||||
}
|
||||
};
|
||||
ignore_globs_builder.add(glob);
|
||||
}
|
||||
|
||||
let ignore_globs = match ignore_globs_builder.build() {
|
||||
Ok(globs) => globs,
|
||||
Err(e) => {
|
||||
return Err(Error::with_description(
|
||||
&e.to_string(),
|
||||
ErrorKind::ValueValidation,
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
/// Set up the `Flags` from either [ArgMatches], a [Config] or its [Default] value.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This can return an [Error], when either the building of the ignore globs or the parsing of
|
||||
/// the recursion depth parameter fails.
|
||||
pub fn configure_from(matches: &ArgMatches, config: &Config) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
display,
|
||||
layout,
|
||||
display_indicators: matches.is_present("indicators"),
|
||||
recursive,
|
||||
recursion_depth,
|
||||
sort_by,
|
||||
sort_order,
|
||||
size: SizeFlag::from(size_inputs[size_inputs.len() - 1]),
|
||||
ignore_globs,
|
||||
blocks,
|
||||
// Take only the last value
|
||||
date: if classic_mode {
|
||||
DateFlag::Date
|
||||
} else {
|
||||
DateFlag::from(date_inputs[date_inputs.len() - 1])
|
||||
},
|
||||
color: if classic_mode {
|
||||
WhenFlag::Never
|
||||
} else {
|
||||
WhenFlag::from(color_inputs[color_inputs.len() - 1])
|
||||
},
|
||||
icon: if classic_mode {
|
||||
WhenFlag::Never
|
||||
} else {
|
||||
WhenFlag::from(icon_inputs[icon_inputs.len() - 1])
|
||||
},
|
||||
icon_theme: IconTheme::from(icon_theme_inputs[icon_theme_inputs.len() - 1]),
|
||||
directory_order: if classic_mode {
|
||||
DirOrderFlag::None
|
||||
} else {
|
||||
DirOrderFlag::from(dir_order_inputs[dir_order_inputs.len() - 1])
|
||||
},
|
||||
no_symlink: matches.is_present("no-symlink"),
|
||||
total_size: matches.is_present("total-size"),
|
||||
inode,
|
||||
dereference,
|
||||
blocks: Blocks::configure_from(matches, config)?,
|
||||
color: Color::configure_from(matches, config),
|
||||
date: DateFlag::configure_from(matches, config),
|
||||
dereference: Dereference::configure_from(matches, config),
|
||||
display: Display::configure_from(matches, config),
|
||||
layout: Layout::configure_from(matches, config),
|
||||
size: SizeFlag::configure_from(matches, config),
|
||||
display_indicators: Indicators::configure_from(matches, config),
|
||||
icons: Icons::configure_from(matches, config),
|
||||
ignore_globs: IgnoreGlobs::configure_from(matches, config)?,
|
||||
no_symlink: NoSymlink::configure_from(matches, config),
|
||||
recursion: Recursion::configure_from(matches, config)?,
|
||||
sorting: Sorting::configure_from(matches, config),
|
||||
total_size: TotalSize::configure_from(matches, config),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Flags {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
display: Display::DisplayOnlyVisible,
|
||||
layout: Layout::Grid,
|
||||
display_indicators: false,
|
||||
recursive: false,
|
||||
recursion_depth: usize::max_value(),
|
||||
sort_by: SortFlag::Name,
|
||||
sort_order: SortOrder::Default,
|
||||
directory_order: DirOrderFlag::None,
|
||||
size: SizeFlag::Default,
|
||||
date: DateFlag::Date,
|
||||
color: WhenFlag::Auto,
|
||||
icon: WhenFlag::Auto,
|
||||
icon_theme: IconTheme::Fancy,
|
||||
blocks: vec![],
|
||||
no_symlink: false,
|
||||
total_size: false,
|
||||
ignore_globs: GlobSet::empty(),
|
||||
inode: false,
|
||||
dereference: false,
|
||||
/// A trait to allow a type to be configured by either command line parameters, a configuration
|
||||
/// file or a [Default] value.
|
||||
pub trait Configurable<T>
|
||||
where
|
||||
T: std::default::Default,
|
||||
{
|
||||
/// Returns a value from either [ArgMatches], a [Config] or a [Default] value. The first value
|
||||
/// that is not [None] is used. The order of precedence for the value used is:
|
||||
/// - [from_arg_matches](Configurable::from_arg_matches)
|
||||
/// - [from_config](Configurable::from_config)
|
||||
/// - [Default::default]
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The configuration file's Yaml is read in any case, to be able to check for errors and print
|
||||
/// out warnings.
|
||||
fn configure_from(matches: &ArgMatches, config: &Config) -> T {
|
||||
let mut result: T = Default::default();
|
||||
|
||||
if let Some(value) = Self::from_config(config) {
|
||||
result = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub enum Block {
|
||||
Permission,
|
||||
User,
|
||||
Group,
|
||||
Size,
|
||||
SizeValue,
|
||||
Date,
|
||||
Name,
|
||||
INode,
|
||||
}
|
||||
impl<'a> From<&'a str> for Block {
|
||||
fn from(block: &'a str) -> Self {
|
||||
match block {
|
||||
// "filetype" => Block::FileType,
|
||||
"permission" => Block::Permission,
|
||||
"user" => Block::User,
|
||||
"group" => Block::Group,
|
||||
"size" => Block::Size,
|
||||
"size_value" => Block::SizeValue,
|
||||
"date" => Block::Date,
|
||||
"name" => Block::Name,
|
||||
"inode" => Block::INode,
|
||||
_ => panic!("invalid \"time\" flag: {}", block),
|
||||
if let Some(value) = Self::from_arg_matches(matches) {
|
||||
result = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum Display {
|
||||
DisplayAll,
|
||||
DisplayAlmostAll,
|
||||
DisplayDirectoryItself,
|
||||
DisplayOnlyVisible,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum SizeFlag {
|
||||
Default,
|
||||
Short,
|
||||
Bytes,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for SizeFlag {
|
||||
fn from(size: &'a str) -> Self {
|
||||
match size {
|
||||
"default" => SizeFlag::Default,
|
||||
"short" => SizeFlag::Short,
|
||||
"bytes" => SizeFlag::Bytes,
|
||||
_ => panic!("invalid \"size\" flag: {}", size),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum DateFlag {
|
||||
Date,
|
||||
Relative,
|
||||
Formatted(String),
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for DateFlag {
|
||||
fn from(time: &'a str) -> Self {
|
||||
match time {
|
||||
"date" => DateFlag::Date,
|
||||
"relative" => DateFlag::Relative,
|
||||
time if time.starts_with('+') => DateFlag::Formatted(time[1..].to_owned()),
|
||||
_ => panic!("invalid \"time\" flag: {}", time),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum WhenFlag {
|
||||
Always,
|
||||
Auto,
|
||||
Never,
|
||||
}
|
||||
impl<'a> From<&'a str> for WhenFlag {
|
||||
fn from(when: &'a str) -> Self {
|
||||
match when {
|
||||
"always" => WhenFlag::Always,
|
||||
"auto" => WhenFlag::Auto,
|
||||
"never" => WhenFlag::Never,
|
||||
_ => panic!("invalid \"when\" flag: {}", when),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum SortFlag {
|
||||
Name,
|
||||
Time,
|
||||
Size,
|
||||
Version,
|
||||
Extension,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum SortOrder {
|
||||
Default,
|
||||
Reverse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum DirOrderFlag {
|
||||
None,
|
||||
First,
|
||||
Last,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for DirOrderFlag {
|
||||
fn from(when: &'a str) -> Self {
|
||||
match when {
|
||||
"none" => DirOrderFlag::None,
|
||||
"first" => DirOrderFlag::First,
|
||||
"last" => DirOrderFlag::Last,
|
||||
_ => panic!("invalid \"when\" flag: {}", when),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum IconTheme {
|
||||
Unicode,
|
||||
Fancy,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for IconTheme {
|
||||
fn from(theme: &'a str) -> Self {
|
||||
match theme {
|
||||
"fancy" => IconTheme::Fancy,
|
||||
"unicode" => IconTheme::Unicode,
|
||||
_ => panic!("invalid \"icon-theme\" flag: {}", theme),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum Layout {
|
||||
Grid,
|
||||
Tree,
|
||||
OneLine,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Flags;
|
||||
use super::SortFlag;
|
||||
use crate::app;
|
||||
use clap::ErrorKind;
|
||||
|
||||
#[test]
|
||||
fn test_validate_depth_value() {
|
||||
let matches = app::build()
|
||||
.get_matches_from_safe(vec!["lsd", "--tree", "--depth", "xx"])
|
||||
.unwrap();
|
||||
let res = Flags::from_matches(&matches);
|
||||
|
||||
assert!(res.is_err());
|
||||
assert_eq!(res.unwrap_err().kind, ErrorKind::ValueValidation);
|
||||
result
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_useless_depth() {
|
||||
let matches = app::build()
|
||||
.get_matches_from_safe(vec!["lsd", "--depth", "10"])
|
||||
.unwrap();
|
||||
let res = Flags::from_matches(&matches);
|
||||
/// The method to implement the value fetching from command line parameters.
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Option<T>;
|
||||
|
||||
assert!(res.is_err());
|
||||
assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_duplicate_depth() {
|
||||
let matches = app::build()
|
||||
.get_matches_from_safe(vec!["lsd", "--tree", "--depth", "1", "--depth", "2"])
|
||||
.unwrap();
|
||||
let res = Flags::from_matches(&matches);
|
||||
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap().recursion_depth, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_missing_depth() {
|
||||
let matches = app::build()
|
||||
.get_matches_from_safe(vec!["lsd", "--tree"])
|
||||
.unwrap();
|
||||
let res = Flags::from_matches(&matches);
|
||||
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap().recursion_depth, usize::max_value());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multi_sort_use_last() {
|
||||
let matches = app::build()
|
||||
.get_matches_from_safe(vec!["lsd", "-t", "-S"])
|
||||
.unwrap();
|
||||
let res = Flags::from_matches(&matches);
|
||||
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap().sort_by, SortFlag::Size);
|
||||
|
||||
let matches = app::build()
|
||||
.get_matches_from_safe(vec!["lsd", "-S", "-t"])
|
||||
.unwrap();
|
||||
let res = Flags::from_matches(&matches);
|
||||
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap().sort_by, SortFlag::Time);
|
||||
|
||||
let matches = app::build()
|
||||
.get_matches_from_safe(vec!["lsd", "-t", "-S", "-X"])
|
||||
.unwrap();
|
||||
let res = Flags::from_matches(&matches);
|
||||
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap().sort_by, SortFlag::Extension);
|
||||
}
|
||||
/// The method to implement the value fetching from a configuration file. This should return
|
||||
/// [None], if the [Config] does not have a [Yaml].
|
||||
fn from_config(config: &Config) -> Option<T>;
|
||||
}
|
||||
|
|
538
src/flags/blocks.rs
Normal file
538
src/flags/blocks.rs
Normal file
|
@ -0,0 +1,538 @@
|
|||
//! This module defines the [Blocks] struct. To set it up from [ArgMatches], a [Yaml] and its
|
||||
//! [Default] value, use its [configure_from](Blocks::configure_from) method.
|
||||
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use crate::config_file::Config;
|
||||
|
||||
use clap::{ArgMatches, Error, ErrorKind};
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
/// A struct to hold a [Vec] of [Block]s and to provide methods to create it.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Blocks(pub Vec<Block>);
|
||||
|
||||
impl Blocks {
|
||||
/// Returns a value from either [ArgMatches], a [Config] or a default value.
|
||||
/// Unless the "long" argument is passed, this returns [Default::default]. Otherwise the first
|
||||
/// value, that is not [None], is used. The order of precedence for the value used is:
|
||||
/// - [from_arg_matches](Blocks::from_arg_matches)
|
||||
/// - [from_config](Blocks::from_config)
|
||||
/// - [long](Blocks::long)
|
||||
///
|
||||
/// No matter if the "long" argument was passed, if the "inode" argument is passed and the
|
||||
/// `Blocks` does not contain a [Block] of variant [INode](Block::INode) yet, one is prepended
|
||||
/// to the returned value.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The configuration file's Yaml is read in any case, to be able to check for errors and print
|
||||
/// out warnings.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This errors if any of the [ArgMatches] parameter arguments causes [Block]'s implementation
|
||||
/// of [TryFrom::try_from] to return an [Err].
|
||||
pub fn configure_from(matches: &ArgMatches, config: &Config) -> Result<Self, Error> {
|
||||
let mut result: Result<Self, Error> = if matches.is_present("long") {
|
||||
Ok(Self::long())
|
||||
} else {
|
||||
Ok(Default::default())
|
||||
};
|
||||
|
||||
if matches.is_present("long") {
|
||||
if config.has_yaml() {
|
||||
if let Some(value) = Self::from_config(config) {
|
||||
result = Ok(value);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(value) = Self::from_arg_matches(matches) {
|
||||
result = value;
|
||||
}
|
||||
}
|
||||
|
||||
if matches.is_present("inode") {
|
||||
if let Ok(blocks) = result.as_mut() {
|
||||
blocks.optional_prepend_inode();
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Get a potential `Blocks` struct from [ArgMatches].
|
||||
///
|
||||
/// If the "blocks" argument is passed, then this returns a `Blocks` containing the parameter
|
||||
/// values in a [Some]. Otherwise if the "long" argument is passed, this returns
|
||||
/// [Blocks::long]. Finally if none of the previous happened, this returns [None].
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This errors if any of the parameter arguments causes [Block]'s implementation of
|
||||
/// [TryFrom::try_from] to return an [Err].
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Option<Result<Self, Error>> {
|
||||
if matches.occurrences_of("blocks") > 0 {
|
||||
if let Some(values) = matches.values_of("blocks") {
|
||||
let mut blocks: Vec<Block> = vec![];
|
||||
for value in values {
|
||||
match Block::try_from(value) {
|
||||
Ok(block) => blocks.push(block),
|
||||
Err(message) => {
|
||||
return Some(Err(Error::with_description(
|
||||
&message,
|
||||
ErrorKind::ValueValidation,
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(Ok(Self(blocks)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a potential `Blocks` struct from a [Config].
|
||||
///
|
||||
/// If the Config's [Yaml] contains an [Array](Yaml::Array) value pointed to by "blocks", each
|
||||
/// of its [String](Yaml::String) values is returned in a `Blocks` in a [Some]. Otherwise it
|
||||
/// returns [None].
|
||||
fn from_config(config: &Config) -> Option<Self> {
|
||||
if let Some(yaml) = &config.yaml {
|
||||
match &yaml["blocks"] {
|
||||
Yaml::BadValue => None,
|
||||
Yaml::Array(values) => Self::from_yaml_array(values, config),
|
||||
_ => {
|
||||
config.print_wrong_type_warning("blocks", "array");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a [Blocks] from a [Yaml] array. The [Config] is used to log warnings about wrong values
|
||||
/// in a Yaml.
|
||||
fn from_yaml_array(values: &[Yaml], config: &Config) -> Option<Self> {
|
||||
let mut blocks: Vec<Block> = vec![];
|
||||
for array_el in values.iter() {
|
||||
match array_el {
|
||||
Yaml::String(value) => match Block::try_from(value.as_str()) {
|
||||
Ok(block) => blocks.push(block),
|
||||
Err(err) => config.print_warning(&err),
|
||||
},
|
||||
_ => config.print_warning("The blocks config values have to be strings."),
|
||||
}
|
||||
}
|
||||
if blocks.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Self(blocks))
|
||||
}
|
||||
}
|
||||
|
||||
/// This returns a Blocks struct for the long format.
|
||||
///
|
||||
/// It contains the [Block]s [Permission](Block::Permission), [User](Block::User),
|
||||
/// [Group](Block::Group), [Size](Block::Size), [Date](Block::Date) and [Name](Block::Name).
|
||||
fn long() -> Self {
|
||||
Self(vec![
|
||||
Block::Permission,
|
||||
Block::User,
|
||||
Block::Group,
|
||||
Block::Size,
|
||||
Block::Date,
|
||||
Block::Name,
|
||||
])
|
||||
}
|
||||
|
||||
/// Checks whether `self` already contains a [Block] of variant [INode](Block::INode).
|
||||
fn contains_inode(&self) -> bool {
|
||||
self.0.contains(&Block::INode)
|
||||
}
|
||||
|
||||
/// Prepends a [Block] of variant [INode](Block::INode) to `self`.
|
||||
fn prepend_inode(&mut self) {
|
||||
self.0.insert(0, Block::INode)
|
||||
}
|
||||
|
||||
/// Prepends a [Block] of variant [INode](Block::INode), if `self` does not already contain a
|
||||
/// Block of that variant.
|
||||
fn optional_prepend_inode(&mut self) {
|
||||
if !self.contains_inode() {
|
||||
self.prepend_inode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The default value for `Blocks` contains a [Vec] of [Name](Block::Name).
|
||||
impl Default for Blocks {
|
||||
fn default() -> Self {
|
||||
Self(vec![Block::Name])
|
||||
}
|
||||
}
|
||||
|
||||
/// A block of data to show.
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub enum Block {
|
||||
Permission,
|
||||
User,
|
||||
Group,
|
||||
Size,
|
||||
SizeValue,
|
||||
Date,
|
||||
Name,
|
||||
INode,
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Block {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(string: &str) -> Result<Self, Self::Error> {
|
||||
match string {
|
||||
"permission" => Ok(Self::Permission),
|
||||
"user" => Ok(Self::User),
|
||||
"group" => Ok(Self::Group),
|
||||
"size" => Ok(Self::Size),
|
||||
"size_value" => Ok(Self::SizeValue),
|
||||
"date" => Ok(Self::Date),
|
||||
"name" => Ok(Self::Name),
|
||||
"inode" => Ok(Self::INode),
|
||||
_ => Err(format!("Not a valid block name: {}", &string)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_blocks {
|
||||
use super::Block;
|
||||
use super::Blocks;
|
||||
|
||||
use crate::app;
|
||||
use crate::config_file::Config;
|
||||
|
||||
use clap::Error;
|
||||
use yaml_rust::YamlLoader;
|
||||
|
||||
// The following tests are implemented using match expressions instead of the assert_eq macro,
|
||||
// because clap::Error does not implement PartialEq.
|
||||
|
||||
macro_rules! assert_eq_ok {
|
||||
($left:expr, $right:expr) => {
|
||||
assert!(
|
||||
match &$left {
|
||||
Ok(inner) if inner == $right.as_ref().unwrap() => true,
|
||||
_ => false,
|
||||
},
|
||||
"\nComparison failed:\nWas: {:?}\nShould be: {:?}\n",
|
||||
&$left,
|
||||
&$right
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_configure_from_without_long() {
|
||||
let argv = vec!["lsd"];
|
||||
let target = Ok::<_, Error>(Blocks::default());
|
||||
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
let result = Blocks::configure_from(&matches, &Config::with_none());
|
||||
|
||||
assert_eq_ok!(result, target);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_configure_from_with_long() {
|
||||
let argv = vec!["lsd", "--long"];
|
||||
let target = Ok::<_, Error>(Blocks::long());
|
||||
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
let result = Blocks::configure_from(&matches, &Config::with_none());
|
||||
|
||||
assert_eq_ok!(result, target);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_configure_from_with_blocks_and_without_long() {
|
||||
let argv = vec!["lsd", "--blocks", "permission"];
|
||||
let target = Ok::<_, Error>(Blocks::default());
|
||||
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
let result = Blocks::configure_from(&matches, &Config::with_none());
|
||||
|
||||
assert_eq_ok!(result, target);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_configure_from_with_blocks_and_long() {
|
||||
let argv = vec!["lsd", "--long", "--blocks", "permission"];
|
||||
let target = Ok::<_, Error>(Blocks(vec![Block::Permission]));
|
||||
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
let result = Blocks::configure_from(&matches, &Config::with_none());
|
||||
|
||||
assert_eq_ok!(result, target);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_configure_from_with_inode() {
|
||||
let argv = vec!["lsd", "--inode"];
|
||||
|
||||
let mut target_blocks = Blocks::default();
|
||||
target_blocks.0.insert(0, Block::INode);
|
||||
let target = Ok::<_, Error>(target_blocks);
|
||||
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
let result = Blocks::configure_from(&matches, &Config::with_none());
|
||||
|
||||
assert_eq_ok!(result, target);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_configure_from_prepend_inode_without_long() {
|
||||
let argv = vec!["lsd", "--blocks", "permission", "--inode"];
|
||||
|
||||
let mut target_blocks = Blocks::default();
|
||||
target_blocks.0.insert(0, Block::INode);
|
||||
let target = Ok::<_, Error>(target_blocks);
|
||||
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
let result = Blocks::configure_from(&matches, &Config::with_none());
|
||||
|
||||
assert_eq_ok!(result, target);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_configure_from_prepend_inode_with_long() {
|
||||
let argv = vec!["lsd", "--long", "--blocks", "permission", "--inode"];
|
||||
let target = Ok::<_, Error>(Blocks(vec![Block::INode, Block::Permission]));
|
||||
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
let result = Blocks::configure_from(&matches, &Config::with_none());
|
||||
|
||||
assert_eq_ok!(result, target);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_configure_from_ignore_prepend_inode_without_long() {
|
||||
let argv = vec!["lsd", "--blocks", "permission,inode", "--inode"];
|
||||
|
||||
let mut target_blocks = Blocks::default();
|
||||
target_blocks.0.insert(0, Block::INode);
|
||||
let target = Ok::<_, Error>(target_blocks);
|
||||
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
let result = Blocks::configure_from(&matches, &Config::with_none());
|
||||
|
||||
assert_eq_ok!(result, target);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_configure_from_ignore_prepend_inode_with_long() {
|
||||
let argv = vec!["lsd", "--long", "--blocks", "permission,inode", "--inode"];
|
||||
let target = Ok::<_, Error>(Blocks(vec![Block::Permission, Block::INode]));
|
||||
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
let result = Blocks::configure_from(&matches, &Config::with_none());
|
||||
|
||||
assert_eq_ok!(result, target);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_none() {
|
||||
let argv = vec!["lsd"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert!(match Blocks::from_arg_matches(&matches) {
|
||||
None => true,
|
||||
_ => false,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_one() {
|
||||
let argv = vec!["lsd", "--blocks", "permission"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
let test_blocks = Blocks(vec![Block::Permission]);
|
||||
assert!(match Blocks::from_arg_matches(&matches) {
|
||||
Some(Ok(blocks)) if blocks == test_blocks => true,
|
||||
_ => false,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_multi_occurences() {
|
||||
let argv = vec!["lsd", "--blocks", "permission", "--blocks", "name"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
let test_blocks = Blocks(vec![Block::Permission, Block::Name]);
|
||||
assert!(match Blocks::from_arg_matches(&matches) {
|
||||
Some(Ok(blocks)) if blocks == test_blocks => true,
|
||||
_ => false,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_multi_values() {
|
||||
let argv = vec!["lsd", "--blocks", "permission,name"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
let test_blocks = Blocks(vec![Block::Permission, Block::Name]);
|
||||
assert!(match Blocks::from_arg_matches(&matches) {
|
||||
Some(Ok(blocks)) if blocks == test_blocks => true,
|
||||
_ => false,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_reversed_default() {
|
||||
let argv = vec!["lsd", "--blocks", "name,date,size,group,user,permission"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
let test_blocks = Blocks(vec![
|
||||
Block::Name,
|
||||
Block::Date,
|
||||
Block::Size,
|
||||
Block::Group,
|
||||
Block::User,
|
||||
Block::Permission,
|
||||
]);
|
||||
assert!(match Blocks::from_arg_matches(&matches) {
|
||||
Some(Ok(blocks)) if blocks == test_blocks => true,
|
||||
_ => false,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_every_second_one() {
|
||||
let argv = vec!["lsd", "--blocks", "permission,group,date"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
let test_blocks = Blocks(vec![Block::Permission, Block::Group, Block::Date]);
|
||||
assert!(match Blocks::from_arg_matches(&matches) {
|
||||
Some(Ok(blocks)) if blocks == test_blocks => true,
|
||||
_ => false,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_none() {
|
||||
assert_eq!(None, Blocks::from_config(&Config::with_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_empty() {
|
||||
let yaml_string = "---";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, Blocks::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_one() {
|
||||
let yaml_string = "blocks:\n - permission";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
let blocks = Blocks(vec![Block::Permission]);
|
||||
assert_eq!(Some(blocks), Blocks::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_reversed_default() {
|
||||
let yaml_string = "blocks:
|
||||
- name
|
||||
- date
|
||||
- size
|
||||
- group
|
||||
- user
|
||||
- permission
|
||||
";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
let blocks = Blocks(vec![
|
||||
Block::Name,
|
||||
Block::Date,
|
||||
Block::Size,
|
||||
Block::Group,
|
||||
Block::User,
|
||||
Block::Permission,
|
||||
]);
|
||||
assert_eq!(Some(blocks), Blocks::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_every_second_one() {
|
||||
let yaml_string = "blocks:
|
||||
- permission
|
||||
- group
|
||||
- date
|
||||
";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
let blocks = Blocks(vec![Block::Permission, Block::Group, Block::Date]);
|
||||
assert_eq!(Some(blocks), Blocks::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_invalid_is_ignored() {
|
||||
let yaml_string = "blocks:
|
||||
- permission
|
||||
- foo
|
||||
- date
|
||||
";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
let blocks = Blocks(vec![Block::Permission, Block::Date]);
|
||||
assert_eq!(Some(blocks), Blocks::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_block {
|
||||
use super::Block;
|
||||
|
||||
use std::convert::TryFrom;
|
||||
|
||||
#[test]
|
||||
fn test_err() {
|
||||
assert_eq!(
|
||||
Err(String::from("Not a valid block name: foo")),
|
||||
Block::try_from("foo")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_permission() {
|
||||
assert_eq!(Ok(Block::Permission), Block::try_from("permission"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_user() {
|
||||
assert_eq!(Ok(Block::User), Block::try_from("user"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_group() {
|
||||
assert_eq!(Ok(Block::Group), Block::try_from("group"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_size() {
|
||||
assert_eq!(Ok(Block::Size), Block::try_from("size"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_size_value() {
|
||||
assert_eq!(Ok(Block::SizeValue), Block::try_from("size_value"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_date() {
|
||||
assert_eq!(Ok(Block::Date), Block::try_from("date"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_name() {
|
||||
assert_eq!(Ok(Block::Name), Block::try_from("name"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inode() {
|
||||
assert_eq!(Ok(Block::INode), Block::try_from("inode"));
|
||||
}
|
||||
}
|
215
src/flags/color.rs
Normal file
215
src/flags/color.rs
Normal file
|
@ -0,0 +1,215 @@
|
|||
//! This module defines the [Color]. To set it up from [ArgMatches], a [Yaml] and its [Default]
|
||||
//! value, use its [configure_from](Configurable::configure_from) method.
|
||||
|
||||
use super::Configurable;
|
||||
|
||||
use crate::config_file::Config;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
/// A collection of flags on how to use colors.
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq, Default)]
|
||||
pub struct Color {
|
||||
/// When to use color.
|
||||
pub when: ColorOption,
|
||||
}
|
||||
|
||||
impl Color {
|
||||
/// Get a `Color` struct from [ArgMatches], a [Config] or the [Default] values.
|
||||
///
|
||||
/// The [ColorOption] is configured with their respective [Configurable] implementation.
|
||||
pub fn configure_from(matches: &ArgMatches, config: &Config) -> Self {
|
||||
let when = ColorOption::configure_from(matches, config);
|
||||
Self { when }
|
||||
}
|
||||
}
|
||||
|
||||
/// The flag showing when to use colors in the output.
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum ColorOption {
|
||||
Always,
|
||||
Auto,
|
||||
Never,
|
||||
}
|
||||
|
||||
impl ColorOption {
|
||||
/// Get a Color value from a [Yaml] string. The [Config] is used to log warnings about wrong
|
||||
/// values in a Yaml.
|
||||
fn from_yaml_string(value: &str, config: &Config) -> Option<Self> {
|
||||
match value {
|
||||
"always" => Some(Self::Always),
|
||||
"auto" => Some(Self::Auto),
|
||||
"never" => Some(Self::Never),
|
||||
_ => {
|
||||
config.print_invalid_value_warning("color->when", &value);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Configurable<Self> for ColorOption {
|
||||
/// Get a potential `ColorOption` variant from [ArgMatches].
|
||||
///
|
||||
/// If the "classic" argument is passed, then this returns the [ColorOption::Never] variant in
|
||||
/// a [Some]. Otherwise if the argument is passed, this returns the variant corresponding to
|
||||
/// its parameter in a [Some]. Otherwise this returns [None].
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
|
||||
if matches.is_present("classic") {
|
||||
Some(Self::Never)
|
||||
} else if matches.occurrences_of("color") > 0 {
|
||||
match matches.value_of("color") {
|
||||
Some("always") => Some(Self::Always),
|
||||
Some("auto") => Some(Self::Auto),
|
||||
Some("never") => Some(Self::Never),
|
||||
_ => panic!("This should not be reachable!"),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a potential `ColorOption` variant from a [Config].
|
||||
///
|
||||
/// If the Config's [Yaml] contains a [Boolean](Yaml::Boolean) value pointed to by "classic"
|
||||
/// and its value is `true`, then this returns the [ColorOption::Never] variant in a [Some].
|
||||
/// Otherwise if the Yaml contains a [String](Yaml::String) value pointed to by "color" ->
|
||||
/// "when" and it is one of "always", "auto" or "never", this returns its corresponding variant
|
||||
/// in a [Some]. Otherwise this returns [None].
|
||||
fn from_config(config: &Config) -> Option<Self> {
|
||||
if let Some(yaml) = &config.yaml {
|
||||
if let Yaml::Boolean(true) = &yaml["classic"] {
|
||||
Some(Self::Never)
|
||||
} else {
|
||||
match &yaml["color"]["when"] {
|
||||
Yaml::BadValue => None,
|
||||
Yaml::String(value) => Self::from_yaml_string(&value, &config),
|
||||
_ => {
|
||||
config.print_wrong_type_warning("color->when", "string");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The default value for `ColorOption` is [ColorOption::Auto].
|
||||
impl Default for ColorOption {
|
||||
fn default() -> Self {
|
||||
Self::Auto
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_color_option {
|
||||
use super::ColorOption;
|
||||
|
||||
use crate::app;
|
||||
use crate::config_file::Config;
|
||||
use crate::flags::Configurable;
|
||||
|
||||
use yaml_rust::YamlLoader;
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_none() {
|
||||
let argv = vec!["lsd"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(None, ColorOption::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_always() {
|
||||
let argv = vec!["lsd", "--color", "always"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(ColorOption::Always),
|
||||
ColorOption::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_autp() {
|
||||
let argv = vec!["lsd", "--color", "auto"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(ColorOption::Auto),
|
||||
ColorOption::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_never() {
|
||||
let argv = vec!["lsd", "--color", "never"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(ColorOption::Never),
|
||||
ColorOption::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_classic_mode() {
|
||||
let argv = vec!["lsd", "--color", "always", "--classic"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(ColorOption::Never),
|
||||
ColorOption::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_none() {
|
||||
assert_eq!(None, ColorOption::from_config(&Config::with_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_empty() {
|
||||
let yaml_string = "---";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, ColorOption::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_always() {
|
||||
let yaml_string = "color:\n when: always";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(ColorOption::Always),
|
||||
ColorOption::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_auto() {
|
||||
let yaml_string = "color:\n when: auto";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(ColorOption::Auto),
|
||||
ColorOption::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_never() {
|
||||
let yaml_string = "color:\n when: never";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(ColorOption::Never),
|
||||
ColorOption::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_classic_mode() {
|
||||
let yaml_string = "classic: true\ncolor:\n when: always";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(ColorOption::Never),
|
||||
ColorOption::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
}
|
222
src/flags/date.rs
Normal file
222
src/flags/date.rs
Normal file
|
@ -0,0 +1,222 @@
|
|||
//! This module defines the [DateFlag]. To set it up from [ArgMatches], a [Yaml] and its
|
||||
//! [Default] value, use its [configure_from](Configurable::configure_from) method.
|
||||
|
||||
use super::Configurable;
|
||||
|
||||
use crate::app;
|
||||
use crate::config_file::Config;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
/// The flag showing which kind of time stamps to display.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum DateFlag {
|
||||
Date,
|
||||
Relative,
|
||||
Formatted(String),
|
||||
}
|
||||
|
||||
impl DateFlag {
|
||||
/// Get a value from a date format string. The [Config] is used to log warnings about wrong
|
||||
/// values in a Yaml.
|
||||
fn from_format_string(value: &str, config: &Config) -> Option<Self> {
|
||||
match app::validate_time_format(&value) {
|
||||
Ok(()) => Some(Self::Formatted(value[1..].to_string())),
|
||||
_ => {
|
||||
config.print_warning(&format!("Not a valid date format: {}", value));
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a value from a [Yaml] string. The [Config] is used to log warnings about wrong values
|
||||
/// in a Yaml.
|
||||
fn from_yaml_string(value: &str, config: &Config) -> Option<Self> {
|
||||
match value {
|
||||
"date" => Some(Self::Date),
|
||||
"relative" => Some(Self::Relative),
|
||||
_ if value.starts_with('+') => Self::from_format_string(&value, &config),
|
||||
_ => {
|
||||
config.print_warning(&format!("Not a valid date value: {}", value));
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Configurable<Self> for DateFlag {
|
||||
/// Get a potential `DateFlag` variant from [ArgMatches].
|
||||
///
|
||||
/// If the "classic" argument is passed, then this returns the [DateFlag::Date] variant in a
|
||||
/// [Some]. Otherwise if the argument is passed, this returns the variant corresponding to its
|
||||
/// parameter in a [Some]. Otherwise this returns [None].
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
|
||||
if matches.is_present("classic") {
|
||||
Some(Self::Date)
|
||||
} else if matches.occurrences_of("date") > 0 {
|
||||
match matches.value_of("date") {
|
||||
Some("date") => Some(Self::Date),
|
||||
Some("relative") => Some(Self::Relative),
|
||||
Some(format) if format.starts_with('+') => {
|
||||
Some(Self::Formatted(format[1..].to_owned()))
|
||||
}
|
||||
_ => panic!("This should not be reachable!"),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a potential `DateFlag` variant from a [Config].
|
||||
///
|
||||
/// If the Config's [Yaml] contains a [Boolean](Yaml::Boolean) value pointed to by "classic"
|
||||
/// and its value is `true`, then this returns the [DateFlag::Date] variant in a [Some].
|
||||
/// Otherwise if the Yaml contains a [String](Yaml::String) value pointed to by "date" and it
|
||||
/// is one of "date" or "relative", this returns its corresponding variant in a [Some].
|
||||
/// Otherwise this returns [None].
|
||||
fn from_config(config: &Config) -> Option<Self> {
|
||||
if let Some(yaml) = &config.yaml {
|
||||
if let Yaml::Boolean(true) = &yaml["classic"] {
|
||||
Some(Self::Date)
|
||||
} else {
|
||||
match &yaml["date"] {
|
||||
Yaml::BadValue => None,
|
||||
Yaml::String(value) => Self::from_yaml_string(&value, &config),
|
||||
_ => {
|
||||
config.print_wrong_type_warning("date", "string");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The default value for `DateFlag` is [DateFlag::Date].
|
||||
impl Default for DateFlag {
|
||||
fn default() -> Self {
|
||||
Self::Date
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::DateFlag;
|
||||
|
||||
use crate::app;
|
||||
use crate::config_file::Config;
|
||||
use crate::flags::Configurable;
|
||||
|
||||
use yaml_rust::YamlLoader;
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_none() {
|
||||
let argv = vec!["lsd"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(None, DateFlag::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_date() {
|
||||
let argv = vec!["lsd", "--date", "date"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(Some(DateFlag::Date), DateFlag::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_relative() {
|
||||
let argv = vec!["lsd", "--date", "relative"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(DateFlag::Relative),
|
||||
DateFlag::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_format() {
|
||||
let argv = vec!["lsd", "--date", "+%F"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(DateFlag::Formatted("%F".to_string())),
|
||||
DateFlag::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "invalid format specifier: %J")]
|
||||
fn test_from_arg_matches_format_invalid() {
|
||||
let argv = vec!["lsd", "--date", "+%J"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
DateFlag::from_arg_matches(&matches);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_classic_mode() {
|
||||
let argv = vec!["lsd", "--date", "date", "--classic"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(Some(DateFlag::Date), DateFlag::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_none() {
|
||||
assert_eq!(None, DateFlag::from_config(&Config::with_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_empty() {
|
||||
let yaml_string = "---";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, DateFlag::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_date() {
|
||||
let yaml_string = "date: date";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(DateFlag::Date),
|
||||
DateFlag::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_relative() {
|
||||
let yaml_string = "date: relative";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(DateFlag::Relative),
|
||||
DateFlag::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_format() {
|
||||
let yaml_string = "date: +%F";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(DateFlag::Formatted("%F".to_string())),
|
||||
DateFlag::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_format_invalid() {
|
||||
let yaml_string = "date: +%J";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, DateFlag::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_classic_mode() {
|
||||
let yaml_string = "classic: true\ndate: relative";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(DateFlag::Date),
|
||||
DateFlag::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
}
|
107
src/flags/dereference.rs
Normal file
107
src/flags/dereference.rs
Normal file
|
@ -0,0 +1,107 @@
|
|||
//! This module defines the [Dereference] flag. To set it up from [ArgMatches], a [Yaml] and its
|
||||
//! [Default] value, use the [configure_from](Configurable::configure_from) method.
|
||||
|
||||
use super::Configurable;
|
||||
|
||||
use crate::config_file::Config;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
/// The flag showing whether to dereference symbolic links.
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq, Default)]
|
||||
pub struct Dereference(pub bool);
|
||||
|
||||
impl Configurable<Self> for Dereference {
|
||||
/// Get a potential `Dereference` value from [ArgMatches].
|
||||
///
|
||||
/// If the "dereference" argument is passed, this returns a `Dereference` with value `true` in
|
||||
/// a [Some]. Otherwise this returns [None].
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
|
||||
if matches.is_present("dereference") {
|
||||
Some(Self(true))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a potential `Dereference` value from a [Config].
|
||||
///
|
||||
/// If the Config's [Yaml] contains the [Boolean](Yaml::Boolean) value pointed to by
|
||||
/// "dereference", this returns its value as the value of the `Dereference`, in a [Some].
|
||||
/// Otherwise this returns [None].
|
||||
fn from_config(config: &Config) -> Option<Self> {
|
||||
if let Some(yaml) = &config.yaml {
|
||||
match &yaml["dereference"] {
|
||||
Yaml::BadValue => None,
|
||||
Yaml::Boolean(value) => Some(Self(*value)),
|
||||
_ => {
|
||||
config.print_wrong_type_warning("dereference", "boolean");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Dereference;
|
||||
|
||||
use crate::app;
|
||||
use crate::config_file::Config;
|
||||
use crate::flags::Configurable;
|
||||
|
||||
use yaml_rust::YamlLoader;
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_none() {
|
||||
let argv = vec!["lsd"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(None, Dereference::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_true() {
|
||||
let argv = vec!["lsd", "--dereference"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(Dereference(true)),
|
||||
Dereference::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_none() {
|
||||
assert_eq!(None, Dereference::from_config(&Config::with_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_empty() {
|
||||
let yaml_string = "---";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, Dereference::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_true() {
|
||||
let yaml_string = "dereference: true";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(Dereference(true)),
|
||||
Dereference::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_false() {
|
||||
let yaml_string = "dereference: false";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(Dereference(false)),
|
||||
Dereference::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
}
|
167
src/flags/display.rs
Normal file
167
src/flags/display.rs
Normal file
|
@ -0,0 +1,167 @@
|
|||
//! This module defines the [Display] flag. To set it up from [ArgMatches], a [Yaml] and its
|
||||
//! [Default] value, use its [configure_from](Configurable::configure_from) method.
|
||||
|
||||
use super::Configurable;
|
||||
|
||||
use crate::config_file::Config;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
/// The flag showing which file system nodes to display.
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum Display {
|
||||
All,
|
||||
AlmostAll,
|
||||
DirectoryItself,
|
||||
DisplayOnlyVisible,
|
||||
}
|
||||
|
||||
impl Display {
|
||||
/// Get a value from a [Yaml] string. The [Config] is used to log warnings about wrong values
|
||||
/// in a Yaml.
|
||||
fn from_yaml_string(value: &str, config: &Config) -> Option<Self> {
|
||||
match value {
|
||||
"all" => Some(Self::All),
|
||||
"almost-all" => Some(Self::AlmostAll),
|
||||
"directory-only" => Some(Self::DirectoryItself),
|
||||
_ => {
|
||||
config.print_invalid_value_warning("display", &value);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Configurable<Self> for Display {
|
||||
/// Get a potential `Display` variant from [ArgMatches].
|
||||
///
|
||||
/// If any of the "all", "almost-all" or "directory-only" arguments is passed, this returns the
|
||||
/// corresponding `Display` variant in a [Some]. If neither of them is passed, this returns
|
||||
/// [None].
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
|
||||
if matches.is_present("all") {
|
||||
Some(Self::All)
|
||||
} else if matches.is_present("almost-all") {
|
||||
Some(Self::AlmostAll)
|
||||
} else if matches.is_present("directory-only") {
|
||||
Some(Self::DirectoryItself)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a potential `Display` variant from a [Config].
|
||||
///
|
||||
/// If the Config's [Yaml] contains a [String](Yaml::String) value pointed to by "display" and
|
||||
/// it is either "all", "almost-all" or "directory-only", this returns the corresponding
|
||||
/// `Display` variant in a [Some]. Otherwise this returns [None].
|
||||
fn from_config(config: &Config) -> Option<Self> {
|
||||
if let Some(yaml) = &config.yaml {
|
||||
match &yaml["display"] {
|
||||
Yaml::BadValue => None,
|
||||
Yaml::String(value) => Self::from_yaml_string(&value, &config),
|
||||
_ => {
|
||||
config.print_wrong_type_warning("display", "string");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The default value for `Display` is [Display::DisplayOnlyVisible].
|
||||
impl Default for Display {
|
||||
fn default() -> Self {
|
||||
Self::DisplayOnlyVisible
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Display;
|
||||
|
||||
use crate::app;
|
||||
use crate::config_file::Config;
|
||||
use crate::flags::Configurable;
|
||||
|
||||
use yaml_rust::YamlLoader;
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_none() {
|
||||
let argv = vec!["lsd"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(None, Display::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_all() {
|
||||
let argv = vec!["lsd", "--all"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(Some(Display::All), Display::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_almost_all() {
|
||||
let argv = vec!["lsd", "--almost-all"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(Display::AlmostAll),
|
||||
Display::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_directory_only() {
|
||||
let argv = vec!["lsd", "--directory-only"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(Display::DirectoryItself),
|
||||
Display::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_none() {
|
||||
assert_eq!(None, Display::from_config(&Config::with_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_empty() {
|
||||
let yaml_string = "---";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, Display::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_all() {
|
||||
let yaml_string = "display: all";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(Display::All),
|
||||
Display::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_almost_all() {
|
||||
let yaml_string = "display: almost-all";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(Display::AlmostAll),
|
||||
Display::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_directory_only() {
|
||||
let yaml_string = "display: directory-only";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(Display::DirectoryItself),
|
||||
Display::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
}
|
356
src/flags/icons.rs
Normal file
356
src/flags/icons.rs
Normal file
|
@ -0,0 +1,356 @@
|
|||
//! This module defines the [IconOption]. To set it up from [ArgMatches], a [Yaml] and its
|
||||
//! [Default] value, use its [configure_from](Configurable::configure_from) method.
|
||||
|
||||
use super::Configurable;
|
||||
|
||||
use crate::config_file::Config;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
/// A collection of flags on how to use icons.
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq, Default)]
|
||||
pub struct Icons {
|
||||
/// When to use icons.
|
||||
pub when: IconOption,
|
||||
/// Which icon theme to use.
|
||||
pub theme: IconTheme,
|
||||
}
|
||||
|
||||
impl Icons {
|
||||
/// Get an `Icons` struct from [ArgMatches], a [Config] or the [Default] values.
|
||||
///
|
||||
/// The [IconOption] and [IconTheme] are configured with their respective [Configurable]
|
||||
/// implementation.
|
||||
pub fn configure_from(matches: &ArgMatches, config: &Config) -> Self {
|
||||
let when = IconOption::configure_from(matches, config);
|
||||
let theme = IconTheme::configure_from(matches, config);
|
||||
Self { when, theme }
|
||||
}
|
||||
}
|
||||
|
||||
/// The flag showing when to use icons in the output.
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum IconOption {
|
||||
Always,
|
||||
Auto,
|
||||
Never,
|
||||
}
|
||||
|
||||
impl IconOption {
|
||||
/// Get a value from a [Yaml] string. The [Config] is used to log warnings about wrong values
|
||||
/// in a Yaml.
|
||||
fn from_yaml_string(value: &str, config: &Config) -> Option<Self> {
|
||||
match value {
|
||||
"always" => Some(Self::Always),
|
||||
"auto" => Some(Self::Auto),
|
||||
"never" => Some(Self::Never),
|
||||
_ => {
|
||||
config.print_invalid_value_warning("icons->when", &value);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Configurable<Self> for IconOption {
|
||||
/// Get a potential `IconOption` variant from [ArgMatches].
|
||||
///
|
||||
/// If the "classic" argument is passed, then this returns the [IconOption::Never] variant in
|
||||
/// a [Some]. Otherwise if the argument is passed, this returns the variant corresponding to
|
||||
/// its parameter in a [Some]. Otherwise this returns [None].
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
|
||||
if matches.is_present("classic") {
|
||||
Some(Self::Never)
|
||||
} else if matches.occurrences_of("icon") > 0 {
|
||||
match matches.value_of("icon") {
|
||||
Some("always") => Some(Self::Always),
|
||||
Some("auto") => Some(Self::Auto),
|
||||
Some("never") => Some(Self::Never),
|
||||
_ => panic!("This should not be reachable!"),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a potential `IconOption` variant from a [Config].
|
||||
///
|
||||
/// If the Configs' [Yaml] contains a [Boolean](Yaml::Boolean) value pointed to by "classic"
|
||||
/// and its value is `true`, then this returns the [IconOption::Never] variant in a [Some].
|
||||
/// Otherwise if the Yaml contains a [String](Yaml::String) value pointed to by "icons" ->
|
||||
/// "when" and it is one of "always", "auto" or "never", this returns its corresponding variant
|
||||
/// in a [Some]. Otherwise this returns [None].
|
||||
fn from_config(config: &Config) -> Option<Self> {
|
||||
if let Some(yaml) = &config.yaml {
|
||||
if let Yaml::Boolean(true) = &yaml["classic"] {
|
||||
Some(Self::Never)
|
||||
} else {
|
||||
match &yaml["icons"]["when"] {
|
||||
Yaml::BadValue => None,
|
||||
Yaml::String(value) => Self::from_yaml_string(&value, &config),
|
||||
_ => {
|
||||
config.print_wrong_type_warning("icons->when", "string");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The default value for the `IconOption` is [IconOption::Auto].
|
||||
impl Default for IconOption {
|
||||
fn default() -> Self {
|
||||
Self::Auto
|
||||
}
|
||||
}
|
||||
|
||||
/// The flag showing which icon theme to use.
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum IconTheme {
|
||||
Unicode,
|
||||
Fancy,
|
||||
}
|
||||
|
||||
impl IconTheme {
|
||||
/// Get a value from a [Yaml] string. The [Config] is used to log warnings about wrong values
|
||||
/// in a Yaml.
|
||||
fn from_yaml_string(value: &str, config: &Config) -> Option<Self> {
|
||||
match value {
|
||||
"fancy" => Some(Self::Fancy),
|
||||
"unicode" => Some(Self::Unicode),
|
||||
_ => {
|
||||
config.print_invalid_value_warning("icons->theme", &value);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Configurable<Self> for IconTheme {
|
||||
/// Get a potential `IconTheme` variant from [ArgMatches].
|
||||
///
|
||||
/// If the argument is passed, this returns the variant corresponding to its parameter in a
|
||||
/// [Some]. Otherwise this returns [None].
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
|
||||
if matches.occurrences_of("icon-theme") > 0 {
|
||||
match matches.value_of("icon-theme") {
|
||||
Some("fancy") => Some(Self::Fancy),
|
||||
Some("unicode") => Some(Self::Unicode),
|
||||
_ => panic!("This should not be reachable!"),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a potential `IconTheme` variant from a [Config].
|
||||
///
|
||||
/// If the Config's [Yaml] contains a [String](Yaml::String) value pointed to by "icons" ->
|
||||
/// "theme" and it is one of "fancy" or "unicode", this returns its corresponding variant in a
|
||||
/// [Some]. Otherwise this returns [None].
|
||||
fn from_config(config: &Config) -> Option<Self> {
|
||||
if let Some(yaml) = &config.yaml {
|
||||
match &yaml["icons"]["theme"] {
|
||||
Yaml::BadValue => None,
|
||||
Yaml::String(value) => Self::from_yaml_string(&value, &config),
|
||||
_ => {
|
||||
config.print_wrong_type_warning("icons->theme", "string");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The default value for `IconTheme` is [IconTheme::Fancy].
|
||||
impl Default for IconTheme {
|
||||
fn default() -> Self {
|
||||
Self::Fancy
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_icon_option {
|
||||
use super::IconOption;
|
||||
|
||||
use crate::app;
|
||||
use crate::config_file::Config;
|
||||
use crate::flags::Configurable;
|
||||
|
||||
use yaml_rust::YamlLoader;
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_none() {
|
||||
let argv = vec!["lsd"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(None, IconOption::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_always() {
|
||||
let argv = vec!["lsd", "--icon", "always"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(IconOption::Always),
|
||||
IconOption::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_autp() {
|
||||
let argv = vec!["lsd", "--icon", "auto"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(IconOption::Auto),
|
||||
IconOption::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_never() {
|
||||
let argv = vec!["lsd", "--icon", "never"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(IconOption::Never),
|
||||
IconOption::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_classic_mode() {
|
||||
let argv = vec!["lsd", "--icon", "always", "--classic"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(IconOption::Never),
|
||||
IconOption::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_none() {
|
||||
assert_eq!(None, IconOption::from_config(&Config::with_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_empty() {
|
||||
let yaml_string = "---";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, IconOption::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_always() {
|
||||
let yaml_string = "icons:\n when: always";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(IconOption::Always),
|
||||
IconOption::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_auto() {
|
||||
let yaml_string = "icons:\n when: auto";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(IconOption::Auto),
|
||||
IconOption::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_never() {
|
||||
let yaml_string = "icons:\n when: never";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(IconOption::Never),
|
||||
IconOption::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_classic_mode() {
|
||||
let yaml_string = "classic: true\nicons:\n when: always";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(IconOption::Never),
|
||||
IconOption::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_icon_theme {
|
||||
use super::IconTheme;
|
||||
|
||||
use crate::app;
|
||||
use crate::config_file::Config;
|
||||
use crate::flags::Configurable;
|
||||
|
||||
use yaml_rust::YamlLoader;
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_none() {
|
||||
let argv = vec!["lsd"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(None, IconTheme::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_fancy() {
|
||||
let argv = vec!["lsd", "--icon-theme", "fancy"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(IconTheme::Fancy),
|
||||
IconTheme::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_unicode() {
|
||||
let argv = vec!["lsd", "--icon-theme", "unicode"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(IconTheme::Unicode),
|
||||
IconTheme::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_none() {
|
||||
assert_eq!(None, IconTheme::from_config(&Config::with_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_empty() {
|
||||
let yaml_string = "---";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, IconTheme::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_fancy() {
|
||||
let yaml_string = "icons:\n theme: fancy";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(IconTheme::Fancy),
|
||||
IconTheme::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_unicode() {
|
||||
let yaml_string = "icons:\n theme: unicode";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(IconTheme::Unicode),
|
||||
IconTheme::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
}
|
188
src/flags/ignore_globs.rs
Normal file
188
src/flags/ignore_globs.rs
Normal file
|
@ -0,0 +1,188 @@
|
|||
//! This module defines the [IgnoreGlobs]. To set it up from [ArgMatches], a [Yaml] and its
|
||||
//! [Default] value, use the [configure_from](IgnoreGlobs::configure_from) method.
|
||||
|
||||
use crate::config_file::Config;
|
||||
|
||||
use clap::{ArgMatches, Error, ErrorKind};
|
||||
use globset::{Glob, GlobSet, GlobSetBuilder};
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
/// The struct holding a [GlobSet] and methods to build it.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct IgnoreGlobs(pub GlobSet);
|
||||
|
||||
impl IgnoreGlobs {
|
||||
/// Returns a value from either [ArgMatches], a [Config] or a [Default] value. The first value
|
||||
/// that is not [None] is used. The order of precedence for the value used is:
|
||||
/// - [from_arg_matches](IgnoreGlobs::from_arg_matches)
|
||||
/// - [from_config](IgnoreGlobs::from_config)
|
||||
/// - [Default::default]
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The configuration file's Yaml is read in any case, to be able to check for errors and print
|
||||
/// out warnings.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If either of the [Glob::new] or [GlobSetBuilder.build] methods return an [Err].
|
||||
pub fn configure_from(matches: &ArgMatches, config: &Config) -> Result<Self, Error> {
|
||||
let mut result: Result<Self, Error> = Ok(Default::default());
|
||||
|
||||
if config.has_yaml() {
|
||||
if let Some(value) = Self::from_config(config) {
|
||||
match value {
|
||||
Ok(glob_set) => result = Ok(Self(glob_set)),
|
||||
Err(err) => result = Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(value) = Self::from_arg_matches(matches) {
|
||||
match value {
|
||||
Ok(glob_set) => result = Ok(Self(glob_set)),
|
||||
Err(err) => result = Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Get a potential [GlobSet] from [ArgMatches].
|
||||
///
|
||||
/// If the "ignore-glob" argument has been passed, this returns a [Result] in a [Some] with
|
||||
/// either the built [GlobSet] or an [Error], if any error was encountered while creating the
|
||||
/// [GlobSet]. If the argument has not been passed, this returns [None].
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Option<Result<GlobSet, Error>> {
|
||||
if matches.occurrences_of("ignore-glob") > 0 {
|
||||
if let Some(values) = matches.values_of("ignore-glob") {
|
||||
let mut glob_set_builder = GlobSetBuilder::new();
|
||||
for value in values {
|
||||
match Self::create_glob(value) {
|
||||
Ok(glob) => {
|
||||
glob_set_builder.add(glob);
|
||||
}
|
||||
Err(err) => return Some(Err(err)),
|
||||
}
|
||||
}
|
||||
Some(Self::create_glob_set(&glob_set_builder))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a potential [GlobSet] from a [Config].
|
||||
///
|
||||
/// If the Config's [Yaml] contains an [Array](Yaml::Array) value pointed to by "ignore-globs",
|
||||
/// each of its [String](Yaml::String) values is used to build the [GlobSet]. If the building
|
||||
/// succeeds, the [GlobSet] is returned in the [Result] in a [Some]. If any error is
|
||||
/// encountered while building, an [Error] is returned in the Result instead. If the Yaml does
|
||||
/// not contain such a key, this returns [None].
|
||||
fn from_config(config: &Config) -> Option<Result<GlobSet, Error>> {
|
||||
if let Some(yaml) = &config.yaml {
|
||||
match &yaml["ignore-globs"] {
|
||||
Yaml::BadValue => None,
|
||||
Yaml::Array(values) => {
|
||||
let mut glob_set_builder = GlobSetBuilder::new();
|
||||
for yaml_str in values.iter() {
|
||||
if let Yaml::String(value) = yaml_str {
|
||||
match Self::create_glob(value) {
|
||||
Ok(glob) => {
|
||||
glob_set_builder.add(glob);
|
||||
}
|
||||
Err(err) => return Some(Err(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(Self::create_glob_set(&glob_set_builder))
|
||||
}
|
||||
_ => {
|
||||
config.print_wrong_type_warning("ignore-globs", "string");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a [Glob] from a provided pattern.
|
||||
///
|
||||
/// This method is mainly a helper to wrap the handling of potential errors.
|
||||
fn create_glob(pattern: &str) -> Result<Glob, Error> {
|
||||
match Glob::new(pattern) {
|
||||
Ok(glob) => Ok(glob),
|
||||
Err(err) => Err(Error::with_description(
|
||||
&err.to_string(),
|
||||
ErrorKind::ValueValidation,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a [GlobSet] from a provided [GlobSetBuilder].
|
||||
///
|
||||
/// This method is mainly a helper to wrap the handling of potential errors.
|
||||
fn create_glob_set(builder: &GlobSetBuilder) -> Result<GlobSet, Error> {
|
||||
match builder.build() {
|
||||
Ok(glob_set) => Ok(glob_set),
|
||||
Err(err) => Err(Error::with_description(
|
||||
&err.to_string(),
|
||||
ErrorKind::ValueValidation,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The default value of `IgnoreGlobs` is the empty [GlobSet], returned by [GlobSet::empty()].
|
||||
impl Default for IgnoreGlobs {
|
||||
fn default() -> Self {
|
||||
Self(GlobSet::empty())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::IgnoreGlobs;
|
||||
|
||||
use crate::app;
|
||||
use crate::config_file::Config;
|
||||
|
||||
use yaml_rust::YamlLoader;
|
||||
|
||||
// The following tests are implemented using match expressions instead of the assert_eq macro,
|
||||
// because clap::Error does not implement PartialEq.
|
||||
//
|
||||
// Further no tests for actually returned GlobSets are implemented, because GlobSet does not
|
||||
// even implement PartialEq and thus can not be easily compared.
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_none() {
|
||||
let argv = vec!["lsd"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert!(match IgnoreGlobs::from_arg_matches(&matches) {
|
||||
None => true,
|
||||
_ => false,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_none() {
|
||||
assert!(match IgnoreGlobs::from_config(&Config::with_none()) {
|
||||
None => true,
|
||||
_ => false,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_empty() {
|
||||
let yaml_string = "---";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert!(match IgnoreGlobs::from_config(&Config::with_yaml(yaml)) {
|
||||
None => true,
|
||||
_ => false,
|
||||
});
|
||||
}
|
||||
}
|
107
src/flags/indicators.rs
Normal file
107
src/flags/indicators.rs
Normal file
|
@ -0,0 +1,107 @@
|
|||
//! This module defines the [Indicators] flag. To set it up from [ArgMatches], a [Yaml] and its
|
||||
//! [Default] value, use the [configure_from](Configurable::configure_from) method.
|
||||
|
||||
use super::Configurable;
|
||||
|
||||
use crate::config_file::Config;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
/// The flag showing whether to print file type indicators.
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq, Default)]
|
||||
pub struct Indicators(pub bool);
|
||||
|
||||
impl Configurable<Self> for Indicators {
|
||||
/// Get a potential `Indicators` value from [ArgMatches].
|
||||
///
|
||||
/// If the "indicators" argument is passed, this returns an `Indicators` with value `true` in a
|
||||
/// [Some]. Otherwise this returns [None].
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
|
||||
if matches.is_present("indicators") {
|
||||
Some(Self(true))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a potential `Indicators` value from a [Config].
|
||||
///
|
||||
/// If the Config's [Yaml] contains the [Boolean](Yaml::Boolean) value pointed to by
|
||||
/// "indicators", this returns its value as the value of the `Indicators`, in a [Some].
|
||||
/// Otherwise this returns [None].
|
||||
fn from_config(config: &Config) -> Option<Self> {
|
||||
if let Some(yaml) = &config.yaml {
|
||||
match &yaml["indicators"] {
|
||||
Yaml::BadValue => None,
|
||||
Yaml::Boolean(value) => Some(Self(*value)),
|
||||
_ => {
|
||||
config.print_wrong_type_warning("indicators", "boolean");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Indicators;
|
||||
|
||||
use crate::app;
|
||||
use crate::config_file::Config;
|
||||
use crate::flags::Configurable;
|
||||
|
||||
use yaml_rust::YamlLoader;
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_none() {
|
||||
let argv = vec!["lsd"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(None, Indicators::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_true() {
|
||||
let argv = vec!["lsd", "--classify"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(Indicators(true)),
|
||||
Indicators::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_none() {
|
||||
assert_eq!(None, Indicators::from_config(&Config::with_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_empty() {
|
||||
let yaml_string = "---";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, Indicators::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_true() {
|
||||
let yaml_string = "indicators: true";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(Indicators(true)),
|
||||
Indicators::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_false() {
|
||||
let yaml_string = "indicators: false";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(Indicators(false)),
|
||||
Indicators::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
}
|
163
src/flags/layout.rs
Normal file
163
src/flags/layout.rs
Normal file
|
@ -0,0 +1,163 @@
|
|||
//! This module defines the [Layout] flag. To set it up from [ArgMatches], a [Yaml] and its
|
||||
//! [Default] value, use its [configure_from](Configurable::configure_from) method.
|
||||
|
||||
use super::Configurable;
|
||||
|
||||
use crate::config_file::Config;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
/// The flag showing which output layout to print.
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum Layout {
|
||||
Grid,
|
||||
Tree,
|
||||
OneLine,
|
||||
}
|
||||
|
||||
impl Configurable<Layout> for Layout {
|
||||
/// Get a potential `Layout` variant from [ArgMatches].
|
||||
///
|
||||
/// If any of the "tree", "long" or "oneline" arguments is passed, this returns the
|
||||
/// corresponding `Layout` variant in a [Some]. Otherwise if the number of passed "blocks"
|
||||
/// arguments is greater than 1, this also returns the [OneLine](Layout::OneLine) variant.
|
||||
/// Finally if neither of them is passed, this returns [None].
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
|
||||
if matches.is_present("tree") {
|
||||
Some(Self::Tree)
|
||||
} else if matches.is_present("long")
|
||||
|| matches.is_present("oneline")
|
||||
|| matches.is_present("inode")
|
||||
|| matches!(matches.values_of("blocks"), Some(values) if values.len() > 1)
|
||||
// TODO: handle this differently
|
||||
{
|
||||
Some(Self::OneLine)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a potential Layout variant from a [Config].
|
||||
///
|
||||
/// If the Config's [Yaml] contains a [String](Yaml::String) value pointed to by "layout" and
|
||||
/// it is either "tree", "oneline" or "grid", this returns the corresponding `Layout` variant
|
||||
/// in a [Some]. Otherwise this returns [None].
|
||||
fn from_config(config: &Config) -> Option<Self> {
|
||||
if let Some(yaml) = &config.yaml {
|
||||
match &yaml["layout"] {
|
||||
Yaml::BadValue => None,
|
||||
Yaml::String(value) => match value.as_ref() {
|
||||
"tree" => Some(Self::Tree),
|
||||
"oneline" => Some(Self::OneLine),
|
||||
"grid" => Some(Self::Grid),
|
||||
_ => {
|
||||
config.print_invalid_value_warning("layout", &value);
|
||||
None
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
config.print_wrong_type_warning("layout", "string");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The default value for `Layout` is [Layout::Grid].
|
||||
impl Default for Layout {
|
||||
fn default() -> Self {
|
||||
Self::Grid
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Layout;
|
||||
|
||||
use crate::app;
|
||||
use crate::config_file::Config;
|
||||
use crate::flags::Configurable;
|
||||
|
||||
use yaml_rust::YamlLoader;
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_none() {
|
||||
let argv = vec!["lsd"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(None, Layout::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_tree() {
|
||||
let argv = vec!["lsd", "--tree"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(Some(Layout::Tree), Layout::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_oneline() {
|
||||
let argv = vec!["lsd", "--oneline"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(Some(Layout::OneLine), Layout::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_oneline_through_long() {
|
||||
let argv = vec!["lsd", "--long"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(Some(Layout::OneLine), Layout::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_oneline_through_blocks() {
|
||||
let argv = vec!["lsd", "--blocks", "permission,name"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(Some(Layout::OneLine), Layout::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_none() {
|
||||
assert_eq!(None, Layout::from_config(&Config::with_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_empty() {
|
||||
let yaml_string = "---";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, Layout::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_tree() {
|
||||
let yaml_string = "layout: tree";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(Layout::Tree),
|
||||
Layout::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_oneline() {
|
||||
let yaml_string = "layout: oneline";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(Layout::OneLine),
|
||||
Layout::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_grid() {
|
||||
let yaml_string = "layout: grid";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(Layout::Grid),
|
||||
Layout::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
}
|
337
src/flags/recursion.rs
Normal file
337
src/flags/recursion.rs
Normal file
|
@ -0,0 +1,337 @@
|
|||
//! This module defines the [Recursion] options. To set it up from [ArgMatches], a [Yaml] and its
|
||||
//! [Default] value, use the [configure_from](Recursion::configure_from) method.
|
||||
|
||||
use crate::config_file::Config;
|
||||
|
||||
use clap::{ArgMatches, Error, ErrorKind};
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
/// The options relating to recursion.
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub struct Recursion {
|
||||
/// Whether the recursion into directories is enabled.
|
||||
pub enabled: bool,
|
||||
/// The depth for how far to recurse into directories.
|
||||
pub depth: usize,
|
||||
}
|
||||
|
||||
impl Recursion {
|
||||
/// Get the Recursion from either [ArgMatches], a [Config] or the [Default] value.
|
||||
///
|
||||
/// The "enabled" value is determined by [enabled_from](Recursion::enabled_from) and the depth
|
||||
/// value is determined by [depth_from](Recursion::depth_from).
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If [depth_from](Recursion::depth_from) returns an [Error], this returns it.
|
||||
pub fn configure_from(matches: &ArgMatches, config: &Config) -> Result<Self, Error> {
|
||||
let enabled = Self::enabled_from(matches, config);
|
||||
let depth = Self::depth_from(matches, config)?;
|
||||
Ok(Self { enabled, depth })
|
||||
}
|
||||
|
||||
/// Get the "enabled" boolean from [ArgMatches], a [Config] or the [Default] value. The first
|
||||
/// value that is not [None] is used. The order of precedence for the value used is:
|
||||
/// - [enabled_from_arg_matches](Recursion::enabled_from_arg_matches)
|
||||
/// - [enabled_from_config](Recursion::enabled_from_config)
|
||||
/// - [Default::default]
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The configuration file's Yaml is read in any case, to be able to check for errors and print
|
||||
/// out warnings.
|
||||
fn enabled_from(matches: &ArgMatches, config: &Config) -> bool {
|
||||
let mut result: bool = Default::default();
|
||||
|
||||
if config.has_yaml() {
|
||||
if let Some(value) = Self::enabled_from_config(config) {
|
||||
result = value;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(value) = Self::enabled_from_arg_matches(matches) {
|
||||
result = value;
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Get a potential "enabled" boolean from [ArgMatches].
|
||||
///
|
||||
/// If the "recursive" argument is passed, this returns `true` in a [Some]. Otherwise this
|
||||
/// returns [None].
|
||||
fn enabled_from_arg_matches(matches: &ArgMatches) -> Option<bool> {
|
||||
if matches.is_present("recursive") {
|
||||
Some(true)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a potential "enabled" boolean from a [Config].
|
||||
///
|
||||
/// If the Config's [Yaml] contains a [Boolean](Yaml::Boolean) value pointed to by "recursion"
|
||||
/// -> "enabled", this returns its value in a [Some]. Otherwise this returns [None].
|
||||
fn enabled_from_config(config: &Config) -> Option<bool> {
|
||||
if let Some(yaml) = &config.yaml {
|
||||
match &yaml["recursion"]["enabled"] {
|
||||
Yaml::BadValue => None,
|
||||
Yaml::Boolean(value) => Some(*value),
|
||||
_ => {
|
||||
config.print_wrong_type_warning("recursion->enabled", "boolean");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the "depth" integer from [ArgMatches], a [Config] or the [Default] value. The first
|
||||
/// value that is not [None] is used. The order of precedence for the value used is:
|
||||
/// - [depth_from_arg_matches](Recursion::depth_from_arg_matches)
|
||||
/// - [depth_from_config](Recursion::depth_from_config)
|
||||
/// - [Default::default]
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The configuration file's Yaml is read in any case, to be able to check for errors and print
|
||||
/// out warnings.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If [depth_from_arg_matches](Recursion::depth_from_arg_matches) returns an [Error], this
|
||||
/// returns it.
|
||||
fn depth_from(matches: &ArgMatches, config: &Config) -> Result<usize, Error> {
|
||||
let mut result: Result<usize, Error> = Ok(usize::max_value());
|
||||
|
||||
if config.has_yaml() {
|
||||
if let Some(value) = Self::depth_from_config(config) {
|
||||
result = Ok(value);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(value) = Self::depth_from_arg_matches(matches) {
|
||||
result = value;
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Get a potential "depth" value from [ArgMatches].
|
||||
///
|
||||
/// If the "depth" argument is passed, its parameter is evaluated. If it can be parsed into a
|
||||
/// [usize], the [Result] is returned in the [Some]. If it can not be parsed an [Error] is
|
||||
/// returned in the [Some]. If the argument has not been passed, a [None] is returned.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If the parameter to the "depth" argument can not be parsed, this returns an [Error] in a
|
||||
/// [Some].
|
||||
fn depth_from_arg_matches(matches: &ArgMatches) -> Option<Result<usize, Error>> {
|
||||
if let Some(str) = matches.value_of("depth") {
|
||||
match str.parse::<usize>() {
|
||||
Ok(value) => return Some(Ok(value)),
|
||||
Err(_) => {
|
||||
return Some(Err(Error::with_description(
|
||||
"The argument '--depth' requires a valid positive number.",
|
||||
ErrorKind::ValueValidation,
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Get a potential "depth" value from a [Config].
|
||||
///
|
||||
/// If the Config's [Yaml] contains a positive [Integer](Yaml::Integer) value pointed to by
|
||||
/// "recursion" -> "depth", this returns its value in a [Some]. Otherwise this returns [None].
|
||||
fn depth_from_config(config: &Config) -> Option<usize> {
|
||||
if let Some(yaml) = &config.yaml {
|
||||
match &yaml["recursion"]["depth"] {
|
||||
Yaml::BadValue => None,
|
||||
Yaml::Integer(value) => {
|
||||
if *value > 0 {
|
||||
Some(*value as usize)
|
||||
} else {
|
||||
config.print_warning(
|
||||
"The recursion->depth value has to be greater than zero.",
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
config.print_wrong_type_warning("recursion->depth", "integer");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The default values for `Recursion` are the boolean default and [prim@usize::max_value()].
|
||||
impl Default for Recursion {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
depth: usize::max_value(),
|
||||
enabled: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Recursion;
|
||||
|
||||
use crate::app;
|
||||
use crate::config_file::Config;
|
||||
|
||||
use clap::ErrorKind;
|
||||
use yaml_rust::YamlLoader;
|
||||
|
||||
#[test]
|
||||
fn test_enabled_from_arg_matches_none() {
|
||||
let argv = vec!["lsd"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(None, Recursion::enabled_from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enabled_from_arg_matches_true() {
|
||||
let argv = vec!["lsd", "--recursive"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(Some(true), Recursion::enabled_from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enabled_from_config_none() {
|
||||
assert_eq!(None, Recursion::enabled_from_config(&Config::with_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enabled_from_config_empty() {
|
||||
let yaml_string = "---";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
None,
|
||||
Recursion::enabled_from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enabled_from_config_true() {
|
||||
let yaml_string = "recursion:\n enabled: true";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(true),
|
||||
Recursion::enabled_from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enabled_from_config_false() {
|
||||
let yaml_string = "recursion:\n enabled: false";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(false),
|
||||
Recursion::enabled_from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
// The following depth_from_arg_matches tests are implemented using match expressions instead
|
||||
// of the assert_eq macro, because clap::Error does not implement PartialEq.
|
||||
|
||||
#[test]
|
||||
fn test_depth_from_arg_matches_none() {
|
||||
let argv = vec!["lsd"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert!(match Recursion::depth_from_arg_matches(&matches) {
|
||||
None => true,
|
||||
_ => false,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_depth_from_arg_matches_integer() {
|
||||
let argv = vec!["lsd", "--depth", "42"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert!(match Recursion::depth_from_arg_matches(&matches) {
|
||||
None => false,
|
||||
Some(result) => {
|
||||
match result {
|
||||
Ok(value) => value == 42,
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_depth_from_arg_matches_neg_int() {
|
||||
let argv = vec!["lsd", "--depth", "\\-42"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert!(match Recursion::depth_from_arg_matches(&matches) {
|
||||
None => false,
|
||||
Some(result) => {
|
||||
match result {
|
||||
Ok(_) => false,
|
||||
Err(error) => error.kind == ErrorKind::ValueValidation,
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_depth_from_arg_matches_non_int() {
|
||||
let argv = vec!["lsd", "--depth", "foo"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert!(match Recursion::depth_from_arg_matches(&matches) {
|
||||
None => false,
|
||||
Some(result) => {
|
||||
match result {
|
||||
Ok(_) => false,
|
||||
Err(error) => error.kind == ErrorKind::ValueValidation,
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_depth_from_config_none() {
|
||||
assert_eq!(None, Recursion::depth_from_config(&Config::with_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_depth_from_config_empty() {
|
||||
let yaml_string = "---";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, Recursion::depth_from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_depth_from_config_pos_integer() {
|
||||
let yaml_string = "recursion:\n depth: 42";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(42),
|
||||
Recursion::depth_from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_depth_from_config_neg_integer() {
|
||||
let yaml_string = "recursion:\n depth: -42";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, Recursion::depth_from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_depth_from_config_string() {
|
||||
let yaml_string = "recursion:\n depth: foo";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, Recursion::depth_from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
}
|
159
src/flags/size.rs
Normal file
159
src/flags/size.rs
Normal file
|
@ -0,0 +1,159 @@
|
|||
//! This module defines the [SizeFlag]. To set it up from [ArgMatches], a [Yaml] and its
|
||||
//! [Default] value, use its [configure_from](Configurable::configure_from) method.
|
||||
|
||||
use super::Configurable;
|
||||
|
||||
use crate::config_file::Config;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
/// The flag showing which file size units to use.
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum SizeFlag {
|
||||
/// The variant to show file size with SI unit prefix and a B for bytes.
|
||||
Default,
|
||||
/// The variant to show file size with only the SI unit prefix.
|
||||
Short,
|
||||
/// The variant to show file size in bytes.
|
||||
Bytes,
|
||||
}
|
||||
|
||||
impl Configurable<Self> for SizeFlag {
|
||||
/// Get a potential `SizeFlag` variant from [ArgMatches].
|
||||
///
|
||||
/// If any of the "default", "short" or "bytes" arguments is passed, the corresponding
|
||||
/// `SizeFlag` variant is returned in a [Some]. If neither of them is passed, this returns
|
||||
/// [None].
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
|
||||
if matches.occurrences_of("size") > 0 {
|
||||
match matches.value_of("size") {
|
||||
Some("default") => Some(Self::Default),
|
||||
Some("short") => Some(Self::Short),
|
||||
Some("bytes") => Some(Self::Bytes),
|
||||
_ => panic!("This should not be reachable!"),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a potential `SizeFlag` variant from a [Config].
|
||||
///
|
||||
/// If the Config's [Yaml] contains a [String](Yaml::String) value, pointed to by "size" and it
|
||||
/// is either "default", "short" or "bytes", this returns the corresponding `SizeFlag` variant
|
||||
/// in a [Some]. Otherwise this returns [None].
|
||||
fn from_config(config: &Config) -> Option<Self> {
|
||||
if let Some(yaml) = &config.yaml {
|
||||
match &yaml["size"] {
|
||||
Yaml::BadValue => None,
|
||||
Yaml::String(value) => match value.as_ref() {
|
||||
"default" => Some(Self::Default),
|
||||
"short" => Some(Self::Short),
|
||||
"bytes" => Some(Self::Bytes),
|
||||
_ => {
|
||||
config.print_invalid_value_warning("size", &value);
|
||||
None
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
config.print_wrong_type_warning("size", "string");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The default value for `SizeFlag` is [SizeFlag::Default].
|
||||
impl Default for SizeFlag {
|
||||
fn default() -> Self {
|
||||
Self::Default
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::SizeFlag;
|
||||
|
||||
use crate::app;
|
||||
use crate::config_file::Config;
|
||||
use crate::flags::Configurable;
|
||||
|
||||
use yaml_rust::YamlLoader;
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_none() {
|
||||
let argv = vec!["lsd"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(None, SizeFlag::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_default() {
|
||||
let argv = vec!["lsd", "--size", "default"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(SizeFlag::Default),
|
||||
SizeFlag::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_short() {
|
||||
let args = vec!["lsd", "--size", "short"];
|
||||
let matches = app::build().get_matches_from_safe(args).unwrap();
|
||||
assert_eq!(Some(SizeFlag::Short), SizeFlag::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_bytes() {
|
||||
let args = vec!["lsd", "--size", "bytes"];
|
||||
let matches = app::build().get_matches_from_safe(args).unwrap();
|
||||
assert_eq!(Some(SizeFlag::Bytes), SizeFlag::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_none() {
|
||||
assert_eq!(None, SizeFlag::from_config(&Config::with_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_empty() {
|
||||
let yaml_string = "---";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, SizeFlag::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_default() {
|
||||
let yaml_string = "size: default";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(SizeFlag::Default),
|
||||
SizeFlag::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_short() {
|
||||
let yaml_string = "size: short";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(SizeFlag::Short),
|
||||
SizeFlag::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_bytes() {
|
||||
let yaml_string = "size: bytes";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(SizeFlag::Bytes),
|
||||
SizeFlag::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
}
|
523
src/flags/sorting.rs
Normal file
523
src/flags/sorting.rs
Normal file
|
@ -0,0 +1,523 @@
|
|||
//! This module defines the [Sorting] options. To set it up from [ArgMatches], a [Yaml]
|
||||
//! and its [Default] value, use the [configure_from](Sorting::configure_from) method.
|
||||
|
||||
use super::Configurable;
|
||||
|
||||
use crate::config_file::Config;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
/// A collection of flags on how to sort the output.
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq, Default)]
|
||||
pub struct Sorting {
|
||||
pub column: SortColumn,
|
||||
pub order: SortOrder,
|
||||
pub dir_grouping: DirGrouping,
|
||||
}
|
||||
|
||||
impl Sorting {
|
||||
/// Get a `Sorting` struct from [ArgMatches], a [Config] or the [Default] values.
|
||||
///
|
||||
/// The [SortColumn], [SortOrder] and [DirGrouping] are configured with their respective
|
||||
/// [Configurable] implementation.
|
||||
pub fn configure_from(matches: &ArgMatches, config: &Config) -> Self {
|
||||
let column = SortColumn::configure_from(matches, config);
|
||||
let order = SortOrder::configure_from(matches, config);
|
||||
let dir_grouping = DirGrouping::configure_from(matches, config);
|
||||
Self {
|
||||
column,
|
||||
order,
|
||||
dir_grouping,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The flag showing which column to use for sorting.
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum SortColumn {
|
||||
Extension,
|
||||
Name,
|
||||
Time,
|
||||
Size,
|
||||
Version,
|
||||
}
|
||||
|
||||
impl Configurable<Self> for SortColumn {
|
||||
/// Get a potential `SortColumn` variant from [ArgMatches].
|
||||
///
|
||||
/// If either the "timesort" or "sizesort" arguments are passed, this returns the corresponding
|
||||
/// `SortColumn` variant in a [Some]. Otherwise this returns [None].
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
|
||||
if matches.is_present("timesort") {
|
||||
Some(Self::Time)
|
||||
} else if matches.is_present("sizesort") {
|
||||
Some(Self::Size)
|
||||
} else if matches.is_present("extensionsort") {
|
||||
Some(Self::Extension)
|
||||
} else if matches.is_present("versionsort") {
|
||||
Some(Self::Version)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a potential `SortColumn` variant from a [Config].
|
||||
///
|
||||
/// If the Config's [Yaml] contains a [String](Yaml::String) value pointed to by "sorting" ->
|
||||
/// "column" and it is one of "time", "size" or "name", this returns the corresponding variant
|
||||
/// in a [Some]. Otherwise this returns [None].
|
||||
fn from_config(config: &Config) -> Option<Self> {
|
||||
if let Some(yaml) = &config.yaml {
|
||||
match &yaml["sorting"]["column"] {
|
||||
Yaml::BadValue => None,
|
||||
Yaml::String(value) => match value.as_ref() {
|
||||
"extension" => Some(Self::Extension),
|
||||
"name" => Some(Self::Name),
|
||||
"time" => Some(Self::Time),
|
||||
"size" => Some(Self::Size),
|
||||
"version" => Some(Self::Version),
|
||||
_ => {
|
||||
config.print_invalid_value_warning("sorting->column", &value);
|
||||
None
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
config.print_wrong_type_warning("sorting->column", "string");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The default value for `SortColumn` is [SortColumn::Name].
|
||||
impl Default for SortColumn {
|
||||
fn default() -> Self {
|
||||
Self::Name
|
||||
}
|
||||
}
|
||||
|
||||
/// The flag showing which sort order to use.
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum SortOrder {
|
||||
Default,
|
||||
Reverse,
|
||||
}
|
||||
|
||||
impl Configurable<Self> for SortOrder {
|
||||
/// Get a potential `SortOrder` variant from [ArgMatches].
|
||||
///
|
||||
/// If the "reverse" argument is passed, this returns [SortOrder::Reverse] in a [Some].
|
||||
/// Otherwise this returns [None].
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
|
||||
if matches.is_present("reverse") {
|
||||
Some(Self::Reverse)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a potential `SortOrder` variant from a [Config].
|
||||
///
|
||||
/// If the Config's [Yaml] contains a [Boolean](Yaml::Boolean) value pointed to by "sorting" ->
|
||||
/// "reverse", this returns a mapped variant in a [Some]. Otherwise [None] is returned. A
|
||||
/// `true` maps to [SortOrder::Reverse] and a `false` maps to [SortOrder::Default].
|
||||
fn from_config(config: &Config) -> Option<Self> {
|
||||
if let Some(yaml) = &config.yaml {
|
||||
match &yaml["sorting"]["reverse"] {
|
||||
Yaml::BadValue => None,
|
||||
Yaml::Boolean(value) => {
|
||||
if *value {
|
||||
Some(Self::Reverse)
|
||||
} else {
|
||||
Some(Self::Default)
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
config.print_wrong_type_warning("sorting->reverse", "boolean");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The default value for `SortOrder` is [SortOrder::Default].
|
||||
impl Default for SortOrder {
|
||||
fn default() -> Self {
|
||||
Self::Default
|
||||
}
|
||||
}
|
||||
|
||||
/// The flag showing where to place directories.
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum DirGrouping {
|
||||
None,
|
||||
First,
|
||||
Last,
|
||||
}
|
||||
|
||||
impl Configurable<Self> for DirGrouping {
|
||||
/// Get a potential `DirGrouping` variant from [ArgMatches].
|
||||
///
|
||||
/// If the "classic" argument is passed, then this returns the [DirGrouping::None] variant in a
|
||||
/// [Some]. Otherwise if the argument is passed, this returns the variant corresponding to its
|
||||
/// parameter in a [Some]. Otherwise this returns [None].
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
|
||||
if matches.is_present("classic") {
|
||||
Some(Self::None)
|
||||
} else if matches.occurrences_of("group-dirs") > 0 {
|
||||
match matches.value_of("group-dirs") {
|
||||
Some("first") => Some(Self::First),
|
||||
Some("last") => Some(Self::Last),
|
||||
Some("none") => Some(Self::None),
|
||||
_ => panic!("This should not be reachable!"),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a potential `DirGrouping` variant from a [Config].
|
||||
///
|
||||
/// If the Config's [Yaml] contains a [Boolean](Yaml::Boolean) value pointed to by "classic"
|
||||
/// and its value is `true`, then this returns the the [DirGrouping::None] variant in a [Some].
|
||||
/// Otherwise if the Yaml contains a [String](Yaml::String) value pointed to by "sorting" ->
|
||||
/// "dir-grouping" and it is one of "first", "last" or "none", this returns its corresponding
|
||||
/// variant in a [Some]. Otherwise this returns [None].
|
||||
fn from_config(config: &Config) -> Option<Self> {
|
||||
if let Some(yaml) = &config.yaml {
|
||||
if let Yaml::Boolean(true) = &yaml["classic"] {
|
||||
Some(Self::None)
|
||||
} else {
|
||||
match &yaml["sorting"]["dir-grouping"] {
|
||||
Yaml::BadValue => None,
|
||||
Yaml::String(value) => match value.as_ref() {
|
||||
"first" => Some(Self::First),
|
||||
"last" => Some(Self::Last),
|
||||
"none" => Some(Self::None),
|
||||
_ => {
|
||||
config.print_invalid_value_warning("sorting->dir-grouping", &value);
|
||||
None
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
config.print_wrong_type_warning("sorting->dir-grouping", "string");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The default value for `DirGrouping` is [DirGrouping::None].
|
||||
impl Default for DirGrouping {
|
||||
fn default() -> Self {
|
||||
Self::None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_sort_column {
|
||||
use super::SortColumn;
|
||||
|
||||
use crate::app;
|
||||
use crate::config_file::Config;
|
||||
use crate::flags::Configurable;
|
||||
|
||||
use yaml_rust::YamlLoader;
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_none() {
|
||||
let argv = vec!["lsd"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(None, SortColumn::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_extension() {
|
||||
let argv = vec!["lsd", "--extensionsort"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(SortColumn::Extension),
|
||||
SortColumn::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_time() {
|
||||
let argv = vec!["lsd", "--timesort"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(SortColumn::Time),
|
||||
SortColumn::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_size() {
|
||||
let argv = vec!["lsd", "--sizesort"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(SortColumn::Size),
|
||||
SortColumn::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_version() {
|
||||
let argv = vec!["lsd", "--versionsort"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(SortColumn::Version),
|
||||
SortColumn::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_none() {
|
||||
assert_eq!(None, SortColumn::from_config(&Config::with_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_empty() {
|
||||
let yaml_string = "---";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, SortColumn::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_invalid() {
|
||||
let yaml_string = "sorting:\n column: foo";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, SortColumn::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_extension() {
|
||||
let yaml_string = "sorting:\n column: extension";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(SortColumn::Extension),
|
||||
SortColumn::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_name() {
|
||||
let yaml_string = "sorting:\n column: name";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(SortColumn::Name),
|
||||
SortColumn::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_time() {
|
||||
let yaml_string = "sorting:\n column: time";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(SortColumn::Time),
|
||||
SortColumn::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_size() {
|
||||
let yaml_string = "sorting:\n column: size";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(SortColumn::Size),
|
||||
SortColumn::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_version() {
|
||||
let yaml_string = "sorting:\n column: version";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(SortColumn::Version),
|
||||
SortColumn::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_sort_order {
|
||||
use super::SortOrder;
|
||||
|
||||
use crate::app;
|
||||
use crate::config_file::Config;
|
||||
use crate::flags::Configurable;
|
||||
|
||||
use yaml_rust::YamlLoader;
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_none() {
|
||||
let argv = vec!["lsd"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(None, SortOrder::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_reverse() {
|
||||
let argv = vec!["lsd", "--reverse"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(SortOrder::Reverse),
|
||||
SortOrder::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_none() {
|
||||
assert_eq!(None, SortOrder::from_config(&Config::with_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_empty() {
|
||||
let yaml_string = "---";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, SortOrder::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_default() {
|
||||
let yaml_string = "sorting:\n reverse: false";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(SortOrder::Default),
|
||||
SortOrder::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_reverse() {
|
||||
let yaml_string = "sorting:\n reverse: true";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(SortOrder::Reverse),
|
||||
SortOrder::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_dir_grouping {
|
||||
use super::DirGrouping;
|
||||
|
||||
use crate::app;
|
||||
use crate::config_file::Config;
|
||||
use crate::flags::Configurable;
|
||||
|
||||
use yaml_rust::YamlLoader;
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_none() {
|
||||
let argv = vec!["lsd"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(None, DirGrouping::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_first() {
|
||||
let argv = vec!["lsd", "--group-dirs", "first"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(DirGrouping::First),
|
||||
DirGrouping::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_last() {
|
||||
let argv = vec!["lsd", "--group-dirs", "last"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(DirGrouping::Last),
|
||||
DirGrouping::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_explicit_none() {
|
||||
let argv = vec!["lsd", "--group-dirs", "none"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(DirGrouping::None),
|
||||
DirGrouping::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_classic_mode() {
|
||||
let argv = vec!["lsd", "--group-dirs", "first", "--classic"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(DirGrouping::None),
|
||||
DirGrouping::from_arg_matches(&matches)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_none() {
|
||||
assert_eq!(None, DirGrouping::from_config(&Config::with_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_empty() {
|
||||
let yaml_string = "---";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, DirGrouping::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_first() {
|
||||
let yaml_string = "sorting:\n dir-grouping: first";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(DirGrouping::First),
|
||||
DirGrouping::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_last() {
|
||||
let yaml_string = "sorting:\n dir-grouping: last";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(DirGrouping::Last),
|
||||
DirGrouping::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_explicit_none() {
|
||||
let yaml_string = "sorting:\n dir-grouping: none";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(DirGrouping::None),
|
||||
DirGrouping::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_classic_mode() {
|
||||
let yaml_string = "classic: true\nsorting:\n dir-grouping: first";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(DirGrouping::None),
|
||||
DirGrouping::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
}
|
104
src/flags/symlinks.rs
Normal file
104
src/flags/symlinks.rs
Normal file
|
@ -0,0 +1,104 @@
|
|||
//! This module defines the [NoSymlink] flag. To set it up from [ArgMatches], a [Yaml] and its
|
||||
//! [Default] value, use the [configure_from](Configurable::configure_from) method.
|
||||
|
||||
use super::Configurable;
|
||||
|
||||
use crate::config_file::Config;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
/// The flag showing whether to follow symbolic links.
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq, Default)]
|
||||
pub struct NoSymlink(pub bool);
|
||||
|
||||
impl Configurable<Self> for NoSymlink {
|
||||
/// Get a potential `NoSymlink` value from [ArgMatches].
|
||||
///
|
||||
/// If the "no-symlink" argument is passed, this returns a `NoSymlink` with value `true` in a
|
||||
/// [Some]. Otherwise this returns [None].
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
|
||||
if matches.is_present("no-symlink") {
|
||||
Some(Self(true))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a potential `NoSymlink` value from a [Config].
|
||||
///
|
||||
/// If the Config's [Yaml] contains the [Boolean](Yaml::Boolean) value pointed to by
|
||||
/// "no-symlink", this returns its value as the value of the `NoSymlink`, in a [Some].
|
||||
/// Otherwise this returns [None].
|
||||
fn from_config(config: &Config) -> Option<Self> {
|
||||
if let Some(yaml) = &config.yaml {
|
||||
match &yaml["no-symlink"] {
|
||||
Yaml::BadValue => None,
|
||||
Yaml::Boolean(value) => Some(Self(*value)),
|
||||
_ => {
|
||||
config.print_wrong_type_warning("no-symlink", "boolean");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::NoSymlink;
|
||||
|
||||
use crate::app;
|
||||
use crate::config_file::Config;
|
||||
use crate::flags::Configurable;
|
||||
|
||||
use yaml_rust::YamlLoader;
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_none() {
|
||||
let argv = vec!["lsd"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(None, NoSymlink::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_true() {
|
||||
let argv = vec!["lsd", "--no-symlink"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(Some(NoSymlink(true)), NoSymlink::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_none() {
|
||||
assert_eq!(None, NoSymlink::from_config(&Config::with_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_empty() {
|
||||
let yaml_string = "---";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, NoSymlink::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_true() {
|
||||
let yaml_string = "no-symlink: true";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(NoSymlink(true)),
|
||||
NoSymlink::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_false() {
|
||||
let yaml_string = "no-symlink: false";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(NoSymlink(false)),
|
||||
NoSymlink::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
}
|
104
src/flags/total_size.rs
Normal file
104
src/flags/total_size.rs
Normal file
|
@ -0,0 +1,104 @@
|
|||
//! This module defines the [TotalSize] flag. To set it up from [ArgMatches], a [Yaml] and its
|
||||
//! [Default] value, use the [configure_from](Configurable::configure_from) method.
|
||||
|
||||
use super::Configurable;
|
||||
|
||||
use crate::config_file::Config;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use yaml_rust::Yaml;
|
||||
|
||||
/// The flag showing whether to show the total size for directories.
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq, Default)]
|
||||
pub struct TotalSize(pub bool);
|
||||
|
||||
impl Configurable<Self> for TotalSize {
|
||||
/// Get a potential `TotalSize` value from [ArgMatches].
|
||||
///
|
||||
/// If the "total-size" argument is passed, this returns a `TotalSize` with value `true` in a
|
||||
/// [Some]. Otherwise this returns [None].
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Option<Self> {
|
||||
if matches.is_present("total-size") {
|
||||
Some(Self(true))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a potential `TotalSize` value from a [Config].
|
||||
///
|
||||
/// If the Config's [Yaml] contains the [Boolean](Yaml::Boolean) value pointed to by
|
||||
/// "total-size", this returns its value as the value of the `TotalSize`, in a [Some].
|
||||
/// Otherwise this returns [None].
|
||||
fn from_config(config: &Config) -> Option<Self> {
|
||||
if let Some(yaml) = &config.yaml {
|
||||
match &yaml["total-size"] {
|
||||
Yaml::BadValue => None,
|
||||
Yaml::Boolean(value) => Some(Self(*value)),
|
||||
_ => {
|
||||
config.print_wrong_type_warning("total-size", "boolean");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::TotalSize;
|
||||
|
||||
use crate::app;
|
||||
use crate::config_file::Config;
|
||||
use crate::flags::Configurable;
|
||||
|
||||
use yaml_rust::YamlLoader;
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_none() {
|
||||
let argv = vec!["lsd"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(None, TotalSize::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_arg_matches_true() {
|
||||
let argv = vec!["lsd", "--total-size"];
|
||||
let matches = app::build().get_matches_from_safe(argv).unwrap();
|
||||
assert_eq!(Some(TotalSize(true)), TotalSize::from_arg_matches(&matches));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_none() {
|
||||
assert_eq!(None, TotalSize::from_config(&Config::with_none()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_empty() {
|
||||
let yaml_string = "---";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(None, TotalSize::from_config(&Config::with_yaml(yaml)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_true() {
|
||||
let yaml_string = "total-size: true";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(TotalSize(true)),
|
||||
TotalSize::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_config_false() {
|
||||
let yaml_string = "total-size: false";
|
||||
let yaml = YamlLoader::load_from_str(yaml_string).unwrap()[0].clone();
|
||||
assert_eq!(
|
||||
Some(TotalSize(false)),
|
||||
TotalSize::from_config(&Config::with_yaml(yaml))
|
||||
);
|
||||
}
|
||||
}
|
12
src/main.rs
12
src/main.rs
|
@ -9,6 +9,7 @@
|
|||
extern crate clap;
|
||||
extern crate ansi_term;
|
||||
extern crate chrono_humanize;
|
||||
extern crate dirs;
|
||||
extern crate libc;
|
||||
extern crate lscolors;
|
||||
#[cfg(test)]
|
||||
|
@ -18,6 +19,8 @@ extern crate terminal_size;
|
|||
extern crate time;
|
||||
extern crate unicode_width;
|
||||
extern crate wild;
|
||||
extern crate xdg;
|
||||
extern crate yaml_rust;
|
||||
|
||||
#[cfg(unix)]
|
||||
extern crate users;
|
||||
|
@ -27,6 +30,7 @@ extern crate winapi;
|
|||
|
||||
mod app;
|
||||
mod color;
|
||||
mod config_file;
|
||||
mod core;
|
||||
mod display;
|
||||
mod flags;
|
||||
|
@ -34,6 +38,7 @@ mod icon;
|
|||
mod meta;
|
||||
mod sort;
|
||||
|
||||
use crate::config_file::Config;
|
||||
use crate::core::Core;
|
||||
use crate::flags::Flags;
|
||||
use std::path::PathBuf;
|
||||
|
@ -94,7 +99,12 @@ fn main() {
|
|||
.map(PathBuf::from)
|
||||
.collect();
|
||||
|
||||
let flags = Flags::from_matches(&matches).unwrap_or_else(|err| err.exit());
|
||||
let config = if matches.is_present("no-config") {
|
||||
Config::with_none()
|
||||
} else {
|
||||
Config::read_config()
|
||||
};
|
||||
let flags = Flags::configure_from(&matches, &config).unwrap_or_else(|err| err.exit());
|
||||
let core = Core::new(flags);
|
||||
|
||||
core.run(inputs);
|
||||
|
|
|
@ -23,7 +23,7 @@ impl From<FileType> for Indicator {
|
|||
|
||||
impl Indicator {
|
||||
pub fn render(&self, flags: &Flags) -> ColoredString {
|
||||
if flags.display_indicators {
|
||||
if flags.display_indicators.0 {
|
||||
ANSIString::from(self.0)
|
||||
} else {
|
||||
ANSIString::from("")
|
||||
|
@ -34,13 +34,13 @@ impl Indicator {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Indicator;
|
||||
use crate::flags::Flags;
|
||||
use crate::flags::{Flags, Indicators};
|
||||
use crate::meta::FileType;
|
||||
|
||||
#[test]
|
||||
fn test_directory_indicator() {
|
||||
let mut flags = Flags::default();
|
||||
flags.display_indicators = true;
|
||||
flags.display_indicators = Indicators(true);
|
||||
|
||||
let file_type = Indicator::from(FileType::Directory { uid: false });
|
||||
|
||||
|
@ -50,7 +50,7 @@ mod test {
|
|||
#[test]
|
||||
fn test_executable_file_indicator() {
|
||||
let mut flags = Flags::default();
|
||||
flags.display_indicators = true;
|
||||
flags.display_indicators = Indicators(true);
|
||||
|
||||
let file_type = Indicator::from(FileType::File {
|
||||
uid: false,
|
||||
|
@ -63,7 +63,7 @@ mod test {
|
|||
#[test]
|
||||
fn test_socket_indicator() {
|
||||
let mut flags = Flags::default();
|
||||
flags.display_indicators = true;
|
||||
flags.display_indicators = Indicators(true);
|
||||
|
||||
let file_type = Indicator::from(FileType::Socket);
|
||||
|
||||
|
@ -73,7 +73,7 @@ mod test {
|
|||
#[test]
|
||||
fn test_symlink_indicator() {
|
||||
let mut flags = Flags::default();
|
||||
flags.display_indicators = true;
|
||||
flags.display_indicators = Indicators(true);
|
||||
|
||||
let file_type = Indicator::from(FileType::SymLink { is_dir: false });
|
||||
assert_eq!("@", file_type.render(&flags).to_string().as_str());
|
||||
|
@ -85,7 +85,7 @@ mod test {
|
|||
#[test]
|
||||
fn test_not_represented_indicator() {
|
||||
let mut flags = Flags::default();
|
||||
flags.display_indicators = true;
|
||||
flags.display_indicators = Indicators(true);
|
||||
|
||||
// The File type doesn't have any indicator
|
||||
let file_type = Indicator::from(FileType::File {
|
||||
|
|
|
@ -20,8 +20,9 @@ pub use self::owner::Owner;
|
|||
pub use self::permissions::Permissions;
|
||||
pub use self::size::Size;
|
||||
pub use self::symlink::SymLink;
|
||||
pub use crate::flags::{Display, Flags, Layout};
|
||||
pub use crate::icon::Icons;
|
||||
|
||||
use crate::flags::{Display, Flags, Layout};
|
||||
use crate::print_error;
|
||||
|
||||
use std::fs::read_link;
|
||||
|
@ -53,7 +54,7 @@ impl Meta {
|
|||
return Ok(None);
|
||||
}
|
||||
|
||||
if flags.display == Display::DisplayDirectoryItself {
|
||||
if flags.display == Display::DirectoryItself {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
|
@ -77,14 +78,14 @@ impl Meta {
|
|||
|
||||
let mut content: Vec<Meta> = Vec::new();
|
||||
|
||||
if let Display::DisplayAll = flags.display {
|
||||
if let Display::All = flags.display {
|
||||
let mut current_meta;
|
||||
|
||||
current_meta = self.clone();
|
||||
current_meta.name.name = ".".to_owned();
|
||||
|
||||
let parent_meta =
|
||||
Self::from_path(&self.path.join(Component::ParentDir), flags.dereference)?;
|
||||
Self::from_path(&self.path.join(Component::ParentDir), flags.dereference.0)?;
|
||||
|
||||
content.push(current_meta);
|
||||
content.push(parent_meta);
|
||||
|
@ -97,7 +98,7 @@ impl Meta {
|
|||
.file_name()
|
||||
.ok_or_else(|| Error::new(ErrorKind::InvalidInput, "invalid file name"))?;
|
||||
|
||||
if flags.ignore_globs.is_match(&name) {
|
||||
if flags.ignore_globs.0.is_match(&name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -107,7 +108,7 @@ impl Meta {
|
|||
}
|
||||
}
|
||||
|
||||
let mut entry_meta = match Self::from_path(&path, flags.dereference) {
|
||||
let mut entry_meta = match Self::from_path(&path, flags.dereference.0) {
|
||||
Ok(res) => res,
|
||||
Err(err) => {
|
||||
print_error!("lsd: {}: {}\n", path.display(), err);
|
||||
|
|
46
src/sort.rs
46
src/sort.rs
|
@ -1,4 +1,4 @@
|
|||
use crate::flags::{DirOrderFlag, Flags, SortFlag, SortOrder};
|
||||
use crate::flags::{DirGrouping, Flags, SortColumn, SortOrder};
|
||||
use crate::meta::Meta;
|
||||
use human_sort::compare;
|
||||
use std::cmp::Ordering;
|
||||
|
@ -7,23 +7,23 @@ pub type SortFn = fn(&Meta, &Meta) -> Ordering;
|
|||
|
||||
pub fn assemble_sorters(flags: &Flags) -> Vec<(SortOrder, SortFn)> {
|
||||
let mut sorters: Vec<(SortOrder, SortFn)> = vec![];
|
||||
match flags.directory_order {
|
||||
DirOrderFlag::First => {
|
||||
match flags.sorting.dir_grouping {
|
||||
DirGrouping::First => {
|
||||
sorters.push((SortOrder::Default, with_dirs_first));
|
||||
}
|
||||
DirOrderFlag::Last => {
|
||||
DirGrouping::Last => {
|
||||
sorters.push((SortOrder::Reverse, with_dirs_first));
|
||||
}
|
||||
DirOrderFlag::None => {}
|
||||
DirGrouping::None => {}
|
||||
};
|
||||
let other_sort = match flags.sort_by {
|
||||
SortFlag::Name => by_name,
|
||||
SortFlag::Size => by_size,
|
||||
SortFlag::Time => by_date,
|
||||
SortFlag::Version => by_version,
|
||||
SortFlag::Extension => by_extension,
|
||||
let other_sort = match flags.sorting.column {
|
||||
SortColumn::Name => by_name,
|
||||
SortColumn::Size => by_size,
|
||||
SortColumn::Time => by_date,
|
||||
SortColumn::Version => by_version,
|
||||
SortColumn::Extension => by_extension,
|
||||
};
|
||||
sorters.push((flags.sort_order, other_sort));
|
||||
sorters.push((flags.sorting.order, other_sort));
|
||||
sorters
|
||||
}
|
||||
|
||||
|
@ -89,14 +89,14 @@ mod tests {
|
|||
let meta_z = Meta::from_path(&path_z, false).expect("failed to get meta");
|
||||
|
||||
let mut flags = Flags::default();
|
||||
flags.directory_order = DirOrderFlag::First;
|
||||
flags.sorting.dir_grouping = DirGrouping::First;
|
||||
|
||||
// Sort with the dirs first
|
||||
let sorter = assemble_sorters(&flags);
|
||||
assert_eq!(by_meta(&sorter, &meta_a, &meta_z), Ordering::Greater);
|
||||
|
||||
// Sort with the dirs first (the dirs stay first)
|
||||
flags.sort_order = SortOrder::Reverse;
|
||||
flags.sorting.order = SortOrder::Reverse;
|
||||
|
||||
let sorter = assemble_sorters(&flags);
|
||||
assert_eq!(by_meta(&sorter, &meta_a, &meta_z), Ordering::Greater);
|
||||
|
@ -117,7 +117,7 @@ mod tests {
|
|||
let meta_z = Meta::from_path(&path_z, false).expect("failed to get meta");
|
||||
|
||||
let mut flags = Flags::default();
|
||||
flags.directory_order = DirOrderFlag::Last;
|
||||
flags.sorting.dir_grouping = DirGrouping::Last;
|
||||
|
||||
// Sort with file first
|
||||
let sorter = assemble_sorters(&flags);
|
||||
|
@ -143,14 +143,14 @@ mod tests {
|
|||
let meta_z = Meta::from_path(&path_z, false).expect("failed to get meta");
|
||||
|
||||
let mut flags = Flags::default();
|
||||
flags.directory_order = DirOrderFlag::None;
|
||||
flags.sorting.dir_grouping = DirGrouping::None;
|
||||
|
||||
// Sort by name unordered
|
||||
let sorter = assemble_sorters(&flags);
|
||||
assert_eq!(by_meta(&sorter, &meta_a, &meta_z), Ordering::Less);
|
||||
|
||||
// Sort by name unordered
|
||||
flags.sort_order = SortOrder::Reverse;
|
||||
flags.sorting.order = SortOrder::Reverse;
|
||||
|
||||
let sorter = assemble_sorters(&flags);
|
||||
assert_eq!(by_meta(&sorter, &meta_a, &meta_z), Ordering::Greater);
|
||||
|
@ -171,14 +171,14 @@ mod tests {
|
|||
let meta_z = Meta::from_path(&path_z, false).expect("failed to get meta");
|
||||
|
||||
let mut flags = Flags::default();
|
||||
flags.directory_order = DirOrderFlag::None;
|
||||
flags.sorting.dir_grouping = DirGrouping::None;
|
||||
|
||||
// Sort by name unordered
|
||||
let sorter = assemble_sorters(&flags);
|
||||
assert_eq!(by_meta(&sorter, &meta_a, &meta_z), Ordering::Greater);
|
||||
|
||||
// Sort by name unordered reversed
|
||||
flags.sort_order = SortOrder::Reverse;
|
||||
flags.sorting.order = SortOrder::Reverse;
|
||||
|
||||
let sorter = assemble_sorters(&flags);
|
||||
assert_eq!(by_meta(&sorter, &meta_a, &meta_z), Ordering::Less);
|
||||
|
@ -220,14 +220,14 @@ mod tests {
|
|||
let meta_z = Meta::from_path(&path_z, false).expect("failed to get meta");
|
||||
|
||||
let mut flags = Flags::default();
|
||||
flags.sort_by = SortFlag::Time;
|
||||
flags.sorting.column = SortColumn::Time;
|
||||
|
||||
// Sort by time
|
||||
let sorter = assemble_sorters(&flags);
|
||||
assert_eq!(by_meta(&sorter, &meta_a, &meta_z), Ordering::Less);
|
||||
|
||||
// Sort by time reversed
|
||||
flags.sort_order = SortOrder::Reverse;
|
||||
flags.sorting.order = SortOrder::Reverse;
|
||||
let sorter = assemble_sorters(&flags);
|
||||
assert_eq!(by_meta(&sorter, &meta_a, &meta_z), Ordering::Greater);
|
||||
}
|
||||
|
@ -257,7 +257,7 @@ mod tests {
|
|||
let meta_t = Meta::from_path(&path_t, false).expect("failed to get meta");
|
||||
|
||||
let mut flags = Flags::default();
|
||||
flags.sort_by = SortFlag::Extension;
|
||||
flags.sorting.column = SortColumn::Extension;
|
||||
|
||||
// Sort by extension
|
||||
let sorter = assemble_sorters(&flags);
|
||||
|
@ -287,7 +287,7 @@ mod tests {
|
|||
let meta_c = Meta::from_path(&path_c, false).expect("failed to get meta");
|
||||
|
||||
let mut flags = Flags::default();
|
||||
flags.sort_by = SortFlag::Version;
|
||||
flags.sorting.column = SortColumn::Version;
|
||||
|
||||
let sorter = assemble_sorters(&flags);
|
||||
assert_eq!(by_meta(&sorter, &meta_b, &meta_a), Ordering::Greater);
|
||||
|
|
|
@ -17,6 +17,7 @@ fn test_runs_okay() {
|
|||
#[test]
|
||||
fn test_list_empty_directory() {
|
||||
cmd()
|
||||
.arg("--no-config")
|
||||
.arg(tempdir().path())
|
||||
.assert()
|
||||
.stdout(predicate::eq(""));
|
||||
|
@ -27,12 +28,14 @@ fn test_list_almost_all_empty_directory() {
|
|||
let matched = "";
|
||||
cmd()
|
||||
.arg("--almost-all")
|
||||
.arg("--no-config")
|
||||
.arg(tempdir().path())
|
||||
.assert()
|
||||
.stdout(predicate::eq(matched));
|
||||
|
||||
cmd()
|
||||
.arg("-A")
|
||||
.arg("--no-config")
|
||||
.arg(tempdir().path())
|
||||
.assert()
|
||||
.stdout(predicate::eq(matched));
|
||||
|
@ -43,12 +46,14 @@ fn test_list_all_empty_directory() {
|
|||
let matched = "\\.\n\\.\\.\n$";
|
||||
cmd()
|
||||
.arg("--all")
|
||||
.arg("--no-config")
|
||||
.arg(tempdir().path())
|
||||
.assert()
|
||||
.stdout(predicate::str::is_match(matched).unwrap());
|
||||
|
||||
cmd()
|
||||
.arg("-a")
|
||||
.arg("--no-config")
|
||||
.arg(tempdir().path())
|
||||
.assert()
|
||||
.stdout(predicate::str::is_match(matched).unwrap());
|
||||
|
@ -60,6 +65,7 @@ fn test_list_populated_directory() {
|
|||
dir.child("one").touch().unwrap();
|
||||
dir.child("two").touch().unwrap();
|
||||
cmd()
|
||||
.arg("--no-config")
|
||||
.arg(dir.path())
|
||||
.assert()
|
||||
.stdout(predicate::str::is_match("one\ntwo\n$").unwrap());
|
||||
|
@ -72,6 +78,7 @@ fn test_list_almost_all_populated_directory() {
|
|||
dir.child("two").touch().unwrap();
|
||||
cmd()
|
||||
.arg("--almost-all")
|
||||
.arg("--no-config")
|
||||
.arg(dir.path())
|
||||
.assert()
|
||||
.stdout(predicate::str::is_match("one\ntwo\n$").unwrap());
|
||||
|
@ -84,6 +91,7 @@ fn test_list_all_populated_directory() {
|
|||
dir.child("two").touch().unwrap();
|
||||
cmd()
|
||||
.arg("--all")
|
||||
.arg("--no-config")
|
||||
.arg(dir.path())
|
||||
.assert()
|
||||
.stdout(predicate::str::is_match("\\.\n\\.\\.\none\ntwo\n$").unwrap());
|
||||
|
@ -102,18 +110,40 @@ fn test_list_inode_populated_directory() {
|
|||
|
||||
cmd()
|
||||
.arg("--inode")
|
||||
.arg("--no-config")
|
||||
.arg(dir.path())
|
||||
.assert()
|
||||
.stdout(predicate::str::is_match(matched).unwrap());
|
||||
cmd()
|
||||
.arg("-i")
|
||||
.arg("--no-config")
|
||||
.arg(dir.path())
|
||||
.assert()
|
||||
.stdout(predicate::str::is_match(matched).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list_block_inode_populated_directory() {
|
||||
fn test_list_block_inode_populated_directory_without_long() {
|
||||
let dir = tempdir();
|
||||
dir.child("one").touch().unwrap();
|
||||
dir.child("two").touch().unwrap();
|
||||
|
||||
#[cfg(unix)]
|
||||
let matched = "one\ntwo\n$";
|
||||
#[cfg(windows)]
|
||||
let matched = "one\ntwo\n$";
|
||||
|
||||
cmd()
|
||||
.arg("--blocks")
|
||||
.arg("inode,name")
|
||||
.arg("--no-config")
|
||||
.arg(dir.path())
|
||||
.assert()
|
||||
.stdout(predicate::str::is_match(matched).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list_block_inode_populated_directory_with_long() {
|
||||
let dir = tempdir();
|
||||
dir.child("one").touch().unwrap();
|
||||
dir.child("two").touch().unwrap();
|
||||
|
@ -124,8 +154,10 @@ fn test_list_block_inode_populated_directory() {
|
|||
let matched = "- one\n\\- two\n$";
|
||||
|
||||
cmd()
|
||||
.arg("--long")
|
||||
.arg("--blocks")
|
||||
.arg("inode,name")
|
||||
.arg("--no-config")
|
||||
.arg(dir.path())
|
||||
.assert()
|
||||
.stdout(predicate::str::is_match(matched).unwrap());
|
||||
|
@ -134,7 +166,13 @@ fn test_list_block_inode_populated_directory() {
|
|||
#[test]
|
||||
fn test_list_inode_with_long_ok() {
|
||||
let dir = tempdir();
|
||||
cmd().arg("-i").arg("-l").arg(dir.path()).assert().success();
|
||||
cmd()
|
||||
.arg("-i")
|
||||
.arg("-l")
|
||||
.arg("--no-config")
|
||||
.arg(dir.path())
|
||||
.assert()
|
||||
.success();
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
|
@ -147,11 +185,13 @@ fn test_list_broken_link_ok() {
|
|||
|
||||
cmd()
|
||||
.arg(&broken_link)
|
||||
.arg("--no-config")
|
||||
.assert()
|
||||
.stderr(predicate::str::contains(matched).not());
|
||||
|
||||
cmd()
|
||||
.arg("-l")
|
||||
.arg("--no-config")
|
||||
.arg(broken_link)
|
||||
.assert()
|
||||
.stderr(predicate::str::contains(matched).not());
|
||||
|
@ -167,11 +207,13 @@ fn test_nosymlink_on_non_long() {
|
|||
|
||||
cmd()
|
||||
.arg("-l")
|
||||
.arg("--no-config")
|
||||
.arg(&link)
|
||||
.assert()
|
||||
.stdout(predicate::str::contains(link_icon));
|
||||
|
||||
cmd()
|
||||
.arg("--no-config")
|
||||
.arg(&link)
|
||||
.assert()
|
||||
.stdout(predicate::str::contains(link_icon).not());
|
||||
|
@ -190,6 +232,7 @@ fn test_dereference_link_right_type_and_no_link() {
|
|||
cmd()
|
||||
.arg("-l")
|
||||
.arg("--dereference")
|
||||
.arg("--no-config")
|
||||
.arg(&link)
|
||||
.assert()
|
||||
.stdout(predicate::str::starts_with(file_type))
|
||||
|
@ -198,6 +241,7 @@ fn test_dereference_link_right_type_and_no_link() {
|
|||
cmd()
|
||||
.arg("-l")
|
||||
.arg("-L")
|
||||
.arg("--no-config")
|
||||
.arg(link)
|
||||
.assert()
|
||||
.stdout(predicate::str::starts_with(file_type))
|
||||
|
@ -213,6 +257,7 @@ fn test_show_folder_content_of_symlink() {
|
|||
fs::symlink("target", &link).unwrap();
|
||||
|
||||
cmd()
|
||||
.arg("--no-config")
|
||||
.arg(link)
|
||||
.assert()
|
||||
.stdout(predicate::str::starts_with("link").not())
|
||||
|
@ -229,6 +274,7 @@ fn test_no_show_folder_content_of_symlink_for_long() {
|
|||
|
||||
cmd()
|
||||
.arg("-l")
|
||||
.arg("--no-config")
|
||||
.arg(link)
|
||||
.assert()
|
||||
.stdout(predicate::str::starts_with("lrw"))
|
||||
|
@ -236,6 +282,7 @@ fn test_no_show_folder_content_of_symlink_for_long() {
|
|||
|
||||
cmd()
|
||||
.arg("-l")
|
||||
.arg("--no-config")
|
||||
.arg(dir.path().join("link/"))
|
||||
.assert()
|
||||
.stdout(predicate::str::starts_with(".rw"))
|
||||
|
@ -252,6 +299,7 @@ fn test_show_folder_of_symlink_for_long_multi() {
|
|||
|
||||
cmd()
|
||||
.arg("-l")
|
||||
.arg("--no-config")
|
||||
.arg(dir.path().join("link/"))
|
||||
.arg(dir.path().join("link"))
|
||||
.assert()
|
||||
|
@ -272,9 +320,14 @@ fn test_version_sort() {
|
|||
dir.child("11").touch().unwrap();
|
||||
dir.child("2").touch().unwrap();
|
||||
dir.child("22").touch().unwrap();
|
||||
cmd().arg("-v").arg(dir.path()).assert().stdout(
|
||||
predicate::str::is_match("0.2\n0.3.7\n0.11\n0.11.5\n1\n2\n11\n11a\n22\n$").unwrap(),
|
||||
);
|
||||
cmd()
|
||||
.arg("-v")
|
||||
.arg("--no-config")
|
||||
.arg(dir.path())
|
||||
.assert()
|
||||
.stdout(
|
||||
predicate::str::is_match("0.2\n0.3.7\n0.11\n0.11.5\n1\n2\n11\n11a\n22\n$").unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -285,6 +338,7 @@ fn test_version_sort_overwrite_by_timesort() {
|
|||
cmd()
|
||||
.arg("-v")
|
||||
.arg("-t")
|
||||
.arg("--no-config")
|
||||
.arg(dir.path())
|
||||
.assert()
|
||||
.stdout(predicate::str::is_match("11\n2\n$").unwrap());
|
||||
|
@ -302,6 +356,7 @@ fn test_version_sort_overwrite_by_sizesort() {
|
|||
cmd()
|
||||
.arg("-v")
|
||||
.arg("-S")
|
||||
.arg("--no-config")
|
||||
.arg(dir.path())
|
||||
.assert()
|
||||
.stdout(predicate::str::is_match("11\n2\n$").unwrap());
|
||||
|
|
Loading…
Reference in a new issue