diff --git a/Cargo.lock b/Cargo.lock index c38d67f..c58160f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,7 +53,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -64,7 +64,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -73,12 +73,72 @@ version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bstr" version = "1.13.0" @@ -91,16 +151,28 @@ dependencies = [ ] [[package]] -name = "bytes" -version = "1.12.1" +name = "bumpalo" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] -name = "cassowary" -version = "0.3.0" +name = "by_address" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" + +[[package]] +name = "bytemuck" +version = "1.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "castaway" @@ -127,6 +199,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_aliases" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + [[package]] name = "clap" version = "4.6.4" @@ -175,9 +253,9 @@ checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "compact_str" -version = "0.8.2" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd622ebbb56a5b2ccb651b32b911cdeb2a9b4b11776b2473bf26a26a286244e" +checksum = "9dfdd1c2274d9aa354115b09dc9a901d6c5576818cdf70d14cae2bdb47df00ab" dependencies = [ "castaway", "cfg-if", @@ -187,14 +265,40 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "crossterm" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" +checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags", + "bitflags 2.13.1", "crossterm_winapi", + "derive_more", + "document-features", "futures-core", "mio", "parking_lot", @@ -213,6 +317,26 @@ dependencies = [ "winapi", ] +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "csscolorparser" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2a7d3066da2de787b7f032c736763eb7ae5d355f81a68bab2675a96008b0bf" +dependencies = [ + "lab", + "phf", +] + [[package]] name = "darling" version = "0.23.0" @@ -247,6 +371,50 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "deltae" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5729f5117e208430e437df2f4843f5e5952997175992d1414f94c57d61e270b4" + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.119", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "dirs" version = "6.0.0" @@ -265,7 +433,16 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.61.2", + "windows-sys", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", ] [[package]] @@ -287,7 +464,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys", +] + +[[package]] +name = "euclid" +version = "0.22.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a05365e3b1c6d1650318537c7460c6923f1abdd272ad6842baa2b509957a06" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fancy-regex" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" +dependencies = [ + "bit-set", + "regex", +] + +[[package]] +name = "fast-srgb8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" + +[[package]] +name = "filedescriptor" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e40758ed24c9b2eeb76c35fb0aebc66c626084edd827e07e1552279814c6682d" +dependencies = [ + "libc", + "thiserror 1.0.69", + "winapi", ] [[package]] @@ -296,11 +509,29 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "finl_unicode" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9844ddc3a6e533d62bba727eb6c28b5d360921d5175e9ff0f1e621a5c590a4d5" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "foldhash" -version = "0.1.5" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "futures-core" @@ -308,6 +539,34 @@ version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7" +[[package]] +name = "futures-task" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109" + +[[package]] +name = "futures-util" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.17" @@ -319,11 +578,34 @@ dependencies = [ "wasi", ] +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", +] + [[package]] name = "hashbrown" -version = "0.15.5" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "allocator-api2", "equivalent", @@ -335,6 +617,11 @@ name = "hashbrown" version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] [[package]] name = "heck" @@ -342,6 +629,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "ident_case" version = "1.0.1" @@ -407,9 +700,9 @@ checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] @@ -420,6 +713,34 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +[[package]] +name = "js-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "kasuari" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde5057d6143cc94e861d90f591b9303d6716c6b9602309150bd068853c10899" +dependencies = [ + "hashbrown 0.16.1", + "portable-atomic", + "thiserror 2.0.19", +] + +[[package]] +name = "lab" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf36173d4167ed999940f804952e6b08197cae5ad5d572eb4db150ce8ad5d58f" + [[package]] name = "lazy_static" version = "1.5.0" @@ -437,6 +758,7 @@ dependencies = [ "include_dir", "once_cell", "ratatui", + "ratatui-textarea", "serde", "serde_json", "serde_yaml", @@ -459,8 +781,7 @@ dependencies = [ "tree-sitter-rust", "tree-sitter-toml-ng", "tree-sitter-typescript", - "tui-textarea", - "unicode-width 0.2.0", + "unicode-width", ] [[package]] @@ -469,6 +790,12 @@ version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + [[package]] name = "libredox" version = "0.1.18" @@ -478,11 +805,26 @@ dependencies = [ "libc", ] +[[package]] +name = "line-clipping" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f50e8f47623268b5407192d26876c4d7f89d686ca130fdc53bced4814cd29f8" +dependencies = [ + "bitflags 2.13.1", +] + [[package]] name = "linux-raw-sys" -version = "0.4.15" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] name = "lock_api" @@ -501,11 +843,21 @@ checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "lru" -version = "0.12.5" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6180140927ee907000b0aa540091f6ea512ead4447c92b8fc35bc72788a5a6" +dependencies = [ + "hashbrown 0.17.1", +] + +[[package]] +name = "mac_address" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +checksum = "c0aeb26bf5e836cc1c341c8106051b573f1766dfa05aa87f0b98be5e51b02303" dependencies = [ - "hashbrown 0.15.5", + "nix", + "winapi", ] [[package]] @@ -523,6 +875,27 @@ version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" +[[package]] +name = "memmem" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64a92489e2744ce060c349162be1c5f33c6969234104dbd99ddb5feb08b8c15" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "mio" version = "1.2.2" @@ -532,7 +905,30 @@ dependencies = [ "libc", "log", "wasi", - "windows-sys 0.61.2", + "windows-sys", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.13.1", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", ] [[package]] @@ -541,99 +937,387 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", ] [[package]] -name = "once_cell" -version = "1.21.4" +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", +] + +[[package]] +name = "palette" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" +dependencies = [ + "approx", + "fast-srgb8", + "libm", + "palette_derive", +] + +[[package]] +name = "palette_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" +dependencies = [ + "by_address", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "pest" +version = "2.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df728be843c7070fab6ab7c328c4e9e9d78e23bf749c0669c86ee7ebfa050a2" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e2dd6fc3b26b3462ee188aac870f5a41d398f1cd5e2408d16531bd71c9591fd" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a7a9205cfb6f596a9e8b689c0a15f9ceb7a1aafae7aaf788150ac65b29975b6" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pest_meta" +version = "2.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85abd351c0de1e8384fc791a0737111a350394937e92b956b743dac12429f57c" +dependencies = [ + "pest", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "portable-atomic" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d20d5497ef88037a52ff98267d066e7f11fcc5e99bbfbd58a42336193aacec3" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" +dependencies = [ + "rand_core", +] [[package]] -name = "once_cell_polyfill" -version = "1.70.2" +name = "rand_core" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" [[package]] -name = "option-ext" -version = "0.2.0" +name = "ratatui" +version = "0.30.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +checksum = "3274ba0a2c5e1bcad2a2005d20f4dc59dad26b2eb0940fb094500dba4099d57d" +dependencies = [ + "instability", + "ratatui-core", + "ratatui-crossterm", + "ratatui-macros", + "ratatui-termina", + "ratatui-termwiz", + "ratatui-widgets", + "serde", +] [[package]] -name = "parking_lot" -version = "0.12.5" +name = "ratatui-core" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +checksum = "cbb175c433c8e28a809d1f5773a2ae96e68c0ce40db865cbab1020bf33ae479c" dependencies = [ - "lock_api", - "parking_lot_core", + "bitflags 2.13.1", + "compact_str", + "critical-section", + "hashbrown 0.17.1", + "itertools", + "kasuari", + "lru", + "palette", + "serde", + "strum", + "thiserror 2.0.19", + "unicode-segmentation", + "unicode-truncate", + "unicode-width", ] [[package]] -name = "parking_lot_core" -version = "0.9.12" +name = "ratatui-crossterm" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +checksum = "567584a3b0e6a8203c23de40b4861497266725eb5363dbfd18a1edd603cca9f0" dependencies = [ "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link", + "crossterm", + "instability", + "ratatui-core", ] [[package]] -name = "paste" -version = "1.0.15" +name = "ratatui-macros" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +checksum = "ed7dc68daa7498a43e4d68e0eb078427e10c38fbcfbb1e42d955f1fa2140d814" +dependencies = [ + "ratatui-core", + "ratatui-widgets", +] [[package]] -name = "pin-project-lite" -version = "0.2.17" +name = "ratatui-termina" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +checksum = "c0bf912d9e66f057a759d92e386a280ea886b352ab757d6ac4d653c7ed2c43c2" +dependencies = [ + "instability", + "ratatui-core", + "termina", +] [[package]] -name = "proc-macro2" -version = "1.0.107" +name = "ratatui-termwiz" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +checksum = "faf03e0380b7744054d6cb74224fe3adf062a029754933f575ca1e3b4c2ce977" dependencies = [ - "unicode-ident", + "ratatui-core", + "termwiz", ] [[package]] -name = "quote" -version = "1.0.47" +name = "ratatui-textarea" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +checksum = "3c78d5ba0f26f97baed69a4c479f268a31c7b5b89d68ab939842152e383d6e73" dependencies = [ - "proc-macro2", + "ratatui-core", + "ratatui-crossterm", + "ratatui-widgets", + "unicode-segmentation", + "unicode-width", ] [[package]] -name = "ratatui" -version = "0.29.0" +name = "ratatui-widgets" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" +checksum = "66e3d19bcc9130ca376277d93b60767ff121ace3be06f5f95f81dd68956407d1" dependencies = [ - "bitflags", - "cassowary", - "compact_str", - "crossterm", + "bitflags 2.13.1", + "hashbrown 0.17.1", "indoc", "instability", "itertools", - "lru", - "paste", + "line-clipping", + "ratatui-core", + "serde", "strum", + "time", "unicode-segmentation", - "unicode-truncate", - "unicode-width 0.2.0", + "unicode-width", ] [[package]] @@ -642,7 +1326,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags", + "bitflags 2.13.1", ] [[package]] @@ -651,7 +1335,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ - "getrandom", + "getrandom 0.2.17", "libredox", "thiserror 2.0.19", ] @@ -685,17 +1369,26 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" -version = "0.38.44" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags", + "bitflags 2.13.1", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys", ] [[package]] @@ -716,6 +1409,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + [[package]] name = "serde" version = "1.0.229" @@ -772,6 +1471,17 @@ dependencies = [ "unsafe-libyaml", ] +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -828,6 +1538,18 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + [[package]] name = "smallvec" version = "1.15.2" @@ -847,7 +1569,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -870,26 +1592,36 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.26.3" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.26.4" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" dependencies = [ "heck", "proc-macro2", "quote", - "rustversion", "syn 2.0.119", ] +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.119" @@ -912,6 +1644,82 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "termina" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9048a889effe34a5cddee0af7f53285198b16dca3be510858d38dfdb3e62a04e" +dependencies = [ + "bitflags 2.13.1", + "parking_lot", + "rustix", + "signal-hook", + "windows-sys", +] + +[[package]] +name = "terminfo" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4ea810f0692f9f51b382fff5893887bb4580f5fa246fde546e0b13e7fcee662" +dependencies = [ + "fnv", + "nom", + "phf", + "phf_codegen", +] + +[[package]] +name = "termios" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b" +dependencies = [ + "libc", +] + +[[package]] +name = "termwiz" +version = "0.23.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7" +dependencies = [ + "anyhow", + "base64", + "bitflags 2.13.1", + "fancy-regex", + "filedescriptor", + "finl_unicode", + "fixedbitset", + "hex", + "lazy_static", + "libc", + "log", + "memmem", + "nix", + "num-derive", + "num-traits", + "ordered-float", + "pest", + "pest_derive", + "phf", + "sha2", + "signal-hook", + "siphasher", + "terminfo", + "termios", + "thiserror 1.0.69", + "ucd-trie", + "unicode-segmentation", + "vtparse", + "wezterm-bidi", + "wezterm-blob-leases", + "wezterm-color-types", + "wezterm-dynamic", + "wezterm-input-types", + "winapi", +] + [[package]] name = "textwrap" version = "0.16.2" @@ -920,7 +1728,7 @@ checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" dependencies = [ "smawk", "unicode-linebreak", - "unicode-width 0.2.0", + "unicode-width", ] [[package]] @@ -972,6 +1780,27 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "time" +version = "0.3.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e1d5e639ff6bab73cb6885cc7e7b1de96c3f32c68ec55f3952614bec1092244" +dependencies = [ + "deranged", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde_core", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + [[package]] name = "tokio" version = "1.53.1" @@ -986,7 +1815,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -1204,15 +2033,16 @@ dependencies = [ ] [[package]] -name = "tui-textarea" -version = "0.7.0" +name = "typenum" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a5318dd619ed73c52a9417ad19046724effc1287fb75cdcc4eca1d6ac1acbae" -dependencies = [ - "crossterm", - "ratatui", - "unicode-width 0.2.0", -] +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "unicode-ident" @@ -1234,21 +2064,15 @@ checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-truncate" -version = "1.1.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" +checksum = "16b380a1238663e5f8a691f9039c73e1cdae598a30e9855f541d29b08b53e9a5" dependencies = [ "itertools", "unicode-segmentation", - "unicode-width 0.1.14", + "unicode-width", ] -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - [[package]] name = "unicode-width" version = "0.2.0" @@ -1267,12 +2091,39 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239" +dependencies = [ + "atomic", + "getrandom 0.4.3", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "valuable" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vtparse" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9b2acfb050df409c972a37d3b8e08cdea3bddb0c09db9d53137e504cfabed0" +dependencies = [ + "utf8parse", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -1280,114 +2131,173 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "winapi" -version = "0.3.9" +name = "wasip2" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "wit-bindgen", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "wasm-bindgen" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "wasm-bindgen-macro" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] [[package]] -name = "windows-link" -version = "0.2.1" +name = "wasm-bindgen-macro-support" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.119", + "wasm-bindgen-shared", +] [[package]] -name = "windows-sys" -version = "0.59.0" +name = "wasm-bindgen-shared" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" dependencies = [ - "windows-targets", + "unicode-ident", ] [[package]] -name = "windows-sys" -version = "0.61.2" +name = "wezterm-bidi" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +checksum = "0c0a6e355560527dd2d1cf7890652f4f09bb3433b6aadade4c9b5ed76de5f3ec" dependencies = [ - "windows-link", + "log", + "wezterm-dynamic", +] + +[[package]] +name = "wezterm-blob-leases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692daff6d93d94e29e4114544ef6d5c942a7ed998b37abdc19b17136ea428eb7" +dependencies = [ + "getrandom 0.3.4", + "mac_address", + "sha2", + "thiserror 1.0.69", + "uuid", +] + +[[package]] +name = "wezterm-color-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de81ef35c9010270d63772bebef2f2d6d1f2d20a983d27505ac850b8c4b4296" +dependencies = [ + "csscolorparser", + "deltae", + "lazy_static", + "wezterm-dynamic", ] [[package]] -name = "windows-targets" -version = "0.52.6" +name = "wezterm-dynamic" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "5f2ab60e120fd6eaa68d9567f3226e876684639d22a4219b313ff69ec0ccd5ac" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "log", + "ordered-float", + "strsim", + "thiserror 1.0.69", + "wezterm-dynamic-derive", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" +name = "wezterm-dynamic-derive" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +checksum = "46c0cf2d539c645b448eaffec9ec494b8b19bd5077d9e58cb1ae7efece8d575b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] [[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" +name = "wezterm-input-types" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +checksum = "7012add459f951456ec9d6c7e6fc340b1ce15d6fc9629f8c42853412c029e57e" +dependencies = [ + "bitflags 1.3.2", + "euclid", + "lazy_static", + "serde", + "wezterm-dynamic", +] [[package]] -name = "windows_i686_gnu" -version = "0.52.6" +name = "winapi" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] [[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] -name = "windows_i686_msvc" -version = "0.52.6" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] [[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" +name = "wit-bindgen" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "zmij" diff --git a/Cargo.toml b/Cargo.toml index 4f41050..5608c5a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,9 +10,9 @@ license = "MIT" [dependencies] anyhow = "1" clap = { version = "4", features = ["derive"] } -crossterm = { version = "0.28", features = ["event-stream"] } +crossterm = { version = "0.29", features = ["event-stream"] } dirs = "6" -ratatui = "0.29" +ratatui = "0.30.2" serde = { version = "1", features = ["derive"] } serde_yaml = "0.9" serde_json = "1" @@ -37,7 +37,7 @@ tree-sitter-css = "0.23" tree-sitter-html = "0.23" tree-sitter-md = "0.3" unicode-width = "0.2" -tui-textarea = { version = "0.7", features = ["crossterm"] } +tui-textarea = { package = "ratatui-textarea", version = "0.9.2", features = ["crossterm"] } textwrap = "0.16.2" [profile.release] diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 5d7e9cc..a94a41a 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -67,8 +67,9 @@ fn list_picker_visible_height(terminal_height: usize) -> usize { pub type Term = Terminal>; const EVENT_DRAIN_LIMIT: usize = 256; -const ESCAPE_CONTINUATION_TIMEOUT: Duration = Duration::from_millis(25); +const ESCAPE_CONTINUATION_TIMEOUT: Duration = Duration::from_millis(50); const MAX_ESCAPE_SEQUENCE_EVENTS: usize = 256; +const POPUP_KEY_TAIL_TIMEOUT: Duration = Duration::from_millis(50); const COMMIT_DETAILS_DEBOUNCE: Duration = Duration::from_millis(120); const MAX_CONCURRENT_DIFF_JOBS: usize = 2; const DIFF_PREVIEW_CACHE_ENTRIES: usize = 8; @@ -101,7 +102,71 @@ fn parse_kitty_modifiers(value: &str) -> KeyModifiers { modifiers } +fn parse_kitty_event_kind(value: &str) -> crossterm::event::KeyEventKind { + match value + .split(':') + .nth(1) + .and_then(|value| value.parse::().ok()) + { + Some(2) => crossterm::event::KeyEventKind::Repeat, + Some(3) => crossterm::event::KeyEventKind::Release, + _ => crossterm::event::KeyEventKind::Press, + } +} + +fn parse_sgr_mouse(sequence: &str) -> Option { + use crossterm::event::{MouseButton, MouseEventKind}; + + let sgr = sequence.strip_prefix("[<")?; + let final_byte = sgr.chars().last()?; + if !matches!(final_byte, 'M' | 'm') { + return None; + } + let body = &sgr[..sgr.len().saturating_sub(final_byte.len_utf8())]; + let mut values = body.trim_end_matches(';').split(';'); + let cb = values.next()?.parse::().ok()?; + let column = values.next()?.parse::().ok()?.checked_sub(1)?; + let row = values.next()?.parse::().ok()?.checked_sub(1)?; + + let button_number = (cb & 0b0000_0011) | ((cb & 0b1100_0000) >> 4); + let dragging = cb & 0b0010_0000 != 0; + let mut kind = match (button_number, dragging) { + (0, false) => MouseEventKind::Down(MouseButton::Left), + (1, false) => MouseEventKind::Down(MouseButton::Middle), + (2, false) => MouseEventKind::Down(MouseButton::Right), + (0, true) => MouseEventKind::Drag(MouseButton::Left), + (1, true) => MouseEventKind::Drag(MouseButton::Middle), + (2, true) => MouseEventKind::Drag(MouseButton::Right), + (3, false) => MouseEventKind::Up(MouseButton::Left), + (3..=5, true) => MouseEventKind::Moved, + (4, false) => MouseEventKind::ScrollUp, + (5, false) => MouseEventKind::ScrollDown, + (6, false) => MouseEventKind::ScrollLeft, + (7, false) => MouseEventKind::ScrollRight, + _ => return None, + }; + if final_byte == 'm' + && let MouseEventKind::Down(button) = kind + { + kind = MouseEventKind::Up(button); + } + + let mut modifiers = KeyModifiers::NONE; + modifiers.set(KeyModifiers::SHIFT, cb & 0b0000_0100 != 0); + modifiers.set(KeyModifiers::ALT, cb & 0b0000_1000 != 0); + modifiers.set(KeyModifiers::CONTROL, cb & 0b0001_0000 != 0); + Some(Event::Mouse(MouseEvent { + kind, + column, + row, + modifiers, + })) +} + fn parse_fragmented_escape_sequence(sequence: &str) -> Option { + if sequence.starts_with("[<") { + return parse_sgr_mouse(sequence); + } if let Some(csi) = sequence.strip_prefix('[') { let final_byte = csi.chars().last()?; let body = &csi[..csi.len().saturating_sub(final_byte.len_utf8())]; @@ -120,12 +185,13 @@ fn parse_fragmented_escape_sequence(sequence: &str) -> Option { } } - let modifiers = body - .rsplit(';') - .next() - .filter(|_| body.contains(';')) + let modifier_field = body.split(';').nth(1); + let modifiers = modifier_field .map(parse_kitty_modifiers) .unwrap_or(KeyModifiers::NONE); + let kind = modifier_field + .map(parse_kitty_event_kind) + .unwrap_or(crossterm::event::KeyEventKind::Press); let code = match final_byte { 'A' => KeyCode::Up, 'B' => KeyCode::Down, @@ -154,7 +220,7 @@ fn parse_fragmented_escape_sequence(sequence: &str) -> Option { }, _ => return None, }; - return Some(Event::Key(KeyEvent::new(code, modifiers))); + return Some(Event::Key(KeyEvent::new_with_kind(code, modifiers, kind))); } let code = match sequence { @@ -235,6 +301,120 @@ fn read_terminal_events() -> io::Result> { Ok(Vec::new()) } +#[derive(Debug)] +struct QueuedTerminalEvent { + event: Event, + repetitions: usize, +} + +fn coalescible_mouse_kind(kind: crossterm::event::MouseEventKind) -> bool { + use crossterm::event::{MouseButton, MouseEventKind}; + + matches!( + kind, + MouseEventKind::Moved + | MouseEventKind::Drag(MouseButton::Left) + | MouseEventKind::Drag(MouseButton::Middle) + | MouseEventKind::Drag(MouseButton::Right) + | MouseEventKind::ScrollDown + | MouseEventKind::ScrollUp + | MouseEventKind::ScrollLeft + | MouseEventKind::ScrollRight + ) +} + +fn push_coalesced_terminal_event(queue: &mut VecDeque, event: Event) { + if let Event::Mouse(mouse) = event { + if coalescible_mouse_kind(mouse.kind) + && let Some(QueuedTerminalEvent { + event: Event::Mouse(previous), + repetitions, + }) = queue.back_mut() + && previous.kind == mouse.kind + && previous.modifiers == mouse.modifiers + { + *previous = mouse; + if matches!( + mouse.kind, + crossterm::event::MouseEventKind::ScrollDown + | crossterm::event::MouseEventKind::ScrollUp + | crossterm::event::MouseEventKind::ScrollLeft + | crossterm::event::MouseEventKind::ScrollRight + ) { + *repetitions = repetitions.saturating_add(1); + } + return; + } + + queue.push_back(QueuedTerminalEvent { + event: Event::Mouse(mouse), + repetitions: 1, + }); + return; + } + + queue.push_back(QueuedTerminalEvent { + event, + repetitions: 1, + }); +} + +fn read_terminal_event_batch() -> io::Result> { + let mut queue = VecDeque::new(); + for _ in 0..EVENT_DRAIN_LIMIT { + for event in read_terminal_events()? { + push_coalesced_terminal_event(&mut queue, event); + } + if !event::poll(Duration::ZERO)? { + break; + } + } + Ok(queue) +} + +fn should_dispatch_key(kind: crossterm::event::KeyEventKind) -> bool { + matches!( + kind, + crossterm::event::KeyEventKind::Press | crossterm::event::KeyEventKind::Repeat + ) +} + +#[derive(Debug, Clone, Copy)] +struct PopupKeyTail { + key: KeyEvent, + expires_at: Instant, +} + +fn suppress_popup_key_tail(tail: &mut Option, key: KeyEvent, now: Instant) -> bool { + let Some(blocked) = *tail else { + return false; + }; + if now > blocked.expires_at { + *tail = None; + return false; + } + + let same_key = key.code == blocked.key.code && key.modifiers == blocked.key.modifiers; + if !same_key { + if key.kind != crossterm::event::KeyEventKind::Release { + *tail = None; + } + return false; + } + + match key.kind { + crossterm::event::KeyEventKind::Repeat => true, + crossterm::event::KeyEventKind::Release => { + *tail = None; + true + } + crossterm::event::KeyEventKind::Press => { + *tail = None; + false + } + } +} + fn has_command_modifier(modifiers: KeyModifiers) -> bool { modifiers.intersects(KeyModifiers::SUPER | KeyModifiers::META) } @@ -889,6 +1069,9 @@ impl Gui { } fn main_loop(&mut self, terminal: &mut Term) -> Result<()> { + let mut terminal_focused = true; + let mut popup_key_tail = None; + loop { // Drain any model parts that have arrived from the background load. if let Some(rx) = &self.initial_load_rx { @@ -1154,14 +1337,44 @@ impl Gui { // Handle events if event::poll(std::time::Duration::from_millis(16))? { - for terminal_event in read_terminal_events()? { + let mut terminal_events = read_terminal_event_batch()?; + // Ghostty may enqueue the character component of a macOS tab + // shortcut immediately before its FocusLost report. Quarantine + // that transition batch, but resume normally after FocusGained. + let mut focus_transition_pending = terminal_events + .iter() + .find_map(|queued| match queued.event { + Event::FocusGained => Some(false), + Event::FocusLost => Some(true), + _ => None, + }) + .unwrap_or(false); + while let Some(QueuedTerminalEvent { + event: terminal_event, + repetitions, + }) = terminal_events.pop_front() + { + let popup_was_open = self.popup != PopupState::None; + let dispatched_key = match &terminal_event { + Event::Key(key) => Some(*key), + _ => None, + }; match terminal_event { - Event::Key(key) if key.kind == crossterm::event::KeyEventKind::Press => { - if let Err(err) = self.handle_key(key) { + Event::Key(key) if terminal_focused && !focus_transition_pending => { + let suppressed = + suppress_popup_key_tail(&mut popup_key_tail, key, Instant::now()); + if should_dispatch_key(key.kind) + && !suppressed + && let Err(err) = self.handle_key(key) + { self.show_error("Command failed", err); } } - Event::Mouse(mouse) => self.handle_mouse(mouse), + Event::Mouse(mouse) if terminal_focused && !focus_transition_pending => { + for _ in 0..repetitions { + self.handle_mouse(mouse); + } + } Event::Resize(w, h) => { self.layout.update_size(w, h); // Re-flow any active commit-message textarea to the new width so @@ -1210,14 +1423,33 @@ impl Gui { _ => {} } } - Event::FocusGained if self.config.user_config.git.auto_refresh => { - self.needs_refresh = true; + Event::FocusGained => { + terminal_focused = true; + focus_transition_pending = false; + if self.config.user_config.git.auto_refresh { + self.needs_refresh = true; + } + } + Event::FocusLost => { + terminal_focused = false; + focus_transition_pending = false; } - Event::Paste(data) => { + Event::Paste(data) if terminal_focused && !focus_transition_pending => { self.handle_paste(data); } _ => {} } + + let popup_is_open = self.popup != PopupState::None; + if popup_was_open + && !popup_is_open + && let Some(key) = dispatched_key + { + popup_key_tail = Some(PopupKeyTail { + key, + expires_at: Instant::now() + POPUP_KEY_TAIL_TIMEOUT, + }); + } } } @@ -5916,7 +6148,7 @@ impl Gui { } = &mut self.popup { body_textarea.scroll((rows, 0)); - let (row, col) = body_textarea.cursor(); + let tui_textarea::DataCursor(row, col) = body_textarea.cursor(); body_state.set_cursor_from_visual(row, col, wrap_width); } return; @@ -7524,7 +7756,7 @@ fn soft_wrap_textarea(textarea: &mut tui_textarea::TextArea<'static>, wrap_width } // Track absolute char offset of cursor so we can restore it after rewrap. - let (cursor_row, cursor_col) = textarea.cursor(); + let tui_textarea::DataCursor(cursor_row, cursor_col) = textarea.cursor(); let mut cursor_abs = 0usize; for (i, line) in textarea.lines().iter().enumerate() { let line_chars = line.chars().count(); @@ -7574,7 +7806,7 @@ fn auto_wrap_textarea(textarea: &mut tui_textarea::TextArea<'static>, wrap_width } // Compute cursor's absolute char offset in the original text - let (cursor_row, cursor_col) = textarea.cursor(); + let tui_textarea::DataCursor(cursor_row, cursor_col) = textarea.cursor(); let original_lines: Vec = textarea.lines().iter().map(|s| s.to_string()).collect(); let mut cursor_abs = 0usize; @@ -7674,13 +7906,14 @@ fn rect_contains(r: ratatui::layout::Rect, col: u16, row: u16) -> bool { fn keyboard_enhancement_flags() -> crossterm::event::KeyboardEnhancementFlags { // Keep printable input on the terminal's normal text path. In particular, // REPORT_ALL_KEYS_AS_ESCAPE_CODES replaces produced text with a logical key - // identity. Crossterm 0.28 does not expose the protocol's associated-text + // identity. Crossterm does not expose the protocol's associated-text // field, so keyboard layouts, IMEs, or remappers can otherwise turn a typed // character into a different shortcut (for example, `q` into `u`). // - // REPORT_EVENT_TYPES is also unnecessary: the UI handles press events only, - // and enabling it would turn key auto-repeat into ignored Repeat events. + // Event types let us explicitly accept Press and Repeat while rejecting + // Release, preventing a released key from acting on a newly opened view. crossterm::event::KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES + | crossterm::event::KeyboardEnhancementFlags::REPORT_EVENT_TYPES } /// Enables button, drag, and scroll events without passive pointer-motion events. @@ -7715,16 +7948,195 @@ mod terminal_mouse_tests { fn keyboard_enhancement_preserves_terminal_text_input() { let flags = keyboard_enhancement_flags(); - assert_eq!( - flags, - crossterm::event::KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES + assert!( + flags.contains(crossterm::event::KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES) ); + assert!(flags.contains(crossterm::event::KeyboardEnhancementFlags::REPORT_EVENT_TYPES)); assert!( !flags.contains( crossterm::event::KeyboardEnhancementFlags::REPORT_ALL_KEYS_AS_ESCAPE_CODES ) ); - assert!(!flags.contains(crossterm::event::KeyboardEnhancementFlags::REPORT_EVENT_TYPES)); + } + + #[test] + fn reconstructed_kitty_keys_preserve_repeat_and_release_kinds() { + assert_eq!( + parse_fragmented_escape_sequence("[49;9:2u"), + Some(Event::Key(KeyEvent::new_with_kind( + KeyCode::Char('1'), + KeyModifiers::SUPER, + crossterm::event::KeyEventKind::Repeat, + ))) + ); + assert_eq!( + parse_fragmented_escape_sequence("[49;9:3u"), + Some(Event::Key(KeyEvent::new_with_kind( + KeyCode::Char('1'), + KeyModifiers::SUPER, + crossterm::event::KeyEventKind::Release, + ))) + ); + } + + #[test] + fn reconstructs_fragmented_sgr_mouse_events() { + use crossterm::event::{MouseButton, MouseEventKind}; + + assert_eq!( + parse_fragmented_escape_sequence("[<0;20;10M"), + Some(Event::Mouse(MouseEvent { + kind: MouseEventKind::Down(MouseButton::Left), + column: 19, + row: 9, + modifiers: KeyModifiers::NONE, + })) + ); + assert_eq!( + parse_fragmented_escape_sequence("[<0;20;10m"), + Some(Event::Mouse(MouseEvent { + kind: MouseEventKind::Up(MouseButton::Left), + column: 19, + row: 9, + modifiers: KeyModifiers::NONE, + })) + ); + } + + #[test] + fn dispatches_key_presses_and_repeats_but_not_releases() { + assert!(should_dispatch_key(crossterm::event::KeyEventKind::Press)); + assert!(should_dispatch_key(crossterm::event::KeyEventKind::Repeat)); + assert!(!should_dispatch_key( + crossterm::event::KeyEventKind::Release + )); + } + + #[test] + fn coalesces_mouse_motion_without_dropping_button_boundaries() { + use crossterm::event::{MouseButton, MouseEventKind}; + + let mouse = |kind, column| { + Event::Mouse(MouseEvent { + kind, + column, + row: 4, + modifiers: KeyModifiers::NONE, + }) + }; + let mut queue = VecDeque::new(); + push_coalesced_terminal_event( + &mut queue, + mouse(MouseEventKind::Down(MouseButton::Left), 1), + ); + push_coalesced_terminal_event( + &mut queue, + mouse(MouseEventKind::Drag(MouseButton::Left), 2), + ); + push_coalesced_terminal_event( + &mut queue, + mouse(MouseEventKind::Drag(MouseButton::Left), 8), + ); + push_coalesced_terminal_event(&mut queue, mouse(MouseEventKind::Up(MouseButton::Left), 8)); + + assert_eq!(queue.len(), 3); + assert!(matches!( + queue[0].event, + Event::Mouse(MouseEvent { + kind: MouseEventKind::Down(MouseButton::Left), + .. + }) + )); + assert!(matches!( + queue[1].event, + Event::Mouse(MouseEvent { + kind: MouseEventKind::Drag(MouseButton::Left), + column: 8, + .. + }) + )); + assert!(matches!( + queue[2].event, + Event::Mouse(MouseEvent { + kind: MouseEventKind::Up(MouseButton::Left), + .. + }) + )); + } + + #[test] + fn coalesces_adjacent_scrolls_but_not_across_key_events() { + use crossterm::event::MouseEventKind; + + let scroll = Event::Mouse(MouseEvent { + kind: MouseEventKind::ScrollDown, + column: 3, + row: 4, + modifiers: KeyModifiers::NONE, + }); + let mut queue = VecDeque::new(); + push_coalesced_terminal_event(&mut queue, scroll.clone()); + push_coalesced_terminal_event(&mut queue, scroll.clone()); + push_coalesced_terminal_event( + &mut queue, + Event::Key(KeyEvent::new(KeyCode::Char('x'), KeyModifiers::NONE)), + ); + push_coalesced_terminal_event(&mut queue, scroll); + + assert_eq!(queue.len(), 3); + assert_eq!(queue[0].repetitions, 2); + assert_eq!(queue[1].repetitions, 1); + assert_eq!(queue[2].repetitions, 1); + } + + #[test] + fn popup_close_suppresses_only_the_closing_keys_tail() { + let now = Instant::now(); + let closing_key = KeyEvent::new_with_kind( + KeyCode::Enter, + KeyModifiers::NONE, + crossterm::event::KeyEventKind::Press, + ); + let mut tail = Some(PopupKeyTail { + key: closing_key, + expires_at: now + POPUP_KEY_TAIL_TIMEOUT, + }); + + assert!(suppress_popup_key_tail( + &mut tail, + KeyEvent::new_with_kind( + KeyCode::Enter, + KeyModifiers::NONE, + crossterm::event::KeyEventKind::Repeat, + ), + now, + )); + assert!(!suppress_popup_key_tail( + &mut tail, + KeyEvent::new(KeyCode::Char('j'), KeyModifiers::NONE), + now, + )); + assert!(tail.is_none()); + } + + #[test] + fn popup_close_release_clears_the_tail() { + let now = Instant::now(); + let mut tail = Some(PopupKeyTail { + key: KeyEvent::new(KeyCode::Esc, KeyModifiers::NONE), + expires_at: now + POPUP_KEY_TAIL_TIMEOUT, + }); + + assert!(suppress_popup_key_tail( + &mut tail, + KeyEvent::new_with_kind( + KeyCode::Esc, + KeyModifiers::NONE, + crossterm::event::KeyEventKind::Release, + ), + now, + )); + assert!(tail.is_none()); } #[test] @@ -7882,21 +8294,28 @@ mod terminal_mouse_tests { fn setup_terminal() -> Result<(Term, bool)> { terminal::enable_raw_mode()?; let mut stdout = io::stdout(); + // The capability probe reads terminal responses. Run it before enabling + // focus and mouse reporting so their control sequences cannot interleave + // with the probe response. + let keyboard_enhanced = crossterm::terminal::supports_keyboard_enhancement().unwrap_or(false); + execute!( stdout, EnterAlternateScreen, - EnableMouseCaptureWithoutHover, - crossterm::event::EnableFocusChange, crossterm::event::EnableBracketedPaste, cursor::Hide )?; - let keyboard_enhanced = crossterm::terminal::supports_keyboard_enhancement().unwrap_or(false); if keyboard_enhanced { execute!( stdout, crossterm::event::PushKeyboardEnhancementFlags(keyboard_enhancement_flags()) )?; } + execute!( + stdout, + EnableMouseCaptureWithoutHover, + crossterm::event::EnableFocusChange + )?; let backend = CrosstermBackend::new(stdout); let terminal = Terminal::new(backend)?; Ok((terminal, keyboard_enhanced))