diff --git a/.github/workflows/nix-cache.yml b/.github/workflows/nix-cache.yml index 23175d7f..f394837a 100644 --- a/.github/workflows/nix-cache.yml +++ b/.github/workflows/nix-cache.yml @@ -6,6 +6,7 @@ on: # - "v*.*.*" branches: - "master" + pull_request: permissions: contents: read diff --git a/build/build-rust-package.nix b/build/build-rust-package.nix index a91d2bed..6a774b75 100644 --- a/build/build-rust-package.nix +++ b/build/build-rust-package.nix @@ -19,6 +19,9 @@ , pkg-config , gtk3 , libayatana-appindicator +, libxkbcommon +, libGL +, libGLU , llvmPackages , cargo-xwin @@ -44,7 +47,7 @@ let ]; }; # rustOrig = rust-bin.stable.latest.default.override rustConfig; - rustOrig = rust-bin.selectLatestNightlyWith (toolchain: toolchain.default.override rustConfig); + rustOrig =rust-bin.selectLatestNightlyWith (toolchain: toolchain.default.override rustConfig); rustPlatformOrig = makeRustPlatform { cargo = rustOrig; rustc = rustOrig; }; xwin = rustPlatformOrig.buildRustPackage rec { name = "xwin"; @@ -117,8 +120,7 @@ let EOF chmod +x $out/bin/cargo '') - // - { inherit (rustOrig) meta; }; + // { inherit (rustOrig) meta targetPlatforms badTargetPlatforms; }; rustPlatform = makeRustPlatform { cargo = passthru.rust; rustc = passthru.rust; }; setupXWin = topDir: /* bash */ '' @@ -194,6 +196,9 @@ let buildInputs = [ gtk3 libayatana-appindicator.out + libxkbcommon.out + libGL.out + libGLU.out ]; outputs = [ "out" "docs" ]; diff --git a/codchi/Cargo.lock b/codchi/Cargo.lock index 3a7985fb..df54edaa 100644 --- a/codchi/Cargo.lock +++ b/codchi/Cargo.lock @@ -2,6 +2,114 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ab_glyph" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" + +[[package]] +name = "accesskit" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3d3b8f9bae46a948369bc4a03e815d4ed6d616bd00de4051133a5019dc31c5a" + +[[package]] +name = "accesskit_atspi_common" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c5dd55e6e94949498698daf4d48fb5659e824d7abec0d394089656ceaf99d4f" +dependencies = [ + "accesskit", + "accesskit_consumer", + "atspi-common", + "serde", + "thiserror 1.0.69", + "zvariant 4.2.0", +] + +[[package]] +name = "accesskit_consumer" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f47983a1084940ba9a39c077a8c63e55c619388be5476ac04c804cfbd1e63459" +dependencies = [ + "accesskit", + "hashbrown 0.15.2", + "immutable-chunkmap", +] + +[[package]] +name = "accesskit_macos" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7329821f3bd1101e03a7d2e03bd339e3ac0dc64c70b4c9f9ae1949e3ba8dece1" +dependencies = [ + "accesskit", + "accesskit_consumer", + "hashbrown 0.15.2", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "accesskit_unix" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcee751cc20d88678c33edaf9c07e8b693cd02819fe89053776f5313492273f5" +dependencies = [ + "accesskit", + "accesskit_atspi_common", + "async-channel", + "async-executor", + "async-task", + "atspi", + "futures-lite", + "futures-util", + "serde", + "zbus 4.4.0", +] + +[[package]] +name = "accesskit_windows" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24fcd5d23d70670992b823e735e859374d694a3d12bfd8dd32bd3bd8bedb5d81" +dependencies = [ + "accesskit", + "accesskit_consumer", + "hashbrown 0.15.2", + "paste", + "static_assertions", + "windows 0.58.0", + "windows-core 0.58.0", +] + +[[package]] +name = "accesskit_winit" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6a48dad5530b6deb9fc7a52cc6c3bf72cdd9eb8157ac9d32d69f2427a5e879" +dependencies = [ + "accesskit", + "accesskit_macos", + "accesskit_unix", + "accesskit_windows", + "raw-window-handle", + "winit", +] + [[package]] name = "addr2line" version = "0.24.2" @@ -17,6 +125,19 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom 0.2.15", + "once_cell", + "version_check", + "zerocopy 0.7.35", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -26,6 +147,33 @@ dependencies = [ "memchr", ] +[[package]] +name = "android-activity" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" +dependencies = [ + "android-properties", + "bitflags 2.8.0", + "cc", + "cesu8", + "jni", + "jni-sys", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys 0.6.0+11769913", + "num_enum", + "thiserror 1.0.69", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -43,9 +191,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -58,52 +206,117 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "once_cell", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4" dependencies = [ "backtrace", ] +[[package]] +name = "arboard" +version = "3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4" +dependencies = [ + "clipboard-win", + "core-graphics 0.23.2", + "image", + "log", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", + "parking_lot", + "windows-sys 0.48.0", + "x11rb", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" + +[[package]] +name = "ash" +version = "0.38.0+1.3.281" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" +dependencies = [ + "libloading 0.8.6", +] + +[[package]] +name = "ashpd" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cbdf310d77fd3aaee6ea2093db7011dc2d35d2eb3481e5607f1f8d942ed99df" +dependencies = [ + "async-fs", + "async-net", + "enumflags2", + "futures-channel", + "futures-util", + "rand 0.9.0", + "raw-window-handle", + "serde", + "serde_repr", + "url", + "zbus 5.5.0", +] + [[package]] name = "async-broadcast" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cd0e2e25ea8e5f7e9df04578dc6cf5c83577fd09b1a46aaf5c85e1c33f2a7e" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" dependencies = [ "event-listener", "event-listener-strategy", @@ -149,9 +362,9 @@ dependencies = [ [[package]] name = "async-io" -version = "2.3.4" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" dependencies = [ "async-lock", "cfg-if", @@ -177,6 +390,17 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-net" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" +dependencies = [ + "async-io", + "blocking", + "futures-lite", +] + [[package]] name = "async-process" version = "2.3.0" @@ -204,7 +428,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] @@ -233,20 +457,20 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.83" +version = "0.1.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] name = "atk" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4af014b17dd80e8af9fa689b2d4a211ddba6eb583c1622f35d0cb543f6b17e4" +checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" dependencies = [ "atk-sys", "glib", @@ -255,9 +479,9 @@ dependencies = [ [[package]] name = "atk-sys" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "251e0b7d90e33e0ba930891a505a9a35ece37b2dd37a14f3ffc306c13b980009" +checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" dependencies = [ "glib-sys", "gobject-sys", @@ -271,6 +495,57 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "atspi" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be534b16650e35237bb1ed189ba2aab86ce65e88cc84c66f4935ba38575cecbf" +dependencies = [ + "atspi-common", + "atspi-connection", + "atspi-proxies", +] + +[[package]] +name = "atspi-common" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1909ed2dc01d0a17505d89311d192518507e8a056a48148e3598fef5e7bb6ba7" +dependencies = [ + "enumflags2", + "serde", + "static_assertions", + "zbus 4.4.0", + "zbus-lockstep", + "zbus-lockstep-macros", + "zbus_names 3.0.0", + "zvariant 4.2.0", +] + +[[package]] +name = "atspi-connection" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "430c5960624a4baaa511c9c0fcc2218e3b58f5dbcc47e6190cafee344b873333" +dependencies = [ + "atspi-common", + "atspi-proxies", + "futures-lite", + "zbus 4.4.0", +] + +[[package]] +name = "atspi-proxies" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e6c5de3e524cf967569722446bcd458d5032348554d9a17d7d72b041ab7496" +dependencies = [ + "atspi-common", + "serde", + "zbus 4.4.0", + "zvariant 4.2.0", +] + [[package]] name = "autocfg" version = "1.4.0" @@ -292,12 +567,33 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + [[package]] name = "bitflags" version = "1.3.2" @@ -306,9 +602,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" dependencies = [ "serde", ] @@ -334,7 +630,16 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" dependencies = [ - "objc2", + "objc2 0.5.2", +] + +[[package]] +name = "block2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d59b4c170e16f0405a2e95aff44432a0d41aa97675f3d52623effe95792a037" +dependencies = [ + "objc2 0.6.0", ] [[package]] @@ -362,15 +667,29 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "bytemuck" -version = "1.18.0" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" +checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] [[package]] name = "byteorder" @@ -386,9 +705,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.7.2" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" [[package]] name = "cairo-rs" @@ -396,12 +715,12 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "cairo-sys-rs", "glib", "libc", "once_cell", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -415,6 +734,32 @@ dependencies = [ "system-deps", ] +[[package]] +name = "calloop" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" +dependencies = [ + "bitflags 2.8.0", + "log", + "polling", + "rustix", + "slab", + "thiserror 1.0.69", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" +dependencies = [ + "calloop", + "rustix", + "wayland-backend", + "wayland-client", +] + [[package]] name = "carapace_spec_clap" version = "1.1.0" @@ -423,17 +768,19 @@ checksum = "09a6810b1aada7fb10830104d1d5dd8019fbdefd5e51bae3961cc5b58f458023" dependencies = [ "clap", "clap_complete", - "indexmap 2.6.0", + "indexmap 2.7.1", "serde", "serde_yaml_ng", ] [[package]] name = "cc" -version = "1.1.28" +version = "1.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1" +checksum = "c736e259eea577f443d5c86c304f9f4ae0295c43f3ba05c21f1d66b5f06001af" dependencies = [ + "jobserver", + "libc", "shlex", ] @@ -465,24 +812,33 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "cgl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" +dependencies = [ + "libc", +] + [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", "serde", - "windows-targets 0.52.6", + "windows-link", ] [[package]] name = "clap" -version = "4.5.19" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" +checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" dependencies = [ "clap_builder", "clap_derive", @@ -490,9 +846,9 @@ dependencies = [ [[package]] name = "clap-verbosity-flag" -version = "2.2.2" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e099138e1807662ff75e2cebe4ae2287add879245574489f9b1588eb5e5564ed" +checksum = "2678fade3b77aa3a8ff3aae87e9c008d3fb00473a41c71fbf74e91c8c7b37e84" dependencies = [ "clap", "log", @@ -500,9 +856,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.19" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" +checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" dependencies = [ "anstream", "anstyle", @@ -512,9 +868,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.32" +version = "4.5.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74a01f4f9ee6c066d42a1c8dedf0dcddad16c72a8981a309d6398de3a75b0c39" +checksum = "f5c5508ea23c5366f77e53f5a0070e5a84e51687ec3ef9e0464c86dc8d13ce98" dependencies = [ "clap", ] @@ -544,9 +900,9 @@ dependencies = [ [[package]] name = "clap_complete_nushell" -version = "4.5.3" +version = "4.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fe32110e006bccf720f8c9af3fee1ba7db290c724eab61544e1d3295be3a40e" +checksum = "c6a8b1593457dfc2fe539002b795710d022dc62a65bf15023f039f9760c7b18a" dependencies = [ "clap", "clap_complete", @@ -554,60 +910,39 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "clap_mangen" -version = "0.2.23" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17415fd4dfbea46e3274fcd8d368284519b358654772afb700dc2e8d2b24eeb" +checksum = "724842fa9b144f9b89b3f3d371a89f3455eea660361d13a554f68f8ae5d6c13a" dependencies = [ "clap", "roff", ] [[package]] -name = "cocoa" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79398230a6e2c08f5c9760610eb6924b52aa9e7950a619602baba59dcbbdbb2" -dependencies = [ - "bitflags 2.6.0", - "block", - "cocoa-foundation", - "core-foundation", - "core-graphics", - "foreign-types", - "libc", - "objc", -] - -[[package]] -name = "cocoa-foundation" -version = "0.2.0" +name = "clipboard-win" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14045fb83be07b5acf1c0884b2180461635b433455fa35d1cd6f17f1450679d" +checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" dependencies = [ - "bitflags 2.6.0", - "block", - "core-foundation", - "core-graphics-types", - "libc", - "objc", + "error-code", ] [[package]] @@ -628,6 +963,9 @@ dependencies = [ "ctrlc", "directories", "duct", + "eframe", + "egui", + "egui_extras", "embed-manifest", "env_logger", "freedesktop_entry_parser", @@ -649,35 +987,54 @@ dependencies = [ "num_enum", "number_prefix", "petname", - "rand", + "rand 0.9.0", + "resvg 0.45.1", + "rfd", "serde", "serde_json", "serde_with", - "strum", + "strum 0.27.1", "sysinfo", "tao", - "thiserror", + "thiserror 2.0.11", "throttle", - "toml_edit 0.22.22", + "toml_edit 0.22.24", "tray-icon", + "usvg 0.45.1", "uuid", "version-compare", "which", - "windows 0.58.0", + "windows 0.60.0", "wslapi", ] [[package]] -name = "colorchoice" -version = "1.0.2" +name = "codespan-reporting" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width 0.1.14", +] [[package]] -name = "combine" -version = "4.6.7" +name = "color_quant" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ "bytes", "memchr", @@ -685,14 +1042,13 @@ dependencies = [ [[package]] name = "comfy-table" -version = "7.1.1" +version = "7.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b34115915337defe99b2aff5c2ce6771e5fbc4079f4b506301f5cf394c8452f7" +checksum = "4a65ebfec4fb190b6f90e944a817d60499ee0744e582530e2c9900a22e591d9a" dependencies = [ - "crossterm 0.27.0", - "strum", - "strum_macros", - "unicode-width", + "crossterm 0.28.1", + "unicode-segmentation", + "unicode-width 0.2.0", ] [[package]] @@ -706,15 +1062,25 @@ dependencies = [ [[package]] name = "console" -version = "0.15.8" +version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" dependencies = [ "encode_unicode", - "lazy_static", "libc", - "unicode-width", - "windows-sys 0.52.0", + "once_cell", + "unicode-width 0.2.0", + "windows-sys 0.59.0", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", ] [[package]] @@ -733,35 +1099,68 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "core-graphics-types 0.1.3", + "foreign-types", + "libc", +] + [[package]] name = "core-graphics" version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" dependencies = [ - "bitflags 2.6.0", - "core-foundation", - "core-graphics-types", + "bitflags 2.8.0", + "core-foundation 0.10.0", + "core-graphics-types 0.2.0", "foreign-types", "libc", ] +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "libc", +] + [[package]] name = "core-graphics-types" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.6.0", - "core-foundation", + "bitflags 2.8.0", + "core-foundation 0.10.0", "libc", ] +[[package]] +name = "core_maths" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30" +dependencies = [ + "libm", +] + [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] @@ -777,18 +1176,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.13" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -805,9 +1204,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossterm" @@ -827,14 +1226,14 @@ dependencies = [ [[package]] name = "crossterm" -version = "0.27.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" +checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "crossterm_winapi", - "libc", "parking_lot", + "rustix", "winapi", ] @@ -867,6 +1266,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "cursor-icon" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" + [[package]] name = "darling" version = "0.20.10" @@ -888,7 +1293,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] @@ -899,9 +1304,15 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.79", + "syn 2.0.98", ] +[[package]] +name = "data-url" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" + [[package]] name = "deranged" version = "0.3.11" @@ -924,18 +1335,18 @@ dependencies = [ [[package]] name = "directories" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" +checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" dependencies = [ "dirs-sys", ] [[package]] name = "dirs" -version = "5.0.1" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" dependencies = [ "dirs-sys", ] @@ -952,14 +1363,14 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", - "redox_users", - "windows-sys 0.48.0", + "redox_users 0.5.0", + "windows-sys 0.59.0", ] [[package]] @@ -969,7 +1380,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", - "redox_users", + "redox_users 0.4.6", "winapi", ] @@ -979,6 +1390,38 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dispatch2" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a0d569e003ff27784e0e14e4a594048698e0c0f0b66cabcb51511be55a7caa0" +dependencies = [ + "bitflags 2.8.0", + "block2 0.6.0", + "libc", + "objc2 0.6.0", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading 0.8.6", +] + [[package]] name = "dlopen2" version = "0.7.0" @@ -999,9 +1442,24 @@ checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", +] + +[[package]] +name = "document-features" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +dependencies = [ + "litrs", ] +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + [[package]] name = "dpi" version = "0.1.1" @@ -1022,15 +1480,160 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.17" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feeef44e73baff3a26d371801df019877a9866a8c493d315ab00177843314f35" + +[[package]] +name = "ecolor" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "878e9005799dd739e5d5d89ff7480491c12d0af571d44399bcaefa1ee172dd76" +dependencies = [ + "bytemuck", + "emath", +] + +[[package]] +name = "eframe" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eba4c50d905804fe9ec4e159fde06b9d38f9440228617ab64a03d7a2091ece63" +dependencies = [ + "ahash", + "bytemuck", + "document-features", + "egui", + "egui-wgpu", + "egui-winit", + "egui_glow", + "glow", + "glutin", + "glutin-winit", + "image", + "js-sys", + "log", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", + "parking_lot", + "percent-encoding", + "profiling", + "raw-window-handle", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "web-time", + "winapi", + "windows-sys 0.59.0", + "winit", +] + +[[package]] +name = "egui" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d2768eaa6d5c80a6e2a008da1f0e062dff3c83eb2b28605ea2d0732d46e74d6" +dependencies = [ + "accesskit", + "ahash", + "bitflags 2.8.0", + "emath", + "epaint", + "log", + "nohash-hasher", + "profiling", +] + +[[package]] +name = "egui-wgpu" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d8151704bcef6271bec1806c51544d70e79ef20e8616e5eac01facfd9c8c54a" +dependencies = [ + "ahash", + "bytemuck", + "document-features", + "egui", + "epaint", + "log", + "profiling", + "thiserror 1.0.69", + "type-map", + "web-time", + "wgpu", + "winit", +] + +[[package]] +name = "egui-winit" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace791b367c1f63e6044aef2f3834904509d1d1a6912fd23ebf3f6a9af92cd84" +dependencies = [ + "accesskit_winit", + "ahash", + "arboard", + "bytemuck", + "egui", + "log", + "profiling", + "raw-window-handle", + "smithay-clipboard", + "web-time", + "webbrowser", + "winit", +] + +[[package]] +name = "egui_extras" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b5cf69510eb3d19211fc0c062fb90524f43fe8e2c012967dcf0e2d81cb040f" +dependencies = [ + "ahash", + "egui", + "enum-map", + "image", + "log", + "mime_guess2", + "profiling", + "resvg 0.37.0", +] + +[[package]] +name = "egui_glow" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +checksum = "9a53e2374a964c3c793cb0b8ead81bca631f24974bc0b747d1a5622f4e39fdd0" +dependencies = [ + "ahash", + "bytemuck", + "egui", + "glow", + "log", + "memoffset", + "profiling", + "wasm-bindgen", + "web-sys", + "winit", +] [[package]] name = "either" -version = "1.13.0" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7914353092ddf589ad78f25c5c1c21b7f80b0ff8621e7c814c3485b5306da9d" + +[[package]] +name = "emath" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "55b7b6be5ad1d247f11738b0e4699d9c20005ed366f2c29f5ec1f8e1de180bc2" +dependencies = [ + "bytemuck", +] [[package]] name = "embed-manifest" @@ -1040,9 +1643,9 @@ checksum = "41cd446c890d6bed1d8b53acef5f240069ebef91d6fae7c5f52efe61fe8b5eae" [[package]] name = "encode_unicode" -version = "0.3.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "endi" @@ -1050,11 +1653,32 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" +[[package]] +name = "enum-map" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" +dependencies = [ + "enum-map-derive", + "serde", +] + +[[package]] +name = "enum-map-derive" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "enumflags2" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" +checksum = "ba2f4b465f5318854c6f8dd686ede6c0a9dc67d4b1ac241cf0eb51521a309147" dependencies = [ "enumflags2_derive", "serde", @@ -1062,30 +1686,36 @@ dependencies = [ [[package]] name = "enumflags2_derive" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" +checksum = "fc4caf64a58d7a6d65ab00639b046ff54399a39f5f2554728895ace4b297cd79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] name = "env_filter" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", "regex", ] +[[package]] +name = "env_home" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" + [[package]] name = "env_logger" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" dependencies = [ "anstream", "anstyle", @@ -1094,27 +1724,57 @@ dependencies = [ "log", ] +[[package]] +name = "epaint" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "275b665a7b9611d8317485187e5458750850f9e64604d3c58434bb3fc1d22915" +dependencies = [ + "ab_glyph", + "ahash", + "bytemuck", + "ecolor", + "emath", + "epaint_default_fonts", + "log", + "nohash-hasher", + "parking_lot", + "profiling", +] + +[[package]] +name = "epaint_default_fonts" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9343d356d7cac894dacafc161b4654e0881301097bdf32a122ed503d97cb94b6" + [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] +[[package]] +name = "error-code" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" + [[package]] name = "event-listener" -version = "5.3.1" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" dependencies = [ "concurrent-queue", "parking", @@ -1123,9 +1783,9 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" dependencies = [ "event-listener", "pin-project-lite", @@ -1133,15 +1793,15 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fdeflate" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8090f921a24b04994d9929e204f50b498a33ea6ba559ffaa05e04f7ee7fb5ab" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" dependencies = [ "simd-adler32", ] @@ -1158,20 +1818,55 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.34" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" dependencies = [ "crc32fast", "miniz_oxide", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" + +[[package]] +name = "fontconfig-parser" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fcfcd44ca6e90c921fee9fa665d530b21ef1327a4c1a6c5250ea44b776ada7" +dependencies = [ + "roxmltree 0.20.0", +] + +[[package]] +name = "fontdb" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905" +dependencies = [ + "fontconfig-parser", + "log", + "memmap2", + "slotmap", + "tinyvec", + "ttf-parser", +] + [[package]] name = "foreign-types" version = "0.5.0" @@ -1190,7 +1885,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] @@ -1215,17 +1910,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db9c27b72f19a99a895f8ca89e2d26e4ef31013376e56fdafef697627306c3e4" dependencies = [ "nom", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "fs4" -version = "0.9.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c6b3bd49c37d2aa3f3f2220233b29a7cd23f79d1fe70e5337d25fb390793de" +checksum = "be058769cf1633370c3d0dac6bb9b223b8f18900cf808abadf7843192e706238" dependencies = [ "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1262,9 +1957,9 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "2.3.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" dependencies = [ "fastrand", "futures-core", @@ -1281,7 +1976,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] @@ -1333,9 +2028,9 @@ dependencies = [ [[package]] name = "gdk" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5ba081bdef3b75ebcdbfc953699ed2d7417d6bd853347a42a37d76406a33646" +checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" dependencies = [ "cairo-rs", "gdk-pixbuf", @@ -1374,9 +2069,9 @@ dependencies = [ [[package]] name = "gdk-sys" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31ff856cb3386dae1703a920f803abafcc580e9b5f711ca62ed1620c25b51ff2" +checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -1391,9 +2086,9 @@ dependencies = [ [[package]] name = "gdkwayland-sys" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90fbf5c033c65d93792192a49a8efb5bb1e640c419682a58bb96f5ae77f3d4a" +checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" dependencies = [ "gdk-sys", "glib-sys", @@ -1405,9 +2100,9 @@ dependencies = [ [[package]] name = "gdkx11-sys" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee8f00f4ee46cad2939b8990f5c70c94ff882c3028f3cc5abf950fa4ab53043" +checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" dependencies = [ "gdk-sys", "glib-sys", @@ -1427,14 +2122,46 @@ dependencies = [ ] [[package]] -name = "getrandom" -version = "0.2.15" +name = "gethostname" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" dependencies = [ - "cfg-if", "libc", - "wasi", + "windows-targets 0.48.5", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", +] + +[[package]] +name = "gif" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +dependencies = [ + "color_quant", + "weezl", ] [[package]] @@ -1459,7 +2186,7 @@ dependencies = [ "once_cell", "pin-project-lite", "smallvec", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1478,21 +2205,31 @@ dependencies = [ [[package]] name = "git-url-parse" version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68d7ff03a34ea818a59cf30c0d7aa55354925484fa30bcc4cb96d784ff07578f" +source = "git+https://github.com/tjtelan/git-url-parse-rs#23031bfa3e7d0cbba17a2ccbe26f348c35f5c524" dependencies = [ - "strum", - "thiserror", + "strum 0.26.3", + "thiserror 1.0.69", "url", ] +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + [[package]] name = "glib" version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "futures-channel", "futures-core", "futures-executor", @@ -1506,7 +2243,7 @@ dependencies = [ "memchr", "once_cell", "smallvec", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1520,7 +2257,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] @@ -1533,6 +2270,84 @@ dependencies = [ "system-deps", ] +[[package]] +name = "glow" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glutin" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03642b8b0cce622392deb0ee3e88511f75df2daac806102597905c3ea1974848" +dependencies = [ + "bitflags 2.8.0", + "cfg_aliases", + "cgl", + "core-foundation 0.9.4", + "dispatch", + "glutin_egl_sys", + "glutin_glx_sys", + "glutin_wgl_sys", + "libloading 0.8.6", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", + "once_cell", + "raw-window-handle", + "wayland-sys", + "windows-sys 0.52.0", + "x11-dl", +] + +[[package]] +name = "glutin-winit" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85edca7075f8fc728f28cb8fbb111a96c3b89e930574369e3e9c27eb75d3788f" +dependencies = [ + "cfg_aliases", + "glutin", + "raw-window-handle", + "winit", +] + +[[package]] +name = "glutin_egl_sys" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c4680ba6195f424febdc3ba46e7a42a0e58743f2edb115297b86d7f8ecc02d2" +dependencies = [ + "gl_generator", + "windows-sys 0.52.0", +] + +[[package]] +name = "glutin_glx_sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7bb2938045a88b612499fbcba375a77198e01306f52272e692f8c1f3751185" +dependencies = [ + "gl_generator", + "x11-dl", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e" +dependencies = [ + "gl_generator", +] + [[package]] name = "gobject-sys" version = "0.18.0" @@ -1544,11 +2359,50 @@ dependencies = [ "system-deps", ] +[[package]] +name = "gpu-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" +dependencies = [ + "bitflags 2.8.0", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" +dependencies = [ + "bitflags 2.8.0", +] + +[[package]] +name = "gpu-descriptor" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf29e94d6d243368b7a56caa16bc213e4f9f8ed38c4d9557069527b5d5281ca" +dependencies = [ + "bitflags 2.8.0", + "gpu-descriptor-types", + "hashbrown 0.15.2", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +dependencies = [ + "bitflags 2.8.0", +] + [[package]] name = "gtk" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c4f5e0e20b60e10631a5f06da7fe3dda744b05ad0ea71fee2f47adf865890c" +checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" dependencies = [ "atk", "cairo-rs", @@ -1567,9 +2421,9 @@ dependencies = [ [[package]] name = "gtk-sys" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771437bf1de2c1c0b496c11505bdf748e26066bbe942dfc8f614c9460f6d7722" +checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" dependencies = [ "atk-sys", "cairo-sys-rs", @@ -1585,15 +2439,15 @@ dependencies = [ [[package]] name = "gtk3-macros" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6063efb63db582968fb7df72e1ae68aa6360dcfb0a75143f34fc7d616bad75e" +checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] @@ -1604,9 +2458,12 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "foldhash", +] [[package]] name = "heck" @@ -1632,13 +2489,19 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + [[package]] name = "home" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1686,6 +2549,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1694,24 +2675,67 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] name = "image" -version = "0.25.2" +version = "0.25.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10" +checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" dependencies = [ "bytemuck", "byteorder-lite", "num-traits", "png", + "tiff", +] + +[[package]] +name = "image-webp" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imagesize" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284" + +[[package]] +name = "imagesize" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" + +[[package]] +name = "immutable-chunkmap" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f97096f508d54f8f8ab8957862eee2ccd628847b6217af1a335e1c44dee578" +dependencies = [ + "arrayvec", ] [[package]] @@ -1727,26 +2751,26 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.2", "serde", ] [[package]] name = "indicatif" -version = "0.17.8" +version = "0.17.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" dependencies = [ "console", - "instant", "number_prefix", "portable-atomic", - "unicode-width", + "unicode-width 0.2.0", + "web-time", ] [[package]] @@ -1771,7 +2795,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fddf93031af70e75410a2511ec04d49e758ed2f26dad3404a934e0fb45cc12a" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "crossterm 0.25.0", "dyn-clone", "fuzzy-matcher", @@ -1779,16 +2803,7 @@ dependencies = [ "newline-converter", "once_cell", "unicode-segmentation", - "unicode-width", -] - -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", + "unicode-width 0.1.14", ] [[package]] @@ -1799,18 +2814,18 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jni" @@ -1823,7 +2838,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror", + "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] @@ -1834,12 +2849,28 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" + [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -1849,11 +2880,28 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "serde", "unicode-segmentation", ] +[[package]] +name = "khronos-egl" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" +dependencies = [ + "libc", + "libloading 0.8.6", + "pkg-config", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + [[package]] name = "known-folders" version = "1.2.0" @@ -1863,11 +2911,30 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "kurbo" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd85a5776cd9500c2e2059c8c76c3b01528566b7fcbaf8098b55a33fc298849b" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "kurbo" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89234b2cc610a7dd927ebde6b41dd1a5d4214cffaef4cf1fb2195d592f92518f" +dependencies = [ + "arrayvec", + "smallvec", +] + [[package]] name = "lazy-regex" -version = "3.3.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d8e41c97e6bc7ecb552016274b99fbb5d035e8de288c582d9b933af6677bfda" +checksum = "60c7310b93682b36b98fa7ea4de998d3463ccbebd94d935d6b48ba5b6ffa7126" dependencies = [ "lazy-regex-proc_macros", "once_cell", @@ -1876,14 +2943,14 @@ dependencies = [ [[package]] name = "lazy-regex-proc_macros" -version = "3.3.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76e1d8b05d672c53cb9c7b920bbba8783845ae4f0b076e02a3db1d02c81b4163" +checksum = "4ba01db5ef81e17eb10a5e0f2109d1b3a3e29bac3070fdbd7d156bf7dbd206a1" dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] @@ -1912,15 +2979,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" dependencies = [ "gtk-sys", - "libloading", + "libloading 0.7.4", "once_cell", ] [[package]] name = "libc" -version = "0.2.159" +version = "0.2.170" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" [[package]] name = "libloading" @@ -1932,21 +2999,50 @@ dependencies = [ "winapi", ] +[[package]] +name = "libloading" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + +[[package]] +name = "libm" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72" + [[package]] name = "libredox" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "libc", + "redox_syscall 0.5.9", ] [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + +[[package]] +name = "litrs" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] name = "lock_api" @@ -1960,9 +3056,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" [[package]] name = "mac-notification-sys" @@ -1992,6 +3088,15 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "memmap2" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.9.1" @@ -2001,6 +3106,37 @@ dependencies = [ "autocfg", ] +[[package]] +name = "metal" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e" +dependencies = [ + "bitflags 2.8.0", + "block", + "core-graphics-types 0.1.3", + "foreign-types", + "log", + "objc", + "paste", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess2" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a3333bb1609500601edc766a39b4c1772874a4ce26022f4d866854dc020c41" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minidl" version = "0.1.6" @@ -2015,9 +3151,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" dependencies = [ "adler2", "simd-adler32", @@ -2031,7 +3167,7 @@ checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.48.0", ] @@ -2048,36 +3184,59 @@ dependencies = [ [[package]] name = "muda" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8123dfd4996055ac9b15a60ad263b44b01e539007523ad7a4a533a3d93b0591" +checksum = "89fed9ce3e5c01700e3a129d3d74619bbf468645b58274b420885107e496ecff" dependencies = [ "crossbeam-channel", "dpi", "gtk", "keyboard-types", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.6.0", + "objc2-app-kit 0.3.0", + "objc2-core-foundation", + "objc2-foundation 0.3.0", "once_cell", "png", - "thiserror", + "thiserror 2.0.11", "windows-sys 0.59.0", ] +[[package]] +name = "naga" +version = "24.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e380993072e52eef724eddfcde0ed013b0c023c3f0417336ed041aa9f076994e" +dependencies = [ + "arrayvec", + "bit-set", + "bitflags 2.8.0", + "cfg_aliases", + "codespan-reporting", + "hexf-parse", + "indexmap 2.7.1", + "log", + "rustc-hash", + "spirv", + "strum 0.26.3", + "termcolor", + "thiserror 2.0.11", + "unicode-xid", +] + [[package]] name = "ndk" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "jni-sys", "log", - "ndk-sys", + "ndk-sys 0.6.0+11769913", "num_enum", "raw-window-handle", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2086,6 +3245,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys", +] + [[package]] name = "ndk-sys" version = "0.6.0+11769913" @@ -2110,13 +3278,19 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "cfg-if", "cfg_aliases", "libc", "memoffset", ] +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "nom" version = "7.1.3" @@ -2129,15 +3303,16 @@ dependencies = [ [[package]] name = "notify-rust" -version = "4.11.3" +version = "4.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5134a72dc570b178bff81b01e81ab14a6fcc015391ed4b3b14853090658cd3a3" +checksum = "7fa3b9f2364a09bd359aa0206702882e208437450866a374d5372d64aece4029" dependencies = [ + "futures-lite", "log", "mac-notification-sys", "serde", "tauri-winrt-notification", - "zbus", + "zbus 5.5.0", ] [[package]] @@ -2182,7 +3357,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] @@ -2227,32 +3402,98 @@ dependencies = [ "objc2-encode", ] +[[package]] +name = "objc2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3531f65190d9cff863b77a99857e74c314dd16bf56c538c4b57c7cbc3f3a6e59" +dependencies = [ + "objc2-encode", +] + [[package]] name = "objc2-app-kit" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.6.0", - "block2", + "bitflags 2.8.0", + "block2 0.5.1", "libc", - "objc2", + "objc2 0.5.2", "objc2-core-data", "objc2-core-image", - "objc2-foundation", + "objc2-foundation 0.2.2", "objc2-quartz-core", ] +[[package]] +name = "objc2-app-kit" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5906f93257178e2f7ae069efb89fbd6ee94f0592740b5f8a1512ca498814d0fb" +dependencies = [ + "bitflags 2.8.0", + "block2 0.6.0", + "objc2 0.6.0", + "objc2-core-foundation", + "objc2-foundation 0.3.0", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" +dependencies = [ + "bitflags 2.8.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-core-location", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-contacts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + [[package]] name = "objc2-core-data" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.6.0", - "block2", - "objc2", - "objc2-foundation", + "bitflags 2.8.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925" +dependencies = [ + "bitflags 2.8.0", + "objc2 0.6.0", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dca602628b65356b6513290a21a6405b4d4027b8b250f0b98dddbb28b7de02" +dependencies = [ + "bitflags 2.8.0", + "objc2-core-foundation", ] [[package]] @@ -2261,17 +3502,29 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" dependencies = [ - "block2", - "objc2", - "objc2-foundation", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", "objc2-metal", ] +[[package]] +name = "objc2-core-location" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-contacts", + "objc2-foundation 0.2.2", +] + [[package]] name = "objc2-encode" -version = "4.0.3" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" [[package]] name = "objc2-foundation" @@ -2279,10 +3532,35 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.6.0", - "block2", + "bitflags 2.8.0", + "block2 0.5.1", + "dispatch", "libc", - "objc2", + "objc2 0.5.2", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a21c6c9014b82c39515db5b396f91645182611c97d24637cf56ac01e5f8d998" +dependencies = [ + "bitflags 2.8.0", + "block2 0.6.0", + "objc2 0.6.0", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -2291,10 +3569,10 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.6.0", - "block2", - "objc2", - "objc2-foundation", + "bitflags 2.8.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", ] [[package]] @@ -2303,13 +3581,68 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.6.0", - "block2", - "objc2", - "objc2-foundation", + "bitflags 2.8.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", "objc2-metal", ] +[[package]] +name = "objc2-symbols" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" +dependencies = [ + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" +dependencies = [ + "bitflags 2.8.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation 0.2.2", + "objc2-link-presentation", + "objc2-quartz-core", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-uniform-type-identifiers" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" +dependencies = [ + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" +dependencies = [ + "bitflags 2.8.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-core-location", + "objc2-foundation 0.2.2", +] + [[package]] name = "objc_id" version = "0.1.1" @@ -2321,18 +3654,18 @@ dependencies = [ [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.20.2" +version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "option-ext" @@ -2340,6 +3673,24 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "orbclient" +version = "0.3.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba0b26cec2e24f08ed8bb31519a9333140a6599b867dac464bb150bdb796fd43" +dependencies = [ + "libredox", +] + +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", +] + [[package]] name = "ordered-stream" version = "0.2.0" @@ -2352,9 +3703,9 @@ dependencies = [ [[package]] name = "os_info" -version = "3.9.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ca711d8b83edbb00b44d504503cd247c9c0bd8b0fa2694f2a1a3d8165379ce" +checksum = "2a604e53c24761286860eba4e2c8b23a0161526476b1de520139d69cdb85a6b5" dependencies = [ "log", "serde", @@ -2371,6 +3722,15 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "owned_ttf_parser" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4" +dependencies = [ + "ttf-parser", +] + [[package]] name = "pango" version = "0.18.3" @@ -2420,11 +3780,17 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.9", "smallvec", "windows-targets 0.52.6", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "percent-encoding" version = "2.3.1" @@ -2441,14 +3807,40 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "rand", + "rand 0.8.5", +] + +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + +[[package]] +name = "pin-project" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfe2e71e1471fe07709406bf725f710b02927c9c54b2b5b2ec0e8087d97c327d" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e859e6e5bd50440ab63c47e3ebabc90f26251f7c73c3d3e837b74a1cc3fa67" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -2475,9 +3867,9 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "png" -version = "0.17.14" +version = "0.17.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" dependencies = [ "bitflags 1.3.2", "crc32fast", @@ -2488,9 +3880,9 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.3" +version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" dependencies = [ "cfg-if", "concurrent-queue", @@ -2501,11 +3893,17 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "pollster" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" + [[package]] name = "portable-atomic" -version = "1.9.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" [[package]] name = "powerfmt" @@ -2519,7 +3917,7 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -2547,7 +3945,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.22.22", + "toml_edit 0.22.24", ] [[package]] @@ -2582,13 +3980,35 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quick-xml" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "quick-xml" version = "0.31.0" @@ -2598,11 +4018,20 @@ dependencies = [ "memchr", ] +[[package]] +name = "quick-xml" +version = "0.37.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "165859e9e55f79d67b96c5d96f4e88b6f2695a1972849c15a6a3f5c59fc2c003" +dependencies = [ + "memchr", +] + [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -2614,8 +4043,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.2", + "zerocopy 0.8.20", ] [[package]] @@ -2625,7 +4065,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.2", ] [[package]] @@ -2634,7 +4084,17 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", +] + +[[package]] +name = "rand_core" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a509b1a2ffbe92afab0e55c8fd99dea1c280e8171bd2d88682bb20bc41cbc2c" +dependencies = [ + "getrandom 0.3.1", + "zerocopy 0.8.20", ] [[package]] @@ -2663,13 +4123,28 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "rctree" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b42e27ef78c35d3998403c1d26f3efd9e135d3e5121b0a4845cc5cc27547f4f" + [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "82b568323e98e49e2a0899dcee453dd679fae22d69adf9b11dd508d1549b7e2f" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", ] [[package]] @@ -2678,16 +4153,27 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom", + "getrandom 0.2.15", + "libredox", + "thiserror 1.0.69", +] + +[[package]] +name = "redox_users" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" +dependencies = [ + "getrandom 0.2.15", "libredox", - "thiserror", + "thiserror 2.0.11", ] [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -2697,9 +4183,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -2713,17 +4199,105 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] -name = "roff" -version = "0.2.2" +name = "renderdoc-sys" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" + +[[package]] +name = "resvg" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadccb3d99a9efb8e5e00c16fbb732cbe400db2ec7fc004697ee7d97d86cf1f4" +dependencies = [ + "log", + "pico-args", + "rgb", + "svgtypes 0.13.0", + "tiny-skia", + "usvg 0.37.0", +] + +[[package]] +name = "resvg" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8928798c0a55e03c9ca6c4c6846f76377427d2c1e1f7e6de3c06ae57942df43" +dependencies = [ + "gif", + "image-webp", + "log", + "pico-args", + "rgb", + "svgtypes 0.15.3", + "tiny-skia", + "usvg 0.45.1", + "zune-jpeg", +] + +[[package]] +name = "rfd" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80c844748fdc82aae252ee4594a89b6e7ebef1063de7951545564cbc4e57075d" +dependencies = [ + "ashpd", + "block2 0.6.0", + "dispatch2", + "js-sys", + "log", + "objc2 0.6.0", + "objc2-app-kit 0.3.0", + "objc2-core-foundation", + "objc2-foundation 0.3.0", + "pollster", + "raw-window-handle", + "urlencoding", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rgb" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "roff" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3" +[[package]] +name = "roxmltree" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f" + +[[package]] +name = "roxmltree" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" + [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.4.1" @@ -2735,28 +4309,46 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + +[[package]] +name = "rustybuzz" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702" +dependencies = [ + "bitflags 2.8.0", + "bytemuck", + "core_maths", + "log", + "smallvec", + "ttf-parser", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-properties", + "unicode-script", +] [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "safe-proc-macro2" @@ -2814,43 +4406,62 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sctk-adwaita" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec" +dependencies = [ + "ab_glyph", + "log", + "memmap2", + "smithay-client-toolkit", + "tiny-skia", +] + [[package]] name = "semver" -version = "1.0.23" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.218" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.218" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6" dependencies = [ "itoa", "memchr", @@ -2866,7 +4477,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] @@ -2880,15 +4491,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ - "base64", + "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.6.0", + "indexmap 2.7.1", "serde", "serde_derive", "serde_json", @@ -2898,14 +4509,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] @@ -2914,7 +4525,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b4db627b98b36d4203a7b458cf3573730f2bb591b28871d916dfa9efabfd41f" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.1", "itoa", "ryu", "serde", @@ -2990,6 +4601,27 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "simplecss" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c" +dependencies = [ + "log", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "slab" version = "0.4.9" @@ -2999,11 +4631,80 @@ dependencies = [ "autocfg", ] +[[package]] +name = "slotmap" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "version_check", +] + [[package]] name = "smallvec" -version = "1.13.2" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" + +[[package]] +name = "smithay-client-toolkit" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" +dependencies = [ + "bitflags 2.8.0", + "calloop", + "calloop-wayland-source", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix", + "thiserror 1.0.69", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + +[[package]] +name = "smithay-clipboard" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc8216eec463674a0e90f29e0ae41a4db573ec5b56b1c6c1c71615d249b6d846" +dependencies = [ + "libc", + "smithay-client-toolkit", + "wayland-backend", +] + +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + +[[package]] +name = "spirv" +version = "0.3.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +dependencies = [ + "bitflags 2.8.0", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "static_assertions" @@ -3011,6 +4712,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +dependencies = [ + "float-cmp", +] + [[package]] name = "strsim" version = "0.11.1" @@ -3023,7 +4733,16 @@ version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ - "strum_macros", + "strum_macros 0.26.4", +] + +[[package]] +name = "strum" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" +dependencies = [ + "strum_macros 0.27.1", ] [[package]] @@ -3036,7 +4755,40 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.79", + "syn 2.0.98", +] + +[[package]] +name = "strum_macros" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.98", +] + +[[package]] +name = "svgtypes" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e44e288cd960318917cbd540340968b90becc8bc81f171345d706e7a89d9d70" +dependencies = [ + "kurbo 0.9.5", + "siphasher 0.3.11", +] + +[[package]] +name = "svgtypes" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68c7541fff44b35860c1a7a47a7cadf3e4a304c457b58f9870d9706ece028afc" +dependencies = [ + "kurbo 0.11.1", + "siphasher 1.0.1", ] [[package]] @@ -3052,20 +4804,31 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "sysinfo" -version = "0.32.0" +version = "0.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ae3f4f7d64646c46c4cae4e3f01d1c5d255c7406fdd7c7f999a94e488791" +checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01" dependencies = [ "core-foundation-sys", "libc", @@ -3090,14 +4853,13 @@ dependencies = [ [[package]] name = "tao" -version = "0.30.3" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0dbbebe82d02044dfa481adca1550d6dd7bd16e086bc34fa0fbecceb5a63751" +checksum = "9899a4cb2590e669dd9d32ea6360ac67f29843fbf0424e06f9fc0e9e1ec9579a" dependencies = [ - "bitflags 2.6.0", - "cocoa", - "core-foundation", - "core-graphics", + "bitflags 2.8.0", + "core-foundation 0.10.0", + "core-graphics 0.24.0", "crossbeam-channel", "dispatch", "dlopen2", @@ -3105,23 +4867,24 @@ dependencies = [ "gdkwayland-sys", "gdkx11-sys", "gtk", - "instant", "jni", "lazy_static", "libc", "log", "ndk", "ndk-context", - "ndk-sys", - "objc", + "ndk-sys 0.6.0+11769913", + "objc2 0.6.0", + "objc2-app-kit 0.3.0", + "objc2-foundation 0.3.0", "once_cell", "parking_lot", "scopeguard", "tao-macros", "unicode-segmentation", "url", - "windows 0.58.0", - "windows-core 0.58.0", + "windows 0.60.0", + "windows-core 0.60.1", "windows-version", "x11-dl", ] @@ -3134,7 +4897,7 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] @@ -3149,42 +4912,72 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f89f5fb70d6f62381f5d9b2ba9008196150b40b75f3068eb24faeddf1c686871" dependencies = [ - "quick-xml", + "quick-xml 0.31.0", "windows 0.56.0", "windows-version", ] [[package]] name = "tempfile" -version = "3.13.0" +version = "3.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" dependencies = [ "cfg-if", "fastrand", + "getrandom 0.3.1", "once_cell", "rustix", "windows-sys 0.59.0", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +dependencies = [ + "thiserror-impl 2.0.11", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "thiserror-impl", + "proc-macro2", + "quote", + "syn 2.0.98", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] @@ -3203,11 +4996,22 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7d2d6a110f96a589b87d0f6c46d4048c84a01a7b81a2dcc97656694ace28b1" +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -3226,19 +5030,55 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", ] +[[package]] +name = "tiny-skia" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "png", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" dependencies = [ "tinyvec_macros", ] @@ -3251,14 +5091,14 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "toml" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.22", + "toml_edit 0.22.24", ] [[package]] @@ -3276,7 +5116,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.1", "toml_datetime", "winnow 0.5.40", ] @@ -3287,29 +5127,29 @@ version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.1", "toml_datetime", "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.1", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.20", + "winnow 0.7.3", ] [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -3318,49 +5158,68 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", ] [[package]] name = "tray-icon" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533fc2d4105e0e3d96ce1c71f2d308c9fbbe2ef9c587cab63dd627ab5bde218f" +checksum = "d433764348e7084bad2c5ea22c96c71b61b17afe3a11645710f533bd72b6a2b5" dependencies = [ - "core-graphics", "crossbeam-channel", "dirs", "libappindicator", "muda", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "objc2 0.6.0", + "objc2-app-kit 0.3.0", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation 0.3.0", "once_cell", "png", - "thiserror", + "thiserror 2.0.11", "windows-sys 0.59.0", ] +[[package]] +name = "ttf-parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" +dependencies = [ + "core_maths", +] + +[[package]] +name = "type-map" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f" +dependencies = [ + "rustc-hash", +] + [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "uds_windows" @@ -3373,26 +5232,47 @@ dependencies = [ "winapi", ] +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + [[package]] name = "unicode-bidi" -version = "0.3.17" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-bidi-mirroring" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfa6e8c60bb66d49db113e0125ee8711b7647b5579dc7f5f19c42357ed039fe" + +[[package]] +name = "unicode-ccc" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" +checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" [[package]] -name = "unicode-normalization" -version = "0.1.24" +name = "unicode-properties" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" + +[[package]] +name = "unicode-script" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" [[package]] name = "unicode-segmentation" @@ -3400,6 +5280,12 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +[[package]] +name = "unicode-vo" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" + [[package]] name = "unicode-width" version = "0.1.14" @@ -3407,22 +5293,124 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] -name = "unsafe-libyaml" -version = "0.2.11" +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "usvg" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b0a51b72ab80ca511d126b77feeeb4fb1e972764653e61feac30adc161a756" +dependencies = [ + "base64 0.21.7", + "log", + "pico-args", + "usvg-parser", + "usvg-tree", + "xmlwriter", +] + +[[package]] +name = "usvg" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80be9b06fbae3b8b303400ab20778c80bbaf338f563afe567cf3c9eea17b47ef" +dependencies = [ + "base64 0.22.1", + "data-url", + "flate2", + "fontdb", + "imagesize 0.13.0", + "kurbo 0.11.1", + "log", + "pico-args", + "roxmltree 0.20.0", + "rustybuzz", + "simplecss", + "siphasher 1.0.1", + "strict-num", + "svgtypes 0.15.3", + "tiny-skia-path", + "unicode-bidi", + "unicode-script", + "unicode-vo", + "xmlwriter", ] +[[package]] +name = "usvg-parser" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd4e3c291f45d152929a31f0f6c819245e2921bfd01e7bd91201a9af39a2bdc" +dependencies = [ + "data-url", + "flate2", + "imagesize 0.12.0", + "kurbo 0.9.5", + "log", + "roxmltree 0.19.0", + "simplecss", + "siphasher 0.3.11", + "svgtypes 0.13.0", + "usvg-tree", +] + +[[package]] +name = "usvg-tree" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee3d202ebdb97a6215604b8f5b4d6ef9024efd623cf2e373a6416ba976ec7d3" +dependencies = [ + "rctree", + "strict-num", + "svgtypes 0.13.0", + "tiny-skia-path", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -3431,11 +5419,11 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.11.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +checksum = "bd8dcafa1ca14750d8d7a05aa05988c17aab20886e1f3ae33a40223c58d92ef7" dependencies = [ - "getrandom", + "getrandom 0.3.1", "sha1_smol", ] @@ -3467,37 +5455,59 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3505,22 +5515,134 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wayland-backend" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7208998eaa3870dad37ec8836979581506e0c5c64c20c9e79e9d2a10d6f47bf" +dependencies = [ + "cc", + "downcast-rs", + "rustix", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f" +dependencies = [ + "bitflags 2.8.0", + "rustix", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-csd-frame" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" +dependencies = [ + "bitflags 2.8.0", + "cursor-icon", + "wayland-backend", +] + +[[package]] +name = "wayland-cursor" +version = "0.31.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a93029cbb6650748881a00e4922b076092a6a08c11e7fbdb923f064b23968c5d" +dependencies = [ + "rustix", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0781cf46869b37e36928f7b432273c0995aa8aed9552c556fb18754420541efc" +dependencies = [ + "bitflags 2.8.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-plasma" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ccaacc76703fefd6763022ac565b590fcade92202492381c95b2edfdf7d46b3" +dependencies = [ + "bitflags 2.8.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248a02e6f595aad796561fa82d25601bd2c8c3b145b1c7453fc8f94c1a58f8b2" +dependencies = [ + "bitflags 2.8.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" +dependencies = [ + "proc-macro2", + "quick-xml 0.37.2", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615" +dependencies = [ + "dlib", + "log", + "once_cell", + "pkg-config", +] [[package]] name = "wchar" @@ -3544,14 +5666,161 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webbrowser" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea9fe1ebb156110ff855242c1101df158b822487e4957b0556d9ffce9db0f535" +dependencies = [ + "block2 0.5.1", + "core-foundation 0.10.0", + "home", + "jni", + "log", + "ndk-context", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "url", + "web-sys", +] + +[[package]] +name = "weezl" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" + +[[package]] +name = "wgpu" +version = "24.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47f55718f85c2fa756edffa0e7f0e0a60aba463d1362b57e23123c58f035e4b6" +dependencies = [ + "arrayvec", + "bitflags 2.8.0", + "cfg_aliases", + "document-features", + "js-sys", + "log", + "parking_lot", + "profiling", + "raw-window-handle", + "smallvec", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "24.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82a39b8842dc9ffcbe34346e3ab6d496b32a47f6497e119d762c97fcaae3cb37" +dependencies = [ + "arrayvec", + "bit-vec", + "bitflags 2.8.0", + "cfg_aliases", + "document-features", + "indexmap 2.7.1", + "log", + "naga", + "once_cell", + "parking_lot", + "profiling", + "raw-window-handle", + "rustc-hash", + "smallvec", + "thiserror 2.0.11", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-hal" +version = "24.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a782e5056b060b0b4010881d1decddd059e44f2ecd01e2db2971b48ad3627e5" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bitflags 2.8.0", + "bytemuck", + "cfg_aliases", + "core-graphics-types 0.1.3", + "glow", + "glutin_wgl_sys", + "gpu-alloc", + "gpu-descriptor", + "js-sys", + "khronos-egl", + "libc", + "libloading 0.8.6", + "log", + "metal", + "naga", + "ndk-sys 0.5.0+25.2.9519653", + "objc", + "once_cell", + "ordered-float", + "parking_lot", + "profiling", + "raw-window-handle", + "renderdoc-sys", + "rustc-hash", + "smallvec", + "thiserror 2.0.11", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "windows 0.58.0", +] + +[[package]] +name = "wgpu-types" +version = "24.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50ac044c0e76c03a0378e7786ac505d010a873665e2d51383dcff8dd227dc69c" +dependencies = [ + "bitflags 2.8.0", + "js-sys", + "log", + "web-sys", +] + [[package]] name = "which" -version = "6.0.3" +version = "7.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" +checksum = "2774c861e1f072b3aadc02f8ba886c26ad6321567ecc294c935434cad06f1283" dependencies = [ "either", - "home", + "env_home", "rustix", "winsafe", ] @@ -3617,6 +5886,28 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf874e74c7a99773e62b1c671427abf01a425e77c3d3fb9fb1e4883ea934529" +dependencies = [ + "windows-collections", + "windows-core 0.60.1", + "windows-future", + "windows-link", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5467f79cc1ba3f52ebb2ed41dbb459b8e7db636cc3429458d9a852e15bc24dec" +dependencies = [ + "windows-core 0.60.1", +] + [[package]] name = "windows-core" version = "0.52.0" @@ -3659,10 +5950,33 @@ dependencies = [ "windows-implement 0.58.0", "windows-interface 0.58.0", "windows-result 0.2.0", - "windows-strings", + "windows-strings 0.1.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.60.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca21a92a9cae9bf4ccae5cf8368dce0837100ddf6e6d57936749e85f152f6247" +dependencies = [ + "windows-implement 0.59.0", + "windows-interface 0.59.0", + "windows-link", + "windows-result 0.3.1", + "windows-strings 0.3.1", +] + +[[package]] +name = "windows-future" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a787db4595e7eb80239b74ce8babfb1363d8e343ab072f2ffe901400c03349f0" +dependencies = [ + "windows-core 0.60.1", + "windows-link", +] + [[package]] name = "windows-implement" version = "0.56.0" @@ -3671,7 +5985,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] @@ -3682,7 +5996,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] @@ -3693,7 +6007,18 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", +] + +[[package]] +name = "windows-implement" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", ] [[package]] @@ -3704,7 +6029,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] @@ -3715,7 +6040,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", ] [[package]] @@ -3726,7 +6051,34 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", +] + +[[package]] +name = "windows-interface" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26fd936d991781ea39e87c3a27285081e3c0da5ca0fcbc02d368cc6f52ff01" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "windows-link" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" + +[[package]] +name = "windows-numerics" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "005dea54e2f6499f2cee279b8f703b3cf3b5734a2d8d21867c8f44003182eeed" +dependencies = [ + "windows-core 0.60.1", + "windows-link", ] [[package]] @@ -3747,6 +6099,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-strings" version = "0.1.0" @@ -3757,6 +6118,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-strings" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.45.0" @@ -3841,11 +6211,11 @@ dependencies = [ [[package]] name = "windows-version" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6998aa457c9ba8ff2fb9f13e9d2a930dabcea28f1d0ab94d687d8b3654844515" +checksum = "7bfbcc4996dd183ff1376a20ade1242da0d2dcaff83cc76710a588d24fd4c5db" dependencies = [ - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -3980,6 +6350,58 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winit" +version = "0.30.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a809eacf18c8eca8b6635091543f02a5a06ddf3dad846398795460e6e0ae3cc0" +dependencies = [ + "ahash", + "android-activity", + "atomic-waker", + "bitflags 2.8.0", + "block2 0.5.1", + "bytemuck", + "calloop", + "cfg_aliases", + "concurrent-queue", + "core-foundation 0.9.4", + "core-graphics 0.23.2", + "cursor-icon", + "dpi", + "js-sys", + "libc", + "memmap2", + "ndk", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", + "objc2-ui-kit", + "orbclient", + "percent-encoding", + "pin-project", + "raw-window-handle", + "redox_syscall 0.4.1", + "rustix", + "sctk-adwaita", + "smithay-client-toolkit", + "smol_str", + "tracing", + "unicode-segmentation", + "wasm-bindgen", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-plasma", + "web-sys", + "web-time", + "windows-sys 0.52.0", + "x11-dl", + "x11rb", + "xkbcommon-dl", +] + [[package]] name = "winnow" version = "0.5.40" @@ -3991,9 +6413,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.20" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" dependencies = [ "memchr", ] @@ -4004,6 +6426,27 @@ version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.8.0", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "wslapi" version = "0.1.3" @@ -4036,6 +6479,33 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "x11rb" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" +dependencies = [ + "as-raw-xcb-connection", + "gethostname", + "libc", + "libloading 0.8.6", + "once_cell", + "rustix", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" + +[[package]] +name = "xcursor" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61" + [[package]] name = "xdg-home" version = "1.3.0" @@ -4046,6 +6516,61 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "xkbcommon-dl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" +dependencies = [ + "bitflags 2.8.0", + "dlib", + "log", + "once_cell", + "xkeysym", +] + +[[package]] +name = "xkeysym" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" + +[[package]] +name = "xml-rs" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4" + +[[package]] +name = "xmlwriter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", + "synstructure", +] + [[package]] name = "zbus" version = "4.4.0" @@ -4070,7 +6595,7 @@ dependencies = [ "hex", "nix", "ordered-stream", - "rand", + "rand 0.8.5", "serde", "serde_repr", "sha1", @@ -4079,9 +6604,69 @@ dependencies = [ "uds_windows", "windows-sys 0.52.0", "xdg-home", - "zbus_macros", - "zbus_names", - "zvariant", + "zbus_macros 4.4.0", + "zbus_names 3.0.0", + "zvariant 4.2.0", +] + +[[package]] +name = "zbus" +version = "5.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59c333f648ea1b647bc95dc1d34807c8e25ed7a6feff3394034dc4776054b236" +dependencies = [ + "async-broadcast", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener", + "futures-core", + "futures-lite", + "hex", + "nix", + "ordered-stream", + "serde", + "serde_repr", + "static_assertions", + "tracing", + "uds_windows", + "windows-sys 0.59.0", + "winnow 0.7.3", + "xdg-home", + "zbus_macros 5.5.0", + "zbus_names 4.2.0", + "zvariant 5.4.0", +] + +[[package]] +name = "zbus-lockstep" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca2c5dceb099bddaade154055c926bb8ae507a18756ba1d8963fd7b51d8ed1d" +dependencies = [ + "zbus_xml", + "zvariant 4.2.0", +] + +[[package]] +name = "zbus-lockstep-macros" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709ab20fc57cb22af85be7b360239563209258430bccf38d8b979c5a2ae3ecce" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", + "zbus-lockstep", + "zbus_xml", + "zvariant 4.2.0", ] [[package]] @@ -4093,8 +6678,23 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.79", - "zvariant_utils", + "syn 2.0.98", + "zvariant_utils 2.1.0", +] + +[[package]] +name = "zbus_macros" +version = "5.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f325ad10eb0d0a3eb060203494c3b7ec3162a01a59db75d2deee100339709fc0" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.98", + "zbus_names 4.2.0", + "zvariant 5.4.0", + "zvariant_utils 3.2.0", ] [[package]] @@ -4105,7 +6705,32 @@ checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" dependencies = [ "serde", "static_assertions", - "zvariant", + "zvariant 4.2.0", +] + +[[package]] +name = "zbus_names" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" +dependencies = [ + "serde", + "static_assertions", + "winnow 0.7.3", + "zvariant 5.4.0", +] + +[[package]] +name = "zbus_xml" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3f374552b954f6abb4bd6ce979e6c9b38fb9d0cd7cc68a7d796e70c9f3a233" +dependencies = [ + "quick-xml 0.30.0", + "serde", + "static_assertions", + "zbus_names 3.0.0", + "zvariant 4.2.0", ] [[package]] @@ -4115,7 +6740,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde3bb8c68a8f3f1ed4ac9221aad6b10cece3e60a8e2ea54a6a2dec806d0084c" +dependencies = [ + "zerocopy-derive 0.8.20", ] [[package]] @@ -4126,7 +6760,76 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eea57037071898bf96a6da35fd626f4f27e9cee3ead2a6c703cf09d472b2e700" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-jpeg" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" +dependencies = [ + "zune-core", ] [[package]] @@ -4139,7 +6842,23 @@ dependencies = [ "enumflags2", "serde", "static_assertions", - "zvariant_derive", + "zvariant_derive 4.2.0", +] + +[[package]] +name = "zvariant" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2df9ee044893fcffbdc25de30546edef3e32341466811ca18421e3cd6c5a3ac" +dependencies = [ + "endi", + "enumflags2", + "serde", + "static_assertions", + "url", + "winnow 0.7.3", + "zvariant_derive 5.4.0", + "zvariant_utils 3.2.0", ] [[package]] @@ -4151,8 +6870,21 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.79", - "zvariant_utils", + "syn 2.0.98", + "zvariant_utils 2.1.0", +] + +[[package]] +name = "zvariant_derive" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74170caa85b8b84cc4935f2d56a57c7a15ea6185ccdd7eadb57e6edd90f94b2f" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.98", + "zvariant_utils 3.2.0", ] [[package]] @@ -4163,5 +6895,19 @@ checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.98", +] + +[[package]] +name = "zvariant_utils" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16edfee43e5d7b553b77872d99bc36afdda75c223ca7ad5e3fbecd82ca5fc34" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "static_assertions", + "syn 2.0.98", + "winnow 0.7.3", ] diff --git a/codchi/Cargo.toml b/codchi/Cargo.toml index 084bdb5f..3724b377 100644 --- a/codchi/Cargo.toml +++ b/codchi/Cargo.toml @@ -20,14 +20,14 @@ log = "0.4" serde = { version = "1", features = ["derive"] } serde_json = "1" serde_with = "3.11" -strum = { version = "0.26", features = ["derive"] } -directories = "5" -itertools = "0.13" +strum = { version = "0.27", features = ["derive"] } +directories = "6" +itertools = "0.14" lazy-regex = "3.3.0" # base64 = "0.22.1" clap = { version = "4", features = ["derive", "cargo", "string"] } clap_complete_command = { version = "0.6.1", features = ["fig", "carapace"] } -clap-verbosity-flag = "2.2.2" +clap-verbosity-flag = "3.0.2" comfy-table = "7.1.1" console = { version = "0.15.8", default-features = false, features = [ "windows-console-colors", @@ -45,22 +45,28 @@ petname = { version = "2.0.2", default-features = false, features = [ "default-words", ] } # rustls-native-certs = "0.8.0" -sysinfo = "0.32.0" -thiserror = "1.0" +sysinfo = "0.33.1" +thiserror = "2.0" throttle = "0.1.0" -tray-icon = { version = "0.19", default-features = false } -image = { version = "0.25", features = ["png"], default-features = false } -tao = { version = "0.30", default-features = false } -fs4 = { version = "0.9", features = ["sync"] } -git-url-parse = "0.4.5" +tray-icon = { version = "0.20", default-features = false } +image = { version = "0.25", features = ["png", "ico"], default-features = false } +tao = { version = "0.32", default-features = false } +fs4 = { version = "0.13", features = ["sync"] } +git-url-parse = { git = "https://github.com/tjtelan/git-url-parse-rs" } toml_edit = { version = "0.22.22", features = ["serde"] } -which = "6.0.3" +which = "7.0.2" notify-rust = "4.11.3" human-panic = "2.0.2" # clap-help = "1.3.0" # termimad = "0.30.0" -rand = "0.8.5" +rand = "0.9.0" ctrlc = { version = "3.4.5", features = ["termination"] } +egui = "0.31.0" +eframe = "0.31.0" +egui_extras = { version = "0.31.0", features = ["default", "image", "svg"] } +rfd = "0.15.3" +usvg = "0.45.1" +resvg = "0.45.1" [target.'cfg(unix)'.dependencies] indoc = "2.0.5" @@ -70,21 +76,14 @@ nix = { version = "0.29.0", features = ["user", "hostname"] } known-folders = "1.2.0" mslnk = "0.1.8" version-compare = "0.2" -windows = { version = "0.58", features = [ - "Win32_System_Console", - "Win32_UI_WindowsAndMessaging", - "Win32_System_Diagnostics_Debug", - "Win32_Storage_FileSystem", - "Win32_Security", - "Win32_System_Threading", -] } +windows = { version = "0.60", features = ["Win32_System_Console", "Win32_UI_WindowsAndMessaging", "Win32_System_Diagnostics_Debug", "Win32_Storage_FileSystem", "Win32_Security", "Win32_System_Threading"] } wslapi = "0.1.3" clap_complete_command = { version = "0.6.1", default-features = false } uuid = { version = "1.11.0", features = ["v5"] } [build-dependencies] clap = { version = "4", features = ["derive", "cargo", "string"] } -clap-verbosity-flag = "2.2.2" +clap-verbosity-flag = "3.0.2" clap_complete = "4" clap_complete_command = { version = "0.6.1", features = ["fig", "carapace"] } clap_complete_fig = "4" @@ -93,7 +92,7 @@ clap_mangen = "0" embed-manifest = "1.4.0" log = "0.4" build-data = "0" -git-url-parse = "0" +git-url-parse = { git = "https://github.com/tjtelan/git-url-parse-rs" } lazy-regex = "3.3.0" duct = "0.13.7" diff --git a/codchi/assets/bug_icon.svg b/codchi/assets/bug_icon.svg new file mode 100755 index 00000000..3073c705 --- /dev/null +++ b/codchi/assets/bug_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/codchi/assets/github_logo.svg b/codchi/assets/github_logo.svg new file mode 100755 index 00000000..8e3a992b --- /dev/null +++ b/codchi/assets/github_logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/codchi/assets/menu_icon.svg b/codchi/assets/menu_icon.svg new file mode 100755 index 00000000..a4c2e73c --- /dev/null +++ b/codchi/assets/menu_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/codchi/assets/reload.png b/codchi/assets/reload.png new file mode 100755 index 00000000..0d4d3d68 Binary files /dev/null and b/codchi/assets/reload.png differ diff --git a/codchi/default.nix b/codchi/default.nix index 0034aebc..d0752028 100644 --- a/codchi/default.nix +++ b/codchi/default.nix @@ -22,5 +22,6 @@ callPackage ../build/build-rust-package.nix cargoLock.outputHashes = { # "tray-icon-0.16.0" = "sha256-LxkEP31myIiWh6FDOzr9rZ8KAWISbja0jmEx0E2lM44="; # "clap-4.5.19" = "sha256-YRuZlp7jk05QLI551shgcVftcqKytTkxHlKbVejT1eE="; + "git-url-parse-0.4.5" = "sha256-q3lrdWE+WpAI0FSbpzUabk9aPCjzoqIHvNoDmqRl2BY="; }; } diff --git a/codchi/shell.nix b/codchi/shell.nix index 1e4979a9..3b8aa8c1 100644 --- a/codchi/shell.nix +++ b/codchi/shell.nix @@ -24,6 +24,9 @@ , cargo-flamegraph , graphviz +, vscode-with-extensions +, vscodium +, vscode-extensions , ... }: let @@ -96,6 +99,16 @@ mkShell (lib.recursiveUpdate runScript = "zed"; }) + (vscode-with-extensions.override { + vscode = vscodium; + vscodeExtensions = with vscode-extensions; [ + rust-lang.rust-analyzer + jnoortheen.nix-ide + mkhl.direnv + asvetliakov.vscode-neovim + ]; + }) + ] ++ (codchi.nativeBuildInputs or [ ]); shellHook = '' diff --git a/codchi/src/cli.rs b/codchi/src/cli.rs index 496e686d..a8e797b7 100644 --- a/codchi/src/cli.rs +++ b/codchi/src/cli.rs @@ -20,7 +20,7 @@ pub static DEBUG: LazyLock = LazyLock::new(|| { CLI_ARGS .get() .and_then(|cli| cli.verbose.log_level()) - .or(::default()) + .or(::default_filter().into()) .unwrap() >= Level::Debug }); @@ -486,11 +486,17 @@ See the following docs on how to register the completions with your shell: #[arg(value_enum)] shell: clap_complete_command::Shell, }, + /// - /// Start the codchi tray if not running. + /// Start the Codchi tray if not running. #[clap(hide = true)] Tray {}, + /// + /// Start the Codchi GUI. + #[clap(hide = true)] + GUI {}, + #[clap( about = "Export the file system of a code machine including NixOS configuration and codchi secrets." )] diff --git a/codchi/src/gui/main_panel/empty_machine_creation.rs b/codchi/src/gui/main_panel/empty_machine_creation.rs new file mode 100644 index 00000000..eedcc814 --- /dev/null +++ b/codchi/src/gui/main_panel/empty_machine_creation.rs @@ -0,0 +1,69 @@ +use egui::*; + +use super::MainPanelIntent; + +#[derive(Default)] +pub struct EmptyMachineCreation { + machine_name: String, + dont_build: bool, +} + +impl EmptyMachineCreation { + pub fn update(&mut self, ui: &mut Ui) -> Vec { + self.update_ui(ui); + + self.update_buttons(ui) + } + + fn update_ui(&mut self, ui: &mut Ui) { + ui.heading("Empty Machine Creation"); + ui.label(""); + ui.separator(); + + Grid::new("empty_generics_grid") + .num_columns(2) + .show(ui, |ui| { + ui.label("Machine Name"); + ui.add_sized( + ui.available_size(), + TextEdit::singleline(&mut self.machine_name).hint_text("My awesome Name"), + ); + ui.end_row(); + + ui.label(""); + ui.separator(); + ui.end_row(); + + ui.checkbox(&mut self.dont_build, "Don't build"); + }); + } + + fn update_buttons(&mut self, ui: &mut Ui) -> Vec { + let mut intent = Vec::new(); + + ui.with_layout(Layout::bottom_up(Align::Min), |ui| { + ui.with_layout(Layout::right_to_left(Align::Max), |ui| { + let create_button = Button::new("Create").fill(Color32::DARK_GREEN); + if ui.add(create_button).clicked() { + let temp = std::mem::take(self); + intent.push(MainPanelIntent::EmptyMachineCreation( + EmptyMachineCreationIntent::CreateMachine( + temp.machine_name, + temp.dont_build, + ), + )); + } + }); + }); + + intent + } + + pub fn reset(&mut self) { + *self = Self::default(); + } +} + +pub enum EmptyMachineCreationIntent { + CreateMachine(String, bool), +} diff --git a/codchi/src/gui/main_panel/machine_creation/generics_panel.rs b/codchi/src/gui/main_panel/machine_creation/generics_panel.rs new file mode 100644 index 00000000..077d612f --- /dev/null +++ b/codchi/src/gui/main_panel/machine_creation/generics_panel.rs @@ -0,0 +1,125 @@ +use super::{AuthUrl, InternalIntent}; +use crate::gui::util::password_field; +use egui::*; + +#[derive(Default)] +pub struct GenericsPanel { + pub(super) machine_name: String, + auth_url: AuthUrl, + pub(super) dont_build: bool, + + occupied_loading_repo: bool, + repo_inaccessible: bool, +} + +impl GenericsPanel { + pub fn update(&mut self, ui: &mut Ui) -> Vec { + self.update_ui(ui); + + self.update_buttons(ui) + } + + fn update_ui(&mut self, ui: &mut Ui) { + ui.heading("Machine Creation"); + ui.separator(); + + Grid::new("generics_grid").num_columns(2).show(ui, |ui| { + ui.label("Machine Name"); + ui.add_sized( + ui.available_size(), + TextEdit::singleline(&mut self.machine_name).hint_text("My awesome Name"), + ); + ui.end_row(); + + ui.label(""); + ui.separator(); + ui.end_row(); + + ui.label("URL"); + add_sized_colored( + ui, + &mut self.repo_inaccessible, + ui.available_size(), + TextEdit::singleline(&mut self.auth_url.url) + .hint_text("https://gitlab.example.com/my_repo"), + ); + ui.end_row(); + + ui.label("Username"); + add_sized_colored( + ui, + &mut self.repo_inaccessible, + ui.available_size(), + TextEdit::singleline(&mut self.auth_url.username), + ); + ui.end_row(); + + ui.label("Password"); + add_sized_colored( + ui, + &mut self.repo_inaccessible, + ui.available_size(), + password_field(&mut self.auth_url.password), + ); + ui.end_row(); + + ui.label(""); + ui.separator(); + ui.end_row(); + + ui.checkbox(&mut self.dont_build, "Don't build"); + }); + } + + fn update_buttons(&mut self, ui: &mut Ui) -> Vec { + let mut intent = Vec::new(); + + ui.with_layout(Layout::bottom_up(Align::Max), |ui| { + let button = Button::new("Next"); + let enabled = !self.occupied_loading_repo + && !self.auth_url.url.is_empty() + && !self.machine_name.is_empty(); + let button_handle = ui.add_enabled(enabled, button); + if button_handle.clicked() { + intent.push(InternalIntent::ToRepositoryPanel(Some( + self.auth_url.clone(), + ))); + self.occupied_loading_repo = true; + } + }); + + intent + } + + pub fn set_url(&mut self, url: String) { + self.auth_url.url = url; + } + + pub fn finished_loading_repo(&mut self) { + self.occupied_loading_repo = false; + } + + pub fn set_repo_inaccessible(&mut self) { + self.repo_inaccessible = true; + } +} + +fn add_sized_colored( + ui: &mut Ui, + condition: &mut bool, + max_size: impl Into, + widget: impl Widget, +) -> Response { + ui.horizontal(|ui| { + if *condition { + ui.visuals_mut().widgets.inactive.bg_stroke.width = 1.0; + ui.visuals_mut().widgets.inactive.bg_stroke.color = Color32::RED; + } + let handle = ui.add_sized(max_size, widget); + if handle.gained_focus() { + *condition = false; + } + handle + }) + .inner +} diff --git a/codchi/src/gui/main_panel/machine_creation/mod.rs b/codchi/src/gui/main_panel/machine_creation/mod.rs new file mode 100644 index 00000000..7f93f98a --- /dev/null +++ b/codchi/src/gui/main_panel/machine_creation/mod.rs @@ -0,0 +1,366 @@ +mod generics_panel; +mod modules_panel; +mod repository_panel; + +use super::MainPanelIntent; +use crate::cli::{InputOptions, ModuleAttrPath, NixpkgsLocation}; +use anyhow::Result; +use egui::*; +use generics_panel::GenericsPanel; +use git_url_parse::GitUrl; +use modules_panel::ModulesPanel; +use repository_panel::RepositoryPanel; +use strum::{EnumIter, IntoEnumIterator}; + +#[derive(Default)] +pub struct MachineCreation { + creation_step: CreationStep, + + generics_panel: GenericsPanel, + repository_panel: RepositoryPanel, + modules_panel: ModulesPanel, +} + +impl MachineCreation { + pub fn update(&mut self, ui: &mut Ui) -> Vec { + self.change_step(self.update_creation_step_buttons(ui)); + + let intents = self.update_panel(ui); + + self.eval_intents(intents) + } + + fn update_creation_step_buttons(&self, ui: &mut Ui) -> Option { + let (button_1_handle, button_2_handle, button_3_handle) = self.add_step_buttons(ui); + + if button_1_handle.clicked() { + return Some(CreationStep::Generics); + } + if button_2_handle.clicked() { + return Some(CreationStep::Repository); + } + if button_3_handle.clicked() { + return Some(CreationStep::Modules); + } + + None + } + + fn add_step_buttons(&self, ui: &mut Ui) -> (Response, Response, Response) { + let steps: Vec = CreationStep::iter().collect(); + + let button_1 = self.get_step_button(&steps[0]); + let button_2 = self.get_step_button(&steps[1]); + let button_3 = self.get_step_button(&steps[2]); + + let enabled_1 = self.is_step_reachable(&steps[0]); + let enabled_2 = self.is_step_reachable(&steps[1]); + let enabled_3 = self.is_step_reachable(&steps[2]); + + let width = (ui.available_width() - (2 as f32 * ui.spacing().item_spacing.x)) / 3 as f32; + + let result = ui + .horizontal_top(|ui| { + ( + ui.add_enabled_ui(enabled_1, |ui| ui.add_sized([width, 0.0], button_1)) + .inner, + ui.add_enabled_ui(enabled_2, |ui| ui.add_sized([width, 0.0], button_2)) + .inner, + ui.add_enabled_ui(enabled_3, |ui| { + ui.add_sized([ui.available_width(), 0.0], button_3) + }) + .inner, + ) + }) + .inner; + + ui.separator(); + + result + } + + fn update_panel(&mut self, ui: &mut Ui) -> Vec { + match self.creation_step { + CreationStep::Generics => self.generics_panel.update(ui), + CreationStep::Repository => self.repository_panel.update(ui), + CreationStep::Modules => self.modules_panel.update(ui), + } + } + + fn get_step_button(&self, creation_step: &CreationStep) -> Button<'_> { + let text = RichText::new(creation_step.to_text()).heading(); + if creation_step == &self.creation_step { + Button::new(text).fill(Color32::DARK_GRAY) + } else { + Button::new(text) + } + } + + fn is_step_reachable(&self, creation_step: &CreationStep) -> bool { + match &creation_step { + CreationStep::Generics => true, + CreationStep::Repository => self.repository_panel.is_current_auth_url_loaded(), + CreationStep::Modules => self.modules_panel.is_current_repo_loaded(), + } + } + + fn change_step(&mut self, creation_step_option: Option) { + if let Some(creation_step) = creation_step_option { + self.creation_step = creation_step; + } + } + + pub fn reset(&mut self) { + *self = Self::default(); + } + + pub fn pass_url(&mut self, url: String) { + self.reset(); + self.generics_panel.set_url(url); + } + + pub fn repo_is_inaccessible(&mut self) { + self.generics_panel.finished_loading_repo(); + self.generics_panel.set_repo_inaccessible(); + } + + pub fn is_auth_url_loaded(&self, auth_url: &AuthUrl) -> bool { + self.repository_panel.is_auth_url_loaded(auth_url) + } + + pub fn pass_branches(&mut self, auth_url: AuthUrl, branches: Vec) { + self.repository_panel + .insert_branches(auth_url.clone(), branches); + if self.repository_panel.is_auth_url_loaded(&auth_url) { + self.to_repository_panel(Some(auth_url)); + } + } + + pub fn pass_tags(&mut self, auth_url: AuthUrl, tags: Vec) { + self.repository_panel.insert_tags(auth_url.clone(), tags); + if self.repository_panel.is_auth_url_loaded(&auth_url) { + self.to_repository_panel(Some(auth_url)); + } + } + + pub fn pass_modules( + &mut self, + repo: (AuthUrl, RepositorySpecification), + modules: Vec, + ) { + self.modules_panel.insert_modules(repo.clone(), modules); + self.to_modules_panel(Some(repo)); + } + + pub fn to_repository_panel(&mut self, auth_url_option: Option) { + if let Some(auth_url) = auth_url_option { + self.repository_panel.set_current_auth_url(auth_url); + self.generics_panel.finished_loading_repo(); + } + self.creation_step = CreationStep::Repository; + } + + fn to_modules_panel(&mut self, repo_option: Option<(AuthUrl, RepositorySpecification)>) { + if let Some(repo) = repo_option { + self.modules_panel.set_current_repo(repo); + } + self.creation_step = CreationStep::Modules; + } + + fn eval_intents(&mut self, intents: Vec) -> Vec { + intents + .into_iter() + .filter_map(|intent| match intent { + InternalIntent::ToGenericsPanel => { + self.creation_step = CreationStep::Generics; + None + } + InternalIntent::ToRepositoryPanel(auth_url_option) => { + if let Some(auth_url) = &auth_url_option { + if !self.repository_panel.is_auth_url_loaded(auth_url) { + return Some(MainPanelIntent::MachineCreation( + MachineCreationIntent::LoadRepository(auth_url.clone()), + )); + } + } + self.to_repository_panel(auth_url_option); + None + } + InternalIntent::ToModulesPanel(repo_option) => { + if let Some(repo) = &repo_option { + if !self.modules_panel.is_repo_loaded(repo) { + return Some(MainPanelIntent::MachineCreation( + MachineCreationIntent::LoadModules(repo.clone()), + )); + } + } + self.to_modules_panel(repo_option); + None + } + InternalIntent::CreateMachine => { + if self.modules_panel.get_current_repo().is_some() { + let temp = std::mem::take(self); + + let modules = temp.modules_panel.get_current_selected_modules(); + let (auth_url, repo_spec) = temp.modules_panel.current_repo.unwrap(); + + let use_nixpkgs = if temp.repository_panel.dont_use_nixpkgs { + Some(NixpkgsLocation::Local) + } else { + Some(NixpkgsLocation::Remote) + }; + let auth = auth_url.get_auth(); + let (branch, tag, commit) = repo_spec.to_triple(); + + let machine_name = temp.generics_panel.machine_name; + let git_url = auth_url.get_git_url().unwrap(); + let options = InputOptions { + dont_prompt: true, + no_build: temp.generics_panel.dont_build, + use_nixpkgs, + auth, + branch, + tag, + commit, + }; + let dont_run_init = temp.repository_panel.dont_run_init_script; + + Some(MainPanelIntent::MachineCreation( + MachineCreationIntent::CreateMachine( + machine_name, + git_url, + options, + modules, + dont_run_init, + ), + )) + } else { + None + } + } + }) + .collect() + } +} + +#[derive(PartialEq, Clone, EnumIter, Default)] +enum CreationStep { + #[default] + Generics, + Repository, + Modules, +} + +impl CreationStep { + fn to_text(&self) -> String { + match self { + CreationStep::Generics => "General".to_string(), + CreationStep::Repository => "Repository".to_string(), + CreationStep::Modules => "Modules".to_string(), + } + } +} + +pub enum MachineCreationIntent { + CreateMachine(String, GitUrl, InputOptions, Vec, bool), + LoadRepository(AuthUrl), + LoadModules((AuthUrl, RepositorySpecification)), +} + +enum InternalIntent { + ToGenericsPanel, + ToRepositoryPanel(Option), + ToModulesPanel(Option<(AuthUrl, RepositorySpecification)>), + CreateMachine, +} + +#[derive(Hash, PartialEq, Eq, Default, Clone)] +pub struct AuthUrl { + pub url: String, + pub username: String, + pub password: String, +} + +impl AuthUrl { + pub fn get_auth(&self) -> Option { + if !self.username.is_empty() { + Some(format!("{}:{}", &self.username, &self.password)) + } else { + None + } + } + + pub fn get_git_url(&self) -> Result { + if let Some(auth) = self.get_auth() { + let url_parts: Vec<&str> = self.url.split("://").collect(); + if url_parts.len() == 2 { + return Ok(GitUrl::parse(&format!( + "{}://{}@{}", + url_parts[0], auth, url_parts[1] + ))?); + } + } + Ok(GitUrl::parse(&self.url)?) + } + + pub fn to_string(&self) -> String { + if let Some(auth_val) = self.get_auth() { + let url_parts: Vec<&str> = self.url.split("://").collect(); + if url_parts.len() == 2 { + return format!("{}://{}@{}", url_parts[0], auth_val, url_parts[1]); + } + } + self.url.to_string() + } +} + +#[derive(EnumIter, Eq, PartialEq, Clone, Hash)] +pub enum RepositorySpecification { + Branch(String), + Tag(String), + Commit(String), +} + +impl Default for RepositorySpecification { + fn default() -> Self { + RepositorySpecification::Branch("".to_string()) + } +} + +impl RepositorySpecification { + fn to_text(&self) -> String { + match self { + RepositorySpecification::Branch(_) => "Branch".to_string(), + RepositorySpecification::Tag(_) => "Tag".to_string(), + RepositorySpecification::Commit(_) => "Commit".to_string(), + } + } + + fn to_full_text(&self) -> String { + match self { + RepositorySpecification::Branch(branch) => format!("Branch '{}'", branch), + RepositorySpecification::Tag(tag) => format!("Tag '{}'", tag), + RepositorySpecification::Commit(commit) => format!("Commit '{}'", commit), + } + } + + fn is_empty(&self) -> bool { + match self { + RepositorySpecification::Branch(branch) => branch.is_empty(), + RepositorySpecification::Tag(tag) => tag.is_empty(), + RepositorySpecification::Commit(commit) => commit.is_empty(), + } + } + + pub fn to_triple(&self) -> (Option, Option, Option) { + if self.is_empty() { + (None, None, None) + } else { + match self { + RepositorySpecification::Branch(branch) => (Some(branch.clone()), None, None), + RepositorySpecification::Tag(tag) => (None, Some(tag.clone()), None), + RepositorySpecification::Commit(commit) => (None, None, Some(commit.clone())), + } + } + } +} diff --git a/codchi/src/gui/main_panel/machine_creation/modules_panel.rs b/codchi/src/gui/main_panel/machine_creation/modules_panel.rs new file mode 100644 index 00000000..77f33306 --- /dev/null +++ b/codchi/src/gui/main_panel/machine_creation/modules_panel.rs @@ -0,0 +1,147 @@ +use super::{AuthUrl, InternalIntent, RepositorySpecification}; +use crate::cli::ModuleAttrPath; +use egui::*; +use std::collections::HashMap; + +#[derive(Default)] +pub struct ModulesPanel { + un_selected_modules: HashMap<(AuthUrl, RepositorySpecification), ModulePaths>, + + pub(super) current_repo: Option<(AuthUrl, RepositorySpecification)>, + is_current_initialized: bool, +} + +impl ModulesPanel { + pub fn update(&mut self, ui: &mut Ui) -> Vec { + self.update_panel(ui); + + self.update_buttons(ui) + } + + fn update_panel(&mut self, ui: &mut Ui) { + ui.heading("Repository Specification"); + if let Some((auth_url, repo_spec)) = &self.current_repo { + ui.label(&auth_url.url); + if !repo_spec.is_empty() { + ui.label(repo_spec.to_full_text()); + } + } + ui.separator(); + + if let Some(current_repo) = &self.current_repo { + if let Some(module_paths) = self.un_selected_modules.get_mut(current_repo) { + let num_cols = 2; + ui.columns(num_cols, |columns| { + fn add_column( + ui: &mut Ui, + text: &str, + module_path_vec: &mut Vec, + pendant_vec: &mut Vec, + ) { + ui.vertical(|ui| { + ui.strong(text); + let mut clicked_index = None; + for i in 0..module_path_vec.len() { + let module_path = &module_path_vec[i]; + let button_text = + format!("{}.{}", module_path.base, module_path.module); + if ui.button(button_text).clicked() { + clicked_index = Some(i); + } + } + if let Some(index) = clicked_index { + let unselected_module_path = module_path_vec.remove(index); + pendant_vec.push(unselected_module_path); + } + }); + } + add_column( + &mut columns[0], + "Unselected Modules", + module_paths.unselected_module_paths.as_mut(), + module_paths.selected_module_paths.as_mut(), + ); + add_column( + &mut columns[1], + "Selected Modules", + module_paths.selected_module_paths.as_mut(), + module_paths.unselected_module_paths.as_mut(), + ); + }); + } + } + } + + fn update_buttons(&mut self, ui: &mut Ui) -> Vec { + let mut intent = Vec::new(); + + ui.with_layout(Layout::bottom_up(Align::Min), |ui| { + ui.horizontal(|ui| { + if ui.button("Previous").clicked() { + if let Some((auth_url, _)) = &self.current_repo { + intent.push(InternalIntent::ToRepositoryPanel(Some(auth_url.clone()))); + } + } + ui.with_layout(Layout::right_to_left(Align::Max), |ui| { + let create_button = Button::new("Create").fill(Color32::DARK_GREEN); + if ui.add(create_button).clicked() { + intent.push(InternalIntent::CreateMachine); + } + }); + }); + }); + + intent + } + + pub fn set_current_repo(&mut self, repo: (AuthUrl, RepositorySpecification)) { + self.is_current_initialized = self.is_repo_loaded(&repo); + self.current_repo = Some(repo); + } + + pub fn is_current_repo_loaded(&self) -> bool { + self.is_current_initialized + } + + pub fn is_repo_loaded(&self, repo: &(AuthUrl, RepositorySpecification)) -> bool { + self.un_selected_modules.contains_key(repo) + } + + pub fn insert_modules( + &mut self, + repo: (AuthUrl, RepositorySpecification), + modules: Vec, + ) { + let value = ModulePaths::new(modules); + self.un_selected_modules.insert(repo, value); + self.is_current_initialized = true; + } + + pub fn get_current_selected_modules(&self) -> Vec { + if let Some(current_repo) = &self.current_repo + && let Some(module_paths) = self.un_selected_modules.get(current_repo) + { + module_paths.selected_module_paths.clone() + } else { + Vec::new() + } + } + + pub fn get_current_repo(&self) -> &Option<(AuthUrl, RepositorySpecification)> { + &self.current_repo + } +} + +struct ModulePaths { + unselected_module_paths: Vec, + selected_module_paths: Vec, +} + +impl ModulePaths { + fn new(unselected_module_paths: Vec) -> Self { + Self { + unselected_module_paths, + selected_module_paths: Vec::new(), + } + } +} diff --git a/codchi/src/gui/main_panel/machine_creation/repository_panel.rs b/codchi/src/gui/main_panel/machine_creation/repository_panel.rs new file mode 100644 index 00000000..eb1c0663 --- /dev/null +++ b/codchi/src/gui/main_panel/machine_creation/repository_panel.rs @@ -0,0 +1,153 @@ +use egui::*; +use std::collections::HashMap; +use strum::IntoEnumIterator; + +use super::{AuthUrl, InternalIntent, RepositorySpecification}; + +#[derive(Default)] +pub struct RepositoryPanel { + repo_infos: HashMap>, Option>)>, + + repo_spec: RepositorySpecification, + pub(super) dont_run_init_script: bool, + pub(super) dont_use_nixpkgs: bool, + + current_auth_url: Option, + is_current_initialized: bool, +} + +impl RepositoryPanel { + pub fn update(&mut self, ui: &mut Ui) -> Vec { + self.update_ui(ui); + + self.update_buttons(ui) + } + + pub fn update_ui(&mut self, ui: &mut Ui) { + let Self { + repo_infos, + repo_spec: repo_specification, + dont_run_init_script, + dont_use_nixpkgs, + current_auth_url, + is_current_initialized: _, + } = self; + + if let Some(auth_url) = current_auth_url { + ui.heading("Repository Specification"); + ui.label(&auth_url.url); + ui.separator(); + + ui.with_layout(Layout::left_to_right(Align::Min), |ui| { + ComboBox::from_id_salt("repo_specification_combobox") + .selected_text(repo_specification.to_text()) + .width(150.0) + .show_ui(ui, |ui| { + for repo_spec in RepositorySpecification::iter() { + let text = repo_spec.to_text(); + ui.selectable_value(repo_specification, repo_spec, text); + } + }); + + match repo_specification { + RepositorySpecification::Branch(branch_name) => { + if let Some((branches_option, _)) = repo_infos.get(auth_url) { + if let Some(branches) = branches_option { + ComboBox::from_id_salt("branch_specification_combobox") + .selected_text(branch_name.to_string()) + .width(ui.available_width()) + .show_ui(ui, |ui| { + for branch in branches { + ui.selectable_value( + branch_name, + branch.to_string(), + branch, + ); + } + }); + } + } + } + RepositorySpecification::Tag(tag_name) => { + if let Some((_, tags_option)) = repo_infos.get(auth_url) { + if let Some(tags) = tags_option { + ComboBox::from_id_salt("branch_specification_combobox") + .selected_text(tag_name.to_string()) + .width(ui.available_width()) + .show_ui(ui, |ui| { + for tag in tags { + ui.selectable_value(tag_name, tag.to_string(), tag); + } + }); + } + } + } + RepositorySpecification::Commit(commit) => { + let commit_line = TextEdit::singleline(commit).hint_text("Commit-Hash"); + ui.add_sized([ui.available_width(), 0.0], commit_line); + } + } + }); + + ui.separator(); + ui.checkbox(dont_run_init_script, "Skip Configuration's Init-Script"); + ui.checkbox(dont_use_nixpkgs, "Ignore provided package versions"); + } + } + + fn update_buttons(&mut self, ui: &mut Ui) -> Vec { + let mut intent = Vec::new(); + + ui.with_layout(Layout::bottom_up(Align::Min), |ui| { + ui.horizontal(|ui| { + if ui.button("Previous").clicked() { + intent.push(InternalIntent::ToGenericsPanel); + } + ui.with_layout(Layout::right_to_left(Align::Max), |ui| { + if ui.button("Next").clicked() { + if let Some(current_auth_url) = &self.current_auth_url { + intent.push(InternalIntent::ToModulesPanel(Some(( + current_auth_url.clone(), + self.repo_spec.clone(), + )))); + } + } + }); + }); + }); + + intent + } + + pub fn set_current_auth_url(&mut self, auth_url: AuthUrl) { + self.is_current_initialized = self.is_auth_url_loaded(&auth_url); + self.current_auth_url = Some(auth_url); + } + + pub fn insert_branches(&mut self, auth_url: AuthUrl, branches: Vec) { + let (branches_option, tags_option) = + self.repo_infos.entry(auth_url).or_insert((None, None)); + *branches_option = Some(branches); + + self.is_current_initialized = branches_option.is_some() && tags_option.is_some(); + } + + pub fn insert_tags(&mut self, auth_url: AuthUrl, tags: Vec) { + let (branches_option, tags_option) = + self.repo_infos.entry(auth_url).or_insert((None, None)); + *tags_option = Some(tags); + + self.is_current_initialized = branches_option.is_some() && tags_option.is_some(); + } + + pub fn is_current_auth_url_loaded(&self) -> bool { + self.is_current_initialized + } + + pub fn is_auth_url_loaded(&self, auth_url: &AuthUrl) -> bool { + match self.repo_infos.get(auth_url) { + Some((branches, tags)) => branches.is_some() && tags.is_some(), + None => false, + } + } +} diff --git a/codchi/src/gui/main_panel/machine_inspection.rs b/codchi/src/gui/main_panel/machine_inspection.rs new file mode 100644 index 00000000..c2b247b2 --- /dev/null +++ b/codchi/src/gui/main_panel/machine_inspection.rs @@ -0,0 +1,423 @@ +use super::{ + super::util::{status_entries::StatusEntries, textures_manager::TexturesManager}, + MainPanelIntent, +}; +use crate::{ + config::Mod, + gui::util::advanced_password_field, + logging::CodchiOutput, + platform::{platform::HostImpl, DesktopEntry, Host, Machine}, + secrets::{EnvSecret, MachineSecrets}, +}; +use anyhow::Result; +use egui::*; +use itertools::Itertools; +use std::collections::HashMap; +use std::{ + sync::mpsc::{channel, Receiver, Sender}, + thread, +}; + +pub struct MachineInspection { + machine_data_map: HashMap, + current_machine: Option, + + sender: Sender<(usize, ChannelDTO)>, + receiver: Receiver<(usize, ChannelDTO)>, +} + +enum ChannelDTO { + Machine(String, Result), + Applications(String, Result>), + Modules(String, Result>), + Secrets(String, Result>), +} + +impl MachineInspection { + pub fn update( + &mut self, + ui: &mut Ui, + status_entries: &mut StatusEntries, + textures_manager: &mut TexturesManager, + ) -> Vec { + self.receive_msgs(status_entries); + + self.update_ui(ui, status_entries, textures_manager) + .into_iter() + .map(|machine_inspection_intent| { + MainPanelIntent::MachineInspection(machine_inspection_intent) + }) + .collect_vec() + } + + pub fn reset(&mut self) { + if let Some(current_machine) = &self.current_machine { + self.machine_data_map.remove(current_machine); + } + + self.current_machine = None; + } + + fn receive_msgs(&mut self, status_entries: &mut StatusEntries) { + while let Ok((status_index, channel_dto)) = self.receiver.try_recv() { + status_entries.decrease(status_index); + + match channel_dto { + ChannelDTO::Machine(machine_name, machine_result) => match machine_result { + Ok(machine) => { + let machine_data = MachineData::create(machine.clone()); + self.machine_data_map.insert(machine_name, machine_data); + + self.load_machine_data(machine, status_entries); + } + Err(_error) => self.load_machine(machine_name, status_entries), + }, + ChannelDTO::Applications(machine_name, applications_result) => { + if let Some(machine_data_entry) = self.machine_data_map.get_mut(&machine_name) { + match applications_result { + Ok(applications) => machine_data_entry.set_applications(applications), + Err(_error) => machine_data_entry.set_applications(Vec::new()), + } + } + } + ChannelDTO::Modules(machine_name, modules_result) => { + if let Some(machine_data_entry) = self.machine_data_map.get_mut(&machine_name) { + match modules_result { + Ok(modules) => machine_data_entry.set_modules(modules), + Err(_error) => machine_data_entry.set_modules(Vec::new()), + } + } + } + ChannelDTO::Secrets(machine_name, secrets_result) => { + if let Some(machine_data_entry) = self.machine_data_map.get_mut(&machine_name) { + match secrets_result { + Ok(secrets) => machine_data_entry.set_secrets(secrets), + Err(_error) => machine_data_entry.set_secrets(Vec::new()), + } + } + } + } + } + } + + pub fn new() -> Self { + let (sender, receiver) = channel(); + Self { + machine_data_map: HashMap::new(), + current_machine: None, + + sender, + receiver, + } + } + + pub fn change(&mut self, machine: Machine, status_entries: &mut StatusEntries) { + let machine_name = machine.config.name.clone(); + + if !self.machine_data_map.contains_key(&machine_name) { + self.machine_data_map + .insert(machine_name.clone(), MachineData::create(machine)); + } + + let machine_data_option = self.machine_data_map.get_mut(&machine_name); + if machine_data_option.is_some_and(|machine_data| !machine_data.is_initialized()) { + self.load_machine(machine_name.clone(), status_entries) + } + + self.current_machine = Some(machine_name); + } + + fn load_machine(&self, machine_name: String, status_entries: &mut StatusEntries) { + let status_index = + status_entries.create_entry(format!("Loading Machine '{}'...", &machine_name)); + + let sender_clone = self.sender.clone(); + thread::spawn(move || { + let machine = Machine::by_name(&machine_name, true); + + sender_clone + .send((status_index, ChannelDTO::Machine(machine_name, machine))) + .unwrap(); + }); + } + + fn load_machine_data(&self, machine: Machine, status_entries: &mut StatusEntries) { + let status_index = + status_entries.push(format!("Loading Data for '{}'...", &machine.config.name), 3); + + let machine_clone = machine.clone(); + let sender_clone = self.sender.clone(); + thread::spawn(move || { + let applications = HostImpl::list_desktop_entries(&machine_clone); + + sender_clone + .send(( + status_index, + ChannelDTO::Applications(machine_clone.config.name, applications), + )) + .unwrap(); + }); + + let machine_name_clone = machine.config.name.clone(); + let modules_clone = machine.config.modules.clone(); + let sender_clone = self.sender.clone(); + thread::spawn(move || { + let modules = modules_clone.to_output(); + + sender_clone + .send(( + status_index, + ChannelDTO::Modules(machine_name_clone, Ok(modules)), + )) + .unwrap(); + }); + + let sender_clone = self.sender.clone(); + thread::spawn(move || { + let secrets = machine + .eval_env_secrets() + .map(|secret_map| secret_map.into_values().collect_vec().to_output()); + + sender_clone + .send(( + status_index, + ChannelDTO::Secrets(machine.config.name, secrets), + )) + .unwrap(); + }); + } + + fn update_ui( + &mut self, + ui: &mut Ui, + status_entries: &mut StatusEntries, + textures_manager: &mut TexturesManager, + ) -> Vec { + let mut intent = Vec::new(); + + let mut machine_menu_intent = self.update_machine_menu(ui, status_entries); + intent.append(&mut machine_menu_intent); + + if let Some(machine_name) = &self.current_machine { + let machine_data = &self.machine_data_map[machine_name]; + let status_text = match machine_data.machine.platform_status { + crate::platform::PlatformStatus::NotInstalled => "Not Installed", + crate::platform::PlatformStatus::Stopped => "Stopped", + crate::platform::PlatformStatus::Running => "Running", + }; + ui.label(status_text); + ui.separator(); + + ui.heading("Applications"); + ui.add_space(3.0); + if let Some(desktop_entries) = &machine_data.applications { + for desktop_entry in desktop_entries { + let app_icon = match &desktop_entry.icon { + Some(icon_path) => textures_manager + .deliver_ico(&desktop_entry.app_name, icon_path) + .map(|tex| Image::from_texture(tex).shrink_to_fit()), + None => None, + }; + let app_text = WidgetText::RichText(RichText::new(&desktop_entry.app_name)); + let app_button = Button::opt_image_and_text(app_icon, Some(app_text)); + if ui.add(app_button).clicked() { + let _ = + HostImpl::execute(&machine_data.machine.config.name, &desktop_entry); + } + } + if ui.button("Shell").clicked() { + let _ = crate::platform::Driver::host().open_terminal(&[ + &std::env::current_exe().unwrap().display().to_string(), + "exec", + &machine_data.machine.config.name, + ]); + } + } else { + ui.horizontal(|ui| { + ui.add_space(20.0); + ui.label("Loading ..."); + }); + } + ui.separator(); + + ui.heading("Modules"); + if let Some(modules) = &machine_data.modules { + if !modules.is_empty() { + Grid::new("modules_grid").show(ui, |ui| { + ui.strong("Name\t"); + ui.strong("URL\t"); + ui.strong("Path\t"); + ui.end_row(); + + for module in modules { + ui.label(format!("{}\t", module.name)); + ui.label(format!("{}\t", module.url)); + ui.label(format!("{}\t", module.flake_module)); + ui.end_row(); + } + }); + } else { + ui.horizontal(|ui| { + ui.label("No modules"); + }); + } + } else { + ui.horizontal(|ui| { + ui.add_space(20.0); + ui.label("Loading ..."); + }); + } + ui.separator(); + + ui.heading("Secrets"); + if let Some(secrets) = &machine_data.secrets { + if !secrets.is_empty() { + Grid::new("secrets_grid").show(ui, |ui| { + ui.strong("Name\t"); + ui.strong("Description\t"); + ui.strong("Value\t"); + ui.end_row(); + + for secret in secrets { + ui.label(format!("{}\t", secret.name)); + ui.label(format!("{}\t", secret.description)); + ui.add(advanced_password_field( + &format!("{}_{}", &machine_name, &secret.name), + |new_password| { + let (lock, mut cfg) = + crate::config::MachineConfig::open_existing( + machine_name, + true, + ) + .unwrap(); + cfg.secrets.insert(secret.name.clone(), new_password); + cfg.write(lock).unwrap(); + }, + &if secret.value.is_some() { + secret.value.clone().unwrap() + } else { + String::from("") + }, + )); + ui.end_row(); + } + }); + } else { + ui.horizontal(|ui| { + ui.label("No secrets"); + }); + } + } else { + ui.horizontal(|ui| { + ui.add_space(20.0); + ui.label("Loading ..."); + }); + } + } + + intent + } + + fn update_machine_menu( + &mut self, + ui: &mut Ui, + status_entries: &mut StatusEntries, + ) -> Vec { + let mut intent = Vec::new(); + + if let Some(machine_name) = &self.current_machine { + ui.horizontal(|ui| { + let title_text = format!("Machine: {}", &machine_name); + ui.add(widgets::Label::new( + RichText::from(title_text).heading().strong(), + )); + ui.with_layout(Layout::right_to_left(Align::BOTTOM), |ui| { + ui.menu_button("Actions", |ui| { + if ui.button("Rebuild").clicked() { + let machine_clone = self.machine_data_map[machine_name].machine.clone(); + intent.push(MachineInspectionIntent::Rebuild(machine_clone)); + } + + if ui.button("Duplicate").clicked() { + let machine_clone = self.machine_data_map[machine_name].machine.clone(); + intent.push(MachineInspectionIntent::Duplicate(machine_clone)); + } + + if ui.button("Export").clicked() { + let machine_clone = self.machine_data_map[machine_name].machine.clone(); + intent.push(MachineInspectionIntent::Tar(machine_clone)); + } + + if ui.button("Stop").clicked() { + let machine_clone = self.machine_data_map[machine_name].machine.clone(); + intent.push(MachineInspectionIntent::Stop(machine_clone)); + } + + let delete_button = Button::new("Delete").fill(Color32::DARK_RED); + if ui.add(delete_button).clicked() { + let machine_clone = self.machine_data_map[machine_name].machine.clone(); + intent.push(MachineInspectionIntent::Delete(machine_clone)); + } + }); + if ui.button("\u{21BA}").on_hover_text("Reload").clicked() { + self.load_machine(machine_name.clone(), status_entries); + } + }); + }); + } + + intent + } + + pub fn unselect_machine(&mut self, machine_name: &String) { + if self + .current_machine + .as_ref() + .is_some_and(|current_machine| current_machine == machine_name) + { + self.current_machine = None; + } + } +} + +struct MachineData { + machine: Machine, + applications: Option>, + modules: Option>, + secrets: Option>, +} + +impl MachineData { + fn create(machine: Machine) -> Self { + Self { + machine, + applications: None, + modules: None, + secrets: None, + } + } + + fn set_applications(&mut self, applications: Vec) { + self.applications = Some(applications); + } + + fn set_modules(&mut self, modules: Vec) { + self.modules = Some(modules); + } + + fn set_secrets(&mut self, secrets: Vec) { + self.secrets = Some(secrets); + } + + fn is_initialized(&self) -> bool { + self.applications.is_some() && self.modules.is_some() && self.secrets.is_some() + } +} + +pub enum MachineInspectionIntent { + Rebuild(Machine), + Duplicate(Machine), + Tar(Machine), + Stop(Machine), + Delete(Machine), +} diff --git a/codchi/src/gui/main_panel/mod.rs b/codchi/src/gui/main_panel/mod.rs new file mode 100644 index 00000000..1bb20408 --- /dev/null +++ b/codchi/src/gui/main_panel/mod.rs @@ -0,0 +1,99 @@ +pub mod empty_machine_creation; +pub mod machine_creation; +pub mod machine_inspection; + +use super::util::{ + dialog_manager::DialogManager, status_entries::StatusEntries, textures_manager::TexturesManager, +}; +use egui::*; +use empty_machine_creation::{EmptyMachineCreation, EmptyMachineCreationIntent}; +use machine_creation::{MachineCreation, MachineCreationIntent}; +use machine_inspection::{MachineInspection, MachineInspectionIntent}; + +pub struct MainPanel { + pub panels: MainPanels, + current_main_panel_type: MainPanelType, +} + +impl MainPanel { + pub fn new() -> Self { + Self { + panels: MainPanels::default(), + current_main_panel_type: MainPanelType::MachineInspection, + } + } + + pub fn update( + &mut self, + ui: &mut Ui, + status_entries: &mut StatusEntries, + dialog_manager: &mut DialogManager, + textures_manager: &mut TexturesManager, + ) -> Vec { + ScrollArea::both() + .id_salt("main_panel_scroll") + .auto_shrink(false) + .show(ui, |ui| match self.current_main_panel_type { + MainPanelType::MachineInspection => self.panels.get_machine_inspection().update( + ui, + status_entries, + textures_manager, + ), + MainPanelType::MachineCreation => self.panels.get_machine_creation().update(ui), + MainPanelType::EmptyMachineCreation => { + self.panels.get_empty_machine_creation().update(ui) + } + }) + .inner + } + + pub fn reset(&mut self) { + match self.current_main_panel_type { + MainPanelType::MachineInspection => self.panels.get_machine_inspection().reset(), + MainPanelType::MachineCreation => self.panels.get_machine_creation().reset(), + MainPanelType::EmptyMachineCreation => self.panels.get_empty_machine_creation().reset(), + } + + self.change(MainPanelType::MachineInspection); + } + + pub fn change(&mut self, main_panel_type: MainPanelType) { + self.current_main_panel_type = main_panel_type; + } +} + +#[derive(Default)] +pub struct MainPanels { + machine_inspection: Option, + machine_creation: Option, + empty_machine_creation: Option, +} + +impl MainPanels { + pub fn get_machine_inspection(&mut self) -> &mut MachineInspection { + self.machine_inspection + .get_or_insert(MachineInspection::new()) + } + + pub fn get_machine_creation(&mut self) -> &mut MachineCreation { + self.machine_creation + .get_or_insert(MachineCreation::default()) + } + + pub fn get_empty_machine_creation(&mut self) -> &mut EmptyMachineCreation { + self.empty_machine_creation + .get_or_insert(EmptyMachineCreation::default()) + } +} + +pub enum MainPanelType { + MachineInspection, + MachineCreation, + EmptyMachineCreation, +} + +pub enum MainPanelIntent { + MachineInspection(MachineInspectionIntent), + MachineCreation(MachineCreationIntent), + EmptyMachineCreation(EmptyMachineCreationIntent), +} diff --git a/codchi/src/gui/menubar.rs b/codchi/src/gui/menubar.rs new file mode 100644 index 00000000..47e80b8f --- /dev/null +++ b/codchi/src/gui/menubar.rs @@ -0,0 +1,194 @@ +use egui::*; + +use crate::config::CodchiConfig; + +use super::util::textures_manager::TexturesManager; + +#[derive(Debug)] +pub enum MenubarIntent { + Home, + OpenGithub, + OpenIssues, + ToggleMode, + ZoomIn, + ZoomOut, + RecoverStore, + ShowTray(bool), + EnableVcxsrv(bool), + ShowTrayVcxsrv(bool), + EnableWslVpnkit(bool), + InsertUrl(String), +} + +pub fn update(ui: &mut Ui, textures_manager: &mut TexturesManager) -> Vec { + let mut intent = Vec::new(); + + ui.horizontal_centered(|ui| { + let codchi_button = match textures_manager.deliver("logo", "assets/logo.png") { + Some(tex_handle) => { + let image = Image::new(tex_handle).max_size(vec2(48.0, 48.0)); + Button::image(image) + } + None => Button::new("Home"), + }; + if ui.add(codchi_button).on_hover_text("Home").clicked() { + intent.push(MenubarIntent::Home); + ui.close_menu(); + } + ui.separator(); + + ui.with_layout(Layout::right_to_left(Align::Center), |ui| { + let github_button = + match textures_manager.deliver_svg("github_logo", "assets/github_logo.svg") { + Some(tex_handle) => Button::image( + Image::new(tex_handle) + .tint(ui.visuals().widgets.inactive.fg_stroke.color) + .max_size(vec2(24.0, 24.0)), + ), + None => Button::new("Github"), + }; + if ui.add(github_button).on_hover_text("Github").clicked() { + intent.push(MenubarIntent::OpenGithub); + ui.close_menu(); + } + + let bug_report_button = + match textures_manager.deliver_svg("bug_icon", "assets/bug_icon.svg") { + Some(tex_handle) => Button::image( + Image::new(tex_handle) + .tint(ui.visuals().widgets.inactive.fg_stroke.color) + .max_size(vec2(24.0, 24.0)), + ), + None => Button::new("Bug-Report"), + }; + if ui + .add(bug_report_button) + .on_hover_text("Bug-Report") + .clicked() + { + intent.push(MenubarIntent::OpenIssues); + ui.close_menu(); + } + + let mut pressed_settings = update_settings_menu(ui, textures_manager); + intent.append(&mut pressed_settings); + + if let Some(url) = singleline_enter(ui, "menubar_url_inputline", "url", 400.0) { + intent.push(MenubarIntent::InsertUrl(url)); + } + }); + }); + + intent +} + +fn update_settings_menu(ui: &mut Ui, textures_manager: &mut TexturesManager) -> Vec { + let mut intent = Vec::new(); + + let menu_button = match textures_manager.deliver_svg("menu", "assets/menu_icon.svg") { + Some(tex_handle) => Button::image( + Image::new(tex_handle) + .tint(ui.visuals().widgets.inactive.fg_stroke.color) + .max_size(vec2(24.0, 24.0)), + ), + None => Button::new("Settings"), + }; + menu::menu_custom_button(ui, menu_button, |ui| { + if ui.button("Change mode").clicked() { + intent.push(MenubarIntent::ToggleMode); + } + if ui.button("Zoom In").clicked() { + intent.push(MenubarIntent::ZoomIn); + ui.close_menu(); + } + if ui.button("Zoom Out").clicked() { + intent.push(MenubarIntent::ZoomOut); + ui.close_menu(); + } + ui.separator(); + #[cfg(target_os = "windows")] + { + if ui.button("Recover store").clicked() { + intent.push(MenubarIntent::RecoverStore); + ui.close_menu(); + } + ui.separator(); + } + + if let Some(checked) = checkbox_clicked( + ui, + "codchi_tray_checkbox", + CodchiConfig::get().tray.autostart, + "Show tray icon", + ) { + intent.push(MenubarIntent::ShowTray(checked)); + } + + #[cfg(target_os = "windows")] + { + ui.menu_button("VcXsrv", |ui| { + if let Some(checked) = checkbox_clicked( + ui, + "vcxsrv_enable_checkbox", + CodchiConfig::get().vcxsrv.enable, + "Enable", + ) { + intent.push(MenubarIntent::EnableVcxsrv(checked)); + } + + if let Some(checked) = checkbox_clicked( + ui, + "vcxsrv_tray_checkbox", + CodchiConfig::get().vcxsrv.tray, + "Show tray icon", + ) { + intent.push(MenubarIntent::ShowTrayVcxsrv(checked)); + } + }); + if let Some(checked) = checkbox_clicked( + ui, + "wsl_vpnkit_enable_checkbox", + CodchiConfig::get().enable_wsl_vpnkit, + "Enable wsl-vpnkit", + ) { + intent.push(MenubarIntent::EnableWslVpnkit(checked)); + } + } + }) + .response + .on_hover_text("Setting"); + + intent +} + +pub fn checkbox_clicked(ui: &mut Ui, id: &str, initial: bool, text: &str) -> Option { + let state_id = ui.id().with(id); + let mut checked = ui.data_mut(|d| d.get_temp::(state_id).unwrap_or(initial)); + + let response = ui.checkbox(&mut checked, text); + ui.data_mut(|d| d.insert_temp(state_id, checked)); + + if response.clicked() { + Some(checked) + } else { + None + } +} + +pub fn singleline_enter(ui: &mut Ui, id: &str, hint_text: &str, width: f32) -> Option { + let state_id = ui.id().with(id); + let mut edit_text = ui.data_mut(|d| d.get_temp::(state_id).unwrap_or("".to_string())); + + let single_line = TextEdit::singleline(&mut edit_text) + .hint_text(hint_text) + .min_size(Vec2 { x: width, y: 0.0 }); + let response = ui.add(single_line); + + if response.lost_focus() && response.ctx.input(|i| i.key_pressed(Key::Enter)) { + ui.data_mut(|d| d.insert_temp(state_id, "".to_string())); + Some(edit_text) + } else { + ui.data_mut(|d| d.insert_temp(state_id, edit_text)); + None + } +} diff --git a/codchi/src/gui/mod.rs b/codchi/src/gui/mod.rs new file mode 100644 index 00000000..ee2b5f89 --- /dev/null +++ b/codchi/src/gui/mod.rs @@ -0,0 +1,458 @@ +mod main_panel; +mod menubar; +mod side_panel; +mod util; + +use anyhow::Result; +use egui::*; +use main_panel::{ + empty_machine_creation::EmptyMachineCreationIntent, machine_creation::MachineCreationIntent, + machine_inspection::MachineInspectionIntent, MainPanel, MainPanelIntent, MainPanelType, +}; +use menubar::MenubarIntent; +use side_panel::{GuiSidePanel, SidePanelIntent}; +use std::path::PathBuf; +use util::{ + backend_broker::{BackendBroker, BackendIntent}, + dialog_manager::{DialogIntent, DialogManager}, + status_entries::StatusEntries, + textures_manager::TexturesManager, +}; + +use crate::config::CodchiConfig; + +struct Gui { + side_panel: GuiSidePanel, + main_panel: MainPanel, + + status_entries: StatusEntries, + dialog_manager: DialogManager, + textures_manager: TexturesManager, + + backend_broker: BackendBroker, +} + +impl eframe::App for Gui { + fn update(&mut self, ctx: &Context, _frame: &mut eframe::Frame) { + self.update_ui(ctx); + } +} + +impl Gui { + fn new() -> Self { + Self { + side_panel: GuiSidePanel::new(), + main_panel: MainPanel::new(), + + status_entries: StatusEntries::new(), + dialog_manager: DialogManager::new(), + textures_manager: TexturesManager::new(), + + backend_broker: BackendBroker::new(), + } + } + + fn update_ui(&mut self, ctx: &Context) { + self.update_menubar(ctx); + self.update_status_bar(ctx); + + self.update_side_panel(ctx); + + self.update_main_panel(ctx); + + self.update_modals(ctx); + self.update_textures(ctx); + + self.update_backend_broker(); + } + + fn update_status_bar(&self, ctx: &Context) { + TopBottomPanel::bottom("status_bar_panel") + .exact_height(25.0) + .resizable(false) + .show(ctx, |ui| { + ui.horizontal(|ui| { + let mut is_first_status = true; + for status in self.status_entries.get_status() { + if is_first_status { + is_first_status = false; + ui.add(egui::Spinner::new()); + } else { + ui.separator(); + } + ui.label(status); + } + }); + }); + } + + fn update_menubar(&mut self, ctx: &Context) { + TopBottomPanel::top("menubar_panel") + .resizable(false) + .show(ctx, |ui| { + let intents = menubar::update(ui, &mut self.textures_manager); + for intent in intents { + self.eval_menubar_intent(ctx, intent); + } + }); + } + + fn update_side_panel(&mut self, ctx: &Context) { + SidePanel::left("side_panel") + .exact_width(200.0) + .resizable(false) + .show(ctx, |ui| { + ScrollArea::vertical().auto_shrink(false).show(ui, |ui| { + let intents = self.side_panel.update( + ui, + &mut self.status_entries, + &self.textures_manager, + ); + for intent in intents { + self.eval_side_panel_intent(intent); + } + }); + }); + } + + fn update_main_panel(&mut self, ctx: &Context) { + CentralPanel::default().show(ctx, |ui| { + ui.with_layout(Layout::right_to_left(Align::Min), |ui| { + ui.separator(); + ui.vertical(|ui| { + let intents = self.main_panel.update( + ui, + &mut self.status_entries, + &mut self.dialog_manager, + &mut self.textures_manager, + ); + + for intent in intents { + self.eval_main_panel_intent(intent); + } + }) + }) + }); + } + + fn update_modals(&mut self, ctx: &Context) { + let intent_option = self.dialog_manager.update(ctx); + if let Some(intent) = intent_option { + self.eval_modals_intent(intent); + } + } + + fn update_textures(&mut self, ctx: &Context) { + self.textures_manager.update(ctx); + } + + fn update_backend_broker(&mut self) { + let intents = self + .backend_broker + .update(&mut self.status_entries, &mut self.dialog_manager); + for intent in intents { + self.eval_backend_intent(intent); + } + } + + fn eval_menubar_intent(&mut self, ctx: &Context, menubar_intent: MenubarIntent) { + match menubar_intent { + MenubarIntent::Home => self.main_panel.reset(), + MenubarIntent::OpenGithub => { + ctx.open_url(OpenUrl::new_tab("https://github.com/aformatik/codchi/")) + } + MenubarIntent::OpenIssues => ctx.open_url(OpenUrl::new_tab( + "https://github.com/aformatik/codchi/issues", + )), + MenubarIntent::ToggleMode => { + if ctx.style().visuals.dark_mode { + ctx.set_visuals(light_visuals()); + } else { + ctx.set_visuals(dark_visuals()); + } + } + MenubarIntent::ZoomIn => gui_zoom::zoom_in(ctx), + MenubarIntent::ZoomOut => gui_zoom::zoom_out(ctx), + MenubarIntent::RecoverStore => { + self.backend_broker.recover_store(&mut self.status_entries) + } + MenubarIntent::ShowTray(val) => { + let mut doc = CodchiConfig::open_mut().expect("Failed to open config"); + doc.tray_autostart(val); + doc.write().expect("Failed to write config"); + } + MenubarIntent::EnableVcxsrv(val) => { + let mut doc = CodchiConfig::open_mut().expect("Failed to open config"); + doc.vcxsrv_enable(val); + doc.write().expect("Failed to write config"); + } + MenubarIntent::ShowTrayVcxsrv(val) => { + let mut doc = CodchiConfig::open_mut().expect("Failed to open config"); + doc.vcxsrv_tray(val); + doc.write().expect("Failed to write config"); + } + MenubarIntent::EnableWslVpnkit(val) => { + let mut doc = CodchiConfig::open_mut().expect("Failed to open config"); + doc.enable_wsl_vpnkit(val); + doc.write().expect("Failed to write config"); + } + MenubarIntent::InsertUrl(url) => { + self.main_panel.panels.get_machine_creation().pass_url(url); + self.main_panel.change(MainPanelType::MachineCreation); + } + } + } + + fn eval_side_panel_intent(&mut self, side_panel_intent: SidePanelIntent) { + match side_panel_intent { + SidePanelIntent::DisplayMachine(machine) => { + self.main_panel + .panels + .get_machine_inspection() + .change(machine, &mut self.status_entries); + self.main_panel.change(MainPanelType::MachineInspection) + } + SidePanelIntent::BeginMachineCreation => { + self.main_panel.change(MainPanelType::MachineCreation) + } + SidePanelIntent::BeginEmptyMachineCreation => { + self.main_panel.change(MainPanelType::EmptyMachineCreation) + } + } + } + + fn eval_modals_intent(&mut self, dialog_intent: DialogIntent) { + match dialog_intent { + util::dialog_manager::DialogIntent::Rebuild { + machine, + update_modules, + } => self.backend_broker.rebuild_machine( + machine, + update_modules, + false, + &mut self.status_entries, + ), + util::dialog_manager::DialogIntent::Duplicate { + machine, + duplicate_name, + } => self.backend_broker.duplicate_machine( + machine, + duplicate_name, + &mut self.status_entries, + ), + util::dialog_manager::DialogIntent::Tar { machine, file_path } => self + .backend_broker + .tar_machine(machine, file_path, &mut self.status_entries), + util::dialog_manager::DialogIntent::Stop { machine } => self + .backend_broker + .stop_machine(machine, &mut self.status_entries), + util::dialog_manager::DialogIntent::Delete { machine, confirm } => { + if confirm { + self.backend_broker + .delete_machine(machine, &mut self.status_entries); + } + } + util::dialog_manager::DialogIntent::Secret { + machine_name, + name, + value, + } => self.backend_broker.insert_secret( + machine_name, + name, + value, + &mut self.status_entries, + ), + } + } + + fn eval_main_panel_intent(&mut self, main_panel_intent: MainPanelIntent) { + match main_panel_intent { + MainPanelIntent::MachineInspection(intent) => { + self.eval_machine_inspection_intent(intent) + } + MainPanelIntent::MachineCreation(intent) => self.eval_machine_creation_intent(intent), + MainPanelIntent::EmptyMachineCreation(intent) => { + self.eval_empty_machine_creation_intent(intent) + } + } + } + + fn eval_machine_inspection_intent( + &mut self, + machine_inspection_intent: MachineInspectionIntent, + ) { + match machine_inspection_intent { + MachineInspectionIntent::Rebuild(machine) => { + self.dialog_manager.queue_generic(DialogIntent::Rebuild { + machine, + update_modules: true, + }); + } + MachineInspectionIntent::Duplicate(machine) => { + self.dialog_manager.queue_generic(DialogIntent::Duplicate { + machine, + duplicate_name: "".to_string(), + }); + } + MachineInspectionIntent::Tar(machine) => { + self.dialog_manager.queue_generic(DialogIntent::Tar { + machine, + file_path: PathBuf::default(), + }); + } + MachineInspectionIntent::Stop(machine) => { + self.dialog_manager + .queue_generic(DialogIntent::Stop { machine }); + } + MachineInspectionIntent::Delete(machine) => { + self.dialog_manager.queue_generic(DialogIntent::Delete { + machine, + confirm: false, + }); + } + } + } + + fn eval_machine_creation_intent(&mut self, machine_creation_intent: MachineCreationIntent) { + match machine_creation_intent { + MachineCreationIntent::CreateMachine( + machine_name, + git_url, + options, + modules, + dont_run_init, + ) => { + self.backend_broker.create_machine( + machine_name, + git_url, + options, + modules, + dont_run_init, + &mut self.status_entries, + ); + } + MachineCreationIntent::LoadRepository(auth_url) => { + if self + .main_panel + .panels + .get_machine_creation() + .is_auth_url_loaded(&auth_url) + { + self.main_panel + .panels + .get_machine_creation() + .to_repository_panel(Some(auth_url)); + } else { + self.backend_broker + .access_repository(auth_url, &mut self.status_entries) + } + } + MachineCreationIntent::LoadModules(repo) => { + self.backend_broker + .load_modules(repo, &mut self.status_entries); + } + } + } + + fn eval_empty_machine_creation_intent( + &mut self, + empty_machine_creation_intent: EmptyMachineCreationIntent, + ) { + match empty_machine_creation_intent { + EmptyMachineCreationIntent::CreateMachine(machine_name, dont_build) => { + self.backend_broker.create_empty_machine( + machine_name, + dont_build, + &mut self.status_entries, + ); + } + } + } + + fn eval_backend_intent(&mut self, backend_intent: BackendIntent) { + match backend_intent { + BackendIntent::DuplicatedMachine(machine_name) => { + self.side_panel + .add_machine(machine_name, &mut self.status_entries); + } + BackendIntent::DeletedMachine(machine_name) => { + self.side_panel.remove_machine(&machine_name); + self.main_panel + .panels + .get_machine_inspection() + .unselect_machine(&machine_name); + } + BackendIntent::AccessedRepository(auth_url, result) => { + if result.is_ok() { + self.backend_broker + .load_repository(auth_url, &mut self.status_entries); + } else { + self.main_panel + .panels + .get_machine_creation() + .repo_is_inaccessible(); + } + } + BackendIntent::LoadedBranches(auth_url, branches_result) => { + if let Ok(branches) = branches_result { + self.main_panel + .panels + .get_machine_creation() + .pass_branches(auth_url, branches); + } + } + BackendIntent::LoadedTags(auth_url, tags_result) => { + if let Ok(tags) = tags_result { + self.main_panel + .panels + .get_machine_creation() + .pass_tags(auth_url, tags); + } + } + BackendIntent::LoadedModules(repo, modules_result) => { + if let Ok(modules) = modules_result { + self.main_panel + .panels + .get_machine_creation() + .pass_modules(repo, modules); + } + } + } + } +} + +pub fn run() -> Result<()> { + let options = eframe::NativeOptions { + viewport: ViewportBuilder::default().with_inner_size((1280.0, 720.0)), + ..Default::default() + }; + eframe::run_native( + "Codchi", + options, + Box::new(|cc| { + // set custom theme + cc.egui_ctx.set_visuals(dark_visuals()); + + // This gives us image support: + egui_extras::install_image_loaders(&cc.egui_ctx); + + // Zoom in a bit initially + let ppp = cc.egui_ctx.pixels_per_point(); + cc.egui_ctx.set_pixels_per_point(1.25 * ppp); + + Ok(Box::::new(Gui::new())) + }), + ) + .unwrap(); + Ok(()) +} + +pub fn light_visuals() -> Visuals { + let visuals = Visuals::light(); + visuals +} + +pub fn dark_visuals() -> Visuals { + let visuals = Visuals::dark(); + visuals +} diff --git a/codchi/src/gui/side_panel.rs b/codchi/src/gui/side_panel.rs new file mode 100644 index 00000000..8d02a14c --- /dev/null +++ b/codchi/src/gui/side_panel.rs @@ -0,0 +1,188 @@ +use std::{ + collections::{HashMap, VecDeque}, + sync::mpsc::{channel, Receiver, Sender}, + thread, +}; + +use egui::*; +use std::time::Instant; + +use crate::platform::{Machine, PlatformStatus}; + +use super::util::{status_entries::StatusEntries, textures_manager::TexturesManager}; + +pub struct GuiSidePanel { + machine_button_names: Vec, + machine_load_names: VecDeque, + machines: HashMap, + + last_reload: Instant, + reloading_machine_name: Option, + + sender: Sender<(usize, Option)>, + receiver: Receiver<(usize, Option)>, + + initialized: bool, +} + +impl GuiSidePanel { + pub fn new() -> Self { + let (sender, receiver) = channel(); + Self { + machine_button_names: Vec::new(), + machine_load_names: VecDeque::new(), + machines: HashMap::new(), + + last_reload: Instant::now(), + reloading_machine_name: None, + + sender, + receiver, + + initialized: false, + } + } + + pub fn update( + &mut self, + ui: &mut Ui, + status_entries: &mut StatusEntries, + textures_manager: &TexturesManager, + ) -> Vec { + if self.reloading_machine_name.is_none() { + let now = Instant::now(); + if !self.initialized || now.duration_since(self.last_reload).as_secs() >= 10 { + self.initialized = true; + self.refresh_machine_list(); + self.reload_machine_from_list(status_entries); + } + } + + self.handle_received_msgs(status_entries); + + self.update_ui(ui, textures_manager) + } + + fn update_ui(&self, ui: &mut Ui, textures_manager: &TexturesManager) -> Vec { + let mut intent = Vec::new(); + + ScrollArea::vertical().auto_shrink(false).show(ui, |ui| { + ui.vertical_centered_justified(|ui| { + ui.menu_button(RichText::new("New").heading(), |ui| { + if ui.button("Standard").clicked() { + intent.push(SidePanelIntent::BeginMachineCreation); + ui.close_menu(); + } + if ui.button("Empty").clicked() { + intent.push(SidePanelIntent::BeginEmptyMachineCreation); + ui.close_menu(); + } + }); + }); + ui.separator(); + + ui.horizontal_top(|ui| { + ui.separator(); + ui.with_layout(Layout::top_down_justified(Align::LEFT), |ui| { + for machine_button_name in &self.machine_button_names { + if let Some(machine) = self.machines.get(machine_button_name) { + let icon_option = if self + .reloading_machine_name + .as_ref() + .is_some_and(|machine_name| &machine.config.name == machine_name) + { + None + } else { + match machine.platform_status { + PlatformStatus::NotInstalled => { + textures_manager.get_image("dark_red") + } + PlatformStatus::Stopped => textures_manager.get_image("red"), + PlatformStatus::Running => textures_manager.get_image("green"), + } + }; + let button_text = RichText::new(&machine.config.name).strong(); + let machine_button = Button::opt_image_and_text( + icon_option, + Some(WidgetText::RichText(button_text)), + ); + let button_handle = ui.add(machine_button); + if button_handle.clicked() { + intent.push(SidePanelIntent::DisplayMachine(machine.clone())); + } + } + } + }) + }); + }); + + intent + } + + fn refresh_machine_list(&mut self) { + if let Ok(machine_list) = Machine::list(false) { + self.machine_load_names = machine_list + .iter() + .map(|machine| machine.config.name.clone()) + .collect(); + + self.machine_button_names + .retain(|name| self.machine_load_names.contains(name)); + } + } + + fn reload_machine_from_list(&mut self, status_entries: &mut StatusEntries) { + self.reloading_machine_name = self.machine_load_names.pop_front(); + + if let Some(machine_name) = &self.reloading_machine_name { + let status_index = status_entries + .create_entry(format!("Updating status for machine '{}'", machine_name)); + + let machine_name_clone = machine_name.clone(); + let sender_clone = self.sender.clone(); + thread::spawn(move || { + let machine_result = Machine::by_name(&machine_name_clone, true); + + sender_clone + .send((status_index, machine_result.ok())) + .unwrap(); + }); + } else { + self.last_reload = Instant::now(); + } + } + + fn handle_received_msgs(&mut self, status_entries: &mut StatusEntries) { + while let Ok((status_index, machine_option)) = self.receiver.try_recv() { + status_entries.decrease(status_index); + + if let Some(machine) = machine_option { + let machine_name = machine.config.name.clone(); + self.machines.insert(machine_name.clone(), machine); + + if let Err(pos) = self.machine_button_names.binary_search(&machine_name) { + self.machine_button_names.insert(pos, machine_name); + } + + self.reload_machine_from_list(status_entries); + } + } + } + + pub fn add_machine(&mut self, machine_name: String, status_entries: &mut StatusEntries) { + self.machine_load_names.push_front(machine_name); + self.reload_machine_from_list(status_entries); + } + + pub fn remove_machine(&mut self, machine_name: &String) { + self.machine_load_names.retain(|name| name != machine_name); + self.machine_button_names + .retain(|name| name != machine_name); + } +} + +pub enum SidePanelIntent { + DisplayMachine(Machine), + BeginMachineCreation, + BeginEmptyMachineCreation, +} diff --git a/codchi/src/gui/util/backend_broker.rs b/codchi/src/gui/util/backend_broker.rs new file mode 100644 index 00000000..c5746059 --- /dev/null +++ b/codchi/src/gui/util/backend_broker.rs @@ -0,0 +1,549 @@ +use super::{ + dialog_manager::{DialogIntent, DialogManager}, + status_entries::StatusEntries, +}; +use crate::{ + cli::{InputOptions, ModuleAttrPath}, + config::MachineConfig, + gui::main_panel::machine_creation::{AuthUrl, RepositorySpecification}, + module, + platform::{Machine, MachineDriver, NixDriver, Store}, + secrets::{EnvSecret, MachineSecrets}, + util::LinuxPath, +}; +use anyhow::Result; +use git_url_parse::GitUrl; +use std::{ + collections::HashMap, + path::PathBuf, + process::Command, + sync::mpsc::{channel, Receiver, Sender}, + thread, +}; + +pub struct BackendBroker { + unresolved_machines: HashMap>)>, + + sender: Sender<(usize, ChannelDTO)>, + receiver: Receiver<(usize, ChannelDTO)>, +} + +enum ChannelDTO { + CreatedMachine(Machine, bool, bool), + + BuiltMachine(Machine, bool), + DuplicatedMachine(String), + DeletedMachine(String), + + RepositoryAccessed(AuthUrl, Result<()>), + BranchesLoaded(AuthUrl, Result>), + TagsLoaded(AuthUrl, Result>), + ModulesLoaded( + (AuthUrl, RepositorySpecification), + Result>, + ), + + FoundUnsetSecrets(Machine, Vec, bool), + WroteSecrets(Machine, bool), + InstalledMachine(Machine, bool), + + Default, +} + +pub enum BackendIntent { + DuplicatedMachine(String), + DeletedMachine(String), + AccessedRepository(AuthUrl, Result<()>), + LoadedBranches(AuthUrl, Result>), + LoadedTags(AuthUrl, Result>), + LoadedModules( + (AuthUrl, RepositorySpecification), + Result>, + ), +} + +impl BackendBroker { + pub fn new() -> Self { + let (sender, receiver) = channel(); + Self { + unresolved_machines: HashMap::new(), + + sender, + receiver, + } + } + + pub fn update( + &mut self, + status_entries: &mut StatusEntries, + dialog_manager: &mut DialogManager, + ) -> Vec { + self.receive_msgs(status_entries, dialog_manager) + } + + fn receive_msgs( + &mut self, + status_entries: &mut StatusEntries, + dialog_manager: &mut DialogManager, + ) -> Vec { + let mut intent = Vec::new(); + + while let Ok((status_index, dto)) = self.receiver.try_recv() { + status_entries.decrease(status_index); + + match dto { + ChannelDTO::CreatedMachine(machine, dont_build, dont_run_init) => { + if !dont_build { + self.rebuild_machine(machine, true, dont_run_init, status_entries); + } + } + ChannelDTO::BuiltMachine(machine, dont_run_init) => { + self.get_unset_secrets(machine, dont_run_init, status_entries); + } + ChannelDTO::DuplicatedMachine(duplicate_name) => { + intent.push(BackendIntent::DuplicatedMachine(duplicate_name)); + } + ChannelDTO::DeletedMachine(machine_name) => { + intent.push(BackendIntent::DeletedMachine(machine_name)); + } + ChannelDTO::RepositoryAccessed(auth_url, result) => { + intent.push(BackendIntent::AccessedRepository(auth_url, result)); + } + ChannelDTO::BranchesLoaded(auth_url, branches) => { + intent.push(BackendIntent::LoadedBranches(auth_url, branches)); + } + ChannelDTO::TagsLoaded(auth_url, tags) => { + intent.push(BackendIntent::LoadedTags(auth_url, tags)); + } + ChannelDTO::ModulesLoaded(repo, modules) => { + intent.push(BackendIntent::LoadedModules(repo, modules)); + } + ChannelDTO::FoundUnsetSecrets(machine, unsets, dont_run_init) => { + for secret in &unsets { + dialog_manager.queue_generic(DialogIntent::Secret { + machine_name: machine.config.name.clone(), + name: secret.name.clone(), + value: "".to_string(), + }) + } + let unsets_map = unsets + .into_iter() + .map(|secret| (secret.name, None)) + .collect(); + self.unresolved_machines.insert( + machine.config.name.clone(), + (machine, dont_run_init, unsets_map), + ); + } + ChannelDTO::WroteSecrets(machine, dont_run_init) => { + self.install_machine(machine, dont_run_init, status_entries); + } + ChannelDTO::InstalledMachine(machine, dont_run_init) => { + if !dont_run_init { + self.run_init_script(machine, dont_run_init, status_entries); + } + } + ChannelDTO::Default => {} + } + } + + intent + } + + pub fn create_empty_machine( + &mut self, + machine_name: String, + dont_build: bool, + status_entries: &mut StatusEntries, + ) { + let status_index = + status_entries.create_entry(format!("Creating empty machine '{}'", &machine_name)); + + let sender_clone = self.sender.clone(); + thread::spawn(move || { + let dto = match module::init(&machine_name, None, &InputOptions::default(), &Vec::new()) + { + Ok(machine) => ChannelDTO::CreatedMachine(machine, dont_build, false), + Err(_) => ChannelDTO::Default, + }; + sender_clone.send((status_index, dto)).unwrap(); + }); + } + + pub fn create_machine( + &mut self, + machine_name: String, + git_url: GitUrl, + options: InputOptions, + modules: Vec, + dont_run_init: bool, + status_entries: &mut StatusEntries, + ) { + let status_index = + status_entries.create_entry(format!("Creating machine '{}'", &machine_name)); + + let sender_clone = self.sender.clone(); + thread::spawn(move || { + let dto = match module::init(&machine_name, Some(git_url), &options, &modules) { + Ok(machine) => ChannelDTO::CreatedMachine(machine, options.no_build, dont_run_init), + Err(_) => ChannelDTO::Default, + }; + sender_clone.send((status_index, dto)).unwrap(); + }); + } + + pub fn rebuild_machine( + &mut self, + mut machine: Machine, + update_modules: bool, + dont_run_init: bool, + status_entries: &mut StatusEntries, + ) { + let status_index = + status_entries.create_entry(format!("Building Machine '{}'", machine.config.name)); + + let sender_clone = self.sender.clone(); + thread::spawn(move || { + let dto = if machine.build(!update_modules).is_ok() { + ChannelDTO::BuiltMachine(machine, dont_run_init) + } else { + ChannelDTO::Default + }; + sender_clone.send((status_index, dto)).unwrap(); + }); + } + + pub fn duplicate_machine( + &mut self, + machine: Machine, + duplicate_name: String, + status_entries: &mut StatusEntries, + ) { + let status_index = + status_entries.create_entry(format!("Duplicating Machine '{}'", machine.config.name)); + + let sender_clone = self.sender.clone(); + thread::spawn(move || { + let dto = if machine.duplicate(&duplicate_name).is_ok() { + ChannelDTO::DuplicatedMachine(duplicate_name) + } else { + ChannelDTO::Default + }; + sender_clone.send((status_index, dto)).unwrap(); + }); + } + + pub fn tar_machine( + &mut self, + machine: Machine, + export_path: PathBuf, + status_entries: &mut StatusEntries, + ) { + let status_index = + status_entries.create_entry(format!("Exporting Machine '{}'", machine.config.name)); + + let sender_clone = self.sender.clone(); + thread::spawn(move || { + machine.tar(&export_path).unwrap(); + sender_clone + .send((status_index, ChannelDTO::Default)) + .unwrap(); + }); + } + + pub fn stop_machine(&mut self, machine: Machine, status_entries: &mut StatusEntries) { + let status_index = + status_entries.create_entry(format!("Stopping Machine '{}'", machine.config.name)); + + let sender_clone = self.sender.clone(); + thread::spawn(move || { + machine.stop(false).unwrap(); + sender_clone + .send((status_index, ChannelDTO::Default)) + .unwrap(); + }); + } + + pub fn delete_machine(&mut self, machine: Machine, status_entries: &mut StatusEntries) { + let status_index = + status_entries.create_entry(format!("Deleting Machine '{}'", machine.config.name)); + + let sender_clone = self.sender.clone(); + thread::spawn(move || { + let machine_name = machine.config.name.clone(); + let dto = if machine.delete(true).is_ok() { + ChannelDTO::DeletedMachine(machine_name) + } else { + ChannelDTO::Default + }; + sender_clone.send((status_index, dto)).unwrap(); + }); + } + + pub fn access_repository(&mut self, auth_url: AuthUrl, status_entries: &mut StatusEntries) { + let status_index = + status_entries.create_entry(format!("Accessing Repository {}", auth_url.url)); + + let sender_clone = self.sender.clone(); + thread::spawn(move || { + let dto = match access_repo(&auth_url) { + Ok(_) => ChannelDTO::RepositoryAccessed(auth_url, Ok(())), + Err(err) => ChannelDTO::RepositoryAccessed(auth_url, Err(err)), + }; + sender_clone.send((status_index, dto)).unwrap(); + }); + } + + pub fn load_repository(&mut self, auth_url: AuthUrl, status_entries: &mut StatusEntries) { + let status_index = status_entries.push(format!("Loading Repository {}", auth_url.url), 2); + + let sender_clone = self.sender.clone(); + let auth_url_clone = auth_url.clone(); + thread::spawn(move || { + let branches_result = load_branches(&auth_url_clone); + let dto = ChannelDTO::BranchesLoaded(auth_url_clone, branches_result); + sender_clone.send((status_index, dto)).unwrap(); + }); + + let sender_clone = self.sender.clone(); + thread::spawn(move || { + let tags_result = load_tags(&auth_url); + let dto = ChannelDTO::TagsLoaded(auth_url, tags_result); + sender_clone.send((status_index, dto)).unwrap(); + }); + } + + pub fn load_modules( + &mut self, + repo: (AuthUrl, RepositorySpecification), + status_entries: &mut StatusEntries, + ) { + let status_index = + status_entries.create_entry(format!("Loading Modules for {}", repo.0.url)); + + let sender_clone = self.sender.clone(); + thread::spawn(move || { + let modules_result = load_modules(&repo); + + let dto = ChannelDTO::ModulesLoaded(repo, modules_result); + sender_clone.send((status_index, dto)).unwrap(); + }); + } + + fn get_unset_secrets( + &mut self, + machine: Machine, + dont_run_init: bool, + status_entries: &mut StatusEntries, + ) { + let status_index = status_entries.create_entry(format!( + "Getting unset secrets of '{}'", + &machine.config.name + )); + + let sender_clone = self.sender.clone(); + thread::spawn(move || { + let unset_secrets_result = get_unset_secrets_for(&machine); + let dto = match unset_secrets_result { + Ok(unsets) => { + if unsets.is_empty() { + ChannelDTO::WroteSecrets(machine, dont_run_init) + } else { + ChannelDTO::FoundUnsetSecrets(machine, unsets, dont_run_init) + } + } + Err(_) => ChannelDTO::Default, + }; + sender_clone.send((status_index, dto)).unwrap(); + }); + } + + fn install_machine( + &mut self, + mut machine: Machine, + dont_run_init: bool, + status_entries: &mut StatusEntries, + ) { + let status_index = + status_entries.create_entry(format!("Installing machine '{}'", &machine.config.name)); + + let sender_clone = self.sender.clone(); + thread::spawn(move || { + let install_result = machine.build_install(); + let dto = match install_result { + Ok(_) => ChannelDTO::InstalledMachine(machine, dont_run_init), + Err(_) => ChannelDTO::Default, + }; + sender_clone.send((status_index, dto)).unwrap(); + }); + } + + fn run_init_script( + &mut self, + machine: Machine, + dont_run_init: bool, + status_entries: &mut StatusEntries, + ) { + let status_index = status_entries.create_entry(format!( + "Running Init-Script for '{}'", + &machine.config.name + )); + + let sender_clone = self.sender.clone(); + thread::spawn(move || { + let _ = machine.run_init_script(dont_run_init); + let dto = ChannelDTO::Default; + sender_clone.send((status_index, dto)).unwrap(); + }); + } + + pub fn insert_secret( + &mut self, + machine_name: String, + secret_name: String, + value: String, + status_entries: &mut StatusEntries, + ) { + if let Some((_, _, unset_secrets)) = self.unresolved_machines.get_mut(&machine_name) { + unset_secrets.insert(secret_name, Some(value)); + + if unset_secrets.values().all(|secret| secret.is_some()) { + if let Some(entry) = self.unresolved_machines.remove(&machine_name) { + self.write_unset_secrets(entry, status_entries); + } + } + } + } + + fn write_unset_secrets( + &mut self, + entry: (Machine, bool, HashMap>), + status_entries: &mut StatusEntries, + ) { + let (mut machine, dont_run_init, unset_secrets) = entry; + let status_index = + status_entries.create_entry(format!("Writing Secrets for '{}'", &machine.config.name)); + + let sender_clone = self.sender.clone(); + thread::spawn(move || { + let dto = match write_secrets(&mut machine, unset_secrets) { + Ok(_) => ChannelDTO::WroteSecrets(machine, dont_run_init), + Err(_) => ChannelDTO::Default, + }; + sender_clone.send((status_index, dto)).unwrap(); + }); + } + + pub fn recover_store(&mut self, status_entries: &mut StatusEntries) { + let index = status_entries.create_entry(String::from("Recovering Codchi store...")); + + let sender_clone = self.sender.clone(); + thread::spawn(move || { + let _ = crate::platform::platform::store_recover(); + sender_clone.send((index, ChannelDTO::Default)).unwrap(); + }); + } +} + +fn access_repo(auth_url: &AuthUrl) -> Result> { + let opts = InputOptions { + dont_prompt: true, + no_build: true, + use_nixpkgs: None, + auth: auth_url.get_auth().or(Some(String::from(":"))), + branch: None, + tag: None, + commit: None, + }; + let git_url = auth_url.get_git_url()?; + let flake_url = crate::module::inquire_module_url(&opts, &git_url, false)?; + let dummy_path = LinuxPath(String::from("")); + let nix_url = flake_url.to_nix_url(dummy_path); + + let modules = crate::platform::Driver::store() + .cmd() + .list_nixos_modules(&nix_url)?; + + Ok(modules) +} + +fn load_branches(auth_url: &AuthUrl) -> Result> { + let output = Command::new("git") + .args(["ls-remote", "--heads", &auth_url.to_string()]) + .output()?; + + let branches = String::from_utf8_lossy(&output.stdout) + .to_string() + .lines() + .filter_map(|line| line.split('\t').nth(1)) + .filter_map(|ref_name| ref_name.strip_prefix("refs/heads/")) + .map(String::from) + .collect(); + + Ok(branches) +} + +fn load_tags(auth_url: &AuthUrl) -> Result> { + let output = Command::new("git") + .args(["ls-remote", "--tags", &auth_url.to_string()]) + .output()?; + + let tags = String::from_utf8_lossy(&output.stdout) + .to_string() + .lines() + .filter_map(|line| line.split('\t').nth(1)) + .filter_map(|ref_name| ref_name.strip_prefix("refs/tags/")) + .map(String::from) + .collect(); + + Ok(tags) +} + +fn load_modules(repo: &(AuthUrl, RepositorySpecification)) -> Result> { + let (auth_url, repo_spec) = repo; + + let git_url = auth_url.get_git_url()?; + let (branch, tag, commit) = repo_spec.to_triple(); + let opts = InputOptions { + dont_prompt: true, + auth: auth_url.get_auth(), + no_build: false, + use_nixpkgs: None, + branch, + tag, + commit, + }; + + let flake_url = crate::module::inquire_module_url(&opts, &git_url, false)?; + let dummy_path = LinuxPath(String::from("")); + let nix_url = flake_url.to_nix_url(dummy_path); + let modules = crate::platform::Driver::store() + .cmd() + .list_nixos_modules(&nix_url)?; + + Ok(modules) +} + +fn get_unset_secrets_for(machine: &Machine) -> Result> { + let mut all_secrets = machine.eval_env_secrets()?; + let (_, cfg) = MachineConfig::open_existing(&machine.config.name, false)?; + let set_secrets = cfg.secrets; + + all_secrets.retain(|name, _| !set_secrets.contains_key(name)); + + Ok(all_secrets.into_values().collect()) +} + +fn write_secrets(machine: &mut Machine, secrets: HashMap>) -> Result<()> { + let (lock, mut cfg) = MachineConfig::open_existing(&machine.config.name, true)?; + for (name, value) in secrets { + if let Some(val) = value { + cfg.secrets.insert(name, val); + } + } + + cfg.write(lock)?; + machine.config = cfg; + + Ok(()) +} diff --git a/codchi/src/gui/util/dialog_manager.rs b/codchi/src/gui/util/dialog_manager.rs new file mode 100644 index 00000000..f752e158 --- /dev/null +++ b/codchi/src/gui/util/dialog_manager.rs @@ -0,0 +1,275 @@ +use std::path::PathBuf; + +use egui::*; + +use crate::platform::Machine; + +use super::password_field; + +pub struct DialogManager { + dialogs: Vec, +} + +impl DialogManager { + pub fn new() -> Self { + Self { + dialogs: Vec::new(), + } + } + + pub fn update(&mut self, ctx: &Context) -> Option { + if !self.dialogs.is_empty() { + let dialog_result = self.dialogs[0].update_ui(ctx); + + if let Some(result) = dialog_result { + let dialog = self.dialogs.remove(0); + + match result { + DialogResult::Confirm => return Some(dialog.intent), + DialogResult::Cancel => {} + } + } + } + + None + } + + fn queue( + &mut self, + intent: DialogIntent, + heading: String, + primary_button_text: String, + primary_button_color: Option<(u8, u8, u8)>, + secondary_button_text: Option, + ) { + self.queue_dialog(GuiDialog { + intent, + heading, + primary_button_text, + primary_button_color, + secondary_button_text, + }); + } + + fn queue_dialog(&mut self, gui_dialog: GuiDialog) { + self.dialogs.push(gui_dialog); + } + + pub fn queue_generic(&mut self, dialog_intent: DialogIntent) { + dialog_intent.to_gui_modal(self); + } +} + +struct GuiDialog { + intent: DialogIntent, + heading: String, + primary_button_text: String, + primary_button_color: Option<(u8, u8, u8)>, + secondary_button_text: Option, +} + +impl GuiDialog { + fn update_ui(&mut self, ctx: &Context) -> Option { + let modal = Modal::new(Id::new("global_modal")).show(ctx, |ui| { + ui.heading(&self.heading); + ui.separator(); + + let confirm_enabled = Self::display_intent_element(ui, &mut self.intent); + + Sides::new().show( + ui, + |ui_left| { + self.secondary_button_text + .as_ref() + .and_then(|text| Some(ui_left.button(text))) + }, + |ui_right| { + let confirm_button = Button::new(&self.primary_button_text); + let confirm_button = match self.primary_button_color { + Some((r, g, b)) => confirm_button.fill(Color32::from_rgb(r, g, b)), + None => confirm_button, + }; + ui_right.add_enabled(confirm_enabled, confirm_button) + }, + ) + }); + + let (cancel_button_option, confirm_button) = modal.inner; + + if let Some(cancel_button) = cancel_button_option { + if cancel_button.clicked() { + return Some(DialogResult::Cancel); + } + } + + if confirm_button.clicked() { + return Some(DialogResult::Confirm); + } + + None + } + + fn display_intent_element(ui: &mut Ui, intent: &mut DialogIntent) -> bool { + match intent { + DialogIntent::Rebuild { + machine: _, + update_modules, + } => { + ui.checkbox(update_modules, "update modules"); + ui.separator(); + + true + } + DialogIntent::Duplicate { + machine: _, + duplicate_name, + } => { + ui.add(TextEdit::singleline(duplicate_name).hint_text("Duplicate Name")); + ui.separator(); + + !duplicate_name.is_empty() + } + DialogIntent::Tar { + machine: _, + file_path, + } => { + let eligible_file = file_path.extension().is_some_and(|ext| ext == "gz"); + + if ui.button("Select").clicked() { + if let Some(selected_folder) = rfd::FileDialog::new() + .add_filter("TAR (*.tar.gz)", &["tar.gz"]) + .save_file() + { + *file_path = selected_folder; + } + } + if eligible_file { + ui.label(format!("{}", file_path.to_string_lossy())); + } + ui.separator(); + + eligible_file + } + DialogIntent::Stop { machine: _ } => true, + DialogIntent::Delete { + machine: _, + confirm, + } => { + ui.checkbox(confirm, "Are you sure?"); + ui.separator(); + + *confirm + } + DialogIntent::Secret { + machine_name: _, + name: _, + value, + } => { + ui.add(password_field(value)); + ui.separator(); + + true + } + } + } +} + +enum DialogResult { + Confirm, + Cancel, +} + +pub enum DialogIntent { + Rebuild { + machine: Machine, + update_modules: bool, + }, + Duplicate { + machine: Machine, + duplicate_name: String, + }, + Tar { + machine: Machine, + file_path: PathBuf, + }, + Stop { + machine: Machine, + }, + Delete { + machine: Machine, + confirm: bool, + }, + + Secret { + machine_name: String, + name: String, + value: String, + }, +} + +impl DialogIntent { + pub fn to_gui_modal(self, dialog_manager: &mut DialogManager) { + let (heading, p_text, p_color, s_text) = match &self { + DialogIntent::Rebuild { + machine, + update_modules: _, + } => { + let heading = format!("Rebuilding Machine '{}'", &machine.config.name); + let p_text = "Rebuild".to_string(); + let p_color = Some((0, 128, 0)); + let s_text = Some("Cancel".to_string()); + (heading, p_text, p_color, s_text) + } + DialogIntent::Duplicate { + machine, + duplicate_name: _, + } => { + let heading = format!("Duplicating Machine '{}'", &machine.config.name); + let p_text = "Duplicate".to_string(); + let p_color = Some((0, 128, 0)); + let s_text = Some("Cancel".to_string()); + (heading, p_text, p_color, s_text) + } + DialogIntent::Tar { + machine, + file_path: _, + } => { + let heading = format!("Exporting Machine '{}'", &machine.config.name); + let p_text = "Export".to_string(); + let p_color = Some((0, 128, 0)); + let s_text = Some("Cancel".to_string()); + (heading, p_text, p_color, s_text) + } + DialogIntent::Stop { machine } => { + let heading = format!("Stopping Machine '{}'", &machine.config.name); + let p_text = "Stop".to_string(); + let p_color = Some((128, 0, 0)); + let s_text = Some("Cancel".to_string()); + (heading, p_text, p_color, s_text) + } + DialogIntent::Delete { + machine, + confirm: _, + } => { + let heading = format!("Delete Machine '{}'", &machine.config.name); + let p_text = "Delete".to_string(); + let p_color = Some((128, 0, 0)); + let s_text = Some("Cancel".to_string()); + (heading, p_text, p_color, s_text) + } + DialogIntent::Secret { + machine_name, + name, + value: _, + } => { + let heading = format!("Setting '{}' for '{}'", name, &machine_name); + let p_text = "Set".to_string(); + let p_color = Some((0, 128, 0)); + let s_text = None; + (heading, p_text, p_color, s_text) + } + }; + + dialog_manager.queue(self, heading, p_text, p_color, s_text); + } +} diff --git a/codchi/src/gui/util/mod.rs b/codchi/src/gui/util/mod.rs new file mode 100644 index 00000000..21def6b3 --- /dev/null +++ b/codchi/src/gui/util/mod.rs @@ -0,0 +1,86 @@ +pub mod backend_broker; +pub mod dialog_manager; +pub mod status_entries; +pub mod textures_manager; + +use egui::*; + +pub fn password_field<'a>(password: &'a mut String) -> impl Widget + 'a { + move |ui: &mut Ui| password_field_ui(ui, password) +} + +fn password_field_ui(ui: &mut Ui, password: &mut String) -> Response { + let state_id = ui.id().with("show_plaintext"); + + let mut show_plaintext = ui.data_mut(|d| d.get_temp::(state_id).unwrap_or(false)); + + let result = ui + .with_layout(Layout::right_to_left(Align::Min), |ui| { + let response = ui + .add(SelectableLabel::new(show_plaintext, "👁")) + .on_hover_text("Show/hide password"); + + if response.clicked() { + show_plaintext = !show_plaintext; + } + + ui.add_sized( + [ui.available_width(), 0.0], + TextEdit::singleline(password).password(!show_plaintext), + ) + }) + .inner; + + ui.data_mut(|d| d.insert_temp(state_id, show_plaintext)); + + result +} + +pub fn advanced_password_field<'a>( + id: &'a str, + write_closure: impl FnOnce(String) + 'a, + password: &'a str, +) -> impl Widget + 'a { + move |ui: &mut Ui| advanced_password_field_ui(ui, id, write_closure, password) +} + +pub fn advanced_password_field_ui( + ui: &mut Ui, + id: &str, + write_closure: impl FnOnce(String), + password: &str, +) -> Response { + let state_id = ui.id().with("show_plaintext"); + let text_id = ui.id().with(id); + + let mut show_plaintext = ui.data_mut(|d| d.get_temp::(state_id).unwrap_or(false)); + let mut text = ui.data_mut(|d| { + d.get_temp::(text_id) + .unwrap_or(String::from(password)) + }); + + let result = ui.with_layout(Layout::right_to_left(Align::Min), |ui| { + let response = ui + .add(SelectableLabel::new(show_plaintext, "👁")) + .on_hover_text("Show/hide password"); + + if response.clicked() { + show_plaintext = !show_plaintext; + } + + ui.add_sized( + [250.0, 0.0], + TextEdit::singleline(&mut text).password(!show_plaintext), + ); + + if password != text { + if ui.button("Write").clicked() { + write_closure(text.clone()); + } + } + }); + ui.data_mut(|d| d.insert_temp(state_id, show_plaintext)); + ui.data_mut(|d| d.insert_temp(text_id, text)); + + result.response +} diff --git a/codchi/src/gui/util/status_entries.rs b/codchi/src/gui/util/status_entries.rs new file mode 100644 index 00000000..220fa5e2 --- /dev/null +++ b/codchi/src/gui/util/status_entries.rs @@ -0,0 +1,68 @@ +pub(crate) struct StatusEntries { + entries: Vec>, + free_entries: Vec, +} + +impl StatusEntries { + pub fn new() -> Self { + Self { + entries: Vec::new(), + free_entries: Vec::new(), + } + } + + pub fn create_entry(&mut self, text: String) -> usize { + self.push(text, 1) + } + + pub fn push(&mut self, text: String, durability: usize) -> usize { + self.push_entry(StatusEntry { text, durability }) + } + + fn push_entry(&mut self, status_entry: StatusEntry) -> usize { + if let Some(free_index) = self.free_entries.pop() { + self.entries[free_index] = Some(status_entry); + free_index + } else { + self.entries.push(Some(status_entry)); + self.entries.len() - 1 + } + } + + pub fn decrease(&mut self, index: usize) { + if index < self.entries.len() { + if let Some(status_entry) = self.entries[index].as_mut() { + if status_entry.decrement() == 0 { + self.entries[index] = None; + self.free_entries.push(index); + } + } + } + } + + pub fn get_status(&self) -> Vec<&str> { + let mut result = Vec::new(); + for status_entry in &self.entries { + if let Some(entry) = status_entry { + result.push(entry.get_text()); + } + } + result + } +} + +struct StatusEntry { + text: String, + durability: usize, +} + +impl StatusEntry { + fn decrement(&mut self) -> usize { + self.durability = self.durability.saturating_sub(1); + self.durability + } + + fn get_text(&self) -> &str { + &self.text + } +} diff --git a/codchi/src/gui/util/textures_manager.rs b/codchi/src/gui/util/textures_manager.rs new file mode 100644 index 00000000..c8ba3c4f --- /dev/null +++ b/codchi/src/gui/util/textures_manager.rs @@ -0,0 +1,197 @@ +use anyhow::Result; +use egui::*; +use image::{ImageBuffer, ImageReader, Rgba}; +use resvg::tiny_skia::Pixmap; +use std::{ + collections::{HashMap, HashSet}, + path::PathBuf, + sync::mpsc::{channel, Receiver, Sender}, + thread, +}; + +pub struct TexturesManager { + textures: HashMap, + + sender: Sender<(String, ChannelDTO)>, + receiver: Receiver<(String, ChannelDTO)>, + + open_requests: HashSet, +} + +enum ChannelDTO { + ColorImage(ColorImage), +} + +impl TexturesManager { + pub fn new() -> Self { + let (sender, receiver) = channel(); + load_square_textures_async(&sender); + Self { + textures: HashMap::new(), + + sender, + receiver, + + open_requests: HashSet::new(), + } + } + + pub fn update(&mut self, ctx: &Context) { + self.receive_msgs(ctx); + } + + pub fn get(&self, name: &str) -> Option<&TextureHandle> { + self.textures.get(name) + } + + pub fn get_image(&self, name: &str) -> Option { + self.get(name).map(|tex| Image::from_texture(tex)) + } + + pub fn deliver(&mut self, name: &str, path: &str) -> Option<&TextureHandle> { + let texture_handle = self.textures.get(name); + + if texture_handle.is_none() { + let name_string = name.to_string(); + if !self.open_requests.contains(&name_string) { + self.open_requests.insert(name_string); + load_color_image_async(&self.sender, name.to_string(), path.to_string()); + } + } + + texture_handle + } + + pub fn deliver_ico(&mut self, name: &str, path: &PathBuf) -> Option<&TextureHandle> { + let texture_handle = self.textures.get(name); + + if texture_handle.is_none() { + let name_string = name.to_string(); + if !self.open_requests.contains(&name_string) { + self.open_requests.insert(name_string); + load_image_buffer_async(&self.sender, name.to_string(), path.clone()); + } + } + + texture_handle + } + + pub fn deliver_svg(&mut self, name: &str, path: &str) -> Option<&TextureHandle> { + let texture_handle = self.textures.get(name); + + if texture_handle.is_none() { + let name_string = name.to_string(); + if !self.open_requests.contains(&name_string) { + self.open_requests.insert(name_string); + load_svg_async(&self.sender, name.to_string(), path.to_string()); + } + } + + texture_handle + } + + fn receive_msgs(&mut self, ctx: &Context) { + while let Ok((name, channel_dto)) = self.receiver.try_recv() { + self.open_requests.remove(&name); + match channel_dto { + ChannelDTO::ColorImage(color_image) => { + let texture_handle = ctx.load_texture(&name, color_image, Default::default()); + self.textures.insert(name, texture_handle); + } + } + } + } +} + +fn load_color_image_async(sender: &Sender<(String, ChannelDTO)>, name: String, location: String) { + let sender_clone = sender.clone(); + thread::spawn(move || { + let path = PathBuf::from(&location); + if let Ok(color_image) = load_color_image_from_path(&path) { + let dto = ChannelDTO::ColorImage(color_image); + sender_clone.send((name, dto)).unwrap(); + } + }); +} + +fn load_image_buffer_async(sender: &Sender<(String, ChannelDTO)>, name: String, path: PathBuf) { + let sender_clone = sender.clone(); + thread::spawn(move || { + if let Ok((image_buffer, size)) = load_image_from_path(&path) { + let color_image = ColorImage::from_rgba_unmultiplied(size, &image_buffer); + let dto = ChannelDTO::ColorImage(color_image); + sender_clone.send((name, dto)).unwrap(); + } + }); +} + +fn load_svg_async(sender: &Sender<(String, ChannelDTO)>, name: String, location: String) { + let sender_clone = sender.clone(); + thread::spawn(move || { + let path = PathBuf::from(&location); + if let Ok(color_image) = load_svg_from_path(&path) { + let dto = ChannelDTO::ColorImage(color_image); + sender_clone.send((name, dto)).unwrap(); + } + }); +} + +fn load_color_image_from_path(path: &PathBuf) -> Result { + let image = ImageReader::open(path)?.decode()?.to_rgba8(); + + let (width, height) = image.dimensions(); + let pixels = image.into_raw(); + + Ok(ColorImage::from_rgba_unmultiplied( + [width as usize, height as usize], + &pixels, + )) +} + +fn load_image_from_path(path: &PathBuf) -> Result<(ImageBuffer, Vec>, [usize; 2])> { + let image = image::open(path)?.to_rgba8(); + let size = [image.width() as usize, image.height() as usize]; + + Ok((image, size)) +} + +fn load_svg_from_path(path: &PathBuf) -> Result { + let rtree = usvg::Tree::from_data(&std::fs::read(path)?, &usvg::Options::default())?; + + let w = rtree.size().width(); + let h = rtree.size().height(); + + let mut pixmap = Pixmap::new(w as u32, h as u32).unwrap(); + resvg::render(&rtree, Default::default(), &mut pixmap.as_mut()); + + Ok(ColorImage::from_rgba_unmultiplied( + [w as usize, h as usize], + pixmap.data(), + )) +} + +fn load_square_textures_async(sender: &Sender<(String, ChannelDTO)>) { + let sender_clone = sender.clone(); + thread::spawn(move || { + let dto = ChannelDTO::ColorImage(ColorImage::new([10, 10], Color32::BLACK)); + sender_clone.send(("black".to_string(), dto)).unwrap(); + }); + + let sender_clone = sender.clone(); + thread::spawn(move || { + let dto = ChannelDTO::ColorImage(ColorImage::new([10, 10], Color32::DARK_RED)); + sender_clone.send(("dark_red".to_string(), dto)).unwrap(); + }); + + let sender_clone = sender.clone(); + thread::spawn(move || { + let dto = ChannelDTO::ColorImage(ColorImage::new([10, 10], Color32::RED)); + sender_clone.send(("red".to_string(), dto)).unwrap(); + }); + + let sender_clone = sender.clone(); + thread::spawn(move || { + let dto = ChannelDTO::ColorImage(ColorImage::new([10, 10], Color32::GREEN)); + sender_clone.send(("green".to_string(), dto)).unwrap(); + }); +} diff --git a/codchi/src/logging/nix.rs b/codchi/src/logging/nix.rs index 79d1dd4c..a6174b7c 100644 --- a/codchi/src/logging/nix.rs +++ b/codchi/src/logging/nix.rs @@ -70,26 +70,26 @@ pub enum Activity { FetchTree, } -impl Activity { - pub fn to_type(&self) -> ActivityType { - match self { - Activity::Unknown => ActivityType::Unknown, - Activity::CopyPath { .. } => ActivityType::CopyPath, - Activity::FileTransfer { .. } => ActivityType::FileTransfer, - Activity::Realise => ActivityType::Realise, - Activity::CopyPaths => ActivityType::CopyPaths, - Activity::Builds => ActivityType::Builds, - Activity::Build { .. } => ActivityType::Build, - Activity::OptimiseStore => ActivityType::OptimiseStore, - Activity::VerifyPaths => ActivityType::VerifyPaths, - Activity::Substitute { .. } => ActivityType::Substitute, - Activity::QueryPathInfo { .. } => ActivityType::QueryPathInfo, - Activity::PostBuildHook { .. } => ActivityType::PostBuildHook, - Activity::BuildWaiting { .. } => ActivityType::BuildWaiting, - Activity::FetchTree { .. } => ActivityType::FetchTree, - } - } -} +// impl Activity { +// pub fn to_type(&self) -> ActivityType { +// match self { +// Activity::Unknown => ActivityType::Unknown, +// Activity::CopyPath { .. } => ActivityType::CopyPath, +// Activity::FileTransfer { .. } => ActivityType::FileTransfer, +// Activity::Realise => ActivityType::Realise, +// Activity::CopyPaths => ActivityType::CopyPaths, +// Activity::Builds => ActivityType::Builds, +// Activity::Build { .. } => ActivityType::Build, +// Activity::OptimiseStore => ActivityType::OptimiseStore, +// Activity::VerifyPaths => ActivityType::VerifyPaths, +// Activity::Substitute { .. } => ActivityType::Substitute, +// Activity::QueryPathInfo { .. } => ActivityType::QueryPathInfo, +// Activity::PostBuildHook { .. } => ActivityType::PostBuildHook, +// Activity::BuildWaiting { .. } => ActivityType::BuildWaiting, +// Activity::FetchTree { .. } => ActivityType::FetchTree, +// } +// } +// } #[derive(Clone, Copy, Debug, TryFromPrimitive, IntoPrimitive, PartialEq, Eq)] #[repr(i64)] diff --git a/codchi/src/logging/progress.rs b/codchi/src/logging/progress.rs index 56ed49f7..42d100de 100644 --- a/codchi/src/logging/progress.rs +++ b/codchi/src/logging/progress.rs @@ -74,13 +74,13 @@ impl Progress { self.status_bar.set_message(msg); } - pub fn with_status(self, msg: M) -> Self - where - M: Into>, - { - self.status_bar.set_message(msg); - self - } + // pub fn with_status(self, msg: M) -> Self + // where + // M: Into>, + // { + // self.status_bar.set_message(msg); + // self + // } pub fn log(&mut self, fallback_target: &str, fallback_level: Level, msg: &str) { let result = nix::parse_line(msg); diff --git a/codchi/src/main.rs b/codchi/src/main.rs index e1e7f8b2..90edeb91 100644 --- a/codchi/src/main.rs +++ b/codchi/src/main.rs @@ -17,7 +17,7 @@ use secrets::MachineSecrets; use std::{ env, io::IsTerminal, - panic::{self, PanicInfo}, + panic::{self, PanicHookInfo}, process::exit, sync::{mpsc::channel, OnceLock}, thread, @@ -28,6 +28,7 @@ use util::{ResultExt, UtilExt}; pub mod cli; pub mod config; pub mod consts; +pub mod gui; pub mod logging; pub mod module; pub mod platform; @@ -36,7 +37,7 @@ pub mod tray; pub mod util; fn main() -> anyhow::Result<()> { - panic::set_hook(Box::new(move |info: &PanicInfo<'_>| { + panic::set_hook(Box::new(move |info: &PanicHookInfo<'_>| { let meta = human_panic::Metadata::new( env!("CARGO_PKG_NAME"), format!( @@ -172,7 +173,7 @@ Thank you kindly!"# module_paths, )?; if !options.no_build { - machine.build(true)?; + machine.full_build(true)?; machine.run_init_script(*dont_run_init)?; log::info!("Machine '{machine_name}' is ready! Use `codchi exec {machine_name}` to start it.") } else { @@ -219,7 +220,7 @@ Thank you kindly!"# } Cmd::Rebuild { no_update, name } => { - Machine::by_name(name, true)?.build(*no_update)?; + Machine::by_name(name, true)?.full_build(*no_update)?; log::info!("Machine {name} rebuilt successfully!"); } @@ -316,7 +317,7 @@ secret. Is this OK? [y/n]", let mut machine = module::add(machine_name, GitUrl::from(url), options, module_paths)?; if !options.no_build { - machine.build(true)?; + machine.full_build(true)?; } else { alert_dirty(machine); } @@ -338,7 +339,7 @@ secret. Is this OK? [y/n]", url.as_ref().map(GitUrl::from), )?; if !options.no_build { - machine.build(false)?; + machine.full_build(false)?; } else { alert_dirty(machine); } @@ -356,6 +357,8 @@ secret. Is this OK? [y/n]", Cmd::Tray {} => tray::run()?, + Cmd::GUI {} => gui::run()?, + Cmd::Completion { .. } => unreachable!(), Cmd::Tar { .. } => unreachable!(), @@ -402,7 +405,7 @@ fn alert_dirty(machine: Machine) { } } -fn get_panic_cause(panic_info: &PanicInfo) -> String { +fn get_panic_cause(panic_info: &PanicHookInfo) -> String { #[cfg(feature = "nightly")] let message = panic_info.message().map(|m| format!("{}", m)); diff --git a/codchi/src/module.rs b/codchi/src/module.rs index 002b792a..51d6a6d3 100644 --- a/codchi/src/module.rs +++ b/codchi/src/module.rs @@ -422,7 +422,7 @@ pub fn fetch_modules( Ok((modules, use_nixpkgs)) } -fn inquire_module_url( +pub(crate) fn inquire_module_url( opts: &InputOptions, url: &GitUrl, allow_local: bool, @@ -600,7 +600,7 @@ pub fn clone( &input_options, module_paths, )?; - machine.build(true)?; + machine.full_build(true)?; progress_scope! { set_progress_status("Cloning git repository..."); diff --git a/codchi/src/platform/host.rs b/codchi/src/platform/host.rs index 8f2d0e4b..ca302490 100644 --- a/codchi/src/platform/host.rs +++ b/codchi/src/platform/host.rs @@ -25,6 +25,12 @@ pub trait Host: Sized { fn delete_shortcuts(name: &str) -> Result<()>; fn write_machine_shortcuts(machine: &Machine) -> Result<()> { + let desktop_entries = Self::list_desktop_entries(machine)?; + Self::write_shortcuts(&machine.config.name, desktop_entries.iter())?; + Ok(()) + } + + fn list_desktop_entries(machine: &Machine) -> Result> { let nix_path = Driver::store().cmd().realpath( &consts::store::DIR_CONFIG .join_machine(&machine.config.name) @@ -92,8 +98,7 @@ pub trait Host: Sized { }); } - Self::write_shortcuts(&machine.config.name, desktop_entries.iter())?; - Ok(()) + Ok(desktop_entries) } fn open_terminal(&self, cmd: &[&str]) -> Result<()>; @@ -109,7 +114,6 @@ pub trait Host: Sized { p.exe().is_some_and(|p| p == exe) && p.cmd().get(1).is_some_and(|arg| arg == "tray") }) { - log::trace!("Kill running: {kill_running}. Process: {:?}", p.cmd()); if kill_running { log::debug!("Killing running tray"); @@ -150,6 +154,8 @@ pub trait Host: Sized { fn post_delete(_machine_name: &str) -> Result<()> { Ok(()) } + + fn execute(machine_name: &str, desktop_entry: &DesktopEntry) -> Result<()>; } #[derive(Clone, Debug)] diff --git a/codchi/src/platform/linux/host.rs b/codchi/src/platform/linux/host.rs index 57cc62c7..324dd89f 100644 --- a/codchi/src/platform/linux/host.rs +++ b/codchi/src/platform/linux/host.rs @@ -165,4 +165,16 @@ impl Host for HostImpl { } bail!("Could not find a terminal."); } + + fn execute(machine_name: &str, desktop_entry: &DesktopEntry) -> Result<()> { + let exe = env::current_exe()?.to_string_lossy().to_string(); + let mut cmd = Command::new(&exe); + cmd.args(["exec", machine_name]); + for arg in desktop_entry.exec.split(" ") { + cmd.arg(arg); + } + cmd.spawn()?; + + Ok(()) + } } diff --git a/codchi/src/platform/machine.rs b/codchi/src/platform/machine.rs index 1faa6b13..14c1874c 100644 --- a/codchi/src/platform/machine.rs +++ b/codchi/src/platform/machine.rs @@ -301,6 +301,14 @@ fi Ok(()) } + pub fn full_build(&mut self, no_update: bool) -> Result<()> { + self.build(no_update)?; + self.build_eval_secrets()?; + self.build_install()?; + + Ok(()) + } + pub fn build(&mut self, no_update: bool) -> Result<()> { self.write_flake()?; @@ -365,6 +373,10 @@ git add flake.* ); } + Ok(()) + } + + fn build_eval_secrets(&mut self) -> Result<()> { set_progress_status("Evaluating secrets..."); let secrets = self.eval_env_secrets()?; @@ -387,6 +399,10 @@ git add flake.* cfg.write(lock)?; self.config = cfg; + Ok(()) + } + + pub fn build_install(&mut self) -> Result<()> { set_progress_status(format!("Building {}...", self.config.name)); let status = Self::read_platform_status(&self.config.name)?; if status == PlatformStatus::NotInstalled { @@ -599,7 +615,7 @@ git add flake.* }; self.duplicate_container(&new_machine)?; new_machine.write_flake()?; - new_machine.build(true)?; + new_machine.full_build(true)?; log::info!( "Successfully duplicated machine '{}' to '{target_name}'", diff --git a/codchi/src/platform/mod.rs b/codchi/src/platform/mod.rs index a8d27640..ecb495e3 100644 --- a/codchi/src/platform/mod.rs +++ b/codchi/src/platform/mod.rs @@ -6,7 +6,7 @@ mod store; #[allow(clippy::module_inception)] #[cfg_attr(target_os = "linux", path = "linux/mod.rs")] #[cfg_attr(target_os = "windows", path = "windows/mod.rs")] -mod platform; +pub mod platform; pub use self::cmd::*; pub use self::host::*; diff --git a/codchi/src/platform/windows/host.rs b/codchi/src/platform/windows/host.rs index e5615ef3..609a2308 100644 --- a/codchi/src/platform/windows/host.rs +++ b/codchi/src/platform/windows/host.rs @@ -11,7 +11,9 @@ use known_folders::{get_known_folder_path, KnownFolder}; use mslnk::{FileAttributeFlags, LinkFlags, MSLinkError, ShellLink}; use std::{env, fs, os::windows::process::CommandExt, path::Path, process::Command}; use sysinfo::System; -use windows::Win32::System::Threading::{CREATE_NEW_PROCESS_GROUP, CREATE_NO_WINDOW}; +use windows::Win32::System::Threading::{ + CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP, CREATE_NO_WINDOW, +}; pub struct HostImpl; impl HostImpl {} @@ -274,4 +276,29 @@ impl Host for HostImpl { Ok(()) } + + fn execute(machine_name: &str, desktop_entry: &DesktopEntry) -> Result<()> { + let codchi_exe = get_known_folder_path(KnownFolder::LocalAppData) + .expect("FOLDERID_LocalAppData missing") + .join("Microsoft") + .join("WindowsApps") + .join("codchi.exe"); + let exe = if desktop_entry.is_terminal { + codchi_exe + } else { + codchi_exe + .parent() + .with_context(|| format!("Missing parent of {codchi_exe:?}"))? + .join("codchiw.exe") + }; + + let mut cmd = Command::new(&exe); + cmd.args(["exec", machine_name]); + for arg in desktop_entry.exec.split(" ") { + cmd.arg(arg); + } + cmd.creation_flags(CREATE_NEW_CONSOLE.0).spawn()?; + + Ok(()) + } } diff --git a/codchi/src/platform/windows/mod.rs b/codchi/src/platform/windows/mod.rs index 9ea35a71..55da34a9 100644 --- a/codchi/src/platform/windows/mod.rs +++ b/codchi/src/platform/windows/mod.rs @@ -368,13 +368,36 @@ tail -f "{log_file}" } fn create_exec_cmd(&self, cmd: &[&str]) -> super::LinuxCommandBuilder { - let cmd = match cmd.split_first() { - Some((cmd, args)) => self.cmd().run(cmd, args), - None => self.cmd().run("bash", &["-l"]), + // let cmd = match cmd.split_first() { + // Some((cmd, args)) => self.cmd().run(cmd, args), + // None => self.cmd().run("bash", &["-l"]), + // }; + let cmd = if cmd.is_empty() { + self.cmd().raw( + "/run/current-system/sw/bin/machinectl", + &[ + &["shell", "-q", &format!("{}@", consts::user::DEFAULT_NAME)], + cmd, + ] + .concat(), + ) + } else { + self.cmd().raw( + "/run/current-system/sw/bin/machinectl", + &[ + "shell", + "-q", + &format!("{}@", consts::user::DEFAULT_NAME), + "/bin/bash", + "-lc", + &cmd.join(" "), + ], + ) }; - cmd.with_cwd(consts::user::DEFAULT_HOME.clone()) - .with_user(LinuxUser::Default) + // cmd.with_cwd(consts::user::DEFAULT_HOME.clone()) + // .with_user(LinuxUser::Default) + cmd.with_user(LinuxUser::Root) } fn tar(&self, target_file: &std::path::Path) -> Result<()> { diff --git a/flake.lock b/flake.lock index f237fb62..a6c51ce7 100644 --- a/flake.lock +++ b/flake.lock @@ -1,35 +1,176 @@ { "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1733328505, + "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1733312601, + "narHash": "sha256-4pDvzqnegAfRkPwO3wmwBhVi/Sye1mzps0zHWYnP88c=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "205b12d8b7cd4802fbcb8e8ef6a0f1408781a4f9", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "git-hooks-nix": { + "inputs": { + "flake-compat": [ + "nix" + ], + "gitignore": [ + "nix" + ], + "nixpkgs": [ + "nix", + "nixpkgs" + ], + "nixpkgs-stable": [ + "nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1734279981, + "narHash": "sha256-NdaCraHPp8iYMWzdXAt5Nv6sA3MUzlCiGiR586TCwo0=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "aa9f40c906904ebd83da78e7f328cd8aeaeae785", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "nix": { + "inputs": { + "flake-compat": "flake-compat", + "flake-parts": "flake-parts", + "git-hooks-nix": "git-hooks-nix", + "nixpkgs": "nixpkgs", + "nixpkgs-23-11": "nixpkgs-23-11", + "nixpkgs-regression": "nixpkgs-regression" + }, + "locked": { + "lastModified": 1739376598, + "narHash": "sha256-EOnBPe+ydQ0/P5ZyWnFekvpyUxMcmh2rnP9yNFi/EqU=", + "owner": "NixOS", + "repo": "nix", + "rev": "b3e92048335d88553c1d6bbcf280e95b9a1b5a75", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "2.26.2", + "repo": "nix", + "type": "github" + } + }, "nixpkgs": { "locked": { - "lastModified": 1720553833, - "narHash": "sha256-IXMiHQMtdShDXcBW95ctA+m5Oq2kLxnBt7WlMxvDQXA=", + "lastModified": 1734359947, + "narHash": "sha256-1Noao/H+N8nFB4Beoy8fgwrcOQLVm9o4zKW1ODaqK9E=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "48d12d5e70ee91fe8481378e540433a7303dbf6a", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "release-24.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-23-11": { + "locked": { + "lastModified": 1717159533, + "narHash": "sha256-oamiKNfr2MS6yH64rUn99mIZjc45nGJlj9eGth/3Xuw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a62e6edd6d5e1fa0329b8653c801147986f8d446", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a62e6edd6d5e1fa0329b8653c801147986f8d446", + "type": "github" + } + }, + "nixpkgs-regression": { + "locked": { + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1740463929, + "narHash": "sha256-4Xhu/3aUdCKeLfdteEHMegx5ooKQvwPHNkOgNCXQrvc=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "249fbde2a178a2ea2638b65b9ecebd531b338cf9", + "rev": "5d7db4668d7a0c6cc5fc8cf6ef33b008b2b1ed8b", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-24.05", + "ref": "nixos-24.11", "repo": "nixpkgs", "type": "github" } }, "root": { "inputs": { - "nixpkgs": "nixpkgs", + "nix": "nix", + "nixpkgs": "nixpkgs_2", "rust-overlay": "rust-overlay" } }, "rust-overlay": { "flake": false, "locked": { - "lastModified": 1720664424, - "narHash": "sha256-+odiMNHRYdvzL1ewl41UVFxsjmdoXfH+maQ8xvUoR4g=", + "lastModified": 1740536993, + "narHash": "sha256-3YI+1ONZ28chM19Hep9Z+TSyiybYf/1VC/gwImVZKUw=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "fec97e65fcbaab0decccba740ac8688f61dadd70", + "rev": "9f05c0655de9dc2c7b60b689447c48abb9190bf8", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index e5fe3565..06bcefe6 100644 --- a/flake.nix +++ b/flake.nix @@ -7,11 +7,12 @@ }; inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11"; rust-overlay = { url = "github:oxalica/rust-overlay"; flake = false; # prevent fetching transitive inputs TODO }; + nix.url = "github:NixOS/nix/2.26.2"; # nixvim = { # url = "github:nix-community/nixvim"; # inputs.nixpkgs.follows = "nixpkgs"; diff --git a/nix/container/store/default.nix b/nix/container/store/default.nix index feef9ed0..3525772f 100644 --- a/nix/container/store/default.nix +++ b/nix/container/store/default.nix @@ -82,10 +82,16 @@ in flakes = [{ exact = true; from = { type = "indirect"; id = "nixpkgs"; }; - to = { type = "path"; path = inputs.nixpkgs.outPath; } - // lib.filterAttrs - (n: _: n == "lastModified" || n == "rev" || n == "revCount" || n == "narHash") - inputs.nixpkgs; + # to = { type = "path"; path = inputs.nixpkgs.outPath; } + # // lib.filterAttrs + # (n: _: n == "lastModified" || n == "rev" || n == "revCount" || n == "narHash") + # inputs.nixpkgs; + to = { + type = "github"; + owner = "NixOS"; + repo = "nixpkgs"; + inherit (inputs.nixpkgs) rev; + }; }]; }); # nix runs as root and needs to access user repositories @@ -113,7 +119,8 @@ in binPackages = with pkgs.pkgsStatic; [ busybox bashInteractive - nix + inputs.nix.packages.${pkgs.system}.nix-everything-static + pkgs.codchi-utils # ndd (pkgs.writeShellScriptBinStatic "run" /* bash */ '' @@ -196,8 +203,8 @@ in nix $NIX_VERBOSITY profile wipe-history else logE "Updating store..." - nix flake update $NIX_VERBOSITY "${consts.store.DIR_CONFIG_STORE}" - ndd $NIX_VERBOSITY profile upgrade --profile "${consts.store.PROFILE_STORE}" '.*' + nix flake update $NIX_VERBOSITY --flake "${consts.store.DIR_CONFIG_STORE}" + ndd $NIX_VERBOSITY profile upgrade --profile "${consts.store.PROFILE_STORE}" --all fi # kill $NIX_DAEMON_PID