From 46c1a8be3a9bb4a3438c22a11bed244970b74236 Mon Sep 17 00:00:00 2001 From: lawrencecchen <54008264+lawrencecchen@users.noreply.github.com> Date: Wed, 8 Jul 2026 15:11:31 -0700 Subject: [PATCH 1/4] =?UTF-8?q?mux:=20modernize=20Rust=20workspace=20?= =?UTF-8?q?=E2=80=94=20edition=202024,=20MSRV=201.88,=20latest=20deps,=20w?= =?UTF-8?q?orkspace=20lints?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Edition 2021->2024 across all crates incl. cmux-client (explicit unsafe blocks in FFI per unsafe_op_in_unsafe_fn). Deps: crossterm 0.29, ratatui 0.30.2, tungstenite 0.29 (Utf8Bytes/Bytes API), bindgen 0.72.1; libc stays 0.2 (1.0 is pre-release alpha). Workspace lints table (unsafe_op_in_unsafe_fn deny, uninlined_format_args, semicolon_if_nothing_returned, redundant_clone, needless_pass_by_value). cargo fmt. Wire/protocol/CLI unchanged; spec untouched. --- mux/Cargo.lock | 1163 +++++++++++++++--- mux/Cargo.toml | 20 +- mux/bindings/rust/Cargo.toml | 4 + mux/bindings/rust/examples/e2e.rs | 2 +- mux/bindings/rust/src/lib.rs | 16 +- mux/crates/ghostty-vt-sys/Cargo.toml | 6 +- mux/crates/ghostty-vt-sys/build.rs | 8 +- mux/crates/ghostty-vt/Cargo.toml | 4 + mux/crates/ghostty-vt/src/key.rs | 2 +- mux/crates/ghostty-vt/src/lib.rs | 2 +- mux/crates/ghostty-vt/src/render.rs | 2 +- mux/crates/ghostty-vt/src/terminal.rs | 2 +- mux/crates/mux-cdp/Cargo.toml | 4 + mux/crates/mux-cdp/src/chrome.rs | 16 +- mux/crates/mux-cdp/src/client.rs | 32 +- mux/crates/mux-cdp/src/lib.rs | 4 +- mux/crates/mux-cdp/tests/fake_cdp.rs | 50 +- mux/crates/mux-core/Cargo.toml | 4 + mux/crates/mux-core/src/browser.rs | 22 +- mux/crates/mux-core/src/lib.rs | 4 +- mux/crates/mux-core/src/mux.rs | 4 +- mux/crates/mux-core/src/platform.rs | 6 +- mux/crates/mux-core/src/server.rs | 24 +- mux/crates/mux-core/src/surface.rs | 2 +- mux/crates/mux-core/tests/browser_runtime.rs | 10 +- mux/crates/mux-core/tests/pty.rs | 4 +- mux/crates/mux-tui/Cargo.toml | 4 + mux/crates/mux-tui/src/app.rs | 24 +- mux/crates/mux-tui/src/browser_input.rs | 2 +- mux/crates/mux-tui/src/cli.rs | 2 +- mux/crates/mux-tui/src/config.rs | 2 +- mux/crates/mux-tui/src/main.rs | 2 +- mux/crates/mux-tui/src/session/mod.rs | 8 +- mux/crates/mux-tui/src/session/remote.rs | 12 +- mux/crates/mux-tui/src/session/tree.rs | 4 +- mux/crates/mux-tui/src/ui/graphics_writer.rs | 2 +- mux/crates/mux-tui/src/ui/mod.rs | 2 +- mux/crates/mux-tui/src/ui/omnibar.rs | 2 +- mux/crates/mux-tui/src/ui/overlay.rs | 2 +- mux/crates/mux-tui/src/ui/pane.rs | 4 +- mux/crates/mux-tui/src/ui/sidebar.rs | 2 +- 41 files changed, 1151 insertions(+), 340 deletions(-) diff --git a/mux/Cargo.lock b/mux/Cargo.lock index 7f526177b68f..f214f3e7512c 100644 --- a/mux/Cargo.lock +++ b/mux/Cargo.lock @@ -23,6 +23,24 @@ version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340" +dependencies = [ + "bytemuck", +] + [[package]] name = "autocfg" version = "1.5.1" @@ -37,14 +55,14 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bindgen" -version = "0.71.1" +version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ "bitflags 2.13.0", "cexpr", "clang-sys", - "itertools", + "itertools 0.13.0", "log", "prettyplease", "proc-macro2", @@ -52,9 +70,24 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn", + "syn 2.0.118", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", ] +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" @@ -77,22 +110,28 @@ dependencies = [ ] [[package]] -name = "byteorder" -version = "1.5.0" +name = "bumpalo" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] -name = "bytes" -version = "1.12.0" +name = "by_address" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" [[package]] -name = "cassowary" -version = "0.3.0" +name = "bytemuck" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" + +[[package]] +name = "bytes" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" [[package]] name = "castaway" @@ -124,6 +163,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "clang-sys" version = "1.8.1" @@ -145,9 +190,9 @@ dependencies = [ [[package]] name = "compact_str" -version = "0.8.2" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd622ebbb56a5b2ccb651b32b911cdeb2a9b4b11776b2473bf26a26a286244e" +checksum = "9dfdd1c2274d9aa354115b09dc9a901d6c5576818cdf70d14cae2bdb47df00ab" dependencies = [ "castaway", "cfg-if", @@ -157,6 +202,15 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -166,17 +220,25 @@ dependencies = [ "libc", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "crossterm" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" +checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ "bitflags 2.13.0", "crossterm_winapi", + "derive_more", + "document-features", "mio", "parking_lot", - "rustix 0.38.44", + "rustix", "signal-hook", "signal-hook-mio", "winapi", @@ -201,6 +263,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "csscolorparser" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2a7d3066da2de787b7f032c736763eb7ae5d355f81a68bab2675a96008b0bf" +dependencies = [ + "lab", + "phf", +] + [[package]] name = "darling" version = "0.23.0" @@ -221,7 +293,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn", + "syn 2.0.118", ] [[package]] @@ -232,7 +304,7 @@ checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ "darling_core", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -241,6 +313,40 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" +[[package]] +name = "deltae" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5729f5117e208430e437df2f4843f5e5952997175992d1414f94c57d61e270b4" + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.118", +] + [[package]] name = "digest" version = "0.10.7" @@ -251,6 +357,15 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + [[package]] name = "downcast-rs" version = "1.2.1" @@ -276,9 +391,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys", +] + +[[package]] +name = "euclid" +version = "0.22.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a05365e3b1c6d1650318537c7460c6923f1abdd272ad6842baa2b509957a06" +dependencies = [ + "num-traits", ] +[[package]] +name = "fancy-regex" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" +dependencies = [ + "bit-set", + "regex", +] + +[[package]] +name = "fast-srgb8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" + [[package]] name = "fastrand" version = "2.4.1" @@ -292,15 +432,57 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e40758ed24c9b2eeb76c35fb0aebc66c626084edd827e07e1552279814c6682d" dependencies = [ "libc", - "thiserror", + "thiserror 1.0.69", "winapi", ] +[[package]] +name = "finl_unicode" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9844ddc3a6e533d62bba727eb6c28b5d360921d5175e9ff0f1e621a5c590a4d5" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "foldhash" -version = "0.1.5" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] [[package]] name = "generic-array" @@ -314,13 +496,14 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.17" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", - "wasi", + "r-efi 5.3.0", + "wasip2", ] [[package]] @@ -331,7 +514,7 @@ checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", "libc", - "r-efi", + "r-efi 6.0.0", ] [[package]] @@ -356,9 +539,20 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "hashbrown" -version = "0.15.5" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" dependencies = [ "allocator-api2", "equivalent", @@ -371,6 +565,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "http" version = "1.4.2" @@ -412,7 +612,7 @@ dependencies = [ "indoc", "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -424,12 +624,49 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +[[package]] +name = "js-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "kasuari" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde5057d6143cc94e861d90f591b9303d6716c6b9602309150bd068853c10899" +dependencies = [ + "hashbrown 0.16.1", + "portable-atomic", + "thiserror 2.0.18", +] + +[[package]] +name = "lab" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf36173d4167ed999940f804952e6b08197cae5ad5d572eb4db150ce8ad5d58f" + [[package]] name = "lazy_static" version = "1.5.0" @@ -453,10 +690,19 @@ dependencies = [ ] [[package]] -name = "linux-raw-sys" -version = "0.4.15" +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "line-clipping" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +checksum = "3f50e8f47623268b5407192d26876c4d7f89d686ca130fdc53bced4814cd29f8" +dependencies = [ + "bitflags 2.13.0", +] [[package]] name = "linux-raw-sys" @@ -464,6 +710,12 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + [[package]] name = "lock_api" version = "0.4.14" @@ -481,11 +733,21 @@ checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "lru" -version = "0.12.5" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a860605968fce16869fd239cf4237a82f3ac470723415db603b0e8b6c8d4fb9" +dependencies = [ + "hashbrown 0.17.1", +] + +[[package]] +name = "mac_address" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +checksum = "c0aeb26bf5e836cc1c341c8106051b573f1766dfa05aa87f0b98be5e51b02303" dependencies = [ - "hashbrown", + "nix 0.29.0", + "winapi", ] [[package]] @@ -494,6 +756,12 @@ version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" +[[package]] +name = "memmem" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64a92489e2744ce060c349162be1c5f33c6969234104dbd99ddb5feb08b8c15" + [[package]] name = "memoffset" version = "0.9.1" @@ -518,7 +786,7 @@ dependencies = [ "libc", "log", "wasi", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -560,7 +828,7 @@ dependencies = [ "ratatui", "serde", "serde_json", - "unicode-width 0.2.0", + "unicode-width", ] [[package]] @@ -571,8 +839,21 @@ checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ "bitflags 2.13.0", "cfg-if", - "cfg_aliases", + "cfg_aliases 0.1.1", + "libc", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.13.0", + "cfg-if", + "cfg_aliases 0.2.1", "libc", + "memoffset", ] [[package]] @@ -585,12 +866,80 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[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_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + [[package]] name = "once_cell" version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", +] + +[[package]] +name = "palette" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" +dependencies = [ + "approx", + "fast-srgb8", + "libm", + "palette_derive", +] + +[[package]] +name = "palette_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" +dependencies = [ + "by_address", + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "parking_lot" version = "0.12.5" @@ -615,69 +964,181 @@ dependencies = [ ] [[package]] -name = "paste" -version = "1.0.15" +name = "pest" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +checksum = "47627dd7305c6a2d6c8c6bcd24c5a4c17dbbf425f4f9c5313e724b38fc9782e9" +dependencies = [ + "memchr", + "ucd-trie", +] [[package]] -name = "portable-pty" -version = "0.9.0" +name = "pest_derive" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4a596a2b3d2752d94f51fac2d4a96737b8705dddd311a32b9af47211f08671e" +checksum = "4b4254325ecad416ab689e27ba51da03ba01a9632bc6e108f5fe7c3c4ad29d58" dependencies = [ - "anyhow", - "bitflags 1.3.2", - "downcast-rs", - "filedescriptor", - "lazy_static", - "libc", - "log", - "nix", - "serial2", - "shared_library", - "shell-words", - "winapi", - "winreg", + "pest", + "pest_generator", ] [[package]] -name = "ppv-lite86" -version = "0.2.21" +name = "pest_generator" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +checksum = "6c4c0e91ead7a8f7acecbca6f003fc2e8282b1dbe2dd9c9d2f16aba42995e0a7" dependencies = [ - "zerocopy", + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.118", ] [[package]] -name = "prettyplease" -version = "0.2.37" +name = "pest_meta" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +checksum = "f9744bc48116fee06334924bb5f2bad41eed5e89bd26e29b0b799f9a3f82c210" dependencies = [ - "proc-macro2", - "syn", + "pest", ] [[package]] -name = "proc-macro2" -version = "1.0.106" +name = "phf" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ - "unicode-ident", + "phf_macros", + "phf_shared", ] [[package]] -name = "quote" -version = "1.0.46" +name = "phf_codegen" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ - "proc-macro2", + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand 0.8.6", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "portable-pty" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4a596a2b3d2752d94f51fac2d4a96737b8705dddd311a32b9af47211f08671e" +dependencies = [ + "anyhow", + "bitflags 1.3.2", + "downcast-rs", + "filedescriptor", + "lazy_static", + "libc", + "log", + "nix 0.28.0", + "serial2", + "shared_library", + "shell-words", + "winapi", + "winreg", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.118", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "r-efi" version = "6.0.0" @@ -690,19 +1151,27 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ - "libc", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +dependencies = [ "rand_chacha", - "rand_core", + "rand_core 0.9.5", ] [[package]] name = "rand_chacha" -version = "0.3.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.9.5", ] [[package]] @@ -710,29 +1179,115 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "getrandom 0.2.17", + "getrandom 0.3.4", ] [[package]] name = "ratatui" -version = "0.29.0" +version = "0.30.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" +checksum = "3274ba0a2c5e1bcad2a2005d20f4dc59dad26b2eb0940fb094500dba4099d57d" +dependencies = [ + "instability", + "ratatui-core", + "ratatui-crossterm", + "ratatui-macros", + "ratatui-termina", + "ratatui-termwiz", + "ratatui-widgets", + "serde", +] + +[[package]] +name = "ratatui-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbb175c433c8e28a809d1f5773a2ae96e68c0ce40db865cbab1020bf33ae479c" dependencies = [ "bitflags 2.13.0", - "cassowary", "compact_str", + "critical-section", + "hashbrown 0.17.1", + "itertools 0.14.0", + "kasuari", + "lru", + "palette", + "serde", + "strum", + "thiserror 2.0.18", + "unicode-segmentation", + "unicode-truncate", + "unicode-width", +] + +[[package]] +name = "ratatui-crossterm" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567584a3b0e6a8203c23de40b4861497266725eb5363dbfd18a1edd603cca9f0" +dependencies = [ + "cfg-if", "crossterm", + "instability", + "ratatui-core", +] + +[[package]] +name = "ratatui-macros" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed7dc68daa7498a43e4d68e0eb078427e10c38fbcfbb1e42d955f1fa2140d814" +dependencies = [ + "ratatui-core", + "ratatui-widgets", +] + +[[package]] +name = "ratatui-termina" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0bf912d9e66f057a759d92e386a280ea886b352ab757d6ac4d653c7ed2c43c2" +dependencies = [ + "instability", + "ratatui-core", + "termina", +] + +[[package]] +name = "ratatui-termwiz" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf03e0380b7744054d6cb74224fe3adf062a029754933f575ca1e3b4c2ce977" +dependencies = [ + "ratatui-core", + "termwiz", +] + +[[package]] +name = "ratatui-widgets" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66e3d19bcc9130ca376277d93b60767ff121ace3be06f5f95f81dd68956407d1" +dependencies = [ + "bitflags 2.13.0", + "hashbrown 0.17.1", "indoc", "instability", - "itertools", - "lru", - "paste", + "itertools 0.14.0", + "line-clipping", + "ratatui-core", + "serde", "strum", + "time", "unicode-segmentation", - "unicode-truncate", - "unicode-width 0.2.0", + "unicode-width", ] [[package]] @@ -780,16 +1335,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" [[package]] -name = "rustix" -version = "0.38.44" +name = "rustc_version" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "bitflags 2.13.0", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", + "semver", ] [[package]] @@ -801,8 +1352,8 @@ dependencies = [ "bitflags 2.13.0", "errno", "libc", - "linux-raw-sys 0.12.1", - "windows-sys 0.61.2", + "linux-raw-sys", + "windows-sys", ] [[package]] @@ -823,6 +1374,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + [[package]] name = "serde" version = "1.0.228" @@ -850,7 +1407,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -874,7 +1431,7 @@ checksum = "9eb6ea5562eeaed6936b8b54e086aa0f88b9e5b1bef45beb038e2519fa1185b1" dependencies = [ "cfg-if", "libc", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -888,6 +1445,17 @@ dependencies = [ "digest", ] +[[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 = "shared_library" version = "0.1.9" @@ -941,6 +1509,18 @@ dependencies = [ "libc", ] +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + [[package]] name = "smallvec" version = "1.15.2" @@ -961,24 +1541,34 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.26.3" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.26.4" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" dependencies = [ "heck", "proc-macro2", "quote", - "rustversion", - "syn", + "syn 2.0.118", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] @@ -1001,8 +1591,84 @@ dependencies = [ "fastrand", "getrandom 0.4.3", "once_cell", - "rustix 1.1.4", - "windows-sys 0.61.2", + "rustix", + "windows-sys", +] + +[[package]] +name = "termina" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9048a889effe34a5cddee0af7f53285198b16dca3be510858d38dfdb3e62a04e" +dependencies = [ + "bitflags 2.13.0", + "parking_lot", + "rustix", + "signal-hook", + "windows-sys", +] + +[[package]] +name = "terminfo" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4ea810f0692f9f51b382fff5893887bb4580f5fa246fde546e0b13e7fcee662" +dependencies = [ + "fnv", + "nom", + "phf", + "phf_codegen", +] + +[[package]] +name = "termios" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b" +dependencies = [ + "libc", +] + +[[package]] +name = "termwiz" +version = "0.23.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7" +dependencies = [ + "anyhow", + "base64", + "bitflags 2.13.0", + "fancy-regex", + "filedescriptor", + "finl_unicode", + "fixedbitset", + "hex", + "lazy_static", + "libc", + "log", + "memmem", + "nix 0.29.0", + "num-derive", + "num-traits", + "ordered-float", + "pest", + "pest_derive", + "phf", + "sha2", + "signal-hook", + "siphasher", + "terminfo", + "termios", + "thiserror 1.0.69", + "ucd-trie", + "unicode-segmentation", + "vtparse", + "wezterm-bidi", + "wezterm-blob-leases", + "wezterm-color-types", + "wezterm-dynamic", + "wezterm-input-types", + "winapi", ] [[package]] @@ -1011,7 +1677,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", ] [[package]] @@ -1022,25 +1697,55 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "time" +version = "0.3.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50" +dependencies = [ + "deranged", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde_core", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + [[package]] name = "tungstenite" -version = "0.24.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" dependencies = [ - "byteorder", "bytes", "data-encoding", "http", "httparse", "log", - "rand", + "rand 0.9.4", "sha1", - "thiserror", - "utf-8", + "thiserror 2.0.18", ] [[package]] @@ -1049,6 +1754,12 @@ version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "uds_windows" version = "1.2.1" @@ -1057,7 +1768,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" dependencies = [ "memoffset", "tempfile", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -1074,32 +1785,38 @@ checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-truncate" -version = "1.1.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" +checksum = "16b380a1238663e5f8a691f9039c73e1cdae598a30e9855f541d29b08b53e9a5" dependencies = [ - "itertools", + "itertools 0.14.0", "unicode-segmentation", - "unicode-width 0.1.14", + "unicode-width", ] [[package]] name = "unicode-width" -version = "0.1.14" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] -name = "unicode-width" -version = "0.2.0" +name = "utf8parse" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] -name = "utf-8" -version = "0.7.6" +name = "uuid" +version = "1.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" +dependencies = [ + "atomic", + "getrandom 0.4.3", + "js-sys", + "wasm-bindgen", +] [[package]] name = "version_check" @@ -1107,6 +1824,15 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "vtparse" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9b2acfb050df409c972a37d3b8e08cdea3bddb0c09db9d53137e504cfabed0" +dependencies = [ + "utf8parse", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -1114,114 +1840,167 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "winapi" -version = "0.3.9" +name = "wasip2" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "wit-bindgen", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "wasm-bindgen" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "wasm-bindgen-macro" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] [[package]] -name = "windows-link" -version = "0.2.1" +name = "wasm-bindgen-macro-support" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.118", + "wasm-bindgen-shared", +] [[package]] -name = "windows-sys" -version = "0.59.0" +name = "wasm-bindgen-shared" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" dependencies = [ - "windows-targets", + "unicode-ident", ] [[package]] -name = "windows-sys" -version = "0.61.2" +name = "wezterm-bidi" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +checksum = "0c0a6e355560527dd2d1cf7890652f4f09bb3433b6aadade4c9b5ed76de5f3ec" dependencies = [ - "windows-link", + "log", + "wezterm-dynamic", +] + +[[package]] +name = "wezterm-blob-leases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692daff6d93d94e29e4114544ef6d5c942a7ed998b37abdc19b17136ea428eb7" +dependencies = [ + "getrandom 0.3.4", + "mac_address", + "sha2", + "thiserror 1.0.69", + "uuid", ] [[package]] -name = "windows-targets" -version = "0.52.6" +name = "wezterm-color-types" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "7de81ef35c9010270d63772bebef2f2d6d1f2d20a983d27505ac850b8c4b4296" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "csscolorparser", + "deltae", + "lazy_static", + "wezterm-dynamic", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" +name = "wezterm-dynamic" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +checksum = "5f2ab60e120fd6eaa68d9567f3226e876684639d22a4219b313ff69ec0ccd5ac" +dependencies = [ + "log", + "ordered-float", + "strsim", + "thiserror 1.0.69", + "wezterm-dynamic-derive", +] [[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" +name = "wezterm-dynamic-derive" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +checksum = "46c0cf2d539c645b448eaffec9ec494b8b19bd5077d9e58cb1ae7efece8d575b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] [[package]] -name = "windows_i686_gnu" -version = "0.52.6" +name = "wezterm-input-types" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +checksum = "7012add459f951456ec9d6c7e6fc340b1ce15d6fc9629f8c42853412c029e57e" +dependencies = [ + "bitflags 1.3.2", + "euclid", + "lazy_static", + "serde", + "wezterm-dynamic", +] [[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" +name = "winapi" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] [[package]] -name = "windows_i686_msvc" -version = "0.52.6" +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] [[package]] name = "winreg" @@ -1232,6 +2011,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + [[package]] name = "zerocopy" version = "0.8.52" @@ -1249,7 +2034,7 @@ checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] diff --git a/mux/Cargo.toml b/mux/Cargo.toml index b522dabf2e0e..37b54b452744 100644 --- a/mux/Cargo.toml +++ b/mux/Cargo.toml @@ -10,10 +10,21 @@ members = [ ] [workspace.package] -edition = "2021" +edition = "2024" +rust-version = "1.88" license = "MIT" publish = false +[workspace.lints.rust] +unsafe_op_in_unsafe_fn = "deny" +unused_qualifications = "warn" + +[workspace.lints.clippy] +uninlined_format_args = "warn" +semicolon_if_nothing_returned = "warn" +redundant_clone = "warn" +needless_pass_by_value = "warn" + [workspace.dependencies] ghostty-vt-sys = { path = "crates/ghostty-vt-sys" } ghostty-vt = { path = "crates/ghostty-vt" } @@ -23,14 +34,15 @@ anyhow = "1" serde = { version = "1", features = ["derive"] } serde_json = "1" portable-pty = "0.9" -crossterm = "0.28" -ratatui = "0.29" +crossterm = "0.29" +ratatui = "0.30" unicode-width = "0.2" base64 = "0.22" libc = "0.2" -tungstenite = { version = "0.24", default-features = false, features = ["handshake"] } +tungstenite = { version = "0.29", default-features = false, features = ["handshake"] } uds_windows = "1.2" regex = "1" +bindgen = "0.72" [profile.release] lto = "thin" diff --git a/mux/bindings/rust/Cargo.toml b/mux/bindings/rust/Cargo.toml index 16fb103da968..b71140692187 100644 --- a/mux/bindings/rust/Cargo.toml +++ b/mux/bindings/rust/Cargo.toml @@ -2,12 +2,16 @@ name = "cmux-client" version = "0.1.2" edition.workspace = true +rust-version.workspace = true license.workspace = true description = "Rust client for the cmux-mux terminal multiplexer control protocol" repository = "https://github.com/manaflow-ai/cmux" homepage = "https://github.com/manaflow-ai/cmux/tree/main/mux/bindings/rust" publish = true +[lints] +workspace = true + [dependencies] serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } diff --git a/mux/bindings/rust/examples/e2e.rs b/mux/bindings/rust/examples/e2e.rs index a9becade510e..95a4e0b1a256 100644 --- a/mux/bindings/rust/examples/e2e.rs +++ b/mux/bindings/rust/examples/e2e.rs @@ -76,7 +76,7 @@ fn next_resized( } match events.recv_timeout(time_left(deadline))? { Event::SurfaceResized(event) if event.surface == surface => { - return Ok((event.cols, event.rows)) + return Ok((event.cols, event.rows)); } _ => {} } diff --git a/mux/bindings/rust/src/lib.rs b/mux/bindings/rust/src/lib.rs index 722e1c54dc54..469a5009e8a4 100644 --- a/mux/bindings/rust/src/lib.rs +++ b/mux/bindings/rust/src/lib.rs @@ -491,7 +491,7 @@ impl CmuxClient { let id = self.next_id(); params.insert("id".to_string(), Value::from(id)); params.insert("cmd".to_string(), Value::from(cmd)); - CmuxStream::open(&self.config.socket_path, self.config.timeout, Value::Object(params)) + CmuxStream::open(&self.config.socket_path, self.config.timeout, &Value::Object(params)) } fn next_id(&mut self) -> u64 { @@ -507,10 +507,10 @@ pub struct CmuxStream { } impl CmuxStream { - fn open(socket_path: &PathBuf, timeout: Duration, request: Value) -> Result { + fn open(socket_path: &PathBuf, timeout: Duration, request: &Value) -> Result { let mut conn = JsonLineConnection::connect(socket_path, timeout)?; let request_id = request.get("id").cloned(); - conn.send(&request)?; + conn.send(request)?; let mut buffered = Vec::new(); loop { let response = conn.recv()?; @@ -551,10 +551,12 @@ impl CmuxStream { if !self.buffered.is_empty() { return Ok(self.buffered.remove(0)); } - self.conn.with_read_timeout(timeout, |conn| loop { - let value = conn.recv()?; - if value.get("event").is_some() { - return Ok(parse_event(value)); + self.conn.with_read_timeout(timeout, |conn| { + loop { + let value = conn.recv()?; + if value.get("event").is_some() { + return Ok(parse_event(value)); + } } }) } diff --git a/mux/crates/ghostty-vt-sys/Cargo.toml b/mux/crates/ghostty-vt-sys/Cargo.toml index c43d94dc0fe7..e83a1bb699c9 100644 --- a/mux/crates/ghostty-vt-sys/Cargo.toml +++ b/mux/crates/ghostty-vt-sys/Cargo.toml @@ -2,10 +2,14 @@ name = "ghostty-vt-sys" version = "0.1.0" edition.workspace = true +rust-version.workspace = true license.workspace = true publish.workspace = true description = "Raw FFI bindings to libghostty-vt, built from the vendored ghostty submodule via zig" links = "ghostty-vt" +[lints] +workspace = true + [build-dependencies] -bindgen = "0.71" +bindgen.workspace = true diff --git a/mux/crates/ghostty-vt-sys/build.rs b/mux/crates/ghostty-vt-sys/build.rs index 84c6ecb71d30..e1ecc777ae7f 100644 --- a/mux/crates/ghostty-vt-sys/build.rs +++ b/mux/crates/ghostty-vt-sys/build.rs @@ -43,10 +43,10 @@ fn main() { .arg("-Demit-lib-vt=true") .arg("-Demit-xcframework=false") .arg("-Doptimize=ReleaseFast"); - if target != host { - if let Some(zig_target) = zig_target_for_rust_target(&target) { - command.arg(format!("-Dtarget={zig_target}")); - } + if target != host + && let Some(zig_target) = zig_target_for_rust_target(&target) + { + command.arg(format!("-Dtarget={zig_target}")); } // Valgrind's instruction emulation doesn't cover every CPU-native SIMD // extension zig's default target detection can select (e.g. some AVX-512 diff --git a/mux/crates/ghostty-vt/Cargo.toml b/mux/crates/ghostty-vt/Cargo.toml index 667700aae3d8..78dc0e9975f6 100644 --- a/mux/crates/ghostty-vt/Cargo.toml +++ b/mux/crates/ghostty-vt/Cargo.toml @@ -2,9 +2,13 @@ name = "ghostty-vt" version = "0.1.0" edition.workspace = true +rust-version.workspace = true license.workspace = true publish.workspace = true description = "Safe Rust wrapper around libghostty-vt" +[lints] +workspace = true + [dependencies] ghostty-vt-sys.workspace = true diff --git a/mux/crates/ghostty-vt/src/key.rs b/mux/crates/ghostty-vt/src/key.rs index 3e4fe9d581e9..8daf5e4407f3 100644 --- a/mux/crates/ghostty-vt/src/key.rs +++ b/mux/crates/ghostty-vt/src/key.rs @@ -3,7 +3,7 @@ use std::ptr; use ghostty_vt_sys as sys; use crate::terminal::Terminal; -use crate::{check, Result}; +use crate::{Result, check}; /// Key press/release/repeat. #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/mux/crates/ghostty-vt/src/lib.rs b/mux/crates/ghostty-vt/src/lib.rs index 8f5f8833c557..f5c52c162ea9 100644 --- a/mux/crates/ghostty-vt/src/lib.rs +++ b/mux/crates/ghostty-vt/src/lib.rs @@ -11,7 +11,7 @@ mod terminal; /// Raw bindings, re-exported for key/mode constants. pub use ghostty_vt_sys as sys; -pub use key::{key_input_from_chord, KeyAction, KeyEncoder, KeyInput, Mods}; +pub use key::{KeyAction, KeyEncoder, KeyInput, Mods, key_input_from_chord}; pub use render::{Cell, ColorSpec, CursorInfo, CursorShape, Dirty, RenderState}; pub use terminal::{Callbacks, NotifyFn, PtyWriteFn, Rgb, Screen, Scrollbar, Terminal}; diff --git a/mux/crates/ghostty-vt/src/render.rs b/mux/crates/ghostty-vt/src/render.rs index 042417c3b5be..2ab422ea2549 100644 --- a/mux/crates/ghostty-vt/src/render.rs +++ b/mux/crates/ghostty-vt/src/render.rs @@ -4,7 +4,7 @@ use std::ptr; use ghostty_vt_sys as sys; use crate::terminal::{Rgb, Terminal}; -use crate::{check, Result}; +use crate::{Result, check}; /// Global dirty state after a [`RenderState::update`]. #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/mux/crates/ghostty-vt/src/terminal.rs b/mux/crates/ghostty-vt/src/terminal.rs index d9b67fc10843..63581543eb84 100644 --- a/mux/crates/ghostty-vt/src/terminal.rs +++ b/mux/crates/ghostty-vt/src/terminal.rs @@ -3,7 +3,7 @@ use std::ptr; use ghostty_vt_sys as sys; -use crate::{check, Result}; +use crate::{Result, check}; /// RGB color triple. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] diff --git a/mux/crates/mux-cdp/Cargo.toml b/mux/crates/mux-cdp/Cargo.toml index aef544640d6e..a298403f9d5b 100644 --- a/mux/crates/mux-cdp/Cargo.toml +++ b/mux/crates/mux-cdp/Cargo.toml @@ -2,10 +2,14 @@ name = "mux-cdp" version = "0.1.0" edition.workspace = true +rust-version.workspace = true license.workspace = true publish.workspace = true description = "Synchronous Chrome DevTools Protocol transport and Chrome lifecycle for cmux-mux" +[lints] +workspace = true + [dependencies] anyhow.workspace = true serde_json.workspace = true diff --git a/mux/crates/mux-cdp/src/chrome.rs b/mux/crates/mux-cdp/src/chrome.rs index ac171a861c55..b521e868457d 100644 --- a/mux/crates/mux-cdp/src/chrome.rs +++ b/mux/crates/mux-cdp/src/chrome.rs @@ -2,9 +2,9 @@ use std::ffi::OsString; use std::io::{BufRead, BufReader}; use std::path::PathBuf; use std::process::{Child, Command, Stdio}; +use std::sync::Mutex; use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::mpsc; -use std::sync::Mutex; use std::time::{Duration, SystemTime, UNIX_EPOCH}; static PROFILE_SEQ: AtomicU64 = AtomicU64::new(1); @@ -28,11 +28,11 @@ impl Chrome { /// Launch Chrome in headless mode and wait for the browser CDP /// endpoint printed on stderr. pub fn launch(binary: PathBuf) -> anyhow::Result { - Chrome::launch_with(ChromeLaunchOptions { binary, user_data_dir: None, ephemeral: true }) + Chrome::launch_with(&ChromeLaunchOptions { binary, user_data_dir: None, ephemeral: true }) } - pub fn launch_with(options: ChromeLaunchOptions) -> anyhow::Result { - let (profile_dir, profile_ephemeral) = profile_dir_for(&options)?; + pub fn launch_with(options: &ChromeLaunchOptions) -> anyhow::Result { + let (profile_dir, profile_ephemeral) = profile_dir_for(options)?; std::fs::create_dir_all(&profile_dir)?; let mut child = Command::new(&options.binary) .arg("--headless=new") @@ -66,11 +66,9 @@ impl Chrome { match reader.read_line(&mut line) { Ok(0) | Err(_) => break, Ok(_) => { - if !sent { - if let Some(url) = parse_devtools_url(&line) { - let _ = tx.send(url); - sent = true; - } + if !sent && let Some(url) = parse_devtools_url(&line) { + let _ = tx.send(url); + sent = true; } } } diff --git a/mux/crates/mux-cdp/src/client.rs b/mux/crates/mux-cdp/src/client.rs index c5b0eb683327..4bc73d5be82c 100644 --- a/mux/crates/mux-cdp/src/client.rs +++ b/mux/crates/mux-cdp/src/client.rs @@ -2,13 +2,13 @@ use std::collections::HashMap; use std::io::{Read, Write}; use std::net::{TcpStream, ToSocketAddrs}; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; -use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError}; +use std::sync::mpsc::{Receiver, Sender, TryRecvError, channel}; use std::sync::{Arc, Mutex, Weak}; use std::time::Duration; -use serde_json::{json, Value}; +use serde_json::{Value, json}; use tungstenite::client::IntoClientRequest; -use tungstenite::{client, Error as WsError, Message, WebSocket}; +use tungstenite::{Error as WsError, Message, WebSocket, client}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct ScreencastFrame { @@ -127,7 +127,7 @@ impl CdpClient { ) -> anyhow::Result<()> { let weak = Arc::downgrade(&self.inner); std::thread::Builder::new().name("mux-cdp-reader".into()).spawn(move || { - reader_loop(weak, ws, outbound); + reader_loop(&weak, ws, &outbound); })?; Ok(()) } @@ -147,8 +147,9 @@ impl CdpClient { let mut msg = json!({ "id": id, "method": method, - "params": params, + "params": null, }); + msg["params"] = params; if let Some(session_id) = session_id { msg["sessionId"] = json!(session_id); } @@ -396,13 +397,13 @@ pub fn discover_browser_ws_url(ports: &[u16]) -> Option { ports.iter().find_map(|port| fetch_json_version("127.0.0.1", *port).ok()) } -fn reader_loop(weak: Weak, mut ws: WebSocket, outbound: Receiver) { +fn reader_loop(weak: &Weak, mut ws: WebSocket, outbound: &Receiver) { loop { let Some(inner) = weak.upgrade() else { break }; if inner.closed.load(Ordering::Acquire) { break; } - if let Err(err) = drain_outbound(&mut ws, &outbound) { + if let Err(err) = drain_outbound(&mut ws, outbound) { close_inner(&inner, &format!("CDP socket error: {err}")); break; } @@ -410,7 +411,7 @@ fn reader_loop(weak: Weak, mut ws: WebSocket, outbound: Receiv match message { Ok(Message::Text(text)) => handle_text(&inner, &text), Ok(Message::Binary(bytes)) => { - if let Ok(text) = String::from_utf8(bytes) { + if let Ok(text) = String::from_utf8(bytes.to_vec()) { handle_text(&inner, &text); } } @@ -441,7 +442,7 @@ fn drain_outbound( ) -> anyhow::Result<()> { loop { match outbound.try_recv() { - Ok(text) => ws.send(Message::Text(text))?, + Ok(text) => ws.send(Message::Text(text.into()))?, Err(TryRecvError::Empty | TryRecvError::Disconnected) => return Ok(()), } } @@ -666,7 +667,7 @@ mod tests { use std::thread; use std::time::{Duration, Instant}; - use tungstenite::{accept, Message}; + use tungstenite::{Message, accept}; use super::*; @@ -697,7 +698,8 @@ mod tests { } } }) - .to_string(), + .to_string() + .into(), )) .unwrap(); @@ -706,7 +708,9 @@ mod tests { let request: Value = serde_json::from_str(&text).unwrap(); let id = request["id"].clone(); ws.send(Message::Text( - json!({"id": id, "result": {"method": request["method"]}}).to_string(), + json!({"id": id, "result": {"method": request["method"]}}) + .to_string() + .into(), )) .unwrap(); responses += 1; @@ -715,7 +719,9 @@ mod tests { let request: Value = serde_json::from_slice(&bytes).unwrap(); let id = request["id"].clone(); ws.send(Message::Text( - json!({"id": id, "result": {"method": request["method"]}}).to_string(), + json!({"id": id, "result": {"method": request["method"]}}) + .to_string() + .into(), )) .unwrap(); responses += 1; diff --git a/mux/crates/mux-cdp/src/lib.rs b/mux/crates/mux-cdp/src/lib.rs index 52fa9f77666e..3cab97ad4bab 100644 --- a/mux/crates/mux-cdp/src/lib.rs +++ b/mux/crates/mux-cdp/src/lib.rs @@ -9,6 +9,6 @@ mod client; pub use chrome::{Chrome, ChromeLaunchOptions}; pub use client::{ - discover_browser_ws_url, resolve_browser_ws_url, CdpClient, CdpEvent, CdpKeyEvent, - NavigationEntry, NavigationHistory, ScreencastFrame, TargetCreated, TargetInfo, + CdpClient, CdpEvent, CdpKeyEvent, NavigationEntry, NavigationHistory, ScreencastFrame, + TargetCreated, TargetInfo, discover_browser_ws_url, resolve_browser_ws_url, }; diff --git a/mux/crates/mux-cdp/tests/fake_cdp.rs b/mux/crates/mux-cdp/tests/fake_cdp.rs index 205fc55b5087..8e59ce532ce7 100644 --- a/mux/crates/mux-cdp/tests/fake_cdp.rs +++ b/mux/crates/mux-cdp/tests/fake_cdp.rs @@ -4,13 +4,13 @@ use std::sync::Mutex; use std::thread; use std::time::Duration; -use mux_cdp::{discover_browser_ws_url, resolve_browser_ws_url, CdpClient, CdpEvent}; -use serde_json::{json, Value}; -use tungstenite::{accept, Message}; +use mux_cdp::{CdpClient, CdpEvent, discover_browser_ws_url, resolve_browser_ws_url}; +use serde_json::{Value, json}; +use tungstenite::{Message, accept}; static TEST_LOCK: Mutex<()> = Mutex::new(()); -fn read_json(ws: &mut tungstenite::WebSocket) -> serde_json::Value { +fn read_json(ws: &mut tungstenite::WebSocket) -> Value { loop { match ws.read().unwrap() { Message::Text(text) => return serde_json::from_str(&text).unwrap(), @@ -20,8 +20,8 @@ fn read_json(ws: &mut tungstenite::WebSocket) -> serde_json } } -fn write_json(ws: &mut tungstenite::WebSocket, value: Value) { - ws.send(Message::Text(value.to_string())).unwrap(); +fn write_json(ws: &mut tungstenite::WebSocket, value: &Value) { + ws.send(Message::Text(value.to_string().into())).unwrap(); } #[test] @@ -37,24 +37,24 @@ fn fake_cdp_flat_sessions_correlation_events_and_screencast_ack() { let create = read_json(&mut ws); assert_eq!(create["method"], "Target.createTarget"); assert_eq!(create["params"]["url"], "https://example.test"); - write_json(&mut ws, json!({"id": create["id"], "result": {"targetId": "target-1"}})); + write_json(&mut ws, &json!({"id": create["id"], "result": {"targetId": "target-1"}})); let attach = read_json(&mut ws); assert_eq!(attach["method"], "Target.attachToTarget"); assert_eq!(attach["params"]["targetId"], "target-1"); assert_eq!(attach["params"]["flatten"], true); - write_json(&mut ws, json!({"id": attach["id"], "result": {"sessionId": "session-1"}})); + write_json(&mut ws, &json!({"id": attach["id"], "result": {"sessionId": "session-1"}})); let first = read_json(&mut ws); let second = read_json(&mut ws); assert_eq!(first["sessionId"], "session-1"); assert_eq!(second["sessionId"], "session-1"); - write_json(&mut ws, json!({"id": second["id"], "result": {"name": second["method"]}})); - write_json(&mut ws, json!({"id": first["id"], "result": {"name": first["method"]}})); + write_json(&mut ws, &json!({"id": second["id"], "result": {"name": second["method"]}})); + write_json(&mut ws, &json!({"id": first["id"], "result": {"name": first["method"]}})); write_json( &mut ws, - json!({ + &json!({ "method": "Target.targetInfoChanged", "params": { "targetInfo": { @@ -68,7 +68,7 @@ fn fake_cdp_flat_sessions_correlation_events_and_screencast_ack() { write_json( &mut ws, - json!({ + &json!({ "method": "Page.screencastFrame", "sessionId": "session-1", "params": { @@ -82,7 +82,7 @@ fn fake_cdp_flat_sessions_correlation_events_and_screencast_ack() { assert_eq!(ack["method"], "Page.screencastFrameAck"); assert_eq!(ack["sessionId"], "session-1"); assert_eq!(ack["params"]["sessionId"], 42); - write_json(&mut ws, json!({"id": ack["id"], "result": {}})); + write_json(&mut ws, &json!({"id": ack["id"], "result": {}})); }); let (event_tx, event_rx) = std::sync::mpsc::channel(); @@ -93,20 +93,21 @@ fn fake_cdp_flat_sessions_correlation_events_and_screencast_ack() { let session_id = client.attach_to_target(&target_id).unwrap(); assert_eq!(session_id, "session-1"); - let left = { - let client = client.clone(); - let session_id = session_id.clone(); - thread::spawn(move || client.call("Test.left", json!({}), Some(&session_id)).unwrap()) - }; + let left_client = client.clone(); + let right_client = client.clone(); + let right_session_id = session_id.clone(); + let left = + thread::spawn(move || left_client.call("Test.left", json!({}), Some(&session_id)).unwrap()); let right = { - let client = client.clone(); - let session_id = session_id.clone(); - thread::spawn(move || client.call("Test.right", json!({}), Some(&session_id)).unwrap()) + thread::spawn(move || { + right_client.call("Test.right", json!({}), Some(&right_session_id)).unwrap() + }) }; let left = left.join().unwrap(); let right = right.join().unwrap(); assert_eq!(left["name"], "Test.left"); assert_eq!(right["name"], "Test.right"); + let client_guard = client; let info = event_rx.recv_timeout(Duration::from_secs(2)).unwrap(); match info { @@ -132,6 +133,7 @@ fn fake_cdp_flat_sessions_correlation_events_and_screencast_ack() { } server.join().unwrap(); + drop(client_guard); } #[test] @@ -148,12 +150,12 @@ fn fake_cdp_activate_target_then_bring_page_to_front() { assert_eq!(activate["method"], "Target.activateTarget"); assert_eq!(activate["params"]["targetId"], "target-1"); assert!(activate.get("sessionId").is_none()); - write_json(&mut ws, json!({"id": activate["id"], "result": {}})); + write_json(&mut ws, &json!({"id": activate["id"], "result": {}})); let front = read_json(&mut ws); assert_eq!(front["method"], "Page.bringToFront"); assert_eq!(front["sessionId"], "session-1"); - write_json(&mut ws, json!({"id": front["id"], "result": {}})); + write_json(&mut ws, &json!({"id": front["id"], "result": {}})); }); let (event_tx, _event_rx) = std::sync::mpsc::channel(); @@ -181,7 +183,7 @@ fn fake_cdp_dispatches_button_none_mouse_move_without_click_count() { assert_eq!(request["params"]["y"], 18.0); assert_eq!(request["params"]["button"], "none"); assert!(request["params"].get("clickCount").is_none()); - write_json(&mut ws, json!({"id": request["id"], "result": {}})); + write_json(&mut ws, &json!({"id": request["id"], "result": {}})); }); let (event_tx, _event_rx) = std::sync::mpsc::channel(); diff --git a/mux/crates/mux-core/Cargo.toml b/mux/crates/mux-core/Cargo.toml index 7ac51e9a9cda..666c6bb48694 100644 --- a/mux/crates/mux-core/Cargo.toml +++ b/mux/crates/mux-core/Cargo.toml @@ -2,10 +2,14 @@ name = "mux-core" version = "0.1.0" edition.workspace = true +rust-version.workspace = true license.workspace = true publish.workspace = true description = "Terminal multiplexer core: workspaces, tabs, panes, PTY runtime, control socket" +[lints] +workspace = true + [dependencies] ghostty-vt.workspace = true mux-cdp.workspace = true diff --git a/mux/crates/mux-core/src/browser.rs b/mux/crates/mux-core/src/browser.rs index 2c178aa3dea8..bcad1a8ef903 100644 --- a/mux/crates/mux-core/src/browser.rs +++ b/mux/crates/mux-core/src/browser.rs @@ -6,8 +6,8 @@ use std::sync::{Arc, Mutex, Weak}; use std::time::{Duration, Instant}; use mux_cdp::{ - discover_browser_ws_url, resolve_browser_ws_url, CdpClient, CdpEvent, CdpKeyEvent, Chrome, - ChromeLaunchOptions, TargetCreated, + CdpClient, CdpEvent, CdpKeyEvent, Chrome, ChromeLaunchOptions, TargetCreated, + discover_browser_ws_url, resolve_browser_ws_url, }; use crate::platform; @@ -332,11 +332,7 @@ fn capture_scale_for(pane_px_w: u32, pane_px_h: u32, opts: BrowserCaptureOptions } let area = f64::from(pane_px_w.max(1)) * f64::from(pane_px_h.max(1)); let budget = opts.max_capture_megapixels.max(f64::MIN_POSITIVE) * 1_000_000.0; - if area <= budget { - 1.0 - } else { - (budget / area).sqrt().clamp(f64::MIN_POSITIVE, 1.0) - } + if area <= budget { 1.0 } else { (budget / area).sqrt().clamp(f64::MIN_POSITIVE, 1.0) } } fn scaled_pixels(pane_px_w: u32, pane_px_h: u32, scale: f64) -> (u32, u32) { @@ -382,7 +378,7 @@ fn runtime_endpoint( &opts.browser_session_name, )?) }; - let chrome = Chrome::launch_with(ChromeLaunchOptions { + let chrome = Chrome::launch_with(&ChromeLaunchOptions { binary: chrome_binary, user_data_dir, ephemeral: opts.browser_ephemeral, @@ -440,11 +436,7 @@ fn sanitize_session_name(name: &str) -> String { } } let trimmed = out.trim_matches('-'); - if trimmed.is_empty() { - "default".to_string() - } else { - trimmed.to_string() - } + if trimmed.is_empty() { "default".to_string() } else { trimmed.to_string() } } fn start_router(runtime: Arc, events: Receiver) -> anyhow::Result<()> { @@ -1141,8 +1133,8 @@ fn percent_encode_query(input: &str) -> String { #[cfg(test)] mod tests { use super::{ - capture_scale_for, new_surface, normalize_url, runtime_endpoint, scaled_pixels, - BrowserCaptureOptions, BrowserFrame, BrowserSource, BrowserStatus, + BrowserCaptureOptions, BrowserFrame, BrowserSource, BrowserStatus, capture_scale_for, + new_surface, normalize_url, runtime_endpoint, scaled_pixels, }; use crate::SurfaceOptions; use std::io::{Read, Write}; diff --git a/mux/crates/mux-core/src/lib.rs b/mux/crates/mux-core/src/lib.rs index 8c31e9cb6efb..eb6780445a68 100644 --- a/mux/crates/mux-core/src/lib.rs +++ b/mux/crates/mux-core/src/lib.rs @@ -20,8 +20,8 @@ pub mod server; pub use browser::normalize_url; pub use layout::{ - directional_neighbor, layout_screen, split_for_pane_edge, split_sides, LayoutResult, Rect, - SplitEdge, SplitResize, + LayoutResult, Rect, SplitEdge, SplitResize, directional_neighbor, layout_screen, + split_for_pane_edge, split_sides, }; pub use model::{Node, Pane, Screen, State, Workspace}; pub use mux::{ diff --git a/mux/crates/mux-core/src/mux.rs b/mux/crates/mux-core/src/mux.rs index 284c1a674c46..fb575672403a 100644 --- a/mux/crates/mux-core/src/mux.rs +++ b/mux/crates/mux-core/src/mux.rs @@ -3,12 +3,12 @@ use std::collections::HashMap; use std::sync::atomic::{AtomicU64, Ordering}; -use std::sync::mpsc::{channel, Receiver, Sender}; +use std::sync::mpsc::{Receiver, Sender, channel}; use std::sync::{Arc, Mutex}; use std::time::{SystemTime, UNIX_EPOCH}; use crate::browser::{self, BrowserBootstrap, BrowserRuntime}; -use crate::layout::{layout_screen, Rect}; +use crate::layout::{Rect, layout_screen}; use crate::model::{Node, Pane, Screen, State, Workspace}; use crate::surface::{DefaultColors, Surface, SurfaceOptions}; use crate::{PaneId, ScreenId, SplitDir, SurfaceId, WorkspaceId}; diff --git a/mux/crates/mux-core/src/platform.rs b/mux/crates/mux-core/src/platform.rs index 0ea6a238ad12..57d91e7dbbd6 100644 --- a/mux/crates/mux-core/src/platform.rs +++ b/mux/crates/mux-core/src/platform.rs @@ -142,11 +142,7 @@ pub fn default_shell() -> String { return shell; } - if Path::new("/bin/bash").is_file() { - "/bin/bash".to_string() - } else { - "/bin/sh".to_string() - } + if Path::new("/bin/bash").is_file() { "/bin/bash".to_string() } else { "/bin/sh".to_string() } } /// Default interactive shell for spawned PTY surfaces. diff --git a/mux/crates/mux-core/src/server.rs b/mux/crates/mux-core/src/server.rs index 7889b1a41e58..44ecbd8e1054 100644 --- a/mux/crates/mux-core/src/server.rs +++ b/mux/crates/mux-core/src/server.rs @@ -25,17 +25,17 @@ use std::sync::{Arc, Mutex}; use std::time::Instant; use base64::Engine; -use ghostty_vt::{key_input_from_chord, KeyEncoder}; +use ghostty_vt::{KeyEncoder, key_input_from_chord}; use regex::Regex; use serde::{Deserialize, Serialize}; -use serde_json::{json, Value}; +use serde_json::{Value, json}; use crate::model::{Screen, State}; use crate::platform::{self, transport}; use crate::{ - assign_short_ids, AgentRecord, AgentSource, AgentState, AttachFrame, DefaultColors, Direction, - LayoutLeafSpec, LayoutSpec, Mux, MuxEvent, Node, NotificationLevel, PaneId, Rgb, ScreenId, - SplitDir, SurfaceId, SurfaceKind, SurfaceNotification, WorkspaceId, ZoomMode, + AgentRecord, AgentSource, AgentState, AttachFrame, DefaultColors, Direction, LayoutLeafSpec, + LayoutSpec, Mux, MuxEvent, Node, NotificationLevel, PaneId, Rgb, ScreenId, SplitDir, SurfaceId, + SurfaceKind, SurfaceNotification, WorkspaceId, ZoomMode, assign_short_ids, }; pub const PROTOCOL_VERSION: u32 = 6; @@ -436,12 +436,14 @@ pub fn serve(mux: Arc, path: Option) -> anyhow::Result { let listener = transport::listen(&path)?; platform::restrict_file(&path)?; - std::thread::Builder::new().name("mux-server".into()).spawn(move || loop { - let Ok(stream) = listener.accept() else { continue }; - let mux = mux.clone(); - let _ = std::thread::Builder::new() - .name("mux-conn".into()) - .spawn(move || handle_connection(mux, stream)); + std::thread::Builder::new().name("mux-server".into()).spawn(move || { + loop { + let Ok(stream) = listener.accept() else { continue }; + let mux = mux.clone(); + let _ = std::thread::Builder::new() + .name("mux-conn".into()) + .spawn(move || handle_connection(mux, stream)); + } })?; Ok(path) } diff --git a/mux/crates/mux-core/src/surface.rs b/mux/crates/mux-core/src/surface.rs index 05617d0c9c6d..ea70ab564d6b 100644 --- a/mux/crates/mux-core/src/surface.rs +++ b/mux/crates/mux-core/src/surface.rs @@ -11,7 +11,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex, Weak}; use ghostty_vt::{Callbacks, RenderState, Rgb, Terminal}; -use portable_pty::{native_pty_system, ChildKiller, CommandBuilder, MasterPty, PtySize}; +use portable_pty::{ChildKiller, CommandBuilder, MasterPty, PtySize, native_pty_system}; use crate::platform; use crate::{Mux, MuxEvent, SurfaceId}; diff --git a/mux/crates/mux-core/tests/browser_runtime.rs b/mux/crates/mux-core/tests/browser_runtime.rs index 56982145de28..ae1a4e59bd0f 100644 --- a/mux/crates/mux-core/tests/browser_runtime.rs +++ b/mux/crates/mux-core/tests/browser_runtime.rs @@ -1,14 +1,14 @@ use std::io::{BufRead, BufReader, Write}; use std::net::TcpListener; use std::os::unix::net::UnixStream; -use std::sync::mpsc; use std::sync::Mutex; +use std::sync::mpsc; use std::thread; use std::time::{Duration, Instant}; -use mux_core::{server, BrowserStatus, Mux, SurfaceKind, SurfaceOptions}; -use serde_json::{json, Value}; -use tungstenite::{accept, Message}; +use mux_core::{BrowserStatus, Mux, SurfaceKind, SurfaceOptions, server}; +use serde_json::{Value, json}; +use tungstenite::{Message, accept}; static TEST_LOCK: Mutex<()> = Mutex::new(()); static SOCKET_SERIAL: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0); @@ -24,7 +24,7 @@ fn read_json(ws: &mut tungstenite::WebSocket) -> Value { } fn write_json(ws: &mut tungstenite::WebSocket, value: Value) { - ws.send(Message::Text(value.to_string())).unwrap(); + ws.send(Message::Text(value.to_string().into())).unwrap(); } fn rpc(path: &std::path::Path, mut cmd: Value) -> Value { diff --git a/mux/crates/mux-core/tests/pty.rs b/mux/crates/mux-core/tests/pty.rs index 2bf876d31cd4..839975abf1b8 100644 --- a/mux/crates/mux-core/tests/pty.rs +++ b/mux/crates/mux-core/tests/pty.rs @@ -620,7 +620,7 @@ fn attach_stream_orders_resize_between_output_frames() { Ok(AttachFrame::Output(bytes)) if bytes.windows(b"before-resize".len()).any(|w| w == b"before-resize") => { - break + break; } Ok(_) => {} Err(_) => assert!(Instant::now() < deadline, "before output never arrived"), @@ -648,7 +648,7 @@ fn attach_stream_orders_resize_between_output_frames() { Ok(AttachFrame::Output(bytes)) if bytes.windows(b"after-resize".len()).any(|w| w == b"after-resize") => { - break + break; } Ok(AttachFrame::Resized { .. }) => panic!("unexpected second resize marker"), Ok(_) => {} diff --git a/mux/crates/mux-tui/Cargo.toml b/mux/crates/mux-tui/Cargo.toml index c9bdbbb7a9e3..2196bda6b3fe 100644 --- a/mux/crates/mux-tui/Cargo.toml +++ b/mux/crates/mux-tui/Cargo.toml @@ -2,10 +2,14 @@ name = "mux-tui" version = "0.1.0" edition.workspace = true +rust-version.workspace = true license.workspace = true publish.workspace = true description = "cmux-mux: tmux-like terminal multiplexer TUI backed by libghostty-vt" +[lints] +workspace = true + [[bin]] name = "cmux-mux" path = "src/main.rs" diff --git a/mux/crates/mux-tui/src/app.rs b/mux/crates/mux-tui/src/app.rs index a4f1790d9d25..4aad9ab07294 100644 --- a/mux/crates/mux-tui/src/app.rs +++ b/mux/crates/mux-tui/src/app.rs @@ -8,27 +8,27 @@ use std::collections::HashMap; use std::io::Write; -use std::sync::mpsc::{channel, Receiver, RecvTimeoutError}; +use std::sync::mpsc::{Receiver, RecvTimeoutError, channel}; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; use base64::Engine; +use crossterm::ExecutableCommand; use crossterm::event::{ DisableBracketedPaste, DisableFocusChange, DisableMouseCapture, EnableBracketedPaste, EnableFocusChange, EnableMouseCapture, Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseButton, MouseEvent, MouseEventKind, }; use crossterm::terminal::{ - disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, + EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode, }; -use crossterm::ExecutableCommand; use ghostty_vt::{KeyEncoder, RenderState, Screen}; use mux_core::{ - layout_screen, split_for_pane_edge, split_sides, BrowserSource, BrowserStatus, MuxEvent, - PaneId, Rect, SplitDir, SplitEdge, SurfaceId, SurfaceKind, WorkspaceId, + BrowserSource, BrowserStatus, MuxEvent, PaneId, Rect, SplitDir, SplitEdge, SurfaceId, + SurfaceKind, WorkspaceId, layout_screen, split_for_pane_edge, split_sides, }; -use ratatui::backend::CrosstermBackend; use ratatui::Terminal as RatatuiTerminal; +use ratatui::backend::CrosstermBackend; use crate::browser_input::{BrowserInputDispatcher, BrowserInputEvent, BrowserInputKind}; use crate::config::{Action, Config, ScrollbarPosition}; @@ -324,11 +324,7 @@ impl Selection { pub fn range(&self) -> ((u16, u64), (u16, u64)) { let a = (self.anchor.1, self.anchor.0); let h = (self.head.1, self.head.0); - if a <= h { - (self.anchor, self.head) - } else { - (self.head, self.anchor) - } + if a <= h { (self.anchor, self.head) } else { (self.head, self.anchor) } } /// Whether a viewport cell is inside the (linear) selection at the @@ -2681,16 +2677,16 @@ fn browser_key_mapping( #[cfg(test)] mod tests { use super::{ - browser_content_size_for_rect, browser_hover_forward_allowed, pane_parts_for_rect, App, - PaneArea, + App, PaneArea, browser_content_size_for_rect, browser_hover_forward_allowed, + pane_parts_for_rect, }; use std::collections::HashMap; use std::sync::{Arc, Mutex}; use ghostty_vt::{KeyEncoder, RenderState}; use mux_core::{BrowserStatus, Mux, Node, Rect, SurfaceKind, SurfaceOptions}; - use ratatui::backend::TestBackend; use ratatui::Terminal; + use ratatui::backend::TestBackend; use crate::browser_input::BrowserInputDispatcher; use crate::config::{Config, ScrollbarPosition}; diff --git a/mux/crates/mux-tui/src/browser_input.rs b/mux/crates/mux-tui/src/browser_input.rs index 8abf03da0cd6..7deb1f13a8ab 100644 --- a/mux/crates/mux-tui/src/browser_input.rs +++ b/mux/crates/mux-tui/src/browser_input.rs @@ -20,7 +20,7 @@ //! that can act on a per-event error, and the surface's own status //! (`BrowserStatus`) is what the UI reports. -use std::sync::mpsc::{sync_channel, Receiver, SyncSender}; +use std::sync::mpsc::{Receiver, SyncSender, sync_channel}; use mux_core::SurfaceId; diff --git a/mux/crates/mux-tui/src/cli.rs b/mux/crates/mux-tui/src/cli.rs index c67e2fd6213e..6e8df8408d4d 100644 --- a/mux/crates/mux-tui/src/cli.rs +++ b/mux/crates/mux-tui/src/cli.rs @@ -4,7 +4,7 @@ use std::path::PathBuf; use std::time::Duration; use mux_core::platform::transport; -use serde_json::{json, Value}; +use serde_json::{Value, json}; const REQUEST_ID: u64 = 1; diff --git a/mux/crates/mux-tui/src/config.rs b/mux/crates/mux-tui/src/config.rs index 9ce96496785b..0e3678299588 100644 --- a/mux/crates/mux-tui/src/config.rs +++ b/mux/crates/mux-tui/src/config.rs @@ -61,8 +61,8 @@ use std::collections::HashMap; use crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; -use mux_core::platform; use mux_core::SurfaceOptions; +use mux_core::platform; use ratatui::style::Color; use serde::{Deserialize, Deserializer}; use serde_json::Value; diff --git a/mux/crates/mux-tui/src/main.rs b/mux/crates/mux-tui/src/main.rs index 6403d3acd5be..5de283c5b3ea 100644 --- a/mux/crates/mux-tui/src/main.rs +++ b/mux/crates/mux-tui/src/main.rs @@ -16,8 +16,8 @@ mod session; mod ui; use std::path::PathBuf; -use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; use mux_core::{Mux, SurfaceOptions}; use session::{RemoteSession, Session}; diff --git a/mux/crates/mux-tui/src/session/mod.rs b/mux/crates/mux-tui/src/session/mod.rs index a19577c2a43b..fa8b5367bffe 100644 --- a/mux/crates/mux-tui/src/session/mod.rs +++ b/mux/crates/mux-tui/src/session/mod.rs @@ -10,9 +10,9 @@ mod remote; pub(crate) mod tree; +use std::sync::Arc; use std::sync::atomic::Ordering; use std::sync::mpsc::Receiver; -use std::sync::Arc; use ghostty_vt::{RenderState, Terminal}; use mux_core::{ @@ -44,11 +44,7 @@ pub(crate) fn resize_action( server: (u16, u16), user_interaction: bool, ) -> bool { - if user_interaction { - desired != server - } else { - asserted != Some(desired) - } + if user_interaction { desired != server } else { asserted != Some(desired) } } #[derive(Clone)] diff --git a/mux/crates/mux-tui/src/session/remote.rs b/mux/crates/mux-tui/src/session/remote.rs index 0ef656a0ec88..54f0162f9fd0 100644 --- a/mux/crates/mux-tui/src/session/remote.rs +++ b/mux/crates/mux-tui/src/session/remote.rs @@ -6,19 +6,19 @@ use std::fs; use std::io::{BufRead, BufReader, Write}; use std::path::Path; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; -use std::sync::mpsc::{channel, Receiver, Sender}; +use std::sync::mpsc::{Receiver, Sender, channel}; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; use base64::Engine; use ghostty_vt::{Callbacks, RenderState, Terminal}; use mux_core::{ - platform::transport, BrowserFrame, BrowserSource, BrowserStatus, DefaultColors, MuxEvent, Rgb, - SurfaceId, SurfaceKind, + BrowserFrame, BrowserSource, BrowserStatus, DefaultColors, MuxEvent, Rgb, SurfaceId, + SurfaceKind, platform::transport, }; -use serde_json::{json, Value}; +use serde_json::{Value, json}; -use super::tree::{parse_tree, TreeView}; +use super::tree::{TreeView, parse_tree}; const SUPPORTED_PROTOCOL_VERSION: u64 = 6; #[derive(Clone)] @@ -626,8 +626,8 @@ fn parse_browser_frame(value: &Value) -> Option { #[cfg(test)] mod tests { - use std::sync::atomic::AtomicBool; use std::sync::Mutex; + use std::sync::atomic::AtomicBool; use ghostty_vt::{Callbacks, Terminal}; use serde_json::json; diff --git a/mux/crates/mux-tui/src/session/tree.rs b/mux/crates/mux-tui/src/session/tree.rs index a6cc51683310..afbb29f59f64 100644 --- a/mux/crates/mux-tui/src/session/tree.rs +++ b/mux/crates/mux-tui/src/session/tree.rs @@ -4,8 +4,8 @@ use std::collections::HashMap; use mux_core::{ - assign_short_ids, BrowserSource, Node, PaneId, ScreenId, SplitDir, State, SurfaceId, - SurfaceKind, SurfaceNotification, WorkspaceId, + BrowserSource, Node, PaneId, ScreenId, SplitDir, State, SurfaceId, SurfaceKind, + SurfaceNotification, WorkspaceId, assign_short_ids, }; use serde_json::Value; diff --git a/mux/crates/mux-tui/src/ui/graphics_writer.rs b/mux/crates/mux-tui/src/ui/graphics_writer.rs index 3dad998ac0e5..44273c6e0f2b 100644 --- a/mux/crates/mux-tui/src/ui/graphics_writer.rs +++ b/mux/crates/mux-tui/src/ui/graphics_writer.rs @@ -1,5 +1,5 @@ use std::io::Write; -use std::sync::mpsc::{sync_channel, Receiver, SyncSender, TrySendError}; +use std::sync::mpsc::{Receiver, SyncSender, TrySendError, sync_channel}; use std::sync::{Arc, Mutex}; use std::thread::JoinHandle; use std::time::Duration; diff --git a/mux/crates/mux-tui/src/ui/mod.rs b/mux/crates/mux-tui/src/ui/mod.rs index 248fb6ecd2cc..4524c802c0c3 100644 --- a/mux/crates/mux-tui/src/ui/mod.rs +++ b/mux/crates/mux-tui/src/ui/mod.rs @@ -13,9 +13,9 @@ mod scrollbar; mod sidebar; use mux_core::Rect; +use ratatui::Frame; use ratatui::layout::Position; use ratatui::style::{Color, Modifier, Style}; -use ratatui::Frame; use crate::app::{App, Hit}; diff --git a/mux/crates/mux-tui/src/ui/omnibar.rs b/mux/crates/mux-tui/src/ui/omnibar.rs index 8cc0a3610ba0..d29bdddc52ca 100644 --- a/mux/crates/mux-tui/src/ui/omnibar.rs +++ b/mux/crates/mux-tui/src/ui/omnibar.rs @@ -1,6 +1,6 @@ use mux_core::{BrowserStatus, Rect, SurfaceKind}; -use ratatui::style::{Color, Modifier, Style}; use ratatui::Frame; +use ratatui::style::{Color, Modifier, Style}; use super::truncate; use crate::app::{App, OmnibarHit, PaneArea}; diff --git a/mux/crates/mux-tui/src/ui/overlay.rs b/mux/crates/mux-tui/src/ui/overlay.rs index 930ad04ae7b2..17cd5daf397b 100644 --- a/mux/crates/mux-tui/src/ui/overlay.rs +++ b/mux/crates/mux-tui/src/ui/overlay.rs @@ -4,10 +4,10 @@ //! keys or mouse hover) highlights across the inner row, padding included. use mux_core::Rect; +use ratatui::Frame; use ratatui::buffer::Buffer; use ratatui::layout::Position; use ratatui::style::{Color, Modifier, Style}; -use ratatui::Frame; use crate::app::{App, ContextMenu}; diff --git a/mux/crates/mux-tui/src/ui/pane.rs b/mux/crates/mux-tui/src/ui/pane.rs index 8d1a93ff26b2..5c08d46dd5c1 100644 --- a/mux/crates/mux-tui/src/ui/pane.rs +++ b/mux/crates/mux-tui/src/ui/pane.rs @@ -8,12 +8,12 @@ use ghostty_vt::{Cell as VtCell, ColorSpec, RenderState, Rgb}; use mux_core::{BrowserStatus, Rect, SurfaceKind}; -use ratatui::style::{Color, Modifier, Style}; use ratatui::Frame; +use ratatui::style::{Color, Modifier, Style}; use super::{thumb_geometry, truncate}; use crate::app::{App, Hit, PaneArea, PaneEdge, Selection}; -use crate::config::{tab_label, Theme}; +use crate::config::{Theme, tab_label}; use crate::session::TabNotificationView; /// Border style for a pane box: active gets the accent color, idle diff --git a/mux/crates/mux-tui/src/ui/sidebar.rs b/mux/crates/mux-tui/src/ui/sidebar.rs index 0600e6621f5f..3c4ecba01cdc 100644 --- a/mux/crates/mux-tui/src/ui/sidebar.rs +++ b/mux/crates/mux-tui/src/ui/sidebar.rs @@ -7,8 +7,8 @@ //! after the sidebar). Rebuilds the click hit map as it draws. use mux_core::Rect; -use ratatui::style::{Color, Modifier, Style}; use ratatui::Frame; +use ratatui::style::{Color, Modifier, Style}; use super::truncate; use crate::app::{App, Hit}; From 02b1c72d7f62adef2f53c35ccd136d77b518a261 Mon Sep 17 00:00:00 2001 From: lawrencecchen <54008264+lawrencecchen@users.noreply.github.com> Date: Wed, 8 Jul 2026 15:34:59 -0700 Subject: [PATCH 2/4] mux: drop std::mem:: qualification on size_of (prelude since 1.80; unused_qualifications) --- mux/crates/ghostty-vt/src/render.rs | 2 +- mux/crates/ghostty-vt/src/terminal.rs | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mux/crates/ghostty-vt/src/render.rs b/mux/crates/ghostty-vt/src/render.rs index 2ab422ea2549..2b62190798cb 100644 --- a/mux/crates/ghostty-vt/src/render.rs +++ b/mux/crates/ghostty-vt/src/render.rs @@ -314,7 +314,7 @@ fn fill_cell(cells: sys::GhosttyRenderStateRowCells, cell: &mut Cell, grapheme_b } let mut style = - sys::GhosttyStyle { size: std::mem::size_of::(), ..Default::default() }; + sys::GhosttyStyle { size: size_of::(), ..Default::default() }; let style_ok = unsafe { sys::ghostty_render_state_row_cells_get( cells, diff --git a/mux/crates/ghostty-vt/src/terminal.rs b/mux/crates/ghostty-vt/src/terminal.rs index 63581543eb84..4f3d5832d9c4 100644 --- a/mux/crates/ghostty-vt/src/terminal.rs +++ b/mux/crates/ghostty-vt/src/terminal.rs @@ -357,25 +357,25 @@ impl Terminal { value: sys::GhosttyPointValue { coordinate: sys::GhosttyPointCoordinate { x, y } }, }; let mut out = sys::GhosttyGridRef { - size: std::mem::size_of::(), + size: size_of::(), ..Default::default() }; let result = unsafe { sys::ghostty_terminal_grid_ref(self.raw, point, &mut out) }; (result == sys::GHOSTTY_SUCCESS).then_some(out) }; let selection = sys::GhosttySelection { - size: std::mem::size_of::(), + size: size_of::(), start: grid_ref(start.0, start.1)?, end: grid_ref(end.0, end.1)?, rectangle: false, }; let opts = sys::GhosttyFormatterTerminalOptions { - size: std::mem::size_of::(), + size: size_of::(), emit: sys::GHOSTTY_FORMATTER_FORMAT_PLAIN, unwrap: unwrap_lines, trim, extra: sys::GhosttyFormatterTerminalExtra { - size: std::mem::size_of::(), + size: size_of::(), ..Default::default() }, selection: &selection, @@ -388,12 +388,12 @@ impl Terminal { /// scrollback. For the rendered viewport only, use [`Self::viewport_text`]. pub fn plain_text(&mut self) -> Result { let opts = sys::GhosttyFormatterTerminalOptions { - size: std::mem::size_of::(), + size: size_of::(), emit: sys::GHOSTTY_FORMATTER_FORMAT_PLAIN, unwrap: false, trim: true, extra: sys::GhosttyFormatterTerminalExtra { - size: std::mem::size_of::(), + size: size_of::(), ..Default::default() }, selection: ptr::null(), @@ -408,12 +408,12 @@ impl Terminal { /// frontend replays this, then follows the live pty stream. pub fn vt_replay(&mut self) -> Result> { let opts = sys::GhosttyFormatterTerminalOptions { - size: std::mem::size_of::(), + size: size_of::(), emit: sys::GHOSTTY_FORMATTER_FORMAT_VT, unwrap: false, trim: false, extra: sys::GhosttyFormatterTerminalExtra { - size: std::mem::size_of::(), + size: size_of::(), palette: true, modes: true, scrolling_region: true, @@ -421,7 +421,7 @@ impl Terminal { pwd: true, keyboard: true, screen: sys::GhosttyFormatterScreenExtra { - size: std::mem::size_of::(), + size: size_of::(), cursor: true, style: true, hyperlink: true, From a8eee6845cad68364e2a5c05fd48f4baa6448427 Mon Sep 17 00:00:00 2001 From: lawrencecchen <54008264+lawrencecchen@users.noreply.github.com> Date: Wed, 8 Jul 2026 18:44:52 -0700 Subject: [PATCH 3/4] mux: fix remaining edition-2024/lint fallout per judge review mux-core: collapse 13 nested ifs into let-chains (edition 2024 idiom), drop one redundant clone, remove needless_pass_by_value from workspace lints (signature churn). mux-tui: wrap test env set_var/remove_var in unsafe (unsafe fn in edition 2024; serialized by CONFIG_ENV_LOCK), inline format args in cli.rs print_tree, add missing statement semicolons in main.rs. --- mux/Cargo.toml | 2 +- mux/crates/mux-core/src/browser.rs | 24 ++++++++--------- mux/crates/mux-core/src/mux.rs | 41 +++++++++++++++--------------- mux/crates/mux-core/src/server.rs | 17 ++++++------- mux/crates/mux-core/src/surface.rs | 41 +++++++++++++++--------------- mux/crates/mux-tui/src/cli.rs | 2 +- mux/crates/mux-tui/src/config.rs | 18 ++++++++----- mux/crates/mux-tui/src/main.rs | 11 ++++---- 8 files changed, 81 insertions(+), 75 deletions(-) diff --git a/mux/Cargo.toml b/mux/Cargo.toml index 37b54b452744..a58f5ceb19db 100644 --- a/mux/Cargo.toml +++ b/mux/Cargo.toml @@ -23,7 +23,7 @@ unused_qualifications = "warn" uninlined_format_args = "warn" semicolon_if_nothing_returned = "warn" redundant_clone = "warn" -needless_pass_by_value = "warn" +# Evaluated and dropped: needless_pass_by_value causes signature churn across mux-core call sites. [workspace.dependencies] ghostty-vt-sys = { path = "crates/ghostty-vt-sys" } diff --git a/mux/crates/mux-core/src/browser.rs b/mux/crates/mux-core/src/browser.rs index bcad1a8ef903..9158372af089 100644 --- a/mux/crates/mux-core/src/browser.rs +++ b/mux/crates/mux-core/src/browser.rs @@ -344,10 +344,10 @@ fn scaled_pixels(pane_px_w: u32, pane_px_h: u32, scale: f64) -> (u32, u32) { fn runtime_endpoint( opts: &SurfaceOptions, ) -> anyhow::Result<(String, Option, BrowserSource)> { - if let Ok(url) = std::env::var("CMUX_MUX_CDP_URL") { - if !url.trim().is_empty() { - return Ok((resolve_browser_ws_url(&url)?, None, BrowserSource::External)); - } + if let Ok(url) = std::env::var("CMUX_MUX_CDP_URL") + && !url.trim().is_empty() + { + return Ok((resolve_browser_ws_url(&url)?, None, BrowserSource::External)); } if let Some(url) = opts.cdp_url.as_deref().filter(|url| !url.trim().is_empty()) { return Ok((resolve_browser_ws_url(url)?, None, BrowserSource::External)); @@ -518,10 +518,10 @@ fn start_surface_thread( seq: 0, }; browser.store_frame(frame); - if !browser.dirty.swap(true, Ordering::AcqRel) { - if let Some(mux) = mux.upgrade() { - mux.emit(MuxEvent::SurfaceOutput(id)); - } + if !browser.dirty.swap(true, Ordering::AcqRel) + && let Some(mux) = mux.upgrade() + { + mux.emit(MuxEvent::SurfaceOutput(id)); } } CdpEvent::TargetCreated(created) => { @@ -532,10 +532,10 @@ fn start_surface_thread( let url_changed = if info.url.is_empty() { false } else { browser.set_url(info.url) }; let title_changed = browser.set_title(title); - if url_changed || title_changed { - if let Some(mux) = mux.upgrade() { - mux.emit(MuxEvent::TitleChanged(id)); - } + if (url_changed || title_changed) + && let Some(mux) = mux.upgrade() + { + mux.emit(MuxEvent::TitleChanged(id)); } } CdpEvent::Other { method, params, .. } if method == "Page.frameNavigated" => { diff --git a/mux/crates/mux-core/src/mux.rs b/mux/crates/mux-core/src/mux.rs index fb575672403a..ff8a3edf9401 100644 --- a/mux/crates/mux-core/src/mux.rs +++ b/mux/crates/mux-core/src/mux.rs @@ -456,14 +456,14 @@ impl Mux { ) -> u64 { let id = self.next_notification_id(); let mut unread_changed = false; - if let Some(surface) = surface { - if self.active_surface() != Some(surface) { - self.surface_notifications - .lock() - .unwrap() - .insert(surface, SurfaceNotification { notification: id, level, unread: true }); - unread_changed = true; - } + if let Some(surface) = surface + && self.active_surface() != Some(surface) + { + self.surface_notifications + .lock() + .unwrap() + .insert(surface, SurfaceNotification { notification: id, level, unread: true }); + unread_changed = true; } self.emit(MuxEvent::Notification(NotificationEvent { notification: id, @@ -486,10 +486,11 @@ impl Mux { session: Option, ) -> AgentRecord { let mut records = self.agent_records.lock().unwrap(); - if let Some(existing) = records.get(&surface) { - if existing.source == AgentSource::Hook && source == AgentSource::Socket { - return existing.clone(); - } + if let Some(existing) = records.get(&surface) + && existing.source == AgentSource::Hook + && source == AgentSource::Socket + { + return existing.clone(); } let record = AgentRecord { surface, state, source, session, updated_at_ms: now_ms() }; records.insert(surface, record.clone()); @@ -1338,10 +1339,10 @@ impl Mux { ) -> anyhow::Result { { let state = self.state.lock().unwrap(); - if let Some(id) = workspace { - if !state.workspaces.iter().any(|ws| ws.id == id) { - anyhow::bail!("unknown workspace {id}"); - } + if let Some(id) = workspace + && !state.workspaces.iter().any(|ws| ws.id == id) + { + anyhow::bail!("unknown workspace {id}"); } } @@ -1591,10 +1592,10 @@ impl Drop for Mux { surface.kill(); } } - if let Ok(runtime) = self.browser_runtime.get_mut() { - if let Some(runtime) = runtime.take() { - runtime.shutdown(); - } + if let Ok(runtime) = self.browser_runtime.get_mut() + && let Some(runtime) = runtime.take() + { + runtime.shutdown(); } } } diff --git a/mux/crates/mux-core/src/server.rs b/mux/crates/mux-core/src/server.rs index 44ecbd8e1054..69f1df096b2c 100644 --- a/mux/crates/mux-core/src/server.rs +++ b/mux/crates/mux-core/src/server.rs @@ -675,10 +675,10 @@ fn workspaces_json( fn ids_json(state: &State, kind: Option<&str>) -> anyhow::Result { let allowed = ["workspace", "screen", "pane", "surface"]; - if let Some(kind) = kind { - if !allowed.contains(&kind) { - anyhow::bail!("bad kind {kind}"); - } + if let Some(kind) = kind + && !allowed.contains(&kind) + { + anyhow::bail!("bad kind {kind}"); } let mut raw = Vec::new(); for ws in &state.workspaces { @@ -1415,11 +1415,10 @@ fn handle_command(mux: &Arc, cmd: Command, writer: &LineWriter) -> anyhow:: std::thread::Builder::new().name("mux-attach-out".into()).spawn(move || { while frames.notify.recv().is_ok() { let update = std::mem::take(&mut *frames.slot.lock().unwrap()); - if let Some(state) = update.state { - if writer.send(&browser_state_json(surface_id, &state, false)).is_err() - { - break; - } + if let Some(state) = update.state + && writer.send(&browser_state_json(surface_id, &state, false)).is_err() + { + break; } if let Some(frame) = update.frame { let value = json!({ diff --git a/mux/crates/mux-core/src/surface.rs b/mux/crates/mux-core/src/surface.rs index ea70ab564d6b..af47cdf410a6 100644 --- a/mux/crates/mux-core/src/surface.rs +++ b/mux/crates/mux-core/src/surface.rs @@ -266,7 +266,6 @@ impl Surface { // PTY reader: pty bytes -> terminal state -> SurfaceOutput events. std::thread::Builder::new().name(format!("surface-{id}-reader")).spawn({ let surface = surface.clone(); - let mux = mux.clone(); move || { let mut buf = [0u8; 64 * 1024]; loop { @@ -302,23 +301,23 @@ impl Surface { scroll_changed = Some(after); } } - if let Some((offset, at_bottom)) = scroll_changed { - if let Some(mux) = mux.upgrade() { - mux.emit(MuxEvent::ScrollChanged { - surface: surface.id, - offset, - at_bottom, - }); - } + if let Some((offset, at_bottom)) = scroll_changed + && let Some(mux) = mux.upgrade() + { + mux.emit(MuxEvent::ScrollChanged { + surface: surface.id, + offset, + at_bottom, + }); } let responses = std::mem::take(&mut *pending_responses.lock().unwrap()); if !responses.is_empty() { let _ = surface.write_bytes(&responses); } - if !pty.dirty.swap(true, Ordering::AcqRel) { - if let Some(mux) = mux.upgrade() { - mux.emit(MuxEvent::SurfaceOutput(surface.id)); - } + if !pty.dirty.swap(true, Ordering::AcqRel) + && let Some(mux) = mux.upgrade() + { + mux.emit(MuxEvent::SurfaceOutput(surface.id)); } } if let Some(pty) = surface.as_pty() { @@ -449,10 +448,10 @@ impl Surface { let after = terminal_scroll_position(&term); (before != after).then_some(after) }; - if let Some((offset, at_bottom)) = changed { - if let Some(mux) = pty.mux.upgrade() { - mux.emit(MuxEvent::ScrollChanged { surface: self.id, offset, at_bottom }); - } + if let Some((offset, at_bottom)) = changed + && let Some(mux) = pty.mux.upgrade() + { + mux.emit(MuxEvent::ScrollChanged { surface: self.id, offset, at_bottom }); } Ok(()) } @@ -468,10 +467,10 @@ impl Surface { let after = terminal_scroll_position(&term); (before != after).then_some(after) }; - if let Some((offset, at_bottom)) = changed { - if let Some(mux) = pty.mux.upgrade() { - mux.emit(MuxEvent::ScrollChanged { surface: self.id, offset, at_bottom }); - } + if let Some((offset, at_bottom)) = changed + && let Some(mux) = pty.mux.upgrade() + { + mux.emit(MuxEvent::ScrollChanged { surface: self.id, offset, at_bottom }); } Ok(()) } diff --git a/mux/crates/mux-tui/src/cli.rs b/mux/crates/mux-tui/src/cli.rs index 6e8df8408d4d..cfbecb5e13c4 100644 --- a/mux/crates/mux-tui/src/cli.rs +++ b/mux/crates/mux-tui/src/cli.rs @@ -1273,7 +1273,7 @@ fn print_tree(data: &Value, out: &mut dyn Write) -> io::Result<()> { for pane in panes { let pane_id = id_field(pane, "id"); if bool_field(pane, "dead") { - writeln!(out, "pane id={} screen={} dead=true", pane_id, screen_id)?; + writeln!(out, "pane id={pane_id} screen={screen_id} dead=true")?; continue; } writeln!( diff --git a/mux/crates/mux-tui/src/config.rs b/mux/crates/mux-tui/src/config.rs index 0e3678299588..89dc8a9570b2 100644 --- a/mux/crates/mux-tui/src/config.rs +++ b/mux/crates/mux-tui/src/config.rs @@ -889,9 +889,11 @@ mod tests { }"##, ) .unwrap(); - std::env::set_var("CMUX_MUX_CONFIG", &path); + // SAFETY: env mutation in tests is serialized by CONFIG_ENV_LOCK. + unsafe { std::env::set_var("CMUX_MUX_CONFIG", &path) }; let config = load(); - std::env::remove_var("CMUX_MUX_CONFIG"); + // SAFETY: env mutation in tests is serialized by CONFIG_ENV_LOCK. + unsafe { std::env::remove_var("CMUX_MUX_CONFIG") }; let _ = std::fs::remove_file(&path); assert_eq!(config.theme.selection_bg, Color::Rgb(0x10, 0x10, 0x10)); assert_eq!(config.theme.sidebar_rail, Color::Indexed(42)); @@ -972,13 +974,15 @@ mod tests { std::fs::create_dir_all(&dir).unwrap(); let path = dir.join("mux.json"); std::fs::write(&path, r##"{"theme": {"selection_foreground": null}}"##).unwrap(); - std::env::set_var("CMUX_MUX_CONFIG", &path); + // SAFETY: env mutation in tests is serialized by CONFIG_ENV_LOCK. + unsafe { std::env::set_var("CMUX_MUX_CONFIG", &path) }; // `load()` always seeds `selection_fg` from the Ghostty selection // colors (or leaves it `None` if there aren't any) before applying // this override, so regardless of the ambient Ghostty config, an // explicit `null` here must land back on `None`. let config = load(); - std::env::remove_var("CMUX_MUX_CONFIG"); + // SAFETY: env mutation in tests is serialized by CONFIG_ENV_LOCK. + unsafe { std::env::remove_var("CMUX_MUX_CONFIG") }; let _ = std::fs::remove_file(&path); assert_eq!(config.theme.selection_fg, None); } @@ -995,7 +999,8 @@ mod tests { r##"{"browser": {"max_capture_megapixels": 3.5, "capture_scale": 0.5}}"##, ) .unwrap(); - std::env::set_var("CMUX_MUX_CONFIG", &path); + // SAFETY: env mutation in tests is serialized by CONFIG_ENV_LOCK. + unsafe { std::env::set_var("CMUX_MUX_CONFIG", &path) }; let config = load(); assert_eq!(config.browser.max_capture_megapixels, 3.5); assert_eq!(config.browser.capture_scale, Some(0.5)); @@ -1006,7 +1011,8 @@ mod tests { ) .unwrap(); let config = load(); - std::env::remove_var("CMUX_MUX_CONFIG"); + // SAFETY: env mutation in tests is serialized by CONFIG_ENV_LOCK. + unsafe { std::env::remove_var("CMUX_MUX_CONFIG") }; let _ = std::fs::remove_file(&path); assert_eq!( config.browser.max_capture_megapixels, diff --git a/mux/crates/mux-tui/src/main.rs b/mux/crates/mux-tui/src/main.rs index 5de283c5b3ea..20066942db58 100644 --- a/mux/crates/mux-tui/src/main.rs +++ b/mux/crates/mux-tui/src/main.rs @@ -110,15 +110,16 @@ fn parse_args(args: impl IntoIterator) -> Args { while let Some(arg) = args.next() { match arg.as_str() { "--session" => { - out.session = args.next().unwrap_or_else(|| usage_exit("--session needs a value")) + out.session = args.next().unwrap_or_else(|| usage_exit("--session needs a value")); } "--socket" => { - out.socket = - Some(args.next().unwrap_or_else(|| usage_exit("--socket needs a value")).into()) + out.socket = Some( + args.next().unwrap_or_else(|| usage_exit("--socket needs a value")).into(), + ); } "--headless" => out.headless = true, "--term" => { - out.term = Some(args.next().unwrap_or_else(|| usage_exit("--term needs a value"))) + out.term = Some(args.next().unwrap_or_else(|| usage_exit("--term needs a value"))); } "-h" | "--help" => { print!("{USAGE}"); @@ -204,7 +205,7 @@ fn run_headless(mux: &Arc, socket_path: &std::path::Path) -> anyhow::Result match events.recv_timeout(std::time::Duration::from_millis(250)) { Ok(_) | Err(std::sync::mpsc::RecvTimeoutError::Timeout) => {} Err(std::sync::mpsc::RecvTimeoutError::Disconnected) => { - std::thread::park_timeout(std::time::Duration::from_millis(250)) + std::thread::park_timeout(std::time::Duration::from_millis(250)); } } } From 8cd6b03d01f8400a5ba169917c771c6dd2a28606 Mon Sep 17 00:00:00 2001 From: lawrencecchen <54008264+lawrencecchen@users.noreply.github.com> Date: Wed, 8 Jul 2026 18:58:26 -0700 Subject: [PATCH 4/4] mux-tui: collapse nested ifs into let-chains, drop redundant tx clone (clippy round 3) --- mux/crates/mux-tui/src/app.rs | 52 ++++++++++++------------ mux/crates/mux-tui/src/cli.rs | 8 ++-- mux/crates/mux-tui/src/config.rs | 8 ++-- mux/crates/mux-tui/src/session/remote.rs | 12 +++--- mux/crates/mux-tui/src/session/tree.rs | 8 ++-- mux/crates/mux-tui/src/ui/graphics.rs | 6 +-- mux/crates/mux-tui/src/ui/mod.rs | 8 ++-- mux/crates/mux-tui/src/ui/pane.rs | 12 +++--- mux/crates/mux-tui/src/ui/sidebar.rs | 10 ++--- 9 files changed, 60 insertions(+), 64 deletions(-) diff --git a/mux/crates/mux-tui/src/app.rs b/mux/crates/mux-tui/src/app.rs index 4aad9ab07294..786921c8f8ca 100644 --- a/mux/crates/mux-tui/src/app.rs +++ b/mux/crates/mux-tui/src/app.rs @@ -481,10 +481,10 @@ fn smart_split_target( cell_pixels: (u16, u16), ) -> Option<(PaneId, SplitDir)> { let ratio = cell_height_width_ratio(cell_pixels); - if let Some(area) = focused.and_then(|pane| areas.iter().find(|area| area.pane == pane)) { - if let Some(dir) = zellij_smart_direction(area.content, ratio) { - return Some((area.pane, dir)); - } + if let Some(area) = focused.and_then(|pane| areas.iter().find(|area| area.pane == pane)) + && let Some(dir) = zellij_smart_direction(area.content, ratio) + { + return Some((area.pane, dir)); } areas .iter() @@ -600,7 +600,6 @@ pub fn run(session: Session, session_label: String) -> anyhow::Result<()> { // Crossterm input → app channel. Start this after startup terminal // probes so DA / window-size responses are not consumed as key input. std::thread::Builder::new().name("input".into()).spawn({ - let tx = tx.clone(); move || { while let Ok(event) = crossterm::event::read() { if tx.send(AppEvent::Input(event)).is_err() { @@ -1667,18 +1666,17 @@ impl App { return; } let Some((surface_id, surface)) = self.active_surface_with_handle() else { return }; - if let KeyCode::Char(c) = key.code { - if !key + if let KeyCode::Char(c) = key.code + && !key .modifiers .intersects(KeyModifiers::CONTROL | KeyModifiers::ALT | KeyModifiers::SUPER) - { - self.browser_input.enqueue(BrowserInputEvent { - surface_id, - surface, - kind: BrowserInputKind::InsertText(c.to_string()), - }); - return; - } + { + self.browser_input.enqueue(BrowserInputEvent { + surface_id, + surface, + kind: BrowserInputKind::InsertText(c.to_string()), + }); + return; } let Some((key_name, code, vk, text)) = browser_key_mapping(key.code) else { return }; let modifiers = browser_modifiers(key.modifiers); @@ -1892,14 +1890,14 @@ impl App { /// hovered element actually changes. fn handle_hover(&mut self, x: u16, y: u16) -> anyhow::Result { self.sync_pointer_shape(x, y); - if let Some(menu) = self.menu.as_mut() { - if let Some(item) = menu.item_at(x, y) { - if item != menu.selected { - menu.selected = item; - return Ok(RenderAction::Draw); - } - return Ok(RenderAction::None); + if let Some(menu) = self.menu.as_mut() + && let Some(item) = menu.item_at(x, y) + { + if item != menu.selected { + menu.selected = item; + return Ok(RenderAction::Draw); } + return Ok(RenderAction::None); } if self.menu.is_none() && self.prompt.is_none() && self.drag.is_none() { let mut over_browser = false; @@ -1966,11 +1964,11 @@ impl App { if (x, y) != menu.right_press { menu.right_drag_moved = true; } - if let Some(item) = menu.item_at(x, y) { - if item != menu.selected { - menu.selected = item; - return Ok(RenderAction::Draw); - } + if let Some(item) = menu.item_at(x, y) + && item != menu.selected + { + menu.selected = item; + return Ok(RenderAction::Draw); } Ok(RenderAction::None) } diff --git a/mux/crates/mux-tui/src/cli.rs b/mux/crates/mux-tui/src/cli.rs index cfbecb5e13c4..3e68774a1031 100644 --- a/mux/crates/mux-tui/src/cli.rs +++ b/mux/crates/mux-tui/src/cli.rs @@ -562,10 +562,10 @@ fn resolve_socket(global: &GlobalArgs) -> PathBuf { if let Some(path) = &global.socket { return path.clone(); } - if let Some(path) = std::env::var_os("CMUX_MUX_SOCKET") { - if !path.is_empty() { - return PathBuf::from(path); - } + if let Some(path) = std::env::var_os("CMUX_MUX_SOCKET") + && !path.is_empty() + { + return PathBuf::from(path); } let session = global.session.as_deref().unwrap_or("main"); mux_core::server::default_socket_path(session) diff --git a/mux/crates/mux-tui/src/config.rs b/mux/crates/mux-tui/src/config.rs index 89dc8a9570b2..7f31ed960d87 100644 --- a/mux/crates/mux-tui/src/config.rs +++ b/mux/crates/mux-tui/src/config.rs @@ -745,10 +745,10 @@ pub fn apply_browser_to_surface_options(config: &Config, options: &mut SurfaceOp /// plus a recognized agent program name (or the full title when /// `show_titles` is on). pub fn tab_label(tabs: &Tabs, index: usize, title: &str, name: Option<&str>) -> String { - if let Some(name) = name { - if !name.is_empty() { - return name.to_string(); - } + if let Some(name) = name + && !name.is_empty() + { + return name.to_string(); } let number = index + 1; let suffix = if tabs.show_titles { diff --git a/mux/crates/mux-tui/src/session/remote.rs b/mux/crates/mux-tui/src/session/remote.rs index 54f0162f9fd0..bf5fb68bd52c 100644 --- a/mux/crates/mux-tui/src/session/remote.rs +++ b/mux/crates/mux-tui/src/session/remote.rs @@ -75,12 +75,12 @@ impl RemoteSurface { let (cols, rows) = (cols.max(1), rows.max(1)); self.set_server_size(cols, rows); let mut term = self.term.lock().unwrap(); - if let Some(replay) = replay { - if let Ok(mut fresh) = Terminal::new(cols, rows, 10_000, Callbacks::default()) { - fresh.vt_write(replay); - *term = fresh; - return; - } + if let Some(replay) = replay + && let Ok(mut fresh) = Terminal::new(cols, rows, 10_000, Callbacks::default()) + { + fresh.vt_write(replay); + *term = fresh; + return; } let _ = term.resize(cols, rows, 8, 16); } diff --git a/mux/crates/mux-tui/src/session/tree.rs b/mux/crates/mux-tui/src/session/tree.rs index afbb29f59f64..a6d983ecf7f3 100644 --- a/mux/crates/mux-tui/src/session/tree.rs +++ b/mux/crates/mux-tui/src/session/tree.rs @@ -130,10 +130,10 @@ impl PaneView { /// Display name: the user-assigned name, else the active tab's /// process title, else "shell". pub fn display_name(&self) -> &str { - if let Some(name) = self.name.as_deref() { - if !name.is_empty() { - return name; - } + if let Some(name) = self.name.as_deref() + && !name.is_empty() + { + return name; } self.tabs .get(self.active_tab) diff --git a/mux/crates/mux-tui/src/ui/graphics.rs b/mux/crates/mux-tui/src/ui/graphics.rs index 61127a3ccd74..c2d85f5ef195 100644 --- a/mux/crates/mux-tui/src/ui/graphics.rs +++ b/mux/crates/mux-tui/src/ui/graphics.rs @@ -108,10 +108,8 @@ pub fn detect_cell_pixels(query_fallback: bool) -> (u16, u16) { if let Some(cell) = ioctl_cell_pixels() { return cell; } - if query_fallback { - if let Some(cell) = query_cell_pixels() { - return cell; - } + if query_fallback && let Some(cell) = query_cell_pixels() { + return cell; } (8, 16) } diff --git a/mux/crates/mux-tui/src/ui/mod.rs b/mux/crates/mux-tui/src/ui/mod.rs index 4524c802c0c3..64b26188e32d 100644 --- a/mux/crates/mux-tui/src/ui/mod.rs +++ b/mux/crates/mux-tui/src/ui/mod.rs @@ -41,10 +41,10 @@ pub fn draw(app: &mut App, frame: &mut Frame) { // sets it on the input row). if app.prompt.is_some() { overlay::draw_prompt(app, frame); - } else if app.menu.is_none() { - if let Some((x, y)) = cursor { - frame.set_cursor_position(Position::new(x, y)); - } + } else if app.menu.is_none() + && let Some((x, y)) = cursor + { + frame.set_cursor_position(Position::new(x, y)); } } diff --git a/mux/crates/mux-tui/src/ui/pane.rs b/mux/crates/mux-tui/src/ui/pane.rs index 5c08d46dd5c1..45339c723e21 100644 --- a/mux/crates/mux-tui/src/ui/pane.rs +++ b/mux/crates/mux-tui/src/ui/pane.rs @@ -341,12 +341,12 @@ fn draw_content( } } - if focused { - if let Some(cursor) = rs.cursor() { - if (cursor.x as usize) < max_cols && (cursor.y as usize) < max_rows { - return Some((rect.x + cursor.x, rect.y + cursor.y)); - } - } + if focused + && let Some(cursor) = rs.cursor() + && (cursor.x as usize) < max_cols + && (cursor.y as usize) < max_rows + { + return Some((rect.x + cursor.x, rect.y + cursor.y)); } None } diff --git a/mux/crates/mux-tui/src/ui/sidebar.rs b/mux/crates/mux-tui/src/ui/sidebar.rs index 3c4ecba01cdc..2ea1f7d75536 100644 --- a/mux/crates/mux-tui/src/ui/sidebar.rs +++ b/mux/crates/mux-tui/src/ui/sidebar.rs @@ -96,11 +96,11 @@ pub fn draw(app: &mut App, frame: &mut Frame) { buf[(0, y)].set_symbol("▎").set_style(rail_style); buf[(0, y + 1)].set_symbol("▎").set_style(rail_style); } - if content_w > 1 { - if let Some(color) = workspace_unread_color(&app.config.theme, ws) { - let dot_style = style.fg(color).add_modifier(Modifier::BOLD); - buf[(0, y)].set_symbol("•").set_style(dot_style); - } + if content_w > 1 + && let Some(color) = workspace_unread_color(&app.config.theme, ws) + { + let dot_style = style.fg(color).add_modifier(Modifier::BOLD); + buf[(0, y)].set_symbol("•").set_style(dot_style); } set_line_from(buf, 1, y, &truncate(&ws.name, content_w - 1), style); hits.push((row_rect(y), Hit::Workspace { index: i, id: ws.id }));