Linutil New design (#1176)
* New theme & design * Fix shellcheck assignment spacing * Fixed system_info file * Fixed Cargo fmt * add ctt logo * update version and fmt * update docs with xtask --------- Co-authored-by: Chris Titus <contact@christitus.com>
This commit is contained in:
Generated
+971
-13
@@ -2,6 +2,12 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.4"
|
||||
@@ -11,6 +17,24 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aligned"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685"
|
||||
dependencies = [
|
||||
"as-slice",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aligned-vec"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b"
|
||||
dependencies = [
|
||||
"equator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
@@ -73,18 +97,103 @@ version = "1.0.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
|
||||
|
||||
[[package]]
|
||||
name = "arg_enum_proc_macro"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "as-slice"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516"
|
||||
dependencies = [
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "av-scenechange"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394"
|
||||
dependencies = [
|
||||
"aligned",
|
||||
"anyhow",
|
||||
"arg_enum_proc_macro",
|
||||
"arrayvec",
|
||||
"log",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
"pastey",
|
||||
"rayon",
|
||||
"thiserror 2.0.18",
|
||||
"v_frame",
|
||||
"y4m",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "av1-grain"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arrayvec",
|
||||
"log",
|
||||
"nom",
|
||||
"num-rational",
|
||||
"v_frame",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "avif-serialize"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47c8fbc0f831f4519fe8b810b6a7a91410ec83031b8233f730a0480029f6a23f"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64-simd"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195"
|
||||
dependencies = [
|
||||
"outref",
|
||||
"vsimd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit_field"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@@ -97,6 +206,39 @@ version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
||||
|
||||
[[package]]
|
||||
name = "bitstream-io"
|
||||
version = "4.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60d4bd9d1db2c6bdf285e223a7fa369d5ce98ec767dec949c6ca62863ce61757"
|
||||
dependencies = [
|
||||
"core2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "built"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder-lite"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
||||
|
||||
[[package]]
|
||||
name = "cassowary"
|
||||
version = "0.3.0"
|
||||
@@ -119,6 +261,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
@@ -174,6 +318,12 @@ version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
|
||||
|
||||
[[package]]
|
||||
name = "color_quant"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.4"
|
||||
@@ -194,6 +344,49 @@ dependencies = [
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core2"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.28.1"
|
||||
@@ -219,6 +412,12 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.11"
|
||||
@@ -287,6 +486,26 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe"
|
||||
|
||||
[[package]]
|
||||
name = "equator"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc"
|
||||
dependencies = [
|
||||
"equator-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equator-macro"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
@@ -303,6 +522,50 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exr"
|
||||
version = "1.74.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"half",
|
||||
"lebe",
|
||||
"miniz_oxide",
|
||||
"rayon-core",
|
||||
"smallvec",
|
||||
"zune-inflate",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fax"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab"
|
||||
dependencies = [
|
||||
"fax_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fax_derive"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fdeflate"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
|
||||
dependencies = [
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filedescriptor"
|
||||
version = "0.8.3"
|
||||
@@ -310,7 +573,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e40758ed24c9b2eeb76c35fb0aebc66c626084edd827e07e1552279814c6682d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
@@ -320,6 +583,16 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
@@ -343,6 +616,39 @@ dependencies = [
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasip2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gif"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f5df2ba84018d80c213569363bdcd0c64e6933c67fe4c1d60ecf822971a3c35e"
|
||||
dependencies = [
|
||||
"color_quant",
|
||||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crunchy",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.5"
|
||||
@@ -366,12 +672,58 @@ version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "icy_sixel"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccc0a9c4770bc47b0a933256a496cfb8b6531f753ea9bccb19c6dff0ff7273fc"
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.25.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder-lite",
|
||||
"color_quant",
|
||||
"exr",
|
||||
"gif",
|
||||
"image-webp",
|
||||
"moxcms",
|
||||
"num-traits",
|
||||
"png",
|
||||
"qoi",
|
||||
"ravif",
|
||||
"rayon",
|
||||
"rgb",
|
||||
"tiff",
|
||||
"zune-core 0.5.1",
|
||||
"zune-jpeg 0.5.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "image-webp"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3"
|
||||
dependencies = [
|
||||
"byteorder-lite",
|
||||
"quick-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imgref"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8"
|
||||
|
||||
[[package]]
|
||||
name = "include_dir"
|
||||
version = "0.7.4"
|
||||
@@ -423,6 +775,17 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "interpolate_name"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ioctl-rs"
|
||||
version = "0.1.6"
|
||||
@@ -447,27 +810,62 @@ dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
|
||||
dependencies = [
|
||||
"getrandom 0.3.4",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "lebe"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.178"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linutil_core"
|
||||
version = "25.12.18"
|
||||
version = "26.1.22"
|
||||
dependencies = [
|
||||
"ego-tree",
|
||||
"include_dir",
|
||||
@@ -479,15 +877,17 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "linutil_tui"
|
||||
version = "25.12.18"
|
||||
version = "26.1.22"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"image",
|
||||
"linutil_core",
|
||||
"nix 0.29.0",
|
||||
"oneshot",
|
||||
"portable-pty",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"ratatui",
|
||||
"ratatui-image",
|
||||
"time",
|
||||
"tree-sitter-bash",
|
||||
"tree-sitter-highlight",
|
||||
@@ -523,6 +923,15 @@ version = "0.4.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||
|
||||
[[package]]
|
||||
name = "loop9"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062"
|
||||
dependencies = [
|
||||
"imgref",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.12.5"
|
||||
@@ -532,6 +941,16 @@ dependencies = [
|
||||
"hashbrown 0.15.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "maybe-rayon"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"rayon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.6"
|
||||
@@ -547,6 +966,16 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.1.1"
|
||||
@@ -559,6 +988,22 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "moxcms"
|
||||
version = "0.7.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"pxfm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.25.1"
|
||||
@@ -585,12 +1030,77 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "8.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "noop_proc_macro"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_threads"
|
||||
version = "0.1.7"
|
||||
@@ -600,6 +1110,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.2"
|
||||
@@ -612,6 +1128,12 @@ version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4ce411919553d3f9fa53a0880544cda985a112117a0444d5ff1e870a893d6ea"
|
||||
|
||||
[[package]]
|
||||
name = "outref"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.5"
|
||||
@@ -641,12 +1163,31 @@ version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pastey"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"crc32fast",
|
||||
"fdeflate",
|
||||
"flate2",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-pty"
|
||||
version = "0.8.1"
|
||||
@@ -692,6 +1233,49 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "profiling"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
|
||||
dependencies = [
|
||||
"profiling-procmacros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "profiling-procmacros"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pxfm"
|
||||
version = "0.1.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7186d3822593aa4393561d186d1393b3923e9d6163d3fbfd6e825e3e6cf3e6a8"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "qoi"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.42"
|
||||
@@ -701,6 +1285,12 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
@@ -708,8 +1298,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -719,7 +1319,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.9.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -728,7 +1338,16 @@ version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
|
||||
dependencies = [
|
||||
"getrandom 0.3.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -743,7 +1362,7 @@ dependencies = [
|
||||
"crossterm",
|
||||
"indoc",
|
||||
"instability",
|
||||
"itertools",
|
||||
"itertools 0.13.0",
|
||||
"lru",
|
||||
"paste",
|
||||
"strum",
|
||||
@@ -752,6 +1371,92 @@ dependencies = [
|
||||
"unicode-width 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ratatui-image"
|
||||
version = "9.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dbebe428e366c230b2251c7091f2a56ec2bf818d96cdc807f6474428ee09040"
|
||||
dependencies = [
|
||||
"base64-simd",
|
||||
"icy_sixel",
|
||||
"image",
|
||||
"rand 0.8.5",
|
||||
"ratatui",
|
||||
"rustix 0.38.44",
|
||||
"thiserror 1.0.69",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rav1e"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b"
|
||||
dependencies = [
|
||||
"aligned-vec",
|
||||
"arbitrary",
|
||||
"arg_enum_proc_macro",
|
||||
"arrayvec",
|
||||
"av-scenechange",
|
||||
"av1-grain",
|
||||
"bitstream-io",
|
||||
"built",
|
||||
"cfg-if",
|
||||
"interpolate_name",
|
||||
"itertools 0.14.0",
|
||||
"libc",
|
||||
"libfuzzer-sys",
|
||||
"log",
|
||||
"maybe-rayon",
|
||||
"new_debug_unreachable",
|
||||
"noop_proc_macro",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"paste",
|
||||
"profiling",
|
||||
"rand 0.9.2",
|
||||
"rand_chacha 0.9.0",
|
||||
"simd_helpers",
|
||||
"thiserror 2.0.18",
|
||||
"v_frame",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ravif"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef69c1990ceef18a116855938e74793a5f7496ee907562bd0857b6ac734ab285"
|
||||
dependencies = [
|
||||
"avif-serialize",
|
||||
"imgref",
|
||||
"loop9",
|
||||
"quick-error",
|
||||
"rav1e",
|
||||
"rayon",
|
||||
"rgb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.18"
|
||||
@@ -790,6 +1495,12 @@ version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
||||
|
||||
[[package]]
|
||||
name = "rgb"
|
||||
version = "0.8.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.44"
|
||||
@@ -967,12 +1678,33 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
|
||||
|
||||
[[package]]
|
||||
name = "simd_helpers"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6"
|
||||
dependencies = [
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
@@ -1045,7 +1777,16 @@ version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
"thiserror-impl 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
|
||||
dependencies = [
|
||||
"thiserror-impl 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1059,6 +1800,31 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiff"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f"
|
||||
dependencies = [
|
||||
"fax",
|
||||
"flate2",
|
||||
"half",
|
||||
"quick-error",
|
||||
"weezl",
|
||||
"zune-jpeg 0.4.21",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.44"
|
||||
@@ -1158,7 +1924,7 @@ dependencies = [
|
||||
"lazy_static",
|
||||
"regex",
|
||||
"streaming-iterator",
|
||||
"thiserror",
|
||||
"thiserror 1.0.69",
|
||||
"tree-sitter",
|
||||
]
|
||||
|
||||
@@ -1195,7 +1961,7 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"itertools 0.13.0",
|
||||
"unicode-segmentation",
|
||||
"unicode-width 0.1.14",
|
||||
]
|
||||
@@ -1218,6 +1984,23 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "v_frame"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2"
|
||||
dependencies = [
|
||||
"aligned-vec",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vsimd"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64"
|
||||
|
||||
[[package]]
|
||||
name = "vt100-ctt"
|
||||
version = "0.16.0"
|
||||
@@ -1259,6 +2042,66 @@ version = "0.11.1+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
|
||||
[[package]]
|
||||
name = "wasip2"
|
||||
version = "1.0.2+wasi-0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "7.0.3"
|
||||
@@ -1293,12 +2136,76 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
|
||||
dependencies = [
|
||||
"windows-core",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
|
||||
dependencies = [
|
||||
"windows-result",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
@@ -1405,13 +2312,25 @@ version = "0.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.51.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
|
||||
|
||||
[[package]]
|
||||
name = "xtask"
|
||||
version = "25.12.18"
|
||||
version = "26.1.22"
|
||||
dependencies = [
|
||||
"linutil_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "y4m"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.31"
|
||||
@@ -1431,3 +2350,42 @@ dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zune-core"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
|
||||
|
||||
[[package]]
|
||||
name = "zune-core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9"
|
||||
|
||||
[[package]]
|
||||
name = "zune-inflate"
|
||||
version = "0.2.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02"
|
||||
dependencies = [
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zune-jpeg"
|
||||
version = "0.4.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713"
|
||||
dependencies = [
|
||||
"zune-core 0.4.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zune-jpeg"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2959ca473aae96a14ecedf501d20b3608d2825ba280d5adb57d651721885b0c2"
|
||||
dependencies = [
|
||||
"zune-core 0.5.1",
|
||||
]
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ default-members = ["tui", "core"]
|
||||
resolver = "2"
|
||||
[workspace.package]
|
||||
license = "MIT"
|
||||
version = "25.12.18"
|
||||
version = "26.1.22"
|
||||
edition = "2021"
|
||||
|
||||
[profile.release]
|
||||
|
||||
@@ -238,4 +238,3 @@ description = "This Script will set the default TTY font to Terminus size 32 Bol
|
||||
script = "terminus-tty.sh"
|
||||
task_list = "I PFM"
|
||||
|
||||
|
||||
|
||||
+14
-20
@@ -107,30 +107,29 @@ https://github.com/ChrisTitusTech/dwm-titus
|
||||
|
||||
- **Loot Filter**: This is a loot filter for Diablo II Resurrected. It's designed to be a simple, clean, and easy to read loot filter that highlights the most important items. Works on battle.net and single player. No frills, no config, just highlights high runes and other valuable items. For more information visit: https://github.com/ChrisTitusTech/d2r-loot-filter
|
||||
|
||||
### Fallout 76
|
||||
### Emulators
|
||||
|
||||
- **Fallout 76 Custom INI**: This script will add a Custom Fallout 76 INI file that improves performance and stability. It also includes some quality of life improvements.
|
||||
|
||||
### Console Emulators
|
||||
|
||||
- **RetroArch**: Frontend for emulators, game engines and media players. NO Games or Bios' are included
|
||||
- **Mesen 2**: NES and SNES Emulator. NO Games are included
|
||||
- **snes9x**: Super Nintendo Emulator. NO Games are included
|
||||
- **Blastem**: A Genesis emulator. NO Games are included
|
||||
- **bsnes**: Super Nintendo Emulator. NO Games are included
|
||||
- **Dolphin Emulator**: GameCube and Wii Emulator. NO Games are included
|
||||
- **Flycast**: A Dreamcase emulator. NO Games are included
|
||||
- **Gopher 64**: N64 Emulator. NO Games are included
|
||||
- **Kronos**: A Sega Saturn emulator. NO Games are included
|
||||
- **MelonDS**: Nintendo DS and DSi Emulator. NO Games are included
|
||||
- **mGBA**: Nintendo Game Boy Advance Emulator. NO Games are included
|
||||
- **Mupen 64 Plus**: N64 Emulator. NO Games are included
|
||||
- **Dolphin Emulator**: GameCube and Wii Emulator. NO Games are included
|
||||
- **MelonDS**: Nintendo DS and DSi Emulator. NO Games are included
|
||||
- **Ryujinx**: Nintendo Switch emulator. NO Games are included
|
||||
- **PCSX**: A Playstation emulator. NO Games or Bios' are included
|
||||
- **PCSX2**: A Playstation 2 emulator. NO Games or Bios' are included
|
||||
- **Play!**: An Experimental Playstation 2 emulator. NO Games or Bios' are included
|
||||
- **RetroArch Game Emulator**: Frontend for emulators, game engines and media players. NO Games or Bios' are included
|
||||
- **RPCS3**: A Playstation 3 emulator. NO Games or Bios' are included
|
||||
- **Ryujinx**: Nintendo Switch emulator. NO Games are included
|
||||
- **snes9x**: Super Nintendo Emulator. NO Games are included
|
||||
- **XEMU**: An Original Xbox emulator. NO Games or Bios' are included
|
||||
- **Xenia**: An Experimental Xbox 360 emulator. NO Games or Bios' are included
|
||||
- **Blastem**: A Genesis emulator. NO Games are included
|
||||
- **Kronos**: A Sega Saturn emulator. NO Games are included
|
||||
- **Flycast**: A Dreamcase emulator. NO Games are included
|
||||
|
||||
### Fallout 76
|
||||
|
||||
- **Fallout 76 INI and Mods**: This script will add a Custom Fallout 76 INI file that improves performance and stability. It also includes some quality of life improvements.
|
||||
|
||||
## Security
|
||||
|
||||
@@ -165,11 +164,6 @@ https://github.com/ChrisTitusTech/dwm-titus
|
||||
- **Install Desktop Environment**: This script allows you to install various desktop environments (GNOME, KDE, XFCE, Cinnamon, MATE, Budgie, LXQt, LXDE) and window managers (i3, Sway, DWM, Awesome, BSPWM, Openbox, Fluxbox) using your distro's package manager. The script provides an interactive menu to select your preferred desktop environment or window manager, and handles the installation process automatically.
|
||||
- **Uninstall Desktop Environment**: This script allows you to uninstall desktop environments and window managers that were previously installed. It provides an interactive menu to select which desktop environment or window manager to remove, and handles the uninstallation process automatically.
|
||||
|
||||
### Desktop Environment Setup
|
||||
|
||||
- **Install Desktop Environment**: This script allows you to install various desktop environments (GNOME, KDE, XFCE, Cinnamon, MATE, Budgie, LXQt, LXDE) and window managers (i3, Sway, DWM, Awesome, BSPWM, Openbox, Fluxbox) using your distro's package manager. The script provides an interactive menu to select your preferred desktop environment or window manager, and handles the installation process automatically.
|
||||
- **Uninstall Desktop Environment**: This script allows you to uninstall desktop environments and window managers that were previously installed. It provides an interactive menu to select which desktop environment or window manager to remove, and handles the uninstallation process automatically.
|
||||
|
||||
### Fedora
|
||||
|
||||
- **Btrfs Assistant, Snapper Config, grub-btrfs**: Installs Btrfs Assistant, Snapper, dnf snapper plugin and takes the first root(/) and /home snapshots. Enables snapper-timeline and snapper-cleanup services. Installs Grub-Btrfs. Notice: To perform a system recovery via grub-btrfs, perform a restore operation with Btrfs Assistant GUI after booting into the snapshot. Notice: If you used the default Fedora disk partitioning during OS installation, the /boot configured as an separate EXT4 partition. Therefore, it cannot be included in root snapshots. Backup separately.
|
||||
|
||||
@@ -18,6 +18,20 @@ check() {
|
||||
unset message
|
||||
}
|
||||
|
||||
SCRIPT_DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
|
||||
if [ -f "$SCRIPT_DIR/Cargo.toml" ] && command -v cargo >/dev/null 2>&1; then
|
||||
TARGET_DIR=${CARGO_TARGET_DIR:-"$HOME/.cache/linutil/target"}
|
||||
mkdir -p "$TARGET_DIR"
|
||||
check $? "Preparing build cache"
|
||||
|
||||
cd "$SCRIPT_DIR"
|
||||
check $? "Entering linutil directory"
|
||||
|
||||
CARGO_TARGET_DIR="$TARGET_DIR" cargo run -p linutil_tui --bin linutil -- "$@"
|
||||
check $? "Running linutil from source"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
findArch() {
|
||||
case "$(uname -m)" in
|
||||
x86_64|amd64) arch="x86_64" ;;
|
||||
|
||||
+4
-2
@@ -7,7 +7,7 @@ edition = "2021"
|
||||
license.workspace = true
|
||||
repository = "https://github.com/ChrisTitusTech/linutil/tree/main/tui"
|
||||
version.workspace = true
|
||||
include = ["src/*.rs", "Cargo.toml", "cool_tips.txt", "../man/linutil.1"]
|
||||
include = ["src/*.rs", "Cargo.toml", "cool_tips.txt", "assets/ctt_logo.png", "../man/linutil.1"]
|
||||
|
||||
[[bin]]
|
||||
name = "linutil"
|
||||
@@ -19,12 +19,14 @@ tips = ["rand"]
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.20", features = ["derive"] }
|
||||
linutil_core = { version = "25.12.18", path = "../core" }
|
||||
image = { version = "0.25.6", default-features = false, features = ["ico", "png"] }
|
||||
linutil_core = { version = "26.1.22", path = "../core" }
|
||||
nix = { version = "0.29.0", features = [ "user" ] }
|
||||
oneshot = { version = "0.1.8", features = ["std"], default-features = false }
|
||||
portable-pty = "0.8.1"
|
||||
rand = { version = "0.8.5", optional = true }
|
||||
ratatui = { version = "0.29.0", features = ["crossterm"], default-features = false }
|
||||
ratatui-image = { version = "9.0.0", default-features = false, features = ["crossterm", "image-defaults"] }
|
||||
time = { version = "0.3.36", features = ["formatting", "local-offset", "macros"], default-features = false }
|
||||
tree-sitter-bash = "0.23.3"
|
||||
tree-sitter-highlight = "0.24.4"
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 194 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.1 KiB |
@@ -60,8 +60,9 @@ impl ConfirmPrompt {
|
||||
impl FloatContent for ConfirmPrompt {
|
||||
fn draw(&mut self, frame: &mut Frame, area: Rect, theme: &theme::Theme) {
|
||||
let block = Block::bordered()
|
||||
.border_set(border::ROUNDED)
|
||||
.title(" Confirm selections ")
|
||||
.border_set(border::PLAIN)
|
||||
.border_style(Style::default().fg(theme.focused_color()))
|
||||
.title(" CONFIRM SELECTIONS ")
|
||||
.title_bottom(Line::from(vec![
|
||||
Span::raw(" ["),
|
||||
Span::styled("y", Style::default().fg(theme.success_color())),
|
||||
@@ -70,7 +71,7 @@ impl FloatContent for ConfirmPrompt {
|
||||
Span::raw("] to abort "),
|
||||
]))
|
||||
.title_alignment(Alignment::Center)
|
||||
.title_style(Style::default().bold())
|
||||
.title_style(Style::default().fg(theme.tab_color()).bold())
|
||||
.style(Style::default());
|
||||
|
||||
let inner_area = block.inner(area);
|
||||
|
||||
+22
-11
@@ -4,7 +4,7 @@ use ratatui::{
|
||||
crossterm::event::{KeyCode, KeyEvent, KeyModifiers},
|
||||
prelude::*,
|
||||
symbols::border,
|
||||
widgets::{Block, Paragraph},
|
||||
widgets::{Block, Padding, Paragraph},
|
||||
};
|
||||
use unicode_width::UnicodeWidthChar;
|
||||
|
||||
@@ -116,10 +116,16 @@ impl Filter {
|
||||
pub fn draw_searchbar(&self, frame: &mut Frame, area: Rect, theme: &Theme) {
|
||||
//Set the search bar text (If empty use the placeholder)
|
||||
let display_text = if !self.in_search_mode && self.search_input.is_empty() {
|
||||
Span::raw("Press / to search")
|
||||
Span::styled(
|
||||
"Type to search (/)",
|
||||
Style::default().fg(theme.unfocused_color()).dim(),
|
||||
)
|
||||
} else {
|
||||
let input_text = self.search_input.iter().collect::<String>();
|
||||
Span::styled(input_text, Style::default().fg(theme.focused_color()))
|
||||
Span::styled(
|
||||
input_text,
|
||||
Style::default().fg(theme.focused_color()).bold(),
|
||||
)
|
||||
};
|
||||
|
||||
let search_color = if self.in_search_mode {
|
||||
@@ -132,8 +138,11 @@ impl Filter {
|
||||
let search_bar = Paragraph::new(display_text)
|
||||
.block(
|
||||
Block::bordered()
|
||||
.border_set(border::ROUNDED)
|
||||
.title(" Search "),
|
||||
.border_set(border::PLAIN)
|
||||
.border_style(Style::default().fg(search_color))
|
||||
.title(" SEARCH ")
|
||||
.title_style(Style::default().fg(theme.tab_color()).bold())
|
||||
.padding(Padding::horizontal(1)),
|
||||
)
|
||||
.style(Style::default().fg(search_color));
|
||||
|
||||
@@ -153,18 +162,20 @@ impl Filter {
|
||||
.iter()
|
||||
.map(|c| c.width().unwrap_or(1) as u16)
|
||||
.sum();
|
||||
let x = area.x + cursor_position + 1;
|
||||
let y = area.y + 1;
|
||||
frame.set_cursor_position(Position::new(x, y));
|
||||
let inner_x = area.x + 2;
|
||||
let inner_y = area.y + 1;
|
||||
let inner_width = area.width.saturating_sub(4);
|
||||
let x = inner_x + cursor_position;
|
||||
frame.set_cursor_position(Position::new(x, inner_y));
|
||||
|
||||
if let Some(preview) = &self.completion {
|
||||
let preview_x = area.x + search_input_size + 1;
|
||||
let preview_x = inner_x + search_input_size;
|
||||
let preview_span =
|
||||
Span::styled(preview, Style::default().fg(theme.search_preview_color()));
|
||||
let preview_area = Rect::new(
|
||||
preview_x,
|
||||
y,
|
||||
(preview.len() as u16).min(area.width - search_input_size - 1), // Ensure the completion preview stays within the search bar bounds
|
||||
inner_y,
|
||||
(preview.len() as u16).min(inner_width.saturating_sub(search_input_size)), // Ensure the completion preview stays within the search bar bounds
|
||||
1,
|
||||
);
|
||||
frame.render_widget(Paragraph::new(preview_span), preview_area);
|
||||
|
||||
@@ -172,13 +172,14 @@ impl<'a> FloatingText<'a> {
|
||||
}
|
||||
|
||||
impl FloatContent for FloatingText<'_> {
|
||||
fn draw(&mut self, frame: &mut Frame, area: Rect, _theme: &Theme) {
|
||||
fn draw(&mut self, frame: &mut Frame, area: Rect, theme: &Theme) {
|
||||
let block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_set(border::ROUNDED)
|
||||
.border_set(border::PLAIN)
|
||||
.border_style(Style::default().fg(theme.focused_color()))
|
||||
.title(self.mode_title.as_str())
|
||||
.title_alignment(Alignment::Center)
|
||||
.title_style(Style::default().reversed())
|
||||
.title_style(Style::default().fg(theme.tab_color()).bold())
|
||||
.style(Style::default());
|
||||
|
||||
let inner_area = block.inner(area);
|
||||
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
use crate::theme::Theme;
|
||||
use image::{imageops::FilterType, RgbaImage};
|
||||
use ratatui::{prelude::*, widgets::Paragraph};
|
||||
use ratatui_image::{
|
||||
picker::{Picker, ProtocolType},
|
||||
protocol::StatefulProtocol,
|
||||
Resize, StatefulImage,
|
||||
};
|
||||
|
||||
const LOGO_TEXT_GAP: u16 = 0;
|
||||
const LOGO_ALPHA_CUTOFF: u8 = 10;
|
||||
const LOGO_SCALE_NUM: u32 = 70;
|
||||
const LOGO_SCALE_DEN: u32 = 100;
|
||||
|
||||
enum Renderer {
|
||||
Protocol {
|
||||
protocol: Box<StatefulProtocol>,
|
||||
resize: Resize,
|
||||
},
|
||||
Blocks,
|
||||
}
|
||||
|
||||
pub struct Logo {
|
||||
renderer: Renderer,
|
||||
rgba: RgbaImage,
|
||||
font_size: (u16, u16),
|
||||
image_size: (u32, u32),
|
||||
cached_size: (u16, u16),
|
||||
cached_lines: Vec<Line<'static>>,
|
||||
last_area_size: (u16, u16),
|
||||
}
|
||||
|
||||
impl Logo {
|
||||
pub fn load() -> Option<Self> {
|
||||
let dyn_image = image::load_from_memory(include_bytes!("../assets/ctt_logo.png")).ok()?;
|
||||
let rgba = dyn_image.to_rgba8();
|
||||
let image_size = rgba.dimensions();
|
||||
|
||||
let mut picker = Picker::from_query_stdio().unwrap_or_else(|_| Picker::halfblocks());
|
||||
picker.set_background_color([0, 0, 0, 0]);
|
||||
let font_size = picker.font_size();
|
||||
|
||||
let renderer = if picker.protocol_type() == ProtocolType::Halfblocks {
|
||||
Renderer::Blocks
|
||||
} else {
|
||||
let protocol =
|
||||
Box::new(picker.new_resize_protocol(image::DynamicImage::ImageRgba8(rgba.clone())));
|
||||
Renderer::Protocol {
|
||||
protocol,
|
||||
resize: Resize::Scale(Some(FilterType::Triangle)),
|
||||
}
|
||||
};
|
||||
|
||||
Some(Self {
|
||||
renderer,
|
||||
rgba,
|
||||
font_size,
|
||||
image_size,
|
||||
cached_size: (0, 0),
|
||||
cached_lines: Vec::new(),
|
||||
last_area_size: (0, 0),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn area_height_for_width(&self, width: u16, max_height: u16) -> u16 {
|
||||
if width == 0 || max_height == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let scaled_width = self.scaled_width(width);
|
||||
let max_image_height = max_height.saturating_sub(LOGO_TEXT_GAP + 1);
|
||||
if max_image_height == 0 {
|
||||
return max_height.min(1);
|
||||
}
|
||||
|
||||
let mut image_height = self.rows_for_width(scaled_width);
|
||||
if image_height > max_image_height {
|
||||
image_height = max_image_height;
|
||||
}
|
||||
|
||||
image_height + LOGO_TEXT_GAP + 1
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, frame: &mut Frame, area: Rect, theme: &Theme) {
|
||||
if area.height == 0 || area.width == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.refresh_protocol_if_needed(area);
|
||||
|
||||
let max_image_height = area.height.saturating_sub(LOGO_TEXT_GAP + 1);
|
||||
let (draw_width, draw_height) = self.draw_size(area.width, max_image_height);
|
||||
|
||||
if draw_width > 0 && draw_height > 0 {
|
||||
let centered_x = area.x + area.width.saturating_sub(draw_width) / 2;
|
||||
let max_x = area.x + area.width.saturating_sub(draw_width);
|
||||
let image_x = centered_x.min(max_x);
|
||||
let image_area = Rect::new(image_x, area.y, draw_width, draw_height);
|
||||
let mut use_blocks = matches!(self.renderer, Renderer::Blocks);
|
||||
|
||||
if !use_blocks {
|
||||
if let Renderer::Protocol { protocol, resize } = &mut self.renderer {
|
||||
let widget =
|
||||
StatefulImage::<StatefulProtocol>::default().resize(resize.clone());
|
||||
frame.render_stateful_widget(widget, image_area, protocol.as_mut());
|
||||
if let Some(result) = protocol.last_encoding_result() {
|
||||
if result.is_err() {
|
||||
use_blocks = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if use_blocks {
|
||||
self.renderer = Renderer::Blocks;
|
||||
self.render_blocks(frame, image_area);
|
||||
}
|
||||
}
|
||||
|
||||
let text_y = if draw_height > 0 {
|
||||
area.y + draw_height + LOGO_TEXT_GAP
|
||||
} else {
|
||||
area.y
|
||||
};
|
||||
if text_y < area.y + area.height {
|
||||
let text_area = Rect::new(area.x, text_y, area.width, 1);
|
||||
let label = Line::styled(
|
||||
format!("Linutil V{}", env!("CARGO_PKG_VERSION")),
|
||||
Style::default().fg(theme.tab_color()).bold(),
|
||||
);
|
||||
let text = Paragraph::new(label).alignment(Alignment::Center);
|
||||
frame.render_widget(text, text_area);
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_size(&self, width: u16, max_height: u16) -> (u16, u16) {
|
||||
if width == 0 || max_height == 0 {
|
||||
return (0, 0);
|
||||
}
|
||||
|
||||
let scaled_width = self.scaled_width(width);
|
||||
let mut draw_width = scaled_width;
|
||||
let mut draw_height = self.rows_for_width(draw_width);
|
||||
if draw_height > max_height {
|
||||
draw_height = max_height;
|
||||
draw_width = self.width_for_height(draw_height).min(scaled_width);
|
||||
}
|
||||
|
||||
(draw_width, draw_height)
|
||||
}
|
||||
|
||||
fn rows_for_width(&self, width: u16) -> u16 {
|
||||
if width == 0 || self.image_size.0 == 0 || self.font_size.0 == 0 || self.font_size.1 == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let pixel_width = u64::from(width) * u64::from(self.font_size.0);
|
||||
let scaled_pixel_height =
|
||||
u64::from(self.image_size.1) * pixel_width / u64::from(self.image_size.0);
|
||||
let row_height = u64::from(self.font_size.1);
|
||||
let rows = scaled_pixel_height.div_ceil(row_height);
|
||||
|
||||
rows.min(u64::from(u16::MAX)) as u16
|
||||
}
|
||||
|
||||
fn width_for_height(&self, height: u16) -> u16 {
|
||||
if height == 0 || self.image_size.1 == 0 || self.font_size.0 == 0 || self.font_size.1 == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let pixel_height = u64::from(height) * u64::from(self.font_size.1);
|
||||
let scaled_pixel_width =
|
||||
u64::from(self.image_size.0) * pixel_height / u64::from(self.image_size.1);
|
||||
let col_width = u64::from(self.font_size.0);
|
||||
let cols = scaled_pixel_width.div_ceil(col_width);
|
||||
|
||||
cols.min(u64::from(u16::MAX)) as u16
|
||||
}
|
||||
|
||||
fn render_blocks(&mut self, frame: &mut Frame, area: Rect) {
|
||||
if area.width == 0 || area.height == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let size = (area.width, area.height);
|
||||
if self.cached_size != size {
|
||||
self.cached_size = size;
|
||||
self.cached_lines.clear();
|
||||
|
||||
let resized = image::imageops::resize(
|
||||
&self.rgba,
|
||||
area.width as u32,
|
||||
area.height as u32,
|
||||
FilterType::Triangle,
|
||||
);
|
||||
|
||||
for y in 0..area.height {
|
||||
let mut spans = Vec::with_capacity(area.width as usize);
|
||||
for x in 0..area.width {
|
||||
let pixel = resized.get_pixel(x as u32, y as u32).0;
|
||||
if pixel[3] < LOGO_ALPHA_CUTOFF {
|
||||
spans.push(Span::raw(" "));
|
||||
} else {
|
||||
spans.push(Span::styled(
|
||||
"#",
|
||||
Style::default().fg(Color::Rgb(pixel[0], pixel[1], pixel[2])),
|
||||
));
|
||||
}
|
||||
}
|
||||
self.cached_lines.push(Line::from(spans));
|
||||
}
|
||||
}
|
||||
|
||||
frame.render_widget(Paragraph::new(Text::from(self.cached_lines.clone())), area);
|
||||
}
|
||||
|
||||
fn refresh_protocol_if_needed(&mut self, area: Rect) {
|
||||
let area_size = (area.width, area.height);
|
||||
if self.last_area_size == area_size {
|
||||
return;
|
||||
}
|
||||
self.last_area_size = area_size;
|
||||
|
||||
if !matches!(self.renderer, Renderer::Protocol { .. }) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut picker = match Picker::from_query_stdio() {
|
||||
Ok(picker) => picker,
|
||||
Err(_) => return,
|
||||
};
|
||||
picker.set_background_color([0, 0, 0, 0]);
|
||||
let new_font_size = picker.font_size();
|
||||
let protocol_type = picker.protocol_type();
|
||||
|
||||
if protocol_type == ProtocolType::Halfblocks {
|
||||
self.renderer = Renderer::Blocks;
|
||||
self.font_size = new_font_size;
|
||||
self.cached_size = (0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if self.font_size != new_font_size {
|
||||
self.font_size = new_font_size;
|
||||
self.renderer = Renderer::Protocol {
|
||||
protocol: Box::new(
|
||||
picker.new_resize_protocol(image::DynamicImage::ImageRgba8(self.rgba.clone())),
|
||||
),
|
||||
resize: Resize::Scale(Some(FilterType::Triangle)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn scaled_width(&self, width: u16) -> u16 {
|
||||
if width == 0 {
|
||||
return 0;
|
||||
}
|
||||
let scaled = (u32::from(width) * LOGO_SCALE_NUM + (LOGO_SCALE_DEN / 2)) / LOGO_SCALE_DEN;
|
||||
scaled.clamp(1, u16::MAX as u32) as u16
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -4,9 +4,11 @@ mod filter;
|
||||
mod float;
|
||||
mod floating_text;
|
||||
mod hint;
|
||||
mod logo;
|
||||
mod root;
|
||||
mod running_command;
|
||||
mod state;
|
||||
mod system_info;
|
||||
mod theme;
|
||||
|
||||
#[cfg(feature = "tips")]
|
||||
@@ -34,13 +36,14 @@ use std::{
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args = Args::parse();
|
||||
let mut state = AppState::new(args.clone());
|
||||
|
||||
stdout().execute(EnterAlternateScreen)?;
|
||||
if args.mouse {
|
||||
stdout().execute(EnableMouseCapture)?;
|
||||
}
|
||||
|
||||
let mut state = AppState::new(args.clone());
|
||||
|
||||
enable_raw_mode()?;
|
||||
let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
|
||||
terminal.clear()?;
|
||||
|
||||
+39
-14
@@ -48,32 +48,57 @@ impl FloatContent for RunningCommand {
|
||||
let block = if !self.is_finished() {
|
||||
// Display a block indicating the command is running
|
||||
Block::bordered()
|
||||
.border_set(border::ROUNDED)
|
||||
.title_top(Line::from("Running the command....").centered())
|
||||
.title_style(Style::default().reversed())
|
||||
.title_bottom(Line::from("Press Ctrl-C to KILL the command"))
|
||||
.border_set(border::PLAIN)
|
||||
.border_style(Style::default().fg(theme.focused_color()))
|
||||
.title_top(
|
||||
Line::styled(
|
||||
" RUNNING COMMAND ",
|
||||
Style::default().fg(theme.focused_color()).bold(),
|
||||
)
|
||||
.centered(),
|
||||
)
|
||||
.title_bottom(
|
||||
Line::styled(
|
||||
" Press Ctrl-C to kill the command ",
|
||||
Style::default().fg(theme.unfocused_color()),
|
||||
)
|
||||
.centered(),
|
||||
)
|
||||
} else {
|
||||
// Display a block with the command's exit status
|
||||
let title_line = if self.get_exit_status().success() {
|
||||
Line::styled(
|
||||
"SUCCESS! Press <ENTER> to close this window",
|
||||
Style::default().fg(theme.success_color()).reversed(),
|
||||
let (title_line, border_color) = if self.get_exit_status().success() {
|
||||
(
|
||||
Line::styled(
|
||||
" SUCCESS - Press <ENTER> to close ",
|
||||
Style::default().fg(theme.success_color()).bold(),
|
||||
),
|
||||
theme.success_color(),
|
||||
)
|
||||
} else {
|
||||
Line::styled(
|
||||
"FAILED! Press <ENTER> to close this window",
|
||||
Style::default().fg(theme.fail_color()).reversed(),
|
||||
(
|
||||
Line::styled(
|
||||
" FAILED - Press <ENTER> to close ",
|
||||
Style::default().fg(theme.fail_color()).bold(),
|
||||
),
|
||||
theme.fail_color(),
|
||||
)
|
||||
};
|
||||
|
||||
let log_path = if let Some(log_path) = &self.log_path {
|
||||
Line::from(format!(" Log saved: {log_path} "))
|
||||
Line::styled(
|
||||
format!(" Log saved: {log_path} "),
|
||||
Style::default().fg(theme.unfocused_color()),
|
||||
)
|
||||
} else {
|
||||
Line::from(" Press 'l' to save command log ")
|
||||
Line::styled(
|
||||
" Press 'l' to save command log ",
|
||||
Style::default().fg(theme.unfocused_color()),
|
||||
)
|
||||
};
|
||||
|
||||
Block::bordered()
|
||||
.border_set(border::ROUNDED)
|
||||
.border_set(border::PLAIN)
|
||||
.border_style(Style::default().fg(border_color))
|
||||
.title_top(title_line.centered())
|
||||
.title_bottom(log_path.centered())
|
||||
};
|
||||
|
||||
+148
-65
@@ -4,9 +4,11 @@ use crate::{
|
||||
float::{Float, FloatContent},
|
||||
floating_text::FloatingText,
|
||||
hint::{create_shortcut_list, Shortcut},
|
||||
logo::Logo,
|
||||
root::check_root_status,
|
||||
running_command::RunningCommand,
|
||||
shortcuts,
|
||||
system_info::SystemInfo,
|
||||
theme::Theme,
|
||||
Args,
|
||||
};
|
||||
@@ -16,7 +18,7 @@ use ratatui::{
|
||||
layout::Flex,
|
||||
prelude::*,
|
||||
symbols::border,
|
||||
widgets::{Block, List, ListState, Paragraph},
|
||||
widgets::{Block, List, ListState, Padding, Paragraph},
|
||||
};
|
||||
use std::rc::Rc;
|
||||
|
||||
@@ -24,7 +26,9 @@ const MIN_WIDTH: u16 = 100;
|
||||
const MIN_HEIGHT: u16 = 25;
|
||||
const FLOAT_SIZE: u16 = 95;
|
||||
const CONFIRM_PROMPT_FLOAT_SIZE: u16 = 40;
|
||||
const TITLE: &str = concat!(" Linux Toolbox - ", env!("CARGO_PKG_VERSION"), " ");
|
||||
const LEFT_EXTRA_WIDTH: u16 = 4;
|
||||
const TITLE: &str = concat!(" LINUTIL v", env!("CARGO_PKG_VERSION"), " ");
|
||||
const LIST_HIGHLIGHT_SYMBOL: &str = "> ";
|
||||
const ACTIONS_GUIDE: &str = "List of important tasks performed by commands' names:
|
||||
|
||||
D - disk modifications (ex. partitioning) (privileged)
|
||||
@@ -67,6 +71,8 @@ pub struct AppState {
|
||||
size_bypass: bool,
|
||||
skip_confirmation: bool,
|
||||
mouse_enabled: bool,
|
||||
system_info: Option<SystemInfo>,
|
||||
logo: Option<Logo>,
|
||||
}
|
||||
|
||||
pub enum Focus {
|
||||
@@ -114,7 +120,7 @@ impl AppState {
|
||||
.iter()
|
||||
.map(|tab| tab.name.len() + args.theme.tab_icon().len())
|
||||
.max()
|
||||
.unwrap_or(22) as u16; // 22 is the length of "Linutil by Chris Titus" title
|
||||
.unwrap_or(22) as u16;
|
||||
|
||||
let mut state = Self {
|
||||
areas: None,
|
||||
@@ -134,6 +140,8 @@ impl AppState {
|
||||
size_bypass: args.size_bypass,
|
||||
skip_confirmation: args.skip_confirmation,
|
||||
mouse_enabled: args.mouse,
|
||||
system_info: SystemInfo::gather(),
|
||||
logo: Logo::load(),
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -294,29 +302,14 @@ impl AppState {
|
||||
return frame.render_widget(warning, centered_layout[1]);
|
||||
}
|
||||
|
||||
let label_block = Block::bordered().border_set(border::Set {
|
||||
top_left: " ",
|
||||
top_right: " ",
|
||||
bottom_left: " ",
|
||||
bottom_right: " ",
|
||||
vertical_left: " ",
|
||||
vertical_right: " ",
|
||||
horizontal_top: "*",
|
||||
horizontal_bottom: "*",
|
||||
});
|
||||
|
||||
let label = Paragraph::new(Line::from(vec![
|
||||
Span::styled("Linutil ", Style::default().bold()),
|
||||
Span::styled("by Chris Titus", Style::default().italic()),
|
||||
]))
|
||||
.block(label_block)
|
||||
.centered();
|
||||
|
||||
let (keybind_scope, shortcuts) = self.get_keybinds();
|
||||
|
||||
let keybinds_block = Block::bordered()
|
||||
.title(format!(" {keybind_scope} "))
|
||||
.border_set(border::ROUNDED);
|
||||
.border_set(border::PLAIN)
|
||||
.border_style(Style::default().fg(self.theme.unfocused_color()))
|
||||
.title_style(Style::default().fg(self.theme.tab_color()).bold())
|
||||
.padding(Padding::horizontal(1));
|
||||
|
||||
let keybind_render_width = keybinds_block.inner(area).width;
|
||||
let keybinds = create_shortcut_list(shortcuts, keybind_render_width);
|
||||
@@ -329,14 +322,49 @@ impl AppState {
|
||||
.split(area);
|
||||
|
||||
let horizontal = Layout::horizontal([
|
||||
Constraint::Min(self.longest_tab_display_len + 5),
|
||||
Constraint::Min(self.longest_tab_display_len + 7 + LEFT_EXTRA_WIDTH),
|
||||
Constraint::Percentage(100),
|
||||
])
|
||||
.split(vertical[0]);
|
||||
|
||||
let left_chunks =
|
||||
Layout::vertical([Constraint::Length(3), Constraint::Min(1)]).split(horizontal[0]);
|
||||
frame.render_widget(label, left_chunks[0]);
|
||||
let info_height = self
|
||||
.system_info
|
||||
.as_ref()
|
||||
.map(|info| info.entries_len() as u16 + 2)
|
||||
.unwrap_or(0);
|
||||
let show_info = info_height > 0 && horizontal[0].height > info_height.saturating_add(3);
|
||||
|
||||
let reserved_info_height = if show_info { info_height } else { 0 };
|
||||
let max_logo_area_height = horizontal[0]
|
||||
.height
|
||||
.saturating_sub(reserved_info_height)
|
||||
.saturating_sub(1);
|
||||
let logo_height = if let Some(logo) = &self.logo {
|
||||
logo.area_height_for_width(horizontal[0].width, max_logo_area_height)
|
||||
} else {
|
||||
max_logo_area_height.min(1)
|
||||
};
|
||||
let left_chunks = if show_info {
|
||||
Layout::vertical([
|
||||
Constraint::Length(logo_height),
|
||||
Constraint::Min(1),
|
||||
Constraint::Length(info_height),
|
||||
])
|
||||
.split(horizontal[0])
|
||||
} else {
|
||||
Layout::vertical([Constraint::Length(logo_height), Constraint::Min(1)])
|
||||
.split(horizontal[0])
|
||||
};
|
||||
if let Some(logo) = &mut self.logo {
|
||||
logo.draw(frame, left_chunks[0], &self.theme);
|
||||
} else {
|
||||
let label = Paragraph::new(Line::styled(
|
||||
format!("Linutil V{}", env!("CARGO_PKG_VERSION")),
|
||||
Style::default().fg(self.theme.tab_color()).bold(),
|
||||
))
|
||||
.alignment(Alignment::Center);
|
||||
frame.render_widget(label, left_chunks[0]);
|
||||
}
|
||||
|
||||
self.areas = Some(Areas {
|
||||
tab_list: left_chunks[1],
|
||||
@@ -349,36 +377,85 @@ impl AppState {
|
||||
.map(|tab| tab.name.as_str())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let (tab_hl_style, highlight_symbol) = if let Focus::TabList = self.focus {
|
||||
(
|
||||
Style::default().reversed().fg(self.theme.tab_color()),
|
||||
self.theme.tab_icon(),
|
||||
)
|
||||
} else if let Focus::Search = self.focus {
|
||||
(Style::reset(), " ")
|
||||
let tab_focus = matches!(self.focus, Focus::TabList);
|
||||
let tab_hl_style = if tab_focus {
|
||||
Style::default()
|
||||
.bg(self.theme.focused_color())
|
||||
.fg(Color::Black)
|
||||
.bold()
|
||||
} else {
|
||||
(
|
||||
Style::new().fg(self.theme.tab_color()),
|
||||
self.theme.tab_icon(),
|
||||
)
|
||||
Style::default().fg(self.theme.unfocused_color())
|
||||
};
|
||||
let highlight_symbol = self.theme.tab_icon();
|
||||
let tab_border_style = if tab_focus {
|
||||
Style::default().fg(self.theme.focused_color())
|
||||
} else {
|
||||
Style::default().fg(self.theme.unfocused_color())
|
||||
};
|
||||
|
||||
let tab_list = List::new(tabs)
|
||||
.block(Block::bordered().border_set(border::ROUNDED))
|
||||
.block(
|
||||
Block::bordered()
|
||||
.border_set(border::PLAIN)
|
||||
.border_style(tab_border_style)
|
||||
.padding(Padding::horizontal(1)),
|
||||
)
|
||||
.style(Style::default().fg(self.theme.tab_color()))
|
||||
.highlight_style(tab_hl_style)
|
||||
.highlight_symbol(highlight_symbol);
|
||||
frame.render_stateful_widget(tab_list, left_chunks[1], &mut self.current_tab);
|
||||
if show_info && left_chunks.len() > 2 {
|
||||
self.draw_system_info(frame, left_chunks[2]);
|
||||
}
|
||||
|
||||
let chunks =
|
||||
Layout::vertical([Constraint::Length(3), Constraint::Min(1)]).split(horizontal[1]);
|
||||
|
||||
self.filter.draw_searchbar(frame, chunks[0], &self.theme);
|
||||
|
||||
let title = if self.multi_select {
|
||||
&format!("{TITLE}[Multi-Select] ")
|
||||
} else {
|
||||
TITLE
|
||||
};
|
||||
|
||||
#[cfg(feature = "tips")]
|
||||
let bottom_title = Line::from(format!(" {} ", self.tip))
|
||||
.bold()
|
||||
.fg(self.theme.unfocused_color())
|
||||
.centered();
|
||||
#[cfg(not(feature = "tips"))]
|
||||
let bottom_title = "";
|
||||
|
||||
let task_list_title = Line::from(" FLAGS ").right_aligned();
|
||||
let list_focus = matches!(self.focus, Focus::List);
|
||||
let list_dim_style = if list_focus {
|
||||
Style::default()
|
||||
} else {
|
||||
Style::default().dim()
|
||||
};
|
||||
let list_border_style = if list_focus {
|
||||
Style::default().fg(self.theme.focused_color())
|
||||
} else {
|
||||
Style::default().fg(self.theme.unfocused_color())
|
||||
};
|
||||
let list_block = Block::bordered()
|
||||
.border_set(border::PLAIN)
|
||||
.border_style(list_border_style)
|
||||
.title(title)
|
||||
.title(task_list_title)
|
||||
.title_bottom(bottom_title)
|
||||
.padding(Padding::horizontal(1));
|
||||
let list_inner_width = list_block.inner(chunks[1]).width as usize;
|
||||
let list_content_width = list_inner_width.saturating_sub(LIST_HIGHLIGHT_SYMBOL.len());
|
||||
|
||||
let mut items: Vec<Line> = Vec::with_capacity(self.filter.item_list().len());
|
||||
|
||||
if !self.at_root() {
|
||||
items.push(
|
||||
Line::from(format!("{} ..", self.theme.dir_icon())).style(self.theme.dir_color()),
|
||||
Line::from(format!("{} ..", self.theme.dir_icon()))
|
||||
.style(self.theme.dir_color())
|
||||
.patch_style(list_dim_style),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -403,54 +480,43 @@ impl AppState {
|
||||
self.theme.dir_color(),
|
||||
)
|
||||
.patch_style(style)
|
||||
.patch_style(list_dim_style)
|
||||
} else {
|
||||
let left_content =
|
||||
format!("{} {} {}", self.theme.cmd_icon(), node.name, indicator);
|
||||
let right_content = format!("{} ", node.task_list);
|
||||
let center_space = " ".repeat(
|
||||
chunks[1].width as usize - left_content.len() - right_content.len(),
|
||||
list_content_width.saturating_sub(left_content.len() + right_content.len()),
|
||||
);
|
||||
Line::styled(
|
||||
format!("{left_content}{center_space}{right_content}"),
|
||||
self.theme.cmd_color(),
|
||||
)
|
||||
.patch_style(style)
|
||||
.patch_style(list_dim_style)
|
||||
}
|
||||
},
|
||||
));
|
||||
|
||||
let style = if let Focus::List = self.focus {
|
||||
Style::default().reversed()
|
||||
let list_highlight_style = if list_focus {
|
||||
Style::default()
|
||||
.bg(self.theme.focused_color())
|
||||
.fg(Color::Black)
|
||||
.bold()
|
||||
} else {
|
||||
Style::new()
|
||||
list_dim_style
|
||||
};
|
||||
|
||||
let title = if self.multi_select {
|
||||
&format!("{TITLE}[Multi-Select] ")
|
||||
let list_highlight_symbol = if list_focus {
|
||||
LIST_HIGHLIGHT_SYMBOL
|
||||
} else {
|
||||
TITLE
|
||||
" "
|
||||
};
|
||||
|
||||
#[cfg(feature = "tips")]
|
||||
let bottom_title = Line::from(format!(" {} ", self.tip))
|
||||
.bold()
|
||||
.blue()
|
||||
.centered();
|
||||
#[cfg(not(feature = "tips"))]
|
||||
let bottom_title = "";
|
||||
|
||||
let task_list_title = Line::from(" Important Actions ").right_aligned();
|
||||
|
||||
// Create the list widget with items
|
||||
let list = List::new(items)
|
||||
.highlight_style(style)
|
||||
.block(
|
||||
Block::bordered()
|
||||
.border_set(border::ROUNDED)
|
||||
.title(title)
|
||||
.title(task_list_title)
|
||||
.title_bottom(bottom_title),
|
||||
)
|
||||
.highlight_style(list_highlight_style)
|
||||
.highlight_symbol(list_highlight_symbol)
|
||||
.block(list_block)
|
||||
.scroll_padding(1);
|
||||
frame.render_stateful_widget(list, chunks[1], &mut self.selection);
|
||||
|
||||
@@ -901,4 +967,21 @@ impl AppState {
|
||||
}
|
||||
self.refresh_tab();
|
||||
}
|
||||
|
||||
fn draw_system_info(&self, frame: &mut Frame, area: Rect) {
|
||||
let Some(info) = &self.system_info else {
|
||||
return;
|
||||
};
|
||||
|
||||
let block = Block::bordered()
|
||||
.border_set(border::PLAIN)
|
||||
.border_style(Style::default().fg(self.theme.unfocused_color()))
|
||||
.title(" SYSTEM ")
|
||||
.title_style(Style::default().fg(self.theme.tab_color()).bold())
|
||||
.padding(Padding::horizontal(1));
|
||||
|
||||
let inner_width = block.inner(area).width as usize;
|
||||
let text = Text::from(info.render_lines(&self.theme, inner_width));
|
||||
frame.render_widget(Paragraph::new(text).block(block), area);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
use crate::theme::Theme;
|
||||
use ratatui::{
|
||||
style::{Style, Stylize},
|
||||
text::{Line, Span},
|
||||
};
|
||||
use std::process::Command;
|
||||
|
||||
const FASTFETCH_ARGS: [&str; 6] = [
|
||||
"--logo",
|
||||
"none",
|
||||
"--separator",
|
||||
" : ",
|
||||
"--structure",
|
||||
"cpu:disk:memory:gpu",
|
||||
];
|
||||
|
||||
pub struct SystemInfo {
|
||||
entries: Vec<InfoEntry>,
|
||||
}
|
||||
|
||||
struct InfoEntry {
|
||||
label: &'static str,
|
||||
value: String,
|
||||
}
|
||||
|
||||
impl SystemInfo {
|
||||
pub fn gather() -> Option<Self> {
|
||||
fastfetch_entries().map(|entries| Self { entries })
|
||||
}
|
||||
|
||||
pub fn entries_len(&self) -> usize {
|
||||
self.entries.len()
|
||||
}
|
||||
|
||||
pub fn render_lines(&self, theme: &Theme, max_width: usize) -> Vec<Line<'static>> {
|
||||
self.entries
|
||||
.iter()
|
||||
.map(|entry| {
|
||||
let prefix = format!("{:>4}: ", entry.label);
|
||||
let value_width = max_width.saturating_sub(prefix.len());
|
||||
let value = truncate_value(&entry.value, value_width);
|
||||
Line::from(vec![
|
||||
Span::styled(
|
||||
format!("{:>4}", entry.label),
|
||||
Style::default().fg(theme.tab_color()).bold(),
|
||||
),
|
||||
Span::styled(": ", Style::default().fg(theme.unfocused_color())),
|
||||
Span::styled(value, Style::default().fg(theme.cmd_color())),
|
||||
])
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn fastfetch_entries() -> Option<Vec<InfoEntry>> {
|
||||
let output = Command::new("fastfetch")
|
||||
.args(FASTFETCH_ARGS)
|
||||
.env("NO_COLOR", "1")
|
||||
.output()
|
||||
.ok()?;
|
||||
|
||||
if !output.status.success() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
let cleaned = strip_ansi_codes(&stdout);
|
||||
|
||||
let mut cpu = None;
|
||||
let mut disk = None;
|
||||
let mut ram = None;
|
||||
let mut gpu = None;
|
||||
|
||||
for line in cleaned.lines() {
|
||||
let line = line.trim();
|
||||
if line.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut parts = line.splitn(2, ':');
|
||||
let label = parts.next().unwrap_or("").trim();
|
||||
let value = parts.next().unwrap_or("").trim();
|
||||
if value.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let label_lower = label.to_ascii_lowercase();
|
||||
if cpu.is_none() && label_lower.starts_with("cpu") {
|
||||
cpu = Some(normalize_value("cpu", value));
|
||||
} else if disk.is_none() && label_lower.starts_with("disk") {
|
||||
disk = Some(normalize_value("disk", value));
|
||||
} else if ram.is_none()
|
||||
&& (label_lower.starts_with("memory") || label_lower.starts_with("ram"))
|
||||
{
|
||||
ram = Some(normalize_value("ram", value));
|
||||
} else if gpu.is_none() && label_lower.starts_with("gpu") {
|
||||
gpu = Some(normalize_value("gpu", value));
|
||||
}
|
||||
}
|
||||
|
||||
if cpu.is_none() && disk.is_none() && ram.is_none() && gpu.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(vec![
|
||||
InfoEntry {
|
||||
label: "CPU",
|
||||
value: cpu.unwrap_or_else(|| "n/a".to_string()),
|
||||
},
|
||||
InfoEntry {
|
||||
label: "DISK",
|
||||
value: disk.unwrap_or_else(|| "n/a".to_string()),
|
||||
},
|
||||
InfoEntry {
|
||||
label: "RAM",
|
||||
value: ram.unwrap_or_else(|| "n/a".to_string()),
|
||||
},
|
||||
InfoEntry {
|
||||
label: "GPU",
|
||||
value: gpu.unwrap_or_else(|| "n/a".to_string()),
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
fn strip_ansi_codes(input: &str) -> String {
|
||||
let mut output = String::with_capacity(input.len());
|
||||
let mut chars = input.chars().peekable();
|
||||
|
||||
while let Some(c) = chars.next() {
|
||||
if c == '\x1b' && matches!(chars.peek(), Some('[')) {
|
||||
chars.next();
|
||||
for next in chars.by_ref() {
|
||||
if next == 'm' {
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
output.push(c);
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
fn normalize_value(label: &str, value: &str) -> String {
|
||||
match label {
|
||||
"cpu" => strip_device_details(value),
|
||||
"gpu" => strip_device_details(value),
|
||||
"disk" => extract_total(value),
|
||||
"ram" => extract_total(value),
|
||||
_ => value.trim().to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn strip_device_details(value: &str) -> String {
|
||||
let mut trimmed = value.trim().to_string();
|
||||
if let Some(idx) = trimmed.find(" @") {
|
||||
trimmed.truncate(idx);
|
||||
trimmed = trimmed.trim().to_string();
|
||||
}
|
||||
if let Some(idx) = trimmed.find(" (") {
|
||||
trimmed.truncate(idx);
|
||||
trimmed = trimmed.trim().to_string();
|
||||
}
|
||||
if let Some(idx) = trimmed.find(" [") {
|
||||
trimmed.truncate(idx);
|
||||
trimmed = trimmed.trim().to_string();
|
||||
}
|
||||
trimmed
|
||||
}
|
||||
|
||||
fn extract_total(value: &str) -> String {
|
||||
let mut parts = value.splitn(2, '/');
|
||||
let _used = parts.next();
|
||||
let Some(total_part) = parts.next() else {
|
||||
return value.trim().to_string();
|
||||
};
|
||||
let mut tokens = total_part.split_whitespace();
|
||||
let Some(amount) = tokens.next() else {
|
||||
return total_part.trim().to_string();
|
||||
};
|
||||
let Some(unit) = tokens.next() else {
|
||||
return amount.to_string();
|
||||
};
|
||||
format!("{amount} {unit}")
|
||||
}
|
||||
|
||||
fn truncate_value(value: &str, max_width: usize) -> String {
|
||||
if max_width == 0 {
|
||||
return String::new();
|
||||
}
|
||||
|
||||
let value_chars: Vec<char> = value.chars().collect();
|
||||
if value_chars.len() <= max_width {
|
||||
return value.to_string();
|
||||
}
|
||||
|
||||
if max_width <= 3 {
|
||||
return value_chars.iter().take(max_width).collect();
|
||||
}
|
||||
|
||||
let slice: String = value_chars.iter().take(max_width - 3).collect();
|
||||
format!("{slice}...")
|
||||
}
|
||||
+17
-17
@@ -16,14 +16,14 @@ pub enum Theme {
|
||||
impl Theme {
|
||||
pub const fn dir_color(&self) -> Color {
|
||||
match self {
|
||||
Theme::Default => Color::Blue,
|
||||
Theme::Compatible => Color::Blue,
|
||||
Theme::Default => Color::LightCyan,
|
||||
Theme::Compatible => Color::Cyan,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn cmd_color(&self) -> Color {
|
||||
match self {
|
||||
Theme::Default => Color::Rgb(204, 224, 208),
|
||||
Theme::Default => Color::White,
|
||||
Theme::Compatible => Color::LightGreen,
|
||||
}
|
||||
}
|
||||
@@ -37,49 +37,49 @@ impl Theme {
|
||||
|
||||
pub const fn tab_color(&self) -> Color {
|
||||
match self {
|
||||
Theme::Default => Color::Rgb(255, 255, 85),
|
||||
Theme::Compatible => Color::Yellow,
|
||||
Theme::Default => Color::Yellow,
|
||||
Theme::Compatible => Color::LightYellow,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn dir_icon(&self) -> &'static str {
|
||||
match self {
|
||||
Theme::Default => " ",
|
||||
Theme::Compatible => "[DIR]",
|
||||
Theme::Default => "[D]",
|
||||
Theme::Compatible => "[D]",
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn cmd_icon(&self) -> &'static str {
|
||||
match self {
|
||||
Theme::Default => " ",
|
||||
Theme::Compatible => "[CMD]",
|
||||
Theme::Default => "[*]",
|
||||
Theme::Compatible => "[*]",
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn tab_icon(&self) -> &'static str {
|
||||
match self {
|
||||
Theme::Default => " ",
|
||||
Theme::Compatible => ">> ",
|
||||
Theme::Default => ">> ",
|
||||
Theme::Compatible => "> ",
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn multi_select_icon(&self) -> &'static str {
|
||||
match self {
|
||||
Theme::Default => "",
|
||||
Theme::Default => "*",
|
||||
Theme::Compatible => "*",
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn success_color(&self) -> Color {
|
||||
match self {
|
||||
Theme::Default => Color::Rgb(5, 255, 55),
|
||||
Theme::Default => Color::LightGreen,
|
||||
Theme::Compatible => Color::Green,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn fail_color(&self) -> Color {
|
||||
match self {
|
||||
Theme::Default => Color::Rgb(199, 55, 44),
|
||||
Theme::Default => Color::LightRed,
|
||||
Theme::Compatible => Color::Red,
|
||||
}
|
||||
}
|
||||
@@ -87,21 +87,21 @@ impl Theme {
|
||||
pub const fn focused_color(&self) -> Color {
|
||||
match self {
|
||||
Theme::Default => Color::LightBlue,
|
||||
Theme::Compatible => Color::LightBlue,
|
||||
Theme::Compatible => Color::LightCyan,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn search_preview_color(&self) -> Color {
|
||||
match self {
|
||||
Theme::Default => Color::DarkGray,
|
||||
Theme::Compatible => Color::DarkGray,
|
||||
Theme::Compatible => Color::Gray,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn unfocused_color(&self) -> Color {
|
||||
match self {
|
||||
Theme::Default => Color::Gray,
|
||||
Theme::Compatible => Color::Gray,
|
||||
Theme::Compatible => Color::DarkGray,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user