mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-04-25 01:58:51 +02:00
feat(core): use PathExt to unify env var resolution
This new implementation allows for expanding any environment variable so it is not limited to just `~`, `$HOME`, `$Env:USERPROFILE` and `$Env:KOMOREBI_CONFIG_HOME`. It expands the follwing formats: - CMD: `%variable%` - PowerShell: `$Env:variable` - Bash: `$variable` I searched throughout the code base for path and migrate any code that might need to PathExt::replace_env. It is possible that I might have missed a few places due to my unfamiliarity with the code base, so if you find any, please let me know. Most of the paths that needed this trait, are in: - Clap arguments, and that was handled by #[value_parse] attribute and a helper function. - SocketMessage and that was handled by custom deserialization with the help of serde_with crate
This commit is contained in:
234
Cargo.lock
generated
234
Cargo.lock
generated
@@ -59,7 +59,7 @@ dependencies = [
|
|||||||
"accesskit_consumer",
|
"accesskit_consumer",
|
||||||
"hashbrown 0.15.2",
|
"hashbrown 0.15.2",
|
||||||
"objc2 0.5.2",
|
"objc2 0.5.2",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit 0.2.2",
|
||||||
"objc2-foundation 0.2.2",
|
"objc2-foundation 0.2.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -295,19 +295,21 @@ checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arboard"
|
name = "arboard"
|
||||||
version = "3.4.1"
|
version = "3.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4"
|
checksum = "c1df21f715862ede32a0c525ce2ca4d52626bb0007f8c18b87a384503ac33e70"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clipboard-win",
|
"clipboard-win",
|
||||||
"core-graphics 0.23.2",
|
|
||||||
"image 0.25.6",
|
"image 0.25.6",
|
||||||
"log",
|
"log",
|
||||||
"objc2 0.5.2",
|
"objc2 0.6.0",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit 0.3.0",
|
||||||
"objc2-foundation 0.2.2",
|
"objc2-core-foundation",
|
||||||
|
"objc2-core-graphics",
|
||||||
|
"objc2-foundation 0.3.0",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"windows-sys 0.48.0",
|
"percent-encoding",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
"x11rb",
|
"x11rb",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -842,9 +844,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.17"
|
version = "1.2.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
|
checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -1231,9 +1233,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ctrlc"
|
name = "ctrlc"
|
||||||
version = "3.4.5"
|
version = "3.4.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3"
|
checksum = "697b5419f348fd5ae2478e8018cb016c00a5881c7f46c717de98ffd135a5651c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nix",
|
"nix",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
@@ -1245,6 +1247,41 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
|
checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling"
|
||||||
|
version = "0.20.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"darling_macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_core"
|
||||||
|
version = "0.20.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"ident_case",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"strsim",
|
||||||
|
"syn 2.0.100",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_macro"
|
||||||
|
version = "0.20.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.100",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deflate"
|
name = "deflate"
|
||||||
version = "0.8.6"
|
version = "0.8.6"
|
||||||
@@ -1257,11 +1294,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deranged"
|
name = "deranged"
|
||||||
version = "0.4.1"
|
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 = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058"
|
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1424,7 +1462,7 @@ dependencies = [
|
|||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
"objc2 0.5.2",
|
"objc2 0.5.2",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit 0.2.2",
|
||||||
"objc2-foundation 0.2.2",
|
"objc2-foundation 0.2.2",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
@@ -1647,9 +1685,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.10"
|
version = "0.3.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
@@ -1701,7 +1739,7 @@ dependencies = [
|
|||||||
"bit_field",
|
"bit_field",
|
||||||
"half",
|
"half",
|
||||||
"lebe",
|
"lebe",
|
||||||
"miniz_oxide 0.8.5",
|
"miniz_oxide 0.8.7",
|
||||||
"rayon-core",
|
"rayon-core",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"zune-inflate",
|
"zune-inflate",
|
||||||
@@ -1766,7 +1804,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
"miniz_oxide 0.8.5",
|
"miniz_oxide 0.8.7",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2148,7 +2186,7 @@ dependencies = [
|
|||||||
"glutin_wgl_sys",
|
"glutin_wgl_sys",
|
||||||
"libloading",
|
"libloading",
|
||||||
"objc2 0.5.2",
|
"objc2 0.5.2",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit 0.2.2",
|
||||||
"objc2-foundation 0.2.2",
|
"objc2-foundation 0.2.2",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
@@ -2249,7 +2287,7 @@ dependencies = [
|
|||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"http",
|
"http",
|
||||||
"indexmap 2.8.0",
|
"indexmap 2.9.0",
|
||||||
"slab",
|
"slab",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
@@ -2594,6 +2632,12 @@ dependencies = [
|
|||||||
"syn 2.0.100",
|
"syn 2.0.100",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ident_case"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
@@ -2696,16 +2740,18 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"hashbrown 0.12.3",
|
"hashbrown 0.12.3",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.8.0"
|
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 = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
|
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.15.2",
|
"hashbrown 0.15.2",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2888,6 +2934,7 @@ dependencies = [
|
|||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json_lenient",
|
"serde_json_lenient",
|
||||||
|
"serde_with",
|
||||||
"serde_yaml 0.9.34+deprecated",
|
"serde_yaml 0.9.34+deprecated",
|
||||||
"shadow-rs",
|
"shadow-rs",
|
||||||
"strum 0.27.1",
|
"strum 0.27.1",
|
||||||
@@ -3097,7 +3144,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall 0.5.10",
|
"redox_syscall 0.5.11",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3315,11 +3362,13 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mime_guess2"
|
name = "mime_guess2"
|
||||||
version = "2.0.5"
|
version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "25a3333bb1609500601edc766a39b4c1772874a4ce26022f4d866854dc020c41"
|
checksum = "f54028747dfea8e8bf00d3c2d4e83cf023c1accfd5d436335456e9864940cb85"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"mime",
|
"mime",
|
||||||
|
"phf 0.11.3",
|
||||||
|
"phf_shared 0.11.3",
|
||||||
"unicase",
|
"unicase",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3359,9 +3408,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.8.5"
|
version = "0.8.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
|
checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"adler2",
|
"adler2",
|
||||||
"simd-adler32",
|
"simd-adler32",
|
||||||
@@ -3411,7 +3460,7 @@ dependencies = [
|
|||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"codespan-reporting",
|
"codespan-reporting",
|
||||||
"hexf-parse",
|
"hexf-parse",
|
||||||
"indexmap 2.8.0",
|
"indexmap 2.9.0",
|
||||||
"log",
|
"log",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"spirv",
|
"spirv",
|
||||||
@@ -3836,6 +3885,18 @@ dependencies = [
|
|||||||
"objc2-quartz-core",
|
"objc2-quartz-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2-app-kit"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5906f93257178e2f7ae069efb89fbd6ee94f0592740b5f8a1512ca498814d0fb"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.9.0",
|
||||||
|
"objc2 0.6.0",
|
||||||
|
"objc2-core-graphics",
|
||||||
|
"objc2-foundation 0.3.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2-cloud-kit"
|
name = "objc2-cloud-kit"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@@ -3872,6 +3933,28 @@ dependencies = [
|
|||||||
"objc2-foundation 0.2.2",
|
"objc2-foundation 0.2.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[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",
|
||||||
|
"objc2 0.6.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2-core-graphics"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8dca602628b65356b6513290a21a6405b4d4027b8b250f0b98dddbb28b7de02"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.9.0",
|
||||||
|
"objc2 0.6.0",
|
||||||
|
"objc2-core-foundation",
|
||||||
|
"objc2-io-surface",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2-core-image"
|
name = "objc2-core-image"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@@ -3923,6 +4006,18 @@ checksum = "3a21c6c9014b82c39515db5b396f91645182611c97d24637cf56ac01e5f8d998"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
"objc2 0.6.0",
|
"objc2 0.6.0",
|
||||||
|
"objc2-core-foundation",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2-io-surface"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "161a8b87e32610086e1a7a9e9ec39f84459db7b3a0881c1f16ca5a2605581c19"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.9.0",
|
||||||
|
"objc2 0.6.0",
|
||||||
|
"objc2-core-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3933,7 +4028,7 @@ checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"block2",
|
"block2",
|
||||||
"objc2 0.5.2",
|
"objc2 0.5.2",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit 0.2.2",
|
||||||
"objc2-foundation 0.2.2",
|
"objc2-foundation 0.2.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -4198,7 +4293,7 @@ dependencies = [
|
|||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"libc",
|
"libc",
|
||||||
"petgraph",
|
"petgraph",
|
||||||
"redox_syscall 0.5.10",
|
"redox_syscall 0.5.11",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thread-id",
|
"thread-id",
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
@@ -4232,7 +4327,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
|
checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fixedbitset",
|
"fixedbitset",
|
||||||
"indexmap 2.8.0",
|
"indexmap 2.9.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4250,6 +4345,7 @@ version = "0.11.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
|
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"phf_macros",
|
||||||
"phf_shared 0.11.3",
|
"phf_shared 0.11.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -4293,6 +4389,20 @@ dependencies = [
|
|||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_macros"
|
||||||
|
version = "0.11.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216"
|
||||||
|
dependencies = [
|
||||||
|
"phf_generator 0.11.3",
|
||||||
|
"phf_shared 0.11.3",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.100",
|
||||||
|
"unicase",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_shared"
|
name = "phf_shared"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@@ -4309,6 +4419,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
|
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"siphasher 1.0.1",
|
"siphasher 1.0.1",
|
||||||
|
"unicase",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4367,7 +4478,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "eac26e981c03a6e53e0aee43c113e3202f5581d5360dae7bd2c70e800dd0451d"
|
checksum = "eac26e981c03a6e53e0aee43c113e3202f5581d5360dae7bd2c70e800dd0451d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"indexmap 2.8.0",
|
"indexmap 2.9.0",
|
||||||
"quick-xml 0.32.0",
|
"quick-xml 0.32.0",
|
||||||
"serde",
|
"serde",
|
||||||
"time",
|
"time",
|
||||||
@@ -4395,7 +4506,7 @@ dependencies = [
|
|||||||
"crc32fast",
|
"crc32fast",
|
||||||
"fdeflate",
|
"fdeflate",
|
||||||
"flate2",
|
"flate2",
|
||||||
"miniz_oxide 0.8.5",
|
"miniz_oxide 0.8.7",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4745,9 +4856,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.10"
|
version = "0.5.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
|
checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
]
|
]
|
||||||
@@ -5179,6 +5290,37 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_with"
|
||||||
|
version = "3.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
"chrono",
|
||||||
|
"hex",
|
||||||
|
"indexmap 1.9.3",
|
||||||
|
"indexmap 2.9.0",
|
||||||
|
"schemars",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"serde_with_macros",
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_with_macros"
|
||||||
|
version = "3.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e"
|
||||||
|
dependencies = [
|
||||||
|
"darling",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.100",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_yaml"
|
name = "serde_yaml"
|
||||||
version = "0.8.26"
|
version = "0.8.26"
|
||||||
@@ -5197,7 +5339,7 @@ version = "0.9.34+deprecated"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.8.0",
|
"indexmap 2.9.0",
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -5335,9 +5477,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.14.0"
|
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 = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
|
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smithay-client-toolkit"
|
name = "smithay-client-toolkit"
|
||||||
@@ -5806,9 +5948,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.44.1"
|
version = "1.44.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a"
|
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -5888,7 +6030,7 @@ version = "0.22.24"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
|
checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.8.0",
|
"indexmap 2.9.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
@@ -6505,7 +6647,7 @@ dependencies = [
|
|||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"document-features",
|
"document-features",
|
||||||
"indexmap 2.8.0",
|
"indexmap 2.9.0",
|
||||||
"log",
|
"log",
|
||||||
"naga",
|
"naga",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -6521,9 +6663,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-hal"
|
name = "wgpu-hal"
|
||||||
version = "24.0.2"
|
version = "24.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4317a17171dc20e6577bf606796794580accae0716a69edbc7388c86a3ec9f23"
|
checksum = "f112f464674ca69f3533248508ee30cb84c67cf06c25ff6800685f5e0294e259"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android_system_properties",
|
"android_system_properties",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
@@ -7259,7 +7401,7 @@ dependencies = [
|
|||||||
"memmap2",
|
"memmap2",
|
||||||
"ndk",
|
"ndk",
|
||||||
"objc2 0.5.2",
|
"objc2 0.5.2",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit 0.2.2",
|
||||||
"objc2-foundation 0.2.2",
|
"objc2-foundation 0.2.2",
|
||||||
"objc2-ui-kit",
|
"objc2-ui-kit",
|
||||||
"orbclient",
|
"orbclient",
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ use komorebi_client::Colour;
|
|||||||
use komorebi_client::KomorebiTheme;
|
use komorebi_client::KomorebiTheme;
|
||||||
use komorebi_client::MonitorNotification;
|
use komorebi_client::MonitorNotification;
|
||||||
use komorebi_client::NotificationEvent;
|
use komorebi_client::NotificationEvent;
|
||||||
|
use komorebi_client::PathExt;
|
||||||
use komorebi_client::SocketMessage;
|
use komorebi_client::SocketMessage;
|
||||||
use komorebi_themes::catppuccin_egui;
|
use komorebi_themes::catppuccin_egui;
|
||||||
use komorebi_themes::Base16Value;
|
use komorebi_themes::Base16Value;
|
||||||
@@ -500,13 +501,16 @@ impl Komobar {
|
|||||||
let home_dir: PathBuf = std::env::var("KOMOREBI_CONFIG_HOME").map_or_else(
|
let home_dir: PathBuf = std::env::var("KOMOREBI_CONFIG_HOME").map_or_else(
|
||||||
|_| dirs::home_dir().expect("there is no home directory"),
|
|_| dirs::home_dir().expect("there is no home directory"),
|
||||||
|home_path| {
|
|home_path| {
|
||||||
let home = PathBuf::from(&home_path);
|
let home = home_path.replace_env();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
home.is_dir(),
|
||||||
|
"$Env:KOMOREBI_CONFIG_HOME is set to '{}', which is not a valid directory",
|
||||||
|
home_path
|
||||||
|
);
|
||||||
|
|
||||||
|
home
|
||||||
|
|
||||||
if home.as_path().is_dir() {
|
|
||||||
home
|
|
||||||
} else {
|
|
||||||
panic!("$Env:KOMOREBI_CONFIG_HOME is set to '{home_path}', which is not a valid directory");
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ use font_loader::system_fonts;
|
|||||||
use hotwatch::EventKind;
|
use hotwatch::EventKind;
|
||||||
use hotwatch::Hotwatch;
|
use hotwatch::Hotwatch;
|
||||||
use image::RgbaImage;
|
use image::RgbaImage;
|
||||||
|
use komorebi_client::replace_env_in_path;
|
||||||
|
use komorebi_client::PathExt;
|
||||||
use komorebi_client::SocketMessage;
|
use komorebi_client::SocketMessage;
|
||||||
use komorebi_client::SubscribeOptions;
|
use komorebi_client::SubscribeOptions;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -65,6 +67,7 @@ struct Opts {
|
|||||||
fonts: bool,
|
fonts: bool,
|
||||||
/// Path to a JSON or YAML configuration file
|
/// Path to a JSON or YAML configuration file
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
|
#[clap(value_parser = replace_env_in_path)]
|
||||||
config: Option<PathBuf>,
|
config: Option<PathBuf>,
|
||||||
/// Write an example komorebi.bar.json to disk
|
/// Write an example komorebi.bar.json to disk
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
@@ -159,13 +162,15 @@ fn main() -> color_eyre::Result<()> {
|
|||||||
let home_dir: PathBuf = std::env::var("KOMOREBI_CONFIG_HOME").map_or_else(
|
let home_dir: PathBuf = std::env::var("KOMOREBI_CONFIG_HOME").map_or_else(
|
||||||
|_| dirs::home_dir().expect("there is no home directory"),
|
|_| dirs::home_dir().expect("there is no home directory"),
|
||||||
|home_path| {
|
|home_path| {
|
||||||
let home = PathBuf::from(&home_path);
|
let home = home_path.replace_env();
|
||||||
|
|
||||||
if home.as_path().is_dir() {
|
assert!(
|
||||||
home
|
home.is_dir(),
|
||||||
} else {
|
"$Env:KOMOREBI_CONFIG_HOME is set to '{}', which is not a valid directory",
|
||||||
panic!("$Env:KOMOREBI_CONFIG_HOME is set to '{home_path}', which is not a valid directory");
|
home_path
|
||||||
}
|
);
|
||||||
|
|
||||||
|
home
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -174,7 +179,7 @@ fn main() -> color_eyre::Result<()> {
|
|||||||
std::fs::write(home_dir.join("komorebi.bar.json"), komorebi_bar_json)?;
|
std::fs::write(home_dir.join("komorebi.bar.json"), komorebi_bar_json)?;
|
||||||
println!(
|
println!(
|
||||||
"Example komorebi.bar.json file written to {}",
|
"Example komorebi.bar.json file written to {}",
|
||||||
home_dir.as_path().display()
|
home_dir.display()
|
||||||
);
|
);
|
||||||
|
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
@@ -182,16 +187,11 @@ fn main() -> color_eyre::Result<()> {
|
|||||||
|
|
||||||
let default_config_path = home_dir.join("komorebi.bar.json");
|
let default_config_path = home_dir.join("komorebi.bar.json");
|
||||||
|
|
||||||
let config_path = opts.config.map_or_else(
|
let config_path = opts.config.or_else(|| {
|
||||||
|| {
|
default_config_path
|
||||||
if !default_config_path.is_file() {
|
.is_file()
|
||||||
None
|
.then_some(default_config_path.clone())
|
||||||
} else {
|
});
|
||||||
Some(default_config_path.clone())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Option::from,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut config = match config_path {
|
let mut config = match config_path {
|
||||||
None => {
|
None => {
|
||||||
@@ -201,17 +201,14 @@ fn main() -> color_eyre::Result<()> {
|
|||||||
std::fs::write(&default_config_path, komorebi_bar_json)?;
|
std::fs::write(&default_config_path, komorebi_bar_json)?;
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
"created example configuration file: {}",
|
"created example configuration file: {}",
|
||||||
default_config_path.as_path().display()
|
default_config_path.display()
|
||||||
);
|
);
|
||||||
|
|
||||||
KomobarConfig::read(&default_config_path)?
|
KomobarConfig::read(&default_config_path)?
|
||||||
}
|
}
|
||||||
Some(ref config) => {
|
Some(ref config) => {
|
||||||
if !opts.aliases {
|
if !opts.aliases {
|
||||||
tracing::info!(
|
tracing::info!("found configuration file: {}", config.display());
|
||||||
"found configuration file: {}",
|
|
||||||
config.as_path().to_string_lossy()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KomobarConfig::read(config)?
|
KomobarConfig::read(config)?
|
||||||
@@ -311,10 +308,7 @@ fn main() -> color_eyre::Result<()> {
|
|||||||
hotwatch.watch(config_path, move |event| match event.kind {
|
hotwatch.watch(config_path, move |event| match event.kind {
|
||||||
EventKind::Modify(_) | EventKind::Remove(_) => match KomobarConfig::read(&config_path_cl) {
|
EventKind::Modify(_) | EventKind::Remove(_) => match KomobarConfig::read(&config_path_cl) {
|
||||||
Ok(updated) => {
|
Ok(updated) => {
|
||||||
tracing::info!(
|
tracing::info!("configuration file updated: {}", config_path_cl.display());
|
||||||
"configuration file updated: {}",
|
|
||||||
config_path_cl.as_path().to_string_lossy()
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Err(error) = tx_config.send(updated) {
|
if let Err(error) = tx_config.send(updated) {
|
||||||
tracing::error!("could not send configuration update to gui: {error}")
|
tracing::error!("could not send configuration update to gui: {error}")
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ pub use komorebi::config_generation::MatchingRule;
|
|||||||
pub use komorebi::config_generation::MatchingStrategy;
|
pub use komorebi::config_generation::MatchingStrategy;
|
||||||
pub use komorebi::container::Container;
|
pub use komorebi::container::Container;
|
||||||
pub use komorebi::core::config_generation::ApplicationConfigurationGenerator;
|
pub use komorebi::core::config_generation::ApplicationConfigurationGenerator;
|
||||||
pub use komorebi::core::resolve_home_path;
|
pub use komorebi::core::replace_env_in_path;
|
||||||
pub use komorebi::core::AnimationStyle;
|
pub use komorebi::core::AnimationStyle;
|
||||||
pub use komorebi::core::ApplicationIdentifier;
|
pub use komorebi::core::ApplicationIdentifier;
|
||||||
pub use komorebi::core::Arrangement;
|
pub use komorebi::core::Arrangement;
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ windows-implement = { workspace = true }
|
|||||||
windows-interface = { workspace = true }
|
windows-interface = { workspace = true }
|
||||||
winput = "0.2"
|
winput = "0.2"
|
||||||
winreg = "0.55"
|
winreg = "0.55"
|
||||||
|
serde_with = { version = "3.12", features = ["schemars_0_8"] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
shadow-rs = { workspace = true }
|
shadow-rs = { workspace = true }
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
#![warn(clippy::all)]
|
#![warn(clippy::all)]
|
||||||
#![allow(clippy::missing_errors_doc, clippy::use_self, clippy::doc_markdown)]
|
#![allow(clippy::missing_errors_doc, clippy::use_self, clippy::doc_markdown)]
|
||||||
|
|
||||||
use std::path::Path;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use clap::ValueEnum;
|
use clap::ValueEnum;
|
||||||
use color_eyre::eyre::anyhow;
|
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
@@ -28,7 +26,10 @@ pub use default_layout::DefaultLayout;
|
|||||||
pub use direction::Direction;
|
pub use direction::Direction;
|
||||||
pub use layout::Layout;
|
pub use layout::Layout;
|
||||||
pub use operation_direction::OperationDirection;
|
pub use operation_direction::OperationDirection;
|
||||||
|
pub use pathext::replace_env_in_path;
|
||||||
|
pub use pathext::resolve_option_hashmap_usize_path;
|
||||||
pub use pathext::PathExt;
|
pub use pathext::PathExt;
|
||||||
|
pub use pathext::ResolvedPathBuf;
|
||||||
pub use rect::Rect;
|
pub use rect::Rect;
|
||||||
|
|
||||||
pub mod animation;
|
pub mod animation;
|
||||||
@@ -44,6 +45,8 @@ pub mod operation_direction;
|
|||||||
pub mod pathext;
|
pub mod pathext;
|
||||||
pub mod rect;
|
pub mod rect;
|
||||||
|
|
||||||
|
// serde_as must be before derive
|
||||||
|
#[serde_with::serde_as]
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, Display)]
|
#[derive(Clone, Debug, Serialize, Deserialize, Display)]
|
||||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||||
#[serde(tag = "type", content = "content")]
|
#[serde(tag = "type", content = "content")]
|
||||||
@@ -105,7 +108,7 @@ pub enum SocketMessage {
|
|||||||
AdjustWorkspacePadding(Sizing, i32),
|
AdjustWorkspacePadding(Sizing, i32),
|
||||||
ChangeLayout(DefaultLayout),
|
ChangeLayout(DefaultLayout),
|
||||||
CycleLayout(CycleDirection),
|
CycleLayout(CycleDirection),
|
||||||
ChangeLayoutCustom(PathBuf),
|
ChangeLayoutCustom(#[serde_as(as = "ResolvedPathBuf")] PathBuf),
|
||||||
FlipLayout(Axis),
|
FlipLayout(Axis),
|
||||||
ToggleWorkspaceWindowContainerBehaviour,
|
ToggleWorkspaceWindowContainerBehaviour,
|
||||||
ToggleWorkspaceFloatOverride,
|
ToggleWorkspaceFloatOverride,
|
||||||
@@ -123,8 +126,8 @@ pub enum SocketMessage {
|
|||||||
RetileWithResizeDimensions,
|
RetileWithResizeDimensions,
|
||||||
QuickSave,
|
QuickSave,
|
||||||
QuickLoad,
|
QuickLoad,
|
||||||
Save(PathBuf),
|
Save(#[serde_as(as = "ResolvedPathBuf")] PathBuf),
|
||||||
Load(PathBuf),
|
Load(#[serde_as(as = "ResolvedPathBuf")] PathBuf),
|
||||||
CycleFocusMonitor(CycleDirection),
|
CycleFocusMonitor(CycleDirection),
|
||||||
CycleFocusWorkspace(CycleDirection),
|
CycleFocusWorkspace(CycleDirection),
|
||||||
CycleFocusEmptyWorkspace(CycleDirection),
|
CycleFocusEmptyWorkspace(CycleDirection),
|
||||||
@@ -147,19 +150,24 @@ pub enum SocketMessage {
|
|||||||
WorkspaceName(usize, usize, String),
|
WorkspaceName(usize, usize, String),
|
||||||
WorkspaceLayout(usize, usize, DefaultLayout),
|
WorkspaceLayout(usize, usize, DefaultLayout),
|
||||||
NamedWorkspaceLayout(String, DefaultLayout),
|
NamedWorkspaceLayout(String, DefaultLayout),
|
||||||
WorkspaceLayoutCustom(usize, usize, PathBuf),
|
WorkspaceLayoutCustom(usize, usize, #[serde_as(as = "ResolvedPathBuf")] PathBuf),
|
||||||
NamedWorkspaceLayoutCustom(String, PathBuf),
|
NamedWorkspaceLayoutCustom(String, #[serde_as(as = "ResolvedPathBuf")] PathBuf),
|
||||||
WorkspaceLayoutRule(usize, usize, usize, DefaultLayout),
|
WorkspaceLayoutRule(usize, usize, usize, DefaultLayout),
|
||||||
NamedWorkspaceLayoutRule(String, usize, DefaultLayout),
|
NamedWorkspaceLayoutRule(String, usize, DefaultLayout),
|
||||||
WorkspaceLayoutCustomRule(usize, usize, usize, PathBuf),
|
WorkspaceLayoutCustomRule(
|
||||||
NamedWorkspaceLayoutCustomRule(String, usize, PathBuf),
|
usize,
|
||||||
|
usize,
|
||||||
|
usize,
|
||||||
|
#[serde_as(as = "ResolvedPathBuf")] PathBuf,
|
||||||
|
),
|
||||||
|
NamedWorkspaceLayoutCustomRule(String, usize, #[serde_as(as = "ResolvedPathBuf")] PathBuf),
|
||||||
ClearWorkspaceLayoutRules(usize, usize),
|
ClearWorkspaceLayoutRules(usize, usize),
|
||||||
ClearNamedWorkspaceLayoutRules(String),
|
ClearNamedWorkspaceLayoutRules(String),
|
||||||
ToggleWorkspaceLayer,
|
ToggleWorkspaceLayer,
|
||||||
// Configuration
|
// Configuration
|
||||||
ReloadConfiguration,
|
ReloadConfiguration,
|
||||||
ReplaceConfiguration(PathBuf),
|
ReplaceConfiguration(#[serde_as(as = "ResolvedPathBuf")] PathBuf),
|
||||||
ReloadStaticConfiguration(PathBuf),
|
ReloadStaticConfiguration(#[serde_as(as = "ResolvedPathBuf")] PathBuf),
|
||||||
WatchConfiguration(bool),
|
WatchConfiguration(bool),
|
||||||
CompleteConfiguration,
|
CompleteConfiguration,
|
||||||
AltFocusHack(bool),
|
AltFocusHack(bool),
|
||||||
@@ -458,45 +466,28 @@ impl Sizing {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_home_path<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
|
#[cfg(test)]
|
||||||
let mut resolved_path = PathBuf::new();
|
mod tests {
|
||||||
let mut resolved = false;
|
use super::*;
|
||||||
for c in path.as_ref().components() {
|
|
||||||
match c {
|
|
||||||
std::path::Component::Normal(c)
|
|
||||||
if (c == "~" || c == "$Env:USERPROFILE" || c == "$HOME") && !resolved =>
|
|
||||||
{
|
|
||||||
let home = dirs::home_dir().ok_or_else(|| anyhow!("there is no home directory"))?;
|
|
||||||
|
|
||||||
resolved_path.extend(home.components());
|
#[test]
|
||||||
resolved = true;
|
fn deserializes() {
|
||||||
}
|
// Set a variable for testing
|
||||||
|
std::env::set_var("VAR", "VALUE");
|
||||||
|
|
||||||
std::path::Component::Normal(c) if (c == "$Env:KOMOREBI_CONFIG_HOME") && !resolved => {
|
let json = r#"{"type":"WorkspaceLayoutCustomRule","content":[0,0,0,"/path/%VAR%/d"]}"#;
|
||||||
let komorebi_config_home =
|
let message: SocketMessage = serde_json::from_str(json).unwrap();
|
||||||
PathBuf::from(std::env::var("KOMOREBI_CONFIG_HOME").ok().ok_or_else(|| {
|
|
||||||
anyhow!("there is no KOMOREBI_CONFIG_HOME environment variable set")
|
|
||||||
})?);
|
|
||||||
|
|
||||||
resolved_path.extend(komorebi_config_home.components());
|
let SocketMessage::WorkspaceLayoutCustomRule(
|
||||||
resolved = true;
|
_workspace_index,
|
||||||
}
|
_workspace_number,
|
||||||
|
_monitor_index,
|
||||||
|
path,
|
||||||
|
) = message
|
||||||
|
else {
|
||||||
|
panic!("Expected WorkspaceLayoutCustomRule");
|
||||||
|
};
|
||||||
|
|
||||||
_ => resolved_path.push(c),
|
assert_eq!(path, PathBuf::from("/path/VALUE/d"));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let parent = resolved_path
|
|
||||||
.parent()
|
|
||||||
.ok_or_else(|| anyhow!("cannot parse parent directory"))?;
|
|
||||||
|
|
||||||
Ok(if parent.is_dir() {
|
|
||||||
let file = resolved_path
|
|
||||||
.components()
|
|
||||||
.next_back()
|
|
||||||
.ok_or_else(|| anyhow!("cannot parse filename"))?;
|
|
||||||
dunce::canonicalize(parent)?.join(file)
|
|
||||||
} else {
|
|
||||||
resolved_path
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,48 +1,192 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::ffi::OsStr;
|
||||||
use std::path::Component;
|
use std::path::Component;
|
||||||
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
/// Path extension trait
|
||||||
pub trait PathExt {
|
pub trait PathExt {
|
||||||
|
/// Resolve environment variables components in a path.
|
||||||
|
///
|
||||||
|
/// Resolves the follwing formats:
|
||||||
|
/// - CMD: `%variable%`
|
||||||
|
/// - PowerShell: `$Env:variable`
|
||||||
|
/// - Bash: `$variable`.
|
||||||
fn replace_env(&self) -> PathBuf;
|
fn replace_env(&self) -> PathBuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PathExt for PathBuf {
|
/// Blanket implementation for all types that can be converted to a `Path`.
|
||||||
|
impl<P: AsRef<Path>> PathExt for P {
|
||||||
fn replace_env(&self) -> PathBuf {
|
fn replace_env(&self) -> PathBuf {
|
||||||
let mut result = PathBuf::new();
|
let mut out = PathBuf::new();
|
||||||
|
|
||||||
for component in self.components() {
|
for c in self.as_ref().components() {
|
||||||
match component {
|
match c {
|
||||||
Component::Normal(segment) => {
|
Component::Normal(mut c) => {
|
||||||
// Check if it starts with `$` or `$Env:`
|
// Special case for ~ and $HOME, replace with $Env:USERPROFILE
|
||||||
if let Some(stripped_segment) = segment.to_string_lossy().strip_prefix('$') {
|
if c == OsStr::new("~") || c.eq_ignore_ascii_case("$HOME") {
|
||||||
let var_name = if let Some(env_name) = stripped_segment.strip_prefix("Env:")
|
c = OsStr::new("$Env:USERPROFILE");
|
||||||
{
|
|
||||||
// Extract the variable name after `$Env:`
|
|
||||||
env_name
|
|
||||||
} else if stripped_segment == "HOME" {
|
|
||||||
// Special case for `$HOME`
|
|
||||||
"USERPROFILE"
|
|
||||||
} else {
|
|
||||||
// Extract the variable name after `$`
|
|
||||||
stripped_segment
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Ok(value) = env::var(var_name) {
|
|
||||||
result.push(&value); // Replace with the value
|
|
||||||
} else {
|
|
||||||
result.push(segment); // Keep as-is if variable is not found
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result.push(segment); // Keep as-is if not an environment variable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let bytes = c.as_encoded_bytes();
|
||||||
|
|
||||||
|
// %LOCALAPPDATA%
|
||||||
|
let var = if bytes[0] == b'%' && bytes[bytes.len() - 1] == b'%' {
|
||||||
|
Some(&bytes[1..bytes.len() - 1])
|
||||||
|
} else {
|
||||||
|
// prefix length is 5 for $Env: and 1 for $
|
||||||
|
// so we take the minimum of 5 and the length of the bytes
|
||||||
|
let prefix = &bytes[..5.min(bytes.len())];
|
||||||
|
let prefix = unsafe { OsStr::from_encoded_bytes_unchecked(prefix) };
|
||||||
|
|
||||||
|
// $Env:LOCALAPPDATA
|
||||||
|
if prefix.eq_ignore_ascii_case("$Env:") {
|
||||||
|
Some(&bytes[5..])
|
||||||
|
} else if bytes[0] == b'$' {
|
||||||
|
// $LOCALAPPDATA
|
||||||
|
Some(&bytes[1..])
|
||||||
|
} else {
|
||||||
|
// not a variable
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// if component is a variable, get the value from the environment
|
||||||
|
if let Some(var) = var {
|
||||||
|
let var = unsafe { OsStr::from_encoded_bytes_unchecked(var) };
|
||||||
|
if let Some(value) = env::var_os(var) {
|
||||||
|
out.push(value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if not a variable, or a value couldn't be obtained from environemnt
|
||||||
|
// then push the component as is
|
||||||
|
out.push(c);
|
||||||
}
|
}
|
||||||
_ => {
|
|
||||||
// Add other components (e.g., root, parent) as-is
|
// other components are pushed as is
|
||||||
result.push(component.as_os_str());
|
_ => out.push(c),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replace environment variables in a path. This is a wrapper around
|
||||||
|
/// [`PathExt::replace_env`] to be used in Clap arguments parsing.
|
||||||
|
pub fn replace_env_in_path(input: &str) -> Result<PathBuf, std::convert::Infallible> {
|
||||||
|
Ok(input.replace_env())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A wrapper around [`PathBuf`] that has a custom [Deserialize] implementation
|
||||||
|
/// that uses [`PathExt::replace_env`] to resolve environment variables
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ResolvedPathBuf(PathBuf);
|
||||||
|
|
||||||
|
impl ResolvedPathBuf {
|
||||||
|
/// Create a new [`ResolvedPathBuf`] from a [`PathBuf`]
|
||||||
|
pub fn new(path: PathBuf) -> Self {
|
||||||
|
Self(path.replace_env())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ResolvedPathBuf> for PathBuf {
|
||||||
|
fn from(path: ResolvedPathBuf) -> Self {
|
||||||
|
path.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serde_with::SerializeAs<PathBuf> for ResolvedPathBuf {
|
||||||
|
fn serialize_as<S>(path: &PathBuf, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
path.serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> serde_with::DeserializeAs<'de, PathBuf> for ResolvedPathBuf {
|
||||||
|
fn deserialize_as<D>(deserializer: D) -> Result<PathBuf, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let path = PathBuf::deserialize(deserializer)?;
|
||||||
|
Ok(path.replace_env())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "schemars")]
|
||||||
|
impl serde_with::schemars_0_8::JsonSchemaAs<PathBuf> for ResolvedPathBuf {
|
||||||
|
fn schema_name() -> String {
|
||||||
|
"PathBuf".to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||||
|
<PathBuf as schemars::JsonSchema>::json_schema(gen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Custom deserializer for [`Option<HashMap<usize, PathBuf>>`] that uses
|
||||||
|
/// [`PathExt::replace_env`] to resolve environment variables in the paths.
|
||||||
|
///
|
||||||
|
/// This is used in `WorkspaceConfig` struct because we can't use
|
||||||
|
/// #[serde_with::serde_as] as it doesn't handle [`Option<HashMap<usize, ResolvedPathBuf>>`]
|
||||||
|
/// quite well and generated compiler errors that can't be fixed because of Rust's orphan rule.
|
||||||
|
pub fn resolve_option_hashmap_usize_path<'de, D>(
|
||||||
|
deserializer: D,
|
||||||
|
) -> Result<Option<HashMap<usize, PathBuf>>, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let map = Option::<HashMap<usize, PathBuf>>::deserialize(deserializer)?;
|
||||||
|
Ok(map.map(|map| map.into_iter().map(|(k, v)| (k, v.replace_env())).collect()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
// helper functions
|
||||||
|
fn expected<P: AsRef<Path>>(p: P) -> PathBuf {
|
||||||
|
// Ensure that the path is using the correct path separator for the OS.
|
||||||
|
p.as_ref().components().collect::<PathBuf>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve<P: AsRef<Path>>(p: P) -> PathBuf {
|
||||||
|
p.replace_env()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn resolves_env_vars() {
|
||||||
|
// Set a variable for testing
|
||||||
|
std::env::set_var("VAR", "VALUE");
|
||||||
|
|
||||||
|
// %VAR% format
|
||||||
|
assert_eq!(resolve("/path/%VAR%/d"), expected("/path/VALUE/d"));
|
||||||
|
// $env:VAR format
|
||||||
|
assert_eq!(resolve("/path/$env:VAR/d"), expected("/path/VALUE/d"));
|
||||||
|
// $VAR format
|
||||||
|
assert_eq!(resolve("/path/$VAR/d"), expected("/path/VALUE/d"));
|
||||||
|
|
||||||
|
// non-existent variable
|
||||||
|
assert_eq!(resolve("/path/%ASD%/to/d"), expected("/path/%ASD%/to/d"));
|
||||||
|
assert_eq!(
|
||||||
|
resolve("/path/$env:ASD/to/d"),
|
||||||
|
expected("/path/$env:ASD/to/d")
|
||||||
|
);
|
||||||
|
assert_eq!(resolve("/path/$ASD/to/d"), expected("/path/$ASD/to/d"));
|
||||||
|
|
||||||
|
// Set a $env:USERPROFILE variable for testing
|
||||||
|
std::env::set_var("USERPROFILE", "C:\\Users\\user");
|
||||||
|
|
||||||
|
// ~ and $HOME should be replaced with $Env:USERPROFILE
|
||||||
|
assert_eq!(resolve("~"), expected("C:\\Users\\user"));
|
||||||
|
assert_eq!(resolve("$HOME"), expected("C:\\Users\\user"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,15 +188,16 @@ lazy_static! {
|
|||||||
Arc::new(Mutex::new(HidingBehaviour::Cloak));
|
Arc::new(Mutex::new(HidingBehaviour::Cloak));
|
||||||
pub static ref HOME_DIR: PathBuf = {
|
pub static ref HOME_DIR: PathBuf = {
|
||||||
std::env::var("KOMOREBI_CONFIG_HOME").map_or_else(|_| dirs::home_dir().expect("there is no home directory"), |home_path| {
|
std::env::var("KOMOREBI_CONFIG_HOME").map_or_else(|_| dirs::home_dir().expect("there is no home directory"), |home_path| {
|
||||||
let home = PathBuf::from(&home_path);
|
let home = home_path.replace_env();
|
||||||
|
|
||||||
if home.as_path().is_dir() {
|
assert!(
|
||||||
home
|
home.is_dir(),
|
||||||
} else {
|
"$Env:KOMOREBI_CONFIG_HOME is set to '{}', which is not a valid directory",
|
||||||
panic!(
|
home_path
|
||||||
"$Env:KOMOREBI_CONFIG_HOME is set to '{home_path}', which is not a valid directory",
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
home
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
pub static ref DATA_DIR: PathBuf = dirs::data_local_dir().expect("there is no local data directory").join("komorebi");
|
pub static ref DATA_DIR: PathBuf = dirs::data_local_dir().expect("there is no local data directory").join("komorebi");
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ use crossbeam_utils::Backoff;
|
|||||||
use komorebi::animation::AnimationEngine;
|
use komorebi::animation::AnimationEngine;
|
||||||
use komorebi::animation::ANIMATION_ENABLED_GLOBAL;
|
use komorebi::animation::ANIMATION_ENABLED_GLOBAL;
|
||||||
use komorebi::animation::ANIMATION_ENABLED_PER_ANIMATION;
|
use komorebi::animation::ANIMATION_ENABLED_PER_ANIMATION;
|
||||||
|
use komorebi::replace_env_in_path;
|
||||||
#[cfg(feature = "deadlock_detection")]
|
#[cfg(feature = "deadlock_detection")]
|
||||||
use parking_lot::deadlock;
|
use parking_lot::deadlock;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
@@ -176,6 +177,7 @@ struct Opts {
|
|||||||
tcp_port: Option<usize>,
|
tcp_port: Option<usize>,
|
||||||
/// Path to a static configuration JSON file
|
/// Path to a static configuration JSON file
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
|
#[clap(value_parser = replace_env_in_path)]
|
||||||
config: Option<PathBuf>,
|
config: Option<PathBuf>,
|
||||||
/// Do not attempt to auto-apply a dumped state temp file from a previously running instance of komorebi
|
/// Do not attempt to auto-apply a dumped state temp file from a previously running instance of komorebi
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ use crate::core::config_generation::ApplicationConfigurationGenerator;
|
|||||||
use crate::core::config_generation::ApplicationOptions;
|
use crate::core::config_generation::ApplicationOptions;
|
||||||
use crate::core::config_generation::MatchingRule;
|
use crate::core::config_generation::MatchingRule;
|
||||||
use crate::core::config_generation::MatchingStrategy;
|
use crate::core::config_generation::MatchingStrategy;
|
||||||
use crate::core::resolve_home_path;
|
|
||||||
use crate::core::AnimationStyle;
|
use crate::core::AnimationStyle;
|
||||||
use crate::core::BorderImplementation;
|
use crate::core::BorderImplementation;
|
||||||
use crate::core::BorderStyle;
|
use crate::core::BorderStyle;
|
||||||
@@ -39,6 +38,7 @@ use crate::current_virtual_desktop;
|
|||||||
use crate::monitor;
|
use crate::monitor;
|
||||||
use crate::monitor::Monitor;
|
use crate::monitor::Monitor;
|
||||||
use crate::monitor_reconciliator;
|
use crate::monitor_reconciliator;
|
||||||
|
use crate::resolve_option_hashmap_usize_path;
|
||||||
use crate::ring::Ring;
|
use crate::ring::Ring;
|
||||||
use crate::stackbar_manager::STACKBAR_FOCUSED_TEXT_COLOUR;
|
use crate::stackbar_manager::STACKBAR_FOCUSED_TEXT_COLOUR;
|
||||||
use crate::stackbar_manager::STACKBAR_FONT_FAMILY;
|
use crate::stackbar_manager::STACKBAR_FONT_FAMILY;
|
||||||
@@ -61,6 +61,7 @@ use crate::Axis;
|
|||||||
use crate::CrossBoundaryBehaviour;
|
use crate::CrossBoundaryBehaviour;
|
||||||
use crate::FloatingLayerBehaviour;
|
use crate::FloatingLayerBehaviour;
|
||||||
use crate::PredefinedAspectRatio;
|
use crate::PredefinedAspectRatio;
|
||||||
|
use crate::ResolvedPathBuf;
|
||||||
use crate::DATA_DIR;
|
use crate::DATA_DIR;
|
||||||
use crate::DEFAULT_CONTAINER_PADDING;
|
use crate::DEFAULT_CONTAINER_PADDING;
|
||||||
use crate::DEFAULT_WORKSPACE_PADDING;
|
use crate::DEFAULT_WORKSPACE_PADDING;
|
||||||
@@ -162,10 +163,12 @@ pub struct ThemeOptions {
|
|||||||
pub bar_accent: Option<komorebi_themes::Base16Value>,
|
pub bar_accent: Option<komorebi_themes::Base16Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[serde_with::serde_as]
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||||
pub struct Wallpaper {
|
pub struct Wallpaper {
|
||||||
/// Path to the wallpaper image file
|
/// Path to the wallpaper image file
|
||||||
|
#[serde_as(as = "ResolvedPathBuf")]
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
/// Generate and apply Base16 theme for this wallpaper (default: true)
|
/// Generate and apply Base16 theme for this wallpaper (default: true)
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
@@ -175,6 +178,8 @@ pub struct Wallpaper {
|
|||||||
pub theme_options: Option<ThemeOptions>,
|
pub theme_options: Option<ThemeOptions>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// serde_as must be before derive
|
||||||
|
#[serde_with::serde_as]
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||||
pub struct WorkspaceConfig {
|
pub struct WorkspaceConfig {
|
||||||
@@ -185,12 +190,14 @@ pub struct WorkspaceConfig {
|
|||||||
pub layout: Option<DefaultLayout>,
|
pub layout: Option<DefaultLayout>,
|
||||||
/// END OF LIFE FEATURE: Custom Layout (default: None)
|
/// END OF LIFE FEATURE: Custom Layout (default: None)
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
#[serde_as(as = "Option<ResolvedPathBuf>")]
|
||||||
pub custom_layout: Option<PathBuf>,
|
pub custom_layout: Option<PathBuf>,
|
||||||
/// Layout rules in the format of threshold => layout (default: None)
|
/// Layout rules in the format of threshold => layout (default: None)
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub layout_rules: Option<HashMap<usize, DefaultLayout>>,
|
pub layout_rules: Option<HashMap<usize, DefaultLayout>>,
|
||||||
/// END OF LIFE FEATURE: Custom layout rules (default: None)
|
/// END OF LIFE FEATURE: Custom layout rules (default: None)
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
#[serde(deserialize_with = "resolve_option_hashmap_usize_path", default)]
|
||||||
pub custom_layout_rules: Option<HashMap<usize, PathBuf>>,
|
pub custom_layout_rules: Option<HashMap<usize, PathBuf>>,
|
||||||
/// Container padding (default: global)
|
/// Container padding (default: global)
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
@@ -369,16 +376,18 @@ impl From<&Monitor> for MonitorConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[serde_with::serde_as]
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum AppSpecificConfigurationPath {
|
pub enum AppSpecificConfigurationPath {
|
||||||
/// A single applications.json file
|
/// A single applications.json file
|
||||||
Single(PathBuf),
|
Single(#[serde_as(as = "ResolvedPathBuf")] PathBuf),
|
||||||
/// Multiple applications.json files
|
/// Multiple applications.json files
|
||||||
Multiple(Vec<PathBuf>),
|
Multiple(#[serde_as(as = "Vec<ResolvedPathBuf>")] Vec<PathBuf>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[serde_with::serde_as]
|
||||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
|
||||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||||
/// The `komorebi.json` static configuration file reference for `v0.1.36`
|
/// The `komorebi.json` static configuration file reference for `v0.1.36`
|
||||||
@@ -519,6 +528,7 @@ pub struct StaticConfig {
|
|||||||
/// Komorebi status bar configuration files for multiple instances on different monitors
|
/// Komorebi status bar configuration files for multiple instances on different monitors
|
||||||
// this option is a little special because it is only consumed by komorebic
|
// this option is a little special because it is only consumed by komorebic
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
#[serde_as(as = "Option<Vec<ResolvedPathBuf>>")]
|
||||||
pub bar_configurations: Option<Vec<PathBuf>>,
|
pub bar_configurations: Option<Vec<PathBuf>>,
|
||||||
/// HEAVILY DISCOURAGED: Identify applications for which komorebi should forcibly remove title bars
|
/// HEAVILY DISCOURAGED: Identify applications for which komorebi should forcibly remove title bars
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
@@ -1171,44 +1181,7 @@ impl StaticConfig {
|
|||||||
|
|
||||||
pub fn read(path: &PathBuf) -> Result<Self> {
|
pub fn read(path: &PathBuf) -> Result<Self> {
|
||||||
let content = std::fs::read_to_string(path)?;
|
let content = std::fs::read_to_string(path)?;
|
||||||
let mut value: Self = serde_json::from_str(&content)?;
|
serde_json::from_str(&content).map_err(Into::into)
|
||||||
|
|
||||||
if let Some(path) = &mut value.app_specific_configuration_path {
|
|
||||||
match path {
|
|
||||||
AppSpecificConfigurationPath::Single(path) => {
|
|
||||||
*path = resolve_home_path(&*path)?;
|
|
||||||
}
|
|
||||||
AppSpecificConfigurationPath::Multiple(paths) => {
|
|
||||||
for path in paths {
|
|
||||||
*path = resolve_home_path(&*path)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(monitors) = &mut value.monitors {
|
|
||||||
for m in monitors {
|
|
||||||
for w in &mut m.workspaces {
|
|
||||||
if let Some(path) = &mut w.custom_layout {
|
|
||||||
*path = resolve_home_path(&*path)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(map) = &mut w.custom_layout_rules {
|
|
||||||
for path in map.values_mut() {
|
|
||||||
*path = resolve_home_path(&*path)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(bar_configurations) = &mut value.bar_configurations {
|
|
||||||
for path in bar_configurations {
|
|
||||||
*path = resolve_home_path(&*path)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
@@ -1773,7 +1746,6 @@ fn handle_asc_file(
|
|||||||
Some(ext) => match ext.to_string_lossy().to_string().as_str() {
|
Some(ext) => match ext.to_string_lossy().to_string().as_str() {
|
||||||
"yaml" => {
|
"yaml" => {
|
||||||
tracing::info!("loading applications.yaml from: {}", path.display());
|
tracing::info!("loading applications.yaml from: {}", path.display());
|
||||||
let path = resolve_home_path(path)?;
|
|
||||||
let content = std::fs::read_to_string(path)?;
|
let content = std::fs::read_to_string(path)?;
|
||||||
let asc = ApplicationConfigurationGenerator::load(&content)?;
|
let asc = ApplicationConfigurationGenerator::load(&content)?;
|
||||||
|
|
||||||
@@ -1822,8 +1794,7 @@ fn handle_asc_file(
|
|||||||
}
|
}
|
||||||
"json" => {
|
"json" => {
|
||||||
tracing::info!("loading applications.json from: {}", path.display());
|
tracing::info!("loading applications.json from: {}", path.display());
|
||||||
let path = resolve_home_path(path)?;
|
let mut asc = ApplicationSpecificConfiguration::load(path)?;
|
||||||
let mut asc = ApplicationSpecificConfiguration::load(&path)?;
|
|
||||||
|
|
||||||
for entry in asc.values_mut() {
|
for entry in asc.values_mut() {
|
||||||
match entry {
|
match entry {
|
||||||
@@ -1885,7 +1856,10 @@ fn handle_asc_file(
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::StaticConfig;
|
use crate::StaticConfig;
|
||||||
|
use crate::WorkspaceConfig;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn backwards_compat() {
|
fn backwards_compat() {
|
||||||
@@ -1914,4 +1888,40 @@ mod tests {
|
|||||||
StaticConfig::read_raw(&config).unwrap();
|
StaticConfig::read_raw(&config).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_custom_layout_rules() {
|
||||||
|
// set an environment variable for testing
|
||||||
|
std::env::set_var("VAR", "VALUE");
|
||||||
|
|
||||||
|
let config = r#"
|
||||||
|
{
|
||||||
|
"name": "Test",
|
||||||
|
"custom_layout_rules": {
|
||||||
|
"1": "path/to/dir",
|
||||||
|
"2": "path/to/%VAR%"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let config = serde_json::from_str::<WorkspaceConfig>(config).unwrap();
|
||||||
|
|
||||||
|
let custom_layout_rules = config.custom_layout_rules.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
custom_layout_rules.get(&1).unwrap(),
|
||||||
|
&PathBuf::from("path/to/dir")
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
custom_layout_rules.get(&2).unwrap(),
|
||||||
|
&PathBuf::from("path/to/VALUE")
|
||||||
|
);
|
||||||
|
|
||||||
|
let config = r#"
|
||||||
|
{
|
||||||
|
"name": "Test",
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let config = serde_json::from_str::<WorkspaceConfig>(config).unwrap();
|
||||||
|
assert_eq!(config.custom_layout_rules, None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,13 @@
|
|||||||
#![allow(clippy::missing_errors_doc, clippy::doc_markdown)]
|
#![allow(clippy::missing_errors_doc, clippy::doc_markdown)]
|
||||||
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
|
use komorebi_client::replace_env_in_path;
|
||||||
|
use komorebi_client::PathExt;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::BufRead;
|
use std::io::BufRead;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::Path;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
@@ -22,7 +23,6 @@ use color_eyre::eyre::bail;
|
|||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use dirs::data_local_dir;
|
use dirs::data_local_dir;
|
||||||
use fs_tail::TailedFile;
|
use fs_tail::TailedFile;
|
||||||
use komorebi_client::resolve_home_path;
|
|
||||||
use komorebi_client::send_message;
|
use komorebi_client::send_message;
|
||||||
use komorebi_client::send_query;
|
use komorebi_client::send_query;
|
||||||
use komorebi_client::AppSpecificConfigurationPath;
|
use komorebi_client::AppSpecificConfigurationPath;
|
||||||
@@ -64,8 +64,7 @@ lazy_static! {
|
|||||||
std::env::var("KOMOREBI_CONFIG_HOME").map_or_else(
|
std::env::var("KOMOREBI_CONFIG_HOME").map_or_else(
|
||||||
|_| dirs::home_dir().expect("there is no home directory"),
|
|_| dirs::home_dir().expect("there is no home directory"),
|
||||||
|home_path| {
|
|home_path| {
|
||||||
let home = PathBuf::from(&home_path);
|
let home = home_path.replace_env();
|
||||||
|
|
||||||
if home.as_path().is_dir() {
|
if home.as_path().is_dir() {
|
||||||
HAS_CUSTOM_CONFIG_HOME.store(true, Ordering::SeqCst);
|
HAS_CUSTOM_CONFIG_HOME.store(true, Ordering::SeqCst);
|
||||||
home
|
home
|
||||||
@@ -88,12 +87,12 @@ lazy_static! {
|
|||||||
.join(".config")
|
.join(".config")
|
||||||
},
|
},
|
||||||
|home_path| {
|
|home_path| {
|
||||||
let whkd_config_home = PathBuf::from(&home_path);
|
let whkd_config_home = home_path.replace_env();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
whkd_config_home.as_path().is_dir(),
|
whkd_config_home.is_dir(),
|
||||||
"$Env:WHKD_CONFIG_HOME is set to '{}', which is not a valid directory",
|
"$Env:WHKD_CONFIG_HOME is set to '{}', which is not a valid directory",
|
||||||
whkd_config_home.to_string_lossy()
|
home_path
|
||||||
);
|
);
|
||||||
|
|
||||||
whkd_config_home
|
whkd_config_home
|
||||||
@@ -299,6 +298,7 @@ pub struct WorkspaceCustomLayout {
|
|||||||
workspace: usize,
|
workspace: usize,
|
||||||
|
|
||||||
/// JSON or YAML file from which the custom layout definition should be loaded
|
/// JSON or YAML file from which the custom layout definition should be loaded
|
||||||
|
#[clap(value_parser = replace_env_in_path)]
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,6 +308,7 @@ pub struct NamedWorkspaceCustomLayout {
|
|||||||
workspace: String,
|
workspace: String,
|
||||||
|
|
||||||
/// JSON or YAML file from which the custom layout definition should be loaded
|
/// JSON or YAML file from which the custom layout definition should be loaded
|
||||||
|
#[clap(value_parser = replace_env_in_path)]
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,6 +351,7 @@ pub struct WorkspaceCustomLayoutRule {
|
|||||||
at_container_count: usize,
|
at_container_count: usize,
|
||||||
|
|
||||||
/// JSON or YAML file from which the custom layout definition should be loaded
|
/// JSON or YAML file from which the custom layout definition should be loaded
|
||||||
|
#[clap(value_parser = replace_env_in_path)]
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,6 +364,7 @@ pub struct NamedWorkspaceCustomLayoutRule {
|
|||||||
at_container_count: usize,
|
at_container_count: usize,
|
||||||
|
|
||||||
/// JSON or YAML file from which the custom layout definition should be loaded
|
/// JSON or YAML file from which the custom layout definition should be loaded
|
||||||
|
#[clap(value_parser = replace_env_in_path)]
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -770,6 +773,7 @@ struct Start {
|
|||||||
ffm: bool,
|
ffm: bool,
|
||||||
/// Path to a static configuration JSON file
|
/// Path to a static configuration JSON file
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
|
#[clap(value_parser = replace_env_in_path)]
|
||||||
config: Option<PathBuf>,
|
config: Option<PathBuf>,
|
||||||
/// Wait for 'komorebic complete-configuration' to be sent before processing events
|
/// Wait for 'komorebic complete-configuration' to be sent before processing events
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
@@ -832,18 +836,21 @@ struct Kill {
|
|||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
struct SaveResize {
|
struct SaveResize {
|
||||||
/// File to which the resize layout dimensions should be saved
|
/// File to which the resize layout dimensions should be saved
|
||||||
|
#[clap(value_parser = replace_env_in_path)]
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
struct LoadResize {
|
struct LoadResize {
|
||||||
/// File from which the resize layout dimensions should be loaded
|
/// File from which the resize layout dimensions should be loaded
|
||||||
|
#[clap(value_parser = replace_env_in_path)]
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
struct LoadCustomLayout {
|
struct LoadCustomLayout {
|
||||||
/// JSON or YAML file from which the custom layout definition should be loaded
|
/// JSON or YAML file from which the custom layout definition should be loaded
|
||||||
|
#[clap(value_parser = replace_env_in_path)]
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -874,28 +881,34 @@ struct UnsubscribePipe {
|
|||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
struct AhkAppSpecificConfiguration {
|
struct AhkAppSpecificConfiguration {
|
||||||
/// YAML file from which the application-specific configurations should be loaded
|
/// YAML file from which the application-specific configurations should be loaded
|
||||||
|
#[clap(value_parser = replace_env_in_path)]
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
/// Optional YAML file of overrides to apply over the first file
|
/// Optional YAML file of overrides to apply over the first file
|
||||||
|
#[clap(value_parser = replace_env_in_path)]
|
||||||
override_path: Option<PathBuf>,
|
override_path: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
struct PwshAppSpecificConfiguration {
|
struct PwshAppSpecificConfiguration {
|
||||||
/// YAML file from which the application-specific configurations should be loaded
|
/// YAML file from which the application-specific configurations should be loaded
|
||||||
|
#[clap(value_parser = replace_env_in_path)]
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
/// Optional YAML file of overrides to apply over the first file
|
/// Optional YAML file of overrides to apply over the first file
|
||||||
|
#[clap(value_parser = replace_env_in_path)]
|
||||||
override_path: Option<PathBuf>,
|
override_path: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
struct FormatAppSpecificConfiguration {
|
struct FormatAppSpecificConfiguration {
|
||||||
/// YAML file from which the application-specific configurations should be loaded
|
/// YAML file from which the application-specific configurations should be loaded
|
||||||
|
#[clap(value_parser = replace_env_in_path)]
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
struct ConvertAppSpecificConfiguration {
|
struct ConvertAppSpecificConfiguration {
|
||||||
/// YAML file from which the application-specific configurations should be loaded
|
/// YAML file from which the application-specific configurations should be loaded
|
||||||
|
#[clap(value_parser = replace_env_in_path)]
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -909,6 +922,7 @@ struct AltFocusHack {
|
|||||||
struct EnableAutostart {
|
struct EnableAutostart {
|
||||||
/// Path to a static configuration JSON file
|
/// Path to a static configuration JSON file
|
||||||
#[clap(action, short, long)]
|
#[clap(action, short, long)]
|
||||||
|
#[clap(value_parser = replace_env_in_path)]
|
||||||
config: Option<PathBuf>,
|
config: Option<PathBuf>,
|
||||||
/// Enable komorebi's custom focus-follows-mouse implementation
|
/// Enable komorebi's custom focus-follows-mouse implementation
|
||||||
#[clap(hide = true)]
|
#[clap(hide = true)]
|
||||||
@@ -932,12 +946,14 @@ struct EnableAutostart {
|
|||||||
struct Check {
|
struct Check {
|
||||||
/// Path to a static configuration JSON file
|
/// Path to a static configuration JSON file
|
||||||
#[clap(action, short, long)]
|
#[clap(action, short, long)]
|
||||||
|
#[clap(value_parser = replace_env_in_path)]
|
||||||
komorebi_config: Option<PathBuf>,
|
komorebi_config: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
struct ReplaceConfiguration {
|
struct ReplaceConfiguration {
|
||||||
/// Static configuration JSON file from which the configuration should be loaded
|
/// Static configuration JSON file from which the configuration should be loaded
|
||||||
|
#[clap(value_parser = replace_env_in_path)]
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1677,7 +1693,7 @@ fn main() -> Result<()> {
|
|||||||
println!("Application specific configuration file path has not been set. Try running 'komorebic fetch-asc'\n");
|
println!("Application specific configuration file path has not been set. Try running 'komorebic fetch-asc'\n");
|
||||||
}
|
}
|
||||||
Some(AppSpecificConfigurationPath::Single(path)) => {
|
Some(AppSpecificConfigurationPath::Single(path)) => {
|
||||||
if !Path::exists(Path::new(&path)) {
|
if !path.exists() {
|
||||||
println!("Application specific configuration file path '{}' does not exist. Try running 'komorebic fetch-asc'\n", path.display());
|
println!("Application specific configuration file path '{}' does not exist. Try running 'komorebic fetch-asc'\n", path.display());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1690,8 +1706,7 @@ fn main() -> Result<()> {
|
|||||||
// errors
|
// errors
|
||||||
let _ = serde_json::from_str::<StaticConfig>(&config_source)?;
|
let _ = serde_json::from_str::<StaticConfig>(&config_source)?;
|
||||||
|
|
||||||
let path = resolve_home_path(static_config)?;
|
let raw = std::fs::read_to_string(static_config)?;
|
||||||
let raw = std::fs::read_to_string(path)?;
|
|
||||||
StaticConfig::aliases(&raw);
|
StaticConfig::aliases(&raw);
|
||||||
StaticConfig::deprecated(&raw);
|
StaticConfig::deprecated(&raw);
|
||||||
StaticConfig::end_of_life(&raw);
|
StaticConfig::end_of_life(&raw);
|
||||||
@@ -1994,13 +2009,13 @@ fn main() -> Result<()> {
|
|||||||
send_message(&SocketMessage::WorkspaceLayoutCustom(
|
send_message(&SocketMessage::WorkspaceLayoutCustom(
|
||||||
arg.monitor,
|
arg.monitor,
|
||||||
arg.workspace,
|
arg.workspace,
|
||||||
resolve_home_path(arg.path)?,
|
arg.path,
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
SubCommand::NamedWorkspaceCustomLayout(arg) => {
|
SubCommand::NamedWorkspaceCustomLayout(arg) => {
|
||||||
send_message(&SocketMessage::NamedWorkspaceLayoutCustom(
|
send_message(&SocketMessage::NamedWorkspaceLayoutCustom(
|
||||||
arg.workspace,
|
arg.workspace,
|
||||||
resolve_home_path(arg.path)?,
|
arg.path,
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
SubCommand::WorkspaceLayoutRule(arg) => {
|
SubCommand::WorkspaceLayoutRule(arg) => {
|
||||||
@@ -2023,14 +2038,14 @@ fn main() -> Result<()> {
|
|||||||
arg.monitor,
|
arg.monitor,
|
||||||
arg.workspace,
|
arg.workspace,
|
||||||
arg.at_container_count,
|
arg.at_container_count,
|
||||||
resolve_home_path(arg.path)?,
|
arg.path,
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
SubCommand::NamedWorkspaceCustomLayoutRule(arg) => {
|
SubCommand::NamedWorkspaceCustomLayoutRule(arg) => {
|
||||||
send_message(&SocketMessage::NamedWorkspaceLayoutCustomRule(
|
send_message(&SocketMessage::NamedWorkspaceLayoutCustomRule(
|
||||||
arg.workspace,
|
arg.workspace,
|
||||||
arg.at_container_count,
|
arg.at_container_count,
|
||||||
resolve_home_path(arg.path)?,
|
arg.path,
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
SubCommand::ClearWorkspaceLayoutRules(arg) => {
|
SubCommand::ClearWorkspaceLayoutRules(arg) => {
|
||||||
@@ -2103,13 +2118,12 @@ fn main() -> Result<()> {
|
|||||||
|
|
||||||
let mut flags = vec![];
|
let mut flags = vec![];
|
||||||
if let Some(config) = &arg.config {
|
if let Some(config) = &arg.config {
|
||||||
let path = resolve_home_path(config)?;
|
if !config.is_file() {
|
||||||
if !path.is_file() {
|
bail!("could not find file: {}", config.display());
|
||||||
bail!("could not find file: {}", path.display());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// we don't need to replace UNC prefix here as `resolve_home_path` already did
|
let config = dunce::simplified(config);
|
||||||
flags.push(format!("'--config=\"{}\"'", path.display()));
|
flags.push(format!("'--config=\"{}\"'", config.display()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if arg.ffm {
|
if arg.ffm {
|
||||||
@@ -2128,17 +2142,12 @@ fn main() -> Result<()> {
|
|||||||
flags.push("'--clean-state'".to_string());
|
flags.push("'--clean-state'".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let exec = exec.unwrap_or("komorebi.exe");
|
||||||
let script = if flags.is_empty() {
|
let script = if flags.is_empty() {
|
||||||
format!(
|
format!("Start-Process '{exec}' -WindowStyle hidden",)
|
||||||
"Start-Process '{}' -WindowStyle hidden",
|
|
||||||
exec.unwrap_or("komorebi.exe")
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
let argument_list = flags.join(",");
|
let argument_list = flags.join(",");
|
||||||
format!(
|
format!("Start-Process '{exec}' -ArgumentList {argument_list} -WindowStyle hidden",)
|
||||||
"Start-Process '{}' -ArgumentList {argument_list} -WindowStyle hidden",
|
|
||||||
exec.unwrap_or("komorebi.exe")
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut system = sysinfo::System::new_all();
|
let mut system = sysinfo::System::new_all();
|
||||||
@@ -2181,9 +2190,8 @@ fn main() -> Result<()> {
|
|||||||
if !running {
|
if !running {
|
||||||
println!("\nRunning komorebi.exe directly for detailed error output\n");
|
println!("\nRunning komorebi.exe directly for detailed error output\n");
|
||||||
if let Some(config) = arg.config {
|
if let Some(config) = arg.config {
|
||||||
let path = resolve_home_path(config)?;
|
|
||||||
if let Ok(output) = Command::new("komorebi.exe")
|
if let Ok(output) = Command::new("komorebi.exe")
|
||||||
.arg(format!("'--config=\"{}\"'", path.display()))
|
.arg(format!("'--config=\"{}\"'", config.display()))
|
||||||
.output()
|
.output()
|
||||||
{
|
{
|
||||||
println!("{}", String::from_utf8(output.stderr)?);
|
println!("{}", String::from_utf8(output.stderr)?);
|
||||||
@@ -2233,25 +2241,20 @@ if (!(Get-Process whkd -ErrorAction SilentlyContinue))
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let static_config = arg.config.clone().map_or_else(
|
let static_config = arg.config.clone().or_else(|| {
|
||||||
|| {
|
let komorebi_json = HOME_DIR.join("komorebi.json");
|
||||||
let komorebi_json = HOME_DIR.join("komorebi.json");
|
komorebi_json.is_file().then_some(komorebi_json)
|
||||||
if komorebi_json.is_file() {
|
});
|
||||||
Option::from(komorebi_json)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Option::from,
|
|
||||||
);
|
|
||||||
|
|
||||||
if arg.bar {
|
if arg.bar {
|
||||||
if let Some(config) = &static_config {
|
if let Some(config) = &static_config {
|
||||||
let mut config = StaticConfig::read(config)?;
|
let mut config = StaticConfig::read(config)?;
|
||||||
if let Some(display_bar_configurations) = &mut config.bar_configurations {
|
if let Some(display_bar_configurations) = &mut config.bar_configurations {
|
||||||
for config_file_path in &mut *display_bar_configurations {
|
for config_file_path in &mut *display_bar_configurations {
|
||||||
let script = r#"Start-Process "komorebi-bar" '"--config" "CONFIGFILE"' -WindowStyle hidden"#
|
let script = format!(
|
||||||
.replace("CONFIGFILE", &config_file_path.to_string_lossy());
|
r#"Start-Process "komorebi-bar" '"--config" "{}"' -WindowStyle hidden"#,
|
||||||
|
config_file_path.to_string_lossy()
|
||||||
|
);
|
||||||
|
|
||||||
match powershell_script::run(&script) {
|
match powershell_script::run(&script) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
@@ -2313,21 +2316,13 @@ if (!(Get-Process masir -ErrorAction SilentlyContinue))
|
|||||||
println!("\n# Documentation");
|
println!("\n# Documentation");
|
||||||
println!("* Read the docs https://lgug2z.github.io/komorebi - Quickly search through all komorebic commands");
|
println!("* Read the docs https://lgug2z.github.io/komorebi - Quickly search through all komorebic commands");
|
||||||
|
|
||||||
let bar_config = arg.config.map_or_else(
|
let bar_config = arg.config.or_else(|| {
|
||||||
|| {
|
let bar_json = HOME_DIR.join("komorebi.bar.json");
|
||||||
let bar_json = HOME_DIR.join("komorebi.bar.json");
|
bar_json.is_file().then_some(bar_json)
|
||||||
if bar_json.is_file() {
|
});
|
||||||
Option::from(bar_json)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Option::from,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(config) = &static_config {
|
if let Some(config) = &static_config {
|
||||||
let path = resolve_home_path(config)?;
|
let raw = std::fs::read_to_string(config)?;
|
||||||
let raw = std::fs::read_to_string(path)?;
|
|
||||||
StaticConfig::aliases(&raw);
|
StaticConfig::aliases(&raw);
|
||||||
StaticConfig::deprecated(&raw);
|
StaticConfig::deprecated(&raw);
|
||||||
StaticConfig::end_of_life(&raw);
|
StaticConfig::end_of_life(&raw);
|
||||||
@@ -2629,9 +2624,7 @@ if (Get-Command Get-CimInstance -ErrorAction SilentlyContinue) {
|
|||||||
send_message(&SocketMessage::CycleLayout(arg.cycle_direction))?;
|
send_message(&SocketMessage::CycleLayout(arg.cycle_direction))?;
|
||||||
}
|
}
|
||||||
SubCommand::LoadCustomLayout(arg) => {
|
SubCommand::LoadCustomLayout(arg) => {
|
||||||
send_message(&SocketMessage::ChangeLayoutCustom(resolve_home_path(
|
send_message(&SocketMessage::ChangeLayoutCustom(arg.path))?;
|
||||||
arg.path,
|
|
||||||
)?))?;
|
|
||||||
}
|
}
|
||||||
SubCommand::FlipLayout(arg) => {
|
SubCommand::FlipLayout(arg) => {
|
||||||
send_message(&SocketMessage::FlipLayout(arg.axis))?;
|
send_message(&SocketMessage::FlipLayout(arg.axis))?;
|
||||||
@@ -2808,10 +2801,10 @@ if (Get-Command Get-CimInstance -ErrorAction SilentlyContinue) {
|
|||||||
send_message(&SocketMessage::QuickLoad)?;
|
send_message(&SocketMessage::QuickLoad)?;
|
||||||
}
|
}
|
||||||
SubCommand::SaveResize(arg) => {
|
SubCommand::SaveResize(arg) => {
|
||||||
send_message(&SocketMessage::Save(resolve_home_path(arg.path)?))?;
|
send_message(&SocketMessage::Save(arg.path))?;
|
||||||
}
|
}
|
||||||
SubCommand::LoadResize(arg) => {
|
SubCommand::LoadResize(arg) => {
|
||||||
send_message(&SocketMessage::Load(resolve_home_path(arg.path)?))?;
|
send_message(&SocketMessage::Load(arg.path))?;
|
||||||
}
|
}
|
||||||
SubCommand::SubscribeSocket(arg) => {
|
SubCommand::SubscribeSocket(arg) => {
|
||||||
send_message(&SocketMessage::AddSubscriberSocket(arg.socket))?;
|
send_message(&SocketMessage::AddSubscriberSocket(arg.socket))?;
|
||||||
@@ -2923,9 +2916,9 @@ if (Get-Command Get-CimInstance -ErrorAction SilentlyContinue) {
|
|||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
SubCommand::AhkAppSpecificConfiguration(arg) => {
|
SubCommand::AhkAppSpecificConfiguration(arg) => {
|
||||||
let content = std::fs::read_to_string(resolve_home_path(arg.path)?)?;
|
let content = std::fs::read_to_string(arg.path)?;
|
||||||
let lines = if let Some(override_path) = arg.override_path {
|
let lines = if let Some(override_path) = arg.override_path {
|
||||||
let override_content = std::fs::read_to_string(resolve_home_path(override_path)?)?;
|
let override_content = std::fs::read_to_string(override_path)?;
|
||||||
|
|
||||||
ApplicationConfigurationGenerator::generate_ahk(
|
ApplicationConfigurationGenerator::generate_ahk(
|
||||||
&content,
|
&content,
|
||||||
@@ -2950,9 +2943,9 @@ if (Get-Command Get-CimInstance -ErrorAction SilentlyContinue) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
SubCommand::PwshAppSpecificConfiguration(arg) => {
|
SubCommand::PwshAppSpecificConfiguration(arg) => {
|
||||||
let content = std::fs::read_to_string(resolve_home_path(arg.path)?)?;
|
let content = std::fs::read_to_string(arg.path)?;
|
||||||
let lines = if let Some(override_path) = arg.override_path {
|
let lines = if let Some(override_path) = arg.override_path {
|
||||||
let override_content = std::fs::read_to_string(resolve_home_path(override_path)?)?;
|
let override_content = std::fs::read_to_string(override_path)?;
|
||||||
|
|
||||||
ApplicationConfigurationGenerator::generate_pwsh(
|
ApplicationConfigurationGenerator::generate_pwsh(
|
||||||
&content,
|
&content,
|
||||||
@@ -2977,23 +2970,21 @@ if (Get-Command Get-CimInstance -ErrorAction SilentlyContinue) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
SubCommand::ConvertAppSpecificConfiguration(arg) => {
|
SubCommand::ConvertAppSpecificConfiguration(arg) => {
|
||||||
let file_path = resolve_home_path(arg.path)?;
|
let content = std::fs::read_to_string(arg.path)?;
|
||||||
let content = std::fs::read_to_string(&file_path)?;
|
|
||||||
let mut asc = ApplicationConfigurationGenerator::load(&content)?;
|
let mut asc = ApplicationConfigurationGenerator::load(&content)?;
|
||||||
asc.sort_by(|a, b| a.name.cmp(&b.name));
|
asc.sort_by(|a, b| a.name.cmp(&b.name));
|
||||||
let v2 = ApplicationSpecificConfiguration::from(asc);
|
let v2 = ApplicationSpecificConfiguration::from(asc);
|
||||||
println!("{}", serde_json::to_string_pretty(&v2)?);
|
println!("{}", serde_json::to_string_pretty(&v2)?);
|
||||||
}
|
}
|
||||||
SubCommand::FormatAppSpecificConfiguration(arg) => {
|
SubCommand::FormatAppSpecificConfiguration(arg) => {
|
||||||
let file_path = resolve_home_path(arg.path)?;
|
let content = std::fs::read_to_string(&arg.path)?;
|
||||||
let content = std::fs::read_to_string(&file_path)?;
|
|
||||||
let formatted_content = ApplicationConfigurationGenerator::format(&content)?;
|
let formatted_content = ApplicationConfigurationGenerator::format(&content)?;
|
||||||
|
|
||||||
let mut file = OpenOptions::new()
|
let mut file = OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
.create(true)
|
.create(true)
|
||||||
.truncate(true)
|
.truncate(true)
|
||||||
.open(file_path)?;
|
.open(arg.path)?;
|
||||||
|
|
||||||
file.write_all(formatted_content.as_bytes())?;
|
file.write_all(formatted_content.as_bytes())?;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user