diff --git a/Cargo.lock b/Cargo.lock index 6ee55693..d1a4d0bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" dependencies = [ "gimli", ] @@ -17,6 +17,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aho-corasick" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] + [[package]] name = "anstream" version = "0.3.2" @@ -34,15 +43,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" +checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" [[package]] name = "anstyle-parse" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" dependencies = [ "utf8parse", ] @@ -74,9 +83,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" dependencies = [ "addr2line", "cc", @@ -87,6 +96,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" + [[package]] name = "bitflags" version = "1.3.2" @@ -95,9 +110,21 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.1" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "bytes" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6776fc96284a0bb647b615056fc496d1fe1644a7ab01829818a6d91cae888b84" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "cc" @@ -150,7 +177,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -192,6 +219,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.4" @@ -221,9 +258,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.14" +version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", "cfg-if 1.0.0", @@ -234,9 +271,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if 1.0.0", ] @@ -293,11 +330,20 @@ version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +[[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "equivalent" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" @@ -357,6 +403,36 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + [[package]] name = "fs-tail" version = "0.1.4" @@ -401,11 +477,59 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-core", + "futures-io", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if 1.0.0", "libc", @@ -426,9 +550,28 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + +[[package]] +name = "h2" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 1.9.3", + "slab", + "tokio", + "tokio-util", + "tracing", +] [[package]] name = "hashbrown" @@ -450,18 +593,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hotwatch" @@ -473,6 +607,87 @@ dependencies = [ "notify", ] +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "indenter" version = "0.3.3" @@ -530,11 +745,11 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi", "libc", "windows-sys 0.48.0", ] @@ -548,23 +763,37 @@ dependencies = [ "libc", ] +[[package]] +name = "ipnet" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" + [[package]] name = "is-terminal" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix", + "hermit-abi", + "rustix 0.38.4", "windows-sys 0.48.0", ] [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] [[package]] name = "kernel32-sys" @@ -580,7 +809,7 @@ dependencies = [ name = "komorebi" version = "0.1.16" dependencies = [ - "bitflags 2.3.1", + "bitflags 2.3.3", "clap", "color-eyre", "crossbeam-channel", @@ -611,7 +840,7 @@ dependencies = [ "windows-implement", "windows-interface", "winput", - "winreg", + "winreg 0.50.0", ] [[package]] @@ -642,11 +871,13 @@ dependencies = [ "lazy_static", "paste", "powershell_script", + "reqwest", "serde", "serde_json", "serde_yaml", "sysinfo", "uds_windows", + "which", "windows", ] @@ -664,21 +895,27 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "linux-raw-sys" -version = "0.3.7" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" +checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -686,12 +923,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if 1.0.0", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "matchers" @@ -699,7 +933,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata", + "regex-automata 0.1.10", ] [[package]] @@ -710,18 +944,24 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" dependencies = [ "autocfg", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "miniz_oxide" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] @@ -745,6 +985,17 @@ dependencies = [ "winapi 0.2.8", ] +[[package]] +name = "mio" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + [[package]] name = "mio-extras" version = "2.0.6" @@ -753,7 +1004,7 @@ checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" dependencies = [ "lazycell", "log", - "mio", + "mio 0.6.23", "slab", ] @@ -787,6 +1038,24 @@ dependencies = [ "rand", ] +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "net2" version = "0.2.39" @@ -822,7 +1091,7 @@ dependencies = [ "fsevent-sys", "inotify", "libc", - "mio", + "mio 0.6.23", "mio-extras", "walkdir", "winapi 0.3.9", @@ -849,28 +1118,72 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] [[package]] name = "object" -version = "0.30.3" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "openssl" +version = "0.10.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +dependencies = [ + "bitflags 1.3.2", + "cfg-if 1.0.0", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.25", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] [[package]] name = "option-ext" @@ -913,25 +1226,31 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "backtrace", "cfg-if 1.0.0", "libc", "petgraph", - "redox_syscall 0.2.16", + "redox_syscall 0.3.5", "smallvec", "thread-id", - "windows-sys 0.45.0", + "windows-targets", ] [[package]] name = "paste" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "petgraph" @@ -945,9 +1264,21 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "powershell_script" @@ -987,9 +1318,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" dependencies = [ "unicode-ident", ] @@ -1086,11 +1417,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.1" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" dependencies = [ - "regex-syntax 0.7.1", + "aho-corasick", + "memchr", + "regex-automata 0.3.3", + "regex-syntax 0.7.4", ] [[package]] @@ -1102,6 +1436,17 @@ dependencies = [ "regex-syntax 0.6.29", ] +[[package]] +name = "regex-automata" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.4", +] + [[package]] name = "regex-syntax" version = "0.6.29" @@ -1110,9 +1455,46 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" + +[[package]] +name = "reqwest" +version = "0.11.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg 0.10.1", +] [[package]] name = "rustc-demangle" @@ -1122,29 +1504,42 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.37.19" +version = "0.37.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" dependencies = [ "bitflags 1.3.2", "errno", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +dependencies = [ + "bitflags 2.3.3", + "errno", + "libc", + "linux-raw-sys 0.4.3", "windows-sys 0.48.0", ] [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "dc31bd9b61a32c31f9650d18add92aa83a49ba979c143eefd27fe7177b05bd5f" [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" [[package]] name = "same-file" @@ -1155,6 +1550,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "schemars" version = "0.8.12" @@ -1185,24 +1589,47 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "security-framework" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "serde" -version = "1.0.165" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c939f902bb7d0ccc5bce4f03297e161543c2dcb30914faf032c2bd0b7a0d48fc" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.165" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eaae920e25fffe4019b75ff65e7660e72091e59dd204cb5849bbd6a3fd343d7" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -1218,10 +1645,22 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5062a995d481b2308b6064e9af76011f2921c35f97b0468811ed9f6cd91dfed" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ + "form_urlencoded", "itoa", "ryu", "serde", @@ -1260,9 +1699,19 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + +[[package]] +name = "socket2" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi 0.3.9", +] [[package]] name = "static_assertions" @@ -1287,15 +1736,15 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.25.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9f3bd7d2e45dcc5e265fbb88d6513e4747d8ef9444cf01a533119bce28a157" +checksum = "6069ca09d878a33f883cc06aaa9718ede171841d3832450354410b718b097232" dependencies = [ "heck", "proc-macro2", "quote", "rustversion", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] @@ -1311,9 +1760,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.23" +version = "2.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737" +checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" dependencies = [ "proc-macro2", "quote", @@ -1337,15 +1786,16 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.5.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ + "autocfg", "cfg-if 1.0.0", "fastrand", "redox_syscall 0.3.5", - "rustix", - "windows-sys 0.45.0", + "rustix 0.37.23", + "windows-sys 0.48.0", ] [[package]] @@ -1354,35 +1804,35 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" dependencies = [ - "rustix", + "rustix 0.37.23", "windows-sys 0.48.0", ] [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] name = "thread-id" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fdfe0627923f7411a43ec9ec9c39c3a9b4151be313e0922042581fb6c9b717f" +checksum = "3ee93aa2b8331c0fec9091548843f2c90019571814057da3b783f9de09349d73" dependencies = [ "libc", "redox_syscall 0.2.16", @@ -1401,9 +1851,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.21" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" +checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" dependencies = [ "itoa", "serde", @@ -1419,13 +1869,75 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" dependencies = [ "time-core", ] +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +dependencies = [ + "autocfg", + "backtrace", + "bytes", + "libc", + "mio 0.8.8", + "num_cpus", + "pin-project-lite", + "socket2", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + [[package]] name = "tracing" version = "0.1.37" @@ -1451,20 +1963,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.23", + "syn 2.0.25", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", "valuable", @@ -1509,6 +2021,12 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + [[package]] name = "uds_windows" version = "1.0.2" @@ -1519,11 +2037,26 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] [[package]] name = "unsafe-libyaml" @@ -1531,6 +2064,17 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1865806a559042e51ab5414598446a5871b561d21b6764f2eabb0dd481d880a6" +[[package]] +name = "url" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + [[package]] name = "utf8parse" version = "0.2.1" @@ -1543,6 +2087,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" @@ -1559,12 +2109,97 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.25", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.25", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "which" version = "4.4.0" @@ -1627,7 +2262,7 @@ checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ "windows-implement", "windows-interface", - "windows-targets 0.48.0", + "windows-targets", ] [[package]] @@ -1667,44 +2302,20 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets", ] [[package]] name = "windows-targets" -version = "0.42.2" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ "windows_aarch64_gnullvm 0.48.0", "windows_aarch64_msvc 0.48.0", @@ -1808,6 +2419,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "winreg" version = "0.50.0" diff --git a/Cargo.toml b/Cargo.toml index be879d6f..c22839b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,28 @@ members = [ "komorebi-core", "komorebic", ] + +[workspace.dependencies] +windows-interface = { version = "0.48" } +windows-implement = { version = "0.48" } + +[workspace.dependencies.windows] +version = "0.48" +features = [ + "implement", + "Win32_System_Com", + "Win32_UI_Shell_Common", # for IObjectArray + "Win32_Foundation", + "Win32_Graphics_Dwm", + "Win32_Graphics_Gdi", + "Win32_System_LibraryLoader", + "Win32_System_RemoteDesktop", + "Win32_System_Threading", + "Win32_UI_Accessibility", + "Win32_UI_HiDpi", + "Win32_UI_Input_KeyboardAndMouse", + "Win32_UI_Shell", + "Win32_UI_Shell_Common", + "Win32_UI_WindowsAndMessaging", + "Win32_System_SystemServices" +] diff --git a/README.md b/README.md index 42cbf1f8..84f3fd93 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,13 @@ This means that: ### Quickstart Make sure that you have either the [Scoop Package Manager](https://scoop.sh) or WinGet installed, then run the following -commands at a PowerShell prompt. +commands at a PowerShell prompt. If you are using WinGet, make sure that you open a new terminal window or reload your +profile after running the installation steps. Since this is not required when using `scoop`, I personally recommend that +you use `scoop` for this process. + +As of v0.1.17, the quickstart recommends the use of a static configuration file. If you would like to see older versions +of this quickstart which recommend the use of dynamic configuration scripts, please refer to +the [README file of v0.1.16](https://github.com/LGUG2Z/komorebi/tree/v0.1.16). ```powershell # if using scoop @@ -173,11 +179,11 @@ scoop install komorebi winget install LGUG2Z.whkd winget install LGUG2Z.komorebi -# save the latest generated app-specific config tweaks and fixes to ~/komorebi.generated.ps1 -iwr https://raw.githubusercontent.com/LGUG2Z/komorebi/master/komorebi.generated.ps1 -OutFile $Env:USERPROFILE\komorebi.generated.ps1 +# save the example configuration to ~/komorebi.json +iwr https://raw.githubusercontent.com/LGUG2Z/komorebi/master/komorebi.example.json -OutFile $Env:USERPROFILE\komorebi.example.json -# save the sample komorebi configuration file to ~/komorebi.ps1 -iwr https://raw.githubusercontent.com/LGUG2Z/komorebi/master/komorebi.sample.ps1 -OutFile $Env:USERPROFILE\komorebi.ps1 +# save the latest generated app-specific config tweaks and fixes +komorebic fetch-app-specific-configuration # ensure the ~/.config folder exists mkdir $Env:USERPROFILE\.config -ea 0 @@ -185,16 +191,16 @@ mkdir $Env:USERPROFILE\.config -ea 0 # save the sample whkdrc file with key bindings to ~/.config/whkdrc iwr https://raw.githubusercontent.com/LGUG2Z/komorebi/master/whkdrc.sample -OutFile $Env:USERPROFILE\.config\whkdrc -# start komorebi -komorebic start --await-configuration +# start komorebi and whkd +komorebic start -c $Env:USERPROFILE\komorebi.json --whkd ``` Thanks to [@sitiom](https://github.com/sitiom) for getting _komorebi_ added to both the popular Scoop Extras bucket and to WinGet. -You can watch a walkthrough video of this quickstart below on YouTube. + -[![Watch the quickstart walkthrough video](https://img.youtube.com/vi/cBnLIwMtv8g/hqdefault.jpg)](https://www.youtube.com/watch?v=cBnLIwMtv8g) + #### Using Autohotkey @@ -204,7 +210,9 @@ Generally, users who opt for AHK will have specific needs that can only be addre and so they are assumed to be able to craft their own configuration files. If you would like to try out AHK, a simple sample configuration powered by `komorebic.lib.ahk` is provided as a starting -point. +point. This sample configuration does not take into account the use of a static configuration file; if you choose to use +a static configuration file alongside AHK, you can remove all the configuration options from your `komorebi.ahk` and use +it solely to handle hotkey bindings. ```powershell # save the latest generated komorebic library to ~/komorebic.lib.ahk @@ -239,7 +247,12 @@ cargo install --path komorebic --locked ### Running -Run `komorebic start --await-configuration` at a Powershell prompt, and you will see the following output: +`komorebi` can be run in two ways, using either a static configuration file or a dynamic configuration script. + +The quickstart covers running with a static configuration file. + +If you would like to use a dynamic configuration script, ensure that you have a `komorebi.ps1` or `komorebi.ahk` file +present, run `komorebic start --await-configuration` at a Powershell prompt, and you will see the following output: ``` Start-Process komorebi.exe -ArgumentList '--await-configuration' -WindowStyle hidden @@ -249,15 +262,37 @@ Waiting for komorebi.exe to start...Started! This means that `komorebi` is now running in the background, tiling all your windows, and listening for commands sent to it by `komorebic`. You can similarly stop the process by running `komorebic stop`. +For further information on running with a dynamic configuration script, please refer to +the quickstart section in the [README file of v0.1.16](https://github.com/LGUG2Z/komorebi/tree/v0.1.16) + ### Configuring -If you followed the quickstart, `komorebi` will find the sample `komorebi.ps1` file in your `$Env:USERPROFILE` directory -and automatically load it. This file also starts `whkd` using the sample `whkrc` file in your `$Env:USERPROFILE\.config` -directory. +If you followed the quickstart, `komorebi.json` will be the single place where you declaratively configure the behaviour +of the window manager. There is a [complete JSON Schema for this configuration file](schema.json) available to provide +users with auto-completions in their editors. + +If you are running with a dynamic configuration script as recommended in v0.1.16 and earlier, `komorebi` will find the +sample `komorebi.ps1` file in your `$Env:USERPROFILE` directory and automatically load it. This file also starts `whkd` using the sample `whkrc` file +in your `$Env:USERPROFILE\.config` directory. Alternatively, if you have AutoHotKey installed and a `komorebi.ahk` file in `$Env:UserProfile` directory, `komorebi` will automatically try to load it when starting. +#### Migrating to a Static Configuration File + +If you have been using `komorebi` with a dynamic configuration script and wish to migrate to using a static +configuration file, once you have `komorebi` running in the desired configuration state, you can +run `komorebic generate-static-config`. + +This will print a static configuration that mostly represents your current configuration to the terminal. + +There are four configuration options that you may need to set yourself, if you make use of them: + +- Custom layouts paths for workspaces +- Custom layout rules for workspaces +- The applications.yaml path +- Any individual application rules you have that are not in applications.yaml + #### Configuration with `komorebic` As previously mentioned, this project does not handle anything related to keybindings and shortcuts directly. I @@ -336,6 +371,8 @@ exist in this folder. #### Generating Common Application-Specific Configurations +❗️**NOTE**: This section is only relevant for people who use dynamic configuration scripts. + A curated selection of application-specific configurations can be generated to help ease the setup for first-time users. [`komorebi-application-specific-configuration`](https://github.com/LGUG2Z/komorebi-application-specific-configuration) @@ -407,7 +444,7 @@ komorebic.exe workspace-padding 0 #### Multiple Layout Changes on Startup -❗️**NOTE**: If you followed the quickstart and are using the sample configurations, this is already the default behaviour. +❗️**NOTE**: This section is only relevant for people who use dynamic configuration scripts. Depending on what is in your configuration, when `komorebi` is started, you may experience the layout rapidly being adjusted with many retile events. diff --git a/komorebi-core/Cargo.toml b/komorebi-core/Cargo.toml index 69dd580e..6b76f8fb 100644 --- a/komorebi-core/Cargo.toml +++ b/komorebi-core/Cargo.toml @@ -13,9 +13,4 @@ serde_json = "1" serde_yaml = "0.9" strum = { version = "0.25", features = ["derive"] } schemars = "0.8" - -[dependencies.windows] -version = "0.48" -features = [ - "Win32_Foundation", -] +windows = { workspace = true } \ No newline at end of file diff --git a/komorebi-core/src/config_generation.rs b/komorebi-core/src/config_generation.rs index 62689dc1..2a370a5c 100644 --- a/komorebi-core/src/config_generation.rs +++ b/komorebi-core/src/config_generation.rs @@ -78,7 +78,7 @@ pub struct ApplicationConfiguration { pub struct ApplicationConfigurationGenerator; impl ApplicationConfigurationGenerator { - fn load(content: &str) -> Result> { + pub fn load(content: &str) -> Result> { Ok(serde_yaml::from_str(content)?) } diff --git a/komorebi-core/src/lib.rs b/komorebi-core/src/lib.rs index 79ee38dd..cf686a53 100644 --- a/komorebi-core/src/lib.rs +++ b/komorebi-core/src/lib.rs @@ -118,6 +118,7 @@ pub enum SocketMessage { ClearNamedWorkspaceLayoutRules(String), // Configuration ReloadConfiguration, + ReloadStaticConfiguration(PathBuf), WatchConfiguration(bool), CompleteConfiguration, AltFocusHack(bool), @@ -151,6 +152,8 @@ pub enum SocketMessage { RemoveSubscriber(String), NotificationSchema, SocketSchema, + StaticConfigSchema, + GenerateStaticConfig, } impl SocketMessage { @@ -192,10 +195,12 @@ pub enum StateQuery { Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema, )] #[strum(serialize_all = "snake_case")] -#[serde(rename_all = "snake_case")] pub enum ApplicationIdentifier { + #[serde(alias = "exe")] Exe, + #[serde(alias = "class")] Class, + #[serde(alias = "title")] Title, } @@ -204,7 +209,9 @@ pub enum ApplicationIdentifier { )] #[strum(serialize_all = "snake_case")] pub enum FocusFollowsMouseImplementation { + /// A custom FFM implementation (slightly more CPU-intensive) Komorebi, + /// The native (legacy) Windows FFM implementation Windows, } @@ -213,7 +220,9 @@ pub enum FocusFollowsMouseImplementation { )] #[strum(serialize_all = "snake_case")] pub enum WindowContainerBehaviour { + /// Create a new container for each new window Create, + /// Append new windows to the focused window container Append, } @@ -222,7 +231,9 @@ pub enum WindowContainerBehaviour { )] #[strum(serialize_all = "snake_case")] pub enum MoveBehaviour { + /// Swap the window container with the window container at the edge of the adjacent monitor Swap, + /// Insert the window container into the focused workspace on the adjacent monitor Insert, } @@ -231,8 +242,11 @@ pub enum MoveBehaviour { )] #[strum(serialize_all = "snake_case")] pub enum HidingBehaviour { + /// Use the SW_HIDE flag to hide windows when switching workspaces (has issues with Electron apps) Hide, + /// Use the SW_MINIMIZE flag to hide windows when switching workspaces (has issues with frequent workspace switching) Minimize, + /// Use the undocumented SetCloak Win32 function to hide windows when switching workspaces (has foregrounding issues) Cloak, } @@ -241,7 +255,9 @@ pub enum HidingBehaviour { )] #[strum(serialize_all = "snake_case")] pub enum OperationBehaviour { + /// Process komorebic commands on temporarily unmanaged/floated windows Op, + /// Ignore komorebic commands on temporarily unmanaged/floated windows NoOp, } diff --git a/komorebi-core/src/rect.rs b/komorebi-core/src/rect.rs index fc5249a1..01ea0960 100644 --- a/komorebi-core/src/rect.rs +++ b/komorebi-core/src/rect.rs @@ -5,9 +5,13 @@ use windows::Win32::Foundation::RECT; #[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, Eq, PartialEq, JsonSchema)] pub struct Rect { + /// The left point in a Win32 Rect pub left: i32, + /// The top point in a Win32 Rect pub top: i32, + /// The right point in a Win32 Rect pub right: i32, + /// The bottom point in a Win32 Rect pub bottom: i32, } diff --git a/komorebi.example.json b/komorebi.example.json new file mode 100644 index 00000000..8b3dc70d --- /dev/null +++ b/komorebi.example.json @@ -0,0 +1,25 @@ +{ + "app_specific_configuration_path": "$Env:USERPROFILE/applications.yaml", + "window_hiding_behaviour": "Cloak", + "cross_monitor_move_behaviour": "Insert", + "alt_focus_hack": true, + "default_workspace_padding": 20, + "default_container_padding": 20, + "active_window_border": false, + "active_window_border_colours": { + "single": { "r": 66, "g": 165, "b": 245 }, + "stack": { "r": 256, "g": 165, "b": 66 }, + "monocle": { "r": 255, "g": 51, "b": 153 } + }, + "monitors": [ + { + "workspaces": [ + { "name": "I", "layout": "BSP" }, + { "name": "II", "layout": "VerticalStack" }, + { "name": "III", "layout": "HorizontalStack" }, + { "name": "IV", "layout": "UltrawideVerticalStack" }, + { "name": "V", "layout": "Rows" } + ] + } + ] +} diff --git a/komorebi/Cargo.toml b/komorebi/Cargo.toml index db63318b..8ae37388 100644 --- a/komorebi/Cargo.toml +++ b/komorebi/Cargo.toml @@ -41,28 +41,9 @@ uds_windows = "1" which = "4" winput = "0.2" winreg = "0.50" -windows-interface = { version = "0.48" } -windows-implement = { version = "0.48" } -[dependencies.windows] -version = "0.48" -features = [ - "implement", - "Win32_System_Com", - "Win32_UI_Shell_Common", # for IObjectArray - "Win32_Foundation", - "Win32_Graphics_Dwm", - "Win32_Graphics_Gdi", - "Win32_System_LibraryLoader", - "Win32_System_RemoteDesktop", - "Win32_System_Threading", - "Win32_UI_Accessibility", - "Win32_UI_HiDpi", - "Win32_UI_Input_KeyboardAndMouse", - "Win32_UI_Shell", - "Win32_UI_Shell_Common", - "Win32_UI_WindowsAndMessaging", - "Win32_System_SystemServices" -] +windows-interface = { workspace = true } +windows-implement = { workspace = true } +windows = { workspace = true } [features] deadlock_detection = [] diff --git a/komorebi/src/main.rs b/komorebi/src/main.rs index 82ff30f3..58573071 100644 --- a/komorebi/src/main.rs +++ b/komorebi/src/main.rs @@ -48,6 +48,7 @@ use crate::process_command::listen_for_commands; use crate::process_command::listen_for_commands_tcp; use crate::process_event::listen_for_events; use crate::process_movement::listen_for_movements; +use crate::static_config::StaticConfig; use crate::window_manager::State; use crate::window_manager::WindowManager; use crate::window_manager_event::WindowManagerEvent; @@ -65,6 +66,7 @@ mod process_command; mod process_event; mod process_movement; mod set_window_position; +mod static_config; mod styles; mod window; mod window_manager; @@ -75,6 +77,8 @@ mod winevent; mod winevent_listener; mod workspace; +type WorkspaceRule = (usize, usize, bool); + lazy_static! { static ref HIDDEN_HWNDS: Arc>> = Arc::new(Mutex::new(vec![])); static ref LAYERED_WHITELIST: Arc>> = @@ -94,7 +98,7 @@ lazy_static! { ])); static ref MONITOR_INDEX_PREFERENCES: Arc>> = Arc::new(Mutex::new(HashMap::new())); - static ref WORKSPACE_RULES: Arc>> = + static ref WORKSPACE_RULES: Arc>> = Arc::new(Mutex::new(HashMap::new())); static ref MANAGE_IDENTIFIERS: Arc>> = Arc::new(Mutex::new(vec![])); static ref FLOAT_IDENTIFIERS: Arc>> = Arc::new(Mutex::new(vec![ @@ -160,6 +164,9 @@ lazy_static! { static ref NO_TITLEBAR: Arc>> = Arc::new(Mutex::new(vec![])); } +pub static DEFAULT_WORKSPACE_PADDING: AtomicI32 = AtomicI32::new(10); +pub static DEFAULT_CONTAINER_PADDING: AtomicI32 = AtomicI32::new(10); + pub static INITIAL_CONFIGURATION_LOADED: AtomicBool = AtomicBool::new(false); pub static CUSTOM_FFM: AtomicBool = AtomicBool::new(false); pub static SESSION_ID: AtomicU32 = AtomicU32::new(0); @@ -411,81 +418,89 @@ struct Opts { /// Start a TCP server on the given port to allow the direct sending of SocketMessages #[clap(action, short, long)] tcp_port: Option, + /// Path to a static configuration JSON file + #[clap(action, short, long)] + config: Option, } #[tracing::instrument] -#[allow(clippy::nonminimal_bool)] +#[allow(clippy::cognitive_complexity)] fn main() -> Result<()> { let opts: Opts = Opts::parse(); CUSTOM_FFM.store(opts.focus_follows_mouse, Ordering::SeqCst); - let arg_count = std::env::args().count(); - - let has_valid_args = arg_count == 1 - || (arg_count == 2 - && (opts.await_configuration || opts.focus_follows_mouse || opts.tcp_port.is_some())) - || (arg_count == 3 && opts.await_configuration && opts.focus_follows_mouse) - || (arg_count == 3 && opts.tcp_port.is_some() && opts.focus_follows_mouse) - || (arg_count == 3 && opts.tcp_port.is_some() && opts.await_configuration) - || (arg_count == 4 - && (opts.focus_follows_mouse && opts.await_configuration && opts.tcp_port.is_some())); + let process_id = WindowsApi::current_process_id(); + WindowsApi::allow_set_foreground_window(process_id)?; + WindowsApi::set_process_dpi_awareness_context()?; - if has_valid_args { - let process_id = WindowsApi::current_process_id(); - WindowsApi::allow_set_foreground_window(process_id)?; - WindowsApi::set_process_dpi_awareness_context()?; + let session_id = WindowsApi::process_id_to_session_id()?; + SESSION_ID.store(session_id, Ordering::SeqCst); - let session_id = WindowsApi::process_id_to_session_id()?; - SESSION_ID.store(session_id, Ordering::SeqCst); + let mut system = sysinfo::System::new_all(); + system.refresh_processes(); - let mut system = sysinfo::System::new_all(); - system.refresh_processes(); + let matched_procs: Vec<&Process> = system.processes_by_name("komorebi.exe").collect(); - let matched_procs: Vec<&Process> = system.processes_by_name("komorebi.exe").collect(); - - if matched_procs.len() > 1 { - let mut len = matched_procs.len(); - for proc in matched_procs { - if proc.root().ends_with("shims") { - len -= 1; - } + if matched_procs.len() > 1 { + let mut len = matched_procs.len(); + for proc in matched_procs { + if proc.root().ends_with("shims") { + len -= 1; } + } - if len > 1 { - tracing::error!("komorebi.exe is already running, please exit the existing process before starting a new one"); - std::process::exit(1); - } + if len > 1 { + tracing::error!("komorebi.exe is already running, please exit the existing process before starting a new one"); + std::process::exit(1); } + } + + // File logging worker guard has to have an assignment in the main fn to work + let (_guard, _color_guard) = setup()?; - // File logging worker guard has to have an assignment in the main fn to work - let (_guard, _color_guard) = setup()?; + #[cfg(feature = "deadlock_detection")] + detect_deadlocks(); - #[cfg(feature = "deadlock_detection")] - detect_deadlocks(); + let (outgoing, incoming): (Sender, Receiver) = + crossbeam_channel::unbounded(); - let (outgoing, incoming): (Sender, Receiver) = - crossbeam_channel::unbounded(); + let winevent_listener = winevent_listener::new(Arc::new(Mutex::new(outgoing))); + winevent_listener.start(); - let winevent_listener = winevent_listener::new(Arc::new(Mutex::new(outgoing))); - winevent_listener.start(); + Hidden::create("komorebi-hidden")?; - Hidden::create("komorebi-hidden")?; + let wm = if let Some(config) = &opts.config { + tracing::info!( + "creating window manager from static configuration file: {}", + config.as_os_str().to_str().unwrap() + ); - let wm = Arc::new(Mutex::new(WindowManager::new(Arc::new(Mutex::new( + Arc::new(Mutex::new(StaticConfig::preload( + config, + Arc::new(Mutex::new(incoming)), + )?)) + } else { + Arc::new(Mutex::new(WindowManager::new(Arc::new(Mutex::new( incoming, - )))?)); + )))?)) + }; - wm.lock().init()?; - listen_for_commands(wm.clone()); + wm.lock().init()?; + if let Some(config) = &opts.config { + StaticConfig::postload(config, &wm)?; + } - if !opts.await_configuration && !INITIAL_CONFIGURATION_LOADED.load(Ordering::SeqCst) { - INITIAL_CONFIGURATION_LOADED.store(true, Ordering::SeqCst); - }; + listen_for_commands(wm.clone()); - if let Some(port) = opts.tcp_port { - listen_for_commands_tcp(wm.clone(), port); - } + if !opts.await_configuration && !INITIAL_CONFIGURATION_LOADED.load(Ordering::SeqCst) { + INITIAL_CONFIGURATION_LOADED.store(true, Ordering::SeqCst); + }; + + if let Some(port) = opts.tcp_port { + listen_for_commands_tcp(wm.clone(), port); + } + if opts.config.is_none() { std::thread::spawn(|| { load_configuration().expect("could not load configuration"); }); @@ -496,36 +511,34 @@ fn main() -> Result<()> { backoff.snooze(); } } + } - wm.lock().retile_all(false)?; - - listen_for_events(wm.clone()); + wm.lock().retile_all(false)?; - if CUSTOM_FFM.load(Ordering::SeqCst) { - listen_for_movements(wm.clone()); - } + listen_for_events(wm.clone()); - let (ctrlc_sender, ctrlc_receiver) = crossbeam_channel::bounded(1); - ctrlc::set_handler(move || { - ctrlc_sender - .send(()) - .expect("could not send signal on ctrl-c channel"); - })?; + if CUSTOM_FFM.load(Ordering::SeqCst) { + listen_for_movements(wm.clone()); + } - ctrlc_receiver - .recv() - .expect("could not receive signal on ctrl-c channel"); + let (ctrlc_sender, ctrlc_receiver) = crossbeam_channel::bounded(1); + ctrlc::set_handler(move || { + ctrlc_sender + .send(()) + .expect("could not send signal on ctrl-c channel"); + })?; - tracing::error!("received ctrl-c, restoring all hidden windows and terminating process"); + ctrlc_receiver + .recv() + .expect("could not receive signal on ctrl-c channel"); - wm.lock().restore_all_windows()?; + tracing::error!("received ctrl-c, restoring all hidden windows and terminating process"); - if WindowsApi::focus_follows_mouse()? { - WindowsApi::disable_focus_follows_mouse()?; - } + wm.lock().restore_all_windows()?; - std::process::exit(130); + if WindowsApi::focus_follows_mouse()? { + WindowsApi::disable_focus_follows_mouse()?; } - Ok(()) + std::process::exit(130); } diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 7060dc96..2ca7df94 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -36,6 +36,7 @@ use komorebi_core::WindowKind; use crate::border::Border; use crate::current_virtual_desktop; use crate::notify_subscribers; +use crate::static_config::StaticConfig; use crate::window::Window; use crate::window_manager; use crate::window_manager::WindowManager; @@ -684,6 +685,7 @@ impl WindowManager { if let Layout::Custom(ref mut custom) = workspace.layout_mut() { if matches!(axis, Axis::Horizontal) { + #[allow(clippy::cast_precision_loss)] let percentage = custom .primary_width_percentage() .unwrap_or(100.0 / (custom.len() as f32)); @@ -877,6 +879,9 @@ impl WindowManager { SocketMessage::ReloadConfiguration => { Self::reload_configuration(); } + SocketMessage::ReloadStaticConfiguration(ref pathbuf) => { + self.reload_static_configuration(pathbuf)?; + } SocketMessage::CompleteConfiguration => { if !INITIAL_CONFIGURATION_LOADED.load(Ordering::SeqCst) { INITIAL_CONFIGURATION_LOADED.store(true, Ordering::SeqCst); @@ -1108,6 +1113,25 @@ impl WindowManager { let mut stream = UnixStream::connect(socket)?; stream.write_all(schema.as_bytes())?; } + SocketMessage::StaticConfigSchema => { + let socket_message = schema_for!(StaticConfig); + let schema = serde_json::to_string_pretty(&socket_message)?; + let mut socket = DATA_DIR.clone(); + socket.push("komorebic.sock"); + let socket = socket.as_path(); + + let mut stream = UnixStream::connect(socket)?; + stream.write_all(schema.as_bytes())?; + } + SocketMessage::GenerateStaticConfig => { + let config = serde_json::to_string_pretty(&StaticConfig::from(&*self))?; + let mut socket = DATA_DIR.clone(); + socket.push("komorebic.sock"); + let socket = socket.as_path(); + + let mut stream = UnixStream::connect(socket)?; + stream.write_all(config.as_bytes())?; + } SocketMessage::RemoveTitleBar(_, ref id) => { let mut identifiers = NO_TITLEBAR.lock(); if !identifiers.contains(id) { @@ -1250,7 +1274,7 @@ impl WindowManager { } #[tracing::instrument(skip(self))] - fn handle_workspace_rules( + pub fn handle_workspace_rules( &mut self, id: &String, monitor_idx: usize, diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs new file mode 100644 index 00000000..b05e03d8 --- /dev/null +++ b/komorebi/src/static_config.rs @@ -0,0 +1,754 @@ +use crate::border::Border; +use crate::current_virtual_desktop; +use crate::monitor::Monitor; +use crate::ring::Ring; +use crate::window_manager::WindowManager; +use crate::window_manager_event::WindowManagerEvent; +use crate::workspace::Workspace; +use crate::ALT_FOCUS_HACK; +use crate::BORDER_COLOUR_CURRENT; +use crate::BORDER_COLOUR_MONOCLE; +use crate::BORDER_COLOUR_SINGLE; +use crate::BORDER_COLOUR_STACK; +use crate::BORDER_ENABLED; +use crate::BORDER_HWND; +use crate::BORDER_OFFSET; +use crate::BORDER_OVERFLOW_IDENTIFIERS; +use crate::BORDER_WIDTH; +use crate::DATA_DIR; +use crate::DEFAULT_CONTAINER_PADDING; +use crate::DEFAULT_WORKSPACE_PADDING; +use crate::FLOAT_IDENTIFIERS; +use crate::HIDING_BEHAVIOUR; +use crate::LAYERED_WHITELIST; +use crate::MANAGE_IDENTIFIERS; +use crate::OBJECT_NAME_CHANGE_ON_LAUNCH; +use crate::TRAY_AND_MULTI_WINDOW_IDENTIFIERS; +use crate::WORKSPACE_RULES; +use color_eyre::Result; +use crossbeam_channel::Receiver; +use dirs::home_dir; +use hotwatch::notify::DebouncedEvent; +use hotwatch::Hotwatch; +use komorebi_core::config_generation::ApplicationConfigurationGenerator; +use komorebi_core::config_generation::ApplicationOptions; +use komorebi_core::config_generation::IdWithIdentifier; +use komorebi_core::ApplicationIdentifier; +use komorebi_core::DefaultLayout; +use komorebi_core::FocusFollowsMouseImplementation; +use komorebi_core::HidingBehaviour; +use komorebi_core::Layout; +use komorebi_core::MoveBehaviour; +use komorebi_core::OperationBehaviour; +use komorebi_core::Rect; +use komorebi_core::SocketMessage; +use komorebi_core::WindowContainerBehaviour; +use parking_lot::Mutex; +use schemars::JsonSchema; +use serde::Deserialize; +use serde::Serialize; +use std::collections::HashMap; +use std::collections::HashSet; +use std::io::ErrorKind; +use std::io::Write; +use std::path::PathBuf; +use std::sync::atomic::Ordering; +use std::sync::Arc; +use uds_windows::UnixListener; +use uds_windows::UnixStream; + +#[derive(Debug, Serialize, Deserialize, JsonSchema)] +pub struct Rgb { + /// Red + pub r: u32, + /// Green + pub g: u32, + /// Blue + pub b: u32, +} + +#[derive(Debug, Serialize, Deserialize, JsonSchema)] +pub struct ActiveWindowBorderColours { + /// Border colour when the container contains a single window + pub single: Rgb, + /// Border colour when the container contains multiple windows + pub stack: Rgb, + /// Border colour when the container is in monocle mode + pub monocle: Rgb, +} + +#[derive(Debug, Serialize, Deserialize, JsonSchema)] +pub struct WorkspaceConfig { + /// Name + pub name: String, + /// Layout (default: BSP) + #[serde(skip_serializing_if = "Option::is_none")] + pub layout: Option, + /// Custom Layout (default: None) + #[serde(skip_serializing_if = "Option::is_none")] + pub custom_layout: Option, + /// Layout rules (default: None) + #[serde(skip_serializing_if = "Option::is_none")] + pub layout_rules: Option>, + /// Layout rules (default: None) + #[serde(skip_serializing_if = "Option::is_none")] + pub custom_layout_rules: Option>, + /// Container padding (default: global) + #[serde(skip_serializing_if = "Option::is_none")] + pub container_padding: Option, + /// Container padding (default: global) + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace_padding: Option, + /// Initial workspace application rules + #[serde(skip_serializing_if = "Option::is_none")] + pub initial_workspace_rules: Option>, + /// Permanent workspace application rules + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace_rules: Option>, +} + +impl From<&Workspace> for WorkspaceConfig { + fn from(value: &Workspace) -> Self { + let mut layout_rules = HashMap::new(); + for (threshold, layout) in value.layout_rules() { + match layout { + Layout::Default(value) => { + layout_rules.insert(*threshold, *value); + } + Layout::Custom(_) => {} + } + } + + let workspace_rules = WORKSPACE_RULES.lock(); + let mut initial_ws_rules = vec![]; + let mut ws_rules = vec![]; + + for (identifier, (_, _, is_initial)) in &*workspace_rules { + if identifier.ends_with("exe") { + let rule = IdWithIdentifier { + kind: ApplicationIdentifier::Exe, + id: identifier.clone(), + }; + + if *is_initial { + initial_ws_rules.push(rule); + } else { + ws_rules.push(rule); + } + } + } + + let initial_ws_rules = if initial_ws_rules.is_empty() { + None + } else { + Option::from(initial_ws_rules) + }; + let ws_rules = if ws_rules.is_empty() { + None + } else { + Option::from(ws_rules) + }; + + let default_container_padding = DEFAULT_CONTAINER_PADDING.load(Ordering::SeqCst); + let default_workspace_padding = DEFAULT_WORKSPACE_PADDING.load(Ordering::SeqCst); + + let container_padding = value.container_padding().and_then(|container_padding| { + if container_padding == default_container_padding { + None + } else { + Option::from(container_padding) + } + }); + + let workspace_padding = value.workspace_padding().and_then(|workspace_padding| { + if workspace_padding == default_workspace_padding { + None + } else { + Option::from(workspace_padding) + } + }); + + Self { + name: value + .name() + .clone() + .unwrap_or_else(|| String::from("unnamed")), + layout: match value.layout() { + Layout::Default(layout) => Option::from(*layout), + // TODO: figure out how we might resolve file references in the future + Layout::Custom(_) => None, + }, + custom_layout: None, + layout_rules: Option::from(layout_rules), + // TODO: figure out how we might resolve file references in the future + custom_layout_rules: None, + container_padding, + workspace_padding, + initial_workspace_rules: initial_ws_rules, + workspace_rules: ws_rules, + } + } +} + +#[derive(Debug, Serialize, Deserialize, JsonSchema)] +pub struct MonitorConfig { + /// Workspace configurations + pub workspaces: Vec, + /// Monitor-specific work area offset (default: None) + #[serde(skip_serializing_if = "Option::is_none")] + pub work_area_offset: Option, +} + +impl From<&Monitor> for MonitorConfig { + fn from(value: &Monitor) -> Self { + let mut workspaces = vec![]; + for w in value.workspaces() { + workspaces.push(WorkspaceConfig::from(w)); + } + + Self { + workspaces, + work_area_offset: value.work_area_offset(), + } + } +} + +#[derive(Debug, Serialize, Deserialize, JsonSchema)] +pub struct StaticConfig { + /// Dimensions of Windows' own invisible borders; don't set these yourself unless you are told to + #[serde(skip_serializing_if = "Option::is_none")] + pub invisible_borders: Option, + /// Delta to resize windows by (default 50) + #[serde(skip_serializing_if = "Option::is_none")] + pub resize_delta: Option, + /// Determine what happens when a new window is opened (default: Create) + #[serde(skip_serializing_if = "Option::is_none")] + pub window_container_behaviour: Option, + /// Determine what happens when a window is moved across a monitor boundary (default: Swap) + #[serde(skip_serializing_if = "Option::is_none")] + pub cross_monitor_move_behaviour: Option, + /// Determine what happens when commands are sent while an unmanaged window is in the foreground (default: Op) + #[serde(skip_serializing_if = "Option::is_none")] + pub unmanaged_window_operation_behaviour: Option, + /// Determine focus follows mouse implementation (default: None) + #[serde(skip_serializing_if = "Option::is_none")] + pub focus_follows_mouse: Option, + /// Enable or disable mouse follows focus (default: true) + #[serde(skip_serializing_if = "Option::is_none")] + pub mouse_follows_focus: Option, + /// Path to applications.yaml from komorebi-application-specific-configurations (default: None) + #[serde(skip_serializing_if = "Option::is_none")] + pub app_specific_configuration_path: Option, + /// Width of the active window border (default: 20) + #[serde(skip_serializing_if = "Option::is_none")] + pub border_width: Option, + /// Offset of the active window border (default: None) + #[serde(skip_serializing_if = "Option::is_none")] + pub border_offset: Option, + /// Display an active window border (default: false) + #[serde(skip_serializing_if = "Option::is_none")] + pub active_window_border: Option, + /// Active window border colours for different container types + #[serde(skip_serializing_if = "Option::is_none")] + pub active_window_border_colours: Option, + /// Global default workspace padding (default: 10) + #[serde(skip_serializing_if = "Option::is_none")] + pub default_workspace_padding: Option, + /// Global default container padding (default: 10) + #[serde(skip_serializing_if = "Option::is_none")] + pub default_container_padding: Option, + /// Monitor and workspace configurations + #[serde(skip_serializing_if = "Option::is_none")] + pub monitors: Option>, + /// Always send the ALT key when using focus commands (default: false) + #[serde(skip_serializing_if = "Option::is_none")] + pub alt_focus_hack: Option, + /// Which Windows signal to use when hiding windows (default: minimize) + #[serde(skip_serializing_if = "Option::is_none")] + pub window_hiding_behaviour: Option, + /// Global work area (space used for tiling) offset (default: None) + #[serde(skip_serializing_if = "Option::is_none")] + pub global_work_area_offset: Option, + /// Individual window floating rules + #[serde(skip_serializing_if = "Option::is_none")] + pub float_rules: Option>, + /// Individual window force-manage rules + #[serde(skip_serializing_if = "Option::is_none")] + pub manage_rules: Option>, + /// Identify border overflow applications + #[serde(skip_serializing_if = "Option::is_none")] + pub border_overflow_applications: Option>, + /// Identify tray and multi-window applications + #[serde(skip_serializing_if = "Option::is_none")] + pub tray_and_multi_window_applications: Option>, + /// Identify applications that have the WS_EX_LAYERED extended window style + #[serde(skip_serializing_if = "Option::is_none")] + pub layered_applications: Option>, + /// Identify applications that send EVENT_OBJECT_NAMECHANGE on launch (very rare) + #[serde(skip_serializing_if = "Option::is_none")] + pub object_name_change_applications: Option>, +} + +impl From<&WindowManager> for StaticConfig { + fn from(value: &WindowManager) -> Self { + let default_invisible_borders = Rect { + left: 7, + top: 0, + right: 14, + bottom: 7, + }; + + let mut monitors = vec![]; + for m in value.monitors() { + monitors.push(MonitorConfig::from(m)); + } + + let mut to_remove = vec![]; + + let workspace_rules = WORKSPACE_RULES.lock(); + for (m_idx, m) in monitors.iter().enumerate() { + for (w_idx, w) in m.workspaces.iter().enumerate() { + if let Some(rules) = &w.initial_workspace_rules { + for iwsr in rules { + for (identifier, (monitor_idx, workspace_idx, _)) in &*workspace_rules { + if iwsr.id.eq(identifier) + && (*monitor_idx != m_idx || *workspace_idx != w_idx) + { + to_remove.push((m_idx, w_idx, iwsr.id.clone())); + } + } + } + } + + if let Some(rules) = &w.workspace_rules { + for wsr in rules { + for (identifier, (monitor_idx, workspace_idx, _)) in &*workspace_rules { + if wsr.id.eq(identifier) + && (*monitor_idx != m_idx || *workspace_idx != w_idx) + { + to_remove.push((m_idx, w_idx, wsr.id.clone())); + } + } + } + } + } + } + + for (m_idx, w_idx, id) in to_remove { + if let Some(monitor) = monitors.get_mut(m_idx) { + if let Some(workspace) = monitor.workspaces.get_mut(w_idx) { + if let Some(rules) = &mut workspace.workspace_rules { + rules.retain(|r| r.id != id); + } + + if let Some(rules) = &mut workspace.initial_workspace_rules { + rules.retain(|r| r.id != id); + } + } + } + } + + Self { + invisible_borders: if value.invisible_borders == default_invisible_borders { + None + } else { + Option::from(value.invisible_borders) + }, + resize_delta: Option::from(value.resize_delta), + window_container_behaviour: Option::from(value.window_container_behaviour), + cross_monitor_move_behaviour: Option::from(value.cross_monitor_move_behaviour), + unmanaged_window_operation_behaviour: Option::from( + value.unmanaged_window_operation_behaviour, + ), + focus_follows_mouse: value.focus_follows_mouse, + mouse_follows_focus: Option::from(value.mouse_follows_focus), + app_specific_configuration_path: None, + border_width: Option::from(BORDER_WIDTH.load(Ordering::SeqCst)), + border_offset: *BORDER_OFFSET.lock(), + active_window_border: Option::from(BORDER_ENABLED.load(Ordering::SeqCst)), + active_window_border_colours: None, + default_workspace_padding: Option::from( + DEFAULT_WORKSPACE_PADDING.load(Ordering::SeqCst), + ), + default_container_padding: Option::from( + DEFAULT_CONTAINER_PADDING.load(Ordering::SeqCst), + ), + monitors: Option::from(monitors), + alt_focus_hack: Option::from(ALT_FOCUS_HACK.load(Ordering::SeqCst)), + window_hiding_behaviour: Option::from(*HIDING_BEHAVIOUR.lock()), + global_work_area_offset: value.work_area_offset, + float_rules: None, + manage_rules: None, + border_overflow_applications: None, + tray_and_multi_window_applications: None, + layered_applications: None, + object_name_change_applications: None, + } + } +} + +impl StaticConfig { + #[allow(clippy::cognitive_complexity, clippy::too_many_lines)] + fn apply_globals(&self) -> Result<()> { + if let Some(behaviour) = self.window_hiding_behaviour { + let mut window_hiding_behaviour = HIDING_BEHAVIOUR.lock(); + *window_hiding_behaviour = behaviour; + } + + if let Some(hack) = self.alt_focus_hack { + ALT_FOCUS_HACK.store(hack, Ordering::SeqCst); + } + + if let Some(container) = self.default_container_padding { + DEFAULT_CONTAINER_PADDING.store(container, Ordering::SeqCst); + } + + if let Some(workspace) = self.default_workspace_padding { + DEFAULT_WORKSPACE_PADDING.store(workspace, Ordering::SeqCst); + } + + if let Some(width) = self.border_width { + BORDER_WIDTH.store(width, Ordering::SeqCst); + } + + if let Some(offset) = self.border_offset { + let mut border_offset = BORDER_OFFSET.lock(); + *border_offset = Some(offset); + } + + if let Some(colours) = &self.active_window_border_colours { + BORDER_COLOUR_SINGLE.store( + colours.single.r | (colours.single.g << 8) | (colours.single.b << 16), + Ordering::SeqCst, + ); + BORDER_COLOUR_CURRENT.store( + colours.single.r | (colours.single.g << 8) | (colours.single.b << 16), + Ordering::SeqCst, + ); + BORDER_COLOUR_STACK.store( + colours.stack.r | (colours.stack.g << 8) | (colours.stack.b << 16), + Ordering::SeqCst, + ); + BORDER_COLOUR_MONOCLE.store( + colours.monocle.r | (colours.monocle.g << 8) | (colours.monocle.b << 16), + Ordering::SeqCst, + ); + } + + let mut float_identifiers = FLOAT_IDENTIFIERS.lock(); + let mut manage_identifiers = MANAGE_IDENTIFIERS.lock(); + let mut tray_and_multi_window_identifiers = TRAY_AND_MULTI_WINDOW_IDENTIFIERS.lock(); + let mut border_overflow_identifiers = BORDER_OVERFLOW_IDENTIFIERS.lock(); + let mut object_name_change_identifiers = OBJECT_NAME_CHANGE_ON_LAUNCH.lock(); + let mut layered_identifiers = LAYERED_WHITELIST.lock(); + + if let Some(float) = &self.float_rules { + for identifier in float { + if !float_identifiers.contains(&identifier.id) { + float_identifiers.push(identifier.id.clone()); + } + } + } + + if let Some(float) = &self.manage_rules { + for identifier in float { + if !manage_identifiers.contains(&identifier.id) { + manage_identifiers.push(identifier.id.clone()); + } + } + } + + if let Some(identifiers) = &self.object_name_change_applications { + for identifier in identifiers { + if !object_name_change_identifiers.contains(&identifier.id) { + object_name_change_identifiers.push(identifier.id.clone()); + } + } + } + + if let Some(identifiers) = &self.layered_applications { + for identifier in identifiers { + if !layered_identifiers.contains(&identifier.id) { + layered_identifiers.push(identifier.id.clone()); + } + } + } + + if let Some(identifiers) = &self.border_overflow_applications { + for identifier in identifiers { + if !border_overflow_identifiers.contains(&identifier.id) { + border_overflow_identifiers.push(identifier.id.clone()); + } + } + } + + if let Some(identifiers) = &self.tray_and_multi_window_applications { + for identifier in identifiers { + if !tray_and_multi_window_identifiers.contains(&identifier.id) { + tray_and_multi_window_identifiers.push(identifier.id.clone()); + } + } + } + + if let Some(path) = &self.app_specific_configuration_path { + let stringified = path.to_string_lossy(); + let stringified = stringified.replace( + "$Env:USERPROFILE", + &home_dir().expect("no home dir").to_string_lossy(), + ); + + let content = std::fs::read_to_string(stringified)?; + let asc = ApplicationConfigurationGenerator::load(&content)?; + + for entry in asc { + if let Some(float) = entry.float_identifiers { + for f in float { + if !float_identifiers.contains(&f.id) { + float_identifiers.push(f.id.clone()); + } + } + } + if let Some(options) = entry.options { + for o in options { + match o { + ApplicationOptions::ObjectNameChange => { + if !object_name_change_identifiers.contains(&entry.identifier.id) { + object_name_change_identifiers + .push(entry.identifier.id.clone()); + } + } + ApplicationOptions::Layered => { + if !layered_identifiers.contains(&entry.identifier.id) { + layered_identifiers.push(entry.identifier.id.clone()); + } + } + ApplicationOptions::BorderOverflow => { + if !border_overflow_identifiers.contains(&entry.identifier.id) { + border_overflow_identifiers.push(entry.identifier.id.clone()); + } + } + ApplicationOptions::TrayAndMultiWindow => { + if !tray_and_multi_window_identifiers.contains(&entry.identifier.id) + { + tray_and_multi_window_identifiers + .push(entry.identifier.id.clone()); + } + } + ApplicationOptions::Force => { + if !manage_identifiers.contains(&entry.identifier.id) { + manage_identifiers.push(entry.identifier.id.clone()); + } + } + } + } + } + } + } + + Ok(()) + } + + #[allow(clippy::too_many_lines)] + pub fn preload( + path: &PathBuf, + incoming: Arc>>, + ) -> Result { + let content = std::fs::read_to_string(path)?; + let value: Self = serde_json::from_str(&content)?; + value.apply_globals()?; + + let socket = DATA_DIR.join("komorebi.sock"); + + match std::fs::remove_file(&socket) { + Ok(_) => {} + Err(error) => match error.kind() { + // Doing this because ::exists() doesn't work reliably on Windows via IntelliJ + ErrorKind::NotFound => {} + _ => { + return Err(error.into()); + } + }, + }; + + let listener = UnixListener::bind(&socket)?; + + let mut wm = WindowManager { + monitors: Ring::default(), + monitor_cache: HashMap::new(), + incoming_events: incoming, + command_listener: listener, + is_paused: false, + invisible_borders: value.invisible_borders.unwrap_or(Rect { + left: 7, + top: 0, + right: 14, + bottom: 7, + }), + virtual_desktop_id: current_virtual_desktop(), + work_area_offset: value.global_work_area_offset, + window_container_behaviour: value + .window_container_behaviour + .unwrap_or(WindowContainerBehaviour::Create), + cross_monitor_move_behaviour: value + .cross_monitor_move_behaviour + .unwrap_or(MoveBehaviour::Swap), + unmanaged_window_operation_behaviour: value + .unmanaged_window_operation_behaviour + .unwrap_or(OperationBehaviour::Op), + resize_delta: value.resize_delta.unwrap_or(50), + focus_follows_mouse: value.focus_follows_mouse, + mouse_follows_focus: value.mouse_follows_focus.unwrap_or(true), + hotwatch: Hotwatch::new()?, + has_pending_raise_op: false, + pending_move_op: None, + already_moved_window_handles: Arc::new(Mutex::new(HashSet::new())), + }; + + let bytes = SocketMessage::ReloadStaticConfiguration(path.clone()).as_bytes()?; + + wm.hotwatch.watch(path, move |event| match event { + // Editing in Notepad sends a NoticeWrite while editing in (Neo)Vim sends + // a NoticeRemove, presumably because of the use of swap files? + DebouncedEvent::NoticeWrite(_) | DebouncedEvent::NoticeRemove(_) => { + let socket = DATA_DIR.join("komorebi.sock"); + let mut stream = + UnixStream::connect(socket).expect("could not connect to komorebi.sock"); + stream + .write_all(&bytes) + .expect("could not write to komorebi.sock"); + } + _ => {} + })?; + + Ok(wm) + } + + pub fn postload(path: &PathBuf, wm: &Arc>) -> Result<()> { + let content = std::fs::read_to_string(path)?; + let value: Self = serde_json::from_str(&content)?; + let mut wm = wm.lock(); + + if let Some(monitors) = value.monitors { + for (i, monitor) in monitors.iter().enumerate() { + if let Some(m) = wm.monitors_mut().get_mut(i) { + m.ensure_workspace_count(monitor.workspaces.len()); + m.set_work_area_offset(monitor.work_area_offset); + + for (j, ws) in m.workspaces_mut().iter_mut().enumerate() { + ws.load_static_config( + monitor + .workspaces + .get(j) + .expect("no static workspace config"), + )?; + } + } + + for (j, ws) in monitor.workspaces.iter().enumerate() { + if let Some(rules) = &ws.workspace_rules { + for r in rules { + wm.handle_workspace_rules(&r.id, i, j, false)?; + } + } + + if let Some(rules) = &ws.initial_workspace_rules { + for r in rules { + wm.handle_workspace_rules(&r.id, i, j, true)?; + } + } + } + } + } + + if value.active_window_border == Some(true) { + if BORDER_HWND.load(Ordering::SeqCst) == 0 { + Border::create("komorebi-border-window")?; + } + + BORDER_ENABLED.store(true, Ordering::SeqCst); + wm.show_border()?; + } + + Ok(()) + } + + pub fn reload(path: &PathBuf, wm: &mut WindowManager) -> Result<()> { + let content = std::fs::read_to_string(path)?; + let value: Self = serde_json::from_str(&content)?; + + value.apply_globals()?; + + if let Some(monitors) = value.monitors { + for (i, monitor) in monitors.iter().enumerate() { + if let Some(m) = wm.monitors_mut().get_mut(i) { + m.ensure_workspace_count(monitor.workspaces.len()); + m.set_work_area_offset(monitor.work_area_offset); + + for (j, ws) in m.workspaces_mut().iter_mut().enumerate() { + ws.load_static_config( + monitor + .workspaces + .get(j) + .expect("no static workspace config"), + )?; + } + } + + for (j, ws) in monitor.workspaces.iter().enumerate() { + if let Some(rules) = &ws.workspace_rules { + for r in rules { + wm.handle_workspace_rules(&r.id, i, j, false)?; + } + } + + if let Some(rules) = &ws.initial_workspace_rules { + for r in rules { + wm.handle_workspace_rules(&r.id, i, j, true)?; + } + } + } + } + } + + if value.active_window_border == Some(true) { + if BORDER_HWND.load(Ordering::SeqCst) == 0 { + Border::create("komorebi-border-window")?; + } + + BORDER_ENABLED.store(true, Ordering::SeqCst); + wm.show_border()?; + } else { + BORDER_ENABLED.store(false, Ordering::SeqCst); + wm.hide_border()?; + } + + if let Some(val) = value.invisible_borders { + wm.invisible_borders = val; + } + + if let Some(val) = value.window_container_behaviour { + wm.window_container_behaviour = val; + } + + if let Some(val) = value.cross_monitor_move_behaviour { + wm.cross_monitor_move_behaviour = val; + } + + if let Some(val) = value.unmanaged_window_operation_behaviour { + wm.unmanaged_window_operation_behaviour = val; + } + + if let Some(val) = value.resize_delta { + wm.resize_delta = val; + } + + if let Some(val) = value.mouse_follows_focus { + wm.mouse_follows_focus = val; + } + + wm.work_area_offset = value.global_work_area_offset; + wm.focus_follows_mouse = value.focus_follows_mouse; + + Ok(()) + } +} diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index e313d3e5..4dea3116 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -37,6 +37,7 @@ use crate::current_virtual_desktop; use crate::load_configuration; use crate::monitor::Monitor; use crate::ring::Ring; +use crate::static_config::StaticConfig; use crate::window::Window; use crate::window_manager_event::WindowManagerEvent; use crate::windows_api::WindowsApi; @@ -234,6 +235,12 @@ impl WindowManager { std::thread::spawn(|| load_configuration().expect("could not load configuration")); } + #[tracing::instrument(skip(self))] + pub fn reload_static_configuration(&mut self, pathbuf: &PathBuf) -> Result<()> { + tracing::info!("reloading static configuration"); + StaticConfig::reload(pathbuf, self) + } + #[tracing::instrument(skip(self))] pub fn watch_configuration(&mut self, enable: bool) -> Result<()> { let home = HOME_DIR.clone(); diff --git a/komorebi/src/workspace.rs b/komorebi/src/workspace.rs index 2ae9f913..28128861 100644 --- a/komorebi/src/workspace.rs +++ b/komorebi/src/workspace.rs @@ -12,6 +12,7 @@ use schemars::JsonSchema; use serde::Serialize; use komorebi_core::Axis; +use komorebi_core::CustomLayout; use komorebi_core::CycleDirection; use komorebi_core::DefaultLayout; use komorebi_core::Layout; @@ -20,8 +21,11 @@ use komorebi_core::Rect; use crate::container::Container; use crate::ring::Ring; +use crate::static_config::WorkspaceConfig; use crate::window::Window; use crate::windows_api::WindowsApi; +use crate::DEFAULT_CONTAINER_PADDING; +use crate::DEFAULT_WORKSPACE_PADDING; use crate::INITIAL_CONFIGURATION_LOADED; use crate::NO_TITLEBAR; use crate::REMOVE_TITLEBARS; @@ -77,8 +81,8 @@ impl Default for Workspace { layout: Layout::Default(DefaultLayout::BSP), layout_rules: vec![], layout_flip: None, - workspace_padding: Option::from(10), - container_padding: Option::from(10), + workspace_padding: Option::from(DEFAULT_WORKSPACE_PADDING.load(Ordering::SeqCst)), + container_padding: Option::from(DEFAULT_CONTAINER_PADDING.load(Ordering::SeqCst)), latest_layout: vec![], resize_dimensions: vec![], tile: true, @@ -87,6 +91,46 @@ impl Default for Workspace { } impl Workspace { + pub fn load_static_config(&mut self, config: &WorkspaceConfig) -> Result<()> { + self.name = Option::from(config.name.clone()); + + if config.container_padding.is_some() { + self.set_container_padding(config.container_padding); + } + + if config.workspace_padding.is_some() { + self.set_workspace_padding(config.workspace_padding); + } + + if let Some(layout) = &config.layout { + self.layout = Layout::Default(*layout); + } + + if let Some(pathbuf) = &config.custom_layout { + let layout = CustomLayout::from_path_buf(pathbuf.clone())?; + self.layout = Layout::Custom(layout); + } + + if let Some(layout_rules) = &config.layout_rules { + let mut all_rules = vec![]; + for (count, rule) in layout_rules { + all_rules.push((*count, Layout::Default(*rule))); + } + + self.set_layout_rules(all_rules); + } + + if let Some(layout_rules) = &config.custom_layout_rules { + let rules = self.layout_rules_mut(); + for (count, pathbuf) in layout_rules { + let rule = CustomLayout::from_path_buf(pathbuf.clone())?; + rules.push((*count, Layout::Custom(rule))); + } + } + + Ok(()) + } + pub fn hide(&mut self) { for container in self.containers_mut() { for window in container.windows_mut() { diff --git a/komorebic/Cargo.toml b/komorebic/Cargo.toml index 7d4434e4..b746fa20 100644 --- a/komorebic/Cargo.toml +++ b/komorebic/Cargo.toml @@ -22,15 +22,11 @@ heck = "0.4" lazy_static = "1" paste = "1" powershell_script = "1.0" +reqwest = { version = "0.11", features = ["blocking"] } serde = { version = "1", features = ["derive"] } serde_json = "1" serde_yaml = "0.9" sysinfo = "0.29" uds_windows = "1" - -[dependencies.windows] -version = "0.48" -features = [ - "Win32_Foundation", - "Win32_UI_WindowsAndMessaging" -] +which = "4" +windows = { workspace = true } \ No newline at end of file diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index 48b28150..5e709045 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -24,6 +24,7 @@ use paste::paste; use sysinfo::SystemExt; use uds_windows::UnixListener; use uds_windows::UnixStream; +use which::which; use windows::Win32::Foundation::HWND; use windows::Win32::UI::WindowsAndMessaging::ShowWindow; use windows::Win32::UI::WindowsAndMessaging::SHOW_WINDOW_CMD; @@ -610,12 +611,18 @@ struct Start { /// Allow the use of komorebi's custom focus-follows-mouse implementation #[clap(action, short, long = "ffm")] ffm: bool, + /// Path to a static configuration JSON file + #[clap(action, short, long)] + config: Option, /// Wait for 'komorebic complete-configuration' to be sent before processing events #[clap(action, short, long)] await_configuration: bool, /// Start a TCP server on the given port to allow the direct sending of SocketMessages #[clap(action, short, long)] tcp_port: Option, + /// Start whkd in a background process + #[clap(action, long)] + whkd: bool, } #[derive(Parser, AhkFunction)] @@ -1018,10 +1025,17 @@ enum SubCommand { #[clap(arg_required_else_help = true)] #[clap(alias = "fmt-asc")] FormatAppSpecificConfiguration(FormatAppSpecificConfiguration), + /// Fetch the latest version of applications.yaml from komorebi-application-specific-configuration + #[clap(alias = "fetch-asc")] + FetchAppSpecificConfiguration, /// Generate a JSON Schema of subscription notifications NotificationSchema, /// Generate a JSON Schema of socket messages SocketSchema, + /// Generate a JSON Schema of the static configuration file + StaticConfigSchema, + /// Generates a static configuration JSON file based on the current window manager state + GenerateStaticConfig, } pub fn send_message(bytes: &[u8]) -> Result<()> { @@ -1030,7 +1044,7 @@ pub fn send_message(bytes: &[u8]) -> Result<()> { Ok(stream.write_all(bytes)?) } -#[allow(clippy::too_many_lines)] +#[allow(clippy::too_many_lines, clippy::cognitive_complexity)] fn main() -> Result<()> { let opts: Opts = Opts::parse(); @@ -1377,6 +1391,10 @@ fn main() -> Result<()> { )?; } SubCommand::Start(arg) => { + if arg.whkd && which("whkd").is_err() { + return Err(anyhow!("could not find whkd, please make sure it is installed before using the --whkd flag")); + } + let mut buf: PathBuf; // The komorebi.ps1 shim will only exist in the Path if installed by Scoop @@ -1400,63 +1418,40 @@ fn main() -> Result<()> { None }; - let script = exec.map_or_else( - || { - if arg.ffm | arg.await_configuration | arg.tcp_port.is_some() { - format!( - "Start-Process komorebi.exe -ArgumentList {} -WindowStyle hidden", - arg.tcp_port.map_or_else( - || if arg.ffm && arg.await_configuration { - "'--ffm','--await-configuration'".to_string() - } else if arg.ffm { - "'--ffm'".to_string() - } else { - "'--await-configuration'".to_string() - }, - |port| if arg.ffm { - format!("'--ffm','--tcp-port={port}'") - } else if arg.await_configuration { - format!("'--await-configuration','--tcp-port={port}'") - } else if arg.ffm && arg.await_configuration { - format!("'--ffm','--await-configuration','--tcp-port={port}'") - } else { - format!("'--tcp-port={port}'") - } - ) - ) - } else { - String::from("Start-Process komorebi.exe -WindowStyle hidden") - } - }, - |exec| { - if arg.ffm | arg.await_configuration { - format!( - "Start-Process '{}' -ArgumentList {} -WindowStyle hidden", - exec, - arg.tcp_port.map_or_else( - || if arg.ffm && arg.await_configuration { - "'--ffm','--await-configuration'".to_string() - } else if arg.ffm { - "'--ffm'".to_string() - } else { - "'--await-configuration'".to_string() - }, - |port| if arg.ffm { - format!("'--ffm','--tcp-port={port}'") - } else if arg.await_configuration { - format!("'--await-configuration','--tcp-port={port}'") - } else if arg.ffm && arg.await_configuration { - format!("'--ffm','--await-configuration','--tcp-port={port}'") - } else { - format!("'--tcp-port={port}'") - } - ) - ) - } else { - format!("Start-Process '{exec}' -WindowStyle hidden") - } - }, - ); + let mut flags = vec![]; + if let Some(config) = arg.config { + let path = resolve_windows_path(config.as_os_str().to_str().unwrap())?; + if !path.is_file() { + return Err(anyhow!("could not find file: {}", path.to_string_lossy())); + } + + flags.push(format!( + "'--config={}'", + path.as_os_str() + .to_string_lossy() + .trim_start_matches(r#"\\?\"#), + )); + } + + if arg.ffm { + flags.push("'--ffm'".to_string()); + } + + if arg.await_configuration { + flags.push("'--await-configuration'".to_string()); + } + + if let Some(port) = arg.tcp_port { + flags.push(format!("'--tcp-port={port}'")); + } + + let argument_list = flags.join(","); + let script = { + format!( + "Start-Process '{}' -ArgumentList {argument_list} -WindowStyle hidden", + exec.unwrap_or("komorebi.exe") + ) + }; let mut running = false; @@ -1483,6 +1478,23 @@ fn main() -> Result<()> { println!("komorebi.exe did not start... Trying again"); } } + + if arg.whkd { + let script = r#" +if (!(Get-Process whkd -ErrorAction SilentlyContinue)) +{ + Start-Process whkd -WindowStyle hidden +} + "#; + match powershell_script::run(script) { + Ok(_) => { + println!("{script}"); + } + Err(error) => { + println!("Error: {error}"); + } + } + } } SubCommand::Stop => { send_message(&SocketMessage::Stop.as_bytes()?)?; @@ -1735,7 +1747,7 @@ fn main() -> Result<()> { _ => { return Err(anyhow!( "this command requires applications to be identified by their exe" - )) + )); } } @@ -1889,6 +1901,29 @@ fn main() -> Result<()> { println!("File successfully formatted for PRs to https://github.com/LGUG2Z/komorebi-application-specific-configuration"); } + SubCommand::FetchAppSpecificConfiguration => { + let content = reqwest::blocking::get("https://raw.githubusercontent.com/LGUG2Z/komorebi-application-specific-configuration/master/applications.yaml")? + .text()?; + + let mut output_file = HOME_DIR.clone(); + output_file.push("applications.yaml"); + + let mut file = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(&output_file)?; + + file.write_all(content.as_bytes())?; + + let output_path = output_file.to_str().unwrap().to_string(); + let output_path = output_path.replace('\\', "/"); + + println!("Latest version of applications.yaml from https://github.com/LGUG2Z/komorebi-application-specific-configuration downloaded\n"); + println!( + "You can add this to your komorebi.json static configuration file like this: \n\n\"app_specific_configuration_path\": \"{output_path}\"", + ); + } SubCommand::NotificationSchema => { let home = DATA_DIR.clone(); let mut socket = home; @@ -1942,6 +1977,74 @@ fn main() -> Result<()> { send_message(&SocketMessage::SocketSchema.as_bytes()?)?; + let listener = UnixListener::bind(socket)?; + match listener.accept() { + Ok(incoming) => { + let stream = BufReader::new(incoming.0); + for line in stream.lines() { + println!("{}", line?); + } + + return Ok(()); + } + Err(error) => { + panic!("{}", error); + } + } + } + SubCommand::StaticConfigSchema => { + let home = DATA_DIR.clone(); + let mut socket = home; + socket.push("komorebic.sock"); + let socket = socket.as_path(); + + match std::fs::remove_file(socket) { + Ok(_) => {} + Err(error) => match error.kind() { + // Doing this because ::exists() doesn't work reliably on Windows via IntelliJ + ErrorKind::NotFound => {} + _ => { + return Err(error.into()); + } + }, + }; + + send_message(&SocketMessage::StaticConfigSchema.as_bytes()?)?; + + let listener = UnixListener::bind(socket)?; + match listener.accept() { + Ok(incoming) => { + let stream = BufReader::new(incoming.0); + for line in stream.lines() { + println!("{}", line?); + } + + return Ok(()); + } + Err(error) => { + panic!("{}", error); + } + } + } + SubCommand::GenerateStaticConfig => { + let home = DATA_DIR.clone(); + let mut socket = home; + socket.push("komorebic.sock"); + let socket = socket.as_path(); + + match std::fs::remove_file(socket) { + Ok(_) => {} + Err(error) => match error.kind() { + // Doing this because ::exists() doesn't work reliably on Windows via IntelliJ + ErrorKind::NotFound => {} + _ => { + return Err(error.into()); + } + }, + }; + + send_message(&SocketMessage::GenerateStaticConfig.as_bytes()?)?; + let listener = UnixListener::bind(socket)?; match listener.accept() { Ok(incoming) => { diff --git a/schema.json b/schema.json new file mode 100644 index 00000000..8ba451ca --- /dev/null +++ b/schema.json @@ -0,0 +1,574 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "StaticConfig", + "type": "object", + "properties": { + "active_window_border": { + "description": "Display an active window border (default: false)", + "type": [ + "boolean", + "null" + ] + }, + "active_window_border_colours": { + "description": "Active window border colours for different container types", + "anyOf": [ + { + "$ref": "#/definitions/ActiveWindowBorderColours" + }, + { + "type": "null" + } + ] + }, + "alt_focus_hack": { + "description": "Always send the ALT key when using focus commands (default: false)", + "type": [ + "boolean", + "null" + ] + }, + "app_specific_configuration_path": { + "description": "Path to applications.yaml from komorebi-application-specific-configurations (default: None)", + "type": [ + "string", + "null" + ] + }, + "border_offset": { + "description": "Offset of the active window border (default: None)", + "anyOf": [ + { + "$ref": "#/definitions/Rect" + }, + { + "type": "null" + } + ] + }, + "border_overflow_applications": { + "description": "Identify border overflow applications", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/IdWithIdentifier" + } + }, + "border_width": { + "description": "Width of the active window border (default: 20)", + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "cross_monitor_move_behaviour": { + "description": "Determine what happens when a window is moved across a monitor boundary (default: Swap)", + "anyOf": [ + { + "$ref": "#/definitions/MoveBehaviour" + }, + { + "type": "null" + } + ] + }, + "default_container_padding": { + "description": "Global default container padding (default: 10)", + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "default_workspace_padding": { + "description": "Global default workspace padding (default: 10)", + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "float_rules": { + "description": "Individual window floating rules", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/IdWithIdentifier" + } + }, + "focus_follows_mouse": { + "description": "Determine focus follows mouse implementation (default: None)", + "anyOf": [ + { + "$ref": "#/definitions/FocusFollowsMouseImplementation" + }, + { + "type": "null" + } + ] + }, + "global_work_area_offset": { + "description": "Global work area (space used for tiling) offset (default: None)", + "anyOf": [ + { + "$ref": "#/definitions/Rect" + }, + { + "type": "null" + } + ] + }, + "invisible_borders": { + "description": "Dimensions of Windows' own invisible borders; don't set these yourself unless you are told to", + "anyOf": [ + { + "$ref": "#/definitions/Rect" + }, + { + "type": "null" + } + ] + }, + "layered_applications": { + "description": "Identify applications that have the WS_EX_LAYERED extended window style", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/IdWithIdentifier" + } + }, + "manage_rules": { + "description": "Individual window force-manage rules", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/IdWithIdentifier" + } + }, + "monitors": { + "description": "Monitor and workspace configurations", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/MonitorConfig" + } + }, + "mouse_follows_focus": { + "description": "Enable or disable mouse follows focus (default: true)", + "type": [ + "boolean", + "null" + ] + }, + "object_name_change_applications": { + "description": "Identify applications that send EVENT_OBJECT_NAMECHANGE on launch (very rare)", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/IdWithIdentifier" + } + }, + "resize_delta": { + "description": "Delta to resize windows by (default 50)", + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "tray_and_multi_window_applications": { + "description": "Identify tray and multi-window applications", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/IdWithIdentifier" + } + }, + "unmanaged_window_operation_behaviour": { + "description": "Determine what happens when commands are sent while an unmanaged window is in the foreground (default: Op)", + "anyOf": [ + { + "$ref": "#/definitions/OperationBehaviour" + }, + { + "type": "null" + } + ] + }, + "window_container_behaviour": { + "description": "Determine what happens when a new window is opened (default: Create)", + "anyOf": [ + { + "$ref": "#/definitions/WindowContainerBehaviour" + }, + { + "type": "null" + } + ] + }, + "window_hiding_behaviour": { + "description": "Which Windows signal to use when hiding windows (default: minimize)", + "anyOf": [ + { + "$ref": "#/definitions/HidingBehaviour" + }, + { + "type": "null" + } + ] + } + }, + "definitions": { + "ActiveWindowBorderColours": { + "type": "object", + "required": [ + "monocle", + "single", + "stack" + ], + "properties": { + "monocle": { + "description": "Border colour when the container is in monocle mode", + "allOf": [ + { + "$ref": "#/definitions/Rgb" + } + ] + }, + "single": { + "description": "Border colour when the container contains a single window", + "allOf": [ + { + "$ref": "#/definitions/Rgb" + } + ] + }, + "stack": { + "description": "Border colour when the container contains multiple windows", + "allOf": [ + { + "$ref": "#/definitions/Rgb" + } + ] + } + } + }, + "ApplicationIdentifier": { + "type": "string", + "enum": [ + "Exe", + "Class", + "Title" + ] + }, + "DefaultLayout": { + "type": "string", + "enum": [ + "BSP", + "Columns", + "Rows", + "VerticalStack", + "HorizontalStack", + "UltrawideVerticalStack" + ] + }, + "FocusFollowsMouseImplementation": { + "oneOf": [ + { + "description": "A custom FFM implementation (slightly more CPU-intensive)", + "type": "string", + "enum": [ + "Komorebi" + ] + }, + { + "description": "The native (legacy) Windows FFM implementation", + "type": "string", + "enum": [ + "Windows" + ] + } + ] + }, + "HidingBehaviour": { + "oneOf": [ + { + "description": "Use the SW_HIDE flag to hide windows when switching workspaces (has issues with Electron apps)", + "type": "string", + "enum": [ + "Hide" + ] + }, + { + "description": "Use the SW_MINIMIZE flag to hide windows when switching workspaces (has issues with frequent workspace switching)", + "type": "string", + "enum": [ + "Minimize" + ] + }, + { + "description": "Use the undocumented SetCloak Win32 function to hide windows when switching workspaces (has foregrounding issues)", + "type": "string", + "enum": [ + "Cloak" + ] + } + ] + }, + "IdWithIdentifier": { + "type": "object", + "required": [ + "id", + "kind" + ], + "properties": { + "id": { + "type": "string" + }, + "kind": { + "$ref": "#/definitions/ApplicationIdentifier" + } + } + }, + "MonitorConfig": { + "type": "object", + "required": [ + "workspaces" + ], + "properties": { + "work_area_offset": { + "description": "Monitor-specific work area offset (default: None)", + "anyOf": [ + { + "$ref": "#/definitions/Rect" + }, + { + "type": "null" + } + ] + }, + "workspaces": { + "description": "Workspace configurations", + "type": "array", + "items": { + "$ref": "#/definitions/WorkspaceConfig" + } + } + } + }, + "MoveBehaviour": { + "oneOf": [ + { + "description": "Swap the window container with the window container at the edge of the adjacent monitor", + "type": "string", + "enum": [ + "Swap" + ] + }, + { + "description": "Insert the window container into the focused workspace on the adjacent monitor", + "type": "string", + "enum": [ + "Insert" + ] + } + ] + }, + "OperationBehaviour": { + "oneOf": [ + { + "description": "Process komorebic commands on temporarily unmanaged/floated windows", + "type": "string", + "enum": [ + "Op" + ] + }, + { + "description": "Ignore komorebic commands on temporarily unmanaged/floated windows", + "type": "string", + "enum": [ + "NoOp" + ] + } + ] + }, + "Rect": { + "type": "object", + "required": [ + "bottom", + "left", + "right", + "top" + ], + "properties": { + "bottom": { + "description": "The bottom point in a Win32 Rect", + "type": "integer", + "format": "int32" + }, + "left": { + "description": "The left point in a Win32 Rect", + "type": "integer", + "format": "int32" + }, + "right": { + "description": "The right point in a Win32 Rect", + "type": "integer", + "format": "int32" + }, + "top": { + "description": "The top point in a Win32 Rect", + "type": "integer", + "format": "int32" + } + } + }, + "Rgb": { + "type": "object", + "required": [ + "b", + "g", + "r" + ], + "properties": { + "b": { + "description": "Blue", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "g": { + "description": "Green", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "r": { + "description": "Red", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + } + }, + "WindowContainerBehaviour": { + "oneOf": [ + { + "description": "Create a new container for each new window", + "type": "string", + "enum": [ + "Create" + ] + }, + { + "description": "Append new windows to the focused window container", + "type": "string", + "enum": [ + "Append" + ] + } + ] + }, + "WorkspaceConfig": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "container_padding": { + "description": "Container padding (default: global)", + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "custom_layout": { + "description": "Custom Layout (default: None)", + "type": [ + "string", + "null" + ] + }, + "custom_layout_rules": { + "description": "Layout rules (default: None)", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "string" + } + }, + "initial_workspace_rules": { + "description": "Initial workspace application rules", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/IdWithIdentifier" + } + }, + "layout": { + "description": "Layout (default: BSP)", + "anyOf": [ + { + "$ref": "#/definitions/DefaultLayout" + }, + { + "type": "null" + } + ] + }, + "layout_rules": { + "description": "Layout rules (default: None)", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "$ref": "#/definitions/DefaultLayout" + } + }, + "name": { + "description": "Name", + "type": "string" + }, + "workspace_padding": { + "description": "Container padding (default: global)", + "type": [ + "integer", + "null" + ], + "format": "int32" + }, + "workspace_rules": { + "description": "Permanent workspace application rules", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/IdWithIdentifier" + } + } + } + } + } +} \ No newline at end of file