From 8b2f8587e75c38f64b57c16dfb619cfe490050ee Mon Sep 17 00:00:00 2001 From: Noam Lewis Date: Tue, 24 Feb 2026 21:52:35 +0200 Subject: [PATCH 1/6] Upgrade dependencies: oxc 0.115, ts-rs 12, rquickjs-serde 0.5, tempfile 3.25 Update ts_export.rs for ts-rs v12 breaking change (decl() now takes &Config). Co-Authored-By: Claude Opus 4.6 --- Cargo.lock | 475 ++++++++++--------- Cargo.toml | 20 +- crates/fresh-editor/Cargo.toml | 6 +- crates/fresh-plugin-runtime/src/ts_export.rs | 79 +-- 4 files changed, 294 insertions(+), 286 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 95d8e4d76..5763d4b2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,7 +54,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46319972e74179d707445f64aaa2893bbf6a111de3a9af29b7eb382f8b39e282" dependencies = [ "base64", - "bitflags 2.10.0", + "bitflags 2.11.0", "home", "libc", "log", @@ -85,7 +85,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", - "bitflags 2.10.0", + "bitflags 2.11.0", "cc", "cesu8", "jni", @@ -122,9 +122,9 @@ checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anyhow" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "arboard" @@ -146,9 +146,9 @@ dependencies = [ [[package]] name = "arc-swap" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ded5f9a03ac8f24d1b8a25101ee812cd32cdc8c50a4c50237de2c4915850e73" +checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5" dependencies = [ "rustversion", ] @@ -205,7 +205,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -266,7 +266,7 @@ version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "cexpr", "clang-sys", "itertools 0.13.0", @@ -277,7 +277,7 @@ dependencies = [ "regex", "rustc-hash 2.1.1", "shlex", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -318,9 +318,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" dependencies = [ "serde_core", ] @@ -373,9 +373,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.1" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "bytemuck" @@ -394,7 +394,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -427,7 +427,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -442,7 +442,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "log", "polling", "rustix 0.38.44", @@ -473,9 +473,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.55" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ "find-msvc-tools", "jobserver", @@ -534,7 +534,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f222a8380768a3f6cd3fb0a77f710e6e08113c815399b8609d1f1d18db40640" dependencies = [ "ahash", - "bitflags 2.10.0", + "bitflags 2.11.0", "cached", "counter", "encoding", @@ -552,9 +552,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.43" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ "iana-time-zone", "num-traits", @@ -580,9 +580,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.57" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6899ea499e3fb9305a65d5ebf6e3d2248c5fab291f300ad0a704fbe142eae31a" +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" dependencies = [ "clap_builder", "clap_derive", @@ -590,9 +590,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.57" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b12c8b680195a62a8364d16b8447b01b6c2c8f9aaf68bee653be34d4245e238" +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" dependencies = [ "anstyle", "clap_lex", @@ -607,14 +607,14 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "clap_lex" -version = "0.7.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" [[package]] name = "clipboard-win" @@ -775,7 +775,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "core-foundation 0.10.1", "libc", ] @@ -854,7 +854,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ "base64", - "bitflags 2.10.0", + "bitflags 2.11.0", "crossterm_winapi", "derive_more", "document-features", @@ -954,7 +954,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -967,7 +967,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -978,7 +978,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -989,7 +989,7 @@ checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ "darling_core 0.23.0", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1000,9 +1000,9 @@ checksum = "5729f5117e208430e437df2f4843f5e5952997175992d1414f94c57d61e270b4" [[package]] name = "deranged" -version = "0.5.5" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ "powerfmt", ] @@ -1026,7 +1026,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1072,7 +1072,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "objc2 0.6.3", ] @@ -1084,7 +1084,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1125,9 +1125,9 @@ checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" [[package]] name = "dragonbox_ecma" -version = "0.1.0" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a5577f010d4e1bb3f3c4d6081e05718eb6992cf20119cab4d3abadff198b5ae" +checksum = "fd8e701084c37e7ef62d3f9e453b618130cbc0ef3573847785952a3ac3f746bf" [[package]] name = "dtor" @@ -1435,7 +1435,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1592,7 +1592,7 @@ version = "0.2.7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -1627,15 +1627,15 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-task" @@ -1645,14 +1645,13 @@ checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-core", "futures-task", "pin-project-lite", - "pin-utils", "slab", ] @@ -1794,7 +1793,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "gpu-descriptor-types", "hashbrown 0.15.5", ] @@ -1805,7 +1804,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", ] [[package]] @@ -2117,7 +2116,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -2232,14 +2231,14 @@ dependencies = [ "indoc", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "interprocess" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53bf2b0e0785c5394a7392f66d7c4fb9c653633c29b27a932280da3cb344c66a" +checksum = "6be5e5c847dbdb44564bd85294740d031f4f8aeb3464e5375ef7141f7538db69" dependencies = [ "doctest-file", "futures-core", @@ -2336,9 +2335,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.85" +version = "0.3.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +checksum = "f4eacb0641a310445a4c513f2a5e23e19952e269c6a38887254d5f837a305506" dependencies = [ "once_cell", "wasm-bindgen", @@ -2434,9 +2433,9 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "libc", - "redox_syscall 0.7.1", + "redox_syscall 0.7.2", ] [[package]] @@ -2445,7 +2444,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f4de44e98ddbf09375cbf4d17714d18f39195f4f4894e8524501726fd9a8a4a" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", ] [[package]] @@ -2596,7 +2595,7 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7047791b5bc903b8cd963014b355f71dc9864a9a0b727057676c1dcae5cbc15" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "block", "core-graphics-types 0.2.0", "foreign-types", @@ -2650,7 +2649,7 @@ checksum = "618f667225063219ddfc61251087db8a9aec3c3f0950c916b614e403486f1135" dependencies = [ "arrayvec", "bit-set 0.8.0", - "bitflags 2.10.0", + "bitflags 2.11.0", "cfg-if", "cfg_aliases 0.2.1", "codespan-reporting", @@ -2674,7 +2673,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "jni-sys", "log", "ndk-sys", @@ -2704,7 +2703,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "cfg-if", "cfg_aliases 0.1.1", "libc", @@ -2716,7 +2715,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "cfg-if", "cfg_aliases 0.2.1", "libc", @@ -2729,7 +2728,7 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "225e7cfe711e0ba79a68baeddb2982723e4235247aefce1482f2f16c27865b66" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "cfg-if", "cfg_aliases 0.2.1", "libc", @@ -2802,7 +2801,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -2843,7 +2842,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -2895,7 +2894,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "block2", "libc", "objc2 0.5.2", @@ -2911,7 +2910,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "objc2 0.6.3", "objc2-core-graphics", "objc2-foundation 0.3.2", @@ -2923,7 +2922,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "block2", "objc2 0.5.2", "objc2-core-location", @@ -2947,7 +2946,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -2959,7 +2958,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "dispatch2", "objc2 0.6.3", ] @@ -2970,7 +2969,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "dispatch2", "objc2 0.6.3", "objc2-core-foundation", @@ -3013,7 +3012,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "block2", "dispatch", "libc", @@ -3026,7 +3025,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "objc2 0.6.3", "objc2-core-foundation", ] @@ -3037,7 +3036,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "objc2 0.6.3", "objc2-core-foundation", ] @@ -3060,7 +3059,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -3072,7 +3071,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "block2", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -3095,7 +3094,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "block2", "objc2 0.5.2", "objc2-cloud-kit", @@ -3127,7 +3126,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "block2", "objc2 0.5.2", "objc2-core-location", @@ -3146,7 +3145,7 @@ version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "libc", "once_cell", "onig_sys", @@ -3207,6 +3206,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ordered-float" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4779c6901a562440c3786d08192c6fbda7c1c2060edd10006b05ee35d10f2d" +dependencies = [ + "num-traits", +] + [[package]] name = "os_pipe" version = "1.2.3" @@ -3234,15 +3242,15 @@ dependencies = [ [[package]] name = "owo-colors" -version = "4.2.3" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" +checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d" [[package]] name = "oxc-browserslist" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b1853bc34cadaa90aa09f95713d8b77ec0c0d3e2d90ccf7a74216f40d20850" +checksum = "abb7a1163a5501f935f8722d839b576491b749c695e7a066aa0b8df988b806df" dependencies = [ "flate2", "postcard", @@ -3275,14 +3283,14 @@ checksum = "d4faecb54d0971f948fbc1918df69b26007e6f279a204793669542e1e8b75eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "oxc_allocator" -version = "0.112.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7b9c7293fac710d0be6e941b70749566dc69f1918cf0446a677d0eb9a7c8259" +checksum = "e16d4295cf7888893b80ae70ff65c078ae3f9f52d5381cfc7eeffab089e07305" dependencies = [ "allocator-api2", "hashbrown 0.16.1", @@ -3292,11 +3300,11 @@ dependencies = [ [[package]] name = "oxc_ast" -version = "0.112.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd97b20b4ad9987795c0e5eda56752de8c24682a4e2cd6b1698fdc8135510e3" +checksum = "be755331a7de00100c60e03151663f26037a0dd720be238de57c036be03b4033" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "oxc_allocator", "oxc_ast_macros", "oxc_data_structures", @@ -3309,21 +3317,21 @@ dependencies = [ [[package]] name = "oxc_ast_macros" -version = "0.112.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58b1eb3b6f9ed42c528030161d0370b023229ed05b785baf7a80d7e99a794da2" +checksum = "a13a58adcfaadd4710b4f7d80ad422599ed5bb4956f4747d07e821c5897b16ef" dependencies = [ "phf 0.13.1", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "oxc_ast_visit" -version = "0.112.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936eaf04ad8fd9f1e7613e277a7a0a2f8575fa9543c7a0fac4a8a6f590c8527c" +checksum = "4e33ffb874949ea07fce9b686c2dba7e221c849e047232c04a84b13bae4496ef" dependencies = [ "oxc_allocator", "oxc_ast", @@ -3333,11 +3341,11 @@ dependencies = [ [[package]] name = "oxc_codegen" -version = "0.112.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb04590335665806a3bc39485bb2f3c31d198c1dfd6bf7aa8405cd93b8205a0" +checksum = "f81db7038dc0288704c5ad72453c96933a46e2d5139376c87b1f5730b3d9cd03" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "cow-utils", "dragonbox_ecma", "itoa", @@ -3354,9 +3362,9 @@ dependencies = [ [[package]] name = "oxc_compat" -version = "0.112.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a1d5d8480010cab1dd1ede5287085472224f39aace766dcd2ae4c0005f3273" +checksum = "c96a136e3422c1b14babd3fe1103e4bc93036c10e72fe4f8634c881ec5285c2d" dependencies = [ "cow-utils", "oxc-browserslist", @@ -3367,18 +3375,18 @@ dependencies = [ [[package]] name = "oxc_data_structures" -version = "0.112.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea257e0e5a91b5cfcf06fd91744514d24e53c5450620f54a9fa1053f2b3fdf2" +checksum = "fd6c22a48542899e5f74162d55710ea2f95735c5d3a809196308b2dbf557f434" dependencies = [ "ropey", ] [[package]] name = "oxc_diagnostics" -version = "0.112.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed1dce4194036de316f09d86c9a02e42aab1693c20423f20dda694c5d9f04394" +checksum = "fe5961a78ce2a24d288f5e7090f19ce49d062486e0d65e6140d01582198c94fd" dependencies = [ "cow-utils", "oxc-miette", @@ -3387,9 +3395,9 @@ dependencies = [ [[package]] name = "oxc_ecmascript" -version = "0.112.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f9465ce204eaddca376dcc235a44915c05ad512e280417d2cafd6bb1934f04" +checksum = "e1fb3d121c372df31514f95d87c92693001739d2c9e56be37909499b5396faf1" dependencies = [ "cow-utils", "num-bigint", @@ -3403,9 +3411,9 @@ dependencies = [ [[package]] name = "oxc_estree" -version = "0.112.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1bc44f56db73d6b7a5b8c4b4979cde79809e7c18d7fe5d99dffc37128bedd8c" +checksum = "d38fc12975751e104dc53c369cba1598ff15aa8ca30aaac49e63937256316969" [[package]] name = "oxc_index" @@ -3419,11 +3427,11 @@ dependencies = [ [[package]] name = "oxc_parser" -version = "0.112.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38f73b67e2ae42ce4a14e4e1dc305d65e1ada635c52959dbfaad5eec7245a15" +checksum = "341602ba5eb6629f7f90e49c1fce06bb8eed989412a4178acd8e7f48cf2c7f9d" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "cow-utils", "memchr", "num-bigint", @@ -3442,11 +3450,11 @@ dependencies = [ [[package]] name = "oxc_regular_expression" -version = "0.112.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b53ad034b3b87531190c0adde3dca1ee8a3d09e9009960576077a4062d9bc10" +checksum = "8e810182cbde172aeada70acc45dae74f6773384e0d295cc27e6e377b1fc277c" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "oxc_allocator", "oxc_ast_macros", "oxc_diagnostics", @@ -3458,9 +3466,9 @@ dependencies = [ [[package]] name = "oxc_semantic" -version = "0.112.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bc73688fe48cf7f8cd6202216864c5d569f3903758b9b0c1733dbd1eedc1fce" +checksum = "ffb04bd9f59bb6d8340bb186b0003bb6e8f1988e17048c61a5473ea216e9ed71" dependencies = [ "itertools 0.14.0", "memchr", @@ -3493,9 +3501,9 @@ dependencies = [ [[package]] name = "oxc_span" -version = "0.112.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4807a64b6063717dcd863fb4c1ce5ec628728d037e2f20e3ffdcf3aa4adf96ca" +checksum = "b9999ef787b0b989b8c2b31669069d3bdca20d017ff34a7284ff9e983cf7b1d8" dependencies = [ "compact_str", "oxc-miette", @@ -3507,28 +3515,28 @@ dependencies = [ [[package]] name = "oxc_str" -version = "0.112.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c64a431903dbb9b8505324824d1bd50e52407ebc30bf9a42279cd477328223e" +checksum = "a6fde66bc256ea0d09895c2a56a24f79e76abffd977f6c171516e42f1efdea51" dependencies = [ "compact_str", + "hashbrown 0.16.1", "oxc_allocator", "oxc_estree", ] [[package]] name = "oxc_syntax" -version = "0.112.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c8d491f4b2755a81aac85cde4706b591129215b3a79229ed0607ef622ed38b" +checksum = "e77ea5bd4ea42ce05b2f51bcef8e46a4598cea5038ab25877a2d27601a90da83" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "cow-utils", "dragonbox_ecma", "nonmax", "oxc_allocator", "oxc_ast_macros", - "oxc_data_structures", "oxc_estree", "oxc_index", "oxc_span", @@ -3538,9 +3546,9 @@ dependencies = [ [[package]] name = "oxc_transformer" -version = "0.112.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "768f8763f5901f4f517b96a25235a838805764cff3c5d2a67eed3c07493f8894" +checksum = "58dd1805067e1770a648cd53fcf6c48da4312fedda734ef556880936f975320f" dependencies = [ "base64", "compact_str", @@ -3567,9 +3575,9 @@ dependencies = [ [[package]] name = "oxc_traverse" -version = "0.112.0" +version = "0.115.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b66d5f2c7cb914d0b773560986d39b0ae5efcf59ce2367c45d4e30f551500b4" +checksum = "aea73a8421e6a433a187fca1c5fe48237ee65eaf40e5dae158d2853f0b2d8949" dependencies = [ "itoa", "oxc_allocator", @@ -3579,6 +3587,7 @@ dependencies = [ "oxc_ecmascript", "oxc_semantic", "oxc_span", + "oxc_str", "oxc_syntax", "rustc-hash 2.1.1", ] @@ -3654,7 +3663,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -3739,7 +3748,7 @@ dependencies = [ "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -3752,7 +3761,7 @@ dependencies = [ "phf_shared 0.13.1", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -3790,7 +3799,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -3799,12 +3808,6 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "piper" version = "0.2.4" @@ -3841,7 +3844,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "crc32fast", "fdeflate", "flate2", @@ -3947,7 +3950,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -3982,7 +3985,7 @@ checksum = "37566cb3fdacef14c0737f9546df7cfeadbfbc9fef10991038bf5015d0c80532" dependencies = [ "bit-set 0.8.0", "bit-vec 0.8.0", - "bitflags 2.10.0", + "bitflags 2.11.0", "num-traits", "rand 0.9.2", "rand_chacha 0.9.0", @@ -3995,11 +3998,11 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0" +checksum = "83c41efbf8f90ac44de7f3a868f0867851d261b56291732d0cbf7cceaaeb55a6" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "memchr", "unicase", ] @@ -4145,7 +4148,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ef8dea09a92caaf73bff7adb70b76162e5937524058a7e5bff37869cbbec293" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "compact_str", "hashbrown 0.16.1", "indoc", @@ -4210,7 +4213,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7dbfa023cd4e604c2553483820c5fe8aa9d71a42eea5aa77c6e7f35756612db" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "hashbrown 0.16.1", "indoc", "instability", @@ -4250,16 +4253,16 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", ] [[package]] name = "redox_syscall" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35985aa610addc02e24fc232012c86fd11f14111180f902b67e2d5331f8ebf2b" +checksum = "6d94dd2f7cd932d4dc02cc8b2b50dfd38bd079a4e5d79198b99743d7fcf9a4b4" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", ] [[package]] @@ -4290,7 +4293,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4318,9 +4321,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "relative-path" @@ -4397,14 +4400,14 @@ dependencies = [ "proc-macro2", "quote", "rquickjs-core", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "rquickjs-serde" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df908bfc058ac1fb7e7b4609afe712bf2ce4ea86b49cd06e041a86c89220e8b" +checksum = "e9382258c8bd1cc5c555887e5e379ab1491ff0287ca68ceb07be39ea561beb23" dependencies = [ "rquickjs", "serde", @@ -4448,7 +4451,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4501,7 +4504,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "errno", "libc", "linux-raw-sys 0.4.15", @@ -4514,7 +4517,7 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "errno", "libc", "linux-raw-sys 0.11.0", @@ -4534,9 +4537,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.36" +version = "0.23.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" dependencies = [ "log", "once_cell", @@ -4591,7 +4594,7 @@ version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "bytemuck", "core_maths", "log", @@ -4640,7 +4643,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4713,7 +4716,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4724,7 +4727,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4749,7 +4752,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -4776,9 +4779,9 @@ dependencies = [ [[package]] name = "serial2" -version = "0.2.33" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cc76fa68e25e771492ca1e3c53d447ef0be3093e05cd3b47f4b712ba10c6f3c" +checksum = "9e1401f562d358cdfdbdf8946e51a7871ede1db68bd0fd99bedc79e400241550" dependencies = [ "cfg-if", "libc", @@ -4923,7 +4926,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "calloop", "calloop-wayland-source", "cursor-icon", @@ -4967,7 +4970,7 @@ version = "0.3.0+sdk-1.3.268.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", ] [[package]] @@ -5024,7 +5027,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5052,9 +5055,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.114" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -5069,7 +5072,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5149,7 +5152,7 @@ checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7" dependencies = [ "anyhow", "base64", - "bitflags 2.10.0", + "bitflags 2.11.0", "fancy-regex 0.11.0", "filedescriptor", "finl_unicode", @@ -5220,7 +5223,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5231,7 +5234,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5366,7 +5369,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5427,9 +5430,9 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.6+spec-1.1.0" +version = "1.0.9+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" dependencies = [ "winnow", ] @@ -5459,7 +5462,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -5755,9 +5758,9 @@ dependencies = [ [[package]] name = "ts-rs" -version = "11.1.0" +version = "12.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4994acea2522cd2b3b85c1d9529a55991e3ad5e25cdcd3de9d505972c4379424" +checksum = "756050066659291d47a554a9f558125db17428b073c5ffce1daf5dcb0f7231d8" dependencies = [ "serde_json", "thiserror 2.0.18", @@ -5766,13 +5769,13 @@ dependencies = [ [[package]] name = "ts-rs-macros" -version = "11.1.0" +version = "12.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6ff59666c9cbaec3533964505d39154dc4e0a56151fdea30a09ed0301f62e2" +checksum = "38d90eea51bc7988ef9e674bf80a85ba6804739e535e9cab48e4bb34a8b652aa" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "termcolor", ] @@ -5841,9 +5844,9 @@ checksum = "81b79ad29b5e19de4260020f8919b443b2ef0277d242ce532ec7b7a2cc8b6007" [[package]] name = "unicode-ident" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-linebreak" @@ -5996,12 +5999,12 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.20.0" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" +checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" dependencies = [ "atomic", - "getrandom 0.3.4", + "getrandom 0.4.1", "js-sys", "wasm-bindgen", ] @@ -6042,7 +6045,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5924018406ce0063cd67f8e008104968b74b563ee1b85dde3ed1f7cb87d3dbd" dependencies = [ "arrayvec", - "bitflags 2.10.0", + "bitflags 2.11.0", "cursor-icon", "log", "memchr", @@ -6103,9 +6106,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.108" +version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +checksum = "05d7d0fce354c88b7982aec4400b3e7fcf723c32737cef571bd165f7613557ee" dependencies = [ "cfg-if", "once_cell", @@ -6116,9 +6119,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.58" +version = "0.4.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" +checksum = "ee85afca410ac4abba5b584b12e77ea225db6ee5471d0aebaae0861166f9378a" dependencies = [ "cfg-if", "futures-util", @@ -6130,9 +6133,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.108" +version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +checksum = "55839b71ba921e4f75b674cb16f843f4b1f3b26ddfcb3454de1cf65cc021ec0f" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6140,22 +6143,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.108" +version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +checksum = "caf2e969c2d60ff52e7e98b7392ff1588bffdd1ccd4769eba27222fd3d621571" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.108" +version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +checksum = "0861f0dcdf46ea819407495634953cdcc8a8c7215ab799a7a7ce366be71c7b30" dependencies = [ "unicode-ident", ] @@ -6188,7 +6191,7 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "hashbrown 0.15.5", "indexmap", "semver", @@ -6214,7 +6217,7 @@ version = "0.31.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e6faa537fbb6c186cb9f1d41f2f811a4120d1b57ec61f50da451a0c5122bec" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "rustix 1.1.3", "wayland-backend", "wayland-scanner", @@ -6226,7 +6229,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "cursor-icon", "wayland-backend", ] @@ -6248,7 +6251,7 @@ version = "0.32.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baeda9ffbcfc8cd6ddaade385eaf2393bd2115a69523c735f12242353c3df4f3" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "wayland-backend", "wayland-client", "wayland-scanner", @@ -6260,7 +6263,7 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa98634619300a535a9a97f338aed9a5ff1e01a461943e8346ff4ae26007306b" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -6273,7 +6276,7 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9597cdf02cf0c34cd5823786dce6b5ae8598f05c2daf5621b6e178d4f7345f3" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -6305,9 +6308,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.85" +version = "0.3.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +checksum = "10053fbf9a374174094915bbce141e87a6bf32ecd9a002980db4b638405e8962" dependencies = [ "js-sys", "wasm-bindgen", @@ -6411,7 +6414,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9cb534d5ffd109c7d1135f34cdae29e60eab94855a625dcfe1705f8bc7ad79f" dependencies = [ "arrayvec", - "bitflags 2.10.0", + "bitflags 2.11.0", "bytemuck", "cfg-if", "cfg_aliases 0.2.1", @@ -6443,7 +6446,7 @@ dependencies = [ "arrayvec", "bit-set 0.8.0", "bit-vec 0.8.0", - "bitflags 2.10.0", + "bitflags 2.11.0", "bytemuck", "cfg_aliases 0.2.1", "document-features", @@ -6503,7 +6506,7 @@ dependencies = [ "arrayvec", "ash", "bit-set 0.8.0", - "bitflags 2.10.0", + "bitflags 2.11.0", "block", "bytemuck", "cfg-if", @@ -6524,7 +6527,7 @@ dependencies = [ "ndk-sys", "objc", "once_cell", - "ordered-float 4.6.0", + "ordered-float 5.1.0", "parking_lot", "portable-atomic", "portable-atomic-util", @@ -6547,7 +6550,7 @@ version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e18308757e594ed2cd27dddbb16a139c42a683819d32a2e0b1b0167552f5840c" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "bytemuck", "js-sys", "log", @@ -6666,7 +6669,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -6677,7 +6680,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -6688,7 +6691,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -6699,7 +6702,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -6994,7 +6997,7 @@ dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.10.0", + "bitflags 2.11.0", "block2", "bytemuck", "calloop", @@ -7085,7 +7088,7 @@ dependencies = [ "heck", "indexmap", "prettyplease", - "syn 2.0.114", + "syn 2.0.117", "wasm-metadata", "wit-bindgen-core", "wit-component", @@ -7101,7 +7104,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "wit-bindgen-core", "wit-bindgen-rust", ] @@ -7113,7 +7116,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.10.0", + "bitflags 2.11.0", "indexmap", "log", "serde", @@ -7232,7 +7235,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "dlib", "log", "once_cell", @@ -7291,7 +7294,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "synstructure", ] @@ -7303,7 +7306,7 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "synstructure", ] @@ -7324,7 +7327,7 @@ checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -7344,7 +7347,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", "synstructure", ] @@ -7395,7 +7398,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] @@ -7406,11 +7409,11 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.117", ] [[package]] name = "zmij" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4de98dfa5d5b7fef4ee834d0073d560c9ca7b6c46a71d058c48db7960f8cfaf7" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index db7b69d8a..71d1ced38 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,22 +38,22 @@ tracing = "0.1" rust-i18n = "3.1.5" schemars = { version = "1.2", features = ["preserve_order"] } rquickjs = { version = "0.11", features = ["bindgen", "futures", "macro"] } -rquickjs-serde = "0.4" -oxc_allocator = "0.112.0" -oxc_ast = "0.112.0" -oxc_parser = "0.112.0" -oxc_transformer = "0.112.0" -oxc_codegen = "0.112.0" -oxc_span = "0.112.0" -oxc_semantic = "0.112.0" -oxc_diagnostics = "0.112.0" +rquickjs-serde = "0.5" +oxc_allocator = "0.115.0" +oxc_ast = "0.115.0" +oxc_parser = "0.115.0" +oxc_transformer = "0.115.0" +oxc_codegen = "0.115.0" +oxc_span = "0.115.0" +oxc_semantic = "0.115.0" +oxc_diagnostics = "0.115.0" tree-sitter = "0.26.5" tree-sitter-highlight = "0.26.3" crossterm = "0.29" winit = "0.30" wgpu = "28.0" lsp-types = "0.97" -ts-rs = { version = "11.1", features = ["serde_json"] } +ts-rs = { version = "12.0", features = ["serde_json"] } # Add more as needed during refactor [profile.release] diff --git a/crates/fresh-editor/Cargo.toml b/crates/fresh-editor/Cargo.toml index be79b9a3b..c6688ee4b 100644 --- a/crates/fresh-editor/Cargo.toml +++ b/crates/fresh-editor/Cargo.toml @@ -140,7 +140,7 @@ nix = { version = "0.31", features = ["signal", "pthread", "resource", "poll", " # Plugin API proc macros for type-safe bindings fresh-plugin-api-macros = { workspace = true, optional = true } # TypeScript type generation from Rust structs -ts-rs = { version = "11.1", optional = true } +ts-rs = { version = "12.0", optional = true } # anyhow is always needed for model error handling anyhow = { workspace = true } @@ -177,7 +177,7 @@ interprocess = { version = "2.2", features = ["tokio"] } # Embedded plugins support (optional) include_dir = { version = "0.7", optional = true } -tempfile = { version = "3.24", optional = true } +tempfile = { version = "3.25", optional = true } trash = { version = "5.2.5", optional = true } open = { version = "5.3", optional = true } @@ -186,7 +186,7 @@ fresh-gui = { workspace = true, optional = true } [dev-dependencies] proptest = "1.9" -tempfile = "3.24.0" +tempfile = "3.25" insta = { version = "1.46", features = ["yaml"] } vt100 = "0.16" # Virtual terminal emulator for testing real ANSI output ctor = "0.6.3" diff --git a/crates/fresh-plugin-runtime/src/ts_export.rs b/crates/fresh-plugin-runtime/src/ts_export.rs index 1045937bc..c8ec33028 100644 --- a/crates/fresh-plugin-runtime/src/ts_export.rs +++ b/crates/fresh-plugin-runtime/src/ts_export.rs @@ -12,7 +12,7 @@ use oxc_allocator::Allocator; use oxc_codegen::Codegen; use oxc_parser::Parser; use oxc_span::SourceType; -use ts_rs::TS; +use ts_rs::{Config as TsConfig, TS}; use fresh_core::api::{ ActionPopupAction, ActionPopupOptions, ActionSpec, BackgroundProcessResult, BufferInfo, @@ -32,70 +32,75 @@ use fresh_core::file_explorer::FileExplorerDecoration; /// Returns None if the type is not known (not registered in this mapping). /// Add new types here when they're added to api.rs with `#[derive(TS)]`. fn get_type_decl(type_name: &str) -> Option { + let cfg = TsConfig::default(); // Map TypeScript type names to their ts-rs declarations // The type name should match either the Rust struct name or the ts(rename = "...") value match type_name { // Core types - "BufferInfo" => Some(BufferInfo::decl()), - "CursorInfo" => Some(CursorInfo::decl()), - "ViewportInfo" => Some(ViewportInfo::decl()), - "ActionSpec" => Some(ActionSpec::decl()), - "BufferSavedDiff" => Some(BufferSavedDiff::decl()), - "LayoutHints" => Some(LayoutHints::decl()), + "BufferInfo" => Some(BufferInfo::decl(&cfg)), + "CursorInfo" => Some(CursorInfo::decl(&cfg)), + "ViewportInfo" => Some(ViewportInfo::decl(&cfg)), + "ActionSpec" => Some(ActionSpec::decl(&cfg)), + "BufferSavedDiff" => Some(BufferSavedDiff::decl(&cfg)), + "LayoutHints" => Some(LayoutHints::decl(&cfg)), // Process types - "SpawnResult" => Some(SpawnResult::decl()), - "BackgroundProcessResult" => Some(BackgroundProcessResult::decl()), + "SpawnResult" => Some(SpawnResult::decl(&cfg)), + "BackgroundProcessResult" => Some(BackgroundProcessResult::decl(&cfg)), // Terminal types - "TerminalResult" => Some(TerminalResult::decl()), - "CreateTerminalOptions" => Some(CreateTerminalOptions::decl()), + "TerminalResult" => Some(TerminalResult::decl(&cfg)), + "CreateTerminalOptions" => Some(CreateTerminalOptions::decl(&cfg)), // Composite buffer types (ts-rs renames these with Ts prefix) - "TsCompositeLayoutConfig" | "CompositeLayoutConfig" => Some(CompositeLayoutConfig::decl()), - "TsCompositeSourceConfig" | "CompositeSourceConfig" => Some(CompositeSourceConfig::decl()), - "TsCompositePaneStyle" | "CompositePaneStyle" => Some(CompositePaneStyle::decl()), - "TsCompositeHunk" | "CompositeHunk" => Some(CompositeHunk::decl()), + "TsCompositeLayoutConfig" | "CompositeLayoutConfig" => { + Some(CompositeLayoutConfig::decl(&cfg)) + } + "TsCompositeSourceConfig" | "CompositeSourceConfig" => { + Some(CompositeSourceConfig::decl(&cfg)) + } + "TsCompositePaneStyle" | "CompositePaneStyle" => Some(CompositePaneStyle::decl(&cfg)), + "TsCompositeHunk" | "CompositeHunk" => Some(CompositeHunk::decl(&cfg)), "TsCreateCompositeBufferOptions" | "CreateCompositeBufferOptions" => { - Some(CreateCompositeBufferOptions::decl()) + Some(CreateCompositeBufferOptions::decl(&cfg)) } // View transform types - "ViewTokenWireKind" => Some(ViewTokenWireKind::decl()), - "ViewTokenStyle" => Some(ViewTokenStyle::decl()), - "ViewTokenWire" => Some(ViewTokenWire::decl()), + "ViewTokenWireKind" => Some(ViewTokenWireKind::decl(&cfg)), + "ViewTokenStyle" => Some(ViewTokenStyle::decl(&cfg)), + "ViewTokenWire" => Some(ViewTokenWire::decl(&cfg)), // UI types (ts-rs renames these with Ts prefix) - "TsActionPopupAction" | "ActionPopupAction" => Some(ActionPopupAction::decl()), - "ActionPopupOptions" => Some(ActionPopupOptions::decl()), - "TsHighlightSpan" => Some(TsHighlightSpan::decl()), - "FileExplorerDecoration" => Some(FileExplorerDecoration::decl()), + "TsActionPopupAction" | "ActionPopupAction" => Some(ActionPopupAction::decl(&cfg)), + "ActionPopupOptions" => Some(ActionPopupOptions::decl(&cfg)), + "TsHighlightSpan" => Some(TsHighlightSpan::decl(&cfg)), + "FileExplorerDecoration" => Some(FileExplorerDecoration::decl(&cfg)), // Virtual buffer option types - "TextPropertyEntry" | "JsTextPropertyEntry" => Some(JsTextPropertyEntry::decl()), - "CreateVirtualBufferOptions" => Some(CreateVirtualBufferOptions::decl()), - "CreateVirtualBufferInSplitOptions" => Some(CreateVirtualBufferInSplitOptions::decl()), + "TextPropertyEntry" | "JsTextPropertyEntry" => Some(JsTextPropertyEntry::decl(&cfg)), + "CreateVirtualBufferOptions" => Some(CreateVirtualBufferOptions::decl(&cfg)), + "CreateVirtualBufferInSplitOptions" => Some(CreateVirtualBufferInSplitOptions::decl(&cfg)), "CreateVirtualBufferInExistingSplitOptions" => { - Some(CreateVirtualBufferInExistingSplitOptions::decl()) + Some(CreateVirtualBufferInExistingSplitOptions::decl(&cfg)) } // Return types - "TextPropertiesAtCursor" => Some(TextPropertiesAtCursor::decl()), - "VirtualBufferResult" => Some(VirtualBufferResult::decl()), + "TextPropertiesAtCursor" => Some(TextPropertiesAtCursor::decl(&cfg)), + "VirtualBufferResult" => Some(VirtualBufferResult::decl(&cfg)), // Prompt and directory types - "PromptSuggestion" | "Suggestion" => Some(Suggestion::decl()), - "DirEntry" => Some(DirEntry::decl()), + "PromptSuggestion" | "Suggestion" => Some(Suggestion::decl(&cfg)), + "DirEntry" => Some(DirEntry::decl(&cfg)), // Diagnostic types - "JsDiagnostic" => Some(JsDiagnostic::decl()), - "JsRange" => Some(JsRange::decl()), - "JsPosition" => Some(JsPosition::decl()), + "JsDiagnostic" => Some(JsDiagnostic::decl(&cfg)), + "JsRange" => Some(JsRange::decl(&cfg)), + "JsPosition" => Some(JsPosition::decl(&cfg)), // Language pack types - "LanguagePackConfig" => Some(LanguagePackConfig::decl()), - "LspServerPackConfig" => Some(LspServerPackConfig::decl()), - "FormatterPackConfig" => Some(FormatterPackConfig::decl()), + "LanguagePackConfig" => Some(LanguagePackConfig::decl(&cfg)), + "LspServerPackConfig" => Some(LspServerPackConfig::decl(&cfg)), + "FormatterPackConfig" => Some(FormatterPackConfig::decl(&cfg)), _ => None, } From 80ab02de9492a8060bffb925028dc49b6b5ba17a Mon Sep 17 00:00:00 2001 From: Noam Lewis Date: Tue, 24 Feb 2026 22:51:26 +0200 Subject: [PATCH 2/6] Non-blocking grammar build: move SyntaxSet::build() to background thread Start with pre-compiled syntect defaults (~0ms, ~50 common languages) and build the full grammar registry on a background thread. When complete, swap in the new registry and re-detect syntax for all open buffers. Plugin grammar rebuilds also moved off the main thread via AsyncMessage::GrammarRegistryBuilt, with batching to coalesce multiple RegisterGrammar+ReloadGrammars sequences into a single rebuild. Removes UnbuiltGrammarRegistry (no longer needed) and the startup command drain loop. Co-Authored-By: Claude Opus 4.6 --- crates/fresh-editor/src/app/async_messages.rs | 3 + crates/fresh-editor/src/app/mod.rs | 79 +++++++++-- .../fresh-editor/src/app/plugin_commands.rs | 133 ++++++++---------- crates/fresh-editor/src/app/render.rs | 3 + .../src/primitives/grammar/types.rs | 25 ++++ .../fresh-editor/src/services/async_bridge.rs | 5 + 6 files changed, 162 insertions(+), 86 deletions(-) diff --git a/crates/fresh-editor/src/app/async_messages.rs b/crates/fresh-editor/src/app/async_messages.rs index 28b019157..cad86e192 100644 --- a/crates/fresh-editor/src/app/async_messages.rs +++ b/crates/fresh-editor/src/app/async_messages.rs @@ -1068,6 +1068,9 @@ impl Editor { } } + // Flush any deferred grammar rebuilds as a single batch + self.flush_pending_grammars(); + has_visual_commands } diff --git a/crates/fresh-editor/src/app/mod.rs b/crates/fresh-editor/src/app/mod.rs index 3434ccfd2..72dbd71fc 100644 --- a/crates/fresh-editor/src/app/mod.rs +++ b/crates/fresh-editor/src/app/mod.rs @@ -264,6 +264,15 @@ pub struct Editor { /// Pending grammars registered by plugins, waiting for reload_grammars() to apply pending_grammars: Vec, + /// Whether a grammar reload has been requested but not yet flushed. + /// This allows batching multiple RegisterGrammar+ReloadGrammars sequences + /// into a single rebuild. + grammar_reload_pending: bool, + + /// Whether a background grammar build is in progress. + /// When true, `flush_pending_grammars()` defers work until the build completes. + grammar_build_in_progress: bool, + /// Active theme theme: crate::view::theme::Theme, @@ -872,8 +881,7 @@ impl Editor { color_capability: crate::view::color_support::ColorCapability, filesystem: Arc, ) -> AnyhowResult { - let grammar_registry = - crate::primitives::grammar::GrammarRegistry::for_editor(dir_context.config_dir.clone()); + let grammar_registry = crate::primitives::grammar::GrammarRegistry::defaults_only(); Self::with_options( config, width, @@ -904,8 +912,8 @@ impl Editor { time_source: Option, grammar_registry: Option>, ) -> AnyhowResult { - let grammar_registry = grammar_registry - .unwrap_or_else(|| crate::primitives::grammar::GrammarRegistry::empty()); + let grammar_registry = + grammar_registry.unwrap_or_else(crate::primitives::grammar::GrammarRegistry::empty); Self::with_options( config, width, @@ -968,11 +976,6 @@ impl Editor { // Set terminal cursor color to match theme theme.set_terminal_cursor_color(); - tracing::info!( - "Grammar registry has {} syntaxes", - grammar_registry.available_syntaxes().len() - ); - let keybindings = KeybindingResolver::new(&config); // Create an empty initial buffer @@ -1174,6 +1177,27 @@ impl Editor { } } + // Spawn background thread to build the full grammar registry + // (includes embedded grammars, user grammars, and language packs). + // The defaults-only registry is used until this completes. + let grammar_build_in_progress = enable_plugins; // only needed when plugins may register grammars + { + let grammar_sender = async_bridge.sender(); + let grammar_config_dir = dir_context.config_dir.clone(); + std::thread::Builder::new() + .name("grammar-build".to_string()) + .spawn(move || { + let registry = + crate::primitives::grammar::GrammarRegistry::for_editor(grammar_config_dir); + let _ = grammar_sender.send( + crate::services::async_bridge::AsyncMessage::GrammarRegistryBuilt { + registry, + }, + ); + }) + .ok(); + } + // Extract config values before moving config into the struct let file_explorer_width = config.file_explorer.width; let recovery_enabled = config.editor.recovery_enabled; @@ -1208,6 +1232,8 @@ impl Editor { dir_context: dir_context.clone(), grammar_registry, pending_grammars: Vec::new(), + grammar_reload_pending: false, + grammar_build_in_progress, theme, theme_registry, ansi_background: None, @@ -4417,6 +4443,41 @@ impl Editor { exit_code, ); } + AsyncMessage::GrammarRegistryBuilt { registry } => { + tracing::info!( + "Background grammar build completed ({} syntaxes)", + registry.available_syntaxes().len() + ); + self.grammar_registry = registry; + self.grammar_build_in_progress = false; + + // Re-detect syntax for all open buffers with the full registry + let buffers_to_update: Vec<_> = self + .buffer_metadata + .iter() + .filter_map(|(id, meta)| meta.file_path().map(|p| (*id, p.to_path_buf()))) + .collect(); + + for (buf_id, path) in buffers_to_update { + if let Some(state) = self.buffers.get_mut(&buf_id) { + let detected = + crate::primitives::detected_language::DetectedLanguage::from_path( + &path, + &self.grammar_registry, + &self.config.languages, + ); + + if detected.highlighter.has_highlighting() + || !state.highlighter.has_highlighting() + { + state.apply_language(detected); + } + } + } + + // Flush any plugin grammars that arrived during the build + self.flush_pending_grammars(); + } } } diff --git a/crates/fresh-editor/src/app/plugin_commands.rs b/crates/fresh-editor/src/app/plugin_commands.rs index 7f07b1ba2..e79c45496 100644 --- a/crates/fresh-editor/src/app/plugin_commands.rs +++ b/crates/fresh-editor/src/app/plugin_commands.rs @@ -1510,32 +1510,55 @@ impl Editor { } /// Handle ReloadGrammars command - /// Rebuilds the grammar registry with pending grammars and invalidates highlight caches + /// Defers the actual rebuild — sets a flag so all pending grammars from the + /// current command batch are collected before a single rebuild. pub(super) fn handle_reload_grammars(&mut self) { - use crate::primitives::grammar::GrammarRegistry; - use std::path::PathBuf; - - tracing::info!( - "[SYNTAX DEBUG] handle_reload_grammars called, pending_grammars count: {}", + tracing::debug!( + "ReloadGrammars requested, pending_grammars count: {}", self.pending_grammars.len() ); + self.grammar_reload_pending = true; + } + + /// Flush pending grammars: spawn a background rebuild if any ReloadGrammars + /// commands were received during this command batch. + /// + /// Called after processing all plugin commands in a batch, so that multiple + /// RegisterGrammar+ReloadGrammars pairs result in only one rebuild. + /// The rebuild happens on a background thread; when complete, a + /// `GrammarRegistryBuilt` message swaps in the new registry. + pub(super) fn flush_pending_grammars(&mut self) { + if !self.grammar_reload_pending { + return; + } + self.grammar_reload_pending = false; + + // If a background build is already in progress, it will call + // flush_pending_grammars() again when it completes — so just + // re-arm the flag and return. + if self.grammar_build_in_progress { + self.grammar_reload_pending = true; + tracing::debug!("Grammar build in progress, deferring flush"); + return; + } + + use std::path::PathBuf; if self.pending_grammars.is_empty() { - tracing::debug!("ReloadGrammars called but no pending grammars"); + tracing::debug!("Grammar reload requested but no pending grammars"); return; } + tracing::info!( + "Flushing {} pending grammars via background rebuild", + self.pending_grammars.len() + ); + // Collect pending grammars let additional: Vec<_> = self .pending_grammars .drain(..) .map(|g| { - tracing::info!( - "[SYNTAX DEBUG] pending grammar: lang='{}', path='{}', extensions={:?}", - g.language, - g.grammar_path, - g.extensions - ); ( g.language.clone(), PathBuf::from(g.grammar_path), @@ -1544,8 +1567,6 @@ impl Editor { }) .collect(); - let grammar_count = additional.len(); - // Update config.languages with the extensions so detect_language() works for (language, _path, extensions) in &additional { let lang_config = self @@ -1553,78 +1574,36 @@ impl Editor { .languages .entry(language.clone()) .or_insert_with(Default::default); - // Add extensions that aren't already present for ext in extensions { if !lang_config.extensions.contains(ext) { lang_config.extensions.push(ext.clone()); } } - tracing::info!( - "[SYNTAX DEBUG] updated config.languages['{}']: extensions={:?}, grammar='{}'", - language, - lang_config.extensions, - lang_config.grammar - ); } - tracing::info!( - "[SYNTAX DEBUG] before rebuild: registry has {} syntaxes, user_extensions: {}", - self.grammar_registry.available_syntaxes().len(), - self.grammar_registry.user_extensions_debug() - ); - - // Rebuild registry with pending grammars - match GrammarRegistry::with_additional_grammars(&self.grammar_registry, &additional) { - Some(new_registry) => { - tracing::info!( - "[SYNTAX DEBUG] after rebuild: new registry has {} syntaxes, user_extensions: {}", - new_registry.available_syntaxes().len(), - new_registry.user_extensions_debug() - ); - self.grammar_registry = std::sync::Arc::new(new_registry); - - // Re-detect syntax for all buffers that might now have highlighting - // Collect buffer IDs and paths first to avoid borrow issues - let buffers_to_update: Vec<_> = self - .buffer_metadata - .iter() - .filter_map(|(id, meta)| meta.file_path().map(|p| (*id, p.to_path_buf()))) - .collect(); - - for (buf_id, path) in buffers_to_update { - if let Some(state) = self.buffers.get_mut(&buf_id) { - let detected = - crate::primitives::detected_language::DetectedLanguage::from_path( - &path, - &self.grammar_registry, - &self.config.languages, - ); - - // Only update if the new engine has highlighting capability - // or if the current one doesn't (don't downgrade) - if detected.highlighter.has_highlighting() - || !state.highlighter.has_highlighting() - { - state.apply_language(detected); - tracing::debug!( - "Updated syntax highlighting for {:?}", - path.file_name() + // Spawn background rebuild + let base_registry = std::sync::Arc::clone(&self.grammar_registry); + if let Some(bridge) = &self.async_bridge { + let sender = bridge.sender(); + self.grammar_build_in_progress = true; + std::thread::Builder::new() + .name("grammar-rebuild".to_string()) + .spawn(move || { + use crate::primitives::grammar::GrammarRegistry; + match GrammarRegistry::with_additional_grammars(&base_registry, &additional) { + Some(new_registry) => { + let _ = sender.send( + crate::services::async_bridge::AsyncMessage::GrammarRegistryBuilt { + registry: std::sync::Arc::new(new_registry), + }, ); } + None => { + tracing::error!("Failed to rebuild grammar registry in background"); + } } - } - - // Emit event for plugins that might want to react - self.emit_event( - "grammars_changed", - serde_json::json!({ "count": grammar_count }), - ); - - tracing::info!("Grammars reloaded ({} new grammars)", grammar_count); - } - None => { - tracing::error!("Failed to rebuild grammar registry"); - } + }) + .ok(); } } } diff --git a/crates/fresh-editor/src/app/render.rs b/crates/fresh-editor/src/app/render.rs index bce938478..f89830d4e 100644 --- a/crates/fresh-editor/src/app/render.rs +++ b/crates/fresh-editor/src/app/render.rs @@ -363,6 +363,9 @@ impl Editor { tracing::error!("Error handling plugin command: {}", e); } } + + // Flush any deferred grammar rebuilds as a single batch + self.flush_pending_grammars(); } // Render editor content (same for both layouts) diff --git a/crates/fresh-editor/src/primitives/grammar/types.rs b/crates/fresh-editor/src/primitives/grammar/types.rs index 2f7614802..8ce818017 100644 --- a/crates/fresh-editor/src/primitives/grammar/types.rs +++ b/crates/fresh-editor/src/primitives/grammar/types.rs @@ -46,6 +46,14 @@ pub const TYPST_GRAMMAR: &str = include_str!("../../grammars/typst.sublime-synta /// /// This struct holds the compiled syntax set and provides lookup methods. /// It does not perform I/O directly - use `GrammarLoader` for loading grammars. +impl std::fmt::Debug for GrammarRegistry { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("GrammarRegistry") + .field("syntax_count", &self.syntax_set.syntaxes().len()) + .finish() + } +} + pub struct GrammarRegistry { /// Combined syntax set (built-in + embedded + user grammars) syntax_set: Arc, @@ -87,6 +95,23 @@ impl GrammarRegistry { }) } + /// Create a registry with only syntect's pre-compiled defaults (~0ms). + /// + /// This provides instant syntax highlighting for ~50 common languages + /// (Rust, Python, JS/TS, C/C++, Go, Java, HTML, CSS, Markdown, etc.) + /// without any `SyntaxSetBuilder::build()` call. Use this at startup, + /// then swap in a full registry built on a background thread. + pub fn defaults_only() -> Arc { + let syntax_set = SyntaxSet::load_defaults_newlines(); + let filename_scopes = Self::build_filename_scopes(); + Arc::new(Self { + syntax_set: Arc::new(syntax_set), + user_extensions: HashMap::new(), + filename_scopes, + loaded_grammar_paths: Vec::new(), + }) + } + /// Build the default filename -> scope mappings for dotfiles and special files. pub fn build_filename_scopes() -> HashMap { let mut map = HashMap::new(); diff --git a/crates/fresh-editor/src/services/async_bridge.rs b/crates/fresh-editor/src/services/async_bridge.rs index 83082007d..7c52bc32e 100644 --- a/crates/fresh-editor/src/services/async_bridge.rs +++ b/crates/fresh-editor/src/services/async_bridge.rs @@ -237,6 +237,11 @@ pub enum AsyncMessage { status: LspServerStatus, message: Option, }, + + /// Background grammar build completed — swap in the new registry + GrammarRegistryBuilt { + registry: std::sync::Arc, + }, } /// LSP progress value types From b50e46a8f475710f2049e3c3a4bb6cccb7a604ce Mon Sep 17 00:00:00 2001 From: Noam Lewis Date: Tue, 24 Feb 2026 23:17:09 +0200 Subject: [PATCH 3/6] Non-blocking plugin loading: fire-and-forget with status bar progress Convert plugin loading from blocking (oneshot recv) to fire-and-forget so the editor can render its first frame immediately without waiting for ~40 plugins to load sequentially. The plugin thread reports progress via SetStatus commands ("Loading plugins (X/Y)") and clears the status bar when done. Co-Authored-By: Claude Opus 4.6 --- crates/fresh-editor/src/app/mod.rs | 38 ++---- .../src/services/plugins/manager.rs | 23 ++-- crates/fresh-plugin-runtime/src/thread.rs | 116 ++++++++++++------ 3 files changed, 97 insertions(+), 80 deletions(-) diff --git a/crates/fresh-editor/src/app/mod.rs b/crates/fresh-editor/src/app/mod.rs index 72dbd71fc..9955be464 100644 --- a/crates/fresh-editor/src/app/mod.rs +++ b/crates/fresh-editor/src/app/mod.rs @@ -933,7 +933,7 @@ impl Editor { /// to verify editor behavior under various I/O conditions #[allow(clippy::too_many_arguments)] fn with_options( - mut config: Config, + config: Config, width: u16, height: u16, working_dir: Option, @@ -1150,37 +1150,23 @@ impl Editor { ); } - // Load from all found plugin directories, respecting config - for plugin_dir in plugin_dirs { - tracing::info!("Loading TypeScript plugins from: {:?}", plugin_dir); - let (errors, discovered_plugins) = - plugin_manager.load_plugins_from_dir_with_config(&plugin_dir, &config.plugins); - - // Merge discovered plugins into config - // discovered_plugins already contains the merged config (saved enabled state + discovered path) - for (name, plugin_config) in discovered_plugins { - config.plugins.insert(name, plugin_config); - } - - if !errors.is_empty() { - for err in &errors { - tracing::error!("TypeScript plugin load error: {}", err); - } - // In debug/test builds, panic to surface plugin loading errors - #[cfg(debug_assertions)] - panic!( - "TypeScript plugin loading failed with {} error(s): {}", - errors.len(), - errors.join("; ") - ); - } + // Fire-and-forget: send all plugin dirs to the plugin thread + if !plugin_dirs.is_empty() { + let dirs: Vec<( + std::path::PathBuf, + std::collections::HashMap, + )> = plugin_dirs + .into_iter() + .map(|dir| (dir, config.plugins.clone())) + .collect(); + plugin_manager.load_plugins_from_dir_with_config(dirs); } } // Spawn background thread to build the full grammar registry // (includes embedded grammars, user grammars, and language packs). // The defaults-only registry is used until this completes. - let grammar_build_in_progress = enable_plugins; // only needed when plugins may register grammars + let grammar_build_in_progress = true; { let grammar_sender = async_bridge.sender(); let grammar_config_dir = dir_context.config_dir.clone(); diff --git a/crates/fresh-editor/src/services/plugins/manager.rs b/crates/fresh-editor/src/services/plugins/manager.rs index ac2741cd7..1c693b61f 100644 --- a/crates/fresh-editor/src/services/plugins/manager.rs +++ b/crates/fresh-editor/src/services/plugins/manager.rs @@ -128,30 +128,25 @@ impl PluginManager { } } - /// Load plugins from a directory with config support. - /// Returns (errors, discovered_plugins) where discovered_plugins is a map of - /// plugin name -> PluginConfig with paths populated. + /// Load plugins from multiple directories with config support (fire-and-forget). + /// Sends all dirs to the plugin thread and returns immediately. #[cfg(feature = "plugins")] pub fn load_plugins_from_dir_with_config( &self, - dir: &Path, - plugin_configs: &HashMap, - ) -> (Vec, HashMap) { + dirs: Vec<(std::path::PathBuf, HashMap)>, + ) { if let Some(ref manager) = self.inner { - return manager.load_plugins_from_dir_with_config(dir, plugin_configs); + manager.load_plugins_from_dir_with_config(dirs); } - (Vec::new(), HashMap::new()) } - /// Load plugins from a directory with config support (no-op when plugins disabled). + /// Load plugins from multiple directories with config support (no-op when plugins disabled). #[cfg(not(feature = "plugins"))] pub fn load_plugins_from_dir_with_config( &self, - dir: &Path, - plugin_configs: &HashMap, - ) -> (Vec, HashMap) { - let _ = (dir, plugin_configs); - (Vec::new(), HashMap::new()) + dirs: Vec<(std::path::PathBuf, HashMap)>, + ) { + let _ = dirs; } /// Unload a plugin by name. diff --git a/crates/fresh-plugin-runtime/src/thread.rs b/crates/fresh-plugin-runtime/src/thread.rs index 0867b169c..683c65cc4 100644 --- a/crates/fresh-plugin-runtime/src/thread.rs +++ b/crates/fresh-plugin-runtime/src/thread.rs @@ -52,13 +52,10 @@ pub enum PluginRequest { response: oneshot::Sender>, }, - /// Load all plugins from a directory with config support - /// Returns (errors, discovered_plugins) where discovered_plugins contains - /// all found plugins with their paths and enabled status - LoadPluginsFromDirWithConfig { - dir: PathBuf, - plugin_configs: HashMap, - response: oneshot::Sender<(Vec, HashMap)>, + /// Load plugins from multiple directories with config support (fire-and-forget) + /// Errors are logged, not returned. + LoadPluginsFromDirs { + dirs: Vec<(PathBuf, HashMap)>, }, /// Unload a plugin by name @@ -424,34 +421,23 @@ impl PluginThreadHandle { .unwrap_or_else(|_| vec!["Plugin thread closed".to_string()]) } - /// Load all plugins from a directory with config support (blocking) - /// Returns (errors, discovered_plugins) where discovered_plugins is a map of - /// plugin name -> PluginConfig with paths populated. + /// Load plugins from multiple directories with config support (fire-and-forget). + /// Sends all dirs to the plugin thread and returns immediately. + /// Errors are logged on the plugin thread, not returned. pub fn load_plugins_from_dir_with_config( &self, - dir: &Path, - plugin_configs: &HashMap, - ) -> (Vec, HashMap) { - let (tx, rx) = oneshot::channel(); + dirs: Vec<(PathBuf, HashMap)>, + ) { let Some(sender) = self.request_sender.as_ref() else { - return (vec!["Plugin thread shut down".to_string()], HashMap::new()); + tracing::error!("Plugin thread shut down before loading plugins"); + return; }; if sender - .send(PluginRequest::LoadPluginsFromDirWithConfig { - dir: dir.to_path_buf(), - plugin_configs: plugin_configs.clone(), - response: tx, - }) + .send(PluginRequest::LoadPluginsFromDirs { dirs }) .is_err() { - return ( - vec!["Plugin thread not responding".to_string()], - HashMap::new(), - ); + tracing::error!("Plugin thread not responding during plugin load"); } - - rx.recv() - .unwrap_or_else(|_| (vec!["Plugin thread closed".to_string()], HashMap::new())) } /// Unload a plugin (blocking) @@ -919,19 +905,60 @@ async fn handle_request( let _ = response.send(errors); } - PluginRequest::LoadPluginsFromDirWithConfig { - dir, - plugin_configs, - response, - } => { - let (errors, discovered) = load_plugins_from_dir_with_config_internal( - Rc::clone(&runtime), - plugins, - &dir, - &plugin_configs, - ) - .await; - let _ = response.send((errors, discovered)); + PluginRequest::LoadPluginsFromDirs { dirs } => { + // Pre-scan all dirs to count total enabled plugins for progress reporting + let mut total_enabled = 0usize; + for (dir, plugin_configs) in &dirs { + if !dir.exists() { + continue; + } + if let Ok(entries) = std::fs::read_dir(dir) { + for entry in entries.flatten() { + let path = entry.path(); + let ext = path.extension().and_then(|s| s.to_str()); + if (ext == Some("ts") || ext == Some("js")) + && !path.to_string_lossy().contains(".i18n.") + { + let name = path + .file_stem() + .and_then(|s| s.to_str()) + .unwrap_or("unknown"); + let enabled = + plugin_configs.get(name).map(|c| c.enabled).unwrap_or(true); + if enabled { + total_enabled += 1; + } + } + } + } + } + + // Send initial status + if total_enabled > 0 { + runtime + .borrow() + .send_status(format!("Loading plugins (0/{total_enabled})")); + } + + let mut loaded = 0usize; + for (dir, plugin_configs) in dirs { + tracing::info!("Loading TypeScript plugins from: {:?}", dir); + let (errors, _discovered) = load_plugins_from_dir_with_config_internal( + Rc::clone(&runtime), + plugins, + &dir, + &plugin_configs, + &mut loaded, + total_enabled, + ) + .await; + for err in &errors { + tracing::error!("TypeScript plugin load error: {}", err); + } + } + + // Clear status when done + runtime.borrow().send_status(String::new()); } PluginRequest::UnloadPlugin { name, response } => { @@ -1178,6 +1205,8 @@ async fn load_plugins_from_dir_with_config_internal( plugins: &mut HashMap, dir: &Path, plugin_configs: &HashMap, + loaded_count: &mut usize, + total_count: usize, ) -> (Vec, HashMap) { tracing::debug!( "load_plugins_from_dir_with_config_internal: scanning directory {:?}", @@ -1249,6 +1278,13 @@ async fn load_plugins_from_dir_with_config_internal( tracing::error!("{}", err); errors.push(err); } + *loaded_count += 1; + if total_count > 0 { + runtime.borrow().send_status(format!( + "Loading plugins ({}/{})", + *loaded_count, total_count + )); + } } else { tracing::info!( "load_plugins_from_dir_with_config_internal: skipping disabled plugin '{}'", From d7b4f3939e9f7ceb3f46445908eeda32db335f93 Mon Sep 17 00:00:00 2001 From: Noam Lewis Date: Tue, 24 Feb 2026 23:41:27 +0200 Subject: [PATCH 4/6] Drain buffered input events before rendering for CPU-constrained responsiveness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Under CPU pressure (e.g., cgroups), terminal.draw() can take 500-800ms wall clock time due to repeated process descheduling. During that time, keyboard events buffer in the kernel. Previously the loop would render after each event, causing N keystrokes to trigger N expensive draws. Restructure the event loop to drain all pending events (non-blocking poll) before drawing a single frame. After each event, recompute_layout_cached() updates the visual layout (view_line_mappings, viewport sync, scroll groups) so subsequent events see correct state — same pattern as macro replay. Only the terminal draw is deferred. Resize events break out of the drain loop immediately since they require a real render to establish new frame dimensions. Co-Authored-By: Claude Opus 4.6 --- crates/fresh-editor/src/app/render.rs | 9 ++ crates/fresh-editor/src/main.rs | 150 ++++++++++++++++---------- 2 files changed, 104 insertions(+), 55 deletions(-) diff --git a/crates/fresh-editor/src/app/render.rs b/crates/fresh-editor/src/app/render.rs index f89830d4e..43103e894 100644 --- a/crates/fresh-editor/src/app/render.rs +++ b/crates/fresh-editor/src/app/render.rs @@ -4076,6 +4076,15 @@ impl Editor { format!("{} → Play Macro", palette_key) } + /// Recompute layout using the last rendered frame dimensions. + /// Used by the event loop to keep layout caches fresh between events + /// when drawing is deferred (e.g., draining buffered input). + pub fn recompute_layout_cached(&mut self) { + let w = self.cached_layout.last_frame_width; + let h = self.cached_layout.last_frame_height; + self.recompute_layout(w, h); + } + /// Recompute the view_line_mappings layout without drawing. /// Used during macro replay so that visual-line movements (MoveLineEnd, /// MoveUp, MoveDown on wrapped lines) see correct, up-to-date layout diff --git a/crates/fresh-editor/src/main.rs b/crates/fresh-editor/src/main.rs index 3d2aa8ad8..1fd3a4630 100644 --- a/crates/fresh-editor/src/main.rs +++ b/crates/fresh-editor/src/main.rs @@ -2764,76 +2764,116 @@ where break; } - if needs_render && last_render.elapsed() >= FRAME_DURATION { - { - let _span = tracing::info_span!("terminal_draw").entered(); - terminal.draw(|frame| editor.render(frame))?; - } - last_render = Instant::now(); - needs_render = false; - } - - let event = if let Some(e) = pending_event.take() { - Some(e) - } else { - let timeout = if needs_render { - FRAME_DURATION.saturating_sub(last_render.elapsed()) + // Drain all pending input events before rendering. + // Under CPU pressure (cgroups, etc.), terminal.draw() takes long wall-clock + // time during which input buffers in the kernel. Draining first ensures all + // buffered keystrokes are applied to a single frame rather than triggering + // multiple expensive draws. + // + // After each event, recompute_layout() updates the cached visual layout + // (view_line_mappings, viewport sync, scroll groups) so that subsequent + // events see correct layout state — same as macro replay does. + // The actual terminal draw is deferred until after the drain. + // + // The drain is capped at 500ms to guarantee periodic renders even under + // sustained input (e.g., held key repeat). This is deliberately longer + // than FRAME_DURATION — under CPU pressure, a shorter cap would defeat + // the purpose of batching. + let drain_deadline = Instant::now() + Duration::from_millis(500); + loop { + let event = if let Some(e) = pending_event.take() { + Some(e) } else { - Duration::from_millis(50) + poll_event(Duration::ZERO)? }; - poll_event(timeout)? - }; - - let Some(event) = event else { continue }; + let Some(event) = event else { break }; - let (event, next) = coalesce_mouse_moves(event)?; - pending_event = next; + let (event, next) = coalesce_mouse_moves(event)?; + pending_event = next; - // Event debug dialog receives ALL RAW events (before any translation or processing) - // This is essential for diagnosing terminal keybinding issues - if editor.is_event_debug_active() { - if let CrosstermEvent::Key(key_event) = event { - if key_event.kind == KeyEventKind::Press { - editor.handle_event_debug_input(&key_event); - needs_render = true; + // Event debug dialog receives ALL RAW events (before any translation or processing) + // This is essential for diagnosing terminal keybinding issues + if editor.is_event_debug_active() { + if let CrosstermEvent::Key(key_event) = event { + if key_event.kind == KeyEventKind::Press { + editor.handle_event_debug_input(&key_event); + needs_render = true; + } } + // Consume all events while event debug is active + continue; } - // Consume all events while event debug is active - continue; - } - match event { - CrosstermEvent::Key(key_event) => { - if key_event.kind == KeyEventKind::Press { - let _span = tracing::trace_span!( - "handle_key", - code = ?key_event.code, - modifiers = ?key_event.modifiers, - ) - .entered(); - // Apply key translation (for input calibration) - // Use editor's translator so calibration changes take effect immediately - let translated_event = editor.key_translator().translate(key_event); - handle_key_event(editor, translated_event)?; + match event { + CrosstermEvent::Key(key_event) => { + if key_event.kind == KeyEventKind::Press { + let _span = tracing::trace_span!( + "handle_key", + code = ?key_event.code, + modifiers = ?key_event.modifiers, + ) + .entered(); + // Apply key translation (for input calibration) + // Use editor's translator so calibration changes take effect immediately + let translated_event = editor.key_translator().translate(key_event); + handle_key_event(editor, translated_event)?; + needs_render = true; + } + } + CrosstermEvent::Mouse(mouse_event) => { + if handle_mouse_event(editor, mouse_event)? { + needs_render = true; + } + } + CrosstermEvent::Resize(w, h) => { + editor.resize(w, h); needs_render = true; + // Resize needs a real render to establish new frame + // dimensions. Stop draining and fall through to draw. + break; } - } - CrosstermEvent::Mouse(mouse_event) => { - if handle_mouse_event(editor, mouse_event)? { + CrosstermEvent::Paste(text) => { + // External paste from terminal (bracketed paste mode) + editor.paste_text(text); needs_render = true; } + _ => {} } - CrosstermEvent::Resize(w, h) => { - editor.resize(w, h); - needs_render = true; + + // Update layout caches after each event so subsequent events in + // this drain batch see correct visual layout (wrapped lines, + // viewport positions, scroll sync). Drawing is deferred. + if needs_render { + editor.recompute_layout_cached(); } - CrosstermEvent::Paste(text) => { - // External paste from terminal (bracketed paste mode) - editor.paste_text(text); - needs_render = true; + + if Instant::now() >= drain_deadline { + break; + } + } + + if needs_render && last_render.elapsed() >= FRAME_DURATION { + { + let _span = tracing::info_span!("terminal_draw").entered(); + terminal.draw(|frame| editor.render(frame))?; } - _ => {} + last_render = Instant::now(); + needs_render = false; + // Loop back immediately to drain any events that arrived during + // the render before considering another frame. + continue; + } + + // Block until next event or timeout + let timeout = if needs_render { + FRAME_DURATION.saturating_sub(last_render.elapsed()) + } else { + Duration::from_millis(50) + }; + + if let Some(event) = poll_event(timeout)? { + pending_event = Some(event); } } From 21200575971f712aa39693c16b8939a58f0cd650 Mon Sep 17 00:00:00 2001 From: Noam Lewis Date: Tue, 24 Feb 2026 23:57:33 +0200 Subject: [PATCH 5/6] Fix clippy let_underscore_must_use lint on channel sends Co-Authored-By: Claude Opus 4.6 --- crates/fresh-editor/src/app/mod.rs | 5 +++-- crates/fresh-editor/src/app/plugin_commands.rs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/fresh-editor/src/app/mod.rs b/crates/fresh-editor/src/app/mod.rs index 9955be464..56ae43378 100644 --- a/crates/fresh-editor/src/app/mod.rs +++ b/crates/fresh-editor/src/app/mod.rs @@ -1175,11 +1175,12 @@ impl Editor { .spawn(move || { let registry = crate::primitives::grammar::GrammarRegistry::for_editor(grammar_config_dir); - let _ = grammar_sender.send( + // Ok to ignore: receiver may be gone if app is shutting down. + drop(grammar_sender.send( crate::services::async_bridge::AsyncMessage::GrammarRegistryBuilt { registry, }, - ); + )); }) .ok(); } diff --git a/crates/fresh-editor/src/app/plugin_commands.rs b/crates/fresh-editor/src/app/plugin_commands.rs index e79c45496..a4f0c2bf4 100644 --- a/crates/fresh-editor/src/app/plugin_commands.rs +++ b/crates/fresh-editor/src/app/plugin_commands.rs @@ -1592,11 +1592,12 @@ impl Editor { use crate::primitives::grammar::GrammarRegistry; match GrammarRegistry::with_additional_grammars(&base_registry, &additional) { Some(new_registry) => { - let _ = sender.send( + // Ok to ignore: receiver may be gone if app is shutting down. + drop(sender.send( crate::services::async_bridge::AsyncMessage::GrammarRegistryBuilt { registry: std::sync::Arc::new(new_registry), }, - ); + )); } None => { tracing::error!("Failed to rebuild grammar registry in background"); From a4fa596d582ed0ddf3d90993f30055cec6dd4684 Mon Sep 17 00:00:00 2001 From: Noam Lewis Date: Tue, 24 Feb 2026 23:58:34 +0200 Subject: [PATCH 6/6] cargo clippy --fix && cargo fmt --- .../fresh-editor/src/app/buffer_management.rs | 7 ++--- crates/fresh-editor/src/app/file_explorer.rs | 2 +- .../fresh-editor/src/app/file_operations.rs | 9 ++++--- crates/fresh-editor/src/app/input.rs | 8 +++--- .../src/app/keybinding_editor/editor.rs | 5 +--- crates/fresh-editor/src/app/mod.rs | 9 +++---- .../fresh-editor/src/app/on_save_actions.rs | 12 +++------ .../fresh-editor/src/app/plugin_commands.rs | 6 +---- crates/fresh-editor/src/app/prompt_actions.rs | 9 +++---- crates/fresh-editor/src/app/render.rs | 8 +++--- crates/fresh-editor/src/app/split_actions.rs | 6 +---- crates/fresh-editor/src/app/workspace.rs | 6 ++--- crates/fresh-editor/src/input/actions.rs | 4 +-- crates/fresh-editor/src/input/line_move.rs | 2 +- .../src/input/quick_open/providers.rs | 2 +- crates/fresh-editor/src/main.rs | 6 ++--- crates/fresh-editor/src/model/buffer.rs | 12 ++++----- crates/fresh-editor/src/model/filesystem.rs | 8 +++--- crates/fresh-editor/src/model/piece_tree.rs | 12 ++------- .../fresh-editor/src/server/input_parser.rs | 2 +- crates/fresh-editor/src/server/ipc/mod.rs | 27 +++++++------------ .../fresh-editor/src/services/fs/manager.rs | 12 ++++----- .../src/services/process_limits.rs | 2 +- .../src/services/remote/connection.rs | 5 +--- .../src/services/remote/filesystem.rs | 2 +- .../src/services/remote/spawner.rs | 2 +- .../fresh-editor/src/view/settings/state.rs | 8 +++--- crates/fresh-editor/src/view/theme/loader.rs | 2 +- .../fresh-editor/src/view/ui/file_explorer.rs | 2 +- .../src/view/ui/split_rendering.rs | 18 ++++++------- 30 files changed, 82 insertions(+), 133 deletions(-) diff --git a/crates/fresh-editor/src/app/buffer_management.rs b/crates/fresh-editor/src/app/buffer_management.rs index 671cc8b4d..ce7614ad5 100644 --- a/crates/fresh-editor/src/app/buffer_management.rs +++ b/crates/fresh-editor/src/app/buffer_management.rs @@ -2377,9 +2377,10 @@ impl Editor { None => return Ok(()), }; - let rt = self.tokio_runtime.as_ref().ok_or_else(|| { - std::io::Error::new(std::io::ErrorKind::Other, "async runtime not available") - })?; + let rt = self + .tokio_runtime + .as_ref() + .ok_or_else(|| std::io::Error::other("async runtime not available"))?; let io_results: Vec> = rt.block_on(async { let mut handles = Vec::with_capacity(io_work.len()); diff --git a/crates/fresh-editor/src/app/file_explorer.rs b/crates/fresh-editor/src/app/file_explorer.rs index b3ad86a0a..bc3a8f475 100644 --- a/crates/fresh-editor/src/app/file_explorer.rs +++ b/crates/fresh-editor/src/app/file_explorer.rs @@ -566,7 +566,7 @@ impl Editor { let delete_result = if self.filesystem.remote_connection_info().is_some() { self.move_to_remote_trash(&path) } else { - trash::delete(&path).map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e)) + trash::delete(&path).map_err(|e| std::io::Error::other(e)) }; match delete_result { diff --git a/crates/fresh-editor/src/app/file_operations.rs b/crates/fresh-editor/src/app/file_operations.rs index 235c3e960..96a669d8b 100644 --- a/crates/fresh-editor/src/app/file_operations.rs +++ b/crates/fresh-editor/src/app/file_operations.rs @@ -900,10 +900,11 @@ impl Editor { let path = self.active_state().buffer.file_path()?; // Get current file modification time - let current_mtime = match self.filesystem.metadata(path).ok().and_then(|m| m.modified) { - Some(mtime) => mtime, - None => return None, // File doesn't exist or can't read metadata - }; + let current_mtime = self + .filesystem + .metadata(path) + .ok() + .and_then(|m| m.modified)?; // Compare with our recorded modification time match self.file_mod_times.get(path) { diff --git a/crates/fresh-editor/src/app/input.rs b/crates/fresh-editor/src/app/input.rs index 917eab179..7acb2cbf8 100644 --- a/crates/fresh-editor/src/app/input.rs +++ b/crates/fresh-editor/src/app/input.rs @@ -305,7 +305,7 @@ impl Editor { let has_line_index = self .buffers .get(&self.active_buffer()) - .map_or(true, |s| s.buffer.line_count().is_some()); + .is_none_or(|s| s.buffer.line_count().is_some()); if has_line_index { self.start_prompt( t!("file.goto_line_prompt").to_string(), @@ -1345,7 +1345,7 @@ impl Editor { .unwrap_or(0); if let Some(view_state) = self .composite_view_states - .get_mut(&(active_split.into(), buffer_id)) + .get_mut(&(active_split, buffer_id)) { view_state.scroll(delta as isize, max_row); tracing::trace!( @@ -2862,7 +2862,7 @@ impl Editor { // Add all available syntaxes from the grammar registry (100+ languages) let mut syntax_names: Vec<&str> = self.grammar_registry.available_syntaxes(); // Sort alphabetically for easier navigation - syntax_names.sort_unstable_by(|a, b| a.to_lowercase().cmp(&b.to_lowercase())); + syntax_names.sort_unstable_by_key(|a| a.to_lowercase()); let mut current_index_found = None; for syntax_name in syntax_names { @@ -2875,7 +2875,7 @@ impl Editor { // config key, e.g. "rust" not "Rust"). let is_current = self .resolve_language_id(syntax_name) - .map_or(false, |id| id == current_language); + .is_some_and(|id| id == current_language); if is_current { current_index_found = Some(suggestions.len()); } diff --git a/crates/fresh-editor/src/app/keybinding_editor/editor.rs b/crates/fresh-editor/src/app/keybinding_editor/editor.rs index 88e74e790..8b5c2d696 100644 --- a/crates/fresh-editor/src/app/keybinding_editor/editor.rs +++ b/crates/fresh-editor/src/app/keybinding_editor/editor.rs @@ -628,10 +628,7 @@ impl KeybindingEditor { /// Apply the edit dialog to create/update a binding. /// Returns an error message if validation fails. pub fn apply_edit_dialog(&mut self) -> Option { - let dialog = match self.edit_dialog.take() { - Some(d) => d, - None => return None, - }; + let dialog = self.edit_dialog.take()?; if dialog.key_code.is_none() || dialog.action_text.is_empty() { self.edit_dialog = Some(dialog); diff --git a/crates/fresh-editor/src/app/mod.rs b/crates/fresh-editor/src/app/mod.rs index 56ae43378..4f12c102b 100644 --- a/crates/fresh-editor/src/app/mod.rs +++ b/crates/fresh-editor/src/app/mod.rs @@ -3203,9 +3203,8 @@ impl Editor { /// Update Quick Open suggestions based on current input fn update_quick_open_suggestions(&mut self, input: &str) { - let suggestions = if input.starts_with('>') { + let suggestions = if let Some(query) = input.strip_prefix('>') { // Command mode - let query = &input[1..]; let active_buffer_mode = self .buffer_metadata .get(&self.active_buffer()) @@ -3218,13 +3217,11 @@ impl Editor { &self.active_custom_contexts, active_buffer_mode, ) - } else if input.starts_with('#') { + } else if let Some(query) = input.strip_prefix('#') { // Buffer mode - let query = &input[1..]; self.get_buffer_suggestions(query) - } else if input.starts_with(':') { + } else if let Some(line_str) = input.strip_prefix(':') { // Go to line mode - let line_str = &input[1..]; self.get_goto_line_suggestions(line_str) } else { // File mode (default) diff --git a/crates/fresh-editor/src/app/on_save_actions.rs b/crates/fresh-editor/src/app/on_save_actions.rs index ee3af4f11..450de2dd1 100644 --- a/crates/fresh-editor/src/app/on_save_actions.rs +++ b/crates/fresh-editor/src/app/on_save_actions.rs @@ -37,16 +37,12 @@ impl Editor { let mut ran_any_action = false; // Run whitespace cleanup actions first (before formatter) - if self.config.editor.trim_trailing_whitespace_on_save { - if self.trim_trailing_whitespace()? { - ran_any_action = true; - } + if self.config.editor.trim_trailing_whitespace_on_save && self.trim_trailing_whitespace()? { + ran_any_action = true; } - if self.config.editor.ensure_final_newline_on_save { - if self.ensure_final_newline()? { - ran_any_action = true; - } + if self.config.editor.ensure_final_newline_on_save && self.ensure_final_newline()? { + ran_any_action = true; } // If whitespace cleanup made changes, re-save diff --git a/crates/fresh-editor/src/app/plugin_commands.rs b/crates/fresh-editor/src/app/plugin_commands.rs index a4f0c2bf4..baf998600 100644 --- a/crates/fresh-editor/src/app/plugin_commands.rs +++ b/crates/fresh-editor/src/app/plugin_commands.rs @@ -1569,11 +1569,7 @@ impl Editor { // Update config.languages with the extensions so detect_language() works for (language, _path, extensions) in &additional { - let lang_config = self - .config - .languages - .entry(language.clone()) - .or_insert_with(Default::default); + let lang_config = self.config.languages.entry(language.clone()).or_default(); for ext in extensions { if !lang_config.extensions.contains(ext) { lang_config.extensions.push(ext.clone()); diff --git a/crates/fresh-editor/src/app/prompt_actions.rs b/crates/fresh-editor/src/app/prompt_actions.rs index 13d48bb35..1fce6ff7e 100644 --- a/crates/fresh-editor/src/app/prompt_actions.rs +++ b/crates/fresh-editor/src/app/prompt_actions.rs @@ -1049,21 +1049,18 @@ impl Editor { selected_index: Option, ) -> PromptResult { // Determine the mode based on prefix - if input.starts_with('>') { + if let Some(query) = input.strip_prefix('>') { // Command mode - find and execute the selected command - let query = &input[1..]; return self.handle_quick_open_command(query, selected_index); } - if input.starts_with('#') { + if let Some(query) = input.strip_prefix('#') { // Buffer mode - switch to selected buffer - let query = &input[1..]; return self.handle_quick_open_buffer(query, selected_index); } - if input.starts_with(':') { + if let Some(line_str) = input.strip_prefix(':') { // Go to line mode - let line_str = &input[1..]; if let Ok(line_num) = line_str.parse::() { if line_num > 0 { self.goto_line_col(line_num, None); diff --git a/crates/fresh-editor/src/app/render.rs b/crates/fresh-editor/src/app/render.rs index 43103e894..696128013 100644 --- a/crates/fresh-editor/src/app/render.rs +++ b/crates/fresh-editor/src/app/render.rs @@ -2186,11 +2186,9 @@ impl Editor { let (new_pos, new_sticky) = match &visual_action { VisualAction::UpDown { direction, .. } => { // Calculate current visual column from cached layout - let current_visual_col = - match self.cached_layout.byte_to_visual_column(split_id, position) { - Some(col) => col, - None => return None, - }; + let current_visual_col = self + .cached_layout + .byte_to_visual_column(split_id, position)?; let goal_visual_col = if sticky_column > 0 { sticky_column diff --git a/crates/fresh-editor/src/app/split_actions.rs b/crates/fresh-editor/src/app/split_actions.rs index 975781c5a..4ccfa9c42 100644 --- a/crates/fresh-editor/src/app/split_actions.rs +++ b/crates/fresh-editor/src/app/split_actions.rs @@ -177,11 +177,7 @@ impl Editor { // Ensure the active tab is visible in the newly active split let split_id = self.split_manager.active_split(); - self.ensure_active_tab_visible( - split_id.into(), - self.active_buffer(), - self.effective_tabs_width(), - ); + self.ensure_active_tab_visible(split_id, self.active_buffer(), self.effective_tabs_width()); let buffer_id = self.active_buffer(); diff --git a/crates/fresh-editor/src/app/workspace.rs b/crates/fresh-editor/src/app/workspace.rs index cb5aaf665..45fdb4168 100644 --- a/crates/fresh-editor/src/app/workspace.rs +++ b/crates/fresh-editor/src/app/workspace.rs @@ -819,8 +819,7 @@ impl Editor { // Restore label if present if let Some(label) = label { - self.split_manager - .set_label(current_leaf_id.into(), label.clone()); + self.split_manager.set_label(current_leaf_id, label.clone()); } // Restore the view state for this split @@ -854,8 +853,7 @@ impl Editor { // Restore label if present if let Some(label) = label { - self.split_manager - .set_label(current_leaf_id.into(), label.clone()); + self.split_manager.set_label(current_leaf_id, label.clone()); } self.split_manager diff --git a/crates/fresh-editor/src/input/actions.rs b/crates/fresh-editor/src/input/actions.rs index cc296a82d..9cfb2b88b 100644 --- a/crates/fresh-editor/src/input/actions.rs +++ b/crates/fresh-editor/src/input/actions.rs @@ -1785,7 +1785,7 @@ pub fn action_to_events( let mut found_pos = None; while let Some((line_start, line_content)) = iter.prev() { // Check if this is an empty line (only whitespace/newline) - let trimmed = line_content.trim_end_matches(|c| c == '\n' || c == '\r'); + let trimmed = line_content.trim_end_matches(['\n', '\r']); if trimmed.is_empty() || trimmed.chars().all(char::is_whitespace) { found_pos = Some(line_start); break; @@ -1822,7 +1822,7 @@ pub fn action_to_events( let mut found_pos = None; while let Some((line_start, line_content)) = iter.next_line() { // Check if this is an empty line (only whitespace/newline) - let trimmed = line_content.trim_end_matches(|c| c == '\n' || c == '\r'); + let trimmed = line_content.trim_end_matches(['\n', '\r']); if trimmed.is_empty() || trimmed.chars().all(char::is_whitespace) { found_pos = Some(line_start); break; diff --git a/crates/fresh-editor/src/input/line_move.rs b/crates/fresh-editor/src/input/line_move.rs index 4bad7839d..02cc6561b 100644 --- a/crates/fresh-editor/src/input/line_move.rs +++ b/crates/fresh-editor/src/input/line_move.rs @@ -228,7 +228,7 @@ pub(crate) fn move_lines( .map(|(cursor_id, cursor)| { ( cursor_id, - cursor.selection_range().map(|range| range.clone()), + cursor.selection_range(), cursor.position, cursor.anchor, cursor.sticky_column, diff --git a/crates/fresh-editor/src/input/quick_open/providers.rs b/crates/fresh-editor/src/input/quick_open/providers.rs index 89b3b8699..a5d31ccab 100644 --- a/crates/fresh-editor/src/input/quick_open/providers.rs +++ b/crates/fresh-editor/src/input/quick_open/providers.rs @@ -409,7 +409,7 @@ impl FileProvider { .try_git_files(cwd) .or_else(|| self.try_fd_files(cwd)) .or_else(|| self.try_find_files(cwd)) - .unwrap_or_else(Vec::new); + .unwrap_or_default(); // Add frecency scores let files: Vec = files diff --git a/crates/fresh-editor/src/main.rs b/crates/fresh-editor/src/main.rs index 1fd3a4630..f54bcd3ef 100644 --- a/crates/fresh-editor/src/main.rs +++ b/crates/fresh-editor/src/main.rs @@ -1535,7 +1535,7 @@ fn create_plugin_package( "#, name, if description.is_empty() { - format!("A Fresh plugin") + "A Fresh plugin".to_string() } else { description.to_string() }, @@ -1636,7 +1636,7 @@ fn create_theme_package( "#, name, if description.is_empty() { - format!("A Fresh theme") + "A Fresh theme".to_string() } else { description.to_string() }, @@ -1765,7 +1765,7 @@ fn create_language_package( "#, name, if description.is_empty() { - format!("Language support for Fresh") + "Language support for Fresh".to_string() } else { description.to_string() }, diff --git a/crates/fresh-editor/src/model/buffer.rs b/crates/fresh-editor/src/model/buffer.rs index d2086d573..c609db22d 100644 --- a/crates/fresh-editor/src/model/buffer.rs +++ b/crates/fresh-editor/src/model/buffer.rs @@ -1268,7 +1268,7 @@ impl TextBuffer { ) -> io::Result<()> { const CHUNK_SIZE: usize = 1024 * 1024; // 1MB chunks - let file_size = self.fs.metadata(src_path)?.size as u64; + let file_size = self.fs.metadata(src_path)?.size; let mut offset = 0u64; while offset < file_size { @@ -1683,7 +1683,7 @@ impl TextBuffer { // querying the entire leaf. This handles unloaded segments in // large file mode after line scanning has populated the metadata. if start == 0 && len == leaf.bytes { - leaf.line_feed_cnt.map(|c| c as usize) + leaf.line_feed_cnt.map(|c| c) } else { None } @@ -2057,11 +2057,9 @@ impl TextBuffer { .map(|b| !b.is_loaded()) .unwrap_or(false); - if needs_loading { - if self.chunk_split_and_load(&piece_view, current_offset)? { - restarted_iteration = true; - break; - } + if needs_loading && self.chunk_split_and_load(&piece_view, current_offset)? { + restarted_iteration = true; + break; } // Calculate the range to read from this piece diff --git a/crates/fresh-editor/src/model/filesystem.rs b/crates/fresh-editor/src/model/filesystem.rs index d33f6adea..00ad84207 100644 --- a/crates/fresh-editor/src/model/filesystem.rs +++ b/crates/fresh-editor/src/model/filesystem.rs @@ -860,9 +860,7 @@ impl FileSystem for StdFileSystem { .stdout(Stdio::null()) .stderr(Stdio::piped()) .spawn() - .map_err(|e| { - io::Error::new(io::ErrorKind::Other, format!("failed to spawn sudo: {}", e)) - })?; + .map_err(|e| io::Error::other(format!("failed to spawn sudo: {}", e)))?; if let Some(mut stdin) = child.stdin.take() { use std::io::Write; @@ -883,7 +881,7 @@ impl FileSystem for StdFileSystem { .args(["chmod", &format!("{:o}", mode), &path.to_string_lossy()]) .status()?; if !status.success() { - return Err(io::Error::new(io::ErrorKind::Other, "sudo chmod failed")); + return Err(io::Error::other("sudo chmod failed")); } // Set ownership via sudo chown @@ -895,7 +893,7 @@ impl FileSystem for StdFileSystem { ]) .status()?; if !status.success() { - return Err(io::Error::new(io::ErrorKind::Other, "sudo chown failed")); + return Err(io::Error::other("sudo chown failed")); } Ok(()) diff --git a/crates/fresh-editor/src/model/piece_tree.rs b/crates/fresh-editor/src/model/piece_tree.rs index 6e1398b79..f46367af0 100644 --- a/crates/fresh-editor/src/model/piece_tree.rs +++ b/crates/fresh-editor/src/model/piece_tree.rs @@ -1111,16 +1111,8 @@ impl PieceTree { } // Partial overlap - keep parts outside delete range - let before_bytes = if delete_start > piece_start { - delete_start - piece_start - } else { - 0 - }; - let after_bytes = if delete_end < piece_end { - piece_end - delete_end - } else { - 0 - }; + let before_bytes = delete_start.saturating_sub(piece_start); + let after_bytes = piece_end.saturating_sub(delete_end); if before_bytes > 0 && after_bytes > 0 { // Delete in the middle of this leaf - split into two diff --git a/crates/fresh-editor/src/server/input_parser.rs b/crates/fresh-editor/src/server/input_parser.rs index 83b0c370c..73ecb0bb2 100644 --- a/crates/fresh-editor/src/server/input_parser.rs +++ b/crates/fresh-editor/src/server/input_parser.rs @@ -475,7 +475,7 @@ fn byte_to_keycode(byte: u8) -> KeyCode { 28..=31 => KeyCode::Char((b'\\' + byte - 28) as char), 32 => KeyCode::Char(' '), 127 => KeyCode::Backspace, - b if b >= 32 && b < 127 => KeyCode::Char(b as char), + b if (32..127).contains(&b) => KeyCode::Char(b as char), _ => KeyCode::Null, } } diff --git a/crates/fresh-editor/src/server/ipc/mod.rs b/crates/fresh-editor/src/server/ipc/mod.rs index 77d846f2e..a1ab5f489 100644 --- a/crates/fresh-editor/src/server/ipc/mod.rs +++ b/crates/fresh-editor/src/server/ipc/mod.rs @@ -207,17 +207,8 @@ impl ServerListener { pub fn accept(&mut self) -> io::Result> { // Try to accept on control socket first (client connects here first) // Use set_nonblocking for non-blocking accept - if let Err(e) = self - .control_listener - .set_nonblocking(ListenerNonblockingMode::Accept) - { - // On Windows, set_nonblocking might fail if the pipe is in a certain state - #[cfg(windows)] - if platform_windows::is_transient_pipe_error(&e) { - return Ok(None); - } - return Err(e); - } + self.control_listener + .set_nonblocking(ListenerNonblockingMode::Accept)?; let control_stream = match self.control_listener.accept() { Ok(stream) => stream, @@ -282,7 +273,7 @@ impl StreamWrapper { pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { self.0 .lock() - .map_err(|_| io::Error::new(io::ErrorKind::Other, "mutex poisoned"))? + .map_err(|_| io::Error::other("mutex poisoned"))? .set_nonblocking(nonblocking) } @@ -291,7 +282,7 @@ impl StreamWrapper { let mut guard = self .0 .lock() - .map_err(|_| io::Error::new(io::ErrorKind::Other, "mutex poisoned"))?; + .map_err(|_| io::Error::other("mutex poisoned"))?; Write::write_all(&mut *guard, buf) } @@ -300,7 +291,7 @@ impl StreamWrapper { let mut guard = self .0 .lock() - .map_err(|_| io::Error::new(io::ErrorKind::Other, "mutex poisoned"))?; + .map_err(|_| io::Error::other("mutex poisoned"))?; Write::flush(&mut *guard) } @@ -315,11 +306,11 @@ impl StreamWrapper { )); } Err(std::sync::TryLockError::Poisoned(_)) => { - return Err(io::Error::new(io::ErrorKind::Other, "mutex poisoned")); + return Err(io::Error::other("mutex poisoned")); } }; - platform::try_read_nonblocking(&mut *guard, buf) + platform::try_read_nonblocking(&mut guard, buf) } } @@ -340,7 +331,7 @@ impl Read for StreamWrapper { let result = self .0 .lock() - .map_err(|_| io::Error::new(io::ErrorKind::Other, "mutex poisoned"))? + .map_err(|_| io::Error::other("mutex poisoned"))? .read(buf); map_windows_pipe_error(result) } @@ -351,7 +342,7 @@ impl Read for &StreamWrapper { let result = self .0 .lock() - .map_err(|_| io::Error::new(io::ErrorKind::Other, "mutex poisoned"))? + .map_err(|_| io::Error::other("mutex poisoned"))? .read(buf); map_windows_pipe_error(result) } diff --git a/crates/fresh-editor/src/services/fs/manager.rs b/crates/fresh-editor/src/services/fs/manager.rs index a18f0e18d..00dfdfd69 100644 --- a/crates/fresh-editor/src/services/fs/manager.rs +++ b/crates/fresh-editor/src/services/fs/manager.rs @@ -74,7 +74,7 @@ impl FsManager { let path_clone = path.clone(); let result = tokio::task::spawn_blocking(move || fs.read_dir(&path_clone)) .await - .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?; + .map_err(|e| io::Error::other(e.to_string()))?; // Notify all waiting requesters let mut pending = self.pending_dir_requests.lock().await; @@ -120,7 +120,7 @@ impl FsManager { for task in tasks { match task.await { Ok(result) => results.push(result), - Err(e) => results.push(Err(io::Error::new(io::ErrorKind::Other, e.to_string()))), + Err(e) => results.push(Err(io::Error::other(e.to_string()))), } } @@ -133,7 +133,7 @@ impl FsManager { let path = path.to_path_buf(); tokio::task::spawn_blocking(move || fs.metadata(&path)) .await - .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))? + .map_err(|e| io::Error::other(e.to_string()))? } /// Check if a path exists @@ -151,7 +151,7 @@ impl FsManager { let path = path.to_path_buf(); tokio::task::spawn_blocking(move || fs.is_dir(&path)) .await - .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))? + .map_err(|e| io::Error::other(e.to_string()))? } /// Get a complete entry for a path (with metadata) @@ -204,7 +204,7 @@ impl FsManager { } }) .await - .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))? + .map_err(|e| io::Error::other(e.to_string()))? } /// Get canonical path @@ -213,7 +213,7 @@ impl FsManager { let path = path.to_path_buf(); tokio::task::spawn_blocking(move || fs.canonicalize(&path)) .await - .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))? + .map_err(|e| io::Error::other(e.to_string()))? } /// List directory and fetch metadata for all entries in parallel diff --git a/crates/fresh-editor/src/services/process_limits.rs b/crates/fresh-editor/src/services/process_limits.rs index 9535d1384..b9618a6bd 100644 --- a/crates/fresh-editor/src/services/process_limits.rs +++ b/crates/fresh-editor/src/services/process_limits.rs @@ -318,7 +318,7 @@ fn apply_memory_limit_setrlimit(bytes: u64) -> io::Result<()> { // Set RLIMIT_AS (address space / virtual memory limit) // On 32-bit platforms, rlim_t is u32, so we need to convert carefully. // If bytes exceeds what rlim_t can represent, clamp to rlim_t::MAX. - let limit = bytes.min(nix::libc::rlim_t::MAX as u64) as nix::libc::rlim_t; + let limit = bytes.min(nix::libc::rlim_t::MAX) as nix::libc::rlim_t; setrlimit(Resource::RLIMIT_AS, limit, limit) .map_err(|e| io::Error::other(format!("setrlimit AS failed: {}", e))) } diff --git a/crates/fresh-editor/src/services/remote/connection.rs b/crates/fresh-editor/src/services/remote/connection.rs index 55f7e1125..13e9f9f66 100644 --- a/crates/fresh-editor/src/services/remote/connection.rs +++ b/crates/fresh-editor/src/services/remote/connection.rs @@ -218,10 +218,7 @@ impl Drop for SshConnection { // If it fails (process already exited, permission error, etc.) // there's nothing we can do in a Drop impl — the OS will clean // up the zombie when our process exits. - match self.process.start_kill() { - Ok(()) => {} - Err(_) => {} - } + if let Ok(()) = self.process.start_kill() {} } } diff --git a/crates/fresh-editor/src/services/remote/filesystem.rs b/crates/fresh-editor/src/services/remote/filesystem.rs index 4d37a13e0..38f710a25 100644 --- a/crates/fresh-editor/src/services/remote/filesystem.rs +++ b/crates/fresh-editor/src/services/remote/filesystem.rs @@ -60,7 +60,7 @@ impl RemoteFileSystem { }; io::Error::new(kind, msg) } - e => io::Error::new(io::ErrorKind::Other, e.to_string()), + e => io::Error::other(e.to_string()), } } diff --git a/crates/fresh-editor/src/services/remote/spawner.rs b/crates/fresh-editor/src/services/remote/spawner.rs index c71a993b8..23482e3a5 100644 --- a/crates/fresh-editor/src/services/remote/spawner.rs +++ b/crates/fresh-editor/src/services/remote/spawner.rs @@ -133,7 +133,7 @@ impl ProcessSpawner for RemoteProcessSpawner { let result = result_rx .await .map_err(|_| SpawnError::Channel(ChannelError::ChannelClosed))? - .map_err(|e| SpawnError::Process(e))?; + .map_err(SpawnError::Process)?; let exit_code = result .get("code") diff --git a/crates/fresh-editor/src/view/settings/state.rs b/crates/fresh-editor/src/view/settings/state.rs index 7f6bfe359..740e5d2a8 100644 --- a/crates/fresh-editor/src/view/settings/state.rs +++ b/crates/fresh-editor/src/view/settings/state.rs @@ -1553,11 +1553,9 @@ impl SettingsState { } } self.on_value_changed(); - } else { - if let Some(item) = self.current_item_mut() { - if let SettingControl::Json(state) = &mut item.control { - state.revert(); - } + } else if let Some(item) = self.current_item_mut() { + if let SettingControl::Json(state) = &mut item.control { + state.revert(); } } self.editing_text = false; diff --git a/crates/fresh-editor/src/view/theme/loader.rs b/crates/fresh-editor/src/view/theme/loader.rs index 96662ccb3..e952722ef 100644 --- a/crates/fresh-editor/src/view/theme/loader.rs +++ b/crates/fresh-editor/src/view/theme/loader.rs @@ -15,7 +15,7 @@ use super::types::{Theme, ThemeFile, ThemeInfo, BUILTIN_THEMES}; /// This ensures that theme names can be matched regardless of how they appear /// in filenames vs. JSON content (e.g., "Catppuccin Mocha" matches "catppuccin-mocha"). pub fn normalize_theme_name(name: &str) -> String { - name.to_lowercase().replace('_', "-").replace(' ', "-") + name.to_lowercase().replace(['_', ' '], "-") } /// A registry holding all loaded themes. diff --git a/crates/fresh-editor/src/view/ui/file_explorer.rs b/crates/fresh-editor/src/view/ui/file_explorer.rs index f7c0abf66..15bd9c534 100644 --- a/crates/fresh-editor/src/view/ui/file_explorer.rs +++ b/crates/fresh-editor/src/view/ui/file_explorer.rs @@ -113,7 +113,7 @@ impl FileExplorerRenderer { // Extract just the hostname from "user@host" or "user@host:port" let hostname = host .split('@') - .last() + .next_back() .unwrap_or(host) .split(':') .next() diff --git a/crates/fresh-editor/src/view/ui/split_rendering.rs b/crates/fresh-editor/src/view/ui/split_rendering.rs index 69db1f884..3dd7082f1 100644 --- a/crates/fresh-editor/src/view/ui/split_rendering.rs +++ b/crates/fresh-editor/src/view/ui/split_rendering.rs @@ -1077,7 +1077,7 @@ impl SplitRenderer { .as_deref() .and_then(|vs| vs.get(&split_id)) .map(|vs| vs.cursors.clone()) - .unwrap_or_else(crate::model::cursor::Cursors::new); + .unwrap_or_default(); // Resolve hidden fold byte ranges so ensure_visible can skip // folded lines when counting distance to the cursor. let hidden_ranges: Vec<(usize, usize)> = split_view_states @@ -1320,7 +1320,7 @@ impl SplitRenderer { let split_cursors = split_view_states .get(&split_id) .map(|vs| vs.cursors.clone()) - .unwrap_or_else(crate::model::cursor::Cursors::new); + .unwrap_or_default(); // Resolve hidden fold byte ranges so ensure_visible can skip // folded lines when counting distance to the cursor. let hidden_ranges: Vec<(usize, usize)> = split_view_states @@ -2543,7 +2543,7 @@ impl SplitRenderer { let viewport_end = tokens .iter() .filter_map(|t| t.source_offset) - .last() + .next_back() .unwrap_or(viewport.top_byte) + 1; let soft_breaks = state.soft_breaks.query_viewport( @@ -2562,7 +2562,7 @@ impl SplitRenderer { let viewport_end = tokens .iter() .filter_map(|t| t.source_offset) - .last() + .next_back() .unwrap_or(viewport.top_byte) + 1; let conceal_ranges = @@ -3919,10 +3919,8 @@ impl SplitRenderer { // Skip markdown compose overlays in Source mode — they should only // render in the Compose-mode split. - if !is_compose { - if overlay.namespace.as_ref() == Some(&md_emphasis_ns) { - continue; - } + if !is_compose && overlay.namespace.as_ref() == Some(&md_emphasis_ns) { + continue; } viewport_overlays.push((overlay.clone(), range)); @@ -3994,7 +3992,7 @@ impl SplitRenderer { // Collapsed headers from marker-based folds let collapsed_headers = folds.collapsed_headers(&state.buffer, &state.marker_list); - for (line, _) in &collapsed_headers { + for line in collapsed_headers.keys() { if *line >= viewport_start_line && *line <= viewport_end_line { indicators.insert(*line, FoldIndicator { collapsed: true }); } @@ -5002,7 +5000,7 @@ impl SplitRenderer { .map(|m| m.line_end_byte) .unwrap_or(0); let near_buffer_end = last_mapped_byte + 2 >= state.buffer.len(); - let already_mapped = view_line_mappings.last().map_or(false, |m| { + let already_mapped = view_line_mappings.last().is_some_and(|m| { m.char_source_bytes.is_empty() && m.line_end_byte == state.buffer.len() }); if near_buffer_end && !already_mapped {