Rework actions and events + start statusbar
This commit is contained in:
parent
0c5e8ab544
commit
0e29fa0299
251
Cargo.lock
generated
251
Cargo.lock
generated
@ -2,6 +2,21 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "addr2line"
|
||||||
|
version = "0.21.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
|
||||||
|
dependencies = [
|
||||||
|
"gimli",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adler"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
version = "0.8.11"
|
version = "0.8.11"
|
||||||
@ -26,6 +41,21 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "backtrace"
|
||||||
|
version = "0.3.69"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
|
||||||
|
dependencies = [
|
||||||
|
"addr2line",
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"miniz_oxide",
|
||||||
|
"object",
|
||||||
|
"rustc-demangle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
@ -53,12 +83,45 @@ dependencies = [
|
|||||||
"rustversion",
|
"rustversion",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.90"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[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.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"owo-colors",
|
||||||
|
"tracing-core",
|
||||||
|
"tracing-error",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "compact_str"
|
name = "compact_str"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
@ -113,6 +176,21 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "form_urlencoded"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||||
|
dependencies = [
|
||||||
|
"percent-encoding",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gimli"
|
||||||
|
version = "0.28.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.3"
|
version = "0.14.3"
|
||||||
@ -129,6 +207,16 @@ version = "0.4.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-bidi",
|
||||||
|
"unicode-normalization",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indenter"
|
name = "indenter"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
@ -156,6 +244,12 @@ version = "1.0.10"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.153"
|
version = "0.2.153"
|
||||||
@ -187,6 +281,21 @@ dependencies = [
|
|||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
|
||||||
|
dependencies = [
|
||||||
|
"adler",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.8.11"
|
version = "0.8.11"
|
||||||
@ -203,9 +312,20 @@ dependencies = [
|
|||||||
name = "molehole"
|
name = "molehole"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"color-eyre",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"eyre",
|
"eyre",
|
||||||
"ratatui",
|
"ratatui",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "object"
|
||||||
|
version = "0.32.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -214,6 +334,12 @@ version = "1.19.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "owo-colors"
|
||||||
|
version = "3.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
@ -243,6 +369,18 @@ version = "1.0.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
|
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "percent-encoding"
|
||||||
|
version = "2.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-lite"
|
||||||
|
version = "0.2.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.78"
|
version = "1.0.78"
|
||||||
@ -290,6 +428,12 @@ dependencies = [
|
|||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-demangle"
|
||||||
|
version = "0.1.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.14"
|
version = "1.0.14"
|
||||||
@ -308,6 +452,15 @@ version = "1.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sharded-slab"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook"
|
name = "signal-hook"
|
||||||
version = "0.3.17"
|
version = "0.3.17"
|
||||||
@ -404,12 +557,93 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thread_local"
|
||||||
|
version = "1.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec_macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec_macros"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing"
|
||||||
|
version = "0.1.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
|
||||||
|
dependencies = [
|
||||||
|
"pin-project-lite",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-core"
|
||||||
|
version = "0.1.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
|
||||||
|
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-subscriber"
|
||||||
|
version = "0.3.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
|
||||||
|
dependencies = [
|
||||||
|
"sharded-slab",
|
||||||
|
"thread_local",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-bidi"
|
||||||
|
version = "0.3.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.12"
|
version = "1.0.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-normalization"
|
||||||
|
version = "0.1.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-segmentation"
|
name = "unicode-segmentation"
|
||||||
version = "1.11.0"
|
version = "1.11.0"
|
||||||
@ -422,6 +656,23 @@ version = "0.1.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "url"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
|
||||||
|
dependencies = [
|
||||||
|
"form_urlencoded",
|
||||||
|
"idna",
|
||||||
|
"percent-encoding",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "valuable"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
|
@ -6,6 +6,8 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
color-eyre = "0.6.2"
|
||||||
crossterm = "0.27.0"
|
crossterm = "0.27.0"
|
||||||
eyre = "0.6.12"
|
eyre = "0.6.12"
|
||||||
ratatui = "0.26.1"
|
ratatui = "0.26.1"
|
||||||
|
url = "2.5.0"
|
||||||
|
63
src/app.rs
63
src/app.rs
@ -1,5 +1,6 @@
|
|||||||
use crossterm::event::Event;
|
use crossterm::event::Event;
|
||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
|
use ratatui::prelude::*;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::app_action::AppAction;
|
use crate::app_action::AppAction;
|
||||||
@ -8,7 +9,6 @@ use crate::component::Component;
|
|||||||
use crate::components;
|
use crate::components;
|
||||||
use crate::keys::key_commands::KeyCommand;
|
use crate::keys::key_commands::KeyCommand;
|
||||||
use crate::tui;
|
use crate::tui;
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
pub tui: tui::Tui,
|
pub tui: tui::Tui,
|
||||||
pub tick_rate: Duration,
|
pub tick_rate: Duration,
|
||||||
@ -22,50 +22,24 @@ impl App {
|
|||||||
pub fn new(tick_rate: Duration) -> Result<Self> {
|
pub fn new(tick_rate: Duration) -> Result<Self> {
|
||||||
let tui = tui::init()?;
|
let tui = tui::init()?;
|
||||||
|
|
||||||
let key_commands = vec![
|
|
||||||
KeyCommand {
|
|
||||||
key_code: "q".to_string(),
|
|
||||||
description: "Quit molehole".to_string(),
|
|
||||||
action: Some(AppAction::Quit),
|
|
||||||
},
|
|
||||||
KeyCommand {
|
|
||||||
key_code: "g".to_string(),
|
|
||||||
description: "Scroll to top".to_string(),
|
|
||||||
action: None,
|
|
||||||
},
|
|
||||||
KeyCommand {
|
|
||||||
key_code: "G".to_string(),
|
|
||||||
description: "Scroll to bottom".to_string(),
|
|
||||||
action: None,
|
|
||||||
},
|
|
||||||
KeyCommand {
|
|
||||||
key_code: "k".to_string(),
|
|
||||||
description: "Scroll up one line".to_string(),
|
|
||||||
action: None,
|
|
||||||
},
|
|
||||||
KeyCommand {
|
|
||||||
key_code: "j".to_string(),
|
|
||||||
description: "Scroll down one line".to_string(),
|
|
||||||
action: None,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
let global_keys = components::global_keys::GlobalKeys {
|
|
||||||
key_commands: key_commands.clone(),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
tui,
|
tui,
|
||||||
tick_rate,
|
tick_rate,
|
||||||
components: vec![Box::new(global_keys)],
|
|
||||||
key_commands,
|
|
||||||
|
|
||||||
should_quit: false,
|
should_quit: false,
|
||||||
|
components: vec![],
|
||||||
|
key_commands: vec![],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self) -> Result<()> {
|
pub fn run(&mut self) -> Result<()> {
|
||||||
|
let global_keys = components::global_keys::GlobalKeys {
|
||||||
|
key_commands: self.key_commands.clone(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let status_bar = components::status::StatusBar::default();
|
||||||
|
self.components = vec![Box::new(global_keys), Box::new(status_bar)];
|
||||||
|
|
||||||
for component in &mut self.components {
|
for component in &mut self.components {
|
||||||
component.init()?;
|
component.init()?;
|
||||||
}
|
}
|
||||||
@ -95,7 +69,7 @@ impl App {
|
|||||||
if let Some(event) = event {
|
if let Some(event) = event {
|
||||||
let mut actions: Vec<AppAction> = vec![];
|
let mut actions: Vec<AppAction> = vec![];
|
||||||
for component in &mut self.components {
|
for component in &mut self.components {
|
||||||
if let Some(action) = component.handle_event(event)? {
|
if let Some(action) = component.handle_event(event.clone())? {
|
||||||
actions.push(action);
|
actions.push(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,9 +84,18 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.tui.draw(|frame| {
|
self.tui.draw(|frame| {
|
||||||
for component in &mut self.components {
|
let layout = Layout::default()
|
||||||
let _ = component.render(frame, frame.size());
|
.direction(Direction::Vertical)
|
||||||
}
|
.constraints(vec![
|
||||||
|
Constraint::Percentage(100),
|
||||||
|
Constraint::Min(1),
|
||||||
|
])
|
||||||
|
.split(frame.size());
|
||||||
|
|
||||||
|
// status bar
|
||||||
|
let _ = self.components[1].render(frame, layout[1]);
|
||||||
|
// global_keys
|
||||||
|
let _ = self.components[0].render(frame, frame.size());
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,8 +1,25 @@
|
|||||||
#[derive(Default, Clone)]
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Default, Clone, Debug)]
|
||||||
pub enum AppAction {
|
pub enum AppAction {
|
||||||
StatusBarMessage(String),
|
StatusBarGetInput(String),
|
||||||
StatusBarError(String),
|
StatusBarSetMessage(String),
|
||||||
StatusBarInput(String),
|
StatusBarSetError(String),
|
||||||
|
OpenUrl,
|
||||||
|
|
||||||
|
ScrollUp,
|
||||||
|
ScrollDown,
|
||||||
|
ScrollTop,
|
||||||
|
ScrollBottom,
|
||||||
|
|
||||||
|
ShowHelpMenu,
|
||||||
|
|
||||||
#[default]
|
#[default]
|
||||||
Quit,
|
Quit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for AppAction {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{:?}", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
use crossterm::event::{KeyEvent, MouseEvent};
|
use crossterm::event::{KeyEvent, MouseEvent};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone)]
|
||||||
pub enum AppEvent {
|
pub enum AppEvent {
|
||||||
Key(KeyEvent),
|
Key(KeyEvent),
|
||||||
Mouse(MouseEvent),
|
Mouse(MouseEvent),
|
||||||
|
|
||||||
|
StatusBarInput(String),
|
||||||
|
OpenUrl(Url),
|
||||||
}
|
}
|
||||||
|
@ -24,60 +24,49 @@ pub struct GlobalKeys {
|
|||||||
|
|
||||||
impl Component for GlobalKeys {
|
impl Component for GlobalKeys {
|
||||||
fn init(&mut self) -> eyre::Result<()> {
|
fn init(&mut self) -> eyre::Result<()> {
|
||||||
self.key_commands.append(&mut vec![KeyCommand {
|
|
||||||
key_code: "?".to_string(),
|
|
||||||
description: "Toggle help menu".to_string(),
|
|
||||||
action: None,
|
|
||||||
}]);
|
|
||||||
|
|
||||||
self.scroll_state =
|
self.scroll_state =
|
||||||
ScrollbarState::new(self.key_commands.len()).position(self.scroll);
|
ScrollbarState::new(self.key_commands.len()).position(self.scroll);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_action(&mut self, action: AppAction) {
|
||||||
|
match action {
|
||||||
|
AppAction::ScrollUp => {
|
||||||
|
if self.scroll > 0 {
|
||||||
|
self.scroll -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AppAction::ScrollDown => {
|
||||||
|
if self.scroll < self.key_commands.len() - 1 {
|
||||||
|
self.scroll += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AppAction::ScrollTop => {
|
||||||
|
self.scroll = 0;
|
||||||
|
}
|
||||||
|
AppAction::ScrollBottom => {
|
||||||
|
self.scroll = self.key_commands.len() - 1;
|
||||||
|
}
|
||||||
|
AppAction::ShowHelpMenu => {
|
||||||
|
self.should_show = !self.should_show;
|
||||||
|
self.scroll = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
self.scroll_state = self.scroll_state.position(self.scroll);
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_key_event(
|
fn handle_key_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
key: KeyEvent,
|
key: KeyEvent,
|
||||||
) -> eyre::Result<Option<AppAction>> {
|
) -> eyre::Result<Option<AppAction>> {
|
||||||
if key.kind == KeyEventKind::Press {
|
if key.kind == KeyEventKind::Press {
|
||||||
let key_event = serialize_key_event(key);
|
let key_event = serialize_key_event(key);
|
||||||
let eat_input = match key_event.as_str() {
|
|
||||||
"?" => {
|
|
||||||
self.should_show = !self.should_show;
|
|
||||||
self.scroll = 0;
|
|
||||||
true
|
|
||||||
}
|
|
||||||
"g" => {
|
|
||||||
self.scroll = 0;
|
|
||||||
true
|
|
||||||
}
|
|
||||||
"G" => {
|
|
||||||
self.scroll = self.key_commands.len() - 1;
|
|
||||||
true
|
|
||||||
}
|
|
||||||
"down" | "j" => {
|
|
||||||
if self.scroll < self.key_commands.len() - 1 {
|
|
||||||
self.scroll += 1;
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
"up" | "k" => {
|
|
||||||
if self.scroll > 0 {
|
|
||||||
self.scroll -= 1;
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
self.scroll_state = self.scroll_state.position(self.scroll);
|
|
||||||
if eat_input && self.should_show {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
for key_command in &mut self.key_commands {
|
for key_command in &mut self.key_commands {
|
||||||
if key_command.key_code == key_event {
|
if key_command.key_code == key_event {
|
||||||
return Ok(key_command.action.clone());
|
return Ok(Some(key_command.action.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,7 +97,8 @@ impl Component for GlobalKeys {
|
|||||||
Title::from("Keyboard shortcuts").alignment(Alignment::Center),
|
Title::from("Keyboard shortcuts").alignment(Alignment::Center),
|
||||||
)
|
)
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.border_type(BorderType::Thick);
|
.border_type(BorderType::Thick)
|
||||||
|
.style(Style::default().bg(Color::DarkGray));
|
||||||
|
|
||||||
let mut lines: Vec<Line> = vec![];
|
let mut lines: Vec<Line> = vec![];
|
||||||
for key_command in &mut self.key_commands {
|
for key_command in &mut self.key_commands {
|
||||||
@ -124,8 +114,7 @@ impl Component for GlobalKeys {
|
|||||||
let commands = Paragraph::new(lines)
|
let commands = Paragraph::new(lines)
|
||||||
.block(block)
|
.block(block)
|
||||||
.wrap(Wrap { trim: true })
|
.wrap(Wrap { trim: true })
|
||||||
.scroll((u16::try_from(self.scroll)?, 0))
|
.scroll((u16::try_from(self.scroll)?, 0));
|
||||||
.style(Style::default().bg(Color::DarkGray).fg(Color::White));
|
|
||||||
|
|
||||||
if self.should_show {
|
if self.should_show {
|
||||||
frame.render_widget(Clear, center);
|
frame.render_widget(Clear, center);
|
||||||
|
@ -1 +1,2 @@
|
|||||||
pub mod global_keys;
|
pub mod global_keys;
|
||||||
|
pub mod status;
|
||||||
|
74
src/components/status.rs
Normal file
74
src/components/status.rs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
use ratatui::prelude::*;
|
||||||
|
use ratatui::widgets::*;
|
||||||
|
|
||||||
|
use crate::app_action::AppAction;
|
||||||
|
use crate::component::Component;
|
||||||
|
use crate::keys::key_commands::serialize_key_event;
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub struct StatusBar {
|
||||||
|
message: String,
|
||||||
|
current_key: String,
|
||||||
|
error: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for StatusBar {
|
||||||
|
fn handle_key_event(
|
||||||
|
&mut self,
|
||||||
|
key: crossterm::event::KeyEvent,
|
||||||
|
) -> eyre::Result<Option<AppAction>> {
|
||||||
|
let key_str = serialize_key_event(key);
|
||||||
|
self.current_key = key_str;
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_action(&mut self, action: crate::app_action::AppAction) {
|
||||||
|
match action {
|
||||||
|
AppAction::StatusBarSetMessage(message) => {
|
||||||
|
self.error = false;
|
||||||
|
self.message = message;
|
||||||
|
}
|
||||||
|
AppAction::StatusBarSetError(message) => {
|
||||||
|
self.error = true;
|
||||||
|
self.message = message;
|
||||||
|
}
|
||||||
|
AppAction::StatusBarGetInput(_prompt) => todo!(),
|
||||||
|
_ => {
|
||||||
|
self.current_key += " ";
|
||||||
|
self.current_key += &action.to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(
|
||||||
|
&mut self,
|
||||||
|
frame: &mut ratatui::prelude::Frame,
|
||||||
|
rect: ratatui::prelude::Rect,
|
||||||
|
) -> eyre::Result<()> {
|
||||||
|
let block =
|
||||||
|
Block::default().style(Style::default().bg(if self.error {
|
||||||
|
Color::Red
|
||||||
|
} else {
|
||||||
|
Color::DarkGray
|
||||||
|
}));
|
||||||
|
|
||||||
|
let layout = Layout::default()
|
||||||
|
.direction(Direction::Horizontal)
|
||||||
|
.constraints(vec![
|
||||||
|
Constraint::Percentage(50),
|
||||||
|
Constraint::Percentage(50),
|
||||||
|
])
|
||||||
|
.split(rect);
|
||||||
|
|
||||||
|
let message = Paragraph::new(self.message.clone()).block(block.clone());
|
||||||
|
let current_key = Paragraph::new(self.current_key.clone())
|
||||||
|
.block(block)
|
||||||
|
.alignment(Alignment::Right);
|
||||||
|
|
||||||
|
frame.render_widget(message, layout[0]);
|
||||||
|
frame.render_widget(current_key, layout[1]);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,7 @@ use crate::app_action::AppAction;
|
|||||||
pub struct KeyCommand {
|
pub struct KeyCommand {
|
||||||
pub key_code: String,
|
pub key_code: String,
|
||||||
pub description: String,
|
pub description: String,
|
||||||
pub action: Option<AppAction>,
|
pub action: AppAction,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for KeyCommand {
|
impl std::fmt::Display for KeyCommand {
|
||||||
|
45
src/main.rs
45
src/main.rs
@ -8,8 +8,53 @@ mod tui;
|
|||||||
|
|
||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
|
|
||||||
|
use app_action::AppAction;
|
||||||
|
use keys::key_commands::KeyCommand;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
tui::install_hooks()?;
|
||||||
let mut app = app::App::new(std::time::Duration::from_millis(10))?;
|
let mut app = app::App::new(std::time::Duration::from_millis(10))?;
|
||||||
|
let mut key_commands = vec![
|
||||||
|
// Status bar
|
||||||
|
KeyCommand {
|
||||||
|
key_code: "o".to_string(),
|
||||||
|
description: "Open new link".to_string(),
|
||||||
|
action: AppAction::OpenUrl,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Navigation
|
||||||
|
KeyCommand {
|
||||||
|
key_code: "g".to_string(),
|
||||||
|
description: "Scroll to top".to_string(),
|
||||||
|
action: AppAction::ScrollTop,
|
||||||
|
},
|
||||||
|
KeyCommand {
|
||||||
|
key_code: "G".to_string(),
|
||||||
|
description: "Scroll to bottom".to_string(),
|
||||||
|
action: AppAction::ScrollBottom,
|
||||||
|
},
|
||||||
|
KeyCommand {
|
||||||
|
key_code: "k".to_string(),
|
||||||
|
description: "Scroll up one line".to_string(),
|
||||||
|
action: AppAction::ScrollUp,
|
||||||
|
},
|
||||||
|
KeyCommand {
|
||||||
|
key_code: "j".to_string(),
|
||||||
|
description: "Scroll down one line".to_string(),
|
||||||
|
action: AppAction::ScrollDown,
|
||||||
|
},
|
||||||
|
KeyCommand {
|
||||||
|
key_code: "q".to_string(),
|
||||||
|
description: "Quit molehole".to_string(),
|
||||||
|
action: AppAction::Quit,
|
||||||
|
},
|
||||||
|
KeyCommand {
|
||||||
|
key_code: "?".to_string(),
|
||||||
|
description: "Show help menu".to_string(),
|
||||||
|
action: AppAction::ShowHelpMenu
|
||||||
|
}
|
||||||
|
];
|
||||||
|
app.key_commands.append(&mut key_commands);
|
||||||
|
|
||||||
app.run()
|
app.run()
|
||||||
}
|
}
|
||||||
|
19
src/tui.rs
19
src/tui.rs
@ -10,6 +10,7 @@ use crossterm::{event, execute};
|
|||||||
use ratatui::prelude::{CrosstermBackend, Terminal};
|
use ratatui::prelude::{CrosstermBackend, Terminal};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{stdout, Stdout};
|
use std::io::{stdout, Stdout};
|
||||||
|
use std::panic;
|
||||||
|
|
||||||
pub type Tui = Terminal<CrosstermBackend<Stdout>>;
|
pub type Tui = Terminal<CrosstermBackend<Stdout>>;
|
||||||
|
|
||||||
@ -41,3 +42,21 @@ pub fn get_event(tick: std::time::Duration) -> io::Result<Option<Event>> {
|
|||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn install_hooks() -> eyre::Result<()> {
|
||||||
|
let hook_builder = color_eyre::config::HookBuilder::default();
|
||||||
|
let (panic_hook, eyre_hook) = hook_builder.into_hooks();
|
||||||
|
|
||||||
|
let panic_hook = panic_hook.into_panic_hook();
|
||||||
|
panic::set_hook(Box::new(move |panic_info| {
|
||||||
|
restore().unwrap();
|
||||||
|
panic_hook(panic_info);
|
||||||
|
}));
|
||||||
|
|
||||||
|
let eyre_hook = eyre_hook.into_eyre_hook();
|
||||||
|
eyre::set_hook(Box::new(move |error| {
|
||||||
|
restore().unwrap();
|
||||||
|
eyre_hook(error)
|
||||||
|
}))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user