mirror of
https://github.com/kdheepak/taskwarrior-tui.git
synced 2025-08-25 08:47:18 +02:00
Refactor using async-std
This commit is contained in:
parent
6df2aba770
commit
979e886a29
7 changed files with 919 additions and 162 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
@ -41,7 +41,7 @@ jobs:
|
|||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all -- --nocapture
|
||||
args: --all -- --test-threads=1 --nocapture
|
||||
|
||||
fmt:
|
||||
name: Rustfmt
|
||||
|
|
582
Cargo.lock
generated
582
Cargo.lock
generated
|
@ -41,6 +41,152 @@ version = "1.0.40"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b"
|
||||
|
||||
[[package]]
|
||||
name = "async-attributes"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener",
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-executor"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb877970c7b440ead138f6321a3b5395d6061183af779340b65e20c0fede9146"
|
||||
dependencies = [
|
||||
"async-task",
|
||||
"concurrent-queue",
|
||||
"fastrand",
|
||||
"futures-lite",
|
||||
"once_cell",
|
||||
"vec-arena",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-global-executor"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-executor",
|
||||
"async-io",
|
||||
"async-mutex",
|
||||
"blocking",
|
||||
"futures-lite",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-io"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9315f8f07556761c3e48fec2e6b276004acf426e6dc068b2c2251854d65ee0fd"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"fastrand",
|
||||
"futures-lite",
|
||||
"libc",
|
||||
"log",
|
||||
"nb-connect",
|
||||
"once_cell",
|
||||
"parking",
|
||||
"polling",
|
||||
"vec-arena",
|
||||
"waker-fn",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-lock"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1996609732bde4a9988bc42125f55f2af5f3c36370e27c778d5191a4a1b63bfb"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-mutex"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-process"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef37b86e2fa961bae5a4d212708ea0154f904ce31d1a4a7f47e1bbc33a0c040b"
|
||||
dependencies = [
|
||||
"async-io",
|
||||
"blocking",
|
||||
"cfg-if 1.0.0",
|
||||
"event-listener",
|
||||
"futures-lite",
|
||||
"once_cell",
|
||||
"signal-hook 0.3.7",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-std"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9f06685bad74e0570f5213741bea82158279a4103d988e57bfada11ad230341"
|
||||
dependencies = [
|
||||
"async-attributes",
|
||||
"async-channel",
|
||||
"async-global-executor",
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"async-process",
|
||||
"crossbeam-utils",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-lite",
|
||||
"gloo-timers",
|
||||
"kv-log-macro",
|
||||
"log",
|
||||
"memchr",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
"wasm-bindgen-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-task"
|
||||
version = "4.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0"
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
|
@ -88,6 +234,32 @@ version = "1.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "blocking"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-task",
|
||||
"atomic-waker",
|
||||
"fastrand",
|
||||
"futures-lite",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe"
|
||||
|
||||
[[package]]
|
||||
name = "cache-padded"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba"
|
||||
|
||||
[[package]]
|
||||
name = "cassowary"
|
||||
version = "0.3.0"
|
||||
|
@ -161,6 +333,15 @@ dependencies = [
|
|||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3"
|
||||
dependencies = [
|
||||
"cache-padded",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.9.2"
|
||||
|
@ -176,6 +357,17 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if 1.0.0",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.17.7"
|
||||
|
@ -184,11 +376,12 @@ checksum = "6f4919d60f26ae233e14233cc39746c8c8bb8cd7b05840ace83604917b51b6c7"
|
|||
dependencies = [
|
||||
"bitflags",
|
||||
"crossterm_winapi",
|
||||
"futures-util",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"signal-hook",
|
||||
"signal-hook 0.1.17",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
|
@ -201,6 +394,16 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.1.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.10.2"
|
||||
|
@ -294,6 +497,12 @@ version = "0.3.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "2.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59"
|
||||
|
||||
[[package]]
|
||||
name = "failure"
|
||||
version = "0.1.8"
|
||||
|
@ -316,6 +525,15 @@ dependencies = [
|
|||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca5faf057445ce5c9d4329e382b2ce7ca38550ef3b73a5348362d5f24e0c7fe3"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
|
@ -332,6 +550,119 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "891a4b7b96d84d5940084b2a37632dd65deeae662c114ceaa2c879629c9c0ad1"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
version = "1.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4481d0cd0de1d204a4fa55e7d45f07b1d958abcb06714b3446438e2eff695fb"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"memchr",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
"waker-fn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea405816a5139fb39af82c2beb921d52143f556038378d6db21183a5c37fbfb7"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85754d98985841b7d4f5e8e6fbfa4a4ac847916893ec511a2917ccd8525b8bb3"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa189ef211c15ee602667a6fcfe1c1fd9e07d42250d2156382820fba33c9df80"
|
||||
|
||||
[[package]]
|
||||
name = "futures-timer"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"proc-macro-hack",
|
||||
"proc-macro-nested",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.16"
|
||||
|
@ -360,6 +691,19 @@ version = "0.23.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
|
||||
|
||||
[[package]]
|
||||
name = "gloo-timers"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.18"
|
||||
|
@ -375,6 +719,15 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.9.0"
|
||||
|
@ -390,6 +743,24 @@ version = "0.4.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kv-log-macro"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
@ -418,6 +789,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"value-bag",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -458,6 +830,16 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nb-connect"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a19900e7eee95eb2b3c2e26d12a874cc80aaf750e31be6fcbe743ead369fa45d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"socket2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.19.1"
|
||||
|
@ -498,12 +880,34 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.10.2"
|
||||
|
@ -528,12 +932,49 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "2.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fc12d774e799ee9ebae13f4076ca003b40d18a11ac0f3641e6f899618580b7b"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"log",
|
||||
"wepoll-sys",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-nested"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.24"
|
||||
|
@ -731,6 +1172,16 @@ dependencies = [
|
|||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6aa894ef3fade0ee7243422f4fbbd6c2b48e6de767e621d37ef65f2310f53cea"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.3.0"
|
||||
|
@ -740,12 +1191,28 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
|
@ -760,9 +1227,9 @@ checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.64"
|
||||
version = "1.0.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f"
|
||||
checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -801,11 +1268,14 @@ name = "taskwarrior-tui"
|
|||
version = "0.12.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-std",
|
||||
"better-panic",
|
||||
"cassowary",
|
||||
"chrono",
|
||||
"clap",
|
||||
"crossterm",
|
||||
"futures",
|
||||
"futures-timer",
|
||||
"itertools",
|
||||
"rand",
|
||||
"regex",
|
||||
|
@ -896,12 +1366,33 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "value-bag"
|
||||
version = "1.0.0-alpha.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b676010e055c99033117c2343b33a40a30b91fecd6c49055ac9cd2d6c305ab1"
|
||||
dependencies = [
|
||||
"ctor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vec-arena"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34b2f665b594b07095e3ac3f718e13c2197143416fae4c5706cffb7b1af8d7f1"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "waker-fn"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
|
@ -914,6 +1405,91 @@ version = "0.10.2+wasi-snapshot-preview1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81b8b767af23de6ac18bf2168b690bed2902743ddf0fb39252e36f9e2bfc63ea"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wepoll-sys"
|
||||
version = "3.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fcb14dea929042224824779fbc82d9fab8d2e6d3cbc0ac404de8edf489e77ff"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
|
|
@ -31,12 +31,15 @@ chrono = "0.4"
|
|||
unicode-width = "0.1"
|
||||
unicode-segmentation = "1.6"
|
||||
tui = { version = "0.12", optional = true, default-features = false }
|
||||
crossterm = { version = "0.17", optional = true, default-features = false }
|
||||
crossterm = { version = "0.17", optional = true, default-features = false, features = ["event-stream"] }
|
||||
rustyline = "7.1.0"
|
||||
uuid = { version = "0.8.1", features = ["serde", "v4"] }
|
||||
better-panic = "0.2.0"
|
||||
shellexpand = "2.1"
|
||||
anyhow = "1"
|
||||
async-std = { version = "1", features = ["attributes", "unstable"] }
|
||||
futures = "0.3"
|
||||
futures-timer = "3.0"
|
||||
|
||||
[package.metadata.rpm]
|
||||
package = "taskwarrior-tui"
|
||||
|
@ -46,3 +49,6 @@ buildflags = ["--release"]
|
|||
|
||||
[package.metadata.rpm.targets]
|
||||
taskwarrior-tui = { path = "/usr/bin/taskwarrior-tui" }
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
|
|
144
src/app.rs
144
src/app.rs
|
@ -30,7 +30,16 @@ use chrono::{Datelike, Local, NaiveDate, NaiveDateTime, TimeZone};
|
|||
|
||||
use anyhow::Result;
|
||||
|
||||
use std::{sync::mpsc, thread, time::Duration};
|
||||
use async_std::prelude::*;
|
||||
use async_std::stream::StreamExt;
|
||||
use async_std::task;
|
||||
use futures::future::join_all;
|
||||
use futures::join;
|
||||
use futures::stream::FuturesOrdered;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use std::time::Duration;
|
||||
use tui::{
|
||||
backend::Backend,
|
||||
layout::{Alignment, Constraint, Direction, Layout, Margin, Rect},
|
||||
|
@ -140,6 +149,7 @@ pub enum AppMode {
|
|||
|
||||
pub struct TaskwarriorTuiApp {
|
||||
pub should_quit: bool,
|
||||
pub dirty: bool,
|
||||
pub task_table_state: TableState,
|
||||
pub context_table_state: TableState,
|
||||
pub current_context_filter: String,
|
||||
|
@ -173,8 +183,10 @@ impl TaskwarriorTuiApp {
|
|||
let c = Config::default()?;
|
||||
let mut kc = KeyConfig::default();
|
||||
kc.update()?;
|
||||
let (w, h) = crossterm::terminal::size()?;
|
||||
let mut app = Self {
|
||||
should_quit: false,
|
||||
dirty: true,
|
||||
task_table_state: TableState::default(),
|
||||
context_table_state: TableState::default(),
|
||||
tasks: vec![],
|
||||
|
@ -198,8 +210,8 @@ impl TaskwarriorTuiApp {
|
|||
contexts: vec![],
|
||||
last_export: None,
|
||||
keyconfig: kc,
|
||||
terminal_width: 0,
|
||||
terminal_height: 0,
|
||||
terminal_width: w,
|
||||
terminal_height: h,
|
||||
};
|
||||
for c in app.config.filter.chars() {
|
||||
app.filter.insert(c, 1);
|
||||
|
@ -223,6 +235,14 @@ impl TaskwarriorTuiApp {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn render<B>(&mut self, terminal: &mut Terminal<B>) -> Result<()>
|
||||
where
|
||||
B: Backend,
|
||||
{
|
||||
terminal.draw(|f| self.draw(f))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, f: &mut Frame<impl Backend>) {
|
||||
let rect = f.size();
|
||||
self.terminal_width = rect.width;
|
||||
|
@ -280,7 +300,6 @@ impl TaskwarriorTuiApp {
|
|||
let mut tasks_with_styles = vec![];
|
||||
|
||||
let tasks_is_empty = self.tasks.is_empty();
|
||||
let tasks_len = self.tasks.len();
|
||||
|
||||
if !tasks_is_empty {
|
||||
let tasks = &self.tasks;
|
||||
|
@ -305,8 +324,7 @@ impl TaskwarriorTuiApp {
|
|||
|
||||
pub fn draw_task(&mut self, f: &mut Frame<impl Backend>) {
|
||||
let tasks_is_empty = self.tasks.is_empty();
|
||||
let tasks_len = self.tasks.len();
|
||||
while !tasks_is_empty && self.current_selection >= tasks_len {
|
||||
while !tasks_is_empty && self.current_selection >= self.tasks.len() {
|
||||
self.task_report_previous();
|
||||
}
|
||||
let rects = Layout::default()
|
||||
|
@ -333,7 +351,7 @@ impl TaskwarriorTuiApp {
|
|||
self.draw_task_details(f, split_task_layout[1]);
|
||||
}
|
||||
let selected = self.current_selection;
|
||||
let task_ids = if tasks_len == 0 {
|
||||
let task_ids = if self.tasks.is_empty() {
|
||||
vec!["0".to_string()]
|
||||
} else {
|
||||
match self.task_table_state.mode() {
|
||||
|
@ -593,24 +611,14 @@ impl TaskwarriorTuiApp {
|
|||
let task_id = self.tasks[selected].id().unwrap_or_default();
|
||||
let task_uuid = *self.tasks[selected].uuid();
|
||||
|
||||
if !self.task_details.contains_key(&task_uuid) {
|
||||
let output = Command::new("task")
|
||||
.arg("rc.color=off")
|
||||
.arg(format!("rc.defaultwidth={}", self.terminal_width - 2))
|
||||
.arg(format!("{}", task_uuid))
|
||||
.output();
|
||||
let data = if let Ok(output) = output {
|
||||
String::from_utf8_lossy(&output.stdout).to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
let data = match self.task_details.get(&task_uuid) {
|
||||
Some(s) => s.clone(),
|
||||
None => "Loading task details ...".to_string(),
|
||||
};
|
||||
let entry = self.task_details.entry(task_uuid).or_insert_with(|| "".to_string());
|
||||
*entry = data;
|
||||
}
|
||||
let data = self.task_details[&task_uuid].clone();
|
||||
|
||||
self.task_details_scroll = std::cmp::min(
|
||||
(data.lines().count() as u16).saturating_sub(rect.height),
|
||||
(data.lines().count() as u16)
|
||||
.saturating_sub(rect.height)
|
||||
.saturating_add(2),
|
||||
self.task_details_scroll,
|
||||
);
|
||||
let p = Paragraph::new(Text::from(&data[..]))
|
||||
|
@ -624,11 +632,11 @@ impl TaskwarriorTuiApp {
|
|||
f.render_widget(p, rect);
|
||||
}
|
||||
|
||||
fn task_details_scroll_down(&mut self) {
|
||||
fn task_details_scroll_up(&mut self) {
|
||||
self.task_details_scroll = self.task_details_scroll.saturating_sub(1);
|
||||
}
|
||||
|
||||
fn task_details_scroll_up(&mut self) {
|
||||
fn task_details_scroll_down(&mut self) {
|
||||
self.task_details_scroll = self.task_details_scroll.saturating_add(1);
|
||||
}
|
||||
|
||||
|
@ -856,13 +864,83 @@ impl TaskwarriorTuiApp {
|
|||
}
|
||||
|
||||
pub fn update(&mut self, force: bool) -> Result<()> {
|
||||
if force || self.tasks_changed_since(self.last_export)? {
|
||||
if force || self.dirty || self.tasks_changed_since(self.last_export)? {
|
||||
self.last_export = Some(std::time::SystemTime::now());
|
||||
self.task_report_table.export_headers()?;
|
||||
let _ = self.export_tasks();
|
||||
self.export_contexts()?;
|
||||
self.update_tags();
|
||||
self.task_details.clear();
|
||||
self.dirty = false;
|
||||
}
|
||||
if self.task_report_show_info {
|
||||
task::block_on(self.update_task_details())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_task_details(&mut self) -> Result<()> {
|
||||
if self.tasks.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// remove task_details of tasks not in task report
|
||||
let mut to_delete = vec![];
|
||||
for k in self.task_details.keys() {
|
||||
if !self.tasks.iter().map(|t| t.uuid()).any(|x| x == k) {
|
||||
to_delete.push(*k);
|
||||
}
|
||||
}
|
||||
for k in to_delete {
|
||||
self.task_details.remove(&k);
|
||||
}
|
||||
|
||||
let selected = self.current_selection;
|
||||
if selected >= self.tasks.len() {
|
||||
return Ok(());
|
||||
}
|
||||
let current_task_uuid = *self.tasks[selected].uuid();
|
||||
|
||||
let mut l = vec![selected];
|
||||
|
||||
for s in 1..=self.config.uda_task_detail_prefetch {
|
||||
l.insert(0, std::cmp::min(selected.saturating_sub(s), self.tasks.len() - 1));
|
||||
l.push(std::cmp::min(selected + s, self.tasks.len() - 1))
|
||||
}
|
||||
|
||||
l.dedup();
|
||||
|
||||
let mut output_futs = FuturesOrdered::new();
|
||||
for s in l.iter() {
|
||||
if self.tasks.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
if s >= &self.tasks.len() {
|
||||
break;
|
||||
}
|
||||
let task_uuid = *self.tasks[*s].uuid();
|
||||
if !self.task_details.contains_key(&task_uuid) || task_uuid == current_task_uuid {
|
||||
let output_fut = async_std::process::Command::new("task")
|
||||
.arg("rc.color=off")
|
||||
.arg(format!("rc.defaultwidth={}", self.terminal_width - 2))
|
||||
.arg(format!("{}", task_uuid))
|
||||
.output();
|
||||
output_futs.push(output_fut);
|
||||
}
|
||||
}
|
||||
|
||||
for s in l.iter() {
|
||||
if s >= &self.tasks.len() {
|
||||
break;
|
||||
}
|
||||
let task_id = self.tasks[*s].id().unwrap_or_default();
|
||||
let task_uuid = *self.tasks[*s].uuid();
|
||||
if !self.task_details.contains_key(&task_uuid) || task_uuid == current_task_uuid {
|
||||
if let Some(Ok(output)) = output_futs.next().await {
|
||||
let data = String::from_utf8_lossy(&output.stdout).to_string();
|
||||
self.task_details.insert(task_uuid, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1708,9 +1786,9 @@ impl TaskwarriorTuiApp {
|
|||
} else if input == Key::PageUp || input == self.keyconfig.page_up {
|
||||
self.task_report_previous_page();
|
||||
} else if input == Key::Ctrl('e') {
|
||||
self.task_details_scroll_up();
|
||||
} else if input == Key::Ctrl('y') {
|
||||
self.task_details_scroll_down();
|
||||
} else if input == Key::Ctrl('y') {
|
||||
self.task_details_scroll_up();
|
||||
} else if input == self.keyconfig.done {
|
||||
match self.task_done() {
|
||||
Ok(_) => self.update(true)?,
|
||||
|
@ -1983,7 +2061,7 @@ impl TaskwarriorTuiApp {
|
|||
}
|
||||
_ => {
|
||||
handle_movement(&mut self.filter, input);
|
||||
// TODO: call self.update(true) here for instant filter updates
|
||||
self.dirty = true;
|
||||
}
|
||||
},
|
||||
AppMode::TaskError => self.mode = AppMode::TaskReport,
|
||||
|
@ -2123,6 +2201,9 @@ mod tests {
|
|||
|
||||
test_draw_empty_task_report();
|
||||
|
||||
test_draw_calendar();
|
||||
test_draw_help_popup();
|
||||
|
||||
setup();
|
||||
|
||||
let app = TaskwarriorTuiApp::new().unwrap();
|
||||
|
@ -2141,6 +2222,7 @@ mod tests {
|
|||
test_task_tomorrow();
|
||||
test_task_earlier_today();
|
||||
test_task_later_today();
|
||||
|
||||
teardown();
|
||||
}
|
||||
|
||||
|
@ -2767,7 +2849,7 @@ mod tests {
|
|||
"╭Task 27─────────────────────────────────────────╮",
|
||||
"│ │",
|
||||
"│Name Value │",
|
||||
"│----------- ------------------------------------│",
|
||||
"│------------- ----------------------------------│",
|
||||
"│ID 27 │",
|
||||
"╰────────────────────────────────────────────────╯",
|
||||
"╭Filter Tasks────────────────────────────────────╮",
|
||||
|
@ -2824,7 +2906,6 @@ mod tests {
|
|||
test_case(&expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_draw_calendar() {
|
||||
let test_case = |expected: &Buffer| {
|
||||
let mut app = TaskwarriorTuiApp::new().unwrap();
|
||||
|
@ -2909,7 +2990,6 @@ mod tests {
|
|||
test_case(&expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_draw_help_popup() {
|
||||
let test_case = |expected: &Buffer| {
|
||||
let mut app = TaskwarriorTuiApp::new().unwrap();
|
||||
|
|
198
src/config.rs
198
src/config.rs
|
@ -1,4 +1,6 @@
|
|||
use anyhow::{Context, Result};
|
||||
use async_std::task;
|
||||
use futures::join;
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::process::Command;
|
||||
|
@ -43,6 +45,7 @@ pub struct Config {
|
|||
pub print_empty_columns: bool,
|
||||
pub due: usize,
|
||||
pub rule_precedence_color: Vec<String>,
|
||||
pub uda_task_detail_prefetch: usize,
|
||||
pub uda_task_report_show_info: bool,
|
||||
pub uda_task_report_looping: bool,
|
||||
pub uda_selection_indicator: String,
|
||||
|
@ -61,28 +64,102 @@ pub struct Config {
|
|||
impl Config {
|
||||
pub fn default() -> Result<Self> {
|
||||
let bool_collection = Self::get_bool_collection();
|
||||
|
||||
let enabled = true;
|
||||
let obfuscate = bool_collection.get("obfuscate").cloned().unwrap_or(false);
|
||||
let print_empty_columns = bool_collection.get("print_empty_columns").cloned().unwrap_or(false);
|
||||
|
||||
let color = Self::get_color_collection();
|
||||
let filter = Self::get_filter();
|
||||
let data_location = Self::get_data_location();
|
||||
let due = Self::get_due();
|
||||
let rule_precedence_color = Self::get_rule_precedence_color();
|
||||
let uda_task_detail_prefetch = Self::get_uda_task_detail_prefetch();
|
||||
let uda_task_report_show_info = Self::get_uda_task_report_show_info();
|
||||
let uda_task_report_looping = Self::get_uda_task_report_looping();
|
||||
let uda_selection_indicator = Self::get_uda_selection_indicator();
|
||||
let uda_mark_indicator = Self::get_uda_mark_indicator();
|
||||
let uda_unmark_indicator = Self::get_uda_unmark_indicator();
|
||||
let uda_selection_bold = Self::get_uda_selection_bold();
|
||||
let uda_selection_italic = Self::get_uda_selection_italic();
|
||||
let uda_selection_dim = Self::get_uda_selection_dim();
|
||||
let uda_selection_blink = Self::get_uda_selection_blink();
|
||||
let uda_calendar_months_per_row = Self::get_uda_months_per_row();
|
||||
let uda_style_calendar_title = Self::get_uda_style("calendar.title");
|
||||
let uda_style_context_active = Self::get_uda_style("context.active");
|
||||
let uda_shortcuts = Self::get_uda_shortcuts();
|
||||
|
||||
let (
|
||||
color,
|
||||
filter,
|
||||
data_location,
|
||||
due,
|
||||
rule_precedence_color,
|
||||
uda_task_detail_prefetch,
|
||||
uda_task_report_show_info,
|
||||
uda_task_report_looping,
|
||||
uda_selection_indicator,
|
||||
uda_mark_indicator,
|
||||
uda_unmark_indicator,
|
||||
uda_selection_bold,
|
||||
uda_selection_italic,
|
||||
uda_selection_dim,
|
||||
uda_selection_blink,
|
||||
uda_calendar_months_per_row,
|
||||
uda_style_calendar_title,
|
||||
uda_style_context_active,
|
||||
uda_shortcuts,
|
||||
) = task::block_on(async {
|
||||
join!(
|
||||
color,
|
||||
filter,
|
||||
data_location,
|
||||
due,
|
||||
rule_precedence_color,
|
||||
uda_task_detail_prefetch,
|
||||
uda_task_report_show_info,
|
||||
uda_task_report_looping,
|
||||
uda_selection_indicator,
|
||||
uda_mark_indicator,
|
||||
uda_unmark_indicator,
|
||||
uda_selection_bold,
|
||||
uda_selection_italic,
|
||||
uda_selection_dim,
|
||||
uda_selection_blink,
|
||||
uda_calendar_months_per_row,
|
||||
uda_style_calendar_title,
|
||||
uda_style_context_active,
|
||||
uda_shortcuts,
|
||||
)
|
||||
});
|
||||
|
||||
let color = color?;
|
||||
let uda_style_calendar_title = uda_style_calendar_title.unwrap_or_default();
|
||||
let uda_style_context_active = uda_style_context_active.unwrap_or_default();
|
||||
|
||||
Ok(Self {
|
||||
enabled: true,
|
||||
obfuscate: bool_collection.get("obfuscate").cloned().unwrap_or(false),
|
||||
print_empty_columns: bool_collection.get("print_empty_columns").cloned().unwrap_or(false),
|
||||
color: Self::get_color_collection()?,
|
||||
filter: Self::get_filter(),
|
||||
data_location: Self::get_data_location(),
|
||||
due: Self::get_due(),
|
||||
rule_precedence_color: Self::get_rule_precedence_color(),
|
||||
uda_task_report_show_info: Self::get_uda_task_report_show_info(),
|
||||
uda_task_report_looping: Self::get_uda_task_report_looping(),
|
||||
uda_selection_indicator: Self::get_uda_selection_indicator(),
|
||||
uda_mark_indicator: Self::get_uda_mark_indicator(),
|
||||
uda_unmark_indicator: Self::get_uda_unmark_indicator(),
|
||||
uda_selection_bold: Self::get_uda_selection_bold(),
|
||||
uda_selection_italic: Self::get_uda_selection_italic(),
|
||||
uda_selection_dim: Self::get_uda_selection_dim(),
|
||||
uda_selection_blink: Self::get_uda_selection_blink(),
|
||||
uda_calendar_months_per_row: Self::get_uda_months_per_row(),
|
||||
uda_style_calendar_title: Self::get_uda_style("calendar.title").unwrap_or_default(),
|
||||
uda_style_context_active: Self::get_uda_style("context.active").unwrap_or_default(),
|
||||
uda_shortcuts: Self::get_uda_shortcuts(),
|
||||
enabled,
|
||||
color,
|
||||
filter,
|
||||
data_location,
|
||||
obfuscate,
|
||||
print_empty_columns,
|
||||
due,
|
||||
rule_precedence_color,
|
||||
uda_task_detail_prefetch,
|
||||
uda_task_report_show_info,
|
||||
uda_task_report_looping,
|
||||
uda_selection_indicator,
|
||||
uda_mark_indicator,
|
||||
uda_unmark_indicator,
|
||||
uda_selection_bold,
|
||||
uda_selection_italic,
|
||||
uda_selection_dim,
|
||||
uda_selection_blink,
|
||||
uda_calendar_months_per_row,
|
||||
uda_style_context_active,
|
||||
uda_style_calendar_title,
|
||||
uda_shortcuts,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -90,25 +167,29 @@ impl Config {
|
|||
HashMap::new()
|
||||
}
|
||||
|
||||
fn get_uda_shortcuts() -> Vec<String> {
|
||||
async fn get_uda_shortcuts() -> Vec<String> {
|
||||
let mut v = vec![];
|
||||
for s in 0..=9 {
|
||||
let c = format!("uda.taskwarrior-tui.shortcuts.{}", s);
|
||||
let s = Self::get_config(&c).unwrap_or_default();
|
||||
let s = Self::get_config(&c).await.unwrap_or_default();
|
||||
v.push(s);
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
fn get_uda_style(config: &str) -> Option<Style> {
|
||||
async fn get_uda_style(config: &str) -> Option<Style> {
|
||||
let c = format!("uda.taskwarrior-tui.style.{}", config);
|
||||
let s = Self::get_config(&c)?;
|
||||
let s = Self::get_config(&c).await?;
|
||||
Some(Self::get_tcolor(&s))
|
||||
}
|
||||
|
||||
fn get_color_collection() -> Result<HashMap<String, Style>> {
|
||||
async fn get_color_collection() -> Result<HashMap<String, Style>> {
|
||||
let mut color_collection = HashMap::new();
|
||||
let output = Command::new("task").arg("rc.color=off").arg("show").output()?;
|
||||
let output = async_std::process::Command::new("task")
|
||||
.arg("rc.color=off")
|
||||
.arg("show")
|
||||
.output()
|
||||
.await?;
|
||||
|
||||
let data = String::from_utf8_lossy(&output.stdout);
|
||||
for line in data.split('\n') {
|
||||
|
@ -274,12 +355,13 @@ impl Config {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_config(config: &str) -> Option<String> {
|
||||
let output = Command::new("task")
|
||||
async fn get_config(config: &str) -> Option<String> {
|
||||
let output = async_std::process::Command::new("task")
|
||||
.arg("rc.color=off")
|
||||
.arg("show")
|
||||
.arg(config)
|
||||
.output()
|
||||
.await
|
||||
.with_context(|| format!("Unable to run `task show {}`.", config))
|
||||
.unwrap();
|
||||
|
||||
|
@ -311,100 +393,119 @@ impl Config {
|
|||
None
|
||||
}
|
||||
|
||||
fn get_due() -> usize {
|
||||
async fn get_due() -> usize {
|
||||
Self::get_config("due")
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.parse::<usize>()
|
||||
.unwrap_or(7)
|
||||
}
|
||||
|
||||
fn get_rule_precedence_color() -> Vec<String> {
|
||||
async fn get_rule_precedence_color() -> Vec<String> {
|
||||
let data = Self::get_config("rule.precedence.color")
|
||||
.await
|
||||
.context("Unable to parse `task show rule.precedence.color`.")
|
||||
.unwrap();
|
||||
data.split(',').map(|s| s.to_string()).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn get_filter() -> String {
|
||||
async fn get_filter() -> String {
|
||||
Self::get_config("report.next.filter")
|
||||
.await
|
||||
.context("Unable to parse `task show report.next.filter`.")
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn get_data_location() -> String {
|
||||
async fn get_data_location() -> String {
|
||||
Self::get_config("data.location")
|
||||
.await
|
||||
.context("Unable to parse `task show data.location`.")
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn get_uda_task_report_show_info() -> bool {
|
||||
async fn get_uda_task_detail_prefetch() -> usize {
|
||||
Self::get_config("uda.taskwarrior-tui.task-report.task-detail-prefetch")
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.parse::<usize>()
|
||||
.unwrap_or(10)
|
||||
}
|
||||
|
||||
async fn get_uda_task_report_show_info() -> bool {
|
||||
Self::get_config("uda.taskwarrior-tui.task-report.show-info")
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.get_bool()
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
fn get_uda_task_report_looping() -> bool {
|
||||
async fn get_uda_task_report_looping() -> bool {
|
||||
Self::get_config("uda.taskwarrior-tui.task-report.looping")
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.get_bool()
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
fn get_uda_selection_indicator() -> String {
|
||||
let indicator = Self::get_config("uda.taskwarrior-tui.selection.indicator");
|
||||
async fn get_uda_selection_indicator() -> String {
|
||||
let indicator = Self::get_config("uda.taskwarrior-tui.selection.indicator").await;
|
||||
match indicator {
|
||||
None => "• ".to_string(),
|
||||
Some(indicator) => format!("{} ", indicator),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_uda_mark_indicator() -> String {
|
||||
let indicator = Self::get_config("uda.taskwarrior-tui.mark.indicator");
|
||||
async fn get_uda_mark_indicator() -> String {
|
||||
let indicator = Self::get_config("uda.taskwarrior-tui.mark.indicator").await;
|
||||
match indicator {
|
||||
None => "✔ ".to_string(),
|
||||
Some(indicator) => format!("{} ", indicator),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_uda_unmark_indicator() -> String {
|
||||
let indicator = Self::get_config("uda.taskwarrior-tui.unmark.indicator");
|
||||
async fn get_uda_unmark_indicator() -> String {
|
||||
let indicator = Self::get_config("uda.taskwarrior-tui.unmark.indicator").await;
|
||||
match indicator {
|
||||
None => " ".to_string(),
|
||||
Some(indicator) => format!("{} ", indicator),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_uda_selection_bold() -> bool {
|
||||
async fn get_uda_selection_bold() -> bool {
|
||||
Self::get_config("uda.taskwarrior-tui.selection.bold")
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.get_bool()
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
fn get_uda_selection_italic() -> bool {
|
||||
async fn get_uda_selection_italic() -> bool {
|
||||
Self::get_config("uda.taskwarrior-tui.selection.italic")
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.get_bool()
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn get_uda_selection_dim() -> bool {
|
||||
async fn get_uda_selection_dim() -> bool {
|
||||
Self::get_config("uda.taskwarrior-tui.selection.dim")
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.get_bool()
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn get_uda_selection_blink() -> bool {
|
||||
async fn get_uda_selection_blink() -> bool {
|
||||
Self::get_config("uda.taskwarrior-tui.selection.blink")
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.get_bool()
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn get_uda_months_per_row() -> usize {
|
||||
async fn get_uda_months_per_row() -> usize {
|
||||
Self::get_config("uda.taskwarrior-tui.calendar.months-per-row")
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.parse::<usize>()
|
||||
.unwrap_or(4)
|
||||
|
@ -416,7 +517,10 @@ mod tests {
|
|||
use super::*;
|
||||
#[test]
|
||||
fn test_uda_configuration() {
|
||||
assert_eq!(None, Config::get_config("uda.taskwarrior-tui.unmark.indicator"));
|
||||
assert_eq!(
|
||||
None,
|
||||
task::block_on(Config::get_config("uda.taskwarrior-tui.unmark.indicator"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
50
src/main.rs
50
src/main.rs
|
@ -21,6 +21,11 @@ use std::io::Write;
|
|||
use std::panic;
|
||||
use std::time::Duration;
|
||||
|
||||
use async_std::prelude::*;
|
||||
use async_std::sync::{Arc, Mutex};
|
||||
use async_std::task;
|
||||
use futures::stream::{FuturesUnordered, StreamExt};
|
||||
|
||||
use crate::util::Key;
|
||||
use app::{AppMode, TaskwarriorTuiApp};
|
||||
|
||||
|
@ -44,28 +49,12 @@ fn main() -> Result<()> {
|
|||
.get_matches();
|
||||
|
||||
let config = matches.value_of("config").unwrap_or("~/.taskrc");
|
||||
let r = tui_main(config);
|
||||
match r {
|
||||
Ok(_) => std::process::exit(0),
|
||||
Err(error) => {
|
||||
if error.to_string().to_lowercase().contains("no such file or directory") {
|
||||
eprintln!(
|
||||
"[taskwarrior-tui error]: Unable to find executable `task`: {}. Check that taskwarrior is installed correctly and try again.", error
|
||||
);
|
||||
} else {
|
||||
eprintln!(
|
||||
"[taskwarrior-tui error]: {}. Please report as a github issue on https://github.com/kdheepak/taskwarrior-tui",
|
||||
error
|
||||
);
|
||||
}
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
task::block_on(tui_main(config))
|
||||
}
|
||||
|
||||
fn tui_main(_config: &str) -> Result<()> {
|
||||
async fn tui_main(_config: &str) -> Result<()> {
|
||||
// Terminal initialization
|
||||
let mut terminal = setup_terminal();
|
||||
let terminal = setup_terminal();
|
||||
|
||||
panic::set_hook(Box::new(|panic_info| {
|
||||
destruct_terminal();
|
||||
|
@ -79,21 +68,30 @@ fn tui_main(_config: &str) -> Result<()> {
|
|||
|
||||
let maybeapp = TaskwarriorTuiApp::new();
|
||||
match maybeapp {
|
||||
Ok(mut app) => {
|
||||
Ok(app) => {
|
||||
let app = Arc::new(Mutex::new(app));
|
||||
let terminal = Arc::new(Mutex::new(terminal));
|
||||
loop {
|
||||
terminal.draw(|mut frame| app.draw(&mut frame)).unwrap();
|
||||
|
||||
let handle = {
|
||||
let app = app.clone();
|
||||
let terminal = terminal.clone();
|
||||
task::spawn_local(async move {
|
||||
let mut t = terminal.lock().await;
|
||||
app.lock().await.render(&mut t).unwrap();
|
||||
})
|
||||
};
|
||||
// Handle input
|
||||
match events.next()? {
|
||||
match events.next().await? {
|
||||
Event::Input(input) => {
|
||||
let r = app.handle_input(input, &mut terminal, &events);
|
||||
let mut t = terminal.lock().await;
|
||||
let r = app.lock().await.handle_input(input, &mut t, &events);
|
||||
if r.is_err() {
|
||||
destruct_terminal();
|
||||
return r;
|
||||
}
|
||||
}
|
||||
Event::Tick => {
|
||||
let r = app.update(false);
|
||||
let r = app.lock().await.update(false);
|
||||
if r.is_err() {
|
||||
destruct_terminal();
|
||||
return r;
|
||||
|
@ -101,7 +99,7 @@ fn tui_main(_config: &str) -> Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
if app.should_quit {
|
||||
if app.lock().await.should_quit {
|
||||
destruct_terminal();
|
||||
break;
|
||||
}
|
||||
|
|
83
src/util.rs
83
src/util.rs
|
@ -1,15 +1,20 @@
|
|||
use crossterm::{
|
||||
cursor,
|
||||
event::{self, DisableMouseCapture, EnableMouseCapture},
|
||||
event::{self, DisableMouseCapture, EnableMouseCapture, EventStream},
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, Clear, ClearType, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use tui::{backend::CrosstermBackend, Terminal};
|
||||
|
||||
use async_std::channel::unbounded;
|
||||
use async_std::sync::Arc;
|
||||
use async_std::task;
|
||||
use futures::prelude::*;
|
||||
use futures::{future::FutureExt, select, StreamExt};
|
||||
use futures_timer::Delay;
|
||||
use std::io::{self, Write};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::{sync::mpsc, thread, time::Duration, time::Instant};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
@ -62,38 +67,36 @@ pub fn destruct_terminal() {
|
|||
}
|
||||
|
||||
pub struct Events {
|
||||
pub rx: mpsc::Receiver<Event<Key>>,
|
||||
pub tx: mpsc::Sender<Event<Key>>,
|
||||
pub rx: async_std::channel::Receiver<Event<Key>>,
|
||||
pub pause_stdin: Arc<AtomicBool>,
|
||||
pub handle: Option<thread::JoinHandle<()>>,
|
||||
}
|
||||
|
||||
impl Events {
|
||||
#[cfg(feature = "crossterm")]
|
||||
pub fn with_config(config: EventConfig) -> Events {
|
||||
use crossterm::event::{KeyCode::*, KeyModifiers};
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let pause_stdin = Arc::new(AtomicBool::new(false));
|
||||
let tick_rate = config.tick_rate;
|
||||
let handle = Some({
|
||||
let tx = tx.clone();
|
||||
let pause_stdin = pause_stdin.clone();
|
||||
thread::spawn(move || {
|
||||
let mut last_tick = Instant::now();
|
||||
let (tx, rx) = unbounded::<Event<Key>>();
|
||||
let ps = pause_stdin.clone();
|
||||
task::spawn_local(async move {
|
||||
let mut reader = EventStream::new();
|
||||
|
||||
loop {
|
||||
if pause_stdin.load(Ordering::SeqCst) {
|
||||
thread::sleep(Duration::from_millis(250));
|
||||
thread::park();
|
||||
last_tick = Instant::now();
|
||||
if ps.load(Ordering::SeqCst) {
|
||||
task::sleep(Duration::from_millis(250)).await;
|
||||
task::yield_now().await;
|
||||
continue;
|
||||
}
|
||||
|
||||
let timeout = Duration::from_millis(10)
|
||||
.checked_sub(last_tick.elapsed())
|
||||
.unwrap_or_else(|| Duration::from_millis(5));
|
||||
let mut delay = Delay::new(Duration::from_millis(250)).fuse();
|
||||
let mut event = reader.next().fuse();
|
||||
|
||||
if event::poll(timeout).unwrap() {
|
||||
if let event::Event::Key(key) = event::read().unwrap() {
|
||||
select! {
|
||||
_ = delay => {
|
||||
tx.send(Event::Tick).await.ok();
|
||||
},
|
||||
maybe_event = event => {
|
||||
if let Some(Ok(event::Event::Key(key))) = maybe_event {
|
||||
let key = match key.code {
|
||||
Backspace => Key::Backspace,
|
||||
Enter => Key::Char('\n'),
|
||||
|
@ -119,49 +122,39 @@ impl Events {
|
|||
_ => Key::Null,
|
||||
},
|
||||
};
|
||||
tx.send(Event::Input(key)).unwrap();
|
||||
tx.send(Event::Input(key)).await.unwrap();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if last_tick.elapsed() >= tick_rate && tx.send(Event::Tick).is_ok() {
|
||||
last_tick = Instant::now();
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
Events {
|
||||
rx,
|
||||
tx,
|
||||
pause_stdin,
|
||||
handle,
|
||||
}
|
||||
Events { rx, pause_stdin }
|
||||
}
|
||||
|
||||
/// Attempts to read an event.
|
||||
/// This function will block the current thread.
|
||||
pub fn next(&self) -> Result<Event<Key>, mpsc::RecvError> {
|
||||
self.rx.recv()
|
||||
pub async fn next(&self) -> Result<Event<Key>, async_std::channel::RecvError> {
|
||||
self.rx.recv().await
|
||||
}
|
||||
|
||||
pub fn pause_event_loop(&self) {
|
||||
pub async fn pause_event_loop(&self) {
|
||||
self.pause_stdin.store(true, Ordering::SeqCst);
|
||||
thread::yield_now();
|
||||
task::yield_now().await;
|
||||
while !self.pause_stdin.load(Ordering::SeqCst) {
|
||||
thread::sleep(Duration::from_millis(50));
|
||||
task::sleep(Duration::from_millis(50)).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resume_event_loop(&self) {
|
||||
pub async fn resume_event_loop(&self) {
|
||||
self.pause_stdin.store(false, Ordering::SeqCst);
|
||||
thread::yield_now();
|
||||
task::yield_now().await;
|
||||
while self.pause_stdin.load(Ordering::SeqCst) {
|
||||
thread::sleep(Duration::from_millis(50));
|
||||
task::sleep(Duration::from_millis(50)).await;
|
||||
}
|
||||
self.handle.as_ref().unwrap().thread().unpark();
|
||||
}
|
||||
|
||||
pub fn pause_key_capture(&self, terminal: &mut Terminal<CrosstermBackend<io::Stdout>>) {
|
||||
self.pause_event_loop();
|
||||
task::block_on(self.pause_event_loop());
|
||||
disable_raw_mode().unwrap();
|
||||
execute!(io::stdout(), LeaveAlternateScreen, DisableMouseCapture).unwrap();
|
||||
terminal.show_cursor().unwrap();
|
||||
|
@ -170,7 +163,7 @@ impl Events {
|
|||
pub fn resume_key_capture(&self, terminal: &mut Terminal<CrosstermBackend<io::Stdout>>) {
|
||||
execute!(io::stdout(), EnterAlternateScreen, EnableMouseCapture).unwrap();
|
||||
enable_raw_mode().unwrap();
|
||||
self.resume_event_loop();
|
||||
task::block_on(self.resume_event_loop());
|
||||
terminal.resize(terminal.size().unwrap()).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue