diff --git a/.cargo-husky/hooks/pre-commit b/.cargo-husky/hooks/pre-commit index 3c6555f..53a76cd 100755 --- a/.cargo-husky/hooks/pre-commit +++ b/.cargo-husky/hooks/pre-commit @@ -1,6 +1,6 @@ #!/usr/bin/env bash -if !(command cargo-make >/dev/null 2>&1); then # Check if cargo-make is installed +if !(command cargo make >/dev/null 2>&1); then # Check if cargo-make is installed echo Attempting to run cargo-make as part of the pre-push hook but it\'s not installed. echo Please install it by running the following command: echo diff --git a/.cargo-husky/hooks/pre-push b/.cargo-husky/hooks/pre-push index 3c6555f..53a76cd 100755 --- a/.cargo-husky/hooks/pre-push +++ b/.cargo-husky/hooks/pre-push @@ -1,6 +1,6 @@ #!/usr/bin/env bash -if !(command cargo-make >/dev/null 2>&1); then # Check if cargo-make is installed +if !(command cargo make >/dev/null 2>&1); then # Check if cargo-make is installed echo Attempting to run cargo-make as part of the pre-push hook but it\'s not installed. echo Please install it by running the following command: echo diff --git a/.config/config.json5 b/.config/config.json5 index 7c847ab..0f6808c 100644 --- a/.config/config.json5 +++ b/.config/config.json5 @@ -1,10 +1,12 @@ { "keybindings": { - "Process": { + "Home": { "": "Quit", // Quit the application "": "Quit", // Another way to quit "": "Quit", // Yet another way to quit - "": "Suspend" // Suspend the application + "": "Suspend", // Suspend the application + "": "Up", + "": "Down" }, } } diff --git a/Cargo.lock b/Cargo.lock index 8316c35..7e47c23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -17,11 +17,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", "once_cell", @@ -76,9 +82,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" @@ -110,9 +116,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.83" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "arc-swap" @@ -120,6 +126,12 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" +[[package]] +name = "arraydeque" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" + [[package]] name = "async-trait" version = "0.1.80" @@ -128,7 +140,16 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.103", +] + +[[package]] +name = "atomic" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340" +dependencies = [ + "bytemuck", ] [[package]] @@ -147,7 +168,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.2", "object", "rustc-demangle", ] @@ -158,6 +179,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "battery" version = "0.7.8" @@ -169,7 +196,7 @@ dependencies = [ "lazycell", "libc", "mach", - "nix", + "nix 0.19.1", "num-traits", "uom", "winapi", @@ -185,6 +212,21 @@ dependencies = [ "console", ] +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" @@ -193,9 +235,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" dependencies = [ "serde", ] @@ -217,43 +259,61 @@ dependencies = [ "battery", "better-panic", "cargo-husky", + "chrono", "clap", "color-eyre", "config", - "crossterm", + "crossterm 0.28.1", "derive_deref", "directories", - "dirs", "futures", "human-panic", - "humansize", "json5", "lazy_static", "libc", - "log", - "log4rs", - "owo-colors 4.0.0", "pretty_assertions", "procfs", "ratatui", "serde", "signal-hook", "strip-ansi-escapes", - "strum", + "strum 0.26.3", "tokio", "tokio-util", "tracing", "tracing-error", "tracing-subscriber", - "tui-input", - "uzers", + "vergen-gix", +] + +[[package]] +name = "bstr" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +dependencies = [ + "memchr", + "regex-automata 0.4.9", + "serde", ] [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" + +[[package]] +name = "bytemuck" +version = "1.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" + +[[package]] +name = "byteorder" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" @@ -261,6 +321,15 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +[[package]] +name = "camino" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab" +dependencies = [ + "serde", +] + [[package]] name = "cargo-husky" version = "1.5.0" @@ -268,16 +337,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b02b629252fe8ef6460461409564e2c21d0c8e77e0944f3d189ff06c4e932ad" [[package]] -name = "cassowary" -version = "0.3.0" +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.12", +] [[package]] name = "castaway" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a17ed5635fc8536268e5d4de1e22e81ac34419e5f052d4d51f4e01dcc263fcc" +checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5" dependencies = [ "rustversion", ] @@ -294,23 +380,31 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", - "windows-targets 0.52.5", + "wasm-bindgen", + "windows-link", ] [[package]] name = "clap" -version = "4.5.4" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", "clap_derive", @@ -318,9 +412,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ "anstream", "anstyle", @@ -333,45 +427,51 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.103", ] [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "clru" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "cbd0f76e066e64fdc5631e3bb46381254deab9ef1158292f27c8c57e3bf3fe59" [[package]] name = "color-eyre" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" +checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d" dependencies = [ "backtrace", "color-spantrace", "eyre", "indenter", "once_cell", - "owo-colors 3.5.0", + "owo-colors", "tracing-error", ] [[package]] name = "color-spantrace" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" +checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427" dependencies = [ "once_cell", - "owo-colors 3.5.0", + "owo-colors", "tracing-core", "tracing-error", ] @@ -384,27 +484,28 @@ checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "compact_str" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" +checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a" dependencies = [ "castaway", "cfg-if", "itoa", + "rustversion", "ryu", + "serde", "static_assertions", ] [[package]] name = "config" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be" +checksum = "68578f196d2a33ff61b27fae256c3164f65e36382648e30666dde05b8cc9dfdf" dependencies = [ "async-trait", - "convert_case", + "convert_case 0.6.0", "json5", - "lazy_static", "nom", "pathdiff", "ron", @@ -412,7 +513,7 @@ dependencies = [ "serde", "serde_json", "toml", - "yaml-rust", + "yaml-rust2", ] [[package]] @@ -442,7 +543,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "getrandom", + "getrandom 0.2.15", "once_cell", "tiny-keccak", ] @@ -456,6 +557,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "convert_case" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.7.0" @@ -474,9 +584,9 @@ checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" @@ -489,25 +599,50 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + [[package]] name = "crossterm" -version = "0.27.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" +checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.9.1", "crossterm_winapi", "futures-core", - "libc", "mio", "parking_lot", + "rustix 0.38.34", + "serde", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" +dependencies = [ + "bitflags 2.9.1", + "crossterm_winapi", + "derive_more", + "document-features", + "mio", + "parking_lot", + "rustix 1.0.7", "serde", "signal-hook", "signal-hook-mio", @@ -540,14 +675,108 @@ dependencies = [ ] [[package]] -name = "derivative" -version = "2.2.0" +name = "csscolorparser" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2a7d3066da2de787b7f032c736763eb7ae5d355f81a68bab2675a96008b0bf" +dependencies = [ + "lab", + "phf", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ + "fnv", + "ident_case", "proc-macro2", "quote", - "syn 1.0.109", + "strsim", + "syn 2.0.103", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.103", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "deltae" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5729f5117e208430e437df2f4843f5e5952997175992d1414f94c57d61e270b4" + +[[package]] +name = "deranged" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.103", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn 2.0.103", ] [[package]] @@ -562,10 +791,25 @@ dependencies = [ ] [[package]] -name = "destructure_traitobject" -version = "0.2.0" +name = "derive_more" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c877555693c14d2f84191cfd3ad8582790fc52b5e2274b40b59cf5f5cea25c7" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "convert_case 0.7.1", + "proc-macro2", + "quote", + "syn 2.0.103", +] [[package]] name = "diff" @@ -592,15 +836,6 @@ dependencies = [ "dirs-sys", ] -[[package]] -name = "dirs" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" -dependencies = [ - "dirs-sys", -] - [[package]] name = "dirs-sys" version = "0.4.1" @@ -613,6 +848,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] + [[package]] name = "dlv-list" version = "0.5.2" @@ -622,6 +868,21 @@ dependencies = [ "const-random", ] +[[package]] +name = "document-features" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +dependencies = [ + "litrs", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "either" version = "1.11.0" @@ -634,6 +895,15 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -642,12 +912,21 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", +] + +[[package]] +name = "euclid" +version = "0.22.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad9cdb4b747e485a12abb0e6566612956c7a1bafa3bdb8d682c5b6d403589e48" +dependencies = [ + "num-traits", ] [[package]] @@ -661,97 +940,182 @@ dependencies = [ ] [[package]] -name = "flate2" -version = "1.0.30" +name = "fancy-regex" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" dependencies = [ - "crc32fast", - "miniz_oxide", + "bit-set", + "regex", ] [[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "futures" -version = "0.3.30" +name = "faster-hex" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183" dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", + "serde", ] [[package]] -name = "futures-channel" -version = "0.3.30" +name = "faster-hex" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "7223ae2d2f179b803433d9c830478527e92b8117eab39460edae7f1614d9fb73" dependencies = [ - "futures-core", - "futures-sink", + "heapless", + "serde", ] [[package]] -name = "futures-core" -version = "0.3.30" +name = "fastrand" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] -name = "futures-executor" -version = "0.3.30" +name = "filedescriptor" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "e40758ed24c9b2eeb76c35fb0aebc66c626084edd827e07e1552279814c6682d" dependencies = [ - "futures-core", - "futures-task", - "futures-util", + "libc", + "thiserror 1.0.60", + "winapi", ] [[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[package]] -name = "futures-macro" -version = "0.3.30" +name = "filetime" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.63", + "cfg-if", + "libc", + "libredox", + "windows-sys 0.59.0", ] [[package]] -name = "futures-sink" -version = "0.3.30" +name = "finl_unicode" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "94c970b525906eb37d3940083aa65b95e481fc1857d467d13374e1d925cfc163" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide 0.8.9", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -783,7 +1147,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] @@ -792,98 +1168,1024 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "gix" +version = "0.71.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a61e71ec6817fc3c9f12f812682cfe51ee6ea0d2e27e02fc3849c35524617435" +dependencies = [ + "gix-actor", + "gix-attributes", + "gix-command", + "gix-commitgraph", + "gix-config", + "gix-date", + "gix-diff", + "gix-dir", + "gix-discover", + "gix-features 0.41.1", + "gix-filter", + "gix-fs", + "gix-glob", + "gix-hash 0.17.0", + "gix-hashtable", + "gix-ignore", + "gix-index", + "gix-lock", + "gix-object", + "gix-odb", + "gix-pack", + "gix-path", + "gix-pathspec", + "gix-protocol", + "gix-ref", + "gix-refspec", + "gix-revision", + "gix-revwalk", + "gix-sec", + "gix-shallow", + "gix-status", + "gix-submodule", + "gix-tempfile", + "gix-trace", + "gix-traverse", + "gix-url", + "gix-utils", + "gix-validate 0.9.4", + "gix-worktree", + "once_cell", + "parking_lot", + "signal-hook", + "smallvec", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-actor" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f438c87d4028aca4b82f82ba8d8ab1569823cfb3e5bc5fa8456a71678b2a20e7" +dependencies = [ + "bstr", + "gix-date", + "gix-utils", + "itoa", + "thiserror 2.0.12", + "winnow 0.7.11", +] + +[[package]] +name = "gix-attributes" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e25825e0430aa11096f8b65ced6780d4a96a133f81904edceebb5344c8dd7f" +dependencies = [ + "bstr", + "gix-glob", + "gix-path", + "gix-quote", + "gix-trace", + "kstring", + "smallvec", + "thiserror 2.0.12", + "unicode-bom", +] + +[[package]] +name = "gix-bitmap" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1db9765c69502650da68f0804e3dc2b5f8ccc6a2d104ca6c85bc40700d37540" +dependencies = [ + "thiserror 2.0.12", +] + +[[package]] +name = "gix-chunk" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b1f1d8764958699dc764e3f727cef280ff4d1bd92c107bbf8acd85b30c1bd6f" +dependencies = [ + "thiserror 2.0.12", +] + +[[package]] +name = "gix-command" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0378995847773a697f8e157fe2963ecf3462fe64be05b7b3da000b3b472def8" +dependencies = [ + "bstr", + "gix-path", + "gix-quote", + "gix-trace", + "shell-words", +] + +[[package]] +name = "gix-commitgraph" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043cbe49b7a7505150db975f3cb7c15833335ac1e26781f615454d9d640a28fe" +dependencies = [ + "bstr", + "gix-chunk", + "gix-hash 0.17.0", + "memmap2", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-config" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c6f830bf746604940261b49abf7f655d2c19cadc9f4142ae9379e3a316e8cfa" +dependencies = [ + "bstr", + "gix-config-value", + "gix-features 0.41.1", + "gix-glob", + "gix-path", + "gix-ref", + "gix-sec", + "memchr", + "once_cell", + "smallvec", + "thiserror 2.0.12", + "unicode-bom", + "winnow 0.7.11", +] + +[[package]] +name = "gix-config-value" +version = "0.14.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dc2c844c4cf141884678cabef736fd91dd73068b9146e6f004ba1a0457944b6" +dependencies = [ + "bitflags 2.9.1", + "bstr", + "gix-path", + "libc", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-date" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daa30058ec7d3511fbc229e4f9e696a35abd07ec5b82e635eff864a2726217e4" +dependencies = [ + "bstr", + "itoa", + "jiff", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-diff" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2c975dad2afc85e4e233f444d1efbe436c3cdcf3a07173984509c436d00a3f8" +dependencies = [ + "bstr", + "gix-attributes", + "gix-command", + "gix-filter", + "gix-fs", + "gix-hash 0.17.0", + "gix-index", + "gix-object", + "gix-path", + "gix-pathspec", + "gix-tempfile", + "gix-trace", + "gix-traverse", + "gix-worktree", + "imara-diff", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-dir" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5879497bd3815d8277ed864ec8975290a70de5b62bb92d2d666a4cefc5d4793b" +dependencies = [ + "bstr", + "gix-discover", + "gix-fs", + "gix-ignore", + "gix-index", + "gix-object", + "gix-path", + "gix-pathspec", + "gix-trace", + "gix-utils", + "gix-worktree", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-discover" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fb8a4349b854506a3915de18d3341e5f1daa6b489c8affc9ca0d69efe86781" +dependencies = [ + "bstr", + "dunce", + "gix-fs", + "gix-hash 0.17.0", + "gix-path", + "gix-ref", + "gix-sec", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-features" +version = "0.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016d6050219458d14520fe22bdfdeb9cb71631dec9bc2724767c983f60109634" +dependencies = [ + "crc32fast", + "flate2", + "gix-path", + "gix-trace", + "gix-utils", + "libc", + "once_cell", + "prodash", + "thiserror 2.0.12", + "walkdir", +] + +[[package]] +name = "gix-features" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f4399af6ec4fd9db84dd4cf9656c5c785ab492ab40a7c27ea92b4241923fed" +dependencies = [ + "gix-trace", + "libc", + "prodash", +] + +[[package]] +name = "gix-filter" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb2b2bbffdc5cc9b2b82fc82da1b98163c9b423ac2b45348baa83a947ac9ab89" +dependencies = [ + "bstr", + "encoding_rs", + "gix-attributes", + "gix-command", + "gix-hash 0.17.0", + "gix-object", + "gix-packetline-blocking", + "gix-path", + "gix-quote", + "gix-trace", + "gix-utils", + "smallvec", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-fs" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "951e886120dc5fa8cac053e5e5c89443f12368ca36811b2e43d1539081f9c111" +dependencies = [ + "bstr", + "fastrand", + "gix-features 0.41.1", + "gix-path", + "gix-utils", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-glob" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20972499c03473e773a2099e5fd0c695b9b72465837797a51a43391a1635a030" +dependencies = [ + "bitflags 2.9.1", + "bstr", + "gix-features 0.41.1", + "gix-path", +] + +[[package]] +name = "gix-hash" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "834e79722063958b03342edaa1e17595cd2939bb2b3306b3225d0815566dcb49" +dependencies = [ + "faster-hex 0.9.0", + "gix-features 0.41.1", + "sha1-checked", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-hash" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d4900562c662852a6b42e2ef03442eccebf24f047d8eab4f23bc12ef0d785d8" +dependencies = [ + "faster-hex 0.10.0", + "gix-features 0.42.1", + "sha1-checked", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-hashtable" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b5cb3c308b4144f2612ff64e32130e641279fcf1a84d8d40dad843b4f64904" +dependencies = [ + "gix-hash 0.18.0", + "hashbrown 0.14.5", + "parking_lot", +] + +[[package]] +name = "gix-ignore" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a27c8380f493a10d1457f756a3f81924d578fc08d6535e304dfcafbf0261d18" +dependencies = [ + "bstr", + "gix-glob", + "gix-path", + "gix-trace", + "unicode-bom", +] + +[[package]] +name = "gix-index" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "855bece2d4153453aa5d0a80d51deea1ce8cd6a3b4cf213da85ac344ccb908a7" +dependencies = [ + "bitflags 2.9.1", + "bstr", + "filetime", + "fnv", + "gix-bitmap", + "gix-features 0.41.1", + "gix-fs", + "gix-hash 0.17.0", + "gix-lock", + "gix-object", + "gix-traverse", + "gix-utils", + "gix-validate 0.9.4", + "hashbrown 0.14.5", + "itoa", + "libc", + "memmap2", + "rustix 0.38.34", + "smallvec", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-lock" +version = "17.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df47b8f11c34520db5541bc5fc9fbc8e4b0bdfcec3736af89ccb1a5728a0126f" +dependencies = [ + "gix-tempfile", + "gix-utils", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-object" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4943fcdae6ffc135920c9ea71e0362ed539182924ab7a85dd9dac8d89b0dd69a" +dependencies = [ + "bstr", + "gix-actor", + "gix-date", + "gix-features 0.41.1", + "gix-hash 0.17.0", + "gix-hashtable", + "gix-path", + "gix-utils", + "gix-validate 0.9.4", + "itoa", + "smallvec", + "thiserror 2.0.12", + "winnow 0.7.11", +] + +[[package]] +name = "gix-odb" +version = "0.68.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50306d40dcc982eb6b7593103f066ea6289c7b094cb9db14f3cd2be0b9f5e610" +dependencies = [ + "arc-swap", + "gix-date", + "gix-features 0.41.1", + "gix-fs", + "gix-hash 0.17.0", + "gix-hashtable", + "gix-object", + "gix-pack", + "gix-path", + "gix-quote", + "parking_lot", + "tempfile", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-pack" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b65fffb09393c26624ca408d32cfe8776fb94cd0a5cdf984905e1d2f39779cb" +dependencies = [ + "clru", + "gix-chunk", + "gix-features 0.41.1", + "gix-hash 0.17.0", + "gix-hashtable", + "gix-object", + "gix-path", + "memmap2", + "smallvec", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-packetline" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "123844a70cf4d5352441dc06bab0da8aef61be94ec239cb631e0ba01dc6d3a04" +dependencies = [ + "bstr", + "faster-hex 0.9.0", + "gix-trace", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-packetline-blocking" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ecf3ea2e105c7e45587bac04099824301262a6c43357fad5205da36dbb233b3" +dependencies = [ + "bstr", + "faster-hex 0.9.0", + "gix-trace", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-path" +version = "0.10.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567f65fec4ef10dfab97ae71f26a27fd4d7fe7b8e3f90c8a58551c41ff3fb65b" +dependencies = [ + "bstr", + "gix-trace", + "gix-validate 0.10.0", + "home", + "once_cell", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-pathspec" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fef8422c3c9066d649074b24025125963f85232bfad32d6d16aea9453b82ec14" +dependencies = [ + "bitflags 2.9.1", + "bstr", + "gix-attributes", + "gix-config-value", + "gix-glob", + "gix-path", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-protocol" +version = "0.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5678ddae1d62880bc30e2200be1b9387af3372e0e88e21f81b4e7f8367355b5a" +dependencies = [ + "bstr", + "gix-date", + "gix-features 0.41.1", + "gix-hash 0.17.0", + "gix-ref", + "gix-shallow", + "gix-transport", + "gix-utils", + "maybe-async", + "thiserror 2.0.12", + "winnow 0.7.11", +] + +[[package]] +name = "gix-quote" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b005c550bf84de3b24aa5e540a23e6146a1c01c7d30470e35d75a12f827f969" +dependencies = [ + "bstr", + "gix-utils", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-ref" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e1f7eb6b7ce82d2d19961f74bd637bab3ea79b1bc7bfb23dbefc67b0415d8b" +dependencies = [ + "gix-actor", + "gix-features 0.41.1", + "gix-fs", + "gix-hash 0.17.0", + "gix-lock", + "gix-object", + "gix-path", + "gix-tempfile", + "gix-utils", + "gix-validate 0.9.4", + "memmap2", + "thiserror 2.0.12", + "winnow 0.7.11", +] + +[[package]] +name = "gix-refspec" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d8587b21e2264a6e8938d940c5c99662779c13a10741a5737b15fc85c252ffc" +dependencies = [ + "bstr", + "gix-hash 0.17.0", + "gix-revision", + "gix-validate 0.9.4", + "smallvec", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-revision" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "342caa4e158df3020cadf62f656307c3948fe4eacfdf67171d7212811860c3e9" +dependencies = [ + "bitflags 2.9.1", + "bstr", + "gix-commitgraph", + "gix-date", + "gix-hash 0.17.0", + "gix-hashtable", + "gix-object", + "gix-revwalk", + "gix-trace", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-revwalk" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc7c3d7e5cdc1ab8d35130106e4af0a4f9f9eca0c81f4312b690780e92bde0d" +dependencies = [ + "gix-commitgraph", + "gix-date", + "gix-hash 0.17.0", + "gix-hashtable", + "gix-object", + "smallvec", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-sec" +version = "0.10.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47aeb0f13de9ef2f3033f5ff218de30f44db827ac9f1286f9ef050aacddd5888" +dependencies = [ + "bitflags 2.9.1", + "gix-path", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "gix-shallow" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc0598aacfe1d52575a21c9492fee086edbb21e228ec36c819c42ab923f434c3" +dependencies = [ + "bstr", + "gix-hash 0.17.0", + "gix-lock", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-status" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "605a6d0eb5891680c46e24b2ee7a63ef7bd39cb136dc7c7e55172960cf68b2f5" +dependencies = [ + "bstr", + "filetime", + "gix-diff", + "gix-dir", + "gix-features 0.41.1", + "gix-filter", + "gix-fs", + "gix-hash 0.17.0", + "gix-index", + "gix-object", + "gix-path", + "gix-pathspec", + "gix-worktree", + "portable-atomic", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-submodule" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c7390c2059505c365e9548016d4edc9f35749c6a9112b7b1214400bbc68da2" +dependencies = [ + "bstr", + "gix-config", + "gix-path", + "gix-pathspec", + "gix-refspec", + "gix-url", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-tempfile" +version = "17.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6de439bbb9a5d3550c9c7fab0e16d2d637d120fcbe0dfbc538772a187f099b" +dependencies = [ + "dashmap", + "gix-fs", + "libc", + "once_cell", + "parking_lot", + "signal-hook", + "signal-hook-registry", + "tempfile", +] + +[[package]] +name = "gix-trace" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c396a2036920c69695f760a65e7f2677267ccf483f25046977d87e4cb2665f7" + +[[package]] +name = "gix-transport" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3f68c2870bfca8278389d2484a7f2215b67d0b0cc5277d3c72ad72acf41787e" +dependencies = [ + "bstr", + "gix-command", + "gix-features 0.41.1", + "gix-packetline", + "gix-quote", + "gix-sec", + "gix-url", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-traverse" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c0b049f8bdb61b20016694102f7b507f2e1727e83e9c5e6dad4f7d84ff7384" +dependencies = [ + "bitflags 2.9.1", + "gix-commitgraph", + "gix-date", + "gix-hash 0.17.0", + "gix-hashtable", + "gix-object", + "gix-revwalk", + "smallvec", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-url" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48dfe23f93f1ddb84977d80bb0dd7aa09d1bf5d5afc0c9b6820cccacc25ae860" +dependencies = [ + "bstr", + "gix-features 0.41.1", + "gix-path", + "percent-encoding", + "thiserror 2.0.12", + "url", +] + +[[package]] +name = "gix-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "189f8724cf903e7fd57cfe0b7bc209db255cacdcb22c781a022f52c3a774f8d0" +dependencies = [ + "bstr", + "fastrand", + "unicode-normalization", +] + +[[package]] +name = "gix-validate" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b5f1253109da6c79ed7cf6e1e38437080bb6d704c76af14c93e2f255234084" +dependencies = [ + "bstr", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-validate" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77b9e00cacde5b51388d28ed746c493b18a6add1f19b5e01d686b3b9ece66d4d" +dependencies = [ + "bstr", + "thiserror 2.0.12", +] + +[[package]] +name = "gix-worktree" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7760dbc4b79aa274fed30adc0d41dca6b917641f26e7867c4071b1fb4dc727b" +dependencies = [ + "bstr", + "gix-attributes", + "gix-features 0.41.1", + "gix-fs", + "gix-glob", + "gix-hash 0.17.0", + "gix-ignore", + "gix-index", + "gix-object", + "gix-path", + "gix-validate 0.9.4", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "home" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "human-panic" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80b84a66a325082740043a6c28bbea400c129eac0d3a27673a1de971e44bf1f7" +dependencies = [ + "anstream", + "anstyle", + "backtrace", + "os_info", + "serde", + "serde_derive", + "toml", + "uuid", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys 0.8.7", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] [[package]] -name = "hashbrown" -version = "0.14.5" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ - "ahash", - "allocator-api2", + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", ] [[package]] -name = "heck" -version = "0.4.1" +name = "icu_normalizer" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] [[package]] -name = "heck" -version = "0.5.0" +name = "icu_normalizer_data" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] -name = "hermit-abi" -version = "0.3.9" +name = "icu_properties" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] [[package]] -name = "hex" -version = "0.4.3" +name = "icu_properties_data" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] -name = "human-panic" +name = "icu_provider" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c5d0e9120f6bca6120d142c7ede1ba376dd6bf276d69dd3dbe6cbeb7824179" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ - "anstream", - "anstyle", - "backtrace", - "os_info", - "serde", - "serde_derive", - "toml", - "uuid", + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", ] [[package]] -name = "humansize" -version = "2.1.3" +name = "ident_case" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" -dependencies = [ - "libm", -] +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] -name = "humantime" -version = "2.1.0" +name = "idna" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] [[package]] -name = "iana-time-zone" -version = "0.1.60" +name = "idna_adapter" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ - "android_system_properties", - "core-foundation-sys 0.8.6", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", + "icu_normalizer", + "icu_properties", ] [[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" +name = "imara-diff" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +checksum = "17d34b7d42178945f775e84bc4c36dde7c1c6cdfea656d3354d009056f2bb3d2" dependencies = [ - "cc", + "hashbrown 0.15.4", ] [[package]] @@ -908,6 +2210,19 @@ version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" +[[package]] +name = "instability" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf9fed6d91cfb734e7476a06bde8300a1b94e217e1b523b6f0cd1a01998c71d" +dependencies = [ + "darling", + "indoc", + "proc-macro2", + "quote", + "syn 2.0.103", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.0" @@ -916,9 +2231,18 @@ checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" [[package]] name = "itertools" -version = "0.12.1" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] @@ -929,12 +2253,54 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jiff" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +dependencies = [ + "jiff-static", + "jiff-tzdb-platform", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", + "windows-sys 0.59.0", +] + +[[package]] +name = "jiff-static" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1283705eb0a21404d2bfd6eef2a7593d240bc42a0bdb39db0ad6fa2ec026524" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" +dependencies = [ + "jiff-tzdb", +] + [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -949,11 +2315,36 @@ dependencies = [ "serde", ] +[[package]] +name = "kasuari" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def1b67294a9fdc95eeeeafd1209c7a1b8a82aa0bf80ac2ab2a7d0318e9c7622" +dependencies = [ + "hashbrown 0.15.4", + "thiserror 2.0.12", +] + +[[package]] +name = "kstring" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "558bf9508a558512042d3095138b1f7b8fe90c5467d94f9f1da28b3731c5dbd1" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "lab" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf36173d4167ed999940f804952e6b08197cae5ad5d572eb4db150ce8ad5d58f" + [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "lazycell" @@ -963,15 +2354,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.154" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" - -[[package]] -name = "libm" -version = "0.2.8" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libredox" @@ -979,15 +2364,19 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.9.1", "libc", + "redox_syscall", ] [[package]] -name = "linked-hash-map" -version = "0.5.6" +name = "line-clipping" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +checksum = "51a1679740111eb63b7b4cb3c97b1d5d9f82e142292a25edcfdb4120a48b3880" +dependencies = [ + "bitflags 2.9.1", +] [[package]] name = "linux-raw-sys" @@ -995,6 +2384,24 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + [[package]] name = "lock_api" version = "0.4.12" @@ -1010,51 +2417,24 @@ name = "log" version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" -dependencies = [ - "serde", -] - -[[package]] -name = "log-mdc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7" [[package]] -name = "log4rs" -version = "1.3.0" +name = "lru" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0816135ae15bd0391cf284eab37e6e3ee0a6ee63d2ceeb659862bd8d0a984ca6" +checksum = "9f8cc7106155f10bdf99a6f379688f543ad6596a415375b36a59a054ceda1198" dependencies = [ - "anyhow", - "arc-swap", - "chrono", - "derivative", - "fnv", - "humantime", - "libc", - "log", - "log-mdc", - "once_cell", - "parking_lot", - "rand", - "serde", - "serde-value", - "serde_json", - "serde_yaml", - "thiserror", - "thread-id", - "typemap-ors", - "winapi", + "hashbrown 0.15.4", ] [[package]] -name = "lru" -version = "0.12.3" +name = "mac_address" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +checksum = "c0aeb26bf5e836cc1c341c8106051b573f1766dfa05aa87f0b98be5e51b02303" dependencies = [ - "hashbrown 0.14.5", + "nix 0.29.0", + "winapi", ] [[package]] @@ -1075,11 +2455,46 @@ dependencies = [ "regex-automata 0.1.10", ] +[[package]] +name = "maybe-async" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] + [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "memmap2" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +dependencies = [ + "libc", +] + +[[package]] +name = "memmem" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64a92489e2744ce060c349162be1c5f33c6969234104dbd99ddb5feb08b8c15" + +[[package]] +name = "memoffset" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] [[package]] name = "minimal-lexical" @@ -1096,16 +2511,25 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + [[package]] name = "mio" -version = "0.8.11" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "log", - "wasi", - "windows-sys 0.48.0", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] @@ -1120,6 +2544,19 @@ dependencies = [ "libc", ] +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.9.1", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + [[package]] name = "nom" version = "7.1.3" @@ -1140,6 +2577,23 @@ dependencies = [ "winapi", ] +[[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 2.0.103", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -1150,15 +2604,20 @@ dependencies = [ ] [[package]] -name = "num_cpus" -version = "1.16.0" +name = "num_threads" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" dependencies = [ - "hermit-abi", "libc", ] +[[package]] +name = "numtoa" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f" + [[package]] name = "object" version = "0.32.2" @@ -1170,9 +2629,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "option-ext" @@ -1182,21 +2641,21 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "ordered-float" -version = "2.10.1" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" dependencies = [ "num-traits", ] [[package]] name = "ordered-multimap" -version = "0.6.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e" +checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" dependencies = [ "dlv-list", - "hashbrown 0.13.2", + "hashbrown 0.14.5", ] [[package]] @@ -1218,15 +2677,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "owo-colors" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" - -[[package]] -name = "owo-colors" -version = "4.0.0" +version = "4.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f" +checksum = "26995317201fa17f3656c36716aed4a7c81743a9634ac4c99c0eeda495db0cec" [[package]] name = "parking_lot" @@ -1248,21 +2701,21 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - [[package]] name = "pathdiff" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + [[package]] name = "pest" version = "2.7.10" @@ -1270,7 +2723,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" dependencies = [ "memchr", - "thiserror", + "thiserror 1.0.60", "ucd-trie", ] @@ -1294,7 +2747,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.103", ] [[package]] @@ -1303,9 +2756,61 @@ version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" dependencies = [ - "once_cell", - "pest", - "sha2", + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.103", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", ] [[package]] @@ -1321,16 +2826,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "ppv-lite86" -version = "0.2.17" +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "pretty_assertions" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" dependencies = [ "diff", "yansi", @@ -1338,66 +2867,69 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "procfs" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" +checksum = "cc5b72d8145275d844d4b5f6d4e1eef00c8cd889edb6035c21675d1bb1f45c9f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.9.1", "chrono", "flate2", "hex", - "lazy_static", "procfs-core", - "rustix", + "rustix 0.38.34", ] [[package]] name = "procfs-core" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" +checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.9.1", "chrono", "hex", ] [[package]] -name = "quote" -version = "1.0.36" +name = "prodash" +version = "29.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "f04bb108f648884c23b98a0e940ebc2c93c0c3b89f04dbaf7eb8256ce617d1bc" dependencies = [ - "proc-macro2", + "log", + "parking_lot", ] [[package]] -name = "rand" -version = "0.8.5" +name = "quote" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ - "libc", - "rand_chacha", - "rand_core", + "proc-macro2", ] [[package]] -name = "rand_chacha" -version = "0.3.1" +name = "r-efi" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "ppv-lite86", "rand_core", ] @@ -1406,26 +2938,102 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "ratatui" +version = "0.30.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63bfff7501cc6892821f54f1133661e0534413342c8e8efbb41af0ffccdcea45" dependencies = [ - "getrandom", + "instability", + "ratatui-core", + "ratatui-crossterm", + "ratatui-macros", + "ratatui-termion", + "ratatui-termwiz", + "ratatui-widgets", + "serde", ] [[package]] -name = "ratatui" -version = "0.26.2" +name = "ratatui-core" +version = "0.1.0-alpha.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a564a852040e82671dc50a37d88f3aa83bbc690dfc6844cfe7a2591620206a80" +checksum = "353047185fbfb81ee05a3f8c573956adb2aa9a505da47fb150c18388806f5e22" dependencies = [ - "bitflags 2.5.0", - "cassowary", + "bitflags 2.9.1", "compact_str", - "crossterm", + "hashbrown 0.15.4", "indoc", - "itertools", + "itertools 0.14.0", + "kasuari", "lru", - "paste", - "stability", - "strum", + "serde", + "strum 0.27.1", + "thiserror 2.0.12", + "unicode-segmentation", + "unicode-truncate", + "unicode-width", +] + +[[package]] +name = "ratatui-crossterm" +version = "0.1.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c729303ad253dd928b75f5866feb41c73d0e72b62ec91b13a5d91141ff5bfd1" +dependencies = [ + "crossterm 0.29.0", + "instability", + "ratatui-core", +] + +[[package]] +name = "ratatui-macros" +version = "0.7.0-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058564a94bc18220b5c37caf05ec334e362bc87711522703fbed1ec9c43a0eae" +dependencies = [ + "ratatui-core", + "ratatui-widgets", +] + +[[package]] +name = "ratatui-termion" +version = "0.1.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ae9ba345f35c517222870d9dbfd93a0b5078a558099df5aeb491187bbaf9ec1" +dependencies = [ + "instability", + "ratatui-core", + "termion", +] + +[[package]] +name = "ratatui-termwiz" +version = "0.1.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca620dea5f1b7e949fc60a7d78626946dc0273707d28eed4ce3ee458ae0218ca" +dependencies = [ + "ratatui-core", + "termwiz", +] + +[[package]] +name = "ratatui-widgets" +version = "0.3.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fab55e77e0421bb88944cc0262317688e039d0e58518195f13a6e689f3e22f42" +dependencies = [ + "bitflags 2.9.1", + "hashbrown 0.15.4", + "indoc", + "instability", + "itertools 0.14.0", + "line-clipping", + "ratatui-core", + "serde", + "strum 0.27.1", + "time", "unicode-segmentation", "unicode-width", ] @@ -1436,30 +3044,36 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.9.1", ] +[[package]] +name = "redox_termios" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb" + [[package]] name = "redox_users" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ - "getrandom", + "getrandom 0.2.15", "libredox", - "thiserror", + "thiserror 1.0.60", ] [[package]] name = "regex" -version = "1.10.4" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.6", - "regex-syntax 0.8.3", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -1473,13 +3087,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.3", + "regex-syntax 0.8.5", ] [[package]] @@ -1490,9 +3104,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "ron" @@ -1500,17 +3114,17 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ - "base64", - "bitflags 2.5.0", + "base64 0.21.7", + "bitflags 2.9.1", "serde", "serde_derive", ] [[package]] name = "rust-ini" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091" +checksum = "3e0698206bcb8882bf2a9ecb4c1e7785db57ff052297085a6efd4fe42302068a" dependencies = [ "cfg-if", "ordered-multimap", @@ -1528,18 +3142,31 @@ version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.9.1", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.13", "windows-sys 0.52.0", ] +[[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags 2.9.1", + "errno", + "libc", + "linux-raw-sys 0.9.4", + "windows-sys 0.59.0", +] + [[package]] name = "rustversion" -version = "1.0.16" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "ryu" @@ -1547,6 +3174,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -1554,42 +3190,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "serde" -version = "1.0.201" +name = "semver" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" dependencies = [ - "serde_derive", + "serde", ] [[package]] -name = "serde-value" -version = "0.7.0" +name = "serde" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ - "ordered-float", - "serde", + "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.201" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.103", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -1604,16 +3240,24 @@ dependencies = [ ] [[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" +name = "sha1" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha1-checked" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89f599ac0c323ebb1c6082821a54962b839832b03984598375bff3975b804423" +dependencies = [ + "digest", + "sha1", ] [[package]] @@ -1636,11 +3280,17 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + [[package]] name = "signal-hook" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" dependencies = [ "libc", "signal-hook-registry", @@ -1648,9 +3298,9 @@ dependencies = [ [[package]] name = "signal-hook-mio" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" dependencies = [ "libc", "mio", @@ -1666,6 +3316,12 @@ dependencies = [ "libc", ] +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "slab" version = "0.4.9" @@ -1692,14 +3348,10 @@ dependencies = [ ] [[package]] -name = "stability" -version = "0.2.0" +name = "stable_deref_trait" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ff9eaf853dec4c8802325d8b6d3dffa86cc707fd7a1a4cdbf416e13b061787a" -dependencies = [ - "quote", - "syn 2.0.63", -] +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "static_assertions" @@ -1709,9 +3361,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strip-ansi-escapes" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ff8ef943b384c414f54aefa961dd2bd853add74ec75e7ac74cf91dba62bcfa" +checksum = "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025" dependencies = [ "vte", ] @@ -1724,24 +3376,46 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.26.2" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros 0.26.4", +] + +[[package]] +name = "strum" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" +dependencies = [ + "strum_macros 0.27.1", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "strum_macros", + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.103", ] [[package]] name = "strum_macros" -version = "0.26.2" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro2", "quote", "rustversion", - "syn 2.0.63", + "syn 2.0.103", ] [[package]] @@ -1757,23 +3431,124 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.63" +version = "2.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" +checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] + +[[package]] +name = "tempfile" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix 1.0.7", + "windows-sys 0.59.0", +] + [[package]] name = "terminal_size" -version = "0.3.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" dependencies = [ - "rustix", - "windows-sys 0.48.0", + "rustix 1.0.7", + "windows-sys 0.59.0", +] + +[[package]] +name = "terminfo" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4ea810f0692f9f51b382fff5893887bb4580f5fa246fde546e0b13e7fcee662" +dependencies = [ + "fnv", + "nom", + "phf", + "phf_codegen", +] + +[[package]] +name = "termion" +version = "4.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3669a69de26799d6321a5aa713f55f7e2cd37bd47be044b50f2acafc42c122bb" +dependencies = [ + "libc", + "libredox", + "numtoa", + "redox_termios", + "serde", +] + +[[package]] +name = "termios" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b" +dependencies = [ + "libc", +] + +[[package]] +name = "termwiz" +version = "0.23.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bitflags 2.9.1", + "fancy-regex", + "filedescriptor", + "finl_unicode", + "fixedbitset", + "hex", + "lazy_static", + "libc", + "log", + "memmem", + "nix 0.29.0", + "num-derive", + "num-traits", + "ordered-float", + "pest", + "pest_derive", + "phf", + "serde", + "sha2", + "signal-hook", + "siphasher", + "terminfo", + "termios", + "thiserror 1.0.60", + "ucd-trie", + "unicode-segmentation", + "vtparse", + "wezterm-bidi", + "wezterm-blob-leases", + "wezterm-color-types", + "wezterm-dynamic", + "wezterm-input-types", + "winapi", ] [[package]] @@ -1782,7 +3557,16 @@ version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.60", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", ] [[package]] @@ -1793,17 +3577,18 @@ checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.103", ] [[package]] -name = "thread-id" -version = "4.2.1" +name = "thiserror-impl" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0ec81c46e9eb50deaa257be2f148adf052d1fb7701cfd55ccfab2525280b70b" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ - "libc", - "winapi", + "proc-macro2", + "quote", + "syn 2.0.103", ] [[package]] @@ -1816,6 +3601,39 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + +[[package]] +name = "time-macros" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -1825,41 +3643,65 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" -version = "1.37.0" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.103", ] [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ "bytes", "futures-core", @@ -1899,14 +3741,14 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.6.8", ] [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -1915,20 +3757,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.103", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", "valuable", @@ -1936,9 +3778,9 @@ dependencies = [ [[package]] name = "tracing-error" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" dependencies = [ "tracing", "tracing-subscriber", @@ -1957,9 +3799,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", "nu-ansi-term", @@ -1974,26 +3816,6 @@ dependencies = [ "tracing-log", ] -[[package]] -name = "tui-input" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e785f863a3af4c800a2a669d0b64c879b538738e352607e2624d03f868dc01" -dependencies = [ - "crossterm", - "serde", - "unicode-width", -] - -[[package]] -name = "typemap-ors" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68c24b707f02dd18f1e4ccceb9d49f2058c2fb86384ef9972592904d7a28867" -dependencies = [ - "unsafe-any-ors", -] - [[package]] name = "typenum" version = "1.17.0" @@ -2015,6 +3837,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "unicode-bom" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -2022,31 +3850,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] -name = "unicode-segmentation" -version = "1.11.0" +name = "unicode-normalization" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] [[package]] -name = "unicode-width" -version = "0.1.12" +name = "unicode-segmentation" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] -name = "unsafe-any-ors" -version = "1.0.0" +name = "unicode-truncate" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a303d30665362d9680d7d91d78b23f5f899504d4f08b3c4cf08d055d87c0ad" +checksum = "8fbf03860ff438702f3910ca5f28f8dac63c1c11e7efb5012b8b175493606330" dependencies = [ - "destructure_traitobject", + "itertools 0.13.0", + "unicode-segmentation", + "unicode-width", ] [[package]] -name = "unsafe-libyaml" -version = "0.2.11" +name = "unicode-width" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "uom" @@ -2058,6 +3891,23 @@ dependencies = [ "typenum", ] +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.1" @@ -2066,28 +3916,63 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.8.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ - "getrandom", + "atomic", + "getrandom 0.3.3", + "js-sys", + "serde", + "wasm-bindgen", ] [[package]] -name = "uzers" -version = "0.12.0" +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vergen" +version = "9.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d85875e16d59b3b1549efce83ff8251a64923b03bef94add0a1862847448de4" +checksum = "6b2bf58be11fc9414104c6d3a2e464163db5ef74b12296bda593cac37b6e4777" dependencies = [ - "libc", - "log", + "anyhow", + "cargo_metadata", + "derive_builder", + "regex", + "rustversion", + "time", + "vergen-lib", ] [[package]] -name = "valuable" -version = "0.1.0" +name = "vergen-gix" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "5f8dfe6eb333a1397e596164ae7326f68e4b95267b41aedc6aa3c81f3426a010" +dependencies = [ + "anyhow", + "derive_builder", + "gix", + "rustversion", + "time", + "vergen", + "vergen-lib", +] + +[[package]] +name = "vergen-lib" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b07e6010c0f3e59fcb164e0163834597da68d1f864e2b8ca49f74de01e9c166" +dependencies = [ + "anyhow", + "derive_builder", + "rustversion", +] [[package]] name = "version_check" @@ -2097,22 +3982,30 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "vte" -version = "0.11.1" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077" +dependencies = [ + "memchr", +] + +[[package]] +name = "vtparse" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197" +checksum = "6d9b2acfb050df409c972a37d3b8e08cdea3bddb0c09db9d53137e504cfabed0" dependencies = [ "utf8parse", - "vte_generate_state_changes", ] [[package]] -name = "vte_generate_state_changes" -version = "0.1.1" +name = "walkdir" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ - "proc-macro2", - "quote", + "same-file", + "winapi-util", ] [[package]] @@ -2121,36 +4014,46 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", + "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.103", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2158,22 +4061,99 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.103", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wezterm-bidi" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0a6e355560527dd2d1cf7890652f4f09bb3433b6aadade4c9b5ed76de5f3ec" +dependencies = [ + "log", + "wezterm-dynamic", +] + +[[package]] +name = "wezterm-blob-leases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692daff6d93d94e29e4114544ef6d5c942a7ed998b37abdc19b17136ea428eb7" +dependencies = [ + "getrandom 0.3.3", + "mac_address", + "serde", + "sha2", + "thiserror 1.0.60", + "uuid", +] + +[[package]] +name = "wezterm-color-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de81ef35c9010270d63772bebef2f2d6d1f2d20a983d27505ac850b8c4b4296" +dependencies = [ + "csscolorparser", + "deltae", + "lazy_static", + "serde", + "wezterm-dynamic", +] + +[[package]] +name = "wezterm-dynamic" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f2ab60e120fd6eaa68d9567f3226e876684639d22a4219b313ff69ec0ccd5ac" +dependencies = [ + "log", + "ordered-float", + "strsim", + "thiserror 1.0.60", + "wezterm-dynamic-derive", +] + +[[package]] +name = "wezterm-dynamic-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c0cf2d539c645b448eaffec9ec494b8b19bd5077d9e58cb1ae7efece8d575b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "wezterm-input-types" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "7012add459f951456ec9d6c7e6fc340b1ce15d6fc9629f8c42853412c029e57e" +dependencies = [ + "bitflags 1.3.2", + "euclid", + "lazy_static", + "serde", + "wezterm-dynamic", +] [[package]] name = "winapi" @@ -2191,6 +4171,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -2199,11 +4188,61 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.52.0" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-targets 0.52.5", + "windows-link", ] [[package]] @@ -2221,7 +4260,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -2241,18 +4289,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -2263,9 +4311,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -2275,9 +4323,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -2287,15 +4335,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -2305,9 +4353,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -2317,9 +4365,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -2329,9 +4377,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -2341,9 +4389,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" @@ -2355,36 +4403,140 @@ dependencies = [ ] [[package]] -name = "yaml-rust" -version = "0.4.5" +name = "winnow" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "yaml-rust2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +checksum = "8902160c4e6f2fb145dbe9d6760a75e3c9522d8bf796ed7047c85919ac7115f8" dependencies = [ - "linked-hash-map", + "arraydeque", + "encoding_rs", + "hashlink", ] [[package]] name = "yansi" -version = "0.5.1" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", + "synstructure", +] [[package]] name = "zerocopy" -version = "0.7.34" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.34" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.103", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.103", ] diff --git a/Cargo.toml b/Cargo.toml index 8379be0..dbfb36f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,51 +8,51 @@ readme = "README.md" edition = "2021" description = "btop in rust" license = "EUPL-1.2" -rust-version = "1.74.1" +rust-version = "1.85.1" [[bin]] name = "brt" -[[bin]] -name = "processbar" -path = "src/processbar.rs" - [dependencies] -anyhow = "1.0.83" -battery = "0.7.8" better-panic = "0.3.0" -clap = { version = "4.5.4", features = ["std", "color", "help", "usage", "error-context", "suggestions", "derive", "cargo", "wrap_help", "unicode", "string", "unstable-styles"] } +clap = { version = "4.5.20", features = [ + "derive", + "cargo", + "wrap_help", + "unicode", + "string", + "unstable-styles", +] } color-eyre = "0.6.3" config = "0.14.0" -crossterm = { version = "0.27.0", features = ["serde", "event-stream"] } +crossterm = { version = "0.28.1", features = ["serde", "event-stream"] } derive_deref = "1.1.1" directories = "5.0.1" -dirs = "5.0.1" -futures = "0.3.30" -human-panic = "2.0.0" -humansize = "2.1.3" +futures = "0.3.31" +human-panic = "2.0.2" json5 = "0.4.1" -lazy_static = "1.4.0" -libc = "0.2.154" -log = "0.4.21" -log4rs = "1.3.0" -owo-colors = "4.0.0" -pretty_assertions = "1.4.0" -procfs = "0.16.0" -ratatui = { version = "0.26.2", features = ["default", "unstable-widget-ref"] } -serde = { version = "1.0.201", features = ["derive"] } +lazy_static = "1.5.0" +libc = "0.2.161" +pretty_assertions = "1.4.1" +ratatui = { version = "0.30.0-alpha.4", features = ["serde", "macros"] } +serde = { version = "1.0.211", features = ["derive"] } signal-hook = "0.3.17" strip-ansi-escapes = "0.2.0" -strum = { version = "0.26.2", features = ["derive"] } -tokio = { version = "1.37.0", features = ["full"] } -tokio-util = "0.7.11" +strum = { version = "0.26.3", features = ["derive"] } +tokio = { version = "1.40.0", features = ["full"] } +tokio-util = "0.7.12" tracing = "0.1.40" tracing-error = "0.2.0" tracing-subscriber = { version = "0.3.18", features = ["env-filter", "serde"] } -tui-input = { version = "0.8.0", features = ["serde"] } -uzers = "0.12.0" +chrono = "0.4.41" +battery = "0.7.8" +procfs = "0.17.0" + +[build-dependencies] +anyhow = "1.0.90" +vergen-gix = { version = "1.0.2", features = ["build", "cargo"] } [dev-dependencies.cargo-husky] version = "1" -default-features = false -features = ["user-hooks"] +#default-features = false +features = ["precommit-hook"] diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..2461afa --- /dev/null +++ b/build.rs @@ -0,0 +1,13 @@ +use anyhow::Result; +use vergen_gix::{BuildBuilder, CargoBuilder, Emitter, GixBuilder}; + +fn main() -> Result<()> { + let build = BuildBuilder::all_build()?; + let gix = GixBuilder::all_git()?; + let cargo = CargoBuilder::all_cargo()?; + Emitter::default() + .add_instructions(&build)? + .add_instructions(&gix)? + .add_instructions(&cargo)? + .emit() +} diff --git a/src/action.rs b/src/action.rs index f92f119..b8edd01 100644 --- a/src/action.rs +++ b/src/action.rs @@ -1,30 +1,18 @@ use serde::{Deserialize, Serialize}; use strum::Display; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Display, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Display, Serialize, Deserialize)] pub enum Action { Tick, Render, Resize(u16, u16), Suspend, Resume, + Update(u128), Quit, - Refresh, - Error(String), - Help, - ToggleShowHelp, - Increment(usize), - Decrement(usize), - CompleteInput(String), - EnterNormal, - EnterInsert, - EnterProcessing, - ExitProcessing, Up, Down, - PageUp, - PageDown, - Left, - Right, - Update, + ClearScreen, + Error(String), + Help, } diff --git a/src/app.rs b/src/app.rs index 5f516a5..142593f 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,159 +1,85 @@ -use color_eyre::eyre::Result; +use color_eyre::Result; use crossterm::event::KeyEvent; use ratatui::prelude::Rect; use serde::{Deserialize, Serialize}; use tokio::sync::mpsc; +use tracing::{debug, info}; +use crate::components::header::Header; +use crate::components::processes::ProcessesComponent; use crate::{ action::Action, - components::{fps::FpsCounter, process::Process, Component}, + components::{fps::FpsCounter, Component}, config::Config, - tui, + tui::{Event, Tui}, }; +pub struct App { + config: Config, + tick_rate: f64, + frame_rate: f64, + components: Vec>, + should_quit: bool, + should_suspend: bool, + mode: Mode, + last_tick_key_events: Vec, + action_tx: mpsc::UnboundedSender, + action_rx: mpsc::UnboundedReceiver, +} + #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Mode { #[default] - Process, -} - -pub struct App { - pub config: Config, - pub tick_rate: f64, - pub frame_rate: f64, - pub components: Vec>, - pub should_quit: bool, - pub should_suspend: bool, - pub mode: Mode, - pub last_tick_key_events: Vec, + Home, } impl App { - pub fn new(tick_rate: f64, frame_rate: f64, debug: bool) -> Result { - let mut process = Process::new(); - process.refresh(); - - let components: Vec> = if debug { - let fps = FpsCounter::new(); - vec![Box::new(process), Box::new(fps)] - } else { - vec![Box::new(process)] - }; - let config = Config::new()?; - let mode = Mode::Process; + pub fn new(tick_rate: f64, frame_rate: f64) -> Result { + let (action_tx, action_rx) = mpsc::unbounded_channel(); Ok(Self { tick_rate, frame_rate, - components, + components: vec![ + Box::new(FpsCounter::default()), + Box::new(Header::default()), + Box::new(ProcessesComponent::default()), + ], should_quit: false, should_suspend: false, - config, - mode, + config: Config::new()?, + mode: Mode::Home, last_tick_key_events: Vec::new(), + action_tx, + action_rx, }) } pub async fn run(&mut self) -> Result<()> { - let (action_tx, mut action_rx) = mpsc::unbounded_channel(); - - let mut tui = tui::Tui::new()?; - tui.tick_rate(self.tick_rate); - tui.frame_rate(self.frame_rate); + let mut tui = Tui::new()? + // .mouse(true) // uncomment this line to enable mouse support + .tick_rate(self.tick_rate) + .frame_rate(self.frame_rate); tui.enter()?; for component in self.components.iter_mut() { - component.register_action_handler(action_tx.clone())?; + component.register_action_handler(self.action_tx.clone())?; } - for component in self.components.iter_mut() { component.register_config_handler(self.config.clone())?; } - for component in self.components.iter_mut() { - component.init()?; + component.init(tui.size()?)?; } + let action_tx = self.action_tx.clone(); loop { - if let Some(e) = tui.next().await { - match e { - tui::Event::Quit => action_tx.send(Action::Quit)?, - tui::Event::Tick => action_tx.send(Action::Tick)?, - tui::Event::Render => action_tx.send(Action::Render)?, - tui::Event::Resize(x, y) => action_tx.send(Action::Resize(x, y))?, - tui::Event::Key(key) => { - if let Some(keymap) = self.config.keybindings.get(&self.mode) { - if let Some(action) = keymap.get(&vec![key]) { - log::info!("Got action: {action:?}"); - action_tx.send(action.clone())?; - } else { - // If the key was not handled as a single key action, - // then consider it for multi-key combinations. - self.last_tick_key_events.push(key); - - // Check for multi-key combinations - if let Some(action) = keymap.get(&self.last_tick_key_events) { - log::info!("Got action: {action:?}"); - action_tx.send(action.clone())?; - } - } - }; - } - _ => {} - } - for component in self.components.iter_mut() { - if let Some(action) = component.handle_events(Some(e.clone()))? { - action_tx.send(action)?; - } - } - } - - while let Ok(action) = action_rx.try_recv() { - match action { - Action::Tick => { - self.last_tick_key_events.drain(..); - } - Action::Quit => self.should_quit = true, - Action::Suspend => self.should_suspend = true, - Action::Resume => self.should_suspend = false, - Action::Resize(w, h) => { - tui.resize(Rect::new(0, 0, w, h))?; - tui.draw(|f| { - for component in self.components.iter_mut() { - let r = component.draw(f, f.size()); - if let Err(e) = r { - action_tx - .send(Action::Error(format!("Failed to draw: {:?}", e))) - .unwrap(); - } - } - })?; - } - Action::Render => { - tui.draw(|f| { - for component in self.components.iter_mut() { - let r = component.draw(f, f.size()); - if let Err(e) = r { - action_tx - .send(Action::Error(format!("Failed to draw: {:?}", e))) - .unwrap(); - } - } - })?; - } - _ => {} - } - for component in self.components.iter_mut() { - if let Some(action) = component.update(action.clone())? { - action_tx.send(action)? - }; - } - } + self.handle_events(&mut tui).await?; + self.handle_actions(&mut tui)?; if self.should_suspend { tui.suspend()?; action_tx.send(Action::Resume)?; - tui = tui::Tui::new()?; - tui.tick_rate(self.tick_rate); - tui.frame_rate(self.frame_rate); + action_tx.send(Action::ClearScreen)?; + // tui.mouse(true); tui.enter()?; } else if self.should_quit { tui.stop()?; @@ -163,4 +89,98 @@ impl App { tui.exit()?; Ok(()) } + + async fn handle_events(&mut self, tui: &mut Tui) -> Result<()> { + let Some(event) = tui.next_event().await else { + return Ok(()); + }; + let action_tx = self.action_tx.clone(); + match event { + Event::Quit => action_tx.send(Action::Quit)?, + Event::Tick => action_tx.send(Action::Tick)?, + Event::Render => action_tx.send(Action::Render)?, + Event::Update(since) => action_tx.send(Action::Update(since.as_millis()))?, + Event::Resize(x, y) => action_tx.send(Action::Resize(x, y))?, + Event::Key(key) => self.handle_key_event(key)?, + _ => {} + } + for component in self.components.iter_mut() { + if let Some(action) = component.handle_events(Some(event.clone()))? { + action_tx.send(action)?; + } + } + Ok(()) + } + + fn handle_key_event(&mut self, key: KeyEvent) -> Result<()> { + info!("key event: {:?}", key); + let action_tx = self.action_tx.clone(); + let Some(keymap) = self.config.keybindings.get(&self.mode) else { + info!("No keybindings found"); + return Ok(()); + }; + match keymap.get(&vec![key]) { + Some(action) => { + info!("Got action: {action:?}"); + action_tx.send(action.clone())?; + } + _ => { + // If the key was not handled as a single key action, + // then consider it for multi-key combinations. + self.last_tick_key_events.push(key); + + // Check for multi-key combinations + if let Some(action) = keymap.get(&self.last_tick_key_events) { + info!("Got multikey action: {action:?}"); + action_tx.send(action.clone())?; + } + } + } + Ok(()) + } + + fn handle_actions(&mut self, tui: &mut Tui) -> Result<()> { + while let Ok(action) = self.action_rx.try_recv() { + if action != Action::Tick && action != Action::Render { + debug!("Action: {action:?}"); + } + match action { + Action::Tick => { + self.last_tick_key_events.drain(..); + } + Action::Quit => self.should_quit = true, + Action::Suspend => self.should_suspend = true, + Action::Resume => self.should_suspend = false, + Action::ClearScreen => tui.terminal.clear()?, + Action::Resize(w, h) => self.handle_resize(tui, w, h)?, + Action::Render => self.render(tui)?, + _ => {} + } + for component in self.components.iter_mut() { + if let Some(action) = component.update(action.clone())? { + self.action_tx.send(action)? + }; + } + } + Ok(()) + } + + fn handle_resize(&mut self, tui: &mut Tui, w: u16, h: u16) -> Result<()> { + tui.resize(Rect::new(0, 0, w, h))?; + self.render(tui)?; + Ok(()) + } + + fn render(&mut self, tui: &mut Tui) -> Result<()> { + tui.draw(|frame| { + for component in self.components.iter_mut() { + if let Err(err) = component.draw(frame, frame.area()) { + let _ = self + .action_tx + .send(Action::Error(format!("Failed to draw: {err:?}"))); + } + } + })?; + Ok(()) + } } diff --git a/src/cli.rs b/src/cli.rs index 46badf5..8696a0a 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,34 +1,42 @@ use clap::Parser; -use crate::utils::version; +use crate::config::{get_config_dir, get_data_dir}; #[derive(Parser, Debug)] #[command(author, version = version(), about)] pub struct Cli { - #[arg( - short, - long, - value_name = "FLOAT", - help = "Tick rate, i.e. number of ticks per second", - default_value_t = 0.2 - )] + /// Tick rate, i.e. number of ticks per second + #[arg(short, long, value_name = "FLOAT", default_value_t = 4.0)] pub tick_rate: f64, - #[arg( - short, - long, - value_name = "FLOAT", - help = "Frame rate, i.e. number of frames per second", - default_value_t = 60.0 - )] + /// Frame rate, i.e. number of frames per second + #[arg(short, long, value_name = "FLOAT", default_value_t = 60.0)] pub frame_rate: f64, +} + +const VERSION_MESSAGE: &str = concat!( + env!("CARGO_PKG_VERSION"), + "-", + env!("VERGEN_GIT_DESCRIBE"), + " (", + env!("VERGEN_BUILD_DATE"), + ")" +); + +pub fn version() -> String { + let author = clap::crate_authors!(); + + // let current_exe_path = PathBuf::from(clap::crate_name!()).display().to_string(); + let config_dir_path = get_config_dir().display().to_string(); + let data_dir_path = get_data_dir().display().to_string(); + + format!( + "\ +{VERSION_MESSAGE} + +Authors: {author} - #[arg( - short = 'x', - long, - value_name = "BOOL", - help = "Show the fps or not", - default_value_t = false - )] - pub debug: bool, +Config directory: {config_dir_path} +Data directory: {data_dir_path}" + ) } diff --git a/src/components.rs b/src/components.rs index 76211bb..5689ce5 100644 --- a/src/components.rs +++ b/src/components.rs @@ -1,49 +1,129 @@ -use color_eyre::eyre::Result; +use color_eyre::Result; use crossterm::event::{KeyEvent, MouseEvent}; -use ratatui::layout::Rect; +use ratatui::{ + layout::{Rect, Size}, + Frame, +}; use tokio::sync::mpsc::UnboundedSender; -use crate::{ - action::Action, - config::Config, - tui::{Event, Frame}, -}; +use crate::{action::Action, config::Config, tui::Event}; pub mod battery; pub mod fps; -pub mod process; +pub mod header; +pub mod home; +pub mod processes; +pub mod time; +/// `Component` is a trait that represents a visual and interactive element of the user interface. +/// +/// Implementors of this trait can be registered with the main application loop and will be able to +/// receive events, update state, and be rendered on the screen. pub trait Component { - #[allow(unused_variables)] + /// Register an action handler that can send actions for processing if necessary. + /// + /// # Arguments + /// + /// * `tx` - An unbounded sender that can send actions. + /// + /// # Returns + /// + /// * `Result<()>` - An Ok result or an error. fn register_action_handler(&mut self, tx: UnboundedSender) -> Result<()> { + let _ = tx; // to appease clippy Ok(()) } - #[allow(unused_variables)] + /// Register a configuration handler that provides configuration settings if necessary. + /// + /// # Arguments + /// + /// * `config` - Configuration settings. + /// + /// # Returns + /// + /// * `Result<()>` - An Ok result or an error. fn register_config_handler(&mut self, config: Config) -> Result<()> { + let _ = config; // to appease clippy Ok(()) } - fn init(&mut self) -> Result<()> { + /// Initialize the component with a specified area if necessary. + /// + /// # Arguments + /// + /// * `area` - Rectangular area to initialize the component within. + /// + /// # Returns + /// + /// * `Result<()>` - An Ok result or an error. + fn init(&mut self, area: Size) -> Result<()> { + let _ = area; // to appease clippy Ok(()) } + /// Handle incoming events and produce actions if necessary. + /// + /// # Arguments + /// + /// * `event` - An optional event to be processed. + /// + /// # Returns + /// + /// * `Result>` - An action to be processed or none. fn handle_events(&mut self, event: Option) -> Result> { - let r = match event { - Some(Event::Key(key_event)) => self.handle_key_events(key_event)?, - Some(Event::Mouse(mouse_event)) => self.handle_mouse_events(mouse_event)?, + let action = match event { + Some(Event::Key(key_event)) => self.handle_key_event(key_event)?, + Some(Event::Mouse(mouse_event)) => self.handle_mouse_event(mouse_event)?, _ => None, }; - Ok(r) + Ok(action) } - #[allow(unused_variables)] - fn handle_key_events(&mut self, key: KeyEvent) -> Result> { + /// Handle key events and produce actions if necessary. + /// + /// # Arguments + /// + /// * `key` - A key event to be processed. + /// + /// # Returns + /// + /// * `Result>` - An action to be processed or none. + fn handle_key_event(&mut self, key: KeyEvent) -> Result> { + let _ = key; // to appease clippy Ok(None) } - #[allow(unused_variables)] - fn handle_mouse_events(&mut self, mouse: MouseEvent) -> Result> { + /// Handle mouse events and produce actions if necessary. + /// + /// # Arguments + /// + /// * `mouse` - A mouse event to be processed. + /// + /// # Returns + /// + /// * `Result>` - An action to be processed or none. + fn handle_mouse_event(&mut self, mouse: MouseEvent) -> Result> { + let _ = mouse; // to appease clippy Ok(None) } - #[allow(unused_variables)] + /// Update the state of the component based on a received action. (REQUIRED) + /// + /// # Arguments + /// + /// * `action` - An action that may modify the state of the component. + /// + /// # Returns + /// + /// * `Result>` - An action to be processed or none. fn update(&mut self, action: Action) -> Result> { + let _ = action; // to appease clippy Ok(None) } - fn draw(&mut self, f: &mut Frame<'_>, rect: Rect) -> Result<()>; + /// Render the component on the screen. (REQUIRED) + /// + /// # Arguments + /// + /// * `f` - A frame used for rendering. + /// * `area` - The area in which the component should be drawn. + /// + /// # Returns + /// + /// * `Result<()>` - An Ok result or an error. + fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()>; } diff --git a/src/components/battery.rs b/src/components/battery.rs index 3315a5b..12b969e 100644 --- a/src/components/battery.rs +++ b/src/components/battery.rs @@ -1,84 +1,164 @@ -use battery as battery_model; -use battery::State; -use ratatui::layout::{Constraint, Direction, Layout, Rect}; -use ratatui::text::Line; - +use super::Component; use crate::action::Action; -use crate::components::Component; -use crate::tui::Frame; +use battery::units::power::watt; +use battery::units::ratio::percent; +use battery::units::time::second; +use battery::{Battery, State}; +use color_eyre::Result; +use ratatui::layout::Rect; +use ratatui::prelude::*; +use ratatui::widgets::Paragraph; +use std::str::FromStr; +use tracing::{error, warn}; -#[derive(Debug)] -pub struct Battery { - battery: Option, +#[derive(Debug, Default, Clone)] +pub struct BatteryComponent<'a> { + pub line: Line<'a>, } -impl Default for Battery { - fn default() -> Self { - Self::new() - } -} +static BATTERY_STATE_SYMBOL_UNKNOWN: &str = "?"; +static BATTERY_STATE_SYMBOL: &[(State, &str)] = &[ + (State::Charging, "▲"), + (State::Discharging, "▼"), + (State::Full, "●"), + (State::Empty, "○"), + (State::Unknown, BATTERY_STATE_SYMBOL_UNKNOWN), +]; -impl Battery { - pub fn new() -> Self { - Self { battery: None } - } +fn get_state_symbol(s: State) -> String { + if let Some((_, symbol)) = BATTERY_STATE_SYMBOL.iter().find(|(state, _)| s == *state) { + return symbol.to_string(); + }; + BATTERY_STATE_SYMBOL_UNKNOWN.to_string() } -impl Component for Battery { - fn init(&mut self) -> color_eyre::Result<()> { - let batteries = battery_model::Manager::new().unwrap().batteries(); - if batteries.is_ok() { - let b = batteries.unwrap().next().unwrap().unwrap(); - self.battery = Some(b); - } - Ok(()) - } +fn line<'a>(battery: Battery) -> Line<'a> { + let percentage = battery.state_of_charge().get::(); + let bat = Span::raw(format!( + "BAT{} {}% ", + get_state_symbol(battery.state()), + percentage + )); + let mut parts = vec![bat]; - fn update(&mut self, _action: Action) -> color_eyre::Result> { - let _ = self.init(); - Ok(None) + let mut bar = bar(percentage); + parts.append(&mut bar); + + if let Some(time_to_empty) = battery.time_to_empty() { + let seconds_to_empty = time_to_empty.get::() as i64; + let (hours, minutes) = seconds_to_hours_minutes(seconds_to_empty); + let time_to_empty = Span::raw(format!(" {hours:02}:{minutes:02}")); + parts.push(time_to_empty); } - fn draw(&mut self, f: &mut Frame<'_>, rect: Rect) -> color_eyre::Result<()> { - let layout = - Layout::new(Direction::Horizontal, vec![Constraint::Percentage(100)]).split(rect); - let mut state = "○"; - if self.battery.is_some() { - state = match self.battery.as_mut().unwrap().state() { - State::Charging => "▲", - State::Discharging => "▼", - State::Full => "■", - State::Unknown => "○", - State::Empty => "○", - _ => "○", - }; - } - let soc = self.battery.as_mut().unwrap().state_of_charge().value * 100.0; - let percentage = format!("{}%", soc as u32); - let status = format!("{}{} {}", "BAT", state, percentage); - let line = Line::from(status); - f.render_widget(line, layout[0]); - Ok(()) + if let Some(time_to_full) = battery.time_to_full() { + let seconds_to_full = time_to_full.get::() as i64; + let (hours, minutes) = seconds_to_hours_minutes(seconds_to_full); + let time_to_full = Span::raw(format!(" {hours:02}:{minutes:02}")); + parts.push(time_to_full); } + + let energy_rate = Span::raw(format!(" {:.2}W", battery.energy_rate().get::())); + parts.push(energy_rate); + Line::from(parts) +} + +fn seconds_to_hours_minutes(seconds: i64) -> (i64, i64) { + let hours = seconds / 3600; + let remaining_seconds = seconds % 3600; + let minutes = remaining_seconds / 60; + (hours, minutes) } -#[cfg(test)] -mod tests { - use super::*; - use log::info; - use ratatui::{backend::TestBackend, prelude::*}; +fn bar(percentage: f32) -> Vec> { + let block_0 = Span::styled( + "■", + Style::default().fg(Color::from_str("#d86453").unwrap()), + ); + let block_1 = Span::styled( + "■", + Style::default().fg(Color::from_str("#d57b59").unwrap()), + ); + let block_2 = Span::styled( + "■", + Style::default().fg(Color::from_str("#d19260").unwrap()), + ); + let block_3 = Span::styled( + "■", + Style::default().fg(Color::from_str("#cea966").unwrap()), + ); + let block_4 = Span::styled( + "■", + Style::default().fg(Color::from_str("#cbc06c").unwrap()), + ); + let block_5 = Span::styled( + "■", + Style::default().fg(Color::from_str("#bac276").unwrap()), + ); + let block_6 = Span::styled( + "■", + Style::default().fg(Color::from_str("#a9c47f").unwrap()), + ); + let block_7 = Span::styled( + "■", + Style::default().fg(Color::from_str("#98c689").unwrap()), + ); + let block_8 = Span::styled( + "■", + Style::default().fg(Color::from_str("#87c892").unwrap()), + ); + let block_9 = Span::styled( + "■", + Style::default().fg(Color::from_str("#77ca9b").unwrap()), + ); + let blocks = vec![ + block_0, block_1, block_2, block_3, block_4, block_5, block_6, block_7, block_8, block_9, + ]; + + let style_empty = Span::styled( + "■", + Style::default().fg(Color::from_str("#404040").unwrap()), + ); + let empty_bar = vec![style_empty; 10]; + + let until = (percentage / 10.0) as usize; + let filled = &blocks[..until].to_vec(); + let emptied = &empty_bar[until..10].to_vec(); + let mut bar = vec![]; + bar.append(&mut filled.clone()); + bar.append(&mut emptied.clone()); + bar +} - #[test] - fn test_battery() { - let mut battery = Battery::default(); - let _ = battery.init(); - let backend = TestBackend::new(40, 20); - let mut terminal = Terminal::new(backend).unwrap(); - let _ = terminal.draw(|frame| { - let _r = battery.draw(frame, Rect::new(3, 3, 10, 1)); - let b = frame.buffer_mut(); - info!("{:#?}", b); - }); - assert_eq!(true, true) +impl Component for BatteryComponent<'_> { + fn update(&mut self, action: Action) -> Result> { + match action { + Action::Tick => { + // add any logic here that should run on every tick + } + Action::Render => { + let manager = battery::Manager::new()?; + let battery = match manager.batteries()?.next() { + Some(Ok(battery)) => battery, + Some(Err(_)) => { + error!("Unable to access battery information"); + self.line = Line::default(); + return Ok(None); + } + None => { + warn!("Unable to find any batteries"); + self.line = Line::default(); + return Ok(None); + } + }; + self.line = line(battery); + } + _ => {} + } + Ok(None) + } + fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> { + frame.render_widget(Paragraph::new(self.line.clone()), area); + Ok(()) } } diff --git a/src/components/cpu.rs b/src/components/cpu.rs deleted file mode 100644 index 9019043..0000000 --- a/src/components/cpu.rs +++ /dev/null @@ -1,63 +0,0 @@ -use ratatui::layout::{Constraint, Direction, Layout, Rect}; -use ratatui::text::Line; - -use crate::action::Action; -use crate::components::Component; -use crate::tui::Frame; - -#[derive(Debug)] -pub struct Cpu { - state: bool, -} - -impl Default for Battery { - fn default() -> Self { - Self::new() - } -} - -impl Cpu { - pub fn new() -> Self { - Self { state: false } - } -} - -impl Component for Cpu { - fn init(&mut self) -> color_eyre::Result<()> { - Ok(()) - } - - fn update(&mut self, _action: Action) -> color_eyre::Result> { - let _ = self.init(); - Ok(None) - } - - fn draw(&mut self, f: &mut Frame<'_>, rect: Rect) -> color_eyre::Result<()> { - let layout = - Layout::new(Direction::Horizontal, vec![Constraint::Percentage(100)]).split(rect); - let message = format!("{}", "."); - let line = Line::from(status); - f.render_widget(line, layout[0]); - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ratatui::{backend::TestBackend, prelude::*}; - - #[test] - fn test_cpu() { - let mut cpu = Cpu::default(); - let _ = battery.init(); - let backend = TestBackend::new(40, 20); - let mut terminal = Terminal::new(backend).unwrap(); - let _ = terminal.draw(|frame| { - let _r = battery.draw(frame, Rect::new(3, 3, 10, 1)); - let b = frame.buffer_mut(); - println!("{:#?}", b); - }); - assert_eq!(true, true) - } -} diff --git a/src/components/fps.rs b/src/components/fps.rs index b6667b3..11641d4 100644 --- a/src/components/fps.rs +++ b/src/components/fps.rs @@ -1,26 +1,27 @@ use std::time::Instant; -use color_eyre::eyre::Result; -use ratatui::{prelude::*, widgets::*}; +use color_eyre::Result; +use ratatui::{ + layout::{Constraint, Layout, Rect}, + style::Style, + text::Span, + widgets::Paragraph, + Frame, +}; use super::Component; -use crate::{action::Action, tui::Frame}; -#[derive(Debug, Clone, PartialEq)] -pub enum Ticker { - AppTick, - RenderTick, -} +use crate::action::Action; #[derive(Debug, Clone, PartialEq)] pub struct FpsCounter { - app_start_time: Instant, - app_frames: u32, - app_fps: f64, + last_tick_update: Instant, + tick_count: u32, + ticks_per_second: f64, - render_start_time: Instant, - render_frames: u32, - render_fps: f64, + last_frame_update: Instant, + frame_count: u32, + frames_per_second: f64, } impl Default for FpsCounter { @@ -32,35 +33,35 @@ impl Default for FpsCounter { impl FpsCounter { pub fn new() -> Self { Self { - app_start_time: Instant::now(), - app_frames: 0, - app_fps: 0.0, - render_start_time: Instant::now(), - render_frames: 0, - render_fps: 0.0, + last_tick_update: Instant::now(), + tick_count: 0, + ticks_per_second: 0.0, + last_frame_update: Instant::now(), + frame_count: 0, + frames_per_second: 0.0, } } fn app_tick(&mut self) -> Result<()> { - self.app_frames += 1; + self.tick_count += 1; let now = Instant::now(); - let elapsed = (now - self.app_start_time).as_secs_f64(); + let elapsed = (now - self.last_tick_update).as_secs_f64(); if elapsed >= 1.0 { - self.app_fps = self.app_frames as f64 / elapsed; - self.app_start_time = now; - self.app_frames = 0; + self.ticks_per_second = self.tick_count as f64 / elapsed; + self.last_tick_update = now; + self.tick_count = 0; } Ok(()) } fn render_tick(&mut self) -> Result<()> { - self.render_frames += 1; + self.frame_count += 1; let now = Instant::now(); - let elapsed = (now - self.render_start_time).as_secs_f64(); + let elapsed = (now - self.last_frame_update).as_secs_f64(); if elapsed >= 1.0 { - self.render_fps = self.render_frames as f64 / elapsed; - self.render_start_time = now; - self.render_frames = 0; + self.frames_per_second = self.frame_count as f64 / elapsed; + self.last_frame_update = now; + self.frame_count = 0; } Ok(()) } @@ -68,66 +69,23 @@ impl FpsCounter { impl Component for FpsCounter { fn update(&mut self, action: Action) -> Result> { - if let Action::Tick = action { - self.app_tick()? - }; - if let Action::Render = action { - self.render_tick()? + match action { + Action::Tick => self.app_tick()?, + Action::Render => self.render_tick()?, + _ => {} }; Ok(None) } - fn draw(&mut self, f: &mut Frame<'_>, rect: Rect) -> Result<()> { - let rects = Layout::default() - .direction(Direction::Vertical) - .constraints(vec![ - Constraint::Length(1), // first row - Constraint::Min(0), - ]) - .split(rect); - - let rect = rects[0]; - - let s = format!( - "{:.2} fps (app) {:.2} fps (render)", - self.app_fps, self.render_fps + fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> { + let [_, bottom] = Layout::vertical([Constraint::Min(0), Constraint::Length(1)]).areas(area); + let message = format!( + "{:.2} ticks/sec, {:.2} FPS", + self.ticks_per_second, self.frames_per_second ); - let block = Block::default().title(block::Title::from(s.dim()).alignment(Alignment::Right)); - f.render_widget(block, rect); + let span = Span::styled(message, Style::new().dim()); + let paragraph = Paragraph::new(span).right_aligned(); + frame.render_widget(paragraph, bottom); Ok(()) } } - -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn test_fps_app_tick() { - let mut fps = FpsCounter::default(); - let _ = fps.app_tick(); - assert_eq!(fps.app_frames, 1); - } - - #[test] - fn test_fps_render_tick() { - let mut fps = FpsCounter::default(); - let _ = fps.render_tick(); - assert_eq!(fps.render_frames, 1); - } - - #[test] - fn test_fps_update_tick() { - let mut fps = FpsCounter::default(); - let _ = fps.update(Action::Tick); - assert_eq!(fps.app_frames, 1); - assert_eq!(fps.render_frames, 0); - } - - #[test] - fn test_fps_update_render() { - let mut fps = FpsCounter::default(); - let _ = fps.update(Action::Render); - assert_eq!(fps.render_frames, 1); - assert_eq!(fps.app_frames, 0); - } -} diff --git a/src/components/header.rs b/src/components/header.rs new file mode 100644 index 0000000..cf7e5f7 --- /dev/null +++ b/src/components/header.rs @@ -0,0 +1,52 @@ +use chrono::{DateTime, Local}; +use color_eyre::Result; +use ratatui::text::ToSpan; +use ratatui::{prelude::*, widgets::*}; + +use super::Component; +use crate::action::Action; +use crate::components::battery::BatteryComponent; + +#[derive(Default)] +pub struct Header<'a> { + time: DateTime, + battery: BatteryComponent<'a>, + _interval: u32, +} + +impl Component for Header<'_> { + fn update(&mut self, action: Action) -> Result> { + match action { + Action::Tick => { + // add any logic here that should run on every tick + } + Action::Render => { + let _ = self.battery.update(Action::Render); + self.time = Local::now(); + } + _ => {} + } + Ok(None) + } + fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> { + let [left, center, right] = Layout::horizontal(vec![ + Constraint::Percentage(40), + Constraint::Percentage(20), + Constraint::Percentage(40), + ]) + .areas(area); + + let binding = self.time.format("brt"); + let paragraph = Paragraph::new(binding.to_span()).left_aligned(); + frame.render_widget(paragraph, left); + + let binding = self.time.format("%H:%M:%S%.3f"); + let paragraph = Paragraph::new(binding.to_span()).centered(); + frame.render_widget(paragraph, center); + + let paragraph = Paragraph::new(self.battery.line.clone()).right_aligned(); + frame.render_widget(paragraph, right); + + Ok(()) + } +} diff --git a/src/components/home.rs b/src/components/home.rs new file mode 100644 index 0000000..9933daf --- /dev/null +++ b/src/components/home.rs @@ -0,0 +1,42 @@ +use color_eyre::Result; +use ratatui::{prelude::*, widgets::*}; +use tokio::sync::mpsc::UnboundedSender; + +use super::Component; +use crate::{action::Action, config::Config}; + +#[derive(Default)] +pub struct Home { + command_tx: Option>, + config: Config, +} + +impl Component for Home { + fn register_action_handler(&mut self, tx: UnboundedSender) -> Result<()> { + self.command_tx = Some(tx); + Ok(()) + } + + fn register_config_handler(&mut self, config: Config) -> Result<()> { + self.config = config; + Ok(()) + } + + fn update(&mut self, action: Action) -> Result> { + match action { + Action::Tick => { + // add any logic here that should run on every tick + } + Action::Render => { + // add any logic here that should run on every render + } + _ => {} + } + Ok(None) + } + + fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> { + frame.render_widget(Paragraph::new("hello world"), area); + Ok(()) + } +} diff --git a/src/components/process.rs b/src/components/process.rs deleted file mode 100644 index 251df9f..0000000 --- a/src/components/process.rs +++ /dev/null @@ -1,366 +0,0 @@ -use std::collections::HashMap; -use std::default::Default; -use std::fmt; - -use color_eyre::eyre::Result; -use crossterm::event::{KeyCode, KeyEvent}; -use log::{debug, info, warn}; -use procfs::process::all_processes; -use ratatui::layout::Constraint::{Fill, Length, Percentage}; -use ratatui::widgets::block::{Position, Title}; -use ratatui::widgets::TableState; -use ratatui::{prelude::*, widgets::*}; -use tokio::sync::mpsc::UnboundedSender; -use tui_input::Input; - -use super::{Component, Frame}; -use crate::action::Action; -use crate::components::process::Order::{Command, Cpu, Name, NumberOfThreads, Pid}; -use crate::model::{create_rows, to_brt_process, BrtProcess}; - -#[derive(Default, Copy, Clone, PartialEq, Eq, Debug)] -pub enum Order { - #[default] - Pid, - Name, - Command, - NumberOfThreads, - Cpu, -} - -impl Order { - fn next(&self) -> Self { - use Order::*; - match *self { - Pid => Name, - Name => Command, - Command => NumberOfThreads, - NumberOfThreads => Cpu, - Cpu => Pid, - } - } - - fn previous(&self) -> Self { - use Order::*; - match *self { - Pid => Cpu, - Cpu => NumberOfThreads, - NumberOfThreads => Command, - Command => Name, - Name => Pid, - } - } -} - -impl fmt::Display for Order { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Pid => write!(f, "pid"), - Name => write!(f, "name"), - Command => write!(f, "command"), - NumberOfThreads => write!(f, "threads"), - Cpu => write!(f, "cpu"), - } - } -} - -#[derive(Default, Debug)] -pub struct Process { - pub show_help: bool, - pub app_ticker: usize, - pub render_ticker: usize, - pub input: Input, - pub process_map: HashMap, - pub processes: Vec, - pub order: Order, - pub scrollbar_state: ScrollbarState, - pub state: TableState, - pub action_tx: Option>, -} - -impl Process { - pub fn new() -> Process { - let mut process = Process::default(); - process.process_map = process.get_processes(); - process.processes = process.process_map.clone().into_values().collect(); - process.state = TableState::new().with_selected(Some(0)); - process - } - - pub fn refresh(&mut self) { - let length = self.process_map.len(); - let new_processes = self.get_processes(); - let mut updated_processes = HashMap::new(); - for (pid, process) in new_processes { - let old_process_option = self.process_map.get(&pid); - if old_process_option.is_some() { - let mut old_process = old_process_option.unwrap().clone(); - old_process.cpus.push_back(process.cpu); - old_process.cpus.pop_front(); - old_process.cpu_graph = crate::model::get_cpu_graph(&old_process.cpus); - updated_processes.insert(pid, old_process); - }; - } - self.process_map = updated_processes; - self.processes = self.process_map.clone().into_values().collect(); - self.scrollbar_state = self.scrollbar_state.content_length(length); - } - - pub fn order_string(&mut self) -> String { - format!("{} {} {}", "<".red(), self.order, ">".red()) - } - - pub fn tick(&mut self) { - self.app_ticker = self.app_ticker.saturating_add(1); - // if self.app_ticker % 5 == 0 { - // self.processes = self.get_all_processes(); - self.refresh(); - - self.order_by_enum(); - info!("Refreshed process list."); - // } - } - - fn get_processes(&mut self) -> HashMap { - let processes: HashMap = all_processes() - .expect("Can't read /proc") - .filter_map(|p| match p { - Ok(p) => { - let brt_process = to_brt_process(&p); - if brt_process.is_some() { - Some((p.pid, brt_process?)) - } else { - None - } - } - Err(e) => match e { - procfs::ProcError::NotFound(_) => None, - procfs::ProcError::Io(_e, _path) => None, - x => { - warn!("Can't read process due to error {x:?}"); - None - } - }, - }) - .collect(); - processes - } - - pub fn order_by_enum(&mut self) { - let order = self.order; - match order { - Pid => self.order_by_pid(), - Name => self.order_by_program(), - Command => self.order_by_command(), - NumberOfThreads => self.order_by_number_of_threads(), - Cpu => self.order_by_cpu(), - } - } - - pub fn order_by_pid(&mut self) { - self.processes.sort_by(|a, b| a.pid.cmp(&b.pid)) - } - - pub fn order_by_program(&mut self) { - self.processes.sort_by(|a, b| a.program.cmp(&b.program)) - } - - pub fn order_by_command(&mut self) { - self.processes.sort_by(|a, b| a.command.cmp(&b.command)) - } - - pub fn order_by_number_of_threads(&mut self) { - self.processes.sort_by(|a, b| { - a.number_of_threads - .partial_cmp(&b.number_of_threads) - .unwrap() - }) - } - - pub fn order_by_cpu(&mut self) { - self.processes - .sort_by(|a, b| a.cpu.partial_cmp(&b.cpu).unwrap()) - } - - pub fn render_tick(&mut self) { - info!("Render Tick"); - self.render_ticker = self.render_ticker.saturating_add(1); - } - - pub fn jump(&mut self, steps: i64) { - let location = self.state.selected().unwrap_or(0) as i64; - let length = self.process_map.len() as i64; - debug!( - "Move {} steps in [{}..{}] when current location is {}.", - steps, 0, length, location - ); - let mut index = location + steps; - while index < 0 { - index += length; - } - let new_location = (index % length) as usize; - debug!("New location is {}.", new_location); - self.state.select(Some(new_location)); - self.scrollbar_state = self.scrollbar_state.position(new_location); - } -} - -impl Component for Process { - fn register_action_handler(&mut self, tx: UnboundedSender) -> Result<()> { - self.action_tx = Some(tx); - Ok(()) - } - - fn handle_key_events(&mut self, key: KeyEvent) -> Result> { - debug!("Handling {:?}.", key); - let action = match key.code { - KeyCode::Up => Action::Up, - KeyCode::Down => Action::Down, - KeyCode::PageUp => Action::PageUp, - KeyCode::PageDown => Action::PageDown, - KeyCode::Left => Action::Left, - KeyCode::Right => Action::Right, - KeyCode::Esc => Action::Quit, - _ => Action::Update, - }; - Ok(Some(action)) - } - - fn update(&mut self, action: Action) -> Result> { - match action { - Action::Tick => self.tick(), - Action::Render => self.render_tick(), - Action::Up => self.jump(-1), - Action::Down => self.jump(1), - Action::PageUp => self.jump(-20), - Action::PageDown => self.jump(20), - Action::Left => { - self.order = self.order.previous(); - self.order_by_enum(); - } - Action::Right => { - self.order = self.order.next(); - self.order_by_enum(); - } - _ => (), - } - Ok(None) - } - - fn draw(&mut self, f: &mut Frame<'_>, _rect: Rect) -> Result<()> { - let layout = Layout::default() - .direction(Direction::Vertical) - .constraints([Percentage(100)]) - .split(f.size()); - - let rows = create_rows(&self.processes); - - let scrollbar = Scrollbar::new(ScrollbarOrientation::VerticalRight) - .begin_symbol(Some("↑")) - .end_symbol(Some("↓")) - .track_symbol(Some(" ")) - .style(Color::White); - - let selected_style = Style::default() - .bg(Color::Rgb(0xd4, 0x54, 0x54)) - .fg(Color::White) - .add_modifier(Modifier::BOLD); - - let header = [ - Cell::new(Line::from("Pid:").alignment(Alignment::Right)), - Cell::new("Program:"), - Cell::new("Command:"), - Cell::new(Line::from("Threads:").alignment(Alignment::Right)), - Cell::new("User:"), - Cell::new("MemB"), - Cell::new(""), - Cell::new("Cpu%"), - ] - .iter() - .cloned() - .map(Cell::from) - .collect::() - .height(1) - .style(Style::default().bold()); - - let processes = self.processes.len(); - let process = format!("{}/{}", self.state.selected().unwrap() + 1, processes); - - let block = Block::default() - .title(Title::from("brt").alignment(Alignment::Center)) - .title(Title::from(self.order_string()).alignment(Alignment::Right)) - .title( - Title::from(process) - .position(Position::Bottom) - .alignment(Alignment::Right), - ) - .borders(Borders::ALL) - .border_style(Style::default().fg(Color::White)) - .border_type(BorderType::Rounded); - - let widths = [ - Percentage(5), - Percentage(15), - Fill(1), - Percentage(5), - Percentage(5), - Length(5), - Length(5), - Length(5), - ]; - - let table = Table::new(rows, widths) - .block(block) - .header(header) - .highlight_style(selected_style); - - f.render_stateful_widget(table, layout[0], &mut self.state); - f.render_stateful_widget( - scrollbar, - layout[0].inner(&Margin { - vertical: 1, - horizontal: 1, - }), - &mut self.scrollbar_state, - ); - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::collections::VecDeque; - - #[test] - fn test_brt_process_new() { - let process = BrtProcess::new(); - assert_eq!(process.pid, 0); - assert_eq!(process.cpus, VecDeque::from(vec![0_f64; 10])); - } - - #[test] - fn test_process_jump() { - let mut process = Process::new(); - process.process_map = process.get_processes(); - assert_eq!(process.state.selected(), Some(0)); - process.jump(5); - assert_eq!(process.state.selected(), Some(5)); - process.jump(5); - assert_eq!(process.state.selected(), Some(10)); - process.jump(-15); - assert_eq!( - process.state.selected(), - Some(process.process_map.len() - 5) - ); - process.jump(4); - assert_eq!( - process.state.selected(), - Some(process.process_map.len() - 1) - ); - process.jump(1); - assert_eq!(process.state.selected(), Some(0)); - process.jump(1); - assert_eq!(process.state.selected(), Some(1)); - } -} diff --git a/src/components/processes.rs b/src/components/processes.rs new file mode 100644 index 0000000..e5bb65a --- /dev/null +++ b/src/components/processes.rs @@ -0,0 +1,225 @@ +use super::Component; +use crate::action::Action; +use color_eyre::Result; +use procfs::process::{all_processes, Stat}; +use ratatui::layout::{Constraint, Layout, Margin, Rect}; +use ratatui::prelude::Constraint::{Fill, Length, Percentage}; +use ratatui::prelude::{Alignment, Color, Line, Modifier, Style}; +use ratatui::widgets::{ + Block, BorderType, Borders, Cell, Row, Scrollbar, ScrollbarOrientation, ScrollbarState, Table, + TableState, +}; +use ratatui::Frame; +use std::collections::VecDeque; +use tracing::info; + +#[allow(dead_code)] +#[derive(Default, Clone, Debug)] +pub struct BrtProcess { + pub pid: i32, + pub ppid: i32, + pub program: String, + pub command: String, + pub number_of_threads: i64, + pub user: Option, + pub resident_memory: u64, + pub cpus: VecDeque, + pub cpu_graph: String, + pub cpu: f64, +} + +impl From for BrtProcess { + fn from(stat: Stat) -> Self { + BrtProcess { + pid: stat.pid, + ppid: stat.ppid, + program: stat.comm, + command: "".to_string(), + number_of_threads: stat.cguest_time.unwrap(), + user: None, + resident_memory: 0, + cpus: Default::default(), + cpu_graph: "foo".to_string(), + cpu: 0.0, + } + } +} + +#[derive(Default)] +pub struct ProcessesComponent { + processes: Vec, + scrollbar_state: ScrollbarState, + state: TableState, +} + +impl ProcessesComponent { + pub fn jump(&mut self, steps: i64) { + let location = self.state.selected().unwrap_or(0) as i64; + let length = self.processes.len() as i64; + info!( + "Move {} steps in [{}..{}] when current location is {}.", + steps, 0, length, location + ); + let mut index = location + steps; + while index < 0 { + index += length; + } + let new_location = (index % length) as usize; + info!("New location is {}.", new_location); + self.state.select(Some(new_location)); + self.scrollbar_state = self.scrollbar_state.position(new_location); + } +} + +pub fn create_row<'a>(process: &BrtProcess) -> Row<'a> { + // let user = process.user.clone(); + // let username = if user.is_some() { + // #[allow(clippy::unnecessary_unwrap)] + // user.unwrap().name().to_os_string().into_string().unwrap() + // } else { + // "unknown".to_string() + // }; + + let special_style = Style::default().fg(Color::Rgb(0x0D, 0xE7, 0x56)); + + // let humansize_options: FormatSizeOptions = FormatSizeOptions::from(BINARY) + // .space_after_value(false) + // .decimal_places(1) + // .decimal_zeroes(0); + + Row::new([ + Cell::new(Line::from(process.pid.to_string()).alignment(Alignment::Right)), + Cell::new(process.program.to_string()).style(special_style), + Cell::new(process.command.to_string()), + Cell::new( + Line::from(process.number_of_threads.to_string()) + .alignment(Alignment::Right) + .style(special_style), + ), + Cell::new(Line::from("username")), + Cell::new( + Line::from("format_size(process.resident_memory, humansize_options)") + .style(special_style), + ), + Cell::new(Line::from("process.cpu_graph.to_string()")), + Cell::new(format!("{:.2}", process.cpu)).style(special_style), + ]) +} + +pub fn create_rows(processes: &Vec) -> Vec { + let mut rows = Vec::new(); + for process in processes { + let row = create_row(process); + rows.push(row); + } + rows +} + +impl Component for ProcessesComponent { + fn update(&mut self, action: Action) -> Result> { + match action { + Action::Tick => { + // add any logic here that should run on every tick + } + Action::Render => { + // add any logic here that should run on every render + } + Action::Up => self.jump(-1), + Action::Down => self.jump(1), + Action::Update(since) => { + // info!("!!! Update at ({})", since); + self.processes = Vec::new(); + for p in all_processes()?.flatten() { + if let Ok(stat) = p.stat() { + self.processes.push(BrtProcess::from(stat)); + } + } + info!("[update|{}] processes len: {}", since, self.processes.len()); + self.scrollbar_state = self.scrollbar_state.content_length(self.processes.len()); + if self.state.selected().is_none() { + self.state.select(Some(0)); + } + } + _ => {} + } + Ok(None) + } + + fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> { + let [_, layout, _] = Layout::vertical([ + Constraint::Length(1), + Constraint::Fill(frame.area().height - 2), + Constraint::Length(1), + ]) + .areas(area); + + let scrollbar = Scrollbar::new(ScrollbarOrientation::VerticalRight) + .begin_symbol(Some("↑")) + .end_symbol(Some("↓")) + .track_symbol(Some(" ")) + .style(Color::White); + + let selected_row_style = Style::default() + .bg(Color::Rgb(0xd4, 0x54, 0x54)) + .add_modifier(Modifier::BOLD); + + let header = [ + Cell::new(Line::from("Pid:").alignment(Alignment::Right)), + Cell::new("Program:"), + Cell::new("Command:"), + Cell::new(Line::from("Threads:").alignment(Alignment::Right)), + Cell::new("User:"), + Cell::new("MemB"), + Cell::new(""), + Cell::new("Cpu%"), + ] + .iter() + .cloned() + .collect::() + .height(1) + .style( + Style::default() + .add_modifier(Modifier::BOLD) + .fg(Color::White), + ); + + let rows = create_rows(&self.processes); + let processes = self.processes.len(); + let process = format!("{}/{}", self.state.selected().unwrap_or(0) + 1, processes); + + let block = Block::default() + .title_top(Line::from("proc").alignment(Alignment::Left)) + .title_bottom(Line::from(process.to_string()).alignment(Alignment::Right)) + .borders(Borders::ALL) + .border_style(Style::default().fg(Color::White)) + .border_type(BorderType::Rounded); + + let widths = [ + Percentage(5), + Percentage(15), + Fill(1), + Percentage(5), + Percentage(5), + Length(5), + Length(5), + Length(5), + ]; + + let table = Table::new(rows, widths) + .block(block) + .header(header) + .row_highlight_style(selected_row_style); + + frame.render_stateful_widget(table, layout, &mut self.state); + frame.render_stateful_widget( + scrollbar, + layout.inner(Margin { + vertical: 1, + horizontal: 1, + }), + &mut self.scrollbar_state, + ); + + Ok(()) + } +} diff --git a/src/components/time.rs b/src/components/time.rs new file mode 100644 index 0000000..de188b6 --- /dev/null +++ b/src/components/time.rs @@ -0,0 +1,49 @@ +use super::Component; +use crate::action::Action; +use crate::config::Config; +use chrono::{DateTime, Local}; +use color_eyre::Result; +use ratatui::layout::Rect; +use ratatui::prelude::*; +use ratatui::text::ToText; +use ratatui::widgets::Paragraph; +use tokio::sync::mpsc::UnboundedSender; + +#[derive(Debug, Clone, Default)] +pub struct TimeWidget { + command_tx: Option>, + config: Config, + time: DateTime, +} + +impl Component for TimeWidget { + fn register_action_handler(&mut self, tx: UnboundedSender) -> Result<()> { + self.command_tx = Some(tx); + Ok(()) + } + + fn register_config_handler(&mut self, config: Config) -> Result<()> { + self.config = config; + Ok(()) + } + + fn update(&mut self, action: Action) -> Result> { + match action { + Action::Tick => { + // add any logic here that should run on every tick + } + Action::Render => { + // add any logic here that should run on every render + self.time = Local::now(); + } + _ => {} + } + Ok(None) + } + + fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> { + let binding = self.time.format("%H:%M:%S%.3f"); + frame.render_widget(Paragraph::new(binding.to_text()), area); + Ok(()) + } +} diff --git a/src/config.rs b/src/config.rs index c3a71d9..e2a8fef 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,21 +1,25 @@ -use std::{collections::HashMap, path::PathBuf}; +#![allow(dead_code)] // Remove this once you start using the code -use color_eyre::eyre::Result; +use std::{collections::HashMap, env, path::PathBuf}; + +use crate::{action::Action, app::Mode}; +use color_eyre::Result; use crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; use derive_deref::{Deref, DerefMut}; +use directories::ProjectDirs; +use lazy_static::lazy_static; use ratatui::style::{Color, Modifier, Style}; use serde::{de::Deserializer, Deserialize}; - -use crate::{action::Action, app::Mode}; +use tracing::error; const CONFIG: &str = include_str!("../.config/config.json5"); #[derive(Clone, Debug, Deserialize, Default)] pub struct AppConfig { #[serde(default)] - pub _data_dir: PathBuf, + pub data_dir: PathBuf, #[serde(default)] - pub _config_dir: PathBuf, + pub config_dir: PathBuf, } #[derive(Clone, Debug, Default, Deserialize)] @@ -28,14 +32,26 @@ pub struct Config { pub styles: Styles, } +lazy_static! { + pub static ref PROJECT_NAME: String = env!("CARGO_CRATE_NAME").to_uppercase().to_string(); + pub static ref DATA_FOLDER: Option = + env::var(format!("{}_DATA", PROJECT_NAME.clone())) + .ok() + .map(PathBuf::from); + pub static ref CONFIG_FOLDER: Option = + env::var(format!("{}_CONFIG", PROJECT_NAME.clone())) + .ok() + .map(PathBuf::from); +} + impl Config { pub fn new() -> Result { let default_config: Config = json5::from_str(CONFIG).unwrap(); - let data_dir = crate::utils::get_data_dir(); - let config_dir = crate::utils::get_config_dir(); + let data_dir = get_data_dir(); + let config_dir = get_config_dir(); let mut builder = config::Config::builder() - .set_default("_data_dir", data_dir.to_str().unwrap())? - .set_default("_config_dir", config_dir.to_str().unwrap())?; + .set_default("data_dir", data_dir.to_str().unwrap())? + .set_default("config_dir", config_dir.to_str().unwrap())?; let config_files = [ ("config.json5", config::FileFormat::Json5), @@ -46,17 +62,16 @@ impl Config { ]; let mut found_config = false; for (file, format) in &config_files { - builder = builder.add_source( - config::File::from(config_dir.join(file)) - .format(*format) - .required(false), - ); + let source = config::File::from(config_dir.join(file)) + .format(*format) + .required(false); + builder = builder.add_source(source); if config_dir.join(file).exists() { found_config = true } } if !found_config { - log::error!("No configuration file found. Application may not behave as expected"); + error!("No configuration file found. Application may not behave as expected"); } let mut cfg: Self = builder.build()?.try_deserialize()?; @@ -72,9 +87,7 @@ impl Config { for (mode, default_styles) in default_config.styles.iter() { let user_styles = cfg.styles.entry(*mode).or_default(); for (style_key, style) in default_styles.iter() { - user_styles - .entry(style_key.clone()) - .or_insert_with(|| *style); + user_styles.entry(style_key.clone()).or_insert(*style); } } @@ -82,6 +95,32 @@ impl Config { } } +pub fn get_data_dir() -> PathBuf { + let directory = if let Some(s) = DATA_FOLDER.clone() { + s + } else if let Some(proj_dirs) = project_directory() { + proj_dirs.data_local_dir().to_path_buf() + } else { + PathBuf::from(".").join(".data") + }; + directory +} + +pub fn get_config_dir() -> PathBuf { + let directory = if let Some(s) = CONFIG_FOLDER.clone() { + s + } else if let Some(proj_dirs) = project_directory() { + proj_dirs.config_local_dir().to_path_buf() + } else { + PathBuf::from(".").join(".config") + }; + directory +} + +fn project_directory() -> Option { + ProjectDirs::from("com", "kdheepak", env!("CARGO_PKG_NAME")) +} + #[derive(Clone, Debug, Default, Deref, DerefMut)] pub struct KeyBindings(pub HashMap, Action>>); @@ -253,7 +292,7 @@ pub fn key_event_to_string(key_event: &KeyEvent) -> String { pub fn parse_key_sequence(raw: &str) -> Result, String> { if raw.chars().filter(|c| *c == '>').count() != raw.chars().filter(|c| *c == '<').count() { - return Err(format!("Unable to parse `{}`", raw)); + return Err(format!("Unable to parse `{raw}`")); } let raw = if !raw.contains("><") { let raw = raw.strip_prefix('<').unwrap_or(raw); @@ -450,7 +489,7 @@ mod tests { #[test] fn test_parse_color_rgb() { let color = parse_color("rgb123"); - let expected = 67; + let expected = 16 + 36 + 2 * 6 + 3; assert_eq!(color, Some(Color::Indexed(expected))); } @@ -465,7 +504,7 @@ mod tests { let c = Config::new()?; assert_eq!( c.keybindings - .get(&Mode::Process) + .get(&Mode::Home) .unwrap() .get(&parse_key_sequence("").unwrap_or_default()) .unwrap(), diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..22f941f --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,78 @@ +use std::env; + +use color_eyre::Result; +use tracing::error; + +pub fn init() -> Result<()> { + let (panic_hook, eyre_hook) = color_eyre::config::HookBuilder::default() + .panic_section(format!( + "This is a bug. Consider reporting it at {}", + env!("CARGO_PKG_REPOSITORY") + )) + .capture_span_trace_by_default(false) + .display_location_section(false) + .display_env_section(false) + .into_hooks(); + eyre_hook.install()?; + std::panic::set_hook(Box::new(move |panic_info| { + if let Ok(mut t) = crate::tui::Tui::new() { + if let Err(r) = t.exit() { + error!("Unable to exit Terminal: {:?}", r); + } + } + + #[cfg(not(debug_assertions))] + { + use human_panic::{handle_dump, metadata, print_msg}; + let metadata = metadata!(); + let file_path = handle_dump(&metadata, panic_info); + // prints human-panic message + print_msg(file_path, &metadata) + .expect("human-panic: printing error message to console failed"); + eprintln!("{}", panic_hook.panic_report(panic_info)); // prints color-eyre stack trace to stderr + } + let msg = format!("{}", panic_hook.panic_report(panic_info)); + error!("Error: {}", strip_ansi_escapes::strip_str(msg)); + + #[cfg(debug_assertions)] + { + // Better Panic stacktrace that is only enabled when debugging. + better_panic::Settings::auto() + .most_recent_first(false) + .lineno_suffix(true) + .verbosity(better_panic::Verbosity::Full) + .create_panic_handler()(panic_info); + } + + std::process::exit(libc::EXIT_FAILURE); + })); + Ok(()) +} + +/// Similar to the `std::dbg!` macro, but generates `tracing` events rather +/// than printing to stdout. +/// +/// By default, the verbosity level for the generated events is `DEBUG`, but +/// this can be customized. +#[macro_export] +macro_rules! trace_dbg { + (target: $target:expr, level: $level:expr, $ex:expr) => { + { + match $ex { + value => { + tracing::event!(target: $target, $level, ?value, stringify!($ex)); + value + } + } + } + }; + (level: $level:expr, $ex:expr) => { + trace_dbg!(target: module_path!(), level: $level, $ex) + }; + (target: $target:expr, $ex:expr) => { + trace_dbg!(target: $target, level: tracing::Level::DEBUG, $ex) + }; + ($ex:expr) => { + trace_dbg!(level: tracing::Level::DEBUG, $ex) + }; +} diff --git a/src/logger.rs b/src/logger.rs deleted file mode 100644 index 4f6ebfe..0000000 --- a/src/logger.rs +++ /dev/null @@ -1,45 +0,0 @@ -use log::LevelFilter; -use log4rs::append::file::FileAppender; -use log4rs::config::{Appender, Logger, Root}; -use log4rs::encode::pattern::PatternEncoder; -use log4rs::Config; -use std::path::PathBuf; - -const LOG_PATTERN: &str = "{d(%Y-%m-%d %H:%M:%S)} | {l} | {f}:{L} | {m}{n}"; - -pub fn initialize_logging() { - let data_local_dir = if let Ok(s) = std::env::var("BRT_DATA") { - PathBuf::from(s) - } else { - dirs::data_local_dir() - .expect("Unable to find data directory for brt") - .join("brt") - }; - - std::fs::create_dir_all(&data_local_dir) - .unwrap_or_else(|_| panic!("Unable to create {:?}", data_local_dir)); - - let logfile = FileAppender::builder() - .encoder(Box::new(PatternEncoder::new(LOG_PATTERN))) - .build(data_local_dir.join("brt.log")) - .expect("Failed to build log file appender."); - - let levelfilter = match std::env::var("BRT_LOG_LEVEL") - .unwrap_or_else(|_| "info".to_string()) - .as_str() - { - "off" => LevelFilter::Off, - "warn" => LevelFilter::Warn, - "info" => LevelFilter::Info, - "debug" => LevelFilter::Debug, - "trace" => LevelFilter::Trace, - _ => LevelFilter::Info, - }; - let config = Config::builder() - .appender(Appender::builder().build("logfile", Box::new(logfile))) - .logger(Logger::builder().build("brt", levelfilter)) - .build(Root::builder().appender("logfile").build(LevelFilter::Info)) - .expect("Failed to build logging config."); - - log4rs::init_config(config).expect("Failed to initialize logging."); -} diff --git a/src/logging.rs b/src/logging.rs new file mode 100644 index 0000000..37df144 --- /dev/null +++ b/src/logging.rs @@ -0,0 +1,36 @@ +use color_eyre::Result; +use tracing_error::ErrorLayer; +use tracing_subscriber::{fmt, prelude::*, EnvFilter}; + +use crate::config; + +lazy_static::lazy_static! { + pub static ref LOG_ENV: String = format!("{}_LOG_LEVEL", config::PROJECT_NAME.clone()); + pub static ref LOG_FILE: String = format!("{}.log", env!("CARGO_PKG_NAME")); +} + +pub fn init() -> Result<()> { + let directory = config::get_data_dir(); + std::fs::create_dir_all(directory.clone())?; + let log_path = directory.join(LOG_FILE.clone()); + let log_file = std::fs::File::create(log_path)?; + let env_filter = EnvFilter::builder().with_default_directive(tracing::Level::INFO.into()); + // If the `RUST_LOG` environment variable is set, use that as the default, otherwise use the + // value of the `LOG_ENV` environment variable. If the `LOG_ENV` environment variable contains + // errors, then this will return an error. + let env_filter = env_filter + .try_from_env() + .or_else(|_| env_filter.with_env_var(LOG_ENV.clone()).from_env())?; + let file_subscriber = fmt::layer() + .with_file(true) + .with_line_number(true) + .with_writer(log_file) + .with_target(false) + .with_ansi(false) + .with_filter(env_filter); + tracing_subscriber::registry() + .with(file_subscriber) + .with(ErrorLayer::default()) + .try_init()?; + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index 37e07b3..7f3f78b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,40 +1,25 @@ -pub mod action; -pub mod app; -pub mod cli; -pub mod components; -pub mod config; -pub mod model; -pub mod tui; -pub mod utils; -pub mod widgets; - use clap::Parser; use cli::Cli; -use color_eyre::eyre::Result; +use color_eyre::Result; -use crate::{ - app::App, - utils::{initialize_logging, initialize_panic_handler}, -}; +use crate::app::App; -async fn tokio_main() -> Result<()> { - initialize_logging()?; +mod action; +mod app; +mod cli; +mod components; +mod config; +mod errors; +mod logging; +mod tui; - initialize_panic_handler()?; +#[tokio::main] +async fn main() -> Result<()> { + crate::errors::init()?; + crate::logging::init()?; let args = Cli::parse(); - let mut app = App::new(args.tick_rate, args.frame_rate, args.debug)?; + let mut app = App::new(args.tick_rate, args.frame_rate)?; app.run().await?; - Ok(()) } - -#[tokio::main] -async fn main() -> Result<()> { - if let Err(e) = tokio_main().await { - eprintln!("{} error: Something went wrong", env!("CARGO_PKG_NAME")); - Err(e) - } else { - Ok(()) - } -} diff --git a/src/model.rs b/src/model.rs deleted file mode 100644 index e558df5..0000000 --- a/src/model.rs +++ /dev/null @@ -1,235 +0,0 @@ -use battery::Battery; -use humansize::{format_size, FormatSizeOptions, BINARY}; -use log::{debug, warn}; -use procfs::process::Process; -use procfs::{ticks_per_second, CpuInfo, Current, Uptime}; -use ratatui::layout::Alignment; -use ratatui::style::{Color, Style}; -use ratatui::text::Line; -use ratatui::widgets::{Cell, Row}; -use std::collections::{HashMap, VecDeque}; -use uzers::{get_user_by_uid, User}; - -pub fn get_battery() -> Battery { - let manager = battery::Manager::new().unwrap(); - manager.batteries().unwrap().next().unwrap().unwrap() -} - -pub fn create_rows<'a>(processes: &Vec) -> Vec> { - let mut rows = Vec::new(); - for process in processes { - let row = create_row(process); - rows.push(row); - } - rows -} - -pub fn create_row<'a>(process: &BrtProcess) -> Row<'a> { - let user = process.user.clone(); - let username = if user.is_some() { - #[allow(clippy::unnecessary_unwrap)] - user.unwrap().name().to_os_string().into_string().unwrap() - } else { - "unknown".to_string() - }; - - let special_style = Style::default().fg(Color::Rgb(0x0D, 0xE7, 0x56)); - - let humansize_options: FormatSizeOptions = FormatSizeOptions::from(BINARY) - .space_after_value(false) - .decimal_places(1) - .decimal_zeroes(0); - - Row::new([ - Cell::new(Line::from(process.pid.to_string()).alignment(Alignment::Right)), - Cell::new(process.program.to_string()).style(special_style), - Cell::new(process.command.to_string()), - Cell::new( - Line::from(process.number_of_threads.to_string()) - .alignment(Alignment::Right) - .style(special_style), - ), - Cell::new(username), - Cell::new(format_size(process.resident_memory, humansize_options)).style(special_style), - Cell::new(process.cpu_graph.to_string()), - Cell::new(format!("{:.2}", process.cpu)).style(special_style), - ]) -} - -fn between(status: &f64, min: f64, max: f64) -> bool { - status >= &min && status < &max -} - -fn get_points(cpu: &f64) -> i32 { - match cpu { - status if between(status, 0_f64, 0.001_f64) => 0, - status if between(status, 0.001_f64, 0.2_f64) => 1, - status if between(status, 0.2_f64, 0.5_f64) => 2, - status if between(status, 0.5_f64, 0.7_f64) => 3, - status if between(status, 0.7_f64, 100_f64) => 4, - _ => { - warn!("Invalid cpu found: {}; setting to zero.", cpu); - 0 - } - } -} - -pub fn get_cpu_graph(cpus: &VecDeque) -> String { - let blocks: HashMap<&str, &str> = HashMap::from([ - ("00", " "), - ("01", "⢀"), - ("02", "⢠"), - ("03", "⢰"), - ("04", "⢸"), - ("10", "⡀"), - ("11", "⣀"), - ("12", "⣠"), - ("13", "⣰"), - ("14", "⣸"), - ("20", "⡄"), - ("21", "⣄"), - ("22", "⣤"), - ("23", "⣴"), - ("24", "⣼"), - ("30", "⡆"), - ("31", "⣆"), - ("32", "⣦"), - ("33", "⣶"), - ("34", "⣾"), - ("40", "⡇"), - ("41", "⣇"), - ("42", "⣧"), - ("43", "⣷"), - ("44", "⣿"), - ]); - let mut graph = "".to_string(); - let v: Vec<&f64> = cpus.iter().collect(); - for cpu in v.chunks(2) { - let first = get_points(cpu[0]); - let second = get_points(cpu[1]); - let slot = blocks.get(format!("{}{}", first, second).as_str()).unwrap(); - graph += slot; - } - graph -} - -#[derive(Default, Clone, Debug)] -pub struct BrtProcess { - pub pid: i32, - pub ppid: i32, - pub program: String, - pub command: String, - pub number_of_threads: i64, - pub user: Option, - pub resident_memory: u64, - pub cpus: VecDeque, - pub cpu_graph: String, - pub cpu: f64, -} - -impl BrtProcess { - pub fn new() -> BrtProcess { - BrtProcess { - cpus: VecDeque::from(vec![0_f64; 10]), - ..Default::default() - } - } -} - -fn create_command(cmdline: &[String]) -> String { - let mut command = "".to_string(); - for part in cmdline.iter() { - command += format!("{} ", part).as_str(); - } - command -} - -pub fn to_brt_process(process: &Process) -> Option { - let mut brt_process: BrtProcess = BrtProcess::new(); - let stat_result = process.stat(); - match stat_result { - Ok(stat) => { - brt_process.pid = stat.pid; - brt_process.ppid = stat.ppid; - brt_process.program = stat.comm; - brt_process.number_of_threads = stat.num_threads; - - // command - let cmd_result = process.cmdline(); - match cmd_result { - Ok(cmd) => { - brt_process.command = create_command(&cmd); - } - Err(_e) => { - brt_process.command = "zombie".to_string(); - } - } - - // user - let uid_result = process.uid(); - match uid_result { - Ok(uid) => { - brt_process.user = get_user_by_uid(uid); - } - Err(_e) => { - warn!("No user found for process {}.", process.pid().to_string()); - brt_process.user = None; - } - } - - // memory - let resident_memory = get_memory(process); - brt_process.resident_memory = resident_memory; - - // cpu(s) - let cpu = get_cpu(process); - brt_process.cpu = cpu; - brt_process.cpus.push_back(cpu); - brt_process.cpus.pop_front(); - brt_process.cpu_graph = get_cpu_graph(&brt_process.cpus); - } - Err(_e) => { - warn!("Stat not found for process {}.", process.pid().to_string()); - return None; - } - } - Some(brt_process) -} - -pub fn get_memory(process: &Process) -> u64 { - let statm = process.statm().unwrap(); // TODO: this can be: NotFound(Some("/proc/3955386/statm")) - let page_size = procfs::page_size(); - statm.resident * page_size -} - -fn get_cpu(process: &Process) -> f64 { - let stat = process.stat().unwrap(); - - let usage = stat.utime / ticks_per_second() + stat.stime / ticks_per_second(); - debug!("usage: {}s", usage); - - let uptime = Uptime::current().unwrap().uptime_duration().as_secs(); - debug!("Uptime: {}s", uptime); - - let starttime = stat.starttime / ticks_per_second(); - debug!("start time: {}s", starttime); - - let runtime = uptime - starttime; - debug!("runtime: {}s", runtime); - - let num_cores = CpuInfo::current().unwrap().num_cores(); - debug!("Uptime: {}s", uptime); - - usage as f64 * 100.0 / runtime as f64 / num_cores as f64 -} - -#[cfg(test)] -mod tests { - - #[test] - fn test_get_all_processes() { - // let all_processes = get_all_processes(); - // assert_eq!(all_processes.is_empty(), false) - assert_eq!(false, false) - } -} diff --git a/src/processbar.rs b/src/processbar.rs deleted file mode 100644 index a3cc6fc..0000000 --- a/src/processbar.rs +++ /dev/null @@ -1,54 +0,0 @@ -pub mod model; - -use anyhow::{Context, Result}; -use clap::Parser; -use log::debug; -use model::get_memory; -use owo_colors::OwoColorize; -use procfs::process::Process; -use procfs::{page_size, ticks_per_second, CpuInfo, Current, Uptime}; - -#[derive(Parser, Debug)] -#[command(version, about, long_about = None)] -struct Args { - #[arg(long)] - pid: i32, -} - -#[allow(dead_code)] -fn main() -> Result<()> { - let args = Args::parse(); - - let pid = args.pid; - - debug!("Checking pid {}...", pid); - let process = Process::new(pid).with_context(|| format!("Pid {pid} not found."))?; - let stat = process.stat().unwrap(); - - debug!("ticks per second: {}", ticks_per_second()); - debug!("pagesize: {}", page_size()); - let usage = stat.utime / ticks_per_second() + stat.stime / ticks_per_second(); - debug!("usage {} ", usage); - - let uptime = Uptime::current().unwrap().uptime_duration().as_secs(); - debug!("Uptime: {}", uptime); - let starttime = stat.starttime / ticks_per_second(); - debug!("Starttime: {}", starttime); - let runtime = uptime - starttime; - debug!("runtime: {}", runtime); - let num_cores = CpuInfo::current().unwrap().num_cores(); - debug!("num cores: {}", num_cores); - let percentage = usage as f64 * 100.0 / runtime as f64 / num_cores as f64; - - let memory = get_memory(&process); - - println!( - "Process {} ({}) has used {:.2}% of the cpu and is using {} bytes of memory.", - stat.comm.green(), - pid.yellow(), - percentage.yellow(), - memory.yellow(), - ); - - Ok(()) -} diff --git a/src/tui.rs b/src/tui.rs index ea89c0b..39784c5 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -1,24 +1,30 @@ -use std::{ - ops::{Deref, DerefMut}, - time::Duration, -}; +#![allow(dead_code)] // Remove this once you start using the code -use color_eyre::eyre::Result; +use color_eyre::Result; use crossterm::{ cursor, - event::{Event as CrosstermEvent, KeyEvent, KeyEventKind, MouseEvent}, + event::{ + DisableBracketedPaste, DisableMouseCapture, EnableBracketedPaste, EnableMouseCapture, + Event as CrosstermEvent, EventStream, KeyEvent, KeyEventKind, MouseEvent, + }, terminal::{EnterAlternateScreen, LeaveAlternateScreen}, }; use futures::{FutureExt, StreamExt}; use ratatui::backend::CrosstermBackend as Backend; use serde::{Deserialize, Serialize}; +use std::{ + io::{stdout, Stdout}, + ops::{Deref, DerefMut}, + time::Duration, +}; +use tokio::time::Instant; use tokio::{ sync::mpsc::{self, UnboundedReceiver, UnboundedSender}, task::JoinHandle, + time::interval, }; use tokio_util::sync::CancellationToken; - -pub type Frame<'a> = ratatui::Frame<'a>; +use tracing::error; #[derive(Clone, Debug, Serialize, Deserialize)] pub enum Event { @@ -34,106 +40,123 @@ pub enum Event { Key(KeyEvent), Mouse(MouseEvent), Resize(u16, u16), + Update(Duration), } pub struct Tui { - pub terminal: ratatui::Terminal>, + pub terminal: ratatui::Terminal>, pub task: JoinHandle<()>, pub cancellation_token: CancellationToken, pub event_rx: UnboundedReceiver, pub event_tx: UnboundedSender, pub frame_rate: f64, pub tick_rate: f64, + pub mouse: bool, + pub paste: bool, } impl Tui { pub fn new() -> Result { - let tick_rate = 4.0; - let frame_rate = 60.0; - let terminal = ratatui::Terminal::new(Backend::new(std::io::stderr()))?; let (event_tx, event_rx) = mpsc::unbounded_channel(); - let cancellation_token = CancellationToken::new(); - let task = tokio::spawn(async {}); Ok(Self { - terminal, - task, - cancellation_token, + terminal: ratatui::Terminal::new(Backend::new(stdout()))?, + task: tokio::spawn(async {}), + cancellation_token: CancellationToken::new(), event_rx, event_tx, - frame_rate, - tick_rate, + frame_rate: 60.0, + tick_rate: 4.0, + mouse: false, + paste: false, }) } - pub fn tick_rate(&mut self, tick_rate: f64) { + pub fn tick_rate(mut self, tick_rate: f64) -> Self { self.tick_rate = tick_rate; + self } - pub fn frame_rate(&mut self, frame_rate: f64) { + pub fn frame_rate(mut self, frame_rate: f64) -> Self { self.frame_rate = frame_rate; + self + } + + pub fn mouse(mut self, mouse: bool) -> Self { + self.mouse = mouse; + self + } + + pub fn paste(mut self, paste: bool) -> Self { + self.paste = paste; + self } pub fn start(&mut self) { - let tick_delay = std::time::Duration::from_secs_f64(1.0 / self.tick_rate); - let render_delay = std::time::Duration::from_secs_f64(1.0 / self.frame_rate); - self.cancel(); + self.cancel(); // Cancel any existing task self.cancellation_token = CancellationToken::new(); - let _cancellation_token = self.cancellation_token.clone(); - let _event_tx = self.event_tx.clone(); - self.task = tokio::spawn(async move { - let mut reader = crossterm::event::EventStream::new(); - let mut tick_interval = tokio::time::interval(tick_delay); - let mut render_interval = tokio::time::interval(render_delay); - _event_tx.send(Event::Init).unwrap(); - loop { - let tick_delay = tick_interval.tick(); - let render_delay = render_interval.tick(); - let crossterm_event = reader.next().fuse(); - tokio::select! { - _ = _cancellation_token.cancelled() => { + let event_loop = Self::event_loop( + self.event_tx.clone(), + self.cancellation_token.clone(), + self.tick_rate, + self.frame_rate, + ); + self.task = tokio::spawn(async { + event_loop.await; + }); + } + + async fn event_loop( + event_tx: UnboundedSender, + cancellation_token: CancellationToken, + tick_rate: f64, + frame_rate: f64, + ) { + let mut event_stream = EventStream::new(); + let mut tick_interval = interval(Duration::from_secs_f64(1.0 / tick_rate)); + let mut render_interval = interval(Duration::from_secs_f64(1.0 / frame_rate)); + let mut component_interval = interval(Duration::from_millis(500)); + + let mut last = Instant::now(); + + // if this fails, then it's likely a bug in the calling code + event_tx + .send(Event::Init) + .expect("failed to send init event"); + + loop { + let event = tokio::select! { + _ = cancellation_token.cancelled() => { break; - } - maybe_event = crossterm_event => { - match maybe_event { - Some(Ok(evt)) => { - match evt { - CrosstermEvent::Key(key) => { - if key.kind == KeyEventKind::Press { - _event_tx.send(Event::Key(key)).unwrap(); - } - }, - CrosstermEvent::Mouse(mouse) => { - _event_tx.send(Event::Mouse(mouse)).unwrap(); - }, - CrosstermEvent::Resize(x, y) => { - _event_tx.send(Event::Resize(x, y)).unwrap(); - }, - CrosstermEvent::FocusLost => { - _event_tx.send(Event::FocusLost).unwrap(); - }, - CrosstermEvent::FocusGained => { - _event_tx.send(Event::FocusGained).unwrap(); - }, - CrosstermEvent::Paste(s) => { - _event_tx.send(Event::Paste(s)).unwrap(); - }, - } - } - Some(Err(_)) => { - _event_tx.send(Event::Error).unwrap(); - } - None => {}, - } - }, - _ = tick_delay => { - _event_tx.send(Event::Tick).unwrap(); - }, - _ = render_delay => { - _event_tx.send(Event::Render).unwrap(); - }, } + _ = tick_interval.tick() => Event::Tick, + _ = render_interval.tick() => Event::Render, + instant = component_interval.tick() => { + // info!("component instant: {:?}", instant); + let event = Event::Update(instant.duration_since(last)); + last = Instant::now(); + // component_interval = interval(Duration::from_millis(1000)); + event + }, + crossterm_event = event_stream.next().fuse() => match crossterm_event { + Some(Ok(event)) => match event { + CrosstermEvent::Key(key) if key.kind == KeyEventKind::Press => Event::Key(key), + CrosstermEvent::Mouse(mouse) => Event::Mouse(mouse), + CrosstermEvent::Resize(x, y) => Event::Resize(x, y), + CrosstermEvent::FocusLost => Event::FocusLost, + CrosstermEvent::FocusGained => Event::FocusGained, + CrosstermEvent::Paste(s) => Event::Paste(s), + _ => continue, // ignore other events + } + Some(Err(_)) => Event::Error, + None => break, // the event stream has stopped and will not produce any more events + }, + }; + if event_tx.send(event).is_err() { + // the receiver has been dropped, so there's no point in continuing the loop + break; } - }); + } + cancellation_token.cancel(); } pub fn stop(&self) -> Result<()> { @@ -146,7 +169,7 @@ impl Tui { self.task.abort(); } if counter > 100 { - log::error!("Failed to abort task in 100 milliseconds for unknown reason"); + error!("Failed to abort task in 100 milliseconds for unknown reason"); break; } } @@ -155,7 +178,13 @@ impl Tui { pub fn enter(&mut self) -> Result<()> { crossterm::terminal::enable_raw_mode()?; - crossterm::execute!(std::io::stderr(), EnterAlternateScreen, cursor::Hide)?; + crossterm::execute!(stdout(), EnterAlternateScreen, cursor::Hide)?; + if self.mouse { + crossterm::execute!(stdout(), EnableMouseCapture)?; + } + if self.paste { + crossterm::execute!(stdout(), EnableBracketedPaste)?; + } self.start(); Ok(()) } @@ -164,7 +193,13 @@ impl Tui { self.stop()?; if crossterm::terminal::is_raw_mode_enabled()? { self.flush()?; - crossterm::execute!(std::io::stderr(), LeaveAlternateScreen, cursor::Show)?; + if self.paste { + crossterm::execute!(stdout(), DisableBracketedPaste)?; + } + if self.mouse { + crossterm::execute!(stdout(), DisableMouseCapture)?; + } + crossterm::execute!(stdout(), LeaveAlternateScreen, cursor::Show)?; crossterm::terminal::disable_raw_mode()?; } Ok(()) @@ -186,13 +221,13 @@ impl Tui { Ok(()) } - pub async fn next(&mut self) -> Option { + pub async fn next_event(&mut self) -> Option { self.event_rx.recv().await } } impl Deref for Tui { - type Target = ratatui::Terminal>; + type Target = ratatui::Terminal>; fn deref(&self) -> &Self::Target { &self.terminal diff --git a/src/utils.rs b/src/utils.rs deleted file mode 100644 index 6379dfc..0000000 --- a/src/utils.rs +++ /dev/null @@ -1,168 +0,0 @@ -use std::path::PathBuf; - -use color_eyre::eyre::Result; -use directories::ProjectDirs; -use lazy_static::lazy_static; -use tracing::error; -use tracing_error::ErrorLayer; -use tracing_subscriber::{ - self, prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt, Layer, -}; - -lazy_static! { - pub static ref PROJECT_NAME: String = env!("CARGO_CRATE_NAME").to_uppercase().to_string(); - pub static ref DATA_FOLDER: Option = - std::env::var(format!("{}_DATA", PROJECT_NAME.clone())) - .ok() - .map(PathBuf::from); - pub static ref CONFIG_FOLDER: Option = - std::env::var(format!("{}_CONFIG", PROJECT_NAME.clone())) - .ok() - .map(PathBuf::from); - pub static ref LOG_ENV: String = format!("{}_LOGLEVEL", PROJECT_NAME.clone()); - pub static ref LOG_FILE: String = format!("{}.log", env!("CARGO_PKG_NAME")); -} - -fn project_directory() -> Option { - ProjectDirs::from("com", "elevenbits", env!("CARGO_PKG_NAME")) -} - -pub fn initialize_panic_handler() -> Result<()> { - let (panic_hook, eyre_hook) = color_eyre::config::HookBuilder::default() - .panic_section(format!( - "This is a bug. Consider reporting it at {}", - env!("CARGO_PKG_REPOSITORY") - )) - .capture_span_trace_by_default(false) - .display_location_section(false) - .display_env_section(false) - .into_hooks(); - eyre_hook.install()?; - std::panic::set_hook(Box::new(move |panic_info| { - if let Ok(mut t) = crate::tui::Tui::new() { - if let Err(r) = t.exit() { - error!("Unable to exit Terminal: {:?}", r); - } - } - - #[cfg(not(debug_assertions))] - { - use human_panic::{metadata, setup_panic}; - setup_panic!(metadata!() - .authors(env!("CARGO_PKG_AUTHORS").replace(':', ", ")) - .homepage(env!("CARGO_PKG_HOMEPAGE"))); - } - let msg = format!("{}", panic_hook.panic_report(panic_info)); - log::error!("Error: {}", strip_ansi_escapes::strip_str(msg)); - - #[cfg(debug_assertions)] - { - // Better Panic stacktrace that is only enabled when debugging. - better_panic::Settings::auto() - .most_recent_first(false) - .lineno_suffix(true) - .verbosity(better_panic::Verbosity::Full) - .create_panic_handler()(panic_info); - } - - std::process::exit(libc::EXIT_FAILURE); - })); - Ok(()) -} - -pub fn get_data_dir() -> PathBuf { - let directory = if let Some(s) = DATA_FOLDER.clone() { - s - } else if let Some(proj_dirs) = project_directory() { - proj_dirs.data_local_dir().to_path_buf() - } else { - PathBuf::from(".").join(".data") - }; - directory -} - -pub fn get_config_dir() -> PathBuf { - let directory = if let Some(s) = CONFIG_FOLDER.clone() { - s - } else if let Some(proj_dirs) = project_directory() { - proj_dirs.config_local_dir().to_path_buf() - } else { - PathBuf::from(".").join(".config") - }; - directory -} - -pub fn initialize_logging() -> Result<()> { - let directory = get_data_dir(); - std::fs::create_dir_all(directory.clone())?; - let log_path = directory.join(LOG_FILE.clone()); - let log_file = std::fs::File::create(log_path)?; - std::env::set_var( - "RUST_LOG", - std::env::var("RUST_LOG") - .or_else(|_| std::env::var(LOG_ENV.clone())) - .unwrap_or_else(|_| format!("{}=info", env!("CARGO_CRATE_NAME"))), - ); - let file_subscriber = tracing_subscriber::fmt::layer() - .with_file(true) - .with_line_number(true) - .with_writer(log_file) - .with_target(false) - .with_ansi(false) - .with_filter(tracing_subscriber::filter::EnvFilter::from_default_env()); - tracing_subscriber::registry() - .with(file_subscriber) - .with(ErrorLayer::default()) - .init(); - Ok(()) -} - -/// Similar to the `std::dbg!` macro, but generates `tracing` events rather -/// than printing to stdout. -/// -/// By default, the verbosity level for the generated events is `DEBUG`, but -/// this can be customized. -#[macro_export] -macro_rules! trace_dbg { - (target: $target:expr, level: $level:expr, $ex:expr) => {{ - match $ex { - value => { - tracing::event!(target: $target, $level, ?value, stringify!($ex)); - value - } - } - }}; - (level: $level:expr, $ex:expr) => { - trace_dbg!(target: module_path!(), level: $level, $ex) - }; - (target: $target:expr, $ex:expr) => { - trace_dbg!(target: $target, level: tracing::Level::DEBUG, $ex) - }; - ($ex:expr) => { - trace_dbg!(level: tracing::Level::DEBUG, $ex) - }; -} - -pub fn version() -> String { - let author = clap::crate_authors!(); - - let mut commit_hash = "no hash"; - #[allow(clippy::option_env_unwrap)] - if option_env!("BRT_GIT_INFO").is_some() { - commit_hash = option_env!("BRT_GIT_INFO").unwrap() - }; - - // let current_exe_path = PathBuf::from(clap::crate_name!()).display().to_string(); - let config_dir_path = get_config_dir().display().to_string(); - let data_dir_path = get_data_dir().display().to_string(); - - format!( - "\ -({commit_hash}) - -Authors: {author} - -Config directory: {config_dir_path} -Data directory: {data_dir_path}" - ) -} diff --git a/src/widgets.rs b/src/widgets.rs deleted file mode 100644 index d3d9d5f..0000000 --- a/src/widgets.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod cpu_graph; diff --git a/src/widgets/cpu_graph.rs b/src/widgets/cpu_graph.rs deleted file mode 100644 index b9d99b4..0000000 --- a/src/widgets/cpu_graph.rs +++ /dev/null @@ -1,59 +0,0 @@ -use ratatui::buffer::Buffer; -use ratatui::layout::Rect; -use ratatui::{prelude::*, widgets::*}; -use std::collections::VecDeque; - -#[derive(Debug, Clone, PartialEq)] -pub struct CpuGraph<'a> { - block: Option>, - data: VecDeque, -} - -impl<'a> Default for CpuGraph<'a> { - fn default() -> CpuGraph<'a> { - CpuGraph { - block: None, - data: VecDeque::from(vec![0_u64, 25]), - } - } -} - -impl<'a> CpuGraph<'a> { - /// Surrounds the `CpuGraph` with a [`Block`]. - #[must_use = "method moves the value of self and returns the modified value"] - pub fn block(mut self, block: Block<'a>) -> Self { - self.block = Some(block); - self - } - - #[must_use = "method moves the value of self and returns the modified value"] - pub fn update(mut self, point: u64) -> Self { - self.data.push_back(point); - self.data.pop_front(); - self - } -} - -impl Widget for CpuGraph<'_> { - fn render(self, area: Rect, buf: &mut Buffer) { - self.render_ref(area, buf); - } -} - -impl WidgetRef for CpuGraph<'_> { - fn render_ref(&self, area: Rect, buf: &mut Buffer) { - self.block.render_ref(area, buf); - let inner = self.block.inner_if_some(area); - self.render_cpu_graph(inner, buf); - } -} - -impl CpuGraph<'_> { - fn render_cpu_graph(&self, gpu_graph_area: Rect, buf: &mut Buffer) { - if gpu_graph_area.is_empty() { - return; - } - let label = Span::raw(format!("{}", self.data.len())); - buf.set_span(0, 0, &label, 1); - } -}