monitors flake works

This commit is contained in:
2025-08-11 11:52:50 -06:00
parent 47f72bc819
commit e0be16231e
3 changed files with 683 additions and 163 deletions

View File

@@ -11,6 +11,12 @@ dependencies = [
"memchr",
]
[[package]]
name = "allocator-api2"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "android-tzdata"
version = "0.1.1"
@@ -50,6 +56,21 @@ version = "3.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
name = "cassowary"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
[[package]]
name = "castaway"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a"
dependencies = [
"rustversion",
]
[[package]]
name = "cc"
version = "1.2.32"
@@ -80,16 +101,16 @@ dependencies = [
]
[[package]]
name = "console"
version = "0.15.11"
name = "compact_str"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f"
dependencies = [
"encode_unicode",
"libc",
"once_cell",
"unicode-width",
"windows-sys 0.59.0",
"castaway",
"cfg-if",
"itoa",
"ryu",
"static_assertions",
]
[[package]]
@@ -99,16 +120,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "dialoguer"
version = "0.11.0"
name = "crossterm"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de"
checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
dependencies = [
"console",
"shell-words",
"tempfile",
"thiserror",
"zeroize",
"bitflags",
"crossterm_winapi",
"libc",
"mio",
"parking_lot",
"signal-hook",
"signal-hook-mio",
"winapi",
]
[[package]]
name = "crossterm_winapi"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
dependencies = [
"winapi",
]
[[package]]
@@ -118,10 +151,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "encode_unicode"
version = "1.0.0"
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
@@ -134,23 +167,28 @@ dependencies = [
]
[[package]]
name = "fastrand"
version = "2.3.0"
name = "foldhash"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "getrandom"
version = "0.3.3"
name = "hashbrown"
version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasi",
"allocator-api2",
"equivalent",
"foldhash",
]
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "home"
version = "0.5.11"
@@ -184,6 +222,30 @@ dependencies = [
"cc",
]
[[package]]
name = "itertools"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "js-sys"
version = "0.3.77"
@@ -207,10 +269,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
[[package]]
name = "linux-raw-sys"
version = "0.9.4"
name = "lock_api"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
@@ -218,20 +284,41 @@ version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "lru"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
dependencies = [
"hashbrown",
]
[[package]]
name = "memchr"
version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "mio"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys 0.48.0",
]
[[package]]
name = "monitor-tui"
version = "0.1.0"
dependencies = [
"anyhow",
"chrono",
"console",
"dialoguer",
"crossterm",
"ratatui",
"regex",
"which",
]
@@ -251,6 +338,35 @@ version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "parking_lot"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"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 = "proc-macro2"
version = "1.0.96"
@@ -270,10 +386,33 @@ dependencies = [
]
[[package]]
name = "r-efi"
version = "5.3.0"
name = "ratatui"
version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
checksum = "f44c9e68fd46eda15c646fbb85e1040b657a58cdc8c98db1d97a55930d991eef"
dependencies = [
"bitflags",
"cassowary",
"compact_str",
"crossterm",
"itertools 0.12.1",
"lru",
"paste",
"stability",
"strum",
"unicode-segmentation",
"unicode-truncate",
"unicode-width",
]
[[package]]
name = "redox_syscall"
version = "0.5.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
dependencies = [
"bitflags",
]
[[package]]
name = "regex"
@@ -313,23 +452,10 @@ dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys 0.4.15",
"linux-raw-sys",
"windows-sys 0.59.0",
]
[[package]]
name = "rustix"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys 0.9.4",
"windows-sys 0.60.2",
]
[[package]]
name = "rustversion"
version = "1.0.22"
@@ -337,10 +463,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "shell-words"
version = "1.1.0"
name = "ryu"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "shlex"
@@ -348,6 +480,80 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-mio"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
dependencies = [
"libc",
"mio",
"signal-hook",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
dependencies = [
"libc",
]
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "stability"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strum"
version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn",
]
[[package]]
name = "syn"
version = "2.0.104"
@@ -359,39 +565,6 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "tempfile"
version = "3.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
dependencies = [
"fastrand",
"getrandom",
"once_cell",
"rustix 1.0.8",
"windows-sys 0.59.0",
]
[[package]]
name = "thiserror"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
@@ -399,19 +572,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "unicode-width"
version = "0.2.1"
name = "unicode-segmentation"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unicode-truncate"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf"
dependencies = [
"itertools 0.13.0",
"unicode-segmentation",
"unicode-width",
]
[[package]]
name = "unicode-width"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "wasi"
version = "0.14.2+wasi-0.2.4"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
dependencies = [
"wit-bindgen-rt",
]
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasm-bindgen"
@@ -479,10 +666,32 @@ checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f"
dependencies = [
"either",
"home",
"rustix 0.38.44",
"rustix",
"winsafe",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-core"
version = "0.61.2"
@@ -542,6 +751,15 @@ dependencies = [
"windows-link",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
@@ -560,6 +778,21 @@ dependencies = [
"windows-targets 0.53.3",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
@@ -593,6 +826,12 @@ dependencies = [
"windows_x86_64_msvc 0.53.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
@@ -605,6 +844,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
@@ -617,6 +862,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
@@ -641,6 +892,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
@@ -653,6 +910,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
@@ -665,6 +928,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
@@ -677,6 +946,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
@@ -694,18 +969,3 @@ name = "winsafe"
version = "0.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
[[package]]
name = "wit-bindgen-rt"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
dependencies = [
"bitflags",
]
[[package]]
name = "zeroize"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"

View File

@@ -8,5 +8,5 @@ regex = "1"
which = "6"
anyhow = "1"
chrono = { version = "0.4", features = ["clock"] }
dialoguer = "0.11"
console = "0.15"
ratatui = "0.26"
crossterm = "0.27"

View File

@@ -1,68 +1,328 @@
use anyhow::Result;
use console::style;
use dialoguer::{theme::ColorfulTheme, Input, MultiSelect, Select};
use std::io;
use crossterm::{
event::{self, Event, KeyCode, KeyEvent, KeyModifiers},
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use ratatui::{
backend::CrosstermBackend,
layout::{Alignment, Constraint, Direction, Layout, Rect},
style::{Modifier, Style},
text::{Line, Span, Text},
widgets::{Block, Borders, Clear, List, ListItem, Padding, Paragraph, Wrap},
Terminal,
};
use std::io::{self, stdout};
const APP_NAME: &str = "GNOME Monitor TUI";
fn theme() -> ColorfulTheme {
let mut t = ColorfulTheme::default();
// Slightly more vivid selection and success colors for a modern feel
t.values_style = t.values_style.bold();
t.active_item_style = t.active_item_style.bold();
// Customize prefixes for a cleaner, modern aesthetic
t.prompt_prefix = style("".to_string());
t.success_prefix = style("".to_string());
t.error_prefix = style("".to_string());
t.active_item_prefix = style("".to_string());
t.inactive_item_prefix = style(" ".to_string());
t.checked_item_prefix = style("".to_string());
t.unchecked_item_prefix = style("".to_string());
t.picked_item_prefix = style("".to_string());
t.unpicked_item_prefix = style(" ".to_string());
t
fn with_terminal<F, T>(mut f: F) -> Result<T>
where
F: FnMut(&mut Terminal<CrosstermBackend<io::Stdout>>) -> Result<T>,
{
enable_raw_mode()?;
let mut out = stdout();
execute!(out, EnterAlternateScreen)?;
let backend = CrosstermBackend::new(out);
let mut terminal = Terminal::new(backend)?;
terminal.clear()?;
let res = f(&mut terminal);
disable_raw_mode()?;
// It's okay if leaving alternate screen fails after rendering; try best-effort
let _ = execute!(terminal.backend_mut(), LeaveAlternateScreen);
let _ = terminal.show_cursor();
res
}
fn center_rect(percent_x: u16, percent_y: u16, area: Rect) -> Rect {
let popup_layout = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Percentage((100 - percent_y) / 2),
Constraint::Percentage(percent_y),
Constraint::Percentage((100 - percent_y) / 2),
])
.split(area);
let vertical = Layout::default()
.direction(Direction::Horizontal)
.constraints([
Constraint::Percentage((100 - percent_x) / 2),
Constraint::Percentage(percent_x),
Constraint::Percentage((100 - percent_x) / 2),
])
.split(popup_layout[1]);
vertical[1]
}
pub fn msgbox(text: &str) {
let bar = "".repeat(64);
println!("\n{}\n{:<62}\n{}\n", bar, APP_NAME, bar);
println!("{}\n", text);
let _ = prompt_enter();
let _ = with_terminal(|t| {
loop {
t.draw(|f| {
let area = center_rect(80, 50, f.size());
let block = Block::default()
.title(APP_NAME)
.borders(Borders::ALL)
.padding(Padding::uniform(1));
let content = Paragraph::new(Text::from(text.to_string()))
.block(block)
.wrap(Wrap { trim: true })
.alignment(Alignment::Left);
let hint = Paragraph::new(Line::from(vec![
Span::raw("Press "),
Span::styled("Enter", Style::default().add_modifier(Modifier::BOLD)),
Span::raw(" to continue"),
]))
.alignment(Alignment::Center);
f.render_widget(Clear, area);
f.render_widget(content, area);
let hint_area = Rect {
x: area.x,
y: area.y + area.height.saturating_sub(2),
width: area.width,
height: 1,
};
f.render_widget(hint, hint_area);
})?;
if let Event::Key(KeyEvent { code, .. }) = event::read()? {
match code {
KeyCode::Enter | KeyCode::Esc => break,
_ => {}
}
}
}
Ok(())
});
}
pub fn inputbox(prompt: &str, default: &str) -> Result<String> {
Ok(Input::with_theme(&theme())
.with_prompt(prompt)
.default(default.to_string())
.interact_text()?)
let mut value = default.to_string();
with_terminal(|t| {
loop {
t.draw(|f| {
let area = center_rect(80, 40, f.size());
let block = Block::default()
.title(APP_NAME)
.borders(Borders::ALL)
.padding(Padding::uniform(1));
let mut lines = Vec::new();
lines.push(Line::from(Span::styled(
prompt,
Style::default().add_modifier(Modifier::BOLD),
)));
lines.push(Line::from(""));
lines.push(Line::from(value.clone()));
lines.push(Line::from(""));
lines.push(Line::from("Enter to accept, Esc to cancel"));
let content = Paragraph::new(Text::from(lines))
.block(block)
.wrap(Wrap { trim: false })
.alignment(Alignment::Left);
f.render_widget(Clear, area);
f.render_widget(content, area);
// place cursor at input line end
let cursor_x = area.x + value.len() as u16;
let cursor_y = area.y + 2; // third line
f.set_cursor(
cursor_x.min(area.x + area.width.saturating_sub(2)),
cursor_y,
);
})?;
match event::read()? {
Event::Key(KeyEvent {
code, modifiers, ..
}) => match code {
KeyCode::Enter => break,
KeyCode::Esc => {
value = default.to_string();
break;
}
KeyCode::Backspace => {
value.pop();
}
KeyCode::Char('u') if modifiers.contains(KeyModifiers::CONTROL) => {
value.clear();
}
KeyCode::Char(c) => value.push(c),
_ => {}
},
_ => {}
}
}
Ok(value.clone())
})
}
pub fn menu(prompt: &str, options: &[(String, String)]) -> Result<Option<String>> {
let items: Vec<String> = options.iter().map(|(_, d)| d.clone()).collect();
let idx = Select::with_theme(&theme())
.with_prompt(prompt)
.items(&items)
.default(0)
.interact_opt()?;
Ok(idx.map(|i| options[i].0.clone()))
if options.is_empty() {
return Ok(None);
}
let mut selected: usize = 0;
with_terminal(|t| {
loop {
t.draw(|f| {
let area = center_rect(80, 70, f.size());
let block = Block::default()
.title(APP_NAME)
.borders(Borders::ALL)
.padding(Padding::uniform(1));
let mut text = Vec::new();
text.push(Line::from(Span::styled(
prompt,
Style::default().add_modifier(Modifier::BOLD),
)));
text.push(Line::from(""));
let items: Vec<ListItem> = options
.iter()
.enumerate()
.map(|(i, (_, d))| {
let prefix = if i == selected { "" } else { " " };
ListItem::new(format!("{}{}", prefix, d))
})
.collect();
let list = List::new(items)
.block(block)
.highlight_symbol("")
.highlight_style(Style::default().add_modifier(Modifier::BOLD));
f.render_widget(Clear, area);
// Render prompt at top area
let top = Rect {
x: area.x,
y: area.y,
width: area.width,
height: 2,
};
let prompt_para = Paragraph::new(Text::from(text)).alignment(Alignment::Left);
f.render_widget(prompt_para, top);
// Render list below
let list_area = Rect {
x: area.x,
y: area.y + 2,
width: area.width,
height: area.height.saturating_sub(2),
};
f.render_widget(list, list_area);
})?;
if let Event::Key(KeyEvent { code, .. }) = event::read()? {
match code {
KeyCode::Up => {
if selected > 0 {
selected -= 1;
}
}
KeyCode::Down => {
if selected + 1 < options.len() {
selected += 1;
}
}
KeyCode::Enter => return Ok(Some(options[selected].0.clone())),
KeyCode::Esc => return Ok(None),
_ => {}
}
}
}
})
}
pub fn checklist(prompt: &str, items: &[(String, String, bool)]) -> Result<Vec<String>> {
let labels: Vec<String> = items
.iter()
.map(|(k, d, _)| format!("{} {}", k, d))
.collect();
let defaults: Vec<bool> = items.iter().map(|(_, _, on)| *on).collect();
let chosen = MultiSelect::with_theme(&theme())
.with_prompt(prompt)
.items(&labels)
.defaults(&defaults)
.interact()?;
Ok(chosen.into_iter().map(|i| items[i].0.clone()).collect())
}
if items.is_empty() {
return Ok(vec![]);
}
let mut active: usize = 0;
let mut checked: Vec<bool> = items.iter().map(|(_, _, on)| *on).collect();
pub fn prompt_enter() -> Result<()> {
let mut s = String::new();
io::stdin().read_line(&mut s)?;
Ok(())
with_terminal(|t| loop {
t.draw(|f| {
let area = center_rect(80, 80, f.size());
let block = Block::default()
.title(APP_NAME)
.borders(Borders::ALL)
.padding(Padding::uniform(1));
let prompt_para = Paragraph::new(Text::from(vec![
Line::from(Span::styled(
prompt,
Style::default().add_modifier(Modifier::BOLD),
)),
Line::from(""),
Line::from("Use ↑/↓ to move, Space to toggle, Enter to confirm, Esc to cancel"),
]))
.alignment(Alignment::Left);
let list_items: Vec<ListItem> = items
.iter()
.enumerate()
.map(|(i, (k, d, _))| {
let mark = if checked[i] { "[x]" } else { "[ ]" };
let cursor = if i == active { "" } else { " " };
ListItem::new(format!("{} {} {} {}", cursor, mark, k, d))
})
.collect();
let list = List::new(list_items)
.block(block)
.highlight_symbol("")
.highlight_style(Style::default().add_modifier(Modifier::BOLD));
f.render_widget(Clear, area);
let top = Rect {
x: area.x,
y: area.y,
width: area.width,
height: 3,
};
f.render_widget(prompt_para, top);
let list_area = Rect {
x: area.x,
y: area.y + 3,
width: area.width,
height: area.height.saturating_sub(3),
};
f.render_widget(list, list_area);
})?;
if let Event::Key(KeyEvent { code, .. }) = event::read()? {
match code {
KeyCode::Up => {
if active > 0 {
active -= 1;
}
}
KeyCode::Down => {
if active + 1 < items.len() {
active += 1;
}
}
KeyCode::Char(' ') => {
checked[active] = !checked[active];
}
KeyCode::Enter => {
let out: Vec<String> = items
.iter()
.enumerate()
.filter_map(
|(i, (k, _, _))| if checked[i] { Some(k.clone()) } else { None },
)
.collect();
return Ok(out);
}
KeyCode::Esc => return Ok(vec![]),
_ => {}
}
}
})
}