improve doc and restructure a bit
This commit is contained in:
parent
bb4dcb6908
commit
88c2cfbd8e
6 changed files with 236 additions and 649 deletions
445
Cargo.lock
generated
445
Cargo.lock
generated
|
@ -2,34 +2,6 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "addr2line"
|
|
||||||
version = "0.24.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
|
|
||||||
dependencies = [
|
|
||||||
"gimli",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "adler2"
|
|
||||||
version = "2.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ahash"
|
|
||||||
version = "0.8.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"once_cell",
|
|
||||||
"serde",
|
|
||||||
"version_check",
|
|
||||||
"zerocopy",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
|
@ -75,7 +47,7 @@ version = "1.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -86,7 +58,7 @@ checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -95,28 +67,6 @@ version = "1.0.97"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
|
checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-stream"
|
|
||||||
version = "0.3.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
|
|
||||||
dependencies = [
|
|
||||||
"async-stream-impl",
|
|
||||||
"futures-core",
|
|
||||||
"pin-project-lite",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-stream-impl"
|
|
||||||
version = "0.3.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
|
@ -134,21 +84,6 @@ version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "backtrace"
|
|
||||||
version = "0.3.74"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
|
|
||||||
dependencies = [
|
|
||||||
"addr2line",
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"miniz_oxide",
|
|
||||||
"object",
|
|
||||||
"rustc-demangle",
|
|
||||||
"windows-targets",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
|
@ -161,12 +96,6 @@ version = "2.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bytes"
|
|
||||||
version = "1.10.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cairo-rs"
|
name = "cairo-rs"
|
||||||
version = "0.20.7"
|
version = "0.20.7"
|
||||||
|
@ -333,27 +262,6 @@ version = "0.8.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "derive_more"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05"
|
|
||||||
dependencies = [
|
|
||||||
"derive_more-impl",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "derive_more-impl"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"unicode-xid",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs"
|
name = "dirs"
|
||||||
version = "6.0.0"
|
version = "6.0.0"
|
||||||
|
@ -372,7 +280,7 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"option-ext",
|
"option-ext",
|
||||||
"redox_users",
|
"redox_users",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -423,7 +331,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
|
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -458,21 +366,6 @@ dependencies = [
|
||||||
"xdgkit",
|
"xdgkit",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures"
|
|
||||||
version = "0.3.31"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
|
|
||||||
dependencies = [
|
|
||||||
"futures-channel",
|
|
||||||
"futures-core",
|
|
||||||
"futures-executor",
|
|
||||||
"futures-io",
|
|
||||||
"futures-sink",
|
|
||||||
"futures-task",
|
|
||||||
"futures-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.31"
|
version = "0.3.31"
|
||||||
|
@ -480,7 +373,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
|
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -506,16 +398,6 @@ version = "0.3.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
|
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-lite"
|
|
||||||
version = "2.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532"
|
|
||||||
dependencies = [
|
|
||||||
"futures-core",
|
|
||||||
"pin-project-lite",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-macro"
|
name = "futures-macro"
|
||||||
version = "0.3.31"
|
version = "0.3.31"
|
||||||
|
@ -527,12 +409,6 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-sink"
|
|
||||||
version = "0.3.31"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-task"
|
name = "futures-task"
|
||||||
version = "0.3.31"
|
version = "0.3.31"
|
||||||
|
@ -545,13 +421,9 @@ version = "0.3.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-channel",
|
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
|
||||||
"futures-macro",
|
"futures-macro",
|
||||||
"futures-sink",
|
|
||||||
"futures-task",
|
"futures-task",
|
||||||
"memchr",
|
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"pin-utils",
|
"pin-utils",
|
||||||
"slab",
|
"slab",
|
||||||
|
@ -626,12 +498,6 @@ dependencies = [
|
||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "gimli"
|
|
||||||
version = "0.31.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gio"
|
name = "gio"
|
||||||
version = "0.20.9"
|
version = "0.20.9"
|
||||||
|
@ -659,7 +525,7 @@ dependencies = [
|
||||||
"gobject-sys",
|
"gobject-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"system-deps",
|
"system-deps",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -898,39 +764,6 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hyprland"
|
|
||||||
version = "0.4.0-beta.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dc9c1413b6f0fd10b2e4463479490e30b2497ae4449f044da16053f5f2cb03b8"
|
|
||||||
dependencies = [
|
|
||||||
"ahash",
|
|
||||||
"async-stream",
|
|
||||||
"derive_more",
|
|
||||||
"either",
|
|
||||||
"futures-lite",
|
|
||||||
"hyprland-macros",
|
|
||||||
"num-traits",
|
|
||||||
"once_cell",
|
|
||||||
"paste",
|
|
||||||
"phf",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"serde_repr",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hyprland-macros"
|
|
||||||
version = "0.4.0-beta.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "69e3cbed6e560408051175d29a9ed6ad1e64a7ff443836addf797b0479f58983"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.9.3"
|
version = "1.9.3"
|
||||||
|
@ -1021,16 +854,6 @@ version = "0.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lock_api"
|
|
||||||
version = "0.4.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"scopeguard",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.27"
|
version = "0.4.27"
|
||||||
|
@ -1068,26 +891,6 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "miniz_oxide"
|
|
||||||
version = "0.8.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430"
|
|
||||||
dependencies = [
|
|
||||||
"adler2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mio"
|
|
||||||
version = "1.0.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"wasi",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "1.2.4"
|
version = "1.2.4"
|
||||||
|
@ -1104,24 +907,6 @@ dependencies = [
|
||||||
"minimal-lexical",
|
"minimal-lexical",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-traits"
|
|
||||||
version = "0.2.19"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "object"
|
|
||||||
version = "0.36.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.21.3"
|
version = "1.21.3"
|
||||||
|
@ -1164,35 +949,6 @@ dependencies = [
|
||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parking_lot"
|
|
||||||
version = "0.12.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
|
|
||||||
dependencies = [
|
|
||||||
"lock_api",
|
|
||||||
"parking_lot_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parking_lot_core"
|
|
||||||
version = "0.9.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"redox_syscall",
|
|
||||||
"smallvec",
|
|
||||||
"windows-targets",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "paste"
|
|
||||||
version = "1.0.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "petgraph"
|
name = "petgraph"
|
||||||
version = "0.6.5"
|
version = "0.6.5"
|
||||||
|
@ -1203,48 +959,6 @@ dependencies = [
|
||||||
"indexmap 2.9.0",
|
"indexmap 2.9.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf"
|
|
||||||
version = "0.11.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
|
|
||||||
dependencies = [
|
|
||||||
"phf_macros",
|
|
||||||
"phf_shared",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf_generator"
|
|
||||||
version = "0.11.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
|
|
||||||
dependencies = [
|
|
||||||
"phf_shared",
|
|
||||||
"rand",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf_macros"
|
|
||||||
version = "0.11.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216"
|
|
||||||
dependencies = [
|
|
||||||
"phf_generator",
|
|
||||||
"phf_shared",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf_shared"
|
|
||||||
version = "0.11.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
|
|
||||||
dependencies = [
|
|
||||||
"siphasher",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
|
@ -1315,21 +1029,6 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand"
|
|
||||||
version = "0.8.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
|
||||||
dependencies = [
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_core"
|
|
||||||
version = "0.6.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon"
|
name = "rayon"
|
||||||
version = "1.10.0"
|
version = "1.10.0"
|
||||||
|
@ -1350,15 +1049,6 @@ dependencies = [
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "redox_syscall"
|
|
||||||
version = "0.5.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.9.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_users"
|
name = "redox_users"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
@ -1399,12 +1089,6 @@ version = "0.8.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustc-demangle"
|
|
||||||
version = "0.1.24"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
@ -1424,7 +1108,7 @@ dependencies = [
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1433,12 +1117,6 @@ version = "1.0.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scopeguard"
|
|
||||||
version = "1.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.26"
|
version = "1.0.26"
|
||||||
|
@ -1477,17 +1155,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_repr"
|
|
||||||
version = "0.1.20"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_spanned"
|
name = "serde_spanned"
|
||||||
version = "0.6.8"
|
version = "0.6.8"
|
||||||
|
@ -1497,21 +1164,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "signal-hook-registry"
|
|
||||||
version = "1.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "siphasher"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
|
@ -1527,16 +1179,6 @@ version = "1.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "socket2"
|
|
||||||
version = "0.5.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
|
@ -1620,35 +1262,6 @@ version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e004df4c5f0805eb5f55883204a514cfa43a6d924741be29e871753a53d5565a"
|
checksum = "e004df4c5f0805eb5f55883204a514cfa43a6d924741be29e871753a53d5565a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio"
|
|
||||||
version = "1.44.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
|
|
||||||
dependencies = [
|
|
||||||
"backtrace",
|
|
||||||
"bytes",
|
|
||||||
"libc",
|
|
||||||
"mio",
|
|
||||||
"parking_lot",
|
|
||||||
"pin-project-lite",
|
|
||||||
"signal-hook-registry",
|
|
||||||
"socket2",
|
|
||||||
"tokio-macros",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio-macros"
|
|
||||||
version = "2.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.8.20"
|
version = "0.8.20"
|
||||||
|
@ -1702,12 +1315,6 @@ version = "1.0.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-xid"
|
|
||||||
version = "0.2.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8parse"
|
name = "utf8parse"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
@ -1720,12 +1327,6 @@ version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
|
checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "version_check"
|
|
||||||
version = "0.9.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
@ -1766,7 +1367,7 @@ version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1775,15 +1376,6 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.59.0"
|
version = "0.59.0"
|
||||||
|
@ -1882,11 +1474,9 @@ dependencies = [
|
||||||
"dirs",
|
"dirs",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"freedesktop-file-parser",
|
"freedesktop-file-parser",
|
||||||
"futures",
|
|
||||||
"gdk4",
|
"gdk4",
|
||||||
"gtk4",
|
"gtk4",
|
||||||
"gtk4-layer-shell",
|
"gtk4-layer-shell",
|
||||||
"hyprland",
|
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"meval",
|
"meval",
|
||||||
|
@ -1896,7 +1486,6 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"strsim 0.11.1",
|
"strsim 0.11.1",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
|
||||||
"toml",
|
"toml",
|
||||||
"tree_magic_mini",
|
"tree_magic_mini",
|
||||||
"which",
|
"which",
|
||||||
|
@ -1928,23 +1517,3 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"linked-hash-map",
|
"linked-hash-map",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerocopy"
|
|
||||||
version = "0.7.35"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
|
||||||
dependencies = [
|
|
||||||
"zerocopy-derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerocopy-derive"
|
|
||||||
version = "0.7.35"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
|
@ -21,6 +21,9 @@ name = "worf"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
no-deps = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
gtk4 = { version = "0.9.5", default-features = true, features = ["v4_6"] }
|
gtk4 = { version = "0.9.5", default-features = true, features = ["v4_6"] }
|
||||||
gtk4-layer-shell = "0.5.0"
|
gtk4-layer-shell = "0.5.0"
|
||||||
|
@ -29,7 +32,6 @@ anyhow = "1.0.97"
|
||||||
env_logger = "0.11.8"
|
env_logger = "0.11.8"
|
||||||
log = "0.4.27"
|
log = "0.4.27"
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
hyprland = "0.4.0-beta.2"
|
|
||||||
clap = { version = "4.5.35", features = ["derive"] }
|
clap = { version = "4.5.35", features = ["derive"] }
|
||||||
thiserror = "2.0.12"
|
thiserror = "2.0.12"
|
||||||
serde = { version = "1.0.219", features = ["derive"] }
|
serde = { version = "1.0.219", features = ["derive"] }
|
||||||
|
@ -44,5 +46,3 @@ which = "7.0.3"
|
||||||
meval = "0.2.0"
|
meval = "0.2.0"
|
||||||
tree_magic_mini = "3.1.6"
|
tree_magic_mini = "3.1.6"
|
||||||
rayon = "1.10.0"
|
rayon = "1.10.0"
|
||||||
tokio = { version = "1.44.2", features = ["full"] }
|
|
||||||
futures = "0.3.31"
|
|
||||||
|
|
|
@ -1,63 +1,17 @@
|
||||||
use std::collections::HashMap;
|
use crate::Error;
|
||||||
use std::path::Path;
|
use crate::config::expand_path;
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::time::Instant;
|
|
||||||
use std::{env, fs};
|
|
||||||
|
|
||||||
use freedesktop_file_parser::DesktopFile;
|
use freedesktop_file_parser::DesktopFile;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::os::unix::prelude::CommandExt;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::{Command, Stdio};
|
||||||
|
use std::time::Instant;
|
||||||
|
use std::{env, fs, io};
|
||||||
|
|
||||||
#[derive(Debug)]
|
/// Returns a regex with supported image extensions
|
||||||
pub enum DesktopError {
|
|
||||||
MissingIcon,
|
|
||||||
ParsingError(String),
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// /// # Errors
|
|
||||||
// ///
|
|
||||||
// /// Will return `Err` if no icon can be found
|
|
||||||
// pub fn default_icon() -> Result<String, DesktopError> {
|
|
||||||
// fetch_icon_from_theme("image-missing").map_err(|_| DesktopError::MissingIcon)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fn fetch_icon_from_theme(icon_name: &str) -> Result<String, DesktopError> {
|
|
||||||
// let display = Display::default();
|
|
||||||
// if display.is_none() {
|
|
||||||
// log::error!("Failed to get display");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// let display = Display::default().expect("Failed to get default display");
|
|
||||||
// let theme = IconTheme::for_display(&display);
|
|
||||||
//
|
|
||||||
// let icon = theme.lookup_icon(
|
|
||||||
// icon_name,
|
|
||||||
// &[],
|
|
||||||
// 32,
|
|
||||||
// 1,
|
|
||||||
// TextDirection::None,
|
|
||||||
// IconLookupFlags::empty(),
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// match icon
|
|
||||||
// .file()
|
|
||||||
// .and_then(|file| file.path())
|
|
||||||
// .and_then(|path| path.to_str().map(string::ToString::to_string))
|
|
||||||
// {
|
|
||||||
// None => {
|
|
||||||
// let path = PathBuf::from("/usr/share/icons")
|
|
||||||
// .join(theme.theme_name())
|
|
||||||
// .join(format!("{icon_name}.svg"));
|
|
||||||
// if path.exists() {
|
|
||||||
// Ok(path.display().to_string())
|
|
||||||
// } else {
|
|
||||||
// Err(DesktopError::MissingIcon)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// Some(i) => Ok(i),
|
|
||||||
// }
|
|
||||||
// }use futures::StreamExt;
|
|
||||||
|
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// When it cannot parse the internal regex
|
/// When it cannot parse the internal regex
|
||||||
|
@ -67,11 +21,16 @@ pub fn known_image_extension_regex_pattern() -> Regex {
|
||||||
.expect("Internal image regex is not valid anymore.")
|
.expect("Internal image regex is not valid anymore.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read an icon from a shared directory
|
||||||
|
/// * /usr/local/share/icon
|
||||||
|
/// * /usr/share/icons
|
||||||
|
/// * /usr/share/pixmaps
|
||||||
|
/// * $HOME/.local/share/icon (if exists)
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Will return `Err`
|
/// Will return `Err`
|
||||||
/// * if it was not able to find any icon
|
/// * if it was not able to find any icon
|
||||||
pub fn fetch_icon_from_common_dirs(icon_name: &str) -> Result<String, DesktopError> {
|
pub fn fetch_icon_from_common_dirs(icon_name: &str) -> Result<String, Error> {
|
||||||
let mut paths = vec![
|
let mut paths = vec![
|
||||||
PathBuf::from("/usr/local/share/icons"),
|
PathBuf::from("/usr/local/share/icons"),
|
||||||
PathBuf::from("/usr/share/icons"),
|
PathBuf::from("/usr/share/icons"),
|
||||||
|
@ -88,19 +47,20 @@ pub fn fetch_icon_from_common_dirs(icon_name: &str) -> Result<String, DesktopErr
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|dir| dir.exists())
|
.filter(|dir| dir.exists())
|
||||||
.find_map(|dir| {
|
.find_map(|dir| {
|
||||||
find_file_case_insensitive(dir.as_path(), &formatted_name)
|
find_file_via_regex(dir.as_path(), &formatted_name)
|
||||||
.and_then(|files| files.first().map(|f| f.to_string_lossy().into_owned()))
|
.and_then(|files| files.first().map(|f| f.to_string_lossy().into_owned()))
|
||||||
})
|
})
|
||||||
.ok_or(DesktopError::MissingIcon)
|
.ok_or(Error::MissingIcon)
|
||||||
} else {
|
} else {
|
||||||
Err(DesktopError::ParsingError(
|
Err(Error::ParsingError(
|
||||||
"Failed to get formatted icon, likely the internal regex did not parse properly"
|
"Failed to get formatted icon, likely the internal regex did not parse properly"
|
||||||
.to_string(),
|
.to_string(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_file_case_insensitive(folder: &Path, file_name: &Regex) -> Option<Vec<PathBuf>> {
|
/// Helper function to retrieve a file with given regex.
|
||||||
|
fn find_file_via_regex(folder: &Path, file_name: &Regex) -> Option<Vec<PathBuf>> {
|
||||||
if !folder.exists() || !folder.is_dir() {
|
if !folder.exists() || !folder.is_dir() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -119,6 +79,10 @@ fn find_file_case_insensitive(folder: &Path, file_name: &Regex) -> Option<Vec<Pa
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse all desktop files in known locations
|
||||||
|
/// * /usr/share/applications
|
||||||
|
/// * /usr/local/share/applications
|
||||||
|
/// * /var/lib/flatpak/exports/share/applications
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// When it cannot parse the internal regex
|
/// When it cannot parse the internal regex
|
||||||
|
@ -151,7 +115,7 @@ pub fn find_desktop_files() -> Vec<DesktopFile> {
|
||||||
let p: Vec<_> = paths
|
let p: Vec<_> = paths
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.filter(|desktop_dir| desktop_dir.exists())
|
.filter(|desktop_dir| desktop_dir.exists())
|
||||||
.filter_map(|icon_dir| find_file_case_insensitive(&icon_dir, regex))
|
.filter_map(|icon_dir| find_file_via_regex(&icon_dir, regex))
|
||||||
.flat_map(|desktop_files| {
|
.flat_map(|desktop_files| {
|
||||||
desktop_files.into_par_iter().filter_map(|desktop_file| {
|
desktop_files.into_par_iter().filter_map(|desktop_file| {
|
||||||
fs::read_to_string(desktop_file)
|
fs::read_to_string(desktop_file)
|
||||||
|
@ -164,30 +128,7 @@ pub fn find_desktop_files() -> Vec<DesktopFile> {
|
||||||
p
|
p
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Panics
|
/// Return all possible locales based on the users preferences
|
||||||
///
|
|
||||||
/// When it cannot parse the internal regex
|
|
||||||
#[must_use]
|
|
||||||
pub fn lookup_icon(name: &str, size: i32) -> gtk4::Image {
|
|
||||||
let img_regex = Regex::new(&format!(
|
|
||||||
r"((?i).*{})|(^/.*)",
|
|
||||||
known_image_extension_regex_pattern()
|
|
||||||
));
|
|
||||||
let image = if img_regex.expect("invalid icon regex").is_match(name) {
|
|
||||||
if let Ok(img) = fetch_icon_from_common_dirs(name) {
|
|
||||||
gtk4::Image::from_file(img)
|
|
||||||
} else {
|
|
||||||
gtk4::Image::from_icon_name(name)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
gtk4::Image::from_icon_name(name)
|
|
||||||
};
|
|
||||||
|
|
||||||
image.set_pixel_size(size);
|
|
||||||
|
|
||||||
image
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_locale_variants() -> Vec<String> {
|
pub fn get_locale_variants() -> Vec<String> {
|
||||||
let locale = env::var("LC_ALL")
|
let locale = env::var("LC_ALL")
|
||||||
|
@ -208,6 +149,7 @@ pub fn get_locale_variants() -> Vec<String> {
|
||||||
variants
|
variants
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Lookup a value from a hashmap with respect to current locale
|
||||||
// implicit hasher does not make sense here, it is only for desktop files
|
// implicit hasher does not make sense here, it is only for desktop files
|
||||||
#[allow(clippy::implicit_hasher)]
|
#[allow(clippy::implicit_hasher)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
@ -222,3 +164,107 @@ pub fn lookup_name_with_locale(
|
||||||
.map(std::borrow::ToOwned::to_owned)
|
.map(std::borrow::ToOwned::to_owned)
|
||||||
.or_else(|| Some(fallback.to_owned()))
|
.or_else(|| Some(fallback.to_owned()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Spawn a new process and forks it away from the current worf process
|
||||||
|
/// # Errors
|
||||||
|
/// * No action in menu item
|
||||||
|
/// * Cannot run command (i.e. not found)
|
||||||
|
pub fn spawn_fork(cmd: &str, working_dir: Option<&String>) -> Result<(), Error> {
|
||||||
|
// todo fix actions ??
|
||||||
|
// todo graphical disk map icon not working
|
||||||
|
|
||||||
|
let parts = cmd.split(' ').collect::<Vec<_>>();
|
||||||
|
if parts.is_empty() {
|
||||||
|
return Err(Error::MissingAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(dir) = working_dir {
|
||||||
|
env::set_current_dir(dir)
|
||||||
|
.map_err(|e| Error::RunFailed(format!("cannot set workdir {e}")))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let exec = parts[0].replace('"', "");
|
||||||
|
let args: Vec<_> = parts
|
||||||
|
.iter()
|
||||||
|
.skip(1)
|
||||||
|
.filter(|arg| !arg.starts_with('%'))
|
||||||
|
.map(|arg| expand_path(arg))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let _ = Command::new(exec)
|
||||||
|
.args(args)
|
||||||
|
.stdin(Stdio::null())
|
||||||
|
.stdout(Stdio::null())
|
||||||
|
.stderr(Stdio::null())
|
||||||
|
.pre_exec(|| {
|
||||||
|
libc::setsid();
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.spawn();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse a simple toml cache file from the format below
|
||||||
|
/// "Key"=score
|
||||||
|
/// i.e.
|
||||||
|
/// "Firefox"=42
|
||||||
|
/// "Chrome"=12
|
||||||
|
/// "Files"=50
|
||||||
|
/// # Errors
|
||||||
|
/// Returns an Error when the given file is not found or did not parse.
|
||||||
|
pub fn load_cache_file(cache_path: Option<&PathBuf>) -> Result<HashMap<String, i64>, Error> {
|
||||||
|
let Some(path) = cache_path else {
|
||||||
|
return Err(Error::MissingFile);
|
||||||
|
};
|
||||||
|
|
||||||
|
let toml_content =
|
||||||
|
fs::read_to_string(path).map_err(|e| Error::UpdateCacheError(format!("{e}")))?;
|
||||||
|
let parsed: toml::Value = toml_content
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| Error::ParsingError("failed to parse cache".to_owned()))?;
|
||||||
|
|
||||||
|
let mut result: HashMap<String, i64> = HashMap::new();
|
||||||
|
if let toml::Value::Table(table) = parsed {
|
||||||
|
for (key, val) in table {
|
||||||
|
if let toml::Value::Integer(i) = val {
|
||||||
|
result.insert(key, i);
|
||||||
|
} else {
|
||||||
|
log::warn!("Skipping key '{key}' because it's not an integer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores a cache file in the cache format. See `load_cache_file` for details.
|
||||||
|
/// # Errors
|
||||||
|
/// `Error::Parsing` if converting into toml was not possible
|
||||||
|
/// `Error::Io` if storing the file failed.
|
||||||
|
// implicit hasher does not make sense here, it is only for desktop files
|
||||||
|
#[allow(clippy::implicit_hasher)]
|
||||||
|
pub fn save_cache_file(path: &PathBuf, data: &HashMap<String, i64>) -> Result<(), Error> {
|
||||||
|
// Convert the HashMap to TOML string
|
||||||
|
let toml_string =
|
||||||
|
toml::ser::to_string(&data).map_err(|e| Error::ParsingError(e.to_string()))?;
|
||||||
|
fs::write(path, toml_string).map_err(|e| Error::Io(e.to_string()))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Crates a new file if it does not exist yet.
|
||||||
|
/// # Errors
|
||||||
|
/// `Errors::Io` if creating the file failed
|
||||||
|
pub fn create_file_if_not_exists(path: &PathBuf) -> Result<(), Error> {
|
||||||
|
let file = fs::OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.create_new(true)
|
||||||
|
.open(path);
|
||||||
|
|
||||||
|
match file {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
|
||||||
|
Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()),
|
||||||
|
Err(e) => Err(Error::Io(e.to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -78,19 +78,29 @@ impl From<config::Align> for Align {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An entry in the list of selectable items in the UI.
|
||||||
|
/// Supports nested items but these cannot nested again (only nesting with depth == 1 is supported)
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct MenuItem<T: Clone> {
|
pub struct MenuItem<T: Clone> {
|
||||||
pub label: String, // todo support empty label?
|
/// text to show in the UI
|
||||||
|
pub label: String,
|
||||||
|
/// optional icon, will use fallback icon if None is given
|
||||||
pub icon_path: Option<String>,
|
pub icon_path: Option<String>,
|
||||||
|
/// the action to run when this is selected.
|
||||||
pub action: Option<String>,
|
pub action: Option<String>,
|
||||||
|
/// Sub elements of this entry. If this already has a parent entry, nesting is not supported
|
||||||
pub sub_elements: Vec<MenuItem<T>>,
|
pub sub_elements: Vec<MenuItem<T>>,
|
||||||
|
/// Working directory to run the action in.
|
||||||
pub working_dir: Option<String>,
|
pub working_dir: Option<String>,
|
||||||
|
/// Initial sort score to display favourites at the top
|
||||||
pub initial_sort_score: f64,
|
pub initial_sort_score: f64,
|
||||||
|
|
||||||
/// Allows to store arbitrary additional information
|
/// Allows to store arbitrary additional information
|
||||||
pub data: Option<T>,
|
pub data: Option<T>,
|
||||||
|
|
||||||
|
/// Score the item got in the current search
|
||||||
search_sort_score: f64,
|
search_sort_score: f64,
|
||||||
|
/// True if the item is visible
|
||||||
visible: bool,
|
visible: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,6 +150,7 @@ struct UiElements<T: Clone> {
|
||||||
menu_rows: ArcMenuMap<T>,
|
menu_rows: ArcMenuMap<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shows the user interface and **blocks** until the user selected an entry
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Will return Err when the channel between the UI and this is broken
|
/// Will return Err when the channel between the UI and this is broken
|
||||||
|
@ -953,6 +964,7 @@ fn percent_or_absolute(value: Option<&String>, base_value: i32) -> Option<i32> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sorts menu items in alphabetical order, while maintaining the initial score
|
||||||
// highly unlikely that we are dealing with > i64 items
|
// highly unlikely that we are dealing with > i64 items
|
||||||
#[allow(clippy::cast_possible_wrap)]
|
#[allow(clippy::cast_possible_wrap)]
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
|
|
@ -1,4 +1,60 @@
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// Defines error the lib can encounter
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Failed to update a cache file with the given reason.
|
||||||
|
UpdateCacheError(String),
|
||||||
|
/// A given or configured file was not found, will also be used when
|
||||||
|
/// cache files are missing.
|
||||||
|
MissingFile,
|
||||||
|
/// Failed to read form standard input. I.e. used for dmenu.
|
||||||
|
StdInReadFail,
|
||||||
|
/// The selection was invalid or looking up the element failed or another reason.
|
||||||
|
InvalidSelection,
|
||||||
|
/// The given parameters did not yield an icon.
|
||||||
|
MissingIcon,
|
||||||
|
/// Parsing a configuration or cache file failed.
|
||||||
|
ParsingError(String),
|
||||||
|
/// A menu item was expected to have an action but none was found.
|
||||||
|
MissingAction,
|
||||||
|
/// Running the action failed with the given reason.
|
||||||
|
RunFailed(String),
|
||||||
|
/// An IO operation failed
|
||||||
|
Io(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Error::UpdateCacheError(s) => write!(f, "UpdateCacheError {s}"),
|
||||||
|
Error::MissingAction => write!(f, "MissingAction"),
|
||||||
|
Error::StdInReadFail => write!(f, "StdInReadFail"),
|
||||||
|
Error::InvalidSelection => write!(f, "InvalidSelection"),
|
||||||
|
Error::MissingFile => {
|
||||||
|
write!(f, "MissingFile")
|
||||||
|
}
|
||||||
|
Error::MissingIcon => {
|
||||||
|
write!(f, "MissingIcon")
|
||||||
|
}
|
||||||
|
Error::ParsingError(s) => {
|
||||||
|
write!(f, "ParsingError {s}")
|
||||||
|
}
|
||||||
|
Error::RunFailed(s) => {
|
||||||
|
write!(f, "RunFailed {s}")
|
||||||
|
}
|
||||||
|
Error::Io(s) => {
|
||||||
|
write!(f, "IO {s}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configuration and command line parsing
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
/// Desktop action like parsing desktop files and launching programs
|
||||||
pub mod desktop;
|
pub mod desktop;
|
||||||
|
/// All things related to the user interface
|
||||||
pub mod gui;
|
pub mod gui;
|
||||||
|
/// Out of the box supported modes, like drun, dmenu, etc...
|
||||||
pub mod mode;
|
pub mod mode;
|
||||||
|
|
146
src/lib/mode.rs
146
src/lib/mode.rs
|
@ -1,42 +1,19 @@
|
||||||
use crate::config::{Config, expand_path};
|
use crate::config::{Config, expand_path};
|
||||||
use crate::desktop::{find_desktop_files, get_locale_variants, lookup_name_with_locale};
|
use crate::desktop::{
|
||||||
use crate::gui;
|
create_file_if_not_exists, find_desktop_files, get_locale_variants, load_cache_file,
|
||||||
|
lookup_name_with_locale, save_cache_file, spawn_fork,
|
||||||
|
};
|
||||||
use crate::gui::{ItemProvider, MenuItem};
|
use crate::gui::{ItemProvider, MenuItem};
|
||||||
use anyhow::Context;
|
use crate::{Error, gui};
|
||||||
use freedesktop_file_parser::EntryType;
|
use freedesktop_file_parser::EntryType;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::os::unix::prelude::CommandExt;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::{Command, Stdio};
|
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use std::{env, fmt, fs, io};
|
use std::{fs, io};
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum ModeError {
|
|
||||||
UpdateCacheError(String),
|
|
||||||
MissingAction,
|
|
||||||
RunError(String),
|
|
||||||
MissingCache,
|
|
||||||
StdInReadFail,
|
|
||||||
InvalidSelection,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ModeError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
ModeError::UpdateCacheError(s) => write!(f, "UpdateCacheError {s}"),
|
|
||||||
ModeError::MissingAction => write!(f, "MissingAction"),
|
|
||||||
ModeError::RunError(s) => write!(f, "RunError, {s}"),
|
|
||||||
ModeError::MissingCache => write!(f, "MissingCache"),
|
|
||||||
ModeError::StdInReadFail => write!(f, "StdInReadFail"),
|
|
||||||
&ModeError::InvalidSelection => write!(f, "InvalidSelection"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
struct DRunCache {
|
struct DRunCache {
|
||||||
|
@ -434,11 +411,11 @@ struct DMenuProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DMenuProvider {
|
impl DMenuProvider {
|
||||||
fn new() -> Result<DMenuProvider, ModeError> {
|
fn new() -> Result<DMenuProvider, Error> {
|
||||||
let mut input = String::new();
|
let mut input = String::new();
|
||||||
io::stdin()
|
io::stdin()
|
||||||
.read_to_string(&mut input)
|
.read_to_string(&mut input)
|
||||||
.map_err(|_| ModeError::StdInReadFail)?;
|
.map_err(|_| Error::StdInReadFail)?;
|
||||||
|
|
||||||
let items: Vec<MenuItem<String>> = input
|
let items: Vec<MenuItem<String>> = input
|
||||||
.lines()
|
.lines()
|
||||||
|
@ -523,10 +500,11 @@ impl ItemProvider<AutoRunType> for AutoItemProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shows the drun mode
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Will return `Err` if it was not able to spawn the process
|
/// Will return `Err` if it was not able to spawn the process
|
||||||
pub fn d_run(config: &Config) -> Result<(), ModeError> {
|
pub fn d_run(config: &Config) -> Result<(), Error> {
|
||||||
let provider = DRunProvider::new(String::new());
|
let provider = DRunProvider::new(String::new());
|
||||||
let cache_path = provider.cache_path.clone();
|
let cache_path = provider.cache_path.clone();
|
||||||
let mut cache = provider.cache.clone();
|
let mut cache = provider.cache.clone();
|
||||||
|
@ -543,11 +521,12 @@ pub fn d_run(config: &Config) -> Result<(), ModeError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shows the auto mode
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Will return `Err`
|
/// Will return `Err`
|
||||||
/// * if it was not able to spawn the process
|
/// * if it was not able to spawn the process
|
||||||
pub fn auto(config: &Config) -> Result<(), ModeError> {
|
pub fn auto(config: &Config) -> Result<(), Error> {
|
||||||
let mut provider = AutoItemProvider::new(config);
|
let mut provider = AutoItemProvider::new(config);
|
||||||
let cache_path = provider.drun.cache_path.clone();
|
let cache_path = provider.drun.cache_path.clone();
|
||||||
let mut cache = provider.drun.cache.clone();
|
let mut cache = provider.drun.cache.clone();
|
||||||
|
@ -592,11 +571,12 @@ pub fn auto(config: &Config) -> Result<(), ModeError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shows the file browser mode
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Will return `Err`
|
/// Will return `Err`
|
||||||
/// * if it was not able to spawn the process
|
/// * if it was not able to spawn the process
|
||||||
pub fn file(config: &Config) -> Result<(), ModeError> {
|
pub fn file(config: &Config) -> Result<(), Error> {
|
||||||
let provider = FileItemProvider::new(String::new());
|
let provider = FileItemProvider::new(String::new());
|
||||||
|
|
||||||
// todo ues a arc instead of cloning the config
|
// todo ues a arc instead of cloning the config
|
||||||
|
@ -615,7 +595,7 @@ pub fn file(config: &Config) -> Result<(), ModeError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ssh_launch<T: Clone>(menu_item: &MenuItem<T>, config: &Config) -> Result<(), ModeError> {
|
fn ssh_launch<T: Clone>(menu_item: &MenuItem<T>, config: &Config) -> Result<(), Error> {
|
||||||
if let Some(action) = &menu_item.action {
|
if let Some(action) = &menu_item.action {
|
||||||
spawn_fork(action, None)?;
|
spawn_fork(action, None)?;
|
||||||
} else {
|
} else {
|
||||||
|
@ -627,15 +607,16 @@ fn ssh_launch<T: Clone>(menu_item: &MenuItem<T>, config: &Config) -> Result<(),
|
||||||
spawn_fork(&cmd, None)?;
|
spawn_fork(&cmd, None)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(ModeError::MissingAction)
|
Err(Error::MissingAction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shows the ssh mode
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Will return `Err`
|
/// Will return `Err`
|
||||||
/// * if it was not able to spawn the process
|
/// * if it was not able to spawn the process
|
||||||
/// * if it didn't find a terminal
|
/// * if it didn't find a terminal
|
||||||
pub fn ssh(config: &Config) -> Result<(), ModeError> {
|
pub fn ssh(config: &Config) -> Result<(), Error> {
|
||||||
let provider = SshProvider::new(String::new(), config);
|
let provider = SshProvider::new(String::new(), config);
|
||||||
let selection_result = gui::show(config.clone(), provider, true);
|
let selection_result = gui::show(config.clone(), provider, true);
|
||||||
if let Ok(mi) = selection_result {
|
if let Ok(mi) = selection_result {
|
||||||
|
@ -646,6 +627,7 @@ pub fn ssh(config: &Config) -> Result<(), ModeError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shows the math mode
|
||||||
pub fn math(config: &Config) {
|
pub fn math(config: &Config) {
|
||||||
let mut cfg_clone = config.clone();
|
let mut cfg_clone = config.clone();
|
||||||
let mut calc: Vec<MenuItem<String>> = vec![];
|
let mut calc: Vec<MenuItem<String>> = vec![];
|
||||||
|
@ -663,10 +645,11 @@ pub fn math(config: &Config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shows the dmenu mode
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// todo
|
/// Forwards errors from the gui. See `gui::show` for details.
|
||||||
pub fn dmenu(config: &Config) -> Result<(), ModeError> {
|
pub fn dmenu(config: &Config) -> Result<(), Error> {
|
||||||
let provider = DMenuProvider::new()?;
|
let provider = DMenuProvider::new()?;
|
||||||
|
|
||||||
let selection_result = gui::show(config.clone(), provider, true);
|
let selection_result = gui::show(config.clone(), provider, true);
|
||||||
|
@ -675,7 +658,7 @@ pub fn dmenu(config: &Config) -> Result<(), ModeError> {
|
||||||
println!("{}", s.label);
|
println!("{}", s.label);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(_) => Err(ModeError::InvalidSelection),
|
Err(_) => Err(Error::InvalidSelection),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -683,7 +666,7 @@ fn update_drun_cache_and_run<T: Clone>(
|
||||||
cache_path: Option<PathBuf>,
|
cache_path: Option<PathBuf>,
|
||||||
cache: &mut HashMap<String, i64>,
|
cache: &mut HashMap<String, i64>,
|
||||||
selection_result: MenuItem<T>,
|
selection_result: MenuItem<T>,
|
||||||
) -> Result<(), ModeError> {
|
) -> Result<(), Error> {
|
||||||
if let Some(cache_path) = cache_path {
|
if let Some(cache_path) = cache_path {
|
||||||
*cache.entry(selection_result.label).or_insert(0) += 1;
|
*cache.entry(selection_result.label).or_insert(0) += 1;
|
||||||
if let Err(e) = save_cache_file(&cache_path, cache) {
|
if let Err(e) = save_cache_file(&cache_path, cache) {
|
||||||
|
@ -694,7 +677,7 @@ fn update_drun_cache_and_run<T: Clone>(
|
||||||
if let Some(action) = selection_result.action {
|
if let Some(action) = selection_result.action {
|
||||||
spawn_fork(&action, selection_result.working_dir.as_ref())
|
spawn_fork(&action, selection_result.working_dir.as_ref())
|
||||||
} else {
|
} else {
|
||||||
Err(ModeError::MissingAction)
|
Err(Error::MissingAction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -711,82 +694,3 @@ fn load_d_run_cache() -> (Option<PathBuf>, HashMap<String, i64>) {
|
||||||
};
|
};
|
||||||
(cache_path, d_run_cache)
|
(cache_path, d_run_cache)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_cache_file(path: &PathBuf, data: &HashMap<String, i64>) -> anyhow::Result<()> {
|
|
||||||
// Convert the HashMap to TOML string
|
|
||||||
let toml_string = toml::ser::to_string(&data).map_err(|e| anyhow::anyhow!(e))?;
|
|
||||||
fs::write(path, toml_string).map_err(|e| anyhow::anyhow!(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_cache_file(cache_path: Option<&PathBuf>) -> Result<HashMap<String, i64>, ModeError> {
|
|
||||||
let Some(path) = cache_path else {
|
|
||||||
return Err(ModeError::MissingCache);
|
|
||||||
};
|
|
||||||
|
|
||||||
let toml_content =
|
|
||||||
fs::read_to_string(path).map_err(|e| ModeError::UpdateCacheError(format!("{e}")))?;
|
|
||||||
let parsed: toml::Value = toml_content.parse().expect("Failed to parse TOML");
|
|
||||||
|
|
||||||
let mut result: HashMap<String, i64> = HashMap::new();
|
|
||||||
if let toml::Value::Table(table) = parsed {
|
|
||||||
for (key, val) in table {
|
|
||||||
if let toml::Value::Integer(i) = val {
|
|
||||||
result.insert(key, i);
|
|
||||||
} else {
|
|
||||||
log::warn!("Skipping key '{key}' because it's not an integer");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_file_if_not_exists(path: &PathBuf) -> anyhow::Result<()> {
|
|
||||||
let file = fs::OpenOptions::new()
|
|
||||||
.write(true)
|
|
||||||
.create_new(true)
|
|
||||||
.open(path);
|
|
||||||
|
|
||||||
match file {
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
|
|
||||||
Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()),
|
|
||||||
Err(e) => Err(e).context(format!("Failed to create file {}", path.display()))?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn spawn_fork(cmd: &str, working_dir: Option<&String>) -> Result<(), ModeError> {
|
|
||||||
// todo fix actions ??
|
|
||||||
// todo graphical disk map icon not working
|
|
||||||
|
|
||||||
let parts = cmd.split(' ').collect::<Vec<_>>();
|
|
||||||
if parts.is_empty() {
|
|
||||||
return Err(ModeError::MissingAction);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(dir) = working_dir {
|
|
||||||
env::set_current_dir(dir)
|
|
||||||
.map_err(|e| ModeError::RunError(format!("cannot set workdir {e}")))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let exec = parts[0].replace('"', "");
|
|
||||||
let args: Vec<_> = parts
|
|
||||||
.iter()
|
|
||||||
.skip(1)
|
|
||||||
.filter(|arg| !arg.starts_with('%'))
|
|
||||||
.map(|arg| expand_path(arg))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let _ = Command::new(exec)
|
|
||||||
.args(args)
|
|
||||||
.stdin(Stdio::null())
|
|
||||||
.stdout(Stdio::null())
|
|
||||||
.stderr(Stdio::null())
|
|
||||||
.pre_exec(|| {
|
|
||||||
libc::setsid();
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.spawn();
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue