From 2bb15f7cf2b0db8e09de6cb759c723d4880fda03 Mon Sep 17 00:00:00 2001 From: Dheepak Krishnamurthy Date: Sun, 3 Sep 2023 06:54:37 -0400 Subject: [PATCH] =?UTF-8?q?feat:=20Use=20color=5Feyre=20instead=20of=20any?= =?UTF-8?q?how=20=E2=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 976 +++++++++++++++++++++++-------- Cargo.toml | 38 +- build.rs | 54 ++ completions/_taskwarrior-tui | 4 +- completions/_taskwarrior-tui.ps1 | 4 +- completions/taskwarrior-tui.fish | 2 +- src/app.rs | 16 +- src/cli.rs | 2 +- src/config.rs | 8 +- src/history.rs | 12 +- src/keyconfig.rs | 2 +- src/main.rs | 166 ++---- src/pane/context.rs | 2 +- src/pane/mod.rs | 2 +- src/pane/project.rs | 2 +- src/task_report.rs | 4 +- src/tui.rs | 150 +++++ src/utils.rs | 148 +++++ 18 files changed, 1180 insertions(+), 412 deletions(-) create mode 100644 src/tui.rs diff --git a/Cargo.lock b/Cargo.lock index 8981dc3..8b1f1a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,10 +18,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] -name = "aho-corasick" -version = "1.0.4" +name = "ahash" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" dependencies = [ "memchr", ] @@ -76,7 +87,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -86,20 +97,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] -name = "anyhow" -version = "1.0.75" +name = "async-trait" +version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" - -[[package]] -name = "arc-swap" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", +] [[package]] name = "autocfg" @@ -123,14 +133,10 @@ dependencies = [ ] [[package]] -name = "better-panic" -version = "0.3.0" +name = "base64" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fa9e1d11a268684cbd90ed36370d7577afb6c62d912ddff5c15fc34343e5036" -dependencies = [ - "backtrace", - "console", -] +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "bitflags" @@ -143,6 +149,18 @@ name = "bitflags" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +dependencies = [ + "serde", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] [[package]] name = "bumpalo" @@ -150,6 +168,12 @@ version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + [[package]] name = "bytes" version = "1.4.0" @@ -179,9 +203,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "95ed24df0632f708f5f6d8082675bef2596f7084dee3dd55f632290bf35bfe0f" dependencies = [ "android-tzdata", "iana-time-zone", @@ -189,30 +213,32 @@ dependencies = [ "num-traits", "time", "wasm-bindgen", - "winapi", + "windows-targets", ] [[package]] name = "clap" -version = "4.4.1" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c8d502cbaec4595d2e7d5f61e318f05417bd2b66fdc3809498f0d3fdf0bea27" +checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6" dependencies = [ "clap_builder", "clap_derive", - "once_cell", ] [[package]] name = "clap_builder" -version = "4.4.1" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5891c7bc0edb3e1c2204fc5e94009affabeb1821c9e5fdc3959536c5c0bb984d" +checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08" dependencies = [ "anstream", "anstyle", "clap_lex", "strsim", + "terminal_size", + "unicase", + "unicode-width", ] [[package]] @@ -226,9 +252,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.0" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9fd1a5729c4548118d7d70ff234a44868d00489a4b6597b0b020918a0e91a1a" +checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" dependencies = [ "heck", "proc-macro2", @@ -253,6 +279,33 @@ dependencies = [ "winapi", ] +[[package]] +name = "color-eyre" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + [[package]] name = "colorchoice" version = "1.0.0" @@ -260,15 +313,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] -name = "console" -version = "0.15.7" +name = "config" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +checksum = "d379af7f68bfc21714c6c7dea883544201741d2ce8274bb12fa54f89507f52a7" dependencies = [ - "encode_unicode", + "async-trait", + "json5", "lazy_static", - "libc", - "windows-sys 0.45.0", + "nom", + "pathdiff", + "ron", + "rust-ini", + "serde", + "serde_json", + "toml 0.5.11", + "yaml-rust", ] [[package]] @@ -277,6 +337,15 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + [[package]] name = "crossterm" version = "0.27.0" @@ -289,6 +358,7 @@ dependencies = [ "libc", "mio", "parking_lot", + "serde", "signal-hook", "signal-hook-mio", "winapi", @@ -303,6 +373,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "darling" version = "0.14.4" @@ -338,17 +418,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "derive_builder" version = "0.12.0" @@ -381,10 +450,29 @@ dependencies = [ ] [[package]] -name = "destructure_traitobject" -version = "0.2.0" +name = "diff" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c877555693c14d2f84191cfd3ad8582790fc52b5e2274b40b59cf5f5cea25c7" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "directories" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" +dependencies = [ + "dirs-sys", +] [[package]] name = "dirs" @@ -404,27 +492,33 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.48.0", + "windows-sys", ] +[[package]] +name = "dlv-list" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" + [[package]] name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" -[[package]] -name = "encode_unicode" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" - [[package]] name = "endian-type" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.3.2" @@ -433,7 +527,7 @@ checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -456,6 +550,16 @@ dependencies = [ "str-buf", ] +[[package]] +name = "eyre" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "fd-lock" version = "3.0.13" @@ -463,8 +567,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" dependencies = [ "cfg-if", - "rustix", - "windows-sys 0.48.0", + "rustix 0.38.8", + "windows-sys", ] [[package]] @@ -562,6 +666,25 @@ dependencies = [ "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.10" @@ -584,6 +707,15 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" [[package]] name = "heck" @@ -603,14 +735,24 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys", ] [[package]] -name = "humantime" -version = "2.1.0" +name = "human-panic" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "eb2df2fb4e13fa697d21d93061ebcbbd876f5ef643b48ff59cfab57a726ef140" +dependencies = [ + "anstream", + "anstyle", + "backtrace", + "os_info", + "serde", + "serde_derive", + "toml 0.7.6", + "uuid", +] [[package]] name = "iana-time-zone" @@ -642,13 +784,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] -name = "indexmap" -version = "1.9.3" +name = "indenter" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ - "autocfg", - "hashbrown", + "equivalent", + "hashbrown 0.14.0", ] [[package]] @@ -657,6 +805,17 @@ version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c785eefb63ebd0e33416dfcb8d6da0bf27ce752843a45632a67bf10d4d4b5c4" +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys", +] + [[package]] name = "itertools" version = "0.11.0" @@ -681,6 +840,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -699,6 +869,12 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + [[package]] name = "linux-raw-sys" version = "0.4.5" @@ -720,47 +896,21 @@ name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" -dependencies = [ - "serde", -] [[package]] -name = "log-mdc" +name = "matchers" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7" - -[[package]] -name = "log4rs" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d36ca1786d9e79b8193a68d480a0907b612f109537115c6ff655a3a1967533fd" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "anyhow", - "arc-swap", - "chrono", - "derivative", - "fnv", - "humantime", - "libc", - "log", - "log-mdc", - "parking_lot", - "serde", - "serde-value", - "serde_json", - "serde_yaml", - "thiserror", - "thread-id", - "typemap-ors", - "winapi", + "regex-automata 0.1.10", ] [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "minimal-lexical" @@ -786,7 +936,7 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -820,6 +970,16 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-traits" version = "0.2.16" @@ -839,6 +999,12 @@ dependencies = [ "libc", ] +[[package]] +name = "numtoa" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" + [[package]] name = "object" version = "0.32.0" @@ -861,14 +1027,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] -name = "ordered-float" -version = "2.10.0" +name = "ordered-multimap" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" +checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" dependencies = [ - "num-traits", + "dlv-list", + "hashbrown 0.12.3", ] +[[package]] +name = "os_info" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "006e42d5b888366f1880eda20371fedde764ed2213dc8496f49622fa0c99cd5e" +dependencies = [ + "log", + "serde", + "winapi", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + [[package]] name = "parking_lot" version = "0.12.1" @@ -889,7 +1079,7 @@ dependencies = [ "libc", "redox_syscall 0.3.5", "smallvec", - "windows-targets 0.48.5", + "windows-targets", ] [[package]] @@ -904,6 +1094,57 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef" +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + +[[package]] +name = "pest" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a4d085fd991ac8d5b05a147b437791b4260b76326baf0fc60cf7c9c27ecd33" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bee7be22ce7918f641a33f08e3f43388c7656772244e2bbb2477f44cc9021a" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1511785c5e98d79a05e8a6bc34b4ac2168a0e3e92161862030ad84daa223141" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.29", +] + +[[package]] +name = "pest_meta" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42f0394d3123e33353ca5e1e89092e533d2cc490389f2bd6131c43c634ebc5f" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "pin-project-lite" version = "0.2.12" @@ -922,6 +1163,16 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "pretty_assertions" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "proc-macro2" version = "1.0.66" @@ -980,6 +1231,20 @@ dependencies = [ "getrandom", ] +[[package]] +name = "ratatui" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8285baa38bdc9f879d92c0e37cb562ef38aa3aeefca22b3200186bc39242d3d5" +dependencies = [ + "bitflags 2.4.0", + "cassowary", + "indoc", + "paste", + "unicode-segmentation", + "unicode-width", +] + [[package]] name = "ratatui" version = "0.23.0" @@ -1015,6 +1280,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_termios" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f" +dependencies = [ + "redox_syscall 0.2.16", +] + [[package]] name = "redox_users" version = "0.4.3" @@ -1028,39 +1302,89 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" +checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.3.8", + "regex-syntax 0.7.5", ] [[package]] name = "regex-automata" -version = "0.3.7" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.7.5", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +[[package]] +name = "ron" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a" +dependencies = [ + "base64", + "bitflags 1.3.2", + "serde", +] + +[[package]] +name = "rust-ini" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df" +dependencies = [ + "cfg-if", + "ordered-multimap", +] + [[package]] name = "rustc-demangle" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustix" +version = "0.37.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys", +] + [[package]] name = "rustix" version = "0.38.8" @@ -1070,8 +1394,8 @@ dependencies = [ "bitflags 2.4.0", "errno", "libc", - "linux-raw-sys", - "windows-sys 0.48.0", + "linux-raw-sys 0.4.5", + "windows-sys", ] [[package]] @@ -1136,16 +1460,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-value" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" -dependencies = [ - "ordered-float", - "serde", -] - [[package]] name = "serde_derive" version = "1.0.188" @@ -1169,15 +1483,32 @@ dependencies = [ ] [[package]] -name = "serde_yaml" -version = "0.8.26" +name = "serde_spanned" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" dependencies = [ - "indexmap", - "ryu", "serde", - "yaml-rust", +] + +[[package]] +name = "sha2" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", ] [[package]] @@ -1247,7 +1578,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1262,6 +1593,15 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" +[[package]] +name = "strip-ansi-escapes" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ff8ef943b384c414f54aefa961dd2bd853add74ec75e7ac74cf91dba62bcfa" +dependencies = [ + "vte", +] + [[package]] name = "strsim" version = "0.10.0" @@ -1331,31 +1671,40 @@ dependencies = [ name = "taskwarrior-tui" version = "0.25.4" dependencies = [ - "anyhow", - "better-panic", "cassowary", "chrono", "clap", "clap_complete", + "color-eyre", + "config", "crossterm", - "dirs", + "directories", "futures", + "human-panic", "itertools", "lazy_static", + "libc", "log", - "log4rs", "path-clean", + "pretty_assertions", "rand", - "ratatui", + "ratatui 0.23.0", "regex", "rustyline", "serde", + "serde_derive", "serde_json", "shellexpand", "shlex", + "signal-hook", + "strip-ansi-escapes", "task-hookrs", "tokio", - "tokio-stream", + "tokio-util", + "tracing", + "tracing-error", + "tracing-subscriber", + "tui-logger", "unicode-segmentation", "unicode-truncate", "unicode-width", @@ -1363,6 +1712,28 @@ dependencies = [ "versions", ] +[[package]] +name = "terminal_size" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" +dependencies = [ + "rustix 0.37.23", + "windows-sys", +] + +[[package]] +name = "termion" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e" +dependencies = [ + "libc", + "numtoa", + "redox_syscall 0.2.16", + "redox_termios", +] + [[package]] name = "thiserror" version = "1.0.47" @@ -1384,14 +1755,13 @@ dependencies = [ ] [[package]] -name = "thread-id" -version = "4.2.0" +name = "thread_local" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79474f573561cdc4871a0de34a51c92f7f5a56039113fbb5b9c9f96bdb756669" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ - "libc", - "redox_syscall 0.2.16", - "winapi", + "cfg-if", + "once_cell", ] [[package]] @@ -1421,7 +1791,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1436,23 +1806,183 @@ dependencies = [ ] [[package]] -name = "tokio-stream" -version = "0.1.14" +name = "tokio-util" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ + "bytes", "futures-core", + "futures-sink", "pin-project-lite", "tokio", ] [[package]] -name = "typemap-ors" -version = "1.0.0" +name = "toml" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68c24b707f02dd18f1e4ccceb9d49f2058c2fb86384ef9972592904d7a28867" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "unsafe-any-ors", + "serde", +] + +[[package]] +name = "toml" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", +] + +[[package]] +name = "tracing-core" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "tui" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1" +dependencies = [ + "bitflags 1.3.2", + "cassowary", + "termion", + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "tui-logger" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9b303440de7c259d03e113a808f2f8ca3cd9097840663dc484b12f19c6f44a6" +dependencies = [ + "chrono", + "fxhash", + "lazy_static", + "log", + "parking_lot", + "ratatui 0.22.0", + "termion", + "tracing", + "tracing-subscriber", + "tui", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", ] [[package]] @@ -1482,15 +2012,6 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" -[[package]] -name = "unsafe-any-ors" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a303d30665362d9680d7d91d78b23f5f899504d4f08b3c4cf08d055d87c0ad" -dependencies = [ - "destructure_traitobject", -] - [[package]] name = "utf8parse" version = "0.2.1" @@ -1507,6 +2028,18 @@ dependencies = [ "serde", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "versions" version = "5.0.1" @@ -1517,6 +2050,26 @@ dependencies = [ "nom", ] +[[package]] +name = "vte" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197" +dependencies = [ + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" @@ -1611,16 +2164,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", + "windows-targets", ] [[package]] @@ -1629,22 +2173,7 @@ 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-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets", ] [[package]] @@ -1653,99 +2182,66 @@ 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", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - [[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_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - [[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_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - [[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_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - [[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_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "winnow" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" +dependencies = [ + "memchr", +] + [[package]] name = "yaml-rust" version = "0.4.5" @@ -1754,3 +2250,9 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/Cargo.toml b/Cargo.toml index d4ef53b..317924b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,38 +7,45 @@ repository = "https://github.com/kdheepak/taskwarrior-tui/" homepage = "https://kdheepak.com/taskwarrior-tui" readme = "README.md" authors = ["Dheepak Krishnamurthy "] -edition = "2018" +edition = "2021" keywords = ["taskwarrior", "tui"] categories = ["command-line-utilities"] [dependencies] -anyhow = "1.0.75" -better-panic = "0.3.0" cassowary = "0.3.0" -chrono = "0.4.26" -clap = { version = "4.4.1", features = ["derive"] } -crossterm = { version = "0.27.0", features = [ - "event-stream", -] } -dirs = "5.0.1" +chrono = "0.4.28" +clap = { version = "4.4.2", features = ["std", "color", "help", "usage", "error-context", "suggestions", "derive", "cargo", "wrap_help", "unicode", "string", "unstable-styles"] } +color-eyre = "0.6.2" +config = "0.13.3" +crossterm = { version = "0.27.0", features = ["event-stream", "serde"] } +directories = "5.0.1" futures = "0.3.28" +human-panic = "1.2.0" itertools = "0.11.0" lazy_static = "1.4.0" +libc = "0.2.147" log = "0.4.20" -log4rs = "1.2.0" path-clean = "1.0.1" +pretty_assertions = "1.4.0" rand = "0.8.5" -regex = "1.9.4" +ratatui = "0.23.0" +regex = "1.9.5" rustyline = { version = "12.0.0", features = ["with-file-history", "derive"] } serde = { version = "1.0.188", features = ["derive"] } +serde_derive = "1.0.188" serde_json = "1.0.105" shellexpand = "3.1.0" shlex = "1.1.0" +signal-hook = "0.3.17" +strip-ansi-escapes = "0.2.0" task-hookrs = "0.9.0" tokio = { version = "1.32.0", features = ["full"] } -tokio-stream = "0.1.14" -ratatui = "0.23.0" +tokio-util = "0.7.8" +tracing = "0.1.37" +tracing-error = "0.2.0" +tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } +tui-logger = { version = "0.9.5", features = ["ratatui-support", "tracing-support"] } unicode-segmentation = "1.10.1" unicode-truncate = "0.2.0" unicode-width = "0.1.10" @@ -55,11 +62,10 @@ buildflags = ["--release"] taskwarrior-tui = { path = "/usr/bin/taskwarrior-tui" } [profile.release] -debug = 1 incremental = true -lto = "off" +lto = true [build-dependencies] -clap = { version = "4.4.1", features = ["derive"] } +clap = { version = "4.4.2", features = ["derive"] } clap_complete = "4.4.0" shlex = "1.1.0" diff --git a/build.rs b/build.rs index 1031588..fdba145 100644 --- a/build.rs +++ b/build.rs @@ -18,7 +18,61 @@ fn run_pandoc() -> Result { cmd.output() } +fn get_commit_hash() { + let git_output = std::process::Command::new("git").args(["rev-parse", "--git-dir"]).output().ok(); + let git_dir = git_output.as_ref().and_then(|output| { + std::str::from_utf8(&output.stdout) + .ok() + .and_then(|s| s.strip_suffix('\n').or_else(|| s.strip_suffix("\r\n"))) + }); + + // Tell cargo to rebuild if the head or any relevant refs change. + if let Some(git_dir) = git_dir { + let git_path = std::path::Path::new(git_dir); + let refs_path = git_path.join("refs"); + if git_path.join("HEAD").exists() { + println!("cargo:rerun-if-changed={}/HEAD", git_dir); + } + if git_path.join("packed-refs").exists() { + println!("cargo:rerun-if-changed={}/packed-refs", git_dir); + } + if refs_path.join("heads").exists() { + println!("cargo:rerun-if-changed={}/refs/heads", git_dir); + } + if refs_path.join("tags").exists() { + println!("cargo:rerun-if-changed={}/refs/tags", git_dir); + } + } + + let git_output = std::process::Command::new("git") + .args(["describe", "--always", "--tags", "--long", "--dirty"]) + .output() + .ok(); + let git_info = git_output + .as_ref() + .and_then(|output| std::str::from_utf8(&output.stdout).ok().map(str::trim)); + let cargo_pkg_version = env!("CARGO_PKG_VERSION"); + + // Default git_describe to cargo_pkg_version + let mut git_describe = String::from(cargo_pkg_version); + + if let Some(git_info) = git_info { + // If the `git_info` contains `CARGO_PKG_VERSION`, we simply use `git_info` as it is. + // Otherwise, prepend `CARGO_PKG_VERSION` to `git_info`. + if git_info.contains(cargo_pkg_version) { + // Remove the 'g' before the commit sha + let git_info = &git_info.replace('g', ""); + git_describe = git_info.to_string(); + } else { + git_describe = format!("v{}-{}", cargo_pkg_version, git_info); + } + } + + println!("cargo:rustc-env=TASKWARRIOR_TUI_GIT_INFO={}", git_describe); +} + fn main() { + get_commit_hash(); let mut app = generate_cli_app(); let name = app.get_name().to_string(); let outdir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("completions/"); diff --git a/completions/_taskwarrior-tui b/completions/_taskwarrior-tui index b8bd2fa..d93eeed 100644 --- a/completions/_taskwarrior-tui +++ b/completions/_taskwarrior-tui @@ -17,8 +17,8 @@ _taskwarrior-tui() { _arguments "${_arguments_options[@]}" \ '-d+[Sets the data folder for taskwarrior-tui]:FOLDER: ' \ '--data=[Sets the data folder for taskwarrior-tui]:FOLDER: ' \ -'-c+[Sets the config folder for taskwarrior-tui (currently not used)]:FOLDER: ' \ -'--config=[Sets the config folder for taskwarrior-tui (currently not used)]:FOLDER: ' \ +'-c+[Sets the config folder for taskwarrior-tui]:FOLDER: ' \ +'--config=[Sets the config folder for taskwarrior-tui]:FOLDER: ' \ '--taskdata=[Sets the .task folder using the TASKDATA environment variable for taskwarrior]:FOLDER: ' \ '--taskrc=[Sets the .taskrc file using the TASKRC environment variable for taskwarrior]:FILE: ' \ '-r+[Sets default report]:STRING: ' \ diff --git a/completions/_taskwarrior-tui.ps1 b/completions/_taskwarrior-tui.ps1 index c80f193..f130596 100644 --- a/completions/_taskwarrior-tui.ps1 +++ b/completions/_taskwarrior-tui.ps1 @@ -23,8 +23,8 @@ Register-ArgumentCompleter -Native -CommandName 'taskwarrior-tui' -ScriptBlock { 'taskwarrior-tui' { [CompletionResult]::new('-d', 'd', [CompletionResultType]::ParameterName, 'Sets the data folder for taskwarrior-tui') [CompletionResult]::new('--data', 'data', [CompletionResultType]::ParameterName, 'Sets the data folder for taskwarrior-tui') - [CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'Sets the config folder for taskwarrior-tui (currently not used)') - [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'Sets the config folder for taskwarrior-tui (currently not used)') + [CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'Sets the config folder for taskwarrior-tui') + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'Sets the config folder for taskwarrior-tui') [CompletionResult]::new('--taskdata', 'taskdata', [CompletionResultType]::ParameterName, 'Sets the .task folder using the TASKDATA environment variable for taskwarrior') [CompletionResult]::new('--taskrc', 'taskrc', [CompletionResultType]::ParameterName, 'Sets the .taskrc file using the TASKRC environment variable for taskwarrior') [CompletionResult]::new('-r', 'r', [CompletionResultType]::ParameterName, 'Sets default report') diff --git a/completions/taskwarrior-tui.fish b/completions/taskwarrior-tui.fish index 7a1ba99..89e1bde 100644 --- a/completions/taskwarrior-tui.fish +++ b/completions/taskwarrior-tui.fish @@ -1,5 +1,5 @@ complete -c taskwarrior-tui -s d -l data -d 'Sets the data folder for taskwarrior-tui' -r -complete -c taskwarrior-tui -s c -l config -d 'Sets the config folder for taskwarrior-tui (currently not used)' -r +complete -c taskwarrior-tui -s c -l config -d 'Sets the config folder for taskwarrior-tui' -r complete -c taskwarrior-tui -l taskdata -d 'Sets the .task folder using the TASKDATA environment variable for taskwarrior' -r complete -c taskwarrior-tui -l taskrc -d 'Sets the .taskrc file using the TASKRC environment variable for taskwarrior' -r complete -c taskwarrior-tui -s r -l report -d 'Sets default report' -r diff --git a/src/app.rs b/src/app.rs index ba4c979..57a02dc 100644 --- a/src/app.rs +++ b/src/app.rs @@ -5,13 +5,13 @@ use std::{ convert::TryInto, fs, io, io::{Read, Write}, - path::Path, + path::{Path, PathBuf}, sync::{mpsc, Arc, Mutex}, time::{Duration, Instant, SystemTime}, }; -use anyhow::{anyhow, Context as AnyhowContext, Result}; use chrono::{DateTime, Datelike, FixedOffset, Local, NaiveDate, NaiveDateTime, TimeZone, Timelike}; +use color_eyre::eyre::{anyhow, Context as AnyhowContext, Result}; use crossterm::{ event::{DisableMouseCapture, EnableMouseCapture}, execute, @@ -57,7 +57,8 @@ use crate::{ scrollbar::Scrollbar, table::{Row, Table, TableMode, TableState}, task_report::TaskReportTable, - ui, utils, + ui, + utils::{self, get_data_dir}, }; const MAX_LINE: usize = 4096; @@ -177,7 +178,6 @@ pub struct TaskwarriorTui { pub all_tasks: Vec, pub task_details: HashMap, pub marked: HashSet, - // stores index of current task that is highlighted pub current_selection: usize, pub current_selection_uuid: Option, pub current_selection_id: Option, @@ -240,7 +240,7 @@ impl TaskwarriorTui { .output() .context("Unable to run `task --version`")?; - let task_version = Versioning::new(String::from_utf8_lossy(&output.stdout).trim()).context("Unable to get version string")?; + let task_version = Versioning::new(String::from_utf8_lossy(&output.stdout).trim()).ok_or(anyhow!("Unable to get version string"))?; let (w, h) = crossterm::terminal::size().unwrap_or((50, 15)); @@ -251,6 +251,8 @@ impl TaskwarriorTui { }; let event_loop = crate::event::EventLoop::new(tick_rate, init_event_loop); + let data_dir = get_data_dir(); + let mut app = Self { should_quit: false, dirty: true, @@ -280,8 +282,8 @@ impl TaskwarriorTui { keyconfig: kc, terminal_width: w, terminal_height: h, - filter_history: HistoryContext::new("filter.history"), - command_history: HistoryContext::new("command.history"), + filter_history: HistoryContext::new("filter.history", data_dir.clone()), + command_history: HistoryContext::new("command.history", data_dir.clone()), history_status: None, completion_list: CompletionList::with_items(vec![]), show_completion_pane: false, diff --git a/src/cli.rs b/src/cli.rs index 3482ceb..dbf0a92 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -21,7 +21,7 @@ pub fn generate_cli_app() -> clap::Command { .short('c') .long("config") .value_name("FOLDER") - .help("Sets the config folder for taskwarrior-tui (currently not used)") + .help("Sets the config folder for taskwarrior-tui") .action(clap::ArgAction::Set), ) .arg( diff --git a/src/config.rs b/src/config.rs index fa7afa1..26811d1 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, error::Error, str}; -use anyhow::{Context, Result}; +use color_eyre::eyre::{eyre, Context, Result}; use ratatui::{ style::{Color, Modifier, Style}, symbols::{bar::FULL, line::DOUBLE_VERTICAL}, @@ -465,14 +465,14 @@ impl Config { fn get_rule_precedence_color(data: &str) -> Vec { let data = Self::get_config("rule.precedence.color", data) - .context("Unable to parse `task show rule.precedence.color`.") + .ok_or_else(|| eyre!("Unable to parse `task show rule.precedence.color`.")) .unwrap(); data.split(',').map(ToString::to_string).collect::>() } fn get_uda_priority_values(data: &str) -> Vec { let data = Self::get_config("uda.priority.values", data) - .context("Unable to parse `task show uda.priority.values`.") + .ok_or_else(|| eyre!("Unable to parse `task show uda.priority.values`.")) .unwrap(); data.split(',').map(ToString::to_string).collect::>() } @@ -489,7 +489,7 @@ impl Config { fn get_data_location(data: &str) -> String { Self::get_config("data.location", data) - .context("Unable to parse `task show data.location`.") + .ok_or_else(|| eyre!("Unable to parse `task show data.location`.")) .unwrap() } diff --git a/src/history.rs b/src/history.rs index 1b9aa52..01b3cd7 100644 --- a/src/history.rs +++ b/src/history.rs @@ -3,7 +3,7 @@ use std::{ path::{Path, PathBuf}, }; -use anyhow::{anyhow, Result}; +use color_eyre::eyre::{anyhow, Result}; use rustyline::{ error::ReadlineError, history::{DefaultHistory, History, SearchDirection}, @@ -16,17 +16,9 @@ pub struct HistoryContext { } impl HistoryContext { - pub fn new(filename: &str) -> Self { + pub fn new(filename: &str, data_path: PathBuf) -> Self { let history = DefaultHistory::new(); - let data_path = if let Ok(s) = std::env::var("TASKWARRIOR_TUI_DATA") { - PathBuf::from(s) - } else { - dirs::data_local_dir() - .map(|d| d.join("taskwarrior-tui")) - .expect("Unable to create configuration directory for taskwarrior-tui") - }; - std::fs::create_dir_all(&data_path).unwrap_or_else(|_| panic!("Unable to create configuration directory in {:?}", &data_path)); let data_path = data_path.join(filename); diff --git a/src/keyconfig.rs b/src/keyconfig.rs index 8db43af..3bb45d5 100644 --- a/src/keyconfig.rs +++ b/src/keyconfig.rs @@ -1,6 +1,6 @@ use std::{collections::HashSet, error::Error, hash::Hash}; -use anyhow::{anyhow, Result}; +use color_eyre::eyre::{anyhow, Result}; use log::{error, info, warn}; use serde::{Deserialize, Serialize}; diff --git a/src/main.rs b/src/main.rs index f47d328..396234e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,6 +17,7 @@ mod pane; mod scrollbar; mod table; mod task_report; +mod tui; mod ui; mod utils; @@ -29,8 +30,8 @@ use std::{ time::Duration, }; -use anyhow::Result; use app::{Mode, TaskwarriorTui}; +use color_eyre::eyre::Result; use crossterm::{ cursor, event::{DisableMouseCapture, EnableMouseCapture, EventStream}, @@ -39,91 +40,20 @@ use crossterm::{ }; use futures::stream::{FuturesUnordered, StreamExt}; use log::{debug, error, info, log_enabled, trace, warn, Level, LevelFilter}; -use log4rs::{ - append::file::FileAppender, - config::{Appender, Config, Logger, Root}, - encode::pattern::PatternEncoder, -}; -use path_clean::PathClean; use ratatui::{backend::CrosstermBackend, Terminal}; +use utils::{get_config_dir, get_data_dir}; -use crate::{action::Action, event::Event, keyconfig::KeyConfig}; +use crate::{ + action::Action, + event::Event, + keyconfig::KeyConfig, + utils::{initialize_logging, initialize_panic_handler}, +}; const LOG_PATTERN: &str = "{d(%Y-%m-%d %H:%M:%S)} | {l} | {f}:{L} | {m}{n}"; -pub fn destruct_terminal() { - disable_raw_mode().unwrap(); - execute!(io::stdout(), LeaveAlternateScreen, DisableMouseCapture).unwrap(); - execute!(io::stdout(), cursor::Show).unwrap(); -} - -pub fn initialize_logging() { - let data_local_dir = if let Ok(s) = std::env::var("TASKWARRIOR_TUI_DATA") { - PathBuf::from(s) - } else { - dirs::data_local_dir() - .expect("Unable to find data directory for taskwarrior-tui") - .join("taskwarrior-tui") - }; - - 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))) - .append(false) - .build(data_local_dir.join("taskwarrior-tui.log")) - .expect("Failed to build log file appender."); - - let levelfilter = match std::env::var("TASKWARRIOR_TUI_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("taskwarrior_tui", levelfilter)) - .build(Root::builder().appender("logfile").build(LevelFilter::Info)) - .expect("Failed to build logging config."); - - log4rs::init_config(config).expect("Failed to initialize logging."); -} - -pub fn absolute_path(path: impl AsRef) -> io::Result { - let path = path.as_ref(); - - let absolute_path = if path.is_absolute() { - path.to_path_buf() - } else { - env::current_dir()?.join(path) - } - .clean(); - - Ok(absolute_path) -} - -async fn tui_main(report: &str) -> Result<()> { - panic::set_hook(Box::new(|panic_info| { - destruct_terminal(); - better_panic::Settings::auto().create_panic_handler()(panic_info); - })); - - let mut app = app::TaskwarriorTui::new(report, true).await?; - - let mut terminal = app.start_tui()?; - - let r = app.run(&mut terminal).await; - - app.pause_tui().await?; - - r -} - -fn main() -> Result<()> { - better_panic::install(); - +#[tokio::main] +async fn main() -> Result<()> { let matches = cli::generate_cli_app().get_matches(); let config = matches.get_one::("config"); @@ -133,58 +63,42 @@ fn main() -> Result<()> { let binding = String::from("next"); let report = matches.get_one::("report").unwrap_or(&binding); - if let Some(e) = config { - if env::var("TASKWARRIOR_TUI_CONFIG").is_err() { - // if environment variable is not set, this env::var returns an error - env::set_var( - "TASKWARRIOR_TUI_CONFIG", - absolute_path(PathBuf::from(e)).expect("Unable to get path for config"), - ) - } else { - warn!("TASKWARRIOR_TUI_CONFIG environment variable cannot be set.") - } - } + let config_dir = config.map(PathBuf::from).unwrap_or_else(get_config_dir); + let data_dir = data.map(PathBuf::from).unwrap_or_else(get_data_dir); - if let Some(e) = data { - if env::var("TASKWARRIOR_TUI_DATA").is_err() { - // if environment variable is not set, this env::var returns an error - env::set_var( - "TASKWARRIOR_TUI_DATA", - absolute_path(PathBuf::from(e)).expect("Unable to get path for data"), - ) - } else { - warn!("TASKWARRIOR_TUI_DATA environment variable cannot be set.") - } - } + // if let Some(e) = taskrc { + // if env::var("TASKRC").is_err() { + // // if environment variable is not set, this env::var returns an error + // env::set_var("TASKRC", absolute_path(PathBuf::from(e)).expect("Unable to get path for taskrc")) + // } else { + // warn!("TASKRC environment variable cannot be set.") + // } + // } + // + // if let Some(e) = taskdata { + // if env::var("TASKDATA").is_err() { + // // if environment variable is not set, this env::var returns an error + // env::set_var("TASKDATA", absolute_path(PathBuf::from(e)).expect("Unable to get path for taskdata")) + // } else { + // warn!("TASKDATA environment variable cannot be set.") + // } + // } - if let Some(e) = taskrc { - if env::var("TASKRC").is_err() { - // if environment variable is not set, this env::var returns an error - env::set_var("TASKRC", absolute_path(PathBuf::from(e)).expect("Unable to get path for taskrc")) - } else { - warn!("TASKRC environment variable cannot be set.") - } - } - - if let Some(e) = taskdata { - if env::var("TASKDATA").is_err() { - // if environment variable is not set, this env::var returns an error - env::set_var("TASKDATA", absolute_path(PathBuf::from(e)).expect("Unable to get path for taskdata")) - } else { - warn!("TASKDATA environment variable cannot be set.") - } - } - - initialize_logging(); + initialize_logging(data_dir)?; + initialize_panic_handler()?; debug!("getting matches from clap..."); debug!("report = {:?}", &report); debug!("config = {:?}", &config); - let r = tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build()? - .block_on(async { tui_main(report).await }); + let mut app = app::TaskwarriorTui::new(report, true).await?; + + let mut terminal = app.start_tui()?; + + let r = app.run(&mut terminal).await; + + app.pause_tui().await?; + if let Err(err) = r { eprintln!("\x1b[0;31m[taskwarrior-tui error]\x1b[0m: {}\n\nIf you need additional help, please report as a github issue on https://github.com/kdheepak/taskwarrior-tui", err); std::process::exit(1); diff --git a/src/pane/context.rs b/src/pane/context.rs index 07a5daf..3df22b9 100644 --- a/src/pane/context.rs +++ b/src/pane/context.rs @@ -1,6 +1,6 @@ use std::fmt; -use anyhow::{anyhow, Context as AnyhowContext, Result}; +use color_eyre::eyre::{anyhow, Context as AnyhowContext, Result}; const NAME: &str = "Name"; const TYPE: &str = "Remaining"; diff --git a/src/pane/mod.rs b/src/pane/mod.rs index ee1f1b3..afd7b7d 100644 --- a/src/pane/mod.rs +++ b/src/pane/mod.rs @@ -1,6 +1,6 @@ use std::ops::Index; -use anyhow::Result; +use color_eyre::eyre::Result; use crate::{ action::Action, diff --git a/src/pane/project.rs b/src/pane/project.rs index 5e37906..813036a 100644 --- a/src/pane/project.rs +++ b/src/pane/project.rs @@ -1,6 +1,6 @@ use std::fmt; -use anyhow::{anyhow, Context as AnyhowContext, Result}; +use color_eyre::eyre::{anyhow, Context as AnyhowContext, Result}; const COL_WIDTH: usize = 21; const PROJECT_HEADER: &str = "Name"; diff --git a/src/task_report.rs b/src/task_report.rs index 3357295..ec8a48b 100644 --- a/src/task_report.rs +++ b/src/task_report.rs @@ -1,7 +1,7 @@ use std::{error::Error, process::Command}; -use anyhow::Result; use chrono::{DateTime, Datelike, Local, NaiveDate, NaiveDateTime, TimeZone}; +use color_eyre::eyre::Result; use itertools::join; use task_hookrs::{task::Task, uda::UDAValue}; use unicode_truncate::UnicodeTruncateStr; @@ -14,7 +14,7 @@ pub fn format_date_time(dt: NaiveDateTime) -> String { pub fn format_date(dt: NaiveDateTime) -> String { let offset = Local.offset_from_utc_datetime(&dt); - let dt = DateTime::::from_utc(dt, offset); + let dt = DateTime::::from_naive_utc_and_offset(dt, offset); dt.format("%Y-%m-%d").to_string() } diff --git a/src/tui.rs b/src/tui.rs new file mode 100644 index 0000000..1e26303 --- /dev/null +++ b/src/tui.rs @@ -0,0 +1,150 @@ +use std::ops::{Deref, DerefMut}; + +use color_eyre::eyre::Result; +use crossterm::{ + cursor, + event::{Event as CrosstermEvent, KeyEvent, KeyEventKind, MouseEvent}, + terminal::{EnterAlternateScreen, LeaveAlternateScreen}, +}; +use futures::{FutureExt, StreamExt}; +use ratatui::backend::CrosstermBackend as Backend; +use serde_derive::{Deserialize, Serialize}; +use tokio::{ + sync::mpsc::{self, UnboundedReceiver, UnboundedSender}, + task::JoinHandle, +}; +use tokio_util::sync::CancellationToken; + +pub type CrosstermFrame<'a> = ratatui::Frame<'a, Backend>; + +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub enum Event { + Quit, + Error, + Closed, + Tick, + Key(KeyEvent), + Mouse(MouseEvent), + Resize(u16, u16), +} + +pub struct Tui { + pub terminal: ratatui::Terminal>, + pub task: JoinHandle<()>, + pub cancellation_token: CancellationToken, + pub event_rx: UnboundedReceiver, + pub event_tx: UnboundedSender, + pub tick_rate: usize, +} + +impl Tui { + pub fn new(tick_rate: usize) -> Result { + 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, + event_rx, + event_tx, + tick_rate, + }) + } + + pub fn start(&mut self) { + let tick_rate = std::time::Duration::from_millis(self.tick_rate as u64); + self.cancellation_token.cancel(); + 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 interval = tokio::time::interval(tick_rate); + loop { + let delay = interval.tick(); + let crossterm_event = reader.next().fuse(); + 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::Resize(x, y) => { + _event_tx.send(Event::Resize(x, y)).unwrap(); + }, + _ => {}, + } + } + Some(Err(_)) => { + _event_tx.send(Event::Error).unwrap(); + } + None => {}, + } + }, + _ = delay => { + _event_tx.send(Event::Tick).unwrap(); + }, + } + } + }); + } + + pub fn enter(&mut self) -> Result<()> { + crossterm::terminal::enable_raw_mode()?; + crossterm::execute!(std::io::stderr(), EnterAlternateScreen, cursor::Hide)?; + self.start(); + Ok(()) + } + + pub fn exit(&self) -> Result<()> { + crossterm::execute!(std::io::stderr(), LeaveAlternateScreen, cursor::Show)?; + crossterm::terminal::disable_raw_mode()?; + self.cancellation_token.cancel(); + Ok(()) + } + + pub fn suspend(&self) -> Result<()> { + self.exit()?; + #[cfg(not(windows))] + signal_hook::low_level::raise(signal_hook::consts::signal::SIGTSTP)?; + Ok(()) + } + + pub fn resume(&mut self) -> Result<()> { + self.enter()?; + Ok(()) + } + + pub async fn next(&mut self) -> Option { + self.event_rx.recv().await + } +} + +impl Deref for Tui { + type Target = ratatui::Terminal>; + + fn deref(&self) -> &Self::Target { + &self.terminal + } +} + +impl DerefMut for Tui { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.terminal + } +} + +impl Drop for Tui { + fn drop(&mut self) { + self.exit().unwrap(); + } +} diff --git a/src/utils.rs b/src/utils.rs index 57f228a..2ffa161 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -15,3 +15,151 @@ impl ChangeListener for Changeset { fn replace(&mut self, idx: usize, old: &str, new: &str) {} } + +use std::path::PathBuf; + +use color_eyre::eyre::{anyhow, Context, Result}; +use directories::ProjectDirs; +use lazy_static::lazy_static; +use tracing::error; +use tracing_error::ErrorLayer; +use tracing_subscriber::{self, filter::EnvFilter, prelude::__tracing_subscriber_SubscriberExt, util::SubscriberInitExt, Layer}; + +use crate::tui::Tui; + +lazy_static! { + pub static ref CRATE_NAME: String = env!("CARGO_CRATE_NAME").to_uppercase().to_string(); + pub static ref DATA_FOLDER: Option = std::env::var(format!("{}_DATA", CRATE_NAME.clone())).ok().map(PathBuf::from); + pub static ref CONFIG_FOLDER: Option = std::env::var(format!("{}_CONFIG", CRATE_NAME.clone())).ok().map(PathBuf::from); + pub static ref GIT_COMMIT_HASH: String = std::env::var(format!("{}_GIT_INFO", CRATE_NAME.clone())).unwrap_or_else(|_| String::from("Unknown")); + pub static ref LOG_FILE: String = format!("{}.log", CRATE_NAME.to_lowercase()); +} + +fn project_directory() -> Option { + ProjectDirs::from("com", "kdheepak", CRATE_NAME.clone().to_lowercase().as_str()) +} + +pub fn initialize_panic_handler() -> Result<()> { + let (panic_hook, eyre_hook) = color_eyre::config::HookBuilder::default().into_hooks(); + eyre_hook.install()?; + std::panic::set_hook(Box::new(move |panic_info| { + if let Ok(t) = Tui::new(0) { + if let Err(r) = t.exit() { + error!("Unable to exit Terminal: {:?}", r); + } + } + let msg = format!("{}", panic_hook.panic_report(panic_info)); + tracing::error!("{}", strip_ansi_escapes::strip_str(&msg)); + use human_panic::{handle_dump, print_msg, Metadata}; + let meta = Metadata { + version: env!("CARGO_PKG_VERSION").into(), + name: env!("CARGO_PKG_NAME").into(), + authors: env!("CARGO_PKG_AUTHORS").replace(':', ", ").into(), + homepage: env!("CARGO_PKG_HOMEPAGE").into(), + }; + let file_path = handle_dump(&meta, panic_info); + print_msg(file_path, &meta).expect("human-panic: printing error message to console failed"); + eprintln!("{}", msg); + 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(directory: PathBuf) -> Result<()> { + 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 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(EnvFilter::from_default_env()); + + tracing_subscriber::registry() + .with(file_subscriber) + .with(tui_logger::tracing_subscriber_layer()) + .with(ErrorLayer::default()) + .init(); + let default_level = std::env::var("RUST_LOG").map_or(log::LevelFilter::Info, |val| match val.to_lowercase().as_str() { + "off" => log::LevelFilter::Off, + "error" => log::LevelFilter::Error, + "warn" => log::LevelFilter::Warn, + "info" => log::LevelFilter::Info, + "debug" => log::LevelFilter::Debug, + "trace" => log::LevelFilter::Trace, + _ => log::LevelFilter::Info, + }); + tui_logger::set_default_level(default_level); + + 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 commit_hash = GIT_COMMIT_HASH.clone(); + + // 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}" + ) +}