From bf249d9949ff8f8b43bb512d8da8f67180e6650a Mon Sep 17 00:00:00 2001 From: Non <43197300+nonperforming@users.noreply.github.com> Date: Mon, 12 May 2025 14:13:38 +1200 Subject: [PATCH 01/16] Move plugin files to folder --- .gitignore => Plugin/.gitignore | 0 Plugin.cs => Plugin/Plugin.cs | 0 .../RhythmDoctor.EditorLaunch.csproj | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename .gitignore => Plugin/.gitignore (100%) rename Plugin.cs => Plugin/Plugin.cs (100%) rename RhythmDoctor.EditorLaunch.csproj => Plugin/RhythmDoctor.EditorLaunch.csproj (100%) diff --git a/.gitignore b/Plugin/.gitignore similarity index 100% rename from .gitignore rename to Plugin/.gitignore diff --git a/Plugin.cs b/Plugin/Plugin.cs similarity index 100% rename from Plugin.cs rename to Plugin/Plugin.cs diff --git a/RhythmDoctor.EditorLaunch.csproj b/Plugin/RhythmDoctor.EditorLaunch.csproj similarity index 100% rename from RhythmDoctor.EditorLaunch.csproj rename to Plugin/RhythmDoctor.EditorLaunch.csproj From 7474b0ff67b7383f997526d29c3590bf0f88938c Mon Sep 17 00:00:00 2001 From: Non <43197300+nonperforming@users.noreply.github.com> Date: Fri, 23 May 2025 13:27:55 +1200 Subject: [PATCH 02/16] Initial release v0.3.0 --- Launcher/.editorconfig | 12 + Launcher/.gitignore | 17 + Launcher/Cargo.lock | 2422 ++++++++++++++++++++++++++++++++ Launcher/Cargo.toml | 54 + Launcher/build.rs | 5 + Launcher/src/built.rs | 1 + Launcher/src/config_wrapper.rs | 83 ++ Launcher/src/main.rs | 147 ++ Launcher/src/rhythm_doctor.rs | 155 ++ 9 files changed, 2896 insertions(+) create mode 100644 Launcher/.editorconfig create mode 100644 Launcher/.gitignore create mode 100644 Launcher/Cargo.lock create mode 100644 Launcher/Cargo.toml create mode 100644 Launcher/build.rs create mode 100644 Launcher/src/built.rs create mode 100644 Launcher/src/config_wrapper.rs create mode 100644 Launcher/src/main.rs create mode 100644 Launcher/src/rhythm_doctor.rs diff --git a/Launcher/.editorconfig b/Launcher/.editorconfig new file mode 100644 index 0000000..a1027e5 --- /dev/null +++ b/Launcher/.editorconfig @@ -0,0 +1,12 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = false \ No newline at end of file diff --git a/Launcher/.gitignore b/Launcher/.gitignore new file mode 100644 index 0000000..0104787 --- /dev/null +++ b/Launcher/.gitignore @@ -0,0 +1,17 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +# RustRover +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ \ No newline at end of file diff --git a/Launcher/Cargo.lock b/Launcher/Cargo.lock new file mode 100644 index 0000000..13ef2bc --- /dev/null +++ b/Launcher/Cargo.lock @@ -0,0 +1,2422 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "atk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" +dependencies = [ + "atk-sys", + "glib", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bstr" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "built" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64" +dependencies = [ + "chrono", + "git2", +] + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "cairo-rs" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" +dependencies = [ + "bitflags", + "cairo-sys-rs", + "glib", + "libc", + "once_cell", + "thiserror 1.0.69", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "cc" +version = "1.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "windows-link", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "config" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595aae20e65c3be792d05818e8c63025294ac3cb7e200f11459063a352a6ef80" +dependencies = [ + "pathdiff", + "serde", + "toml", + "winnow 0.7.10", +] + +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" +dependencies = [ + "bitflags", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags", + "core-foundation", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "deranged" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags", + "objc2", +] + +[[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.101", +] + +[[package]] +name = "dlopen2" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1297103d2bbaea85724fcee6294c2d50b1081f9ad47d0f6f6f61eda65315a6" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "dpi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "env_home" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "field-offset" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-macro", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "gdk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" +dependencies = [ + "cairo-rs", + "gdk-pixbuf", + "gdk-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" +dependencies = [ + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", + "once_cell", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkwayland-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" +dependencies = [ + "gdk-sys", + "glib-sys", + "gobject-sys", + "libc", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkx11-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" +dependencies = [ + "gdk-sys", + "glib-sys", + "libc", + "system-deps", + "x11", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi", +] + +[[package]] +name = "gio" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "gio-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + +[[package]] +name = "git2" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log", + "url", +] + +[[package]] +name = "glib" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" +dependencies = [ + "bitflags", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "memchr", + "once_cell", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "glib-macros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" +dependencies = [ + "heck 0.4.1", + "proc-macro-crate 2.0.2", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "glib-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "gobject-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gtk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" +dependencies = [ + "atk", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk", + "gdk-pixbuf", + "gio", + "glib", + "gtk-sys", + "gtk3-macros", + "libc", + "pango", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "gtk3-macros" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "hashbrown" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "home" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "keyvalues-parser" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e4c8354918309196302015ac9cae43362f1a13d0d5c5539a33b4c2fd2cd6d25" +dependencies = [ + "pest", + "pest_derive", + "thiserror 1.0.69", +] + +[[package]] +name = "keyvalues-serde" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db0b750e9ae64e6c3d913832dc19ed580b9210bcd7c4dd6d0dd21af469fc14" +dependencies = [ + "keyvalues-parser", + "serde", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "libgit2-sys" +version = "0.18.1+1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1dcb20f84ffcdd825c7a311ae347cce604a6f084a767dec4a4929829645290e" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + +[[package]] +name = "libz-sys" +version = "1.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags", + "jni-sys", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "normpath" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8911957c4b1549ac0dc74e30db9c8b0e66ddcd6d7acc33098f4c63a64a6d7ed" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate 2.0.2", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "objc2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" +dependencies = [ + "bitflags", + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +dependencies = [ + "bitflags", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" +dependencies = [ + "bitflags", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "opener" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de96cad6ee771be7f68df884d3767460b4684012308d8342ed5623fe62b2628c" +dependencies = [ + "bstr", + "normpath", + "windows-sys 0.59.0", +] + +[[package]] +name = "pango" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" +dependencies = [ + "gio", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" +dependencies = [ + "memchr", + "thiserror 2.0.12", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "pest_meta" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime", + "toml_edit 0.20.2", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "redox_syscall" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" + +[[package]] +name = "rhythm_doctor_editor_launcher" +version = "0.3.0" +dependencies = [ + "built", + "config", + "log", + "opener", + "simplelog", + "steamlocate", + "tao", + "which", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simplelog" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0" +dependencies = [ + "log", + "termcolor", + "time", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "steamlocate" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13160bc6ea5cd80cde195ad4a4c629701db2bf397b62c139aa9e739016d2499" +dependencies = [ + "crc", + "home", + "keyvalues-parser", + "keyvalues-serde", + "serde", + "winreg", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck 0.5.0", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "tao" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e59c1f38e657351a2e822eadf40d6a2ad4627b9c25557bc1180ec1b3295ef82" +dependencies = [ + "bitflags", + "core-foundation", + "core-graphics", + "crossbeam-channel", + "dispatch", + "dlopen2", + "dpi", + "gdkwayland-sys", + "gdkx11-sys", + "gtk", + "jni", + "lazy_static", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "once_cell", + "parking_lot", + "raw-window-handle", + "scopeguard", + "tao-macros", + "unicode-segmentation", + "url", + "windows", + "windows-core", + "windows-version", + "x11-dl", +] + +[[package]] +name = "tao-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[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.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.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "time" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + +[[package]] +name = "time-macros" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "toml" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.20.2", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.101", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "which" +version = "7.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762" +dependencies = [ + "either", + "env_home", + "rustix", + "winsafe", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-link", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core", + "windows-link", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core", + "windows-link", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-version" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e04a5c6627e310a23ad2358483286c7df260c964eb2d003d8efd6d0f4e79265c" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" +dependencies = [ + "cfg-if", + "windows-sys 0.59.0", +] + +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] diff --git a/Launcher/Cargo.toml b/Launcher/Cargo.toml new file mode 100644 index 0000000..21c96b0 --- /dev/null +++ b/Launcher/Cargo.toml @@ -0,0 +1,54 @@ +[package] +name = "rhythm_doctor_editor_launcher" +version = "0.3.0" +edition = "2024" +description = "Helper app for the RhythmDoctor.EditorLaunch plugin" +readme = "../README.md" +homepage = "https://github.com/nonperforming/RhythmDoctor.EditorLaunch/" +repository = "https://github.com/nonperforming/RhythmDoctor.EditorLaunch/" +license = "MIT" +publish = false + +[dependencies] +config = { version = "0.15.11", default-features = false, features = ["toml"] } +log = "0.4.27" +opener = "0.8.1" +simplelog = "0.12.2" +steamlocate = "2.0.1" +which = "7.0.3" + +[target.'cfg(target_os = "macos")'.dependencies] +tao = "0.33.0" + +[build-dependencies] +built = { version = "0.8.0", features = ["chrono", "git2"] } + +[profile.release] +codegen-units = 1 +panic = "abort" +lto = true +opt-level = "z" # Optimize for size +strip = true + +[package.metadata.packager] +before-packaging-command = "cargo build --release" +identifier = "io.github.nonperforming.rdlauncher" +product-name = "Rhythm Doctor Editor Launcher" +description = "Launch Rhythm Doctor Editor" +long-description = "Launch Rhythm Doctor Editor from .rdlevel/.rdzip files" +homepage = "https://github.com/nonperforming/RhythmDoctor.EditorLaunch/" +authors = ["nonperforming"] +copyright = "MIT" +category = "MusicGame" + +[[package.metadata.packager.file-associations]] +extensions = ["rdlevel"] +mime-type = "application/json" +name = "Rhythm Doctor Custom Level" +description = "Rhythm Doctor Custom Level" + +[[package.metadata.packager.file-associations]] +extensions = ["rdzip", "zip"] +mime-type = "application/zip" +name = "Rhythm Doctor Custom Level Package" +description = "Rhythm Doctor Custom Level Package" diff --git a/Launcher/build.rs b/Launcher/build.rs new file mode 100644 index 0000000..d3c0381 --- /dev/null +++ b/Launcher/build.rs @@ -0,0 +1,5 @@ +use built::write_built_file; + +fn main() { + write_built_file().expect("Failed to acquire build-time information"); +} diff --git a/Launcher/src/built.rs b/Launcher/src/built.rs new file mode 100644 index 0000000..ee17776 --- /dev/null +++ b/Launcher/src/built.rs @@ -0,0 +1 @@ +include!(concat!(env!("OUT_DIR"), "/built.rs")); diff --git a/Launcher/src/config_wrapper.rs b/Launcher/src/config_wrapper.rs new file mode 100644 index 0000000..2012039 --- /dev/null +++ b/Launcher/src/config_wrapper.rs @@ -0,0 +1,83 @@ +use config::{Config, ConfigError}; +use log::info; +use opener::open; +use std::env::current_exe; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +const LOG_FILENAME: &str = "launcher.log"; +const CONFIG_FILENAME: &str = "launcher.toml"; + +pub fn get_log_path() -> PathBuf { + get_parent_folder().join(LOG_FILENAME) +} + +pub fn get_config_path() -> PathBuf { + get_parent_folder().join(CONFIG_FILENAME) +} + +fn get_parent_folder() -> PathBuf { + let current_exe = current_exe().unwrap(); + + if cfg!(target_os = "windows") || cfg!(target_os = "linux") { + return current_exe.parent().unwrap().to_path_buf(); + } else if cfg!(target_os = "macos") { + // MacOS has "application" *folders* (folders with the extension .app), + // so we need to navigate up this. + return current_exe // rhythm_doctor_editor_launcher + .parent() // MacOS + .unwrap() + .parent() // Contents + .unwrap() + .parent() // Rhythm Doctor Editor Launcher.app + .unwrap() + .parent() + .unwrap() + .to_path_buf(); + } + panic!("Unsupported OS"); +} + +pub fn build_config() -> Result { + Config::builder() + .add_source(config::File::with_name(get_config_path().to_str().unwrap())) + .build() +} + +pub fn write_config_file() -> Result { + info!("Creating new settings file"); + + match File::create(get_config_path()) { + Ok(mut file) => { + let write = file.write_all(b"# Open Rhythm Doctor with Steam.\nsteam = true"); + match write { + Ok(_) => { + info!("Created new settings file"); + match build_config() { + Ok(config) => { + info!("Loaded new settings file"); + Ok(config) + } + Err(error) => Err(format!("Failed to load new settings file: {error}")), + } + } + Err(error) => Err(format!("Failed to write to new settings file: {error}")), + } + } + Err(error) => Err(format!("Failed to create new settings file: {error}")), + } +} + +pub fn open_config_file() -> Result<(), String> { + if let Ok(_) = open(get_config_path()) { + return Ok(()); + } + return Err("Failed to open settings file".to_string()); +} + +pub fn write_path_file() -> Option { + todo!( + "Implement path file to write to when finding Steam fails (use steam://run/APPID instead)" + ); +} diff --git a/Launcher/src/main.rs b/Launcher/src/main.rs new file mode 100644 index 0000000..cde6696 --- /dev/null +++ b/Launcher/src/main.rs @@ -0,0 +1,147 @@ +#![windows_subsystem = "windows"] + +mod built; +mod config_wrapper; +mod rhythm_doctor; + +use built::{BUILT_TIME_UTC, GIT_VERSION, PKG_VERSION, PROFILE, RUSTC_VERSION, TARGET}; +use config_wrapper::*; +use rhythm_doctor::*; + +use log::{debug, error, info, warn}; +use std::collections::HashMap; +use std::env::{args, current_exe}; +use std::process::ExitCode; + +/// Forward the given launch option to Rhythm Doctor. +fn main() -> ExitCode { + if cfg!(debug_assertions) { + let _ = simplelog::CombinedLogger::init(vec![ + simplelog::TermLogger::new( + simplelog::LevelFilter::Trace, + simplelog::Config::default(), + simplelog::TerminalMode::Stdout, + simplelog::ColorChoice::Auto, + ), + simplelog::WriteLogger::new( + simplelog::LevelFilter::Trace, + simplelog::Config::default(), + std::fs::File::create(get_log_path()).unwrap(), + ), + ]); + } else { + let _ = simplelog::CombinedLogger::init(vec![ + simplelog::TermLogger::new( + simplelog::LevelFilter::Info, + simplelog::Config::default(), + simplelog::TerminalMode::Stdout, + simplelog::ColorChoice::Auto, + ), + simplelog::WriteLogger::new( + simplelog::LevelFilter::Info, + simplelog::Config::default(), + std::fs::File::create(get_log_path()).unwrap(), + ), + ]); + } + + info!( + "Started - {} v{} ({}) compiled with {} on {} for {}", + PROFILE, + PKG_VERSION, + GIT_VERSION.unwrap_or("Unknown"), + RUSTC_VERSION, + BUILT_TIME_UTC, + TARGET + ); + debug!("Running under {}", current_exe().unwrap().display()); + debug!("Config path is {}", get_config_path().display()); + + let config_built = build_config(); + + let settings_config = match config_built { + Ok(settings) => settings, + Err(error) => { + warn!("Failed to load settings: {error}"); + match write_config_file() { + Ok(config) => config, + Err(error) => { + error!("Failed to create new settings file: {error}"); + return ExitCode::from(2); + } + } + } + }; + + let settings = settings_config + .try_deserialize::>() + .unwrap(); + + let args: Vec = args().collect(); + let with_steam = settings.get("steam").is_some_and(|steam| steam == "true"); + + let level = match args.get(1) { + Some(level) => level, + None => { + info!("Run with no arguments"); + if cfg!(target_os = "macos") { + // Handle .rdlevel/.rdzip/.zip files opened in macOS + debug!("Creating event loop to listen for file"); + + use tao::event::Event; + use tao::event_loop::ControlFlow; + use tao::event_loop::EventLoop; + + let event_loop = EventLoop::new(); + let mut empty_polls = 0; + + event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Wait; + + match event { + Event::Opened { urls } => { + info!("Opened event"); + if let Some(level) = urls.get(0) { + open_rhythm_doctor_with_level( + with_steam, + level.to_file_path().unwrap().display().to_string(), + ); + *control_flow = ControlFlow::ExitWithCode(0); + } else { + warn!("No URL found in opened event") + } + } + _ => { + empty_polls += 1; + // == 50 as we do not want to open the config file multiple times + if empty_polls == 50 { + warn!( + "No events for 50 polls, opening configuration file and closing" + ); + let _ = open_config_file().unwrap(); + *control_flow = ControlFlow::ExitWithCode(1); + } + } + } + }); + } else { + info!("Opening configuration file"); + let _ = open_config_file(); + return ExitCode::from(1); + } + } + }; + + open_rhythm_doctor_with_level(with_steam, level.to_string()); + ExitCode::from(0) +} + +fn open_rhythm_doctor_with_level(with_steam: bool, level: String) -> ExitCode { + info!("Opening Rhythm Doctor with level {}", level); + if let Err(error) = launch_rhythm_doctor(level, with_steam) { + error!("Failed to launch Rhythm Doctor: {error}"); + return ExitCode::from(2); + } + + return ExitCode::from(0); +} diff --git a/Launcher/src/rhythm_doctor.rs b/Launcher/src/rhythm_doctor.rs new file mode 100644 index 0000000..735cfdb --- /dev/null +++ b/Launcher/src/rhythm_doctor.rs @@ -0,0 +1,155 @@ +use log::{error, info, trace, warn}; +use opener::open; +use std::path::{Path, PathBuf}; +use std::process::Command; +use steamlocate::SteamDir; +use which::which; + +use crate::config_wrapper::write_path_file; + +/// Rhythm Doctor's App ID. +const APP_ID: u32 = 774181; + +/// Launch Rhythm Doctor with BepInEx. +/// Note that launching BepInEx is different on Windows, Linux, and macOS. +pub fn launch_rhythm_doctor(path: String, with_steam: bool) -> Result<(), String> { + trace!("Launching Rhythm Doctor"); + + info!("Launching Rhythm Doctor with BepInEx and path argument"); + + if with_steam { + // Launch by passing parameter directly to Steam + if let Some(steam_path) = find_steam_executable() { + if cfg!(target_os = "windows") { + // No additional action required + Command::new(steam_path) + .args(["-applaunch", APP_ID.to_string().as_str(), &path]) + .status() + .expect("Failed to launch Rhythm Doctor"); + return Ok(()); + } else if cfg!(target_os = "macos") { + Command::new(steam_path) + .args(["-applaunch", APP_ID.to_string().as_str(), &path]) + .status() + .expect("Failed to launch Rhythm Doctor"); + return Ok(()); + } else if cfg!(target_os = "linux") { + // Requires run_bepinex.sh script + Command::new(steam_path) + .args([ + "-applaunch", + APP_ID.to_string().as_str(), + "./run_bepinex.sh %command%", + &path, + ]) + .status() + .expect("Failed to launch Rhythm Doctor"); + return Ok(()); + } + } + + // Could't find Steam, fallback to using file + steam:// + warn!("Using file fallback method"); + match write_path_file() { + Some(error) => { + error!("Failed to write path file - {error}"); + } + None => match open("steam://run/".to_owned() + &APP_ID.to_string()) { + Ok(()) => { + return Ok(()); + } + Err(error) => { + error!("Failed to open steam:// - {error}"); + } + }, + } + } + + // Couldn't open Steam, fallback to using Rhythm Doctor (slow!) + warn!("Opening Rhythm Doctor directly"); + if let Some(mut path) = find_rhythm_doctor() { + if cfg!(target_os = "windows") { + path = path.join("Rhythm Doctor.exe"); + } else if cfg!(target_os = "macos") { + path = path.join("Rhythm Doctor.app"); + } else if cfg!(target_os = "linux") { + path = path.join("Rhythm Doctor"); + } else { + panic!("Unsupported OS"); + } + + open(path).expect("Failed to open Rhythm Doctor"); + return Ok(()); + } + + return Err("Couldn't open Rhythm Doctor".to_string()); +} + +/// Attempt to find the Steam executable. +fn find_steam_executable() -> Option { + trace!("Trying to find Steam on path"); + // TODO: Check if steam-native binary on some systems exists? + match which("steam") { + Ok(path) => return Some(path), + Err(error) => { + warn!("Couldn't find Steam on path - {error}"); + } + }; + + // Try to find Steam based on default install locations + trace!("Trying to find Steam based on default install locations"); + if cfg!(target_os = "windows") { + trace!(r"Checking for Steam executable at C:\Program Files (x86)\Steam\steam.exe"); + if Path::new(r"C:\Program Files (x86)\Steam\steam.exe").exists() { + info!(r"Found Steam executable at C:\Program Files (x86)\Steam\steam.exe"); + return Some(PathBuf::from(r"C:\Program Files (x86)\Steam\steam.exe")); + } + } else if cfg!(target_os = "macos") { + trace!("Checking for Steam executable at /Applications/Steam.app/Contents/MacOS/steam_osx"); + if Path::new("/Applications/Steam.app/Contents/MacOS/steam_osx").exists() { + info!("Found Steam executable at /Applications/Steam.app/Contents/MacOS/steam_osx"); + return Some(PathBuf::from( + "/Applications/Steam.app/Contents/MacOS/steam_osx", + )); + } + } else if cfg!(target_os = "linux") { + // TODO: Add flatpak, native, etc + // We should have better luck searching on PATH anyways. + // Official .deb package from https://cdn.cloudflare.steamstatic.com/client/installer/steam.deb + trace!("Checking for Steam executable at /usr/games/steam (Official)"); + if Path::new("/usr/games/steam").exists() { + info!("Found Steam executable at /usr/games/steam (Official)"); + return Some(PathBuf::from("/usr/games/steam")); + } + } + + // Couldn't find Steam + error!("Couldn't find Steam executable"); + None +} + +/// Get the path to Rhythm Doctor's install location +fn find_rhythm_doctor() -> Option { + trace!("Trying to find Rhythm Doctor install path"); + if let Ok(steam) = SteamDir::locate() { + if let Ok(rhythm_doctor) = steam.find_app(APP_ID) { + match rhythm_doctor { + Some((app, library)) => { + let path = library.resolve_app_dir(&app); + info!("Found Rhythm Doctor at {}", path.display()); + return Some(path); + } + None => { + error!("Couldn't find Rhythm Doctor (case 2)"); + return None; + } + } + } else { + error!("Couldn't find Rhythm Doctor (case 1)"); + return None; + } + } else { + error!("Couldn't find Steam"); + return None; + } +} From b9a12f8df19841cc4ffd53291de56ab2ca5a6341 Mon Sep 17 00:00:00 2001 From: Non <43197300+nonperforming@users.noreply.github.com> Date: Fri, 23 May 2025 19:54:04 +1200 Subject: [PATCH 03/16] Cleanup clippy messages --- Launcher/src/built.rs | 2 + Launcher/src/config_wrapper.rs | 6 +- Launcher/src/macos.rs | 45 ++++++++++ Launcher/src/main.rs | 147 +++++++++++++-------------------- Launcher/src/rhythm_doctor.rs | 60 ++++++++------ 5 files changed, 141 insertions(+), 119 deletions(-) create mode 100644 Launcher/src/macos.rs diff --git a/Launcher/src/built.rs b/Launcher/src/built.rs index ee17776..11e5b78 100644 --- a/Launcher/src/built.rs +++ b/Launcher/src/built.rs @@ -1 +1,3 @@ +//! Metainformation about the build, generated at compile-time. + include!(concat!(env!("OUT_DIR"), "/built.rs")); diff --git a/Launcher/src/config_wrapper.rs b/Launcher/src/config_wrapper.rs index 2012039..686a725 100644 --- a/Launcher/src/config_wrapper.rs +++ b/Launcher/src/config_wrapper.rs @@ -52,7 +52,7 @@ pub fn write_config_file() -> Result { Ok(mut file) => { let write = file.write_all(b"# Open Rhythm Doctor with Steam.\nsteam = true"); match write { - Ok(_) => { + Ok(()) => { info!("Created new settings file"); match build_config() { Ok(config) => { @@ -70,10 +70,10 @@ pub fn write_config_file() -> Result { } pub fn open_config_file() -> Result<(), String> { - if let Ok(_) = open(get_config_path()) { + if open(get_config_path()).is_ok() { return Ok(()); } - return Err("Failed to open settings file".to_string()); + Err("Failed to open settings file".to_owned()) } pub fn write_path_file() -> Option { diff --git a/Launcher/src/macos.rs b/Launcher/src/macos.rs new file mode 100644 index 0000000..13c818e --- /dev/null +++ b/Launcher/src/macos.rs @@ -0,0 +1,45 @@ +//! Handle .rdlevel/.rdzip/.zip files opened in macOS using an event loop + +#![cfg(target_os = "macos")] + +use log::{debug, info, warn}; +use tao::event::Event; +use tao::event_loop::ControlFlow; +use tao::event_loop::EventLoop; + +use crate::config_wrapper::open_config_file; +use crate::open_rhythm_doctor_with_level; + +/// Handle .rdlevel/.rdzip/.zip files opened in macOS +pub fn event_loop(with_steam: bool) -> ! { + debug!("Creating event loop to listen for file"); + + let event_loop = EventLoop::new(); + let mut empty_polls: u8 = 0; + + event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Wait; + + if let Event::Opened { urls } = event { + info!("Opened event"); + if let Some(level) = urls.first() { + open_rhythm_doctor_with_level( + with_steam, + &level.to_file_path().unwrap().display().to_string(), + ); + *control_flow = ControlFlow::ExitWithCode(0); + } else { + warn!("No URL found in opened event"); + } + } else { + // #[allow(clippy::arithmetic_side_effects)] // blocked by https://github.com/rust-lang/rust/issues/15701 + empty_polls += 1; + // == 50 as we do not want to open the config file multiple times + if empty_polls == 50 { + warn!("No events for 50 polls, opening configuration file and closing"); + open_config_file().unwrap(); + *control_flow = ControlFlow::ExitWithCode(1); + } + } + }); +} diff --git a/Launcher/src/main.rs b/Launcher/src/main.rs index cde6696..b8443a4 100644 --- a/Launcher/src/main.rs +++ b/Launcher/src/main.rs @@ -1,49 +1,26 @@ #![windows_subsystem = "windows"] -mod built; -mod config_wrapper; -mod rhythm_doctor; - use built::{BUILT_TIME_UTC, GIT_VERSION, PKG_VERSION, PROFILE, RUSTC_VERSION, TARGET}; -use config_wrapper::*; -use rhythm_doctor::*; +use config_wrapper::{ + build_config, get_config_path, get_log_path, open_config_file, write_config_file, +}; +#[cfg(target_os = "macos")] +use macos::event_loop; +use rhythm_doctor::launch_rhythm_doctor; use log::{debug, error, info, warn}; use std::collections::HashMap; use std::env::{args, current_exe}; use std::process::ExitCode; +mod built; +mod config_wrapper; +mod macos; +mod rhythm_doctor; + /// Forward the given launch option to Rhythm Doctor. fn main() -> ExitCode { - if cfg!(debug_assertions) { - let _ = simplelog::CombinedLogger::init(vec![ - simplelog::TermLogger::new( - simplelog::LevelFilter::Trace, - simplelog::Config::default(), - simplelog::TerminalMode::Stdout, - simplelog::ColorChoice::Auto, - ), - simplelog::WriteLogger::new( - simplelog::LevelFilter::Trace, - simplelog::Config::default(), - std::fs::File::create(get_log_path()).unwrap(), - ), - ]); - } else { - let _ = simplelog::CombinedLogger::init(vec![ - simplelog::TermLogger::new( - simplelog::LevelFilter::Info, - simplelog::Config::default(), - simplelog::TerminalMode::Stdout, - simplelog::ColorChoice::Auto, - ), - simplelog::WriteLogger::new( - simplelog::LevelFilter::Info, - simplelog::Config::default(), - std::fs::File::create(get_log_path()).unwrap(), - ), - ]); - } + init_log(); info!( "Started - {} v{} ({}) compiled with {} on {} for {}", @@ -80,68 +57,60 @@ fn main() -> ExitCode { let args: Vec = args().collect(); let with_steam = settings.get("steam").is_some_and(|steam| steam == "true"); - let level = match args.get(1) { - Some(level) => level, - None => { - info!("Run with no arguments"); - if cfg!(target_os = "macos") { - // Handle .rdlevel/.rdzip/.zip files opened in macOS - debug!("Creating event loop to listen for file"); - - use tao::event::Event; - use tao::event_loop::ControlFlow; - use tao::event_loop::EventLoop; - - let event_loop = EventLoop::new(); - let mut empty_polls = 0; - - event_loop.run(move |event, _, control_flow| { - *control_flow = ControlFlow::Wait; - - match event { - Event::Opened { urls } => { - info!("Opened event"); - if let Some(level) = urls.get(0) { - open_rhythm_doctor_with_level( - with_steam, - level.to_file_path().unwrap().display().to_string(), - ); - *control_flow = ControlFlow::ExitWithCode(0); - } else { - warn!("No URL found in opened event") - } - } - _ => { - empty_polls += 1; - // == 50 as we do not want to open the config file multiple times - if empty_polls == 50 { - warn!( - "No events for 50 polls, opening configuration file and closing" - ); - let _ = open_config_file().unwrap(); - *control_flow = ControlFlow::ExitWithCode(1); - } - } - } - }); - } else { - info!("Opening configuration file"); - let _ = open_config_file(); - return ExitCode::from(1); - } + let Some(level) = args.get(1) else { + info!("Run with no arguments"); + if cfg!(target_os = "macos") { + event_loop(with_steam); + } else { + info!("Opening configuration file"); + let _ = open_config_file(); + return ExitCode::from(1); } }; - open_rhythm_doctor_with_level(with_steam, level.to_string()); + open_rhythm_doctor_with_level(with_steam, level); ExitCode::from(0) } -fn open_rhythm_doctor_with_level(with_steam: bool, level: String) -> ExitCode { - info!("Opening Rhythm Doctor with level {}", level); +/// Sets up logging +fn init_log() { + if cfg!(debug_assertions) { + let _ = simplelog::CombinedLogger::init(vec![ + simplelog::TermLogger::new( + simplelog::LevelFilter::Trace, + simplelog::Config::default(), + simplelog::TerminalMode::Stdout, + simplelog::ColorChoice::Auto, + ), + simplelog::WriteLogger::new( + simplelog::LevelFilter::Trace, + simplelog::Config::default(), + std::fs::File::create(get_log_path()).unwrap(), + ), + ]); + } else { + let _ = simplelog::CombinedLogger::init(vec![ + simplelog::TermLogger::new( + simplelog::LevelFilter::Info, + simplelog::Config::default(), + simplelog::TerminalMode::Stdout, + simplelog::ColorChoice::Auto, + ), + simplelog::WriteLogger::new( + simplelog::LevelFilter::Info, + simplelog::Config::default(), + std::fs::File::create(get_log_path()).unwrap(), + ), + ]); + } +} + +fn open_rhythm_doctor_with_level(with_steam: bool, level: &str) -> ExitCode { + info!("Opening Rhythm Doctor with level {level}"); if let Err(error) = launch_rhythm_doctor(level, with_steam) { error!("Failed to launch Rhythm Doctor: {error}"); return ExitCode::from(2); } - return ExitCode::from(0); -} + ExitCode::from(0) +} \ No newline at end of file diff --git a/Launcher/src/rhythm_doctor.rs b/Launcher/src/rhythm_doctor.rs index 735cfdb..d2ce8ad 100644 --- a/Launcher/src/rhythm_doctor.rs +++ b/Launcher/src/rhythm_doctor.rs @@ -1,3 +1,5 @@ +//! Find and launch Rhythm Doctor with arguments and Steam. + use log::{error, info, trace, warn}; use opener::open; use std::path::{Path, PathBuf}; @@ -8,11 +10,15 @@ use which::which; use crate::config_wrapper::write_path_file; /// Rhythm Doctor's App ID. +#[allow(clippy::unreadable_literal)] const APP_ID: u32 = 774181; -/// Launch Rhythm Doctor with BepInEx. +const APP_ID_STR: &str = "774181"; + +#[allow(clippy::doc_markdown)] +/// Launch Rhythm Doctor with [BepInEx](https://docs.bepinex.dev/index.html). /// Note that launching BepInEx is different on Windows, Linux, and macOS. -pub fn launch_rhythm_doctor(path: String, with_steam: bool) -> Result<(), String> { +pub fn launch_rhythm_doctor(path: &str, with_steam: bool) -> Result<(), String> { trace!("Launching Rhythm Doctor"); info!("Launching Rhythm Doctor with BepInEx and path argument"); @@ -23,13 +29,13 @@ pub fn launch_rhythm_doctor(path: String, with_steam: bool) -> Result<(), String if cfg!(target_os = "windows") { // No additional action required Command::new(steam_path) - .args(["-applaunch", APP_ID.to_string().as_str(), &path]) + .args(["-applaunch", APP_ID_STR, path]) .status() .expect("Failed to launch Rhythm Doctor"); return Ok(()); } else if cfg!(target_os = "macos") { Command::new(steam_path) - .args(["-applaunch", APP_ID.to_string().as_str(), &path]) + .args(["-applaunch", APP_ID_STR, path]) .status() .expect("Failed to launch Rhythm Doctor"); return Ok(()); @@ -38,9 +44,9 @@ pub fn launch_rhythm_doctor(path: String, with_steam: bool) -> Result<(), String Command::new(steam_path) .args([ "-applaunch", - APP_ID.to_string().as_str(), + APP_ID_STR, "./run_bepinex.sh %command%", - &path, + path, ]) .status() .expect("Failed to launch Rhythm Doctor"); @@ -54,7 +60,7 @@ pub fn launch_rhythm_doctor(path: String, with_steam: bool) -> Result<(), String Some(error) => { error!("Failed to write path file - {error}"); } - None => match open("steam://run/".to_owned() + &APP_ID.to_string()) { + None => match open("steam://run/".to_owned() + APP_ID_STR) { Ok(()) => { return Ok(()); } @@ -67,22 +73,25 @@ pub fn launch_rhythm_doctor(path: String, with_steam: bool) -> Result<(), String // Couldn't open Steam, fallback to using Rhythm Doctor (slow!) warn!("Opening Rhythm Doctor directly"); - if let Some(mut path) = find_rhythm_doctor() { + if let Some(mut game_path) = find_rhythm_doctor() { if cfg!(target_os = "windows") { - path = path.join("Rhythm Doctor.exe"); + game_path = game_path.join("Rhythm Doctor.exe"); } else if cfg!(target_os = "macos") { - path = path.join("Rhythm Doctor.app"); + game_path = game_path.join("Rhythm Doctor.app"); } else if cfg!(target_os = "linux") { - path = path.join("Rhythm Doctor"); + game_path = game_path.join("Rhythm Doctor"); } else { - panic!("Unsupported OS"); + return Err("Unsupported OS".to_owned()); } - open(path).expect("Failed to open Rhythm Doctor"); + Command::new(game_path) + .arg(path) + .status() + .expect("Failed to launch Rhythm Doctor"); return Ok(()); } - return Err("Couldn't open Rhythm Doctor".to_string()); + Err("Couldn't open Rhythm Doctor".to_owned()) } /// Attempt to find the Steam executable. @@ -94,7 +103,7 @@ fn find_steam_executable() -> Option { Err(error) => { warn!("Couldn't find Steam on path - {error}"); } - }; + } // Try to find Steam based on default install locations trace!("Trying to find Steam based on default install locations"); @@ -133,23 +142,20 @@ fn find_rhythm_doctor() -> Option { trace!("Trying to find Rhythm Doctor install path"); if let Ok(steam) = SteamDir::locate() { if let Ok(rhythm_doctor) = steam.find_app(APP_ID) { - match rhythm_doctor { - Some((app, library)) => { - let path = library.resolve_app_dir(&app); - info!("Found Rhythm Doctor at {}", path.display()); - return Some(path); - } - None => { - error!("Couldn't find Rhythm Doctor (case 2)"); - return None; - } + if let Some((app, library)) = rhythm_doctor { + let path = library.resolve_app_dir(&app); + info!("Found Rhythm Doctor at {}", path.display()); + Some(path) + } else { + error!("Couldn't find Rhythm Doctor (case 2)"); + None } } else { error!("Couldn't find Rhythm Doctor (case 1)"); - return None; + None } } else { error!("Couldn't find Steam"); - return None; + None } } From 9a7229652a862879cb4fdca818df3cd048f084f8 Mon Sep 17 00:00:00 2001 From: Non <43197300+nonperforming@users.noreply.github.com> Date: Fri, 23 May 2025 20:03:27 +1200 Subject: [PATCH 04/16] Simplify launching Rhythm Doctor --- Launcher/src/rhythm_doctor.rs | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/Launcher/src/rhythm_doctor.rs b/Launcher/src/rhythm_doctor.rs index d2ce8ad..675f3fe 100644 --- a/Launcher/src/rhythm_doctor.rs +++ b/Launcher/src/rhythm_doctor.rs @@ -26,32 +26,11 @@ pub fn launch_rhythm_doctor(path: &str, with_steam: bool) -> Result<(), String> if with_steam { // Launch by passing parameter directly to Steam if let Some(steam_path) = find_steam_executable() { - if cfg!(target_os = "windows") { - // No additional action required - Command::new(steam_path) - .args(["-applaunch", APP_ID_STR, path]) - .status() - .expect("Failed to launch Rhythm Doctor"); - return Ok(()); - } else if cfg!(target_os = "macos") { - Command::new(steam_path) - .args(["-applaunch", APP_ID_STR, path]) - .status() - .expect("Failed to launch Rhythm Doctor"); - return Ok(()); - } else if cfg!(target_os = "linux") { - // Requires run_bepinex.sh script - Command::new(steam_path) - .args([ - "-applaunch", - APP_ID_STR, - "./run_bepinex.sh %command%", - path, - ]) - .status() - .expect("Failed to launch Rhythm Doctor"); - return Ok(()); - } + Command::new(steam_path) + .args(["-applaunch", APP_ID_STR, path]) + .status() + .expect("Failed to launch Rhythm Doctor"); + return Ok(()); } // Could't find Steam, fallback to using file + steam:// From 22fbd4905893b82b9d9869691f683ecdb9c18334 Mon Sep 17 00:00:00 2001 From: Non <43197300+nonperforming@users.noreply.github.com> Date: Fri, 23 May 2025 20:07:56 +1200 Subject: [PATCH 05/16] Move write_path_file to rhythm_doctor.rs --- Launcher/src/config_wrapper.rs | 6 ------ Launcher/src/rhythm_doctor.rs | 9 +++++++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Launcher/src/config_wrapper.rs b/Launcher/src/config_wrapper.rs index 686a725..e9a1f77 100644 --- a/Launcher/src/config_wrapper.rs +++ b/Launcher/src/config_wrapper.rs @@ -75,9 +75,3 @@ pub fn open_config_file() -> Result<(), String> { } Err("Failed to open settings file".to_owned()) } - -pub fn write_path_file() -> Option { - todo!( - "Implement path file to write to when finding Steam fails (use steam://run/APPID instead)" - ); -} diff --git a/Launcher/src/rhythm_doctor.rs b/Launcher/src/rhythm_doctor.rs index 675f3fe..ffb09f5 100644 --- a/Launcher/src/rhythm_doctor.rs +++ b/Launcher/src/rhythm_doctor.rs @@ -7,8 +7,6 @@ use std::process::Command; use steamlocate::SteamDir; use which::which; -use crate::config_wrapper::write_path_file; - /// Rhythm Doctor's App ID. #[allow(clippy::unreadable_literal)] const APP_ID: u32 = 774181; @@ -73,6 +71,13 @@ pub fn launch_rhythm_doctor(path: &str, with_steam: bool) -> Result<(), String> Err("Couldn't open Rhythm Doctor".to_owned()) } +/// Write to the file the RhythmDoctor.EditorLaunch plugin will look for to load rdlevel/rdzip. +pub fn write_path_file() -> Option { + todo!( + "Implement path file to write to when finding Steam fails (use steam://run/APPID instead)" + ); +} + /// Attempt to find the Steam executable. fn find_steam_executable() -> Option { trace!("Trying to find Steam on path"); From 951cf12b03c700f279db0424b4afe85d54af2497 Mon Sep 17 00:00:00 2001 From: Non <43197300+nonperforming@users.noreply.github.com> Date: Mon, 26 May 2025 14:22:47 +1200 Subject: [PATCH 06/16] Create launcher.yml --- .github/workflows/launcher.yml | 47 ++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .github/workflows/launcher.yml diff --git a/.github/workflows/launcher.yml b/.github/workflows/launcher.yml new file mode 100644 index 0000000..033e20d --- /dev/null +++ b/.github/workflows/launcher.yml @@ -0,0 +1,47 @@ +name: Build Launcher + +on: + push: + paths: + - Launcher + - .github/workflows/launcher.yml + pull_request: + paths: + - Launcher + - .github/workflows/launcher.yml + workflow_call: + +env: + CARGO_TERM_COLOR: always + +jobs: + build_launcher: + name: Build Launcher + runs-on: ${{ matrix.os }} + defaults: + run: + working-directory: ./Launcher + strategy: + matrix: + toolchain: + - stable + - nightly + os: + - windows-latest + - ubuntu-latest + - macos-latest + - windows-11-arm + - ubuntu-24.04-arm + steps: + - name: Checkout + uses: actions/checkout@v4.2.2 + - name: Setup Rust + run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} + - name: Build + run: cargo build --verbose + - name: Upload artifact + uses: actions/upload-artifact@v4.6.2 + with: + name: ${{ matrix.os }}-${{ matrix.toolchain }} + path: ^target/debug/rhythm_doctor_launcher(?:\.exe)?$ + if-no-files-found: error From 66a42fb52a73b039cfd05606f3fba717bc45d35b Mon Sep 17 00:00:00 2001 From: Non <43197300+nonperforming@users.noreply.github.com> Date: Mon, 26 May 2025 14:27:47 +1200 Subject: [PATCH 07/16] ci: Fix ARM builds --- .github/workflows/launcher.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/launcher.yml b/.github/workflows/launcher.yml index 033e20d..10008db 100644 --- a/.github/workflows/launcher.yml +++ b/.github/workflows/launcher.yml @@ -35,8 +35,10 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4.2.2 - - name: Setup Rust - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} + - name: Setup rust + uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b + with: + toolchain: ${{ matrix.toolchain }} - name: Build run: cargo build --verbose - name: Upload artifact From 2577ca4c175bac33e8545ec963a5bf39b8c83f7b Mon Sep 17 00:00:00 2001 From: Non <43197300+nonperforming@users.noreply.github.com> Date: Mon, 26 May 2025 14:42:18 +1200 Subject: [PATCH 08/16] Use #[cfg()] instead of if cfg!() Actually conditionally compile instead of checking at runtime --- Launcher/src/config_wrapper.rs | 9 ++-- Launcher/src/main.rs | 85 +++++++++++++++++++--------------- Launcher/src/rhythm_doctor.rs | 29 ++++++++---- 3 files changed, 74 insertions(+), 49 deletions(-) diff --git a/Launcher/src/config_wrapper.rs b/Launcher/src/config_wrapper.rs index e9a1f77..50f8860 100644 --- a/Launcher/src/config_wrapper.rs +++ b/Launcher/src/config_wrapper.rs @@ -20,9 +20,11 @@ pub fn get_config_path() -> PathBuf { fn get_parent_folder() -> PathBuf { let current_exe = current_exe().unwrap(); - if cfg!(target_os = "windows") || cfg!(target_os = "linux") { - return current_exe.parent().unwrap().to_path_buf(); - } else if cfg!(target_os = "macos") { + #[cfg(not(target_os = "macos"))] + return current_exe.parent().unwrap().to_path_buf(); + + #[cfg(target_os = "macos")] + { // MacOS has "application" *folders* (folders with the extension .app), // so we need to navigate up this. return current_exe // rhythm_doctor_editor_launcher @@ -36,7 +38,6 @@ fn get_parent_folder() -> PathBuf { .unwrap() .to_path_buf(); } - panic!("Unsupported OS"); } pub fn build_config() -> Result { diff --git a/Launcher/src/main.rs b/Launcher/src/main.rs index b8443a4..5a79979 100644 --- a/Launcher/src/main.rs +++ b/Launcher/src/main.rs @@ -2,10 +2,8 @@ use built::{BUILT_TIME_UTC, GIT_VERSION, PKG_VERSION, PROFILE, RUSTC_VERSION, TARGET}; use config_wrapper::{ - build_config, get_config_path, get_log_path, open_config_file, write_config_file, + build_config, get_config_path, get_log_path, write_config_file, }; -#[cfg(target_os = "macos")] -use macos::event_loop; use rhythm_doctor::launch_rhythm_doctor; use log::{debug, error, info, warn}; @@ -15,9 +13,19 @@ use std::process::ExitCode; mod built; mod config_wrapper; -mod macos; mod rhythm_doctor; +// MacOS +#[cfg(target_os = "macos")] +use macos::event_loop; + +#[cfg(target_os = "macos")] +mod macos; + +// Not MacOS +#[cfg(not(target_os = "macos"))] +use config_wrapper::open_config_file; + /// Forward the given launch option to Rhythm Doctor. fn main() -> ExitCode { init_log(); @@ -59,9 +67,12 @@ fn main() -> ExitCode { let Some(level) = args.get(1) else { info!("Run with no arguments"); - if cfg!(target_os = "macos") { - event_loop(with_steam); - } else { + + #[cfg(target_os = "macos")] + event_loop(with_steam); + + #[cfg(not(target_os = "macos"))] + { info!("Opening configuration file"); let _ = open_config_file(); return ExitCode::from(1); @@ -74,35 +85,35 @@ fn main() -> ExitCode { /// Sets up logging fn init_log() { - if cfg!(debug_assertions) { - let _ = simplelog::CombinedLogger::init(vec![ - simplelog::TermLogger::new( - simplelog::LevelFilter::Trace, - simplelog::Config::default(), - simplelog::TerminalMode::Stdout, - simplelog::ColorChoice::Auto, - ), - simplelog::WriteLogger::new( - simplelog::LevelFilter::Trace, - simplelog::Config::default(), - std::fs::File::create(get_log_path()).unwrap(), - ), - ]); - } else { - let _ = simplelog::CombinedLogger::init(vec![ - simplelog::TermLogger::new( - simplelog::LevelFilter::Info, - simplelog::Config::default(), - simplelog::TerminalMode::Stdout, - simplelog::ColorChoice::Auto, - ), - simplelog::WriteLogger::new( - simplelog::LevelFilter::Info, - simplelog::Config::default(), - std::fs::File::create(get_log_path()).unwrap(), - ), - ]); - } + #[cfg(debug_assertions)] + let _ = simplelog::CombinedLogger::init(vec![ + simplelog::TermLogger::new( + simplelog::LevelFilter::Trace, + simplelog::Config::default(), + simplelog::TerminalMode::Stdout, + simplelog::ColorChoice::Auto, + ), + simplelog::WriteLogger::new( + simplelog::LevelFilter::Trace, + simplelog::Config::default(), + std::fs::File::create(get_log_path()).unwrap(), + ), + ]); + + #[cfg(not(debug_assertions))] + let _ = simplelog::CombinedLogger::init(vec![ + simplelog::TermLogger::new( + simplelog::LevelFilter::Info, + simplelog::Config::default(), + simplelog::TerminalMode::Stdout, + simplelog::ColorChoice::Auto, + ), + simplelog::WriteLogger::new( + simplelog::LevelFilter::Info, + simplelog::Config::default(), + std::fs::File::create(get_log_path()).unwrap(), + ), + ]); } fn open_rhythm_doctor_with_level(with_steam: bool, level: &str) -> ExitCode { @@ -113,4 +124,4 @@ fn open_rhythm_doctor_with_level(with_steam: bool, level: &str) -> ExitCode { } ExitCode::from(0) -} \ No newline at end of file +} diff --git a/Launcher/src/rhythm_doctor.rs b/Launcher/src/rhythm_doctor.rs index ffb09f5..2318fbe 100644 --- a/Launcher/src/rhythm_doctor.rs +++ b/Launcher/src/rhythm_doctor.rs @@ -51,14 +51,19 @@ pub fn launch_rhythm_doctor(path: &str, with_steam: bool) -> Result<(), String> // Couldn't open Steam, fallback to using Rhythm Doctor (slow!) warn!("Opening Rhythm Doctor directly"); if let Some(mut game_path) = find_rhythm_doctor() { - if cfg!(target_os = "windows") { + #[cfg(target_os = "windows")] + { game_path = game_path.join("Rhythm Doctor.exe"); - } else if cfg!(target_os = "macos") { + } + + #[cfg(target_os = "macos")] + { game_path = game_path.join("Rhythm Doctor.app"); - } else if cfg!(target_os = "linux") { + } + + #[cfg(target_os = "linux")] + { game_path = game_path.join("Rhythm Doctor"); - } else { - return Err("Unsupported OS".to_owned()); } Command::new(game_path) @@ -91,13 +96,18 @@ fn find_steam_executable() -> Option { // Try to find Steam based on default install locations trace!("Trying to find Steam based on default install locations"); - if cfg!(target_os = "windows") { + + #[cfg(target_os = "windows")] + { trace!(r"Checking for Steam executable at C:\Program Files (x86)\Steam\steam.exe"); if Path::new(r"C:\Program Files (x86)\Steam\steam.exe").exists() { info!(r"Found Steam executable at C:\Program Files (x86)\Steam\steam.exe"); return Some(PathBuf::from(r"C:\Program Files (x86)\Steam\steam.exe")); } - } else if cfg!(target_os = "macos") { + } + + #[cfg(target_os = "macos")] + { trace!("Checking for Steam executable at /Applications/Steam.app/Contents/MacOS/steam_osx"); if Path::new("/Applications/Steam.app/Contents/MacOS/steam_osx").exists() { info!("Found Steam executable at /Applications/Steam.app/Contents/MacOS/steam_osx"); @@ -105,7 +115,10 @@ fn find_steam_executable() -> Option { "/Applications/Steam.app/Contents/MacOS/steam_osx", )); } - } else if cfg!(target_os = "linux") { + } + + #[cfg(target_os = "linux")] + { // TODO: Add flatpak, native, etc // We should have better luck searching on PATH anyways. // Official .deb package from https://cdn.cloudflare.steamstatic.com/client/installer/steam.deb From aa17ce4a9cb08f5a9894c939b949d2e3f5cdb1d3 Mon Sep 17 00:00:00 2001 From: Non <43197300+nonperforming@users.noreply.github.com> Date: Mon, 26 May 2025 14:44:45 +1200 Subject: [PATCH 09/16] Include all files in Launcher to autorun --- .github/workflows/launcher.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/launcher.yml b/.github/workflows/launcher.yml index 10008db..5c6c0c3 100644 --- a/.github/workflows/launcher.yml +++ b/.github/workflows/launcher.yml @@ -3,11 +3,11 @@ name: Build Launcher on: push: paths: - - Launcher + - Launcher/* - .github/workflows/launcher.yml pull_request: paths: - - Launcher + - Launcher/* - .github/workflows/launcher.yml workflow_call: From 823b95fa5a914a758b715af13889b97c2120d821 Mon Sep 17 00:00:00 2001 From: Non <43197300+nonperforming@users.noreply.github.com> Date: Mon, 26 May 2025 14:48:09 +1200 Subject: [PATCH 10/16] ci: Fix uploading artifacts --- .github/workflows/launcher.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/launcher.yml b/.github/workflows/launcher.yml index 5c6c0c3..4d142d1 100644 --- a/.github/workflows/launcher.yml +++ b/.github/workflows/launcher.yml @@ -3,7 +3,7 @@ name: Build Launcher on: push: paths: - - Launcher/* + - Launcher/** - .github/workflows/launcher.yml pull_request: paths: @@ -11,9 +11,6 @@ on: - .github/workflows/launcher.yml workflow_call: -env: - CARGO_TERM_COLOR: always - jobs: build_launcher: name: Build Launcher @@ -35,7 +32,7 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4.2.2 - - name: Setup rust + - name: Setup Rust uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b with: toolchain: ${{ matrix.toolchain }} @@ -45,5 +42,8 @@ jobs: uses: actions/upload-artifact@v4.6.2 with: name: ${{ matrix.os }}-${{ matrix.toolchain }} - path: ^target/debug/rhythm_doctor_launcher(?:\.exe)?$ + path: | + ${{ github.workspace }}/Launcher/target/debug/rhythm_doctor_editor_launcher + ${{ github.workspace }}/Launcher/target/debug/rhythm_doctor_editor_launcher.exe + ${{ github.workspace }}/Launcher/target/debug/rhythm_doctor_editor_launcher.pdb if-no-files-found: error From f8ae6b6a510d1ffb3599602ed7bf8efe2b715f6b Mon Sep 17 00:00:00 2001 From: Non <43197300+nonperforming@users.noreply.github.com> Date: Wed, 28 May 2025 12:12:53 +1200 Subject: [PATCH 11/16] Launcher: Cleanup --- Launcher/Cargo.lock | 2 +- Launcher/Cargo.toml | 2 +- Launcher/src/config_wrapper.rs | 4 ++-- Launcher/src/macos.rs | 2 -- Launcher/src/main.rs | 16 +++++++--------- Launcher/src/rhythm_doctor.rs | 22 +++++++++------------- 6 files changed, 20 insertions(+), 28 deletions(-) diff --git a/Launcher/Cargo.lock b/Launcher/Cargo.lock index 13ef2bc..88eb711 100644 --- a/Launcher/Cargo.lock +++ b/Launcher/Cargo.lock @@ -1444,7 +1444,7 @@ checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" [[package]] name = "rhythm_doctor_editor_launcher" -version = "0.3.0" +version = "0.3.1" dependencies = [ "built", "config", diff --git a/Launcher/Cargo.toml b/Launcher/Cargo.toml index 21c96b0..462cf81 100644 --- a/Launcher/Cargo.toml +++ b/Launcher/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rhythm_doctor_editor_launcher" -version = "0.3.0" +version = "0.3.1" edition = "2024" description = "Helper app for the RhythmDoctor.EditorLaunch plugin" readme = "../README.md" diff --git a/Launcher/src/config_wrapper.rs b/Launcher/src/config_wrapper.rs index 50f8860..01ef39e 100644 --- a/Launcher/src/config_wrapper.rs +++ b/Launcher/src/config_wrapper.rs @@ -27,7 +27,7 @@ fn get_parent_folder() -> PathBuf { { // MacOS has "application" *folders* (folders with the extension .app), // so we need to navigate up this. - return current_exe // rhythm_doctor_editor_launcher + current_exe // rhythm_doctor_editor_launcher .parent() // MacOS .unwrap() .parent() // Contents @@ -36,7 +36,7 @@ fn get_parent_folder() -> PathBuf { .unwrap() .parent() .unwrap() - .to_path_buf(); + .to_path_buf() } } diff --git a/Launcher/src/macos.rs b/Launcher/src/macos.rs index 13c818e..58b1daa 100644 --- a/Launcher/src/macos.rs +++ b/Launcher/src/macos.rs @@ -1,7 +1,5 @@ //! Handle .rdlevel/.rdzip/.zip files opened in macOS using an event loop -#![cfg(target_os = "macos")] - use log::{debug, info, warn}; use tao::event::Event; use tao::event_loop::ControlFlow; diff --git a/Launcher/src/main.rs b/Launcher/src/main.rs index 5a79979..9e01a3e 100644 --- a/Launcher/src/main.rs +++ b/Launcher/src/main.rs @@ -1,9 +1,11 @@ #![windows_subsystem = "windows"] +mod built; +mod config_wrapper; +mod rhythm_doctor; + use built::{BUILT_TIME_UTC, GIT_VERSION, PKG_VERSION, PROFILE, RUSTC_VERSION, TARGET}; -use config_wrapper::{ - build_config, get_config_path, get_log_path, write_config_file, -}; +use config_wrapper::{build_config, get_config_path, get_log_path, write_config_file}; use rhythm_doctor::launch_rhythm_doctor; use log::{debug, error, info, warn}; @@ -11,16 +13,12 @@ use std::collections::HashMap; use std::env::{args, current_exe}; use std::process::ExitCode; -mod built; -mod config_wrapper; -mod rhythm_doctor; - // MacOS #[cfg(target_os = "macos")] -use macos::event_loop; +mod macos; #[cfg(target_os = "macos")] -mod macos; +use macos::event_loop; // Not MacOS #[cfg(not(target_os = "macos"))] diff --git a/Launcher/src/rhythm_doctor.rs b/Launcher/src/rhythm_doctor.rs index 2318fbe..ae20e25 100644 --- a/Launcher/src/rhythm_doctor.rs +++ b/Launcher/src/rhythm_doctor.rs @@ -50,21 +50,17 @@ pub fn launch_rhythm_doctor(path: &str, with_steam: bool) -> Result<(), String> // Couldn't open Steam, fallback to using Rhythm Doctor (slow!) warn!("Opening Rhythm Doctor directly"); - if let Some(mut game_path) = find_rhythm_doctor() { - #[cfg(target_os = "windows")] - { - game_path = game_path.join("Rhythm Doctor.exe"); - } + if let Some(game_path) = find_rhythm_doctor() { + let game_path: PathBuf = { + #[cfg(target_os = "windows")] + { game_path.join("Rhythm Doctor.exe") } - #[cfg(target_os = "macos")] - { - game_path = game_path.join("Rhythm Doctor.app"); - } + #[cfg(target_os = "macos")] + { game_path.join("Rhythm Doctor.app") } - #[cfg(target_os = "linux")] - { - game_path = game_path.join("Rhythm Doctor"); - } + #[cfg(target_os = "linux")] + { game_path.join("Rhythm Doctor") } + }; Command::new(game_path) .arg(path) From 4522260d65f2b4f8b82db1efaeeb1b1a01b55066 Mon Sep 17 00:00:00 2001 From: Non <43197300+nonperforming@users.noreply.github.com> Date: Wed, 28 May 2025 16:41:16 +1200 Subject: [PATCH 12/16] ci: Cache dependencies --- .github/workflows/launcher.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/launcher.yml b/.github/workflows/launcher.yml index 4d142d1..5e47225 100644 --- a/.github/workflows/launcher.yml +++ b/.github/workflows/launcher.yml @@ -36,8 +36,12 @@ jobs: uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b with: toolchain: ${{ matrix.toolchain }} + - name: Cache dependencies + uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 + with: + key: ${{ steps.toolchain.outputs.cachekey }} - name: Build - run: cargo build --verbose + run: cargo +${{ steps.toolchain.outputs.name }} build --verbose - name: Upload artifact uses: actions/upload-artifact@v4.6.2 with: From c00641107979cda29ffab672851c968bcf52e8b7 Mon Sep 17 00:00:00 2001 From: Non <43197300+nonperforming@users.noreply.github.com> Date: Wed, 28 May 2025 16:47:50 +1200 Subject: [PATCH 13/16] ci: Fix rust-cache workspace --- .github/workflows/launcher.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/launcher.yml b/.github/workflows/launcher.yml index 5e47225..a18baa5 100644 --- a/.github/workflows/launcher.yml +++ b/.github/workflows/launcher.yml @@ -19,6 +19,7 @@ jobs: run: working-directory: ./Launcher strategy: + fail-fast: false matrix: toolchain: - stable @@ -40,6 +41,7 @@ jobs: uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 with: key: ${{ steps.toolchain.outputs.cachekey }} + workspaces: "./Launcher -> target" - name: Build run: cargo +${{ steps.toolchain.outputs.name }} build --verbose - name: Upload artifact From 8b71c0e0165f556d2e1053bb3fe52bc71a92cbad Mon Sep 17 00:00:00 2001 From: Non <43197300+nonperforming@users.noreply.github.com> Date: Wed, 28 May 2025 16:53:35 +1200 Subject: [PATCH 14/16] ci: Fix empty toolchain expression --- .github/workflows/launcher.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/launcher.yml b/.github/workflows/launcher.yml index a18baa5..d50290f 100644 --- a/.github/workflows/launcher.yml +++ b/.github/workflows/launcher.yml @@ -35,15 +35,16 @@ jobs: uses: actions/checkout@v4.2.2 - name: Setup Rust uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b + id: rust with: toolchain: ${{ matrix.toolchain }} - name: Cache dependencies uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 with: - key: ${{ steps.toolchain.outputs.cachekey }} + key: ${{ steps.rust.outputs.cachekey }} workspaces: "./Launcher -> target" - name: Build - run: cargo +${{ steps.toolchain.outputs.name }} build --verbose + run: cargo +${{ steps.rust.outputs.name }} build --verbose - name: Upload artifact uses: actions/upload-artifact@v4.6.2 with: From 7e2387afb3bd924ce8a115e226d58aa83fe904dd Mon Sep 17 00:00:00 2001 From: Non <43197300+nonperforming@users.noreply.github.com> Date: Fri, 30 May 2025 13:26:10 +1200 Subject: [PATCH 15/16] Cleanup macOS event loop --- Launcher/src/macos.rs | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/Launcher/src/macos.rs b/Launcher/src/macos.rs index 58b1daa..6339aa4 100644 --- a/Launcher/src/macos.rs +++ b/Launcher/src/macos.rs @@ -1,6 +1,6 @@ //! Handle .rdlevel/.rdzip/.zip files opened in macOS using an event loop -use log::{debug, info, warn}; +use log::{debug, info, trace, warn}; use tao::event::Event; use tao::event_loop::ControlFlow; use tao::event_loop::EventLoop; @@ -12,32 +12,39 @@ use crate::open_rhythm_doctor_with_level; pub fn event_loop(with_steam: bool) -> ! { debug!("Creating event loop to listen for file"); - let event_loop = EventLoop::new(); - let mut empty_polls: u8 = 0; - - event_loop.run(move |event, _, control_flow| { + let mut exiting = false; + EventLoop::new().run(move |event, _, control_flow| { *control_flow = ControlFlow::Wait; + if exiting { + // Do not process events when we're exiting. + // In theory we should be able to check `*control_flow == ControlFlow::Exit`, + // as it is "sticky" but control_flow always seems to be set to ControlFlow::Wait + return; + } + + trace!("Control flow: {:?}", control_flow); + trace!("Event: {:?}", event); + if let Event::Opened { urls } = event { - info!("Opened event"); + info!("Got Opened event"); if let Some(level) = urls.first() { open_rhythm_doctor_with_level( with_steam, &level.to_file_path().unwrap().display().to_string(), ); *control_flow = ControlFlow::ExitWithCode(0); + exiting = true; } else { warn!("No URL found in opened event"); + *control_flow = ControlFlow::ExitWithCode(2); + exiting = true; } } else { - // #[allow(clippy::arithmetic_side_effects)] // blocked by https://github.com/rust-lang/rust/issues/15701 - empty_polls += 1; - // == 50 as we do not want to open the config file multiple times - if empty_polls == 50 { - warn!("No events for 50 polls, opening configuration file and closing"); - open_config_file().unwrap(); - *control_flow = ControlFlow::ExitWithCode(1); - } + warn!("No Opened event, opening configuration file"); + open_config_file().unwrap(); + *control_flow = ControlFlow::ExitWithCode(1); + exiting = true; } }); } From 76140b3298d0eddd990edebfd1b3297b7fd000dd Mon Sep 17 00:00:00 2001 From: Non <43197300+nonperforming@users.noreply.github.com> Date: Fri, 30 May 2025 13:26:39 +1200 Subject: [PATCH 16/16] Add doc to rhythm_doctor::APP_ID_STR --- Launcher/src/rhythm_doctor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Launcher/src/rhythm_doctor.rs b/Launcher/src/rhythm_doctor.rs index ae20e25..8a4874b 100644 --- a/Launcher/src/rhythm_doctor.rs +++ b/Launcher/src/rhythm_doctor.rs @@ -10,7 +10,7 @@ use which::which; /// Rhythm Doctor's App ID. #[allow(clippy::unreadable_literal)] const APP_ID: u32 = 774181; - +/// Rhythm Doctor's App ID. const APP_ID_STR: &str = "774181"; #[allow(clippy::doc_markdown)]