drun:
* move drun into modes * add support for wrapping labels * make MenuItem a generic struct * add optional field to struct to pass data along * merge config and args
This commit is contained in:
parent
d8e64f28fb
commit
f398848dcf
10 changed files with 610 additions and 1005 deletions
594
Cargo.lock
generated
594
Cargo.lock
generated
|
|
@ -114,7 +114,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -123,7 +123,7 @@ version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.1.19",
|
"hermit-abi",
|
||||||
"libc",
|
"libc",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
@ -161,26 +161,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 = "bytemuck"
|
|
||||||
version = "1.22.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bytemuck_derive"
|
|
||||||
version = "1.9.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.100",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.10.1"
|
version = "1.10.1"
|
||||||
|
|
@ -210,54 +190,6 @@ dependencies = [
|
||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "calloop"
|
|
||||||
version = "0.13.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.9.0",
|
|
||||||
"log",
|
|
||||||
"polling",
|
|
||||||
"rustix",
|
|
||||||
"slab",
|
|
||||||
"thiserror 1.0.69",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "calloop"
|
|
||||||
version = "0.14.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "10929724661d1c43856fd87c7a127ae944ec55579134fb485e4136fb6a46fdcb"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.9.0",
|
|
||||||
"polling",
|
|
||||||
"rustix",
|
|
||||||
"slab",
|
|
||||||
"tracing",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "calloop-wayland-source"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20"
|
|
||||||
dependencies = [
|
|
||||||
"calloop 0.13.0",
|
|
||||||
"rustix",
|
|
||||||
"wayland-backend",
|
|
||||||
"wayland-client",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.2.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
|
|
||||||
dependencies = [
|
|
||||||
"shlex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-expr"
|
name = "cfg-expr"
|
||||||
version = "0.17.2"
|
version = "0.17.2"
|
||||||
|
|
@ -321,7 +253,7 @@ dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -345,15 +277,6 @@ version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "concurrent-queue"
|
|
||||||
version = "2.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "configparser"
|
name = "configparser"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
|
@ -416,12 +339,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 = "cursor-icon"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
|
@ -439,15 +356,30 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn",
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "downcast-rs"
|
name = "dirs"
|
||||||
version = "1.2.1"
|
version = "6.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
|
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
||||||
|
dependencies = [
|
||||||
|
"dirs-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dirs-sys"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"option-ext",
|
||||||
|
"redox_users",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
|
|
@ -484,16 +416,6 @@ version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "errno"
|
|
||||||
version = "0.3.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"windows-sys 0.59.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "field-offset"
|
name = "field-offset"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
|
|
@ -510,7 +432,7 @@ version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6059d3997cc694ec3e9a378db855866233ef7edfeafd85afcb2239fd130e6e6b"
|
checksum = "6059d3997cc694ec3e9a378db855866233ef7edfeafd85afcb2239fd130e6e6b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror 2.0.12",
|
"thiserror",
|
||||||
"xdgkit",
|
"xdgkit",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -564,7 +486,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -645,6 +567,17 @@ dependencies = [
|
||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[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]]
|
[[package]]
|
||||||
name = "gimli"
|
name = "gimli"
|
||||||
version = "0.31.1"
|
version = "0.31.1"
|
||||||
|
|
@ -732,7 +665,7 @@ dependencies = [
|
||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -868,7 +801,7 @@ dependencies = [
|
||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -917,12 +850,6 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hermit-abi"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "home"
|
name = "home"
|
||||||
version = "0.5.11"
|
version = "0.5.11"
|
||||||
|
|
@ -962,7 +889,7 @@ checksum = "69e3cbed6e560408051175d29a9ed6ad1e64a7ff443836addf797b0479f58983"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1027,7 +954,7 @@ checksum = "4cdde31a9d349f1b1f51a0b3714a5940ac022976f4b49485fc04be052b183b4c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1042,18 +969,22 @@ version = "0.2.171"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libredox"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.9.0",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linked-hash-map"
|
name = "linked-hash-map"
|
||||||
version = "0.5.6"
|
version = "0.5.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "linux-raw-sys"
|
|
||||||
version = "0.4.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.27"
|
version = "0.4.27"
|
||||||
|
|
@ -1066,24 +997,6 @@ version = "2.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memmap2"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memmap2"
|
|
||||||
version = "0.9.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memoffset"
|
name = "memoffset"
|
||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
|
|
@ -1093,28 +1006,6 @@ dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "merge"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "10bbef93abb1da61525bbc45eeaff6473a41907d19f8f9aa5168d214e10693e9"
|
|
||||||
dependencies = [
|
|
||||||
"merge_derive",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "merge_derive"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro-error",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 1.0.109",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.8.7"
|
version = "0.8.7"
|
||||||
|
|
@ -1135,15 +1026,6 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ntapi"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.19"
|
version = "0.2.19"
|
||||||
|
|
@ -1153,15 +1035,6 @@ dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "objc2-core-foundation"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.9.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.36.7"
|
version = "0.36.7"
|
||||||
|
|
@ -1177,6 +1050,12 @@ version = "1.21.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "option-ext"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_str_bytes"
|
name = "os_str_bytes"
|
||||||
version = "6.6.1"
|
version = "6.6.1"
|
||||||
|
|
@ -1243,7 +1122,7 @@ dependencies = [
|
||||||
"phf_shared",
|
"phf_shared",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1273,21 +1152,6 @@ version = "0.3.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "polling"
|
|
||||||
version = "3.7.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"concurrent-queue",
|
|
||||||
"hermit-abi 0.4.0",
|
|
||||||
"pin-project-lite",
|
|
||||||
"rustix",
|
|
||||||
"tracing",
|
|
||||||
"windows-sys 0.59.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "portable-atomic"
|
name = "portable-atomic"
|
||||||
version = "1.11.0"
|
version = "1.11.0"
|
||||||
|
|
@ -1312,30 +1176,6 @@ dependencies = [
|
||||||
"toml_edit",
|
"toml_edit",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-error"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro-error-attr",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 1.0.109",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-error-attr"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.94"
|
version = "1.0.94"
|
||||||
|
|
@ -1355,15 +1195,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quick-xml"
|
|
||||||
version = "0.37.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a4ce8c88de324ff838700f36fb6ab86c96df0e3c4ab6ef3a9b2044465cce1369"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.40"
|
version = "1.0.40"
|
||||||
|
|
@ -1388,6 +1219,17 @@ version = "0.6.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_users"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
"libredox",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.11.1"
|
version = "1.11.1"
|
||||||
|
|
@ -1432,19 +1274,6 @@ dependencies = [
|
||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustix"
|
|
||||||
version = "0.38.44"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.9.0",
|
|
||||||
"errno",
|
|
||||||
"libc",
|
|
||||||
"linux-raw-sys",
|
|
||||||
"windows-sys 0.59.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.20"
|
version = "1.0.20"
|
||||||
|
|
@ -1474,7 +1303,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1497,7 +1326,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1509,12 +1338,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "shlex"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
|
@ -1536,34 +1359,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 = "smithay-client-toolkit"
|
|
||||||
version = "0.19.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.9.0",
|
|
||||||
"bytemuck",
|
|
||||||
"calloop 0.13.0",
|
|
||||||
"calloop-wayland-source",
|
|
||||||
"cursor-icon",
|
|
||||||
"libc",
|
|
||||||
"log",
|
|
||||||
"memmap2 0.9.5",
|
|
||||||
"pkg-config",
|
|
||||||
"rustix",
|
|
||||||
"thiserror 1.0.69",
|
|
||||||
"wayland-backend",
|
|
||||||
"wayland-client",
|
|
||||||
"wayland-csd-frame",
|
|
||||||
"wayland-cursor",
|
|
||||||
"wayland-protocols",
|
|
||||||
"wayland-protocols-wlr",
|
|
||||||
"wayland-scanner",
|
|
||||||
"xkbcommon",
|
|
||||||
"xkeysym",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.5.9"
|
version = "0.5.9"
|
||||||
|
|
@ -1586,17 +1381,6 @@ version = "0.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "1.0.109"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.100"
|
version = "2.0.100"
|
||||||
|
|
@ -1608,19 +1392,6 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sysinfo"
|
|
||||||
version = "0.34.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a4b93974b3d3aeaa036504b8eefd4c039dced109171c1ae973f1dc63b2c7e4b2"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"memchr",
|
|
||||||
"ntapi",
|
|
||||||
"objc2-core-foundation",
|
|
||||||
"windows",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "system-deps"
|
name = "system-deps"
|
||||||
version = "7.0.3"
|
version = "7.0.3"
|
||||||
|
|
@ -1655,33 +1426,13 @@ version = "0.16.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057"
|
checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thiserror"
|
|
||||||
version = "1.0.69"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
|
||||||
dependencies = [
|
|
||||||
"thiserror-impl 1.0.69",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "2.0.12"
|
version = "2.0.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl 2.0.12",
|
"thiserror-impl",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thiserror-impl"
|
|
||||||
version = "1.0.69"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.100",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1692,7 +1443,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1725,7 +1476,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1762,23 +1513,6 @@ dependencies = [
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing"
|
|
||||||
version = "0.1.41"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"pin-project-lite",
|
|
||||||
"tracing-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing-core"
|
|
||||||
version = "0.1.33"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
|
|
@ -1815,98 +1549,6 @@ version = "0.11.0+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-backend"
|
|
||||||
version = "0.3.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b7208998eaa3870dad37ec8836979581506e0c5c64c20c9e79e9d2a10d6f47bf"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"downcast-rs",
|
|
||||||
"rustix",
|
|
||||||
"smallvec",
|
|
||||||
"wayland-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-client"
|
|
||||||
version = "0.31.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.9.0",
|
|
||||||
"rustix",
|
|
||||||
"wayland-backend",
|
|
||||||
"wayland-scanner",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-csd-frame"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.9.0",
|
|
||||||
"cursor-icon",
|
|
||||||
"wayland-backend",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-cursor"
|
|
||||||
version = "0.31.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a93029cbb6650748881a00e4922b076092a6a08c11e7fbdb923f064b23968c5d"
|
|
||||||
dependencies = [
|
|
||||||
"rustix",
|
|
||||||
"wayland-client",
|
|
||||||
"xcursor",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-protocols"
|
|
||||||
version = "0.32.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0781cf46869b37e36928f7b432273c0995aa8aed9552c556fb18754420541efc"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.9.0",
|
|
||||||
"wayland-backend",
|
|
||||||
"wayland-client",
|
|
||||||
"wayland-scanner",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-protocols-wlr"
|
|
||||||
version = "0.3.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "248a02e6f595aad796561fa82d25601bd2c8c3b145b1c7453fc8f94c1a58f8b2"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.9.0",
|
|
||||||
"wayland-backend",
|
|
||||||
"wayland-client",
|
|
||||||
"wayland-protocols",
|
|
||||||
"wayland-scanner",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-scanner"
|
|
||||||
version = "0.31.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quick-xml 0.37.4",
|
|
||||||
"quote",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-sys"
|
|
||||||
version = "0.31.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615"
|
|
||||||
dependencies = [
|
|
||||||
"pkg-config",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
|
|
@ -1938,59 +1580,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"
|
|
||||||
version = "0.57.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
|
|
||||||
dependencies = [
|
|
||||||
"windows-core",
|
|
||||||
"windows-targets",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-core"
|
|
||||||
version = "0.57.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
|
|
||||||
dependencies = [
|
|
||||||
"windows-implement",
|
|
||||||
"windows-interface",
|
|
||||||
"windows-result",
|
|
||||||
"windows-targets",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-implement"
|
|
||||||
version = "0.57.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.100",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-interface"
|
|
||||||
version = "0.57.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.100",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-result"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
|
|
@ -2087,9 +1676,9 @@ name = "worf"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"calloop 0.14.2",
|
|
||||||
"clap 4.5.35",
|
"clap 4.5.35",
|
||||||
"crossbeam",
|
"crossbeam",
|
||||||
|
"dirs",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"freedesktop-file-parser",
|
"freedesktop-file-parser",
|
||||||
"gdk4",
|
"gdk4",
|
||||||
|
|
@ -2100,25 +1689,14 @@ dependencies = [
|
||||||
"ini",
|
"ini",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"merge",
|
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"smithay-client-toolkit",
|
|
||||||
"strsim 0.11.1",
|
"strsim 0.11.1",
|
||||||
"sysinfo",
|
"thiserror",
|
||||||
"thiserror 2.0.12",
|
|
||||||
"toml",
|
"toml",
|
||||||
"wayland-client",
|
|
||||||
"wayland-protocols",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "xcursor"
|
|
||||||
version = "0.3.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xdgkit"
|
name = "xdgkit"
|
||||||
version = "3.2.5"
|
version = "3.2.5"
|
||||||
|
|
@ -2126,31 +1704,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5aeac9c0125f3c131c6a2898d2a9f25c11b7954c3ff644a018cb9e06fa92919b"
|
checksum = "5aeac9c0125f3c131c6a2898d2a9f25c11b7954c3ff644a018cb9e06fa92919b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 3.2.25",
|
"clap 3.2.25",
|
||||||
"quick-xml 0.21.0",
|
"quick-xml",
|
||||||
"serde",
|
"serde",
|
||||||
"tini",
|
"tini",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "xkbcommon"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "13867d259930edc7091a6c41b4ce6eee464328c6ff9659b7e4c668ca20d4c91e"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"memmap2 0.8.0",
|
|
||||||
"xkeysym",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "xkeysym"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xml-rs"
|
name = "xml-rs"
|
||||||
version = "0.8.25"
|
version = "0.8.25"
|
||||||
|
|
@ -2183,5 +1741,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -13,19 +13,14 @@ home = "0.5.11"
|
||||||
log = "0.4.27"
|
log = "0.4.27"
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
hyprland = "0.4.0-beta.2"
|
hyprland = "0.4.0-beta.2"
|
||||||
sysinfo = "0.34.2"
|
|
||||||
ini = "1.3.0"
|
ini = "1.3.0"
|
||||||
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"] }
|
||||||
toml = "0.8.20"
|
toml = "0.8.20"
|
||||||
merge = "0.1.0"
|
|
||||||
serde_json = "1.0.140"
|
serde_json = "1.0.140"
|
||||||
wayland-client = "0.31.8"
|
|
||||||
wayland-protocols = "0.32.6"
|
|
||||||
smithay-client-toolkit = { version = "0.19.2", features = ["calloop"]}
|
|
||||||
calloop = "0.14.2"
|
|
||||||
crossbeam = "0.8.4"
|
crossbeam = "0.8.4"
|
||||||
libc = "0.2.171"
|
libc = "0.2.171"
|
||||||
freedesktop-file-parser = "0.1.0"
|
freedesktop-file-parser = "0.1.0"
|
||||||
strsim = "0.11.1"
|
strsim = "0.11.1"
|
||||||
|
dirs = "6.0.0"
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@ layerrule = blur, worf
|
||||||
because worf is build on GTK4 instead of GTK3 there will be differences in the look and feel.
|
because worf is build on GTK4 instead of GTK3 there will be differences in the look and feel.
|
||||||
* Configuration files are not 100% compatible, Worf is using toml files instead, for most part this only means strings have to be quoted
|
* Configuration files are not 100% compatible, Worf is using toml files instead, for most part this only means strings have to be quoted
|
||||||
* Color files are not supported
|
* Color files are not supported
|
||||||
|
* `mode` dropped, use show
|
||||||
|
* `D` argument dropped. Arguments are the same as config in worf, no need to have have this flag.
|
||||||
|
|
||||||
## Dropped configuration options
|
## Dropped configuration options
|
||||||
* stylesheet -> use style instead
|
* stylesheet -> use style instead
|
||||||
|
|
|
||||||
201
src/args.rs
201
src/args.rs
|
|
@ -1,201 +0,0 @@
|
||||||
use crate::lib::config::{Align, MatchMethod, Orientation};
|
|
||||||
use clap::Parser;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::str::FromStr;
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
// Define a custom error type using the `thiserror` crate
|
|
||||||
#[derive(Debug, Error)]
|
|
||||||
pub enum ArgsError {
|
|
||||||
#[error("input is not valid {0}")]
|
|
||||||
InvalidParameter(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub enum Mode {
|
|
||||||
/// searches $PATH for executables and allows them to be run by selecting them.
|
|
||||||
Run,
|
|
||||||
/// searches $XDG_DATA_HOME/applications and $XDG_DATA_DIRS/applications for desktop files and allows them to be run by selecting them.
|
|
||||||
Drun,
|
|
||||||
|
|
||||||
/// reads from stdin and displays options which when selected will be output to stdout.
|
|
||||||
Dmenu,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for Mode {
|
|
||||||
type Err = ArgsError;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
match s {
|
|
||||||
"run" => Ok(Mode::Run),
|
|
||||||
"drun" => Ok(Mode::Drun),
|
|
||||||
"dmenu" => Ok(Mode::Dmenu),
|
|
||||||
_ => Err(ArgsError::InvalidParameter(
|
|
||||||
format!("{s} is not a valid argument show this, see help for details").to_owned(),
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Parser, Debug, Deserialize, Serialize)]
|
|
||||||
#[clap(about = "Worf is a wofi clone written in rust, it aims to be a drop in replacement")]
|
|
||||||
pub struct Args {
|
|
||||||
/// Forks the menu so you can close the terminal
|
|
||||||
#[clap(short = 'f', long = "fork")]
|
|
||||||
fork: bool,
|
|
||||||
|
|
||||||
/// Selects a config file to use
|
|
||||||
#[clap(short = 'c', long = "conf")]
|
|
||||||
pub config: Option<String>,
|
|
||||||
|
|
||||||
/// Selects a stylesheet to use
|
|
||||||
#[clap(short = 's', long = "style")]
|
|
||||||
style: Option<String>,
|
|
||||||
|
|
||||||
/// Runs in dmenu mode
|
|
||||||
#[clap(short = 'd', long = "dmenu")]
|
|
||||||
dmenu: bool,
|
|
||||||
|
|
||||||
/// Specifies the mode to run in. A list can be found in wofi(7)
|
|
||||||
#[clap(long = "show")]
|
|
||||||
pub mode: Mode,
|
|
||||||
|
|
||||||
/// Specifies the surface width
|
|
||||||
#[clap(short = 'W', long = "width")]
|
|
||||||
width: Option<String>,
|
|
||||||
|
|
||||||
/// Specifies the surface height
|
|
||||||
#[clap(short = 'H', long = "height")]
|
|
||||||
height: Option<String>,
|
|
||||||
|
|
||||||
/// Prompt to display
|
|
||||||
#[clap(short = 'p', long = "prompt")]
|
|
||||||
pub prompt: Option<String>,
|
|
||||||
|
|
||||||
/// The x offset
|
|
||||||
#[clap(short = 'x', long = "xoffset")]
|
|
||||||
x: Option<i32>,
|
|
||||||
|
|
||||||
/// The y offset
|
|
||||||
#[clap(short = 'y', long = "yoffset")]
|
|
||||||
y: Option<i32>,
|
|
||||||
|
|
||||||
/// Render to a normal window
|
|
||||||
#[clap(short = 'n', long = "normal-window")]
|
|
||||||
normal_window: bool,
|
|
||||||
|
|
||||||
/// Allows images to be rendered
|
|
||||||
#[clap(short = 'I', long = "allow-images")]
|
|
||||||
allow_images: bool,
|
|
||||||
|
|
||||||
/// Allows pango markup
|
|
||||||
#[clap(short = 'm', long = "allow-markup")]
|
|
||||||
allow_markup: bool,
|
|
||||||
|
|
||||||
/// Sets the cache file to use
|
|
||||||
#[clap(short = 'k', long = "cache-file")]
|
|
||||||
cache_file: Option<String>,
|
|
||||||
|
|
||||||
/// Specifies the terminal to use when running in a term
|
|
||||||
#[clap(short = 't', long = "term")]
|
|
||||||
terminal: Option<String>,
|
|
||||||
|
|
||||||
/// Runs in password mode
|
|
||||||
#[clap(short = 'P', long = "password")]
|
|
||||||
password_char: Option<String>,
|
|
||||||
|
|
||||||
/// Makes enter always use the search contents, not the first result
|
|
||||||
#[clap(short = 'e', long = "exec-search")]
|
|
||||||
exec_search: bool,
|
|
||||||
|
|
||||||
/// Hides the scroll bars
|
|
||||||
#[clap(short = 'b', long = "hide-scroll")]
|
|
||||||
hide_scroll: bool,
|
|
||||||
|
|
||||||
/// Sets the matching method, default is contains
|
|
||||||
#[clap(short = 'M', long = "matching")]
|
|
||||||
matching: Option<MatchMethod>,
|
|
||||||
|
|
||||||
/// Allows case insensitive searching
|
|
||||||
#[clap(short = 'i', long = "insensitive")]
|
|
||||||
insensitive: bool,
|
|
||||||
|
|
||||||
/// Parses the search text removing image escapes and pango
|
|
||||||
#[clap(short = 'q', long = "parse-search")]
|
|
||||||
parse_search: bool,
|
|
||||||
|
|
||||||
/// Prints the version and then exits
|
|
||||||
#[clap(short = 'v', long = "version")]
|
|
||||||
version: bool,
|
|
||||||
|
|
||||||
/// Sets the location
|
|
||||||
#[clap(short = 'l', long = "location")]
|
|
||||||
location: Option<String>,
|
|
||||||
|
|
||||||
/// Disables multiple actions for modes that support it
|
|
||||||
#[clap(short = 'a', long = "no-actions")]
|
|
||||||
no_actions: bool,
|
|
||||||
|
|
||||||
/// Sets a config option
|
|
||||||
#[clap(short = 'D', long = "define")]
|
|
||||||
define: Option<String>,
|
|
||||||
|
|
||||||
/// Sets the height in number of lines
|
|
||||||
#[clap(short = 'L', long = "lines")]
|
|
||||||
lines: Option<String>,
|
|
||||||
|
|
||||||
/// Sets the number of columns to display
|
|
||||||
#[clap(short = 'w', long = "columns")]
|
|
||||||
columns: Option<u8>,
|
|
||||||
|
|
||||||
/// Sets the sort order
|
|
||||||
#[clap(short = 'O', long = "sort-order")]
|
|
||||||
sort_order: Option<String>,
|
|
||||||
|
|
||||||
/// Uses the dark variant of the current GTK theme
|
|
||||||
#[clap(short = 'G', long = "gtk-dark")]
|
|
||||||
gtk_dark: bool,
|
|
||||||
|
|
||||||
/// Search for something immediately on open
|
|
||||||
#[clap(short = 'Q', long = "search")]
|
|
||||||
search: Option<String>,
|
|
||||||
|
|
||||||
/// Sets the monitor to open on
|
|
||||||
#[clap(short = 'o', long = "monitor")]
|
|
||||||
monitor: Option<String>,
|
|
||||||
|
|
||||||
/// Runs command for the displayed entries, without changing the output. %s for the real string
|
|
||||||
#[clap(short = 'r', long = "pre-display-cmd")]
|
|
||||||
pre_display_cmd: Option<String>,
|
|
||||||
|
|
||||||
/// Defines how good a fuzzy match must be, to be shown.
|
|
||||||
#[clap(long = "fuzzy-min-score")]
|
|
||||||
fuzzy_min_score: Option<f64>,
|
|
||||||
|
|
||||||
/// Size of displayed images
|
|
||||||
#[clap(long = "image-size")]
|
|
||||||
image_size: Option<i32>,
|
|
||||||
|
|
||||||
/// Orientation of main window
|
|
||||||
#[clap(long = "orientation")]
|
|
||||||
orientation: Option<Orientation>,
|
|
||||||
|
|
||||||
/// Orientation of the row box, defining if label is below or at the side.
|
|
||||||
#[clap(long = "row-box-orientation")]
|
|
||||||
row_bow_orientation: Option<Orientation>,
|
|
||||||
|
|
||||||
/// Specifies the horizontal align for the entire scrolled area,
|
|
||||||
/// it can be any of fill, start, end, or center, default is fill.
|
|
||||||
#[clap(long = "halign")]
|
|
||||||
pub halign: Option<Align>,
|
|
||||||
//// Specifies the horizontal align for the individual entries,
|
|
||||||
// it can be any of fill, start, end, or center, default is fill.
|
|
||||||
#[clap(long = "content-halign")]
|
|
||||||
pub content_halign: Option<Align>,
|
|
||||||
|
|
||||||
/// Specifies the vertical align for the entire scrolled area, it can be any of fill, start, e
|
|
||||||
/// nd, or center, the default is orientation dependent. If vertical then it defaults to
|
|
||||||
/// start, if horizontal it defaults to center.
|
|
||||||
#[clap(long = "valign")]
|
|
||||||
pub valign: Option<Align>,
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +1,16 @@
|
||||||
use crate::args::Args;
|
|
||||||
use crate::lib::system;
|
use crate::lib::system;
|
||||||
use anyhow::anyhow;
|
use anyhow::{anyhow, Context};
|
||||||
use clap::ValueEnum;
|
use clap::builder::TypedValueParser;
|
||||||
|
use clap::{Parser, ValueEnum};
|
||||||
use gtk4::prelude::ToValue;
|
use gtk4::prelude::ToValue;
|
||||||
use merge::Merge;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::env;
|
use std::collections::HashMap;
|
||||||
|
use std::env::Args;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::{env, fs};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug, Serialize, Deserialize)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug, Serialize, Deserialize)]
|
||||||
pub enum MatchMethod {
|
pub enum MatchMethod {
|
||||||
|
|
@ -29,74 +32,180 @@ pub enum Align {
|
||||||
Center,
|
Center,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Merge, Clone)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum Mode {
|
||||||
|
/// searches $PATH for executables and allows them to be run by selecting them.
|
||||||
|
Run,
|
||||||
|
/// searches $XDG_DATA_HOME/applications and $XDG_DATA_DIRS/applications f
|
||||||
|
/// or desktop files and allows them to be run by selecting them.
|
||||||
|
Drun,
|
||||||
|
|
||||||
|
/// reads from stdin and displays options which when selected will be output to stdout.
|
||||||
|
Dmenu,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum ArgsError {
|
||||||
|
#[error("input is not valid {0}")]
|
||||||
|
InvalidParameter(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Mode {
|
||||||
|
type Err = ArgsError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"run" => Ok(Mode::Run),
|
||||||
|
"drun" => Ok(Mode::Drun),
|
||||||
|
"dmenu" => Ok(Mode::Dmenu),
|
||||||
|
_ => Err(ArgsError::InvalidParameter(
|
||||||
|
format!("{s} is not a valid argument show this, see help for details").to_owned(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Clone, Parser)]
|
||||||
|
#[clap(about = "Worf is a wofi clone written in rust, it aims to be a drop-in replacement")]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
/// Defines the path to the stylesheet being used.
|
/// Forks the menu so you can close the terminal
|
||||||
/// Defaults to XDG_CONFIG_DIR/worf/style.css
|
#[clap(short = 'f', long = "fork")]
|
||||||
/// If XDG_CONFIG_DIR is not defined $HOME/.config will be used instead
|
pub fork: Option<bool>,
|
||||||
|
|
||||||
|
/// Selects a config file to use
|
||||||
|
#[clap(short = 'c', long = "conf")]
|
||||||
|
pub config: Option<String>,
|
||||||
|
|
||||||
|
/// Runs in dmenu mode
|
||||||
|
#[clap(short = 'd', long = "dmenu")]
|
||||||
|
pub dmenu: Option<bool>,
|
||||||
|
|
||||||
|
/// Prints the version and then exits
|
||||||
|
#[clap(short = 'v', long = "version")]
|
||||||
|
pub version: Option<bool>,
|
||||||
|
|
||||||
|
/// Defines the style sheet to be loaded.
|
||||||
|
/// Defaults to $XDG_CONF_DIR/worf/style.css
|
||||||
|
/// or $HOME/.config/worf/style.css if XDG_CONF_DIR is not set.
|
||||||
#[serde(default = "default_style")]
|
#[serde(default = "default_style")]
|
||||||
|
#[clap(long = "style")]
|
||||||
pub style: Option<String>,
|
pub style: Option<String>,
|
||||||
pub show: Option<String>,
|
|
||||||
pub mode: Option<String>,
|
/// Defines the mode worf is running in
|
||||||
|
#[clap(long = "show")]
|
||||||
|
pub show: Option<Mode>,
|
||||||
|
|
||||||
|
/// Default width of the window, defaults to 50% of the screen
|
||||||
#[serde(default = "default_width")]
|
#[serde(default = "default_width")]
|
||||||
|
#[clap(long = "width")]
|
||||||
pub width: Option<String>,
|
pub width: Option<String>,
|
||||||
|
|
||||||
|
/// Default height of the window, defaults to 40% of the screen
|
||||||
#[serde(default = "default_height")]
|
#[serde(default = "default_height")]
|
||||||
|
#[clap(long = "height")]
|
||||||
pub height: Option<String>,
|
pub height: Option<String>,
|
||||||
|
|
||||||
|
#[clap(short = 'p', long = "prompt")]
|
||||||
pub prompt: Option<String>,
|
pub prompt: Option<String>,
|
||||||
|
|
||||||
|
#[clap(short = 'x', long = "xoffset")]
|
||||||
pub xoffset: Option<i32>,
|
pub xoffset: Option<i32>,
|
||||||
|
|
||||||
|
#[clap(long = "x")]
|
||||||
pub x: Option<i32>,
|
pub x: Option<i32>,
|
||||||
|
|
||||||
|
#[clap(short = 'y', long = "yoffset")]
|
||||||
pub yoffset: Option<i32>,
|
pub yoffset: Option<i32>,
|
||||||
|
|
||||||
|
#[clap(long = "y")]
|
||||||
pub y: Option<i32>,
|
pub y: Option<i32>,
|
||||||
|
|
||||||
|
/// If true a normal window instead of a layer shell will be used
|
||||||
#[serde(default = "default_normal_window")]
|
#[serde(default = "default_normal_window")]
|
||||||
pub normal_window: Option<bool>,
|
#[clap(short = 'n', long = "normal-window")]
|
||||||
|
pub normal_window: bool,
|
||||||
|
|
||||||
|
#[clap(short = 'I', long = "allow-images")]
|
||||||
pub allow_images: Option<bool>,
|
pub allow_images: Option<bool>,
|
||||||
|
|
||||||
|
#[clap(short = 'm', long = "allow-markup")]
|
||||||
pub allow_markup: Option<bool>,
|
pub allow_markup: Option<bool>,
|
||||||
|
|
||||||
|
#[clap(short = 'k', long = "cache-file")]
|
||||||
pub cache_file: Option<String>,
|
pub cache_file: Option<String>,
|
||||||
|
|
||||||
|
#[clap(short = 't', long = "term")]
|
||||||
pub term: Option<String>,
|
pub term: Option<String>,
|
||||||
|
|
||||||
#[serde(default = "default_password_char")]
|
#[serde(default = "default_password_char")]
|
||||||
|
#[clap(short = 'P', long = "password")]
|
||||||
pub password: Option<String>,
|
pub password: Option<String>,
|
||||||
|
|
||||||
|
#[clap(short = 'e', long = "exec-search")]
|
||||||
pub exec_search: Option<bool>,
|
pub exec_search: Option<bool>,
|
||||||
|
|
||||||
|
#[clap(short = 'b', long = "hide-scroll")]
|
||||||
pub hide_scroll: Option<bool>,
|
pub hide_scroll: Option<bool>,
|
||||||
|
|
||||||
/// Defines how matching is done
|
|
||||||
#[serde(default = "default_match_method")]
|
#[serde(default = "default_match_method")]
|
||||||
|
#[clap(short = 'M', long = "matching")]
|
||||||
pub matching: Option<MatchMethod>,
|
pub matching: Option<MatchMethod>,
|
||||||
|
|
||||||
|
#[clap(short = 'i', long = "insensitive")]
|
||||||
pub insensitive: Option<bool>,
|
pub insensitive: Option<bool>,
|
||||||
|
|
||||||
|
#[clap(short = 'q', long = "parse-search")]
|
||||||
pub parse_search: Option<bool>,
|
pub parse_search: Option<bool>,
|
||||||
|
|
||||||
|
#[clap(short = 'l', long = "location")]
|
||||||
pub location: Option<String>,
|
pub location: Option<String>,
|
||||||
|
|
||||||
|
#[clap(short = 'a', long = "no-actions")]
|
||||||
pub no_actions: Option<bool>,
|
pub no_actions: Option<bool>,
|
||||||
|
|
||||||
|
#[clap(short = 'L', long = "lines")]
|
||||||
pub lines: Option<u32>,
|
pub lines: Option<u32>,
|
||||||
/// Defines how many columns are shown per row
|
|
||||||
#[serde(default = "default_columns")]
|
#[serde(default = "default_columns")]
|
||||||
|
#[clap(short = 'w', long = "columns")]
|
||||||
pub columns: Option<u32>,
|
pub columns: Option<u32>,
|
||||||
|
|
||||||
|
#[clap(short = 'O', long = "sort-order")]
|
||||||
pub sort_order: Option<String>,
|
pub sort_order: Option<String>,
|
||||||
|
|
||||||
|
#[clap(short = 'G', long = "gtk-dark")]
|
||||||
pub gtk_dark: Option<bool>,
|
pub gtk_dark: Option<bool>,
|
||||||
|
|
||||||
|
#[clap(short = 'Q', long = "search")]
|
||||||
pub search: Option<String>,
|
pub search: Option<String>,
|
||||||
|
|
||||||
|
#[clap(short = 'o', long = "monitor")]
|
||||||
pub monitor: Option<String>,
|
pub monitor: Option<String>,
|
||||||
|
|
||||||
|
#[clap(short = 'r', long = "pre-display-cmd")]
|
||||||
pub pre_display_cmd: Option<String>,
|
pub pre_display_cmd: Option<String>,
|
||||||
/// Defines how the entries root container are ordered
|
|
||||||
/// Default is vertical
|
|
||||||
#[serde(default = "default_orientation")]
|
#[serde(default = "default_orientation")]
|
||||||
|
#[clap(long = "orientation")]
|
||||||
pub orientation: Option<Orientation>,
|
pub orientation: Option<Orientation>,
|
||||||
/// Specifies the horizontal align for the entire scrolled area,
|
|
||||||
/// it can be any of fill, start, end, or center, default is fill.
|
|
||||||
#[serde(default = "default_halign")]
|
#[serde(default = "default_halign")]
|
||||||
|
#[clap(long = "halign")]
|
||||||
pub halign: Option<Align>,
|
pub halign: Option<Align>,
|
||||||
//// Specifies the horizontal align for the individual entries,
|
|
||||||
// it can be any of fill, start, end, or center, default is fill.
|
|
||||||
#[serde(default = "default_content_halign")]
|
#[serde(default = "default_content_halign")]
|
||||||
|
#[clap(long = "content-halign")]
|
||||||
pub content_halign: Option<Align>,
|
pub content_halign: Option<Align>,
|
||||||
|
|
||||||
/// Specifies the vertical align for the entire scrolled area, it can be any of fill, start, e
|
#[clap(long = "valign")]
|
||||||
/// nd, or center, the default is orientation dependent. If vertical then it defaults to
|
|
||||||
/// start, if horizontal it defaults to center.
|
|
||||||
pub valign: Option<Align>,
|
pub valign: Option<Align>,
|
||||||
|
|
||||||
pub filter_rate: Option<u32>,
|
pub filter_rate: Option<u32>,
|
||||||
/// Specifies the image size when enabled.
|
|
||||||
/// Defaults to 32.
|
|
||||||
#[serde(default = "default_image_size")]
|
#[serde(default = "default_image_size")]
|
||||||
|
#[clap(long = "image-size")]
|
||||||
pub image_size: Option<i32>,
|
pub image_size: Option<i32>,
|
||||||
|
|
||||||
pub key_up: Option<String>,
|
pub key_up: Option<String>,
|
||||||
pub key_down: Option<String>,
|
pub key_down: Option<String>,
|
||||||
pub key_left: Option<String>,
|
pub key_left: Option<String>,
|
||||||
|
|
@ -110,8 +219,10 @@ pub struct Config {
|
||||||
pub key_expand: Option<String>,
|
pub key_expand: Option<String>,
|
||||||
pub key_hide_search: Option<String>,
|
pub key_hide_search: Option<String>,
|
||||||
pub key_copy: Option<String>,
|
pub key_copy: Option<String>,
|
||||||
#[serde(flatten)]
|
|
||||||
pub custom_keys: Option<std::collections::HashMap<String, String>>,
|
// todo re-add this
|
||||||
|
// #[serde(flatten)]
|
||||||
|
// pub key_custom: Option<HashMap<String, String>>,
|
||||||
pub line_wrap: Option<String>,
|
pub line_wrap: Option<String>,
|
||||||
pub global_coords: Option<bool>,
|
pub global_coords: Option<bool>,
|
||||||
pub hide_search: Option<bool>,
|
pub hide_search: Option<bool>,
|
||||||
|
|
@ -121,25 +232,39 @@ pub struct Config {
|
||||||
pub single_click: Option<bool>,
|
pub single_click: Option<bool>,
|
||||||
pub pre_display_exec: Option<bool>,
|
pub pre_display_exec: Option<bool>,
|
||||||
|
|
||||||
// Exclusive options
|
/// Minimum score for a fuzzy search to be shown
|
||||||
/// Minimum score for the fuzzy finder to accept a match.
|
|
||||||
/// Must be a value between 0 and 1
|
|
||||||
/// Defaults to 0.1.
|
|
||||||
#[serde(default = "default_fuzzy_min_score")]
|
#[serde(default = "default_fuzzy_min_score")]
|
||||||
|
#[clap(long = "fuzzy-min-score")]
|
||||||
pub fuzzy_min_score: Option<f64>,
|
pub fuzzy_min_score: Option<f64>,
|
||||||
|
|
||||||
/// Defines how the content in the row box is aligned
|
/// Orientation of items in the row box where items are displayed
|
||||||
/// Defaults to vertical
|
|
||||||
#[serde(default = "default_row_box_orientation")]
|
#[serde(default = "default_row_box_orientation")]
|
||||||
|
#[clap(long = "row-box-orientation")]
|
||||||
pub row_bow_orientation: Option<Orientation>,
|
pub row_bow_orientation: Option<Orientation>,
|
||||||
|
|
||||||
|
/// Set to to true to wrap text after a given amount of chars
|
||||||
|
#[serde(default = "default_text_wrap")]
|
||||||
|
#[clap(long = "text-wrap")]
|
||||||
|
pub text_wrap: Option<bool>,
|
||||||
|
|
||||||
|
/// Defines after how many chars a line is broken over.
|
||||||
|
/// Only cuts at spaces.
|
||||||
|
#[serde(default = "default_text_wrap_length")]
|
||||||
|
#[clap(long = "text-wrap-length")]
|
||||||
|
pub text_wrap_length: Option<usize>,
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Config {
|
Config {
|
||||||
|
fork: None,
|
||||||
|
config: None,
|
||||||
|
dmenu: None,
|
||||||
|
version: None,
|
||||||
style: default_style(),
|
style: default_style(),
|
||||||
show: None,
|
show: None,
|
||||||
mode: None,
|
|
||||||
width: default_width(),
|
width: default_width(),
|
||||||
height: default_height(),
|
height: default_height(),
|
||||||
prompt: None,
|
prompt: None,
|
||||||
|
|
@ -147,7 +272,7 @@ impl Default for Config {
|
||||||
x: None,
|
x: None,
|
||||||
yoffset: None,
|
yoffset: None,
|
||||||
y: None,
|
y: None,
|
||||||
normal_window: None,
|
normal_window: default_normal_window(),
|
||||||
allow_images: None,
|
allow_images: None,
|
||||||
allow_markup: None,
|
allow_markup: None,
|
||||||
cache_file: None,
|
cache_file: None,
|
||||||
|
|
@ -186,7 +311,7 @@ impl Default for Config {
|
||||||
key_expand: None,
|
key_expand: None,
|
||||||
key_hide_search: None,
|
key_hide_search: None,
|
||||||
key_copy: None,
|
key_copy: None,
|
||||||
custom_keys: None,
|
//key_custom: None,
|
||||||
line_wrap: None,
|
line_wrap: None,
|
||||||
global_coords: None,
|
global_coords: None,
|
||||||
hide_search: None,
|
hide_search: None,
|
||||||
|
|
@ -197,6 +322,8 @@ impl Default for Config {
|
||||||
pre_display_exec: None,
|
pre_display_exec: None,
|
||||||
fuzzy_min_score: default_fuzzy_min_score(),
|
fuzzy_min_score: default_fuzzy_min_score(),
|
||||||
row_bow_orientation: default_row_box_orientation(),
|
row_bow_orientation: default_row_box_orientation(),
|
||||||
|
text_wrap: default_text_wrap(),
|
||||||
|
text_wrap_length: default_text_wrap_length(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -205,7 +332,7 @@ fn default_row_box_orientation() -> Option<Orientation> {
|
||||||
Some(Orientation::Horizontal)
|
Some(Orientation::Horizontal)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_orientation() -> Option<Orientation> {
|
pub(crate) fn default_orientation() -> Option<Orientation> {
|
||||||
Some(Orientation::Vertical)
|
Some(Orientation::Vertical)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -221,8 +348,8 @@ fn default_columns() -> Option<u32> {
|
||||||
Some(1)
|
Some(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_normal_window() -> Option<bool> {
|
fn default_normal_window() -> bool {
|
||||||
Some(false)
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
@ -303,7 +430,7 @@ fn default_normal_window() -> Option<bool> {
|
||||||
// char* key_copy = (i == 0) ? key_default : config_get(config, "key_copy", key_default);
|
// char* key_copy = (i == 0) ? key_default : config_get(config, "key_copy", key_default);
|
||||||
|
|
||||||
fn default_style() -> Option<String> {
|
fn default_style() -> Option<String> {
|
||||||
system::config_path(None)
|
style_path(None)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|pb| Some(pb.display().to_string()))
|
.and_then(|pb| Some(pb.display().to_string()))
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
|
|
@ -340,7 +467,89 @@ pub fn default_image_size() -> Option<i32> {
|
||||||
Some(32)
|
Some(32)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn merge_config_with_args(config: &mut Config, args: &Args) -> anyhow::Result<Config> {
|
pub fn default_text_wrap_length() -> Option<usize> {
|
||||||
|
Some(15)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default_text_wrap() -> Option<bool> {
|
||||||
|
Some(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_args() -> Config {
|
||||||
|
Config::parse()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn style_path(full_path: Option<String>) -> Result<PathBuf, anyhow::Error> {
|
||||||
|
let alternative_paths = path_alternatives(vec![dirs::config_dir()], PathBuf::from("worf").join("style.css"));
|
||||||
|
resolve_path(
|
||||||
|
full_path,
|
||||||
|
alternative_paths
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path_alternatives(base_paths: Vec<Option<PathBuf>>, sub_path: PathBuf) -> Vec<PathBuf> {
|
||||||
|
base_paths
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|s| s)
|
||||||
|
.map(|pb| pb.join(&sub_path))
|
||||||
|
.filter_map(|pb| pb.canonicalize().ok())
|
||||||
|
.filter(|c| c.exists())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolve_path(
|
||||||
|
full_path: Option<String>,
|
||||||
|
alternatives: Vec<PathBuf>,
|
||||||
|
) -> Result<PathBuf, anyhow::Error> {
|
||||||
|
full_path
|
||||||
|
.map(PathBuf::from)
|
||||||
|
.and_then(|p| p.canonicalize().ok().filter(|c| c.exists()))
|
||||||
|
.or_else(|| {
|
||||||
|
alternatives
|
||||||
|
.into_iter()
|
||||||
|
.filter(|p| p.exists())
|
||||||
|
.find_map(|pb| pb.canonicalize().ok().filter(|c| c.exists()))
|
||||||
|
})
|
||||||
|
.ok_or_else(|| anyhow!("Could not find a valid config file."))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_config(args_opt: Option<Config>) -> Result<Config, anyhow::Error> {
|
||||||
|
let home_dir = env::var("HOME")?;
|
||||||
|
let config_path = args_opt.as_ref().map(|c| {
|
||||||
|
c.config
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|p| Some(PathBuf::from(p)))
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
env::var("XDG_CONF_HOME")
|
||||||
|
.map_or(
|
||||||
|
PathBuf::from(home_dir.clone()).join(".config"),
|
||||||
|
|xdg_conf_home| PathBuf::from(&xdg_conf_home),
|
||||||
|
)
|
||||||
|
.join("worf")
|
||||||
|
.join("config")
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
match config_path {
|
||||||
|
Some(path) => {
|
||||||
|
let toml_content = fs::read_to_string(path)?;
|
||||||
|
let mut config: Config = toml::from_str(&toml_content)?;
|
||||||
|
|
||||||
|
if let Some(args) = args_opt {
|
||||||
|
let merge_result = merge_config_with_args(&mut config, &args)?;
|
||||||
|
Ok(merge_result)
|
||||||
|
} else {
|
||||||
|
Ok(config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => Err(anyhow!("No config file found")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn merge_config_with_args(config: &mut Config, args: &Config) -> anyhow::Result<Config> {
|
||||||
let args_json = serde_json::to_value(args)?;
|
let args_json = serde_json::to_value(args)?;
|
||||||
let mut config_json = serde_json::to_value(config)?;
|
let mut config_json = serde_json::to_value(config)?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,8 @@ use log::{debug, error, info};
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::sync::{Arc, Mutex, MutexGuard};
|
use std::sync::{Arc, Mutex, MutexGuard};
|
||||||
|
|
||||||
type ArcMenuMap = Arc<Mutex<HashMap<FlowBoxChild, MenuItem>>>;
|
type ArcMenuMap<T> = Arc<Mutex<HashMap<FlowBoxChild, MenuItem<T>>>>;
|
||||||
type MenuItemSender = Sender<Result<MenuItem, anyhow::Error>>;
|
type MenuItemSender<T> = Sender<Result<MenuItem<T>, anyhow::Error>>;
|
||||||
|
|
||||||
impl Into<Orientation> for config::Orientation {
|
impl Into<Orientation> for config::Orientation {
|
||||||
fn into(self) -> Orientation {
|
fn into(self) -> Orientation {
|
||||||
|
|
@ -49,17 +49,20 @@ impl Into<Align> for config::Align {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct MenuItem {
|
pub struct MenuItem<T> {
|
||||||
pub label: String, // todo support empty label?
|
pub label: String, // todo support empty label?
|
||||||
pub icon_path: Option<String>,
|
pub icon_path: Option<String>,
|
||||||
pub action: Option<String>,
|
pub action: Option<String>,
|
||||||
pub sub_elements: Vec<MenuItem>,
|
pub sub_elements: Vec<MenuItem<T>>,
|
||||||
pub working_dir: Option<String>,
|
pub working_dir: Option<String>,
|
||||||
pub initial_sort_score: i64,
|
pub initial_sort_score: i64,
|
||||||
pub search_sort_score: f64,
|
pub search_sort_score: f64,
|
||||||
|
|
||||||
|
/// Allows to store arbitrary additional information
|
||||||
|
pub data: Option<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show(config: Config, elements: Vec<MenuItem>) -> Result<MenuItem, anyhow::Error> {
|
pub fn show<T>(config: Config, elements: Vec<MenuItem<T>>) -> Result<MenuItem<T>, anyhow::Error> where T: Clone + 'static {
|
||||||
if let Some(ref css) = config.style {
|
if let Some(ref css) = config.style {
|
||||||
let provider = CssProvider::new();
|
let provider = CssProvider::new();
|
||||||
let css_file_path = File::for_path(css);
|
let css_file_path = File::for_path(css);
|
||||||
|
|
@ -85,12 +88,12 @@ pub fn show(config: Config, elements: Vec<MenuItem>) -> Result<MenuItem, anyhow:
|
||||||
selection
|
selection
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_ui(
|
fn build_ui<T>(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
elements: &Vec<MenuItem>,
|
elements: &Vec<MenuItem<T>>,
|
||||||
sender: Sender<Result<MenuItem, anyhow::Error>>,
|
sender: Sender<Result<MenuItem<T>, anyhow::Error>>,
|
||||||
app: &Application,
|
app: &Application,
|
||||||
) {
|
) where T: Clone + 'static {
|
||||||
// Create a toplevel undecorated window
|
// Create a toplevel undecorated window
|
||||||
let window = ApplicationWindow::builder()
|
let window = ApplicationWindow::builder()
|
||||||
.application(app)
|
.application(app)
|
||||||
|
|
@ -102,15 +105,13 @@ fn build_ui(
|
||||||
|
|
||||||
window.set_widget_name("window");
|
window.set_widget_name("window");
|
||||||
|
|
||||||
config.normal_window.map(|normal| {
|
if !config.normal_window {
|
||||||
if !normal {
|
|
||||||
// Initialize the window as a layer
|
// Initialize the window as a layer
|
||||||
window.init_layer_shell();
|
window.init_layer_shell();
|
||||||
window.set_layer(gtk4_layer_shell::Layer::Overlay);
|
window.set_layer(gtk4_layer_shell::Layer::Overlay);
|
||||||
window.set_keyboard_mode(KeyboardMode::Exclusive);
|
window.set_keyboard_mode(KeyboardMode::Exclusive);
|
||||||
window.set_namespace(Some("worf"));
|
window.set_namespace(Some("worf"));
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
let outer_box = gtk4::Box::new(config.orientation.unwrap().into(), 0);
|
let outer_box = gtk4::Box::new(config.orientation.unwrap().into(), 0);
|
||||||
outer_box.set_widget_name("outer-box");
|
outer_box.set_widget_name("outer-box");
|
||||||
|
|
@ -159,7 +160,7 @@ fn build_ui(
|
||||||
inner_box.set_max_children_per_line(config.columns.unwrap());
|
inner_box.set_max_children_per_line(config.columns.unwrap());
|
||||||
inner_box.set_activate_on_single_click(true);
|
inner_box.set_activate_on_single_click(true);
|
||||||
|
|
||||||
let mut list_items: ArcMenuMap = Arc::new(Mutex::new(HashMap::new()));
|
let mut list_items: ArcMenuMap<T> = Arc::new(Mutex::new(HashMap::new()));
|
||||||
for entry in elements {
|
for entry in elements {
|
||||||
list_items
|
list_items
|
||||||
.lock()
|
.lock()
|
||||||
|
|
@ -221,13 +222,13 @@ fn build_ui(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_key_event_handler(
|
fn setup_key_event_handler<T: Clone + 'static>(
|
||||||
window: &ApplicationWindow,
|
window: &ApplicationWindow,
|
||||||
entry_clone: SearchEntry,
|
entry_clone: SearchEntry,
|
||||||
inner_box: FlowBox,
|
inner_box: FlowBox,
|
||||||
app: Application,
|
app: Application,
|
||||||
sender: MenuItemSender,
|
sender: MenuItemSender<T>,
|
||||||
list_items: Arc<Mutex<HashMap<FlowBoxChild, MenuItem>>>,
|
list_items: Arc<Mutex<HashMap<FlowBoxChild, MenuItem<T>>>>,
|
||||||
config: Config,
|
config: Config,
|
||||||
) {
|
) {
|
||||||
let key_controller = EventControllerKey::new();
|
let key_controller = EventControllerKey::new();
|
||||||
|
|
@ -269,10 +270,10 @@ fn setup_key_event_handler(
|
||||||
window.add_controller(key_controller);
|
window.add_controller(key_controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sort_menu_items(
|
fn sort_menu_items<T>(
|
||||||
child1: &FlowBoxChild,
|
child1: &FlowBoxChild,
|
||||||
child2: &FlowBoxChild,
|
child2: &FlowBoxChild,
|
||||||
items_lock: &Mutex<HashMap<FlowBoxChild, MenuItem>>,
|
items_lock: &Mutex<HashMap<FlowBoxChild, MenuItem<T>>>,
|
||||||
) -> Ordering {
|
) -> Ordering {
|
||||||
let lock = items_lock.lock().unwrap();
|
let lock = items_lock.lock().unwrap();
|
||||||
let m1 = lock.get(child1);
|
let m1 = lock.get(child1);
|
||||||
|
|
@ -281,13 +282,13 @@ fn sort_menu_items(
|
||||||
match (m1, m2) {
|
match (m1, m2) {
|
||||||
(Some(menu1), Some(menu2)) => {
|
(Some(menu1), Some(menu2)) => {
|
||||||
if menu1.search_sort_score != 0.0 || menu2.search_sort_score != 0.0 {
|
if menu1.search_sort_score != 0.0 || menu2.search_sort_score != 0.0 {
|
||||||
if menu1.search_sort_score > menu2.search_sort_score {
|
if menu1.search_sort_score < menu2.search_sort_score {
|
||||||
Ordering::Smaller
|
Ordering::Smaller
|
||||||
} else {
|
} else {
|
||||||
Ordering::Larger
|
Ordering::Larger
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if menu1.initial_sort_score > menu2.initial_sort_score {
|
if menu1.initial_sort_score < menu2.initial_sort_score {
|
||||||
Ordering::Smaller
|
Ordering::Smaller
|
||||||
} else {
|
} else {
|
||||||
Ordering::Larger
|
Ordering::Larger
|
||||||
|
|
@ -300,12 +301,12 @@ fn sort_menu_items(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_selected_item(
|
fn handle_selected_item<T>(
|
||||||
sender: &MenuItemSender,
|
sender: &MenuItemSender<T>,
|
||||||
app: &Application,
|
app: &Application,
|
||||||
inner_box: &FlowBox,
|
inner_box: &FlowBox,
|
||||||
lock_arc: &ArcMenuMap,
|
lock_arc: &ArcMenuMap<T>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> where T: Clone {
|
||||||
for s in inner_box.selected_children() {
|
for s in inner_box.selected_children() {
|
||||||
let list_items = lock_arc.lock().unwrap();
|
let list_items = lock_arc.lock().unwrap();
|
||||||
let item = list_items.get(&s);
|
let item = list_items.get(&s);
|
||||||
|
|
@ -320,12 +321,12 @@ fn handle_selected_item(
|
||||||
Err("selected item cannot be resolved".to_owned())
|
Err("selected item cannot be resolved".to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_menu_item(
|
fn add_menu_item<T: Clone + 'static>(
|
||||||
inner_box: &FlowBox,
|
inner_box: &FlowBox,
|
||||||
entry_element: &MenuItem,
|
entry_element: &MenuItem<T>,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
sender: MenuItemSender,
|
sender: MenuItemSender<T>,
|
||||||
lock_arc: ArcMenuMap,
|
lock_arc: ArcMenuMap<T>,
|
||||||
app: Application,
|
app: Application,
|
||||||
) -> FlowBoxChild {
|
) -> FlowBoxChild {
|
||||||
let parent: Widget = if !entry_element.sub_elements.is_empty() {
|
let parent: Widget = if !entry_element.sub_elements.is_empty() {
|
||||||
|
|
@ -390,11 +391,11 @@ fn add_menu_item(
|
||||||
child
|
child
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_menu_row(
|
fn create_menu_row<T: Clone + 'static>(
|
||||||
menu_item: &MenuItem,
|
menu_item: &MenuItem<T>,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
lock_arc: ArcMenuMap,
|
lock_arc: ArcMenuMap<T>,
|
||||||
sender: MenuItemSender,
|
sender: MenuItemSender<T>,
|
||||||
app: Application,
|
app: Application,
|
||||||
inner_box: FlowBox,
|
inner_box: FlowBox,
|
||||||
) -> Widget {
|
) -> Widget {
|
||||||
|
|
@ -434,7 +435,13 @@ fn create_menu_row(
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo make max length configurable
|
// todo make max length configurable
|
||||||
let label = Label::new(Some(&wrap_text(&menu_item.label, 15)));
|
let text = if config.text_wrap.is_some_and(|x| x == true) {
|
||||||
|
&wrap_text(&menu_item.label, config.text_wrap_length)
|
||||||
|
} else {
|
||||||
|
menu_item.label.as_str()
|
||||||
|
};
|
||||||
|
|
||||||
|
let label = Label::new(Some(text));
|
||||||
label.set_hexpand(true);
|
label.set_hexpand(true);
|
||||||
label.set_widget_name("label");
|
label.set_widget_name("label");
|
||||||
label.set_wrap(true);
|
label.set_wrap(true);
|
||||||
|
|
@ -448,9 +455,9 @@ fn create_menu_row(
|
||||||
row.upcast()
|
row.upcast()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter_widgets(
|
fn filter_widgets<T>(
|
||||||
query: &str,
|
query: &str,
|
||||||
items: &mut HashMap<FlowBoxChild, MenuItem>,
|
items: &mut HashMap<FlowBoxChild, MenuItem<T>>,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
inner_box: &FlowBox,
|
inner_box: &FlowBox,
|
||||||
) {
|
) {
|
||||||
|
|
@ -537,9 +544,9 @@ fn percent_or_absolute(value: &String, base_value: i32) -> Option<i32> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initialize_sort_scores(items: &mut Vec<MenuItem>) {
|
pub fn initialize_sort_scores<T>(items: &mut Vec<MenuItem<T>>) {
|
||||||
let mut regular_score = items.len() as i64;
|
let mut regular_score = items.len() as i64;
|
||||||
items.sort_by(|l, r| r.label.cmp(&l.label));
|
items.sort_by(|l, r| l.label.cmp(&r.label));
|
||||||
|
|
||||||
for item in items.iter_mut() {
|
for item in items.iter_mut() {
|
||||||
if item.initial_sort_score == 0 {
|
if item.initial_sort_score == 0 {
|
||||||
|
|
@ -549,12 +556,13 @@ pub fn initialize_sort_scores(items: &mut Vec<MenuItem>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_text(text: &str, line_length: usize) -> String {
|
fn wrap_text(text: &str, line_length: Option<usize>) -> String {
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
|
let len = line_length.unwrap_or(text.len());
|
||||||
|
|
||||||
for word in text.split_whitespace() {
|
for word in text.split_whitespace() {
|
||||||
if line.len() + word.len() + 1 > line_length {
|
if line.len() + word.len() + 1 > len {
|
||||||
if !line.is_empty() {
|
if !line.is_empty() {
|
||||||
result.push_str(&line.trim_end());
|
result.push_str(&line.trim_end());
|
||||||
result.push('\n');
|
result.push('\n');
|
||||||
|
|
|
||||||
|
|
@ -2,3 +2,4 @@ pub mod config;
|
||||||
pub mod desktop;
|
pub mod desktop;
|
||||||
pub mod gui;
|
pub mod gui;
|
||||||
pub mod system;
|
pub mod system;
|
||||||
|
pub mod mode;
|
||||||
|
|
|
||||||
211
src/lib/mode.rs
Normal file
211
src/lib/mode.rs
Normal file
|
|
@ -0,0 +1,211 @@
|
||||||
|
use crate::lib::config::Config;
|
||||||
|
use crate::lib::desktop::{default_icon, find_desktop_files, get_locale_variants};
|
||||||
|
use crate::lib::gui;
|
||||||
|
use crate::lib::gui::MenuItem;
|
||||||
|
use crate::lookup_name_with_locale;
|
||||||
|
use anyhow::{Context, anyhow};
|
||||||
|
use freedesktop_file_parser::EntryType;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::os::unix::prelude::CommandExt;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::{Command, Stdio};
|
||||||
|
use std::{env, fs, io};
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
|
struct DRunCache {
|
||||||
|
desktop_entry: String,
|
||||||
|
run_count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn d_run(mut config: Config) -> anyhow::Result<()> {
|
||||||
|
let locale_variants = get_locale_variants();
|
||||||
|
let default_icon = default_icon();
|
||||||
|
|
||||||
|
let cache_path = dirs::cache_dir().map(|x| x.join("worf-drun"));
|
||||||
|
let mut d_run_cache = {
|
||||||
|
if let Some(ref cache_path) = cache_path {
|
||||||
|
if let Err(e) = create_file_if_not_exists(cache_path) {
|
||||||
|
log::warn!("No drun cache file and cannot create: {e:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
load_cache_file(&cache_path).unwrap_or_default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut entries: Vec<MenuItem<String>> = Vec::new();
|
||||||
|
for file in find_desktop_files().iter().filter(|f| {
|
||||||
|
f.entry.hidden.map_or(true, |hidden| !hidden)
|
||||||
|
&& f.entry.no_display.map_or(true, |no_display| !no_display)
|
||||||
|
}) {
|
||||||
|
let (action, working_dir) = match &file.entry.entry_type {
|
||||||
|
EntryType::Application(app) => (app.exec.clone(), app.path.clone()),
|
||||||
|
_ => (None, None),
|
||||||
|
};
|
||||||
|
|
||||||
|
let name = match lookup_name_with_locale(
|
||||||
|
&locale_variants,
|
||||||
|
&file.entry.name.variants,
|
||||||
|
&file.entry.name.default,
|
||||||
|
) {
|
||||||
|
Some(name) => name,
|
||||||
|
None => {
|
||||||
|
log::debug!("Skipping desktop entry without name {file:?}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let icon = file
|
||||||
|
.entry
|
||||||
|
.icon
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.content.clone())
|
||||||
|
.or(Some(default_icon.clone()));
|
||||||
|
log::debug!("file, name={name:?}, icon={icon:?}, action={action:?}");
|
||||||
|
let sort_score = d_run_cache.get(&name).unwrap_or(&0);
|
||||||
|
|
||||||
|
let mut entry: MenuItem<String> = MenuItem {
|
||||||
|
label: name,
|
||||||
|
icon_path: icon.clone(),
|
||||||
|
action,
|
||||||
|
sub_elements: Vec::default(),
|
||||||
|
working_dir: working_dir.clone(),
|
||||||
|
initial_sort_score: -(*sort_score),
|
||||||
|
search_sort_score: 0.0,
|
||||||
|
data: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
file.actions.iter().for_each(|(_, action)| {
|
||||||
|
let action_name = lookup_name_with_locale(
|
||||||
|
&locale_variants,
|
||||||
|
&action.name.variants,
|
||||||
|
&action.name.default,
|
||||||
|
);
|
||||||
|
let action_icon = action
|
||||||
|
.icon
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.content.clone())
|
||||||
|
.or(icon.as_ref().map(|s| s.clone()));
|
||||||
|
|
||||||
|
log::debug!("sub, action_name={action_name:?}, action_icon={action_icon:?}");
|
||||||
|
|
||||||
|
let sub_entry = MenuItem {
|
||||||
|
label: action_name.unwrap().trim().to_owned(),
|
||||||
|
icon_path: action_icon,
|
||||||
|
action: action.exec.clone(),
|
||||||
|
sub_elements: Vec::default(),
|
||||||
|
working_dir: working_dir.clone(),
|
||||||
|
initial_sort_score: 0, // subitems are never sorted right now.
|
||||||
|
search_sort_score: 0.0,
|
||||||
|
data: None,
|
||||||
|
};
|
||||||
|
entry.sub_elements.push(sub_entry);
|
||||||
|
});
|
||||||
|
|
||||||
|
entries.push(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
gui::initialize_sort_scores(&mut entries);
|
||||||
|
|
||||||
|
// todo ues a arc instead of cloning the config
|
||||||
|
let selection_result = gui::show(config.clone(), entries.clone());
|
||||||
|
match selection_result {
|
||||||
|
Ok(selected_item) => {
|
||||||
|
if let Some(cache) = cache_path {
|
||||||
|
*d_run_cache.entry(selected_item.label).or_insert(0) += 1;
|
||||||
|
if let Err(e) = save_cache_file(&cache, d_run_cache) {
|
||||||
|
log::warn!("cannot save drun cache {e:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(action) = selected_item.action {
|
||||||
|
spawn_fork(&action, &selected_item.working_dir)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
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>) -> anyhow::Result<HashMap<String, i64>> {
|
||||||
|
let path = match cache_path {
|
||||||
|
Some(p) => p,
|
||||||
|
None => return Err(anyhow!("Cache is missing")),
|
||||||
|
};
|
||||||
|
|
||||||
|
let toml_content = fs::read_to_string(path)?;
|
||||||
|
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 '{}' because it's not an integer", key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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>) -> anyhow::Result<()> {
|
||||||
|
// todo probably remove arguments?
|
||||||
|
// todo support working dir
|
||||||
|
// todo fix actions
|
||||||
|
// todo graphical disk map icon not working
|
||||||
|
// Unix-like systems (Linux, macOS)
|
||||||
|
|
||||||
|
let parts = cmd.split(' ').collect::<Vec<_>>();
|
||||||
|
if parts.is_empty() {
|
||||||
|
return Err(anyhow!("empty command passed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(dir) = working_dir {
|
||||||
|
env::set_current_dir(dir)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let exec = parts[0];
|
||||||
|
let args: Vec<_> = parts
|
||||||
|
.iter()
|
||||||
|
.skip(1)
|
||||||
|
.filter(|arg| !arg.starts_with("%"))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let _ = Command::new(exec)
|
||||||
|
.args(args)
|
||||||
|
.stdin(Stdio::null())
|
||||||
|
.stdout(Stdio::null())
|
||||||
|
.stderr(Stdio::null())
|
||||||
|
.pre_exec(|| {
|
||||||
|
libc::setsid();
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.spawn();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
@ -1,31 +1,3 @@
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub fn home_dir() -> Result<String, anyhow::Error> {
|
|
||||||
env::var("HOME").map_err(|e| anyhow::anyhow!("$HOME not set: {e}"))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn conf_home() -> Result<String, anyhow::Error> {
|
|
||||||
env::var("XDG_CONF_HOME").map_err(|e| anyhow::anyhow!("XDG_CONF_HOME not set: {e}"))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn config_path(config_path: Option<String>) -> Result<PathBuf, anyhow::Error> {
|
|
||||||
config_path
|
|
||||||
.map(PathBuf::from)
|
|
||||||
.and_then(|p| p.canonicalize().ok().filter(|c| c.exists()))
|
|
||||||
.or_else(|| {
|
|
||||||
[
|
|
||||||
conf_home().ok().map(PathBuf::from),
|
|
||||||
home_dir()
|
|
||||||
.ok()
|
|
||||||
.map(PathBuf::from)
|
|
||||||
.map(|c| c.join(".config")),
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.flatten()
|
|
||||||
.map(|base| base.join("worf").join("style.css"))
|
|
||||||
.find_map(|p| p.canonicalize().ok())
|
|
||||||
})
|
|
||||||
.ok_or_else(|| anyhow!("Could not find a valid config file."))
|
|
||||||
}
|
|
||||||
|
|
|
||||||
178
src/main.rs
178
src/main.rs
|
|
@ -3,10 +3,9 @@
|
||||||
|
|
||||||
// todo resolve paths like ~/
|
// todo resolve paths like ~/
|
||||||
|
|
||||||
use crate::args::{Args, Mode};
|
use crate::lib::config::Config;
|
||||||
use crate::lib::config::{Config, merge_config_with_args};
|
|
||||||
use crate::lib::desktop::{default_icon, find_desktop_files, get_locale_variants};
|
use crate::lib::desktop::{default_icon, find_desktop_files, get_locale_variants};
|
||||||
use crate::lib::gui;
|
use crate::lib::{config, gui, mode};
|
||||||
use crate::lib::gui::MenuItem;
|
use crate::lib::gui::MenuItem;
|
||||||
use anyhow::{Error, anyhow};
|
use anyhow::{Error, anyhow};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
@ -18,7 +17,6 @@ use gtk4::prelude::{
|
||||||
};
|
};
|
||||||
use gtk4_layer_shell::LayerShell;
|
use gtk4_layer_shell::LayerShell;
|
||||||
use log::{debug, info, warn};
|
use log::{debug, info, warn};
|
||||||
use merge::Merge;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::os::unix::process::CommandExt;
|
use std::os::unix::process::CommandExt;
|
||||||
|
|
@ -28,9 +26,9 @@ use std::sync::Arc;
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
use std::{env, fs, time};
|
use std::{env, fs, time};
|
||||||
|
|
||||||
mod args;
|
|
||||||
mod lib;
|
mod lib;
|
||||||
|
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
gtk4::init()?;
|
gtk4::init()?;
|
||||||
|
|
||||||
|
|
@ -38,43 +36,23 @@ fn main() -> anyhow::Result<()> {
|
||||||
// todo change to error as default
|
// todo change to error as default
|
||||||
.parse_filters(&env::var("RUST_LOG").unwrap_or_else(|_| "debug".to_owned()))
|
.parse_filters(&env::var("RUST_LOG").unwrap_or_else(|_| "debug".to_owned()))
|
||||||
.init();
|
.init();
|
||||||
let args = Args::parse();
|
|
||||||
|
|
||||||
let home_dir = env::var("HOME")?;
|
let args = config::parse_args();
|
||||||
let config_path = args
|
let config = config::load_config(Some(args))?;
|
||||||
.config
|
|
||||||
.as_ref()
|
|
||||||
.map(|c| PathBuf::from(c))
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
env::var("XDG_CONF_HOME")
|
|
||||||
.map_or(
|
|
||||||
PathBuf::from(home_dir.clone()).join(".config"),
|
|
||||||
|xdg_conf_home| PathBuf::from(&xdg_conf_home),
|
|
||||||
)
|
|
||||||
.join("worf")
|
|
||||||
.join("config")
|
|
||||||
});
|
|
||||||
|
|
||||||
let drun_cache = env::var("XDG_CACHE_HOME")
|
if let Some(show) = &config.show {
|
||||||
.map_or(
|
match show {
|
||||||
PathBuf::from(home_dir.clone()).join(".cache"),
|
config::Mode::Run => {}
|
||||||
|xdg_conf_home| PathBuf::from(&xdg_conf_home),
|
config::Mode::Drun => {
|
||||||
)
|
mode::d_run(config)?;
|
||||||
.join("worf-drun");
|
|
||||||
|
|
||||||
let toml_content = fs::read_to_string(config_path)?;
|
|
||||||
let mut config: Config = toml::from_str(&toml_content)?; // todo bail out properly
|
|
||||||
let config = merge_config_with_args(&mut config, &args)?;
|
|
||||||
|
|
||||||
match args.mode {
|
|
||||||
Mode::Run => {}
|
|
||||||
Mode::Drun => {
|
|
||||||
drun(config)?;
|
|
||||||
}
|
}
|
||||||
Mode::Dmenu => {}
|
config::Mode::Dmenu => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(anyhow!("No mode provided"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_name_with_locale(
|
fn lookup_name_with_locale(
|
||||||
|
|
@ -90,135 +68,7 @@ fn lookup_name_with_locale(
|
||||||
.or_else(|| Some(fallback.to_owned()))
|
.or_else(|| Some(fallback.to_owned()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drun(mut config: Config) -> anyhow::Result<()> {
|
|
||||||
let mut entries: Vec<MenuItem> = Vec::new();
|
|
||||||
let locale_variants = get_locale_variants();
|
|
||||||
let default_icon = default_icon();
|
|
||||||
|
|
||||||
for file in find_desktop_files().iter().filter(|f| {
|
|
||||||
f.entry.hidden.map_or(true, |hidden| !hidden)
|
|
||||||
&& f.entry.no_display.map_or(true, |no_display| !no_display)
|
|
||||||
}) {
|
|
||||||
let (action, working_dir) = match &file.entry.entry_type {
|
|
||||||
EntryType::Application(app) => (app.exec.clone(), app.path.clone()),
|
|
||||||
_ => (None, None),
|
|
||||||
};
|
|
||||||
|
|
||||||
let name = lookup_name_with_locale(
|
|
||||||
&locale_variants,
|
|
||||||
&file.entry.name.variants,
|
|
||||||
&file.entry.name.default,
|
|
||||||
);
|
|
||||||
if name.is_none() {
|
|
||||||
debug!("Skipping desktop entry without name {file:?}")
|
|
||||||
}
|
|
||||||
|
|
||||||
let icon = file
|
|
||||||
.entry
|
|
||||||
.icon
|
|
||||||
.as_ref()
|
|
||||||
.map(|s| s.content.clone())
|
|
||||||
.or(Some(default_icon.clone()));
|
|
||||||
debug!("file, name={name:?}, icon={icon:?}, action={action:?}");
|
|
||||||
let mut sort_score = 0.0;
|
|
||||||
if name.as_ref().unwrap().contains("ox") {
|
|
||||||
sort_score = 999.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut entry = MenuItem {
|
|
||||||
label: name.unwrap(),
|
|
||||||
icon_path: icon.clone(),
|
|
||||||
action,
|
|
||||||
sub_elements: Vec::default(),
|
|
||||||
working_dir: working_dir.clone(),
|
|
||||||
initial_sort_score: 0,
|
|
||||||
search_sort_score: sort_score,
|
|
||||||
};
|
|
||||||
|
|
||||||
file.actions.iter().for_each(|(_, action)| {
|
|
||||||
let action_name = lookup_name_with_locale(
|
|
||||||
&locale_variants,
|
|
||||||
&action.name.variants,
|
|
||||||
&action.name.default,
|
|
||||||
);
|
|
||||||
let action_icon = action
|
|
||||||
.icon
|
|
||||||
.as_ref()
|
|
||||||
.map(|s| s.content.clone())
|
|
||||||
.or(icon.as_ref().map(|s| s.clone()));
|
|
||||||
|
|
||||||
debug!("sub, action_name={action_name:?}, action_icon={action_icon:?}");
|
|
||||||
|
|
||||||
let sub_entry = MenuItem {
|
|
||||||
label: action_name.unwrap().trim().to_owned(),
|
|
||||||
icon_path: action_icon,
|
|
||||||
action: action.exec.clone(),
|
|
||||||
sub_elements: Vec::default(),
|
|
||||||
working_dir: working_dir.clone(),
|
|
||||||
initial_sort_score: 0,
|
|
||||||
search_sort_score: 0.0,
|
|
||||||
};
|
|
||||||
entry.sub_elements.push(sub_entry);
|
|
||||||
});
|
|
||||||
|
|
||||||
entries.push(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
gui::initialize_sort_scores(&mut entries);
|
|
||||||
|
|
||||||
// todo ues a arc instead of cloning the config
|
|
||||||
let selection_result = gui::show(config.clone(), entries.clone());
|
|
||||||
match selection_result {
|
|
||||||
Ok(selected_item) => {
|
|
||||||
if let Some(action) = selected_item.action {
|
|
||||||
spawn_fork(&action, &selected_item.working_dir)?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("{e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn spawn_fork(cmd: &str, working_dir: &Option<String>) -> anyhow::Result<()> {
|
|
||||||
// todo probably remove arguments?
|
|
||||||
// todo support working dir
|
|
||||||
// todo fix actions
|
|
||||||
// todo graphical disk map icon not working
|
|
||||||
// Unix-like systems (Linux, macOS)
|
|
||||||
|
|
||||||
let parts = cmd.split(' ').collect::<Vec<_>>();
|
|
||||||
if parts.is_empty() {
|
|
||||||
return Err(anyhow!("empty command passed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(dir) = working_dir {
|
|
||||||
env::set_current_dir(dir)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let exec = parts[0];
|
|
||||||
let args: Vec<_> = parts
|
|
||||||
.iter()
|
|
||||||
.skip(1)
|
|
||||||
.filter(|arg| !arg.starts_with("%"))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let _ = Command::new(exec)
|
|
||||||
.args(args)
|
|
||||||
.stdin(Stdio::null()) // Disconnect stdin
|
|
||||||
.stdout(Stdio::null()) // Disconnect stdout
|
|
||||||
.stderr(Stdio::null()) // Disconnect stderr
|
|
||||||
.pre_exec(|| {
|
|
||||||
libc::setsid();
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.spawn();
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
//
|
//
|
||||||
// fn main() -> anyhow::Result<()> {
|
// fn main() -> anyhow::Result<()> {
|
||||||
// env_logger::Builder::new()
|
// env_logger::Builder::new()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue