aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlukeflo2024-11-11 22:13:32 +0100
committerlukeflo2024-11-14 09:35:45 +0100
commit761ce14125f0e4ecffbfaf3bf82b4b406f5aa769 (patch)
treef78f106d93bfb2466f1d7785b3080eb4b0e333d9
parent45d85162e455db37f9263088a7703d614969b373 (diff)
downloadbibiman-761ce14125f0e4ecffbfaf3bf82b4b406f5aa769.tar.gz
bibiman-761ce14125f0e4ecffbfaf3bf82b4b406f5aa769.zip
impl popup for keybindings/messages
-rw-r--r--Cargo.lock555
-rw-r--r--Cargo.toml2
-rw-r--r--src/app.rs15
-rw-r--r--src/bibiman.rs28
-rw-r--r--src/bibiman/search.rs4
-rw-r--r--src/main.rs7
-rw-r--r--src/tui.rs3
-rw-r--r--src/tui/commands.rs4
-rw-r--r--src/tui/handler.rs197
-rw-r--r--src/tui/popup.rs104
-rw-r--r--src/tui/ui.rs36
11 files changed, 747 insertions, 208 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 0ee7ace..83fbcb4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -70,6 +70,12 @@ dependencies = [
]
[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
name = "bibiman"
version = "0.6.4"
dependencies = [
@@ -77,6 +83,7 @@ dependencies = [
"biblatex",
"color-eyre",
"crossterm",
+ "doi",
"editor-command",
"futures",
"itertools",
@@ -87,6 +94,7 @@ dependencies = [
"tokio",
"tokio-util",
"tui-input",
+ "tui-popup",
]
[[package]]
@@ -303,6 +311,52 @@ dependencies = [
]
[[package]]
+name = "darling"
+version = "0.20.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.20.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.20.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "derive-getters"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74ef43543e701c01ad77d3a5922755c6a1d71b22d942cb8042be4994b380caff"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "derive-new"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -314,6 +368,29 @@ dependencies = [
]
[[package]]
+name = "derive_setters"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e8ef033054e131169b8f0f9a7af8f5533a9436fadf3c500ed547f730f07090d"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "displaydoc"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "dlib"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -323,6 +400,24 @@ dependencies = [
]
[[package]]
+name = "document-features"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0"
+dependencies = [
+ "litrs",
+]
+
+[[package]]
+name = "doi"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "036cd0c9915dacb495b6124b728d1f70a6a9135ac1b00e92f9d2b8ef05459c00"
+dependencies = [
+ "ureq",
+]
+
+[[package]]
name = "downcast-rs"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -446,6 +541,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
name = "futures"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -545,6 +649,17 @@ dependencies = [
]
[[package]]
+name = "getrandom"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
name = "gimli"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -583,6 +698,151 @@ dependencies = [
]
[[package]]
+name = "icu_collections"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_locid_transform_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
+
+[[package]]
+name = "icu_normalizer"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "utf16_iter",
+ "utf8_iter",
+ "write16",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
+
+[[package]]
+name = "icu_properties"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_locid_transform",
+ "icu_properties_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
+
+[[package]]
+name = "icu_provider"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_provider_macros",
+ "stable_deref_trait",
+ "tinystr",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_provider_macros"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
+name = "idna"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
+dependencies = [
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
+]
+
+[[package]]
name = "image"
version = "0.25.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -677,6 +937,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]]
+name = "litemap"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704"
+
+[[package]]
+name = "litrs"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
+
+[[package]]
name = "lock_api"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -952,6 +1224,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
name = "petgraph"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1050,6 +1328,21 @@ dependencies = [
]
[[package]]
+name = "ring"
+version = "0.17.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "getrandom",
+ "libc",
+ "spin",
+ "untrusted",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
name = "rustc-demangle"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1069,6 +1362,38 @@ dependencies = [
]
[[package]]
+name = "rustls"
+version = "0.23.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e"
+dependencies = [
+ "log",
+ "once_cell",
+ "ring",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
+
+[[package]]
+name = "rustls-webpki"
+version = "0.102.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
+dependencies = [
+ "ring",
+ "rustls-pki-types",
+ "untrusted",
+]
+
+[[package]]
name = "rustversion"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1099,6 +1424,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
+name = "serde"
+version = "1.0.210"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.210"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.132"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
name = "sharded-slab"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1181,12 +1538,30 @@ dependencies = [
]
[[package]]
+name = "spin"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
+[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
name = "strum"
version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1209,6 +1584,12 @@ dependencies = [
]
[[package]]
+name = "subtle"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+
+[[package]]
name = "syn"
version = "2.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1220,6 +1601,17 @@ dependencies = [
]
[[package]]
+name = "synstructure"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "tempfile"
version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1274,6 +1666,16 @@ dependencies = [
]
[[package]]
+name = "tinystr"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
+dependencies = [
+ "displaydoc",
+ "zerovec",
+]
+
+[[package]]
name = "tinyvec"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1396,6 +1798,18 @@ dependencies = [
]
[[package]]
+name = "tui-popup"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9ee3d08800c83ba0a2efaec44d225bcc3f885f30e2b520a17e2cd962b7da6ab"
+dependencies = [
+ "derive-getters",
+ "derive_setters",
+ "document-features",
+ "ratatui",
+]
+
+[[package]]
name = "unicode-ident"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1446,6 +1860,53 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9df2af067a7953e9c3831320f35c1cc0600c30d44d9f7a12b01db1cd88d6b47"
[[package]]
+name = "untrusted"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
+
+[[package]]
+name = "ureq"
+version = "2.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a"
+dependencies = [
+ "base64",
+ "flate2",
+ "log",
+ "once_cell",
+ "rustls",
+ "rustls-pki-types",
+ "serde",
+ "serde_json",
+ "url",
+ "webpki-roots",
+]
+
+[[package]]
+name = "url"
+version = "2.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+]
+
+[[package]]
+name = "utf16_iter"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
+
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
+[[package]]
name = "valuable"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1531,6 +1992,15 @@ dependencies = [
]
[[package]]
+name = "webpki-roots"
+version = "0.26.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
name = "weezl"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1727,6 +2197,18 @@ dependencies = [
]
[[package]]
+name = "write16"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
+
+[[package]]
+name = "writeable"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
+
+[[package]]
name = "x11rb"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1742,3 +2224,76 @@ name = "x11rb-protocol"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d"
+
+[[package]]
+name = "yoke"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5"
+dependencies = [
+ "serde",
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
+
+[[package]]
+name = "zerovec"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
diff --git a/Cargo.toml b/Cargo.toml
index 8f8f9b1..485fe8e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,6 +14,7 @@ arboard = { version = "3.4.1", features = ["wayland-data-control"] }
biblatex = "0.10.0"
color-eyre = "0.6.3"
crossterm = { version = "0.28.1", features = ["event-stream"] }
+doi = "0.3.0"
editor-command = "0.1.1"
futures = "0.3.30"
itertools = "0.13.0"
@@ -24,3 +25,4 @@ signal-hook = "0.3.17"
tokio = { version = "1.39.3", features = ["full"] }
tokio-util = "0.7.12"
tui-input = "0.11.0"
+tui-popup = "0.6.0"
diff --git a/src/app.rs b/src/app.rs
index fe47882..c256542 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -19,6 +19,7 @@ use crate::bibiman::CurrentArea;
// use super::Event;
use crate::cliargs::CLIArgs;
use crate::tui::commands::{InputCmdAction, OpenRessource};
+use crate::tui::popup::PopupKind;
use crate::tui::{self, Tui};
use crate::{bibiman::Bibiman, tui::commands::CmdAction};
use color_eyre::eyre::{Ok, Result};
@@ -68,6 +69,11 @@ impl App {
// Event::Key(key_event) => handle_key_events(key_event, self, &mut tui)?,
// Event::Mouse(_) => {}
Event::Key(key_event) => {
+ if let Some(PopupKind::Message) = self.bibiman.popup_area.popup_kind {
+ self.bibiman.popup_area.popup_close_message()
+ } else if let Some(PopupKind::Help) = self.bibiman.popup_area.popup_kind {
+ self.bibiman.go_back()
+ }
let command = if self.input_mode {
CmdAction::Input(InputCmdAction::parse(key_event, &self.input))
} else {
@@ -187,6 +193,8 @@ impl App {
CmdAction::Confirm => {
if let CurrentArea::TagArea = self.bibiman.current_area {
self.bibiman.filter_for_tags();
+ } else if let CurrentArea::PopupArea = self.bibiman.current_area {
+ self.bibiman.go_back();
}
}
CmdAction::SortList => {
@@ -196,6 +204,10 @@ impl App {
}
CmdAction::YankItem => {
Bibiman::yank_text(&self.bibiman.get_selected_citekey());
+ self.bibiman.popup_area.popup_message(
+ "Yanked citekey to clipboard:",
+ self.bibiman.get_selected_citekey().to_string(),
+ );
}
CmdAction::EditFile => {
if let CurrentArea::EntryArea = self.bibiman.current_area {
@@ -215,6 +227,9 @@ impl App {
}
OpenRessource::Note => {}
},
+ CmdAction::ShowHelp => {
+ self.bibiman.show_help();
+ }
CmdAction::Exit => {
self.quit();
}
diff --git a/src/bibiman.rs b/src/bibiman.rs
index a573ee7..f3d9272 100644
--- a/src/bibiman.rs
+++ b/src/bibiman.rs
@@ -18,6 +18,7 @@
use crate::bibiman::entries::EntryTableColumn;
use crate::bibiman::{bibisetup::*, search::BibiSearch};
use crate::cliargs::CLIArgs;
+use crate::tui::popup::{PopupArea, PopupKind};
use crate::tui::Tui;
use crate::{bibiman::entries::EntryTable, bibiman::keywords::TagList};
use arboard::Clipboard;
@@ -40,6 +41,7 @@ pub enum CurrentArea {
EntryArea,
TagArea,
SearchArea,
+ PopupArea,
}
// Check which area was active when popup set active
@@ -69,6 +71,8 @@ pub struct Bibiman {
pub current_area: CurrentArea,
// mode for popup window
pub former_area: Option<FormerArea>,
+ // active popup
+ pub popup_area: PopupArea,
}
impl Bibiman {
@@ -89,9 +93,33 @@ impl Bibiman {
scroll_info: 0,
current_area,
former_area: None,
+ popup_area: PopupArea::default(),
})
}
+ pub fn show_help(&mut self) {
+ if let CurrentArea::EntryArea = self.current_area {
+ self.former_area = Some(FormerArea::EntryArea);
+ } else if let CurrentArea::TagArea = self.current_area {
+ self.former_area = Some(FormerArea::TagArea);
+ }
+ self.popup_area.is_popup = true;
+ self.current_area = CurrentArea::PopupArea;
+ self.popup_area.popup_kind = Some(PopupKind::Help);
+ }
+
+ pub fn go_back(&mut self) {
+ if let CurrentArea::PopupArea = self.current_area {
+ self.popup_area.is_popup = false;
+ self.popup_area.popup_kind = None;
+ if let Some(FormerArea::EntryArea) = self.former_area {
+ self.current_area = CurrentArea::EntryArea
+ } else if let Some(FormerArea::TagArea) = self.former_area {
+ self.current_area = CurrentArea::TagArea
+ }
+ };
+ }
+
pub fn update_lists(&mut self) {
self.main_biblio = BibiSetup::new(&self.main_bibfile);
self.tag_list = TagList::new(self.main_biblio.keyword_list.clone());
diff --git a/src/bibiman/search.rs b/src/bibiman/search.rs
index 362d0f9..896d1a4 100644
--- a/src/bibiman/search.rs
+++ b/src/bibiman/search.rs
@@ -139,8 +139,8 @@ mod tests {
keywords: "hello, bye".to_string(),
citekey: "author_1999".to_string(),
abstract_text: "An abstract with multiple sentences. Here is the second".to_string(),
- doi_url: "https://www.bibiman.org".to_string(),
- filepath: "/home/file/path.pdf".to_string(),
+ doi_url: Some("https://www.bibiman.org".to_string()),
+ filepath: Some("/home/file/path.pdf".to_string()),
subtitle: None,
};
diff --git a/src/main.rs b/src/main.rs
index c2c5121..8a78d62 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -26,6 +26,13 @@ pub mod cliargs;
pub mod errorsetup;
pub mod tui;
+// Color indices
+const MAIN_BLUE_COLOR_INDEX: u8 = 75;
+const MAIN_PURPLE_COLOR_INDEX: u8 = 135;
+const MAIN_GREEN_COLOR_INDEX: u8 = 29;
+const TEXT_HIGHLIGHT_COLOR_INDEX: u8 = 254;
+const TEXT_FG_COLOR_INDEX: u8 = 250;
+
#[tokio::main]
async fn main() -> Result<()> {
// Parse CLI arguments
diff --git a/src/tui.rs b/src/tui.rs
index 963abf9..ba43b2e 100644
--- a/src/tui.rs
+++ b/src/tui.rs
@@ -15,9 +15,8 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
/////
-// pub mod command;
pub mod commands;
-// pub mod handler;
+pub mod popup;
pub mod ui;
use crate::App;
diff --git a/src/tui/commands.rs b/src/tui/commands.rs
index dc6b2c8..6a2ab13 100644
--- a/src/tui/commands.rs
+++ b/src/tui/commands.rs
@@ -67,6 +67,8 @@ pub enum CmdAction {
Input(InputCmdAction),
// Hexdump command.
Exit,
+ // Show keybindings
+ ShowHelp,
// Do nothing.
Nothing,
}
@@ -148,6 +150,8 @@ impl From<KeyEvent> for CmdAction {
KeyCode::Char('y') => Self::YankItem,
// Sort entry table by selected col
KeyCode::Char('s') => Self::SortList,
+ // Show help popup
+ KeyCode::Char('?') => Self::ShowHelp,
// Else do nothing
_ => Self::Nothing,
}
diff --git a/src/tui/handler.rs b/src/tui/handler.rs
deleted file mode 100644
index ae2fd4d..0000000
--- a/src/tui/handler.rs
+++ /dev/null
@@ -1,197 +0,0 @@
-// bibiman - a TUI for managing BibLaTeX databases
-// Copyright (C) 2024 lukeflo
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-/////
-
-use crate::bibiman::{Bibiman, CurrentArea};
-use crate::tui::Tui;
-use crate::App;
-use color_eyre::eyre::Result;
-use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
-
-/// Handles the key events and updates the state of [`App`].
-pub fn handle_key_events(key_event: KeyEvent, app: &mut App, tui: &mut Tui) -> Result<()> {
- // Keycodes activated for every area (high priority)
- match key_event.code {
- // Exit application on `ESC` or `q`
- KeyCode::Char('Q') | KeyCode::Char('q') => {
- app.quit();
- }
- // Exit application on `Ctrl-C`
- KeyCode::Char('c') | KeyCode::Char('C') => {
- if key_event.modifiers == KeyModifiers::CONTROL {
- app.quit();
- }
- }
- KeyCode::PageDown => {
- app.bibiman.scroll_info_down();
- }
- KeyCode::PageUp => {
- app.bibiman.scroll_info_up();
- }
- _ => {}
- }
- // Keycodes for specific areas
- match app.bibiman.current_area {
- // Keycodes for the tag area
- CurrentArea::TagArea => match key_event.code {
- KeyCode::Down => {
- app.bibiman.select_next_tag(1);
- }
- KeyCode::Up => {
- app.bibiman.select_previous_tag(1);
- }
- KeyCode::Char('j') => {
- if key_event.modifiers == KeyModifiers::ALT {
- app.bibiman.scroll_info_down();
- } else {
- app.bibiman.select_next_tag(1);
- }
- }
- KeyCode::Char('k') => {
- if key_event.modifiers == KeyModifiers::ALT {
- app.bibiman.scroll_info_up();
- } else {
- app.bibiman.select_previous_tag(1);
- }
- }
- KeyCode::Char('d') => {
- if key_event.modifiers == KeyModifiers::CONTROL {
- app.bibiman.select_next_tag(5)
- }
- }
- KeyCode::Char('u') => {
- if key_event.modifiers == KeyModifiers::CONTROL {
- app.bibiman.select_previous_tag(5)
- }
- }
- KeyCode::Char('g') | KeyCode::Home => {
- app.bibiman.select_first_tag();
- }
- KeyCode::Char('G') | KeyCode::End => {
- app.bibiman.select_last_tag();
- }
- KeyCode::Char('/') => {
- app.bibiman.enter_search_area();
- }
- KeyCode::Char('f') | KeyCode::Char('F') => {
- if key_event.modifiers == KeyModifiers::CONTROL {
- app.bibiman.enter_search_area();
- }
- }
- KeyCode::Tab | KeyCode::BackTab => {
- app.bibiman.toggle_area();
- }
- KeyCode::Esc => {
- app.bibiman.reset_current_list();
- }
- KeyCode::Enter => {
- app.bibiman.filter_for_tags();
- }
- _ => {}
- },
- // Keycodes for the entry area
- CurrentArea::EntryArea => match key_event.code {
- KeyCode::Down => {
- app.bibiman.select_next_entry(1);
- }
- KeyCode::Up => {
- app.bibiman.select_previous_entry(1);
- }
- KeyCode::Char('j') => {
- if key_event.modifiers == KeyModifiers::ALT {
- app.bibiman.scroll_info_down();
- } else {
- app.bibiman.select_next_entry(1);
- }
- }
- KeyCode::Char('k') => {
- if key_event.modifiers == KeyModifiers::ALT {
- app.bibiman.scroll_info_up();
- } else {
- app.bibiman.select_previous_entry(1);
- }
- }
- KeyCode::Char('d') => {
- if key_event.modifiers == KeyModifiers::CONTROL {
- app.bibiman.select_next_entry(5);
- }
- }
- KeyCode::Char('u') => {
- if key_event.modifiers == KeyModifiers::CONTROL {
- app.bibiman.select_previous_entry(5);
- } else {
- app.bibiman.open_doi_url()?;
- }
- }
- KeyCode::Char('g') | KeyCode::Home => {
- app.bibiman.select_first_entry();
- }
- KeyCode::Char('G') | KeyCode::End => {
- app.bibiman.select_last_entry();
- }
- KeyCode::Char('h') => {
- app.bibiman.select_prev_column();
- }
- KeyCode::Char('l') => {
- app.bibiman.select_next_column();
- }
- KeyCode::Char('s') => {
- app.bibiman.entry_table.sort_entry_table(true);
- }
- KeyCode::Char('y') => {
- Bibiman::yank_text(&app.bibiman.get_selected_citekey());
- }
- KeyCode::Char('e') => {
- app.bibiman.run_editor(tui)?;
- }
- KeyCode::Char('o') => {
- app.bibiman.open_connected_file()?;
- }
- KeyCode::Char('/') => {
- app.bibiman.enter_search_area();
- }
- KeyCode::Char('f') | KeyCode::Char('F') => {
- if key_event.modifiers == KeyModifiers::CONTROL {
- app.bibiman.enter_search_area();
- }
- }
- KeyCode::Tab | KeyCode::BackTab => {
- app.bibiman.toggle_area();
- }
- KeyCode::Esc => {
- app.bibiman.reset_current_list();
- }
- _ => {}
- },
- // Keycodes for the search area (rendered in footer)
- CurrentArea::SearchArea => match key_event.code {
- KeyCode::Esc => {
- app.bibiman.break_search();
- }
- KeyCode::Enter => {
- app.bibiman.confirm_search();
- }
- KeyCode::Backspace => {
- app.bibiman.search_pattern_pop();
- }
- KeyCode::Char(search_pattern) => {
- app.bibiman.search_pattern_push(search_pattern);
- }
- _ => {}
- },
- }
- Ok(())
-}
diff --git a/src/tui/popup.rs b/src/tui/popup.rs
new file mode 100644
index 0000000..60c58b4
--- /dev/null
+++ b/src/tui/popup.rs
@@ -0,0 +1,104 @@
+// bibiman - a TUI for managing BibLaTeX databases
+// Copyright (C) 2024 lukeflo
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+/////
+
+use ratatui::{
+ style::{Color, Stylize},
+ text::{Line, Span, Text},
+ widgets::ListState,
+};
+
+use crate::MAIN_PURPLE_COLOR_INDEX;
+
+#[derive(Debug)]
+pub enum PopupKind {
+ Help,
+ Message,
+ Selection,
+}
+
+#[derive(Debug)]
+pub struct PopupArea {
+ pub is_popup: bool,
+ pub popup_kind: Option<PopupKind>,
+ pub popup_message: String,
+ pub popup_list: Vec<String>,
+ pub popup_state: ListState,
+}
+
+impl Default for PopupArea {
+ fn default() -> Self {
+ PopupArea {
+ is_popup: false,
+ popup_kind: None,
+ popup_message: String::new(),
+ popup_list: Vec::new(),
+ popup_state: ListState::default(),
+ }
+ }
+}
+
+impl PopupArea {
+ pub fn popup_help<'a>() -> Text<'a> {
+ let help = [
+ ("j,k|↓,↑: ", "Select next/previous item"),
+ ("h,l|←,→: ", "Select next/previous column (Entry table)"),
+ ("g|Home: ", "Go to first item"),
+ ("G|End: ", "Go to last item"),
+ ("s: ", "sort entries by selected column (toggles reversed)"),
+ ("TAB: ", "Toggle areas (Entries, Keywords)"),
+ ("/|Ctrl+f: ", "Enter search mode"),
+ ("y: ", "yank/copy citekey of selected entry to clipboard"),
+ ("e: ", "Open editor at selected entry"),
+ ("o: ", "Open with selected entry associated PDF"),
+ ("u: ", "Open DOI/URL of selected entry"),
+ ("ESC: ", "Reset all lists/abort search"),
+ ("ENTER: ", "Confirm search/filter by selected keyword"),
+ ("q|Ctrl+c: ", "Quit bibiman"),
+ ];
+
+ let help_text: Vec<Line<'_>> = help
+ .into_iter()
+ .map(|(keys, help)| {
+ Line::from(vec![
+ Span::raw(keys)
+ .bold()
+ .fg(Color::Indexed(MAIN_PURPLE_COLOR_INDEX)),
+ Span::raw(help),
+ ])
+ })
+ .collect();
+
+ let text = Text::from(help_text);
+ text
+ }
+
+ pub fn popup_message(&mut self, message: &str, object: String) {
+ if object.is_empty() {
+ self.popup_message = message.into();
+ } else {
+ self.popup_message = format!("{} \"{}\"", message, object);
+ }
+ self.popup_kind = Some(PopupKind::Message);
+ self.is_popup = true;
+ }
+
+ pub fn popup_close_message(&mut self) {
+ self.is_popup = false;
+ self.popup_message.clear();
+ self.popup_kind = None
+ }
+}
diff --git a/src/tui/ui.rs b/src/tui/ui.rs
index f2091a5..260f401 100644
--- a/src/tui/ui.rs
+++ b/src/tui/ui.rs
@@ -15,9 +15,15 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
/////
+use super::popup::PopupArea;
use crate::bibiman::entries::EntryTableColumn;
use crate::bibiman::{CurrentArea, FormerArea};
+use crate::tui::popup::PopupKind;
use crate::App;
+use crate::{
+ MAIN_BLUE_COLOR_INDEX, MAIN_GREEN_COLOR_INDEX, MAIN_PURPLE_COLOR_INDEX, TEXT_FG_COLOR_INDEX,
+ TEXT_HIGHLIGHT_COLOR_INDEX,
+};
use ratatui::layout::{Direction, Position};
use ratatui::widgets::Clear;
use ratatui::Frame;
@@ -31,13 +37,7 @@ use ratatui::{
ScrollbarOrientation, Table, Wrap,
},
};
-
-// Color indices
-const MAIN_BLUE_COLOR_INDEX: u8 = 75;
-const MAIN_PURPLE_COLOR_INDEX: u8 = 135;
-const MAIN_GREEN_COLOR_INDEX: u8 = 29;
-const TEXT_HIGHLIGHT_COLOR_INDEX: u8 = 254;
-const TEXT_FG_COLOR_INDEX: u8 = 250;
+use tui_popup::Popup;
// Text colors
const TEXT_FG_COLOR: Color = Color::Indexed(TEXT_FG_COLOR_INDEX);
@@ -48,6 +48,7 @@ const MAIN_GREEN: Color = Color::Indexed(MAIN_GREEN_COLOR_INDEX);
// Background colors
const HEADER_FOOTER_BG: Color = Color::Indexed(235);
+const POPUP_BG: Color = Color::Indexed(233);
// Box styles
// Keyword Box
@@ -72,6 +73,8 @@ const BOX_SELECTED_TITLE_STYLE: Style = Style::new()
const BOX_UNSELECTED_BORDER_STYLE: Style = Style::new().fg(TEXT_FG_COLOR);
const BOX_UNSELECTED_TITLE_STYLE: Style =
Style::new().fg(TEXT_FG_COLOR).add_modifier(Modifier::BOLD);
+// Popup box
+const POPUP_HELP_BOX: Style = Style::new().fg(TEXT_FG_COLOR).bg(POPUP_BG);
// Entry table styles
const ENTRY_SELECTED_ROW_STYLE: Style = Style::new()
@@ -142,6 +145,25 @@ pub fn render_ui(app: &mut App, frame: &mut Frame) {
render_selected_item(app, frame, info_area);
render_taglist(app, frame, tag_area);
render_file_info(app, frame, entry_info_area);
+ if app.bibiman.popup_area.is_popup {
+ render_popup(app, frame);
+ }
+}
+
+pub fn render_popup(app: &mut App, frame: &mut Frame) {
+ let popup = if let Some(PopupKind::Help) = app.bibiman.popup_area.popup_kind {
+ Popup::new(PopupArea::popup_help())
+ .title(" Keybindings ".bold().into_centered_line())
+ .style(POPUP_HELP_BOX)
+ .border_style(Style::new().fg(MAIN_BLUE))
+ } else if let Some(PopupKind::Message) = app.bibiman.popup_area.popup_kind {
+ Popup::new(Text::from(app.bibiman.popup_area.popup_message.as_str()).fg(MAIN_GREEN))
+ .title(" Message ".bold().into_centered_line().fg(MAIN_GREEN))
+ .style(POPUP_HELP_BOX)
+ } else {
+ panic!("No popup text detected")
+ };
+ frame.render_widget(&popup, frame.area())
}
pub fn render_header(frame: &mut Frame, rect: Rect) {