Unnamed repository; edit this file 'description' to name the repository.
137 files changed, 3120 insertions, 5480 deletions
diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d972953e..0e460ebe 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,14 +12,6 @@ updates: update-types: - "minor" - "patch" - ignore: - # MSRV: these deps use edition 2024 in their newest versions. - # Once the MSRV reaches 1.85 these can be updated and unignored. - - dependency-name: ignore - - dependency-name: globset - - dependency-name: grep-matcher - # Now requires Rust 1.87: - - dependency-name: etcetera - package-ecosystem: "github-actions" directory: "/" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7331a2dc..4020e505 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,7 +36,7 @@ jobs: - name: Bundle grammars run: tar cJf grammars.tar.xz -C runtime/grammars/sources . - - uses: actions/upload-artifact@v5 + - uses: actions/upload-artifact@v4 with: name: grammars path: grammars.tar.xz @@ -107,7 +107,7 @@ jobs: uses: actions/checkout@v5 - name: Download grammars - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v5 - name: Move grammars under runtime if: "!startsWith(matrix.os, 'windows')" @@ -224,7 +224,7 @@ jobs: fi cp -r runtime dist - - uses: actions/upload-artifact@v5 + - uses: actions/upload-artifact@v4 with: name: bins-${{ matrix.build }} path: dist @@ -237,7 +237,7 @@ jobs: - name: Checkout sources uses: actions/checkout@v5 - - uses: actions/download-artifact@v6 + - uses: actions/download-artifact@v5 - name: Build archive shell: bash @@ -294,7 +294,7 @@ jobs: overwrite: true - name: Upload binaries as artifact - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v4 if: env.preview == 'true' with: name: release @@ -3,19 +3,27 @@ version = 3 [[package]] -name = "ahash" -version = "0.8.12" +name = "addr2line" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ - "cfg-if", - "getrandom 0.3.1", - "once_cell", - "version_check", - "zerocopy", + "gimli", ] [[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -41,9 +49,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "arc-swap" @@ -58,10 +66,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide 0.7.4", + "object", + "rustc-demangle", +] + +[[package]] name = "bitflags" -version = "2.10.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "block-buffer" @@ -85,9 +108,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" @@ -97,9 +120,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cassowary" @@ -109,9 +132,9 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] name = "cc" -version = "1.2.43" +version = "1.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" +checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" dependencies = [ "find-msvc-tools", "shlex", @@ -186,9 +209,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.5.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -219,32 +242,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] -name = "crossterm" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" -dependencies = [ - "bitflags", - "crossterm_winapi", - "futures-core", - "mio", - "parking_lot", - "rustix 0.38.44", - "signal-hook", - "signal-hook-mio", - "winapi", -] - -[[package]] -name = "crossterm_winapi" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" -dependencies = [ - "winapi", -] - -[[package]] name = "crypto-common" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -269,12 +266,6 @@ dependencies = [ ] [[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - -[[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -381,18 +372,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] -name = "faststr" -version = "0.2.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baec6a0289d7f1fe5665586ef7340af82e3037207bef60f5785e57569776f0c8" -dependencies = [ - "bytes", - "rkyv", - "serde", - "simdutf8", -] - -[[package]] name = "fern" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -415,9 +394,20 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.4" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" +checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" + +[[package]] +name = "flate2" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +dependencies = [ + "crc32fast", + "libz-rs-sys", + "miniz_oxide 0.8.7", +] [[package]] name = "fnv" @@ -516,10 +506,16 @@ dependencies = [ ] [[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] name = "gix" -version = "0.74.1" +version = "0.73.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd3a6fea165debe0e80648495f894aa2371a771e3ceb7a7dcc304f1c4344c43" +checksum = "514c29cc879bdc0286b0cbc205585a49b252809eb86c69df4ce4f855ee75f635" dependencies = [ "gix-actor", "gix-attributes", @@ -560,15 +556,16 @@ dependencies = [ "gix-utils", "gix-validate", "gix-worktree", + "once_cell", "smallvec", "thiserror", ] [[package]] name = "gix-actor" -version = "0.35.6" +version = "0.35.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "987a51a7e66db6ef4dc030418eb2a42af6b913a79edd8670766122d8af3ba59e" +checksum = "58ebbb8f41071c7cf318a0b1db667c34e1df49db7bf387d282a4e61a3b97882c" dependencies = [ "bstr", "gix-date", @@ -580,9 +577,9 @@ dependencies = [ [[package]] name = "gix-attributes" -version = "0.28.1" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6591add69314fc43db078076a8da6f07957c65abb0b21c3e1b6a3cf50aa18d" +checksum = "45442188216d08a5959af195f659cb1f244a50d7d2d0c3873633b1cd7135f638" dependencies = [ "bstr", "gix-glob", @@ -597,27 +594,27 @@ dependencies = [ [[package]] name = "gix-bitmap" -version = "0.2.15" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e150161b8a75b5860521cb876b506879a3376d3adc857ec7a9d35e7c6a5e531" +checksum = "b1db9765c69502650da68f0804e3dc2b5f8ccc6a2d104ca6c85bc40700d37540" dependencies = [ "thiserror", ] [[package]] name = "gix-chunk" -version = "0.4.12" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c356b3825677cb6ff579551bb8311a81821e184453cbd105e2fc5311b288eeb" +checksum = "0b1f1d8764958699dc764e3f727cef280ff4d1bd92c107bbf8acd85b30c1bd6f" dependencies = [ "thiserror", ] [[package]] name = "gix-command" -version = "0.6.3" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "095c8367c9dc4872a7706fbc39c7f34271b88b541120a4365ff0e36366f66e62" +checksum = "6b31b65ca48a352ae86312b27a514a0c661935f96b481ac8b4371f65815eb196" dependencies = [ "bstr", "gix-path", @@ -628,9 +625,9 @@ dependencies = [ [[package]] name = "gix-commitgraph" -version = "0.30.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826994ff6c01f1ff00d6a1844d7506717810a91ffed143da71e3bf39369751ef" +checksum = "6bb23121e952f43a5b07e3e80890336cb847297467a410475036242732980d06" dependencies = [ "bstr", "gix-chunk", @@ -641,9 +638,9 @@ dependencies = [ [[package]] name = "gix-config" -version = "0.47.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e74f57ea99025de9207db53488be4d59cf2000f617964c1b550880524fefbc3" +checksum = "5dfb898c5b695fd4acfc3c0ab638525a65545d47706064dcf7b5ead6cdb136c0" dependencies = [ "bstr", "gix-config-value", @@ -653,6 +650,7 @@ dependencies = [ "gix-ref", "gix-sec", "memchr", + "once_cell", "smallvec", "thiserror", "unicode-bom", @@ -661,9 +659,9 @@ dependencies = [ [[package]] name = "gix-config-value" -version = "0.15.3" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c489abb061c74b0c3ad790e24a606ef968cebab48ec673d6a891ece7d5aef64" +checksum = "9f012703eb67e263c6c1fc96649fec47694dd3e5d2a91abfc65e4a6a6dc85309" dependencies = [ "bitflags", "bstr", @@ -674,9 +672,9 @@ dependencies = [ [[package]] name = "gix-date" -version = "0.10.7" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "661245d045aa7c16ba4244daaabd823c562c3e45f1f25b816be2c57ee09f2171" +checksum = "d7235bdf4d9d54a6901928e3a37f91c16f419e6957f520ed929c3d292b84226e" dependencies = [ "bstr", "itoa", @@ -687,9 +685,9 @@ dependencies = [ [[package]] name = "gix-diff" -version = "0.54.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd78d9da421baca219a650d71c797706117095635d7963f21bb6fdf2410abe04" +checksum = "de854852010d44a317f30c92d67a983e691c9478c8a3fb4117c1f48626bcdea8" dependencies = [ "bstr", "gix-attributes", @@ -711,9 +709,9 @@ dependencies = [ [[package]] name = "gix-dir" -version = "0.16.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f99fb4dcba076453d791949bf3af977c5678a1cbd76740ec2cfe37e29431daf3" +checksum = "dad34e4f373f94902df1ba1d2a1df3a1b29eacd15e316ac5972d842e31422dd7" dependencies = [ "bstr", "gix-discover", @@ -731,9 +729,9 @@ dependencies = [ [[package]] name = "gix-discover" -version = "0.42.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d24547153810634636471af88338240e6ab0831308cd41eb6ebfffea77811c6" +checksum = "ffb180c91ca1a2cf53e828bb63d8d8f8fa7526f49b83b33d7f46cbeb5d79d30a" dependencies = [ "bstr", "dunce", @@ -747,16 +745,16 @@ dependencies = [ [[package]] name = "gix-features" -version = "0.44.1" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfa64593d1586135102307fb57fb3a9d3868b6b1f45a4da1352cce5070f8916a" +checksum = "9a92748623c201568785ee69a561f4eec06f745b4fac67dab1d44ca9891a57ee" dependencies = [ "crc32fast", + "flate2", "gix-path", "gix-trace", "gix-utils", "libc", - "libz-rs-sys", "once_cell", "prodash", "thiserror", @@ -765,9 +763,9 @@ dependencies = [ [[package]] name = "gix-filter" -version = "0.21.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1253452c9808da01eaaf9b1c4929b9982efec29ef0a668b3326b8046d9b8fb" +checksum = "aa6571a3927e7ab10f64279a088e0dae08e8da05547771796d7389bbe28ad9ff" dependencies = [ "bstr", "encoding_rs", @@ -786,9 +784,9 @@ dependencies = [ [[package]] name = "gix-fs" -version = "0.17.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f1ecd896258cdc5ccd94d18386d17906b8de265ad2ecf68e3bea6b007f6a28f" +checksum = "d793f71e955d18f228d20ec433dcce6d0e8577efcdfd11d72d09d7cc2758dfd1" dependencies = [ "bstr", "fastrand", @@ -800,9 +798,9 @@ dependencies = [ [[package]] name = "gix-glob" -version = "0.22.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74254992150b0a88fdb3ad47635ab649512dff2cbbefca7916bb459894fc9d56" +checksum = "b947db8366823e7a750c254f6bb29e27e17f27e457bf336ba79b32423db62cd5" dependencies = [ "bitflags", "bstr", @@ -812,9 +810,9 @@ dependencies = [ [[package]] name = "gix-hash" -version = "0.20.1" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826036a9bee95945b0be1e2394c64cd4289916c34a639818f8fd5153906985c1" +checksum = "251fad79796a731a2a7664d9ea95ee29a9e99474de2769e152238d4fdb69d50e" dependencies = [ "faster-hex", "gix-features", @@ -824,20 +822,20 @@ dependencies = [ [[package]] name = "gix-hashtable" -version = "0.10.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27d4a3ea9640da504a2657fef3419c517fd71f1767ad8935298bcc805edd195" +checksum = "c35300b54896153e55d53f4180460931ccd69b7e8d2f6b9d6401122cdedc4f07" dependencies = [ "gix-hash", - "hashbrown 0.16.0", + "hashbrown 0.15.5", "parking_lot", ] [[package]] name = "gix-ignore" -version = "0.17.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93b6a9679a1488123b7f2929684bacfd9cd2a24f286b52203b8752cbb8d7fc49" +checksum = "564d6fddf46e2c981f571b23d6ad40cb08bddcaf6fc7458b1d49727ad23c2870" dependencies = [ "bstr", "gix-glob", @@ -848,9 +846,9 @@ dependencies = [ [[package]] name = "gix-index" -version = "0.42.1" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31244542fb98ea4f3e964a4f8deafc2f4c77ad42bed58a1e8424bca1965fae99" +checksum = "2af39fde3ce4ce11371d9ce826f2936ec347318f2d1972fe98c2e7134e267e25" dependencies = [ "bitflags", "bstr", @@ -865,20 +863,20 @@ dependencies = [ "gix-traverse", "gix-utils", "gix-validate", - "hashbrown 0.16.0", + "hashbrown 0.15.5", "itoa", "libc", "memmap2", - "rustix 1.1.2", + "rustix", "smallvec", "thiserror", ] [[package]] name = "gix-lock" -version = "19.0.0" +version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "729d7857429a66023bc0c29d60fa21d0d6ae8862f33c1937ba89e0f74dd5c67f" +checksum = "b9fa71da90365668a621e184eb5b979904471af1b3b09b943a84bc50e8ad42ed" dependencies = [ "gix-tempfile", "gix-utils", @@ -887,9 +885,9 @@ dependencies = [ [[package]] name = "gix-object" -version = "0.51.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba1815638759c80d2318c8e98296fb396f577c2e588a3d9c13f9a5d5184051" +checksum = "49664e3e212bc34f7060f5738ce7022247e4afd959b68a4f666b1fd29c00b23c" dependencies = [ "bstr", "gix-actor", @@ -908,9 +906,9 @@ dependencies = [ [[package]] name = "gix-odb" -version = "0.71.1" +version = "0.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6efc6736d3ea62640efe8c1be695fb0760af63614a7356d2091208a841f1a634" +checksum = "9c9d7af10fda9df0bb4f7f9bd507963560b3c66cb15a5b825caf752e0eb109ac" dependencies = [ "arc-swap", "gix-date", @@ -929,9 +927,9 @@ dependencies = [ [[package]] name = "gix-pack" -version = "0.61.1" +version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719c60524be76874f4769da20d525ad2c00a0e7059943cc4f31fcb65cfb6b260" +checksum = "d8571df89bfca5abb49c3e3372393f7af7e6f8b8dbe2b96303593cef5b263019" dependencies = [ "clru", "gix-chunk", @@ -947,9 +945,9 @@ dependencies = [ [[package]] name = "gix-packetline" -version = "0.19.3" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64286a8b5148e76ab80932e72762dd27ccf6169dd7a134b027c8a262a8262fcf" +checksum = "2592fbd36249a2fea11056f7055cc376301ef38d903d157de41998335bbf1f93" dependencies = [ "bstr", "faster-hex", @@ -959,9 +957,9 @@ dependencies = [ [[package]] name = "gix-packetline-blocking" -version = "0.19.3" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89c59c3ad41e68cb38547d849e9ef5ccfc0d00f282244ba1441ae856be54d001" +checksum = "fc4e706f328cd494cc8f932172e123a72b9a4711b0db5e411681432a89bd4c94" dependencies = [ "bstr", "faster-hex", @@ -971,22 +969,23 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.10.21" +version = "0.10.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0416b41cd00ff292af9b94b0660880c44bd2ed66828ddca9a2b333535cbb71b8" +checksum = "c6279d323d925ad4790602105ae27df4b915e7a7d81e4cdba2603121c03ad111" dependencies = [ "bstr", "gix-trace", "gix-validate", "home", + "once_cell", "thiserror", ] [[package]] name = "gix-pathspec" -version = "0.13.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e28457dca7c65a2dbe118869aab922a5bd382b7bb10cff5354f366845c128" +checksum = "daedead611c9bd1f3640dc90a9012b45f790201788af4d659f28d94071da7fba" dependencies = [ "bitflags", "bstr", @@ -999,9 +998,9 @@ dependencies = [ [[package]] name = "gix-protocol" -version = "0.52.1" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64f19873bbf924fd077580d4ccaaaeddb67c3b3c09a8ffb61e6b4cb67e3c9302" +checksum = "12b4b807c47ffcf7c1e5b8119585368a56449f3493da93b931e1d4239364e922" dependencies = [ "bstr", "gix-date", @@ -1018,9 +1017,9 @@ dependencies = [ [[package]] name = "gix-quote" -version = "0.6.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e912ec04b7b1566a85ad486db0cab6b9955e3e32bcd3c3a734542ab3af084c5b" +checksum = "4a375a75b4d663e8bafe3bf4940a18a23755644c13582fa326e99f8f987d83fd" dependencies = [ "bstr", "gix-utils", @@ -1029,9 +1028,9 @@ dependencies = [ [[package]] name = "gix-ref" -version = "0.54.1" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8881d262f28eda39c244e60ae968f4f6e56c747f65addd6f4100b25f75ed8b88" +checksum = "4b7a23209d4e4cbdc2086d294f5f3f8707ac6286768847024d952d8cd3278c5b" dependencies = [ "gix-actor", "gix-features", @@ -1050,9 +1049,9 @@ dependencies = [ [[package]] name = "gix-refspec" -version = "0.32.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93147960f77695ba89b72019b789679278dd4dad6a0f9a4a5bf2fd07aba56912" +checksum = "7d29cae1ae31108826e7156a5e60bffacab405f4413f5bc0375e19772cce0055" dependencies = [ "bstr", "gix-hash", @@ -1064,9 +1063,9 @@ dependencies = [ [[package]] name = "gix-revision" -version = "0.36.1" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c5267e530d8762842be7d51b48d2b134c9dec5b650ca607f735a56a4b12413" +checksum = "f651f2b1742f760bb8161d6743229206e962b73d9c33c41f4e4aefa6586cbd3d" dependencies = [ "bstr", "gix-commitgraph", @@ -1079,9 +1078,9 @@ dependencies = [ [[package]] name = "gix-revwalk" -version = "0.22.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2de4f91d712b1f6873477f769225fe430ffce2af8c7c85721c3ff955783b3" +checksum = "06e74f91709729e099af6721bd0fa7d62f243f2005085152301ca5cdd86ec02c" dependencies = [ "gix-commitgraph", "gix-date", @@ -1094,21 +1093,21 @@ dependencies = [ [[package]] name = "gix-sec" -version = "0.12.2" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea9962ed6d9114f7f100efe038752f41283c225bb507a2888903ac593dffa6be" +checksum = "09f7053ed7c66633b56c57bc6ed3377be3166eaf3dc2df9f1c5ec446df6fdf2c" dependencies = [ "bitflags", "gix-path", "libc", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] name = "gix-shallow" -version = "0.6.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2374692db1ee1ffa0eddcb9e86ec218f7c4cdceda800ebc5a9fdf73a8c08223" +checksum = "d936745103243ae4c510f19e0760ce73fb0f08096588fdbe0f0d7fb7ce8944b7" dependencies = [ "bstr", "gix-hash", @@ -1118,9 +1117,9 @@ dependencies = [ [[package]] name = "gix-status" -version = "0.21.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c64039358f66c955a471432aef0ea1eeebc7afe0e0a4be7b6b737cc19925e3b" +checksum = "2a4afff9b34eeececa8bdc32b42fb318434b6b1391d9f8d45fe455af08dc2d35" dependencies = [ "bstr", "filetime", @@ -1141,9 +1140,9 @@ dependencies = [ [[package]] name = "gix-submodule" -version = "0.21.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bacc06333b50abc4fc06204622c2dd92850de2066bb5d421ac776d2bef7ae55" +checksum = "657cc5dd43cbc7a14d9c5aaf02cfbe9c2a15d077cded3f304adb30ef78852d3e" dependencies = [ "bstr", "gix-config", @@ -1156,28 +1155,29 @@ dependencies = [ [[package]] name = "gix-tempfile" -version = "19.0.1" +version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e265fc6b54e57693232a79d84038381ebfda7b1a3b1b8a9320d4d5fe6e820086" +checksum = "666c0041bcdedf5fa05e9bef663c897debab24b7dc1741605742412d1d47da57" dependencies = [ "dashmap", "gix-fs", "libc", + "once_cell", "parking_lot", "tempfile", ] [[package]] name = "gix-trace" -version = "0.1.15" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3f59a8de2934f6391b6b3a1a7654eae18961fcb9f9c843533fed34ad0f3457" +checksum = "e2ccaf54b0b1743a695b482ca0ab9d7603744d8d10b2e5d1a332fef337bee658" [[package]] name = "gix-transport" -version = "0.49.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8da4a77922accb1e26e610c7a84ef7e6b34fd07112e6a84afd68d7f3e795957" +checksum = "12f7cc0179fc89d53c54e1f9ce51229494864ab4bf136132d69db1b011741ca3" dependencies = [ "bstr", "gix-command", @@ -1191,9 +1191,9 @@ dependencies = [ [[package]] name = "gix-traverse" -version = "0.48.0" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "412126bade03a34f5d4125fd64878852718575b3b360eaae3b29970cb555e2a2" +checksum = "c7cdc82509d792ba0ad815f86f6b469c7afe10f94362e96c4494525a6601bdd5" dependencies = [ "bitflags", "gix-commitgraph", @@ -1208,9 +1208,9 @@ dependencies = [ [[package]] name = "gix-url" -version = "0.33.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c79b07b48dd9285485eb10429696ddcd1bfe6fb942ec0e5efb401ae7e40238e5" +checksum = "1b76a9d266254ad287ffd44467cd88e7868799b08f4d52e02d942b93e514d16f" dependencies = [ "bstr", "gix-features", @@ -1222,9 +1222,9 @@ dependencies = [ [[package]] name = "gix-utils" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "befcdbdfb1238d2854591f760a48711bed85e72d80a10e8f2f93f656746ef7c5" +checksum = "5351af2b172caf41a3728eb4455326d84e0d70fe26fc4de74ab0bd37df4191c5" dependencies = [ "bstr", "fastrand", @@ -1233,9 +1233,9 @@ dependencies = [ [[package]] name = "gix-validate" -version = "0.10.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b1e63a5b516e970a594f870ed4571a8fdcb8a344e7bd407a20db8bd61dbfde4" +checksum = "77b9e00cacde5b51388d28ed746c493b18a6add1f19b5e01d686b3b9ece66d4d" dependencies = [ "bstr", "thiserror", @@ -1243,9 +1243,9 @@ dependencies = [ [[package]] name = "gix-worktree" -version = "0.43.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df3dfc8b62b0eccc923c757b40f488abc357c85c03d798622edfc3eb5137e04" +checksum = "55f625ac9126c19bef06dbc6d2703cdd7987e21e35b497bb265ac37d383877b1" dependencies = [ "bstr", "gix-attributes", @@ -1409,7 +1409,6 @@ dependencies = [ "serde", "serde_json", "slotmap", - "sonic-rs", "thiserror", "tokio", "tokio-stream", @@ -1464,7 +1463,6 @@ dependencies = [ "serde", "serde_json", "slotmap", - "sonic-rs", "thiserror", "tokio", "tokio-stream", @@ -1495,11 +1493,11 @@ dependencies = [ "regex-automata", "regex-cursor", "ropey", - "rustix 1.1.2", + "rustix", "tempfile", "unicode-segmentation", "which", - "windows-sys 0.61.2", + "windows-sys 0.61.0", ] [[package]] @@ -1510,11 +1508,9 @@ dependencies = [ "arc-swap", "chrono", "content_inspector", - "crossterm", "dashmap", "fern", "futures-util", - "grep-matcher", "grep-regex", "grep-searcher", "helix-core", @@ -1548,7 +1544,6 @@ dependencies = [ "tokio", "tokio-stream", "toml", - "tree-house", "url", ] @@ -1558,7 +1553,6 @@ version = "25.7.1" dependencies = [ "bitflags", "cassowary", - "crossterm", "helix-core", "helix-view", "log", @@ -1593,7 +1587,6 @@ dependencies = [ "bitflags", "chardetng", "clipboard-win", - "crossterm", "futures-util", "helix-core", "helix-dap", @@ -1608,7 +1601,7 @@ dependencies = [ "log", "once_cell", "parking_lot", - "rustix 1.1.2", + "rustix", "serde", "serde_json", "slotmap", @@ -1835,21 +1828,29 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.12.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" dependencies = [ "equivalent", - "hashbrown 0.16.0", + "hashbrown 0.15.5", ] [[package]] name = "indoc" -version = "2.0.7" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" + +[[package]] +name = "io-uring" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" dependencies = [ - "rustversion", + "bitflags", + "cfg-if", + "libc", ] [[package]] @@ -1920,11 +1921,10 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.80" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ - "once_cell", "wasm-bindgen", ] @@ -1939,9 +1939,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.177" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "libloading" @@ -1966,24 +1966,18 @@ dependencies = [ [[package]] name = "libz-rs-sys" -version = "0.5.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "840db8cf39d9ec4dd794376f38acc40d0fc65eec2a8f484f7fd375b84602becd" +checksum = "6489ca9bd760fe9642d7644e827b0c9add07df89857b0416ee15c1cc1a3b8c5a" dependencies = [ "zlib-rs", ] [[package]] name = "linux-raw-sys" -version = "0.4.15" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - -[[package]] -name = "linux-raw-sys" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9" [[package]] name = "litemap" @@ -1993,10 +1987,11 @@ checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" [[package]] name = "lock_api" -version = "0.4.14" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ + "autocfg", "scopeguard", ] @@ -2025,44 +2020,41 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" -version = "0.9.9" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" dependencies = [ "libc", ] [[package]] -name = "mio" -version = "1.0.2" +name = "miniz_oxide" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ - "hermit-abi", - "libc", - "log", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "adler", ] [[package]] -name = "munge" -version = "0.4.6" +name = "miniz_oxide" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7feb0b48aa0a25f9fe0899482c6e1379ee7a11b24a53073eacdecb9adb6dc60" +checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" dependencies = [ - "munge_macro", + "adler2", ] [[package]] -name = "munge_macro" -version = "0.4.6" +name = "mio" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2e3795a5d2da581a8b252fec6022eee01aea10161a4d1bf237d4cbe47f7e988" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ - "proc-macro2", - "quote", - "syn", + "hermit-abi", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", ] [[package]] @@ -2106,6 +2098,15 @@ dependencies = [ ] [[package]] +name = "object" +version = "0.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +dependencies = [ + "memchr", +] + +[[package]] name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2124,9 +2125,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.5" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -2134,15 +2135,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.12" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-link", + "windows-targets 0.52.6", ] [[package]] @@ -2185,16 +2186,6 @@ dependencies = [ ] [[package]] -name = "pretty_assertions" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" -dependencies = [ - "diff", - "yansi", -] - -[[package]] name = "proc-macro2" version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2213,26 +2204,6 @@ dependencies = [ ] [[package]] -name = "ptr_meta" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9e76f66d3f9606f44e45598d155cb13ecf09f4a28199e48daf8c8fc937ea90" -dependencies = [ - "ptr_meta_derive", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] name = "pulldown-cmark" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2262,15 +2233,6 @@ dependencies = [ ] [[package]] -name = "rancor" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf5f7161924b9d1cea0e4cabc97c372cea92b5f927fc13c6bca67157a0ad947" -dependencies = [ - "ptr_meta", -] - -[[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2318,30 +2280,10 @@ dependencies = [ ] [[package]] -name = "ref-cast" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" -dependencies = [ - "ref-cast-impl", -] - -[[package]] -name = "ref-cast-impl" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] name = "regex" -version = "1.12.2" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" dependencies = [ "aho-corasick", "memchr", @@ -2351,9 +2293,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" dependencies = [ "aho-corasick", "memchr", @@ -2380,41 +2322,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] -name = "rend" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35e8a6bf28cd121053a66aa2e6a2e3eaffad4a60012179f0e864aa5ffeff215" - -[[package]] -name = "rkyv" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f5c3e5da784cd8c69d32cdc84673f3204536ca56e1fa01be31a74b92c932ac" -dependencies = [ - "bytes", - "hashbrown 0.15.5", - "indexmap", - "munge", - "ptr_meta", - "rancor", - "rend", - "rkyv_derive", - "tinyvec", - "uuid", -] - -[[package]] -name = "rkyv_derive" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4270433626cffc9c4c1d3707dd681f2a2718d3d7b09ad754bec137acecda8d22" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] name = "ropey" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2425,38 +2332,25 @@ dependencies = [ ] [[package]] -name = "rustix" -version = "0.38.44" +name = "rustc-demangle" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" -version = "1.1.2" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys 0.11.0", - "windows-sys 0.61.2", + "linux-raw-sys", + "windows-sys 0.59.0", ] [[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2479,28 +2373,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.228" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -2509,24 +2393,23 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" dependencies = [ "itoa", "memchr", "ryu", "serde", - "serde_core", ] [[package]] name = "serde_spanned" -version = "1.0.3" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" +checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" dependencies = [ - "serde_core", + "serde", ] [[package]] @@ -2573,17 +2456,6 @@ dependencies = [ ] [[package]] -name = "signal-hook-mio" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" -dependencies = [ - "libc", - "mio", - "signal-hook", -] - -[[package]] name = "signal-hook-registry" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2605,12 +2477,6 @@ dependencies = [ ] [[package]] -name = "simdutf8" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" - -[[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2662,45 +2528,6 @@ dependencies = [ ] [[package]] -name = "sonic-number" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a74044c092f4f43ca7a6cfd62854cf9fb5ac8502b131347c990bf22bef1dfe" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "sonic-rs" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22540d56ba14521e4878ad436d498518c59698c39a89d5905c694932f0bf7134" -dependencies = [ - "ahash", - "bumpalo", - "bytes", - "cfg-if", - "faststr", - "itoa", - "ref-cast", - "ryu", - "serde", - "simdutf8", - "sonic-number", - "sonic-simd", - "thiserror", -] - -[[package]] -name = "sonic-simd" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b421f7b6aa4a5de8f685aaf398dfaa828346ee639d2b1c1061ab43d40baa6223" -dependencies = [ - "cfg-if", -] - -[[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2742,15 +2569,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.23.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" dependencies = [ "fastrand", "getrandom 0.3.1", "once_cell", - "rustix 1.1.2", - "windows-sys 0.61.2", + "rustix", + "windows-sys 0.59.0", ] [[package]] @@ -2762,9 +2589,9 @@ dependencies = [ "bitflags", "futures-core", "parking_lot", - "rustix 1.1.2", + "rustix", "signal-hook", - "windows-sys 0.61.2", + "windows-sys 0.61.0", ] [[package]] @@ -2789,18 +2616,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" dependencies = [ "proc-macro2", "quote", @@ -2843,26 +2670,29 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.48.0" +version = "1.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" dependencies = [ + "backtrace", "bytes", + "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", + "slab", "socket2", "tokio-macros", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", @@ -2882,12 +2712,12 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.8" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" +checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" dependencies = [ "indexmap", - "serde_core", + "serde", "serde_spanned", "toml_datetime", "toml_parser", @@ -2897,27 +2727,27 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" dependencies = [ - "serde_core", + "serde", ] [[package]] name = "toml_parser" -version = "1.0.4" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" dependencies = [ "winnow", ] [[package]] name = "toml_writer" -version = "1.0.4" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" +checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" [[package]] name = "tree-house" @@ -2929,13 +2759,11 @@ dependencies = [ "hashbrown 0.15.5", "kstring", "once_cell", - "pretty_assertions", "regex", "regex-cursor", "ropey", "slab", "tree-house-bindings", - "unicode-width 0.1.12", ] [[package]] @@ -2974,9 +2802,9 @@ checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217" [[package]] name = "unicode-general-category" -version = "1.1.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b993bddc193ae5bd0d623b49ec06ac3e9312875fdae725a975c51db1cc1677f" +checksum = "24adfe8311434967077a6adff125729161e6e4934d76f6b7c55318ac5c9246d3" [[package]] name = "unicode-ident" @@ -3042,16 +2870,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] -name = "uuid" -version = "1.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3084,25 +2902,24 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.103" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", "once_cell", - "rustversion", "wasm-bindgen-macro", - "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.103" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", + "once_cell", "proc-macro2", "quote", "syn", @@ -3111,9 +2928,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.103" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3121,9 +2938,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.103" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", @@ -3134,12 +2951,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.103" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" -dependencies = [ - "unicode-ident", -] +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "which" @@ -3148,27 +2962,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fabb953106c3c8eea8306e4393700d7657561cb43122571b172bbfb7c7ba1d" dependencies = [ "env_home", - "rustix 1.1.2", + "rustix", "winsafe", ] [[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] name = "winapi-util" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3178,12 +2976,6 @@ dependencies = [ ] [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] name = "windows-core" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3194,9 +2986,9 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.2.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" [[package]] name = "windows-sys" @@ -3218,9 +3010,9 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.61.2" +version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" dependencies = [ "windows-link", ] @@ -3355,9 +3147,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.13" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" dependencies = [ "memchr", ] @@ -3401,12 +3193,6 @@ dependencies = [ ] [[package]] -name = "yansi" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" - -[[package]] name = "yoke" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3431,26 +3217,6 @@ dependencies = [ ] [[package]] -name = "zerocopy" -version = "0.8.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] name = "zerofrom" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3495,6 +3261,6 @@ dependencies = [ [[package]] name = "zlib-rs" -version = "0.5.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f06ae92f42f5e5c42443fd094f245eb656abf56dd7cce9b8b263236565e00f2" +checksum = "868b928d7949e09af2f6086dfc1e01936064cc7a819253bce650d4e2a2d63ba8" @@ -41,8 +41,8 @@ tree-house = { version = "0.3.0", default-features = false } nucleo = "0.5.0" slotmap = "1.0.7" thiserror = "2.0" -tempfile = "3.23.0" -bitflags = "2.10" +tempfile = "3.21.0" +bitflags = "2.9" unicode-segmentation = "1.2" ropey = { version = "1.6.1", default-features = false, features = ["simd"] } foldhash = "0.2" @@ -52,9 +52,6 @@ futures-util = { version = "0.3", features = ["std", "async-await"], default-fea tokio-stream = "0.1.17" toml = "0.9" termina = "0.1" -sonic-rs = "0.5" -# MSRV: update once the MSRV is >=1.85 -globset = "=0.4.16" [workspace.package] version = "25.7.1" diff --git a/book/src/editor.md b/book/src/editor.md index 92e21f9c..a9ea219b 100644 --- a/book/src/editor.md +++ b/book/src/editor.md @@ -27,11 +27,11 @@ |--|--|---------| | `scrolloff` | Number of lines of padding around the edge of the screen when scrolling | `5` | | `mouse` | Enable mouse mode | `true` | -| `default-yank-register` | Default register used for yank/paste | `'"'` | +| `default-yank-register` | Default register used for yank/paste | `"` | | `middle-click-paste` | Middle click paste support | `true` | | `scroll-lines` | Number of lines to scroll per scroll wheel step | `3` | | `shell` | Shell to use when running external commands | Unix: `["sh", "-c"]`<br/>Windows: `["cmd", "/C"]` | -| `line-number` | Line number display: `absolute` simply shows each line's number, while `relative` shows the distance from the current line. When unfocused or in insert mode, `relative` will still show absolute line numbers | `"absolute"` | +| `line-number` | Line number display: `absolute` simply shows each line's number, while `relative` shows the distance from the current line. When unfocused or in insert mode, `relative` will still show absolute line numbers | `absolute` | | `cursorline` | Highlight all lines with a cursor | `false` | | `cursorcolumn` | Highlight all columns with a cursor | `false` | | `continue-comments` | if helix should automatically add a line comment token if you create a new line inside a comment. | `true` | @@ -43,28 +43,28 @@ | `completion-timeout` | Time in milliseconds after typing a word character before completions are shown, set to 5 for instant. | `250` | | `preview-completion-insert` | Whether to apply completion item instantly when selected | `true` | | `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` | -| `completion-replace` | Whether to make completions always replace the entire word and not just the part before the cursor | `false` | +| `completion-replace` | Set to `true` to make completions always replace the entire word and not just the part before the cursor | `false` | | `auto-info` | Whether to display info boxes | `true` | -| `true-color` | Whether to override automatic detection of terminal truecolor support in the event of a false negative | `false` | -| `undercurl` | Whether to override automatic detection of terminal undercurl support in the event of a false negative | `false` | +| `true-color` | Set to `true` to override automatic detection of terminal truecolor support in the event of a false negative | `false` | +| `undercurl` | Set to `true` to override automatic detection of terminal undercurl support in the event of a false negative | `false` | | `rulers` | List of column positions at which to display the rulers. Can be overridden by language specific `rulers` in `languages.toml` file | `[]` | -| `bufferline` | Renders a line at the top of the editor displaying open buffers. Can be `always`, `never` or `multiple` (only shown if more than one buffer is in use) | `"never"` | +| `bufferline` | Renders a line at the top of the editor displaying open buffers. Can be `always`, `never` or `multiple` (only shown if more than one buffer is in use) | `never` | | `color-modes` | Whether to color the mode indicator with different colors depending on the mode itself | `false` | | `text-width` | Maximum line length. Used for the `:reflow` command and soft-wrapping if `soft-wrap.wrap-at-text-width` is set | `80` | | `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml` | `[]` | -| `default-line-ending` | The line ending to use for new documents. Can be `native`, `lf`, `crlf`, `ff`, `cr` or `nel`. `native` uses the platform's native line ending (`crlf` on Windows, otherwise `lf`). | `"native"` | +| `default-line-ending` | The line ending to use for new documents. Can be `native`, `lf`, `crlf`, `ff`, `cr` or `nel`. `native` uses the platform's native line ending (`crlf` on Windows, otherwise `lf`). | `native` | | `insert-final-newline` | Whether to automatically insert a trailing line-ending on write if missing | `true` | | `atomic-save` | Whether to use atomic operations to write documents to disk. This prevents data loss if the editor is interrupted while writing the file, but may confuse some file watching/hot reloading programs. | `true` | | `trim-final-newlines` | Whether to automatically remove line-endings after the final one on write | `false` | | `trim-trailing-whitespace` | Whether to automatically remove whitespace preceding line endings on write | `false` | -| `popup-border` | Draw border around `popup`, `menu`, `all`, or `none` | `"none"` | -| `indent-heuristic` | How the indentation for a newly inserted line is computed: `simple` just copies the indentation level from the previous line, `tree-sitter` computes the indentation based on the syntax tree and `hybrid` combines both approaches. If the chosen heuristic is not available, a different one will be used as a fallback (the fallback order being `hybrid` -> `tree-sitter` -> `simple`). | `"hybrid"` | -| `jump-label-alphabet` | The characters that are used to generate two character jump labels. Characters at the start of the alphabet are used first. | `"abcdefghijklmnopqrstuvwxyz"` | -| `end-of-line-diagnostics` | Minimum severity of diagnostics to render at the end of the line. Set to `disable` to disable entirely. Refer to the setting about `inline-diagnostics` for more details | `"hint"` | +| `popup-border` | Draw border around `popup`, `menu`, `all`, or `none` | `none` | +| `indent-heuristic` | How the indentation for a newly inserted line is computed: `simple` just copies the indentation level from the previous line, `tree-sitter` computes the indentation based on the syntax tree and `hybrid` combines both approaches. If the chosen heuristic is not available, a different one will be used as a fallback (the fallback order being `hybrid` -> `tree-sitter` -> `simple`). | `hybrid` +| `jump-label-alphabet` | The characters that are used to generate two character jump labels. Characters at the start of the alphabet are used first. | `"abcdefghijklmnopqrstuvwxyz"` +| `end-of-line-diagnostics` | Minimum severity of diagnostics to render at the end of the line. Set to `disable` to disable entirely. Refer to the setting about `inline-diagnostics` for more details | `"hint"` | `clipboard-provider` | Which API to use for clipboard interaction. One of `pasteboard` (MacOS), `wayland`, `x-clip`, `x-sel`, `win32-yank`, `termux`, `tmux`, `windows`, `termcode`, `none`, or a custom command set. | Platform and environment specific. | | `editor-config` | Whether to read settings from [EditorConfig](https://editorconfig.org) files | `true` | | `rainbow-brackets` | Whether to render rainbow colors for matching brackets. Requires tree-sitter `rainbows.scm` queries for the language. | `false` | -| `kitty-keyboard-protocol` | Whether to enable Kitty Keyboard Protocol. Can be `enabled`, `disabled` or `auto` | `"auto"` | +| `kitty-keyboard-protocol` | Whether to enable Kitty Keyboard Protocol. Can be `enabled`, `disabled` or `auto` | `auto` | ### `[editor.clipboard-provider]` Section @@ -180,11 +180,11 @@ Valid values for these options are `block`, `bar`, `underline`, or `hidden`. > 💡 Due to limitations of the terminal environment, only the primary cursor can > change shape. -| Key | Description | Default | -| --- | ----------- | ------- | -| `normal` | Cursor shape in [normal mode][normal mode] | `"block"` | -| `insert` | Cursor shape in [insert mode][insert mode] | `"block"` | -| `select` | Cursor shape in [select mode][select mode] | `"block"` | +| Key | Description | Default | +| --- | ----------- | ------- | +| `normal` | Cursor shape in [normal mode][normal mode] | `block` | +| `insert` | Cursor shape in [insert mode][insert mode] | `block` | +| `select` | Cursor shape in [select mode][select mode] | `block` | [normal mode]: ./keymap.md#normal-mode [insert mode]: ./keymap.md#insert-mode @@ -224,25 +224,6 @@ Example: !.gitattributes ``` -### `[editor.file-explorer]` Section - -In addition to the options for the file picker and global search, a similar set of options is presented to configure the file explorer separately. However, unlike the file picker, the defaults are set to avoid ignoring most files. - -Note that the ignore files consulted by the file explorer when `ignore` is set to true are the same ones used by the file picker, including the aforementioned Helix-specific ignore files. - - -| Key | Description | Default | -|--|--|---------| -|`hidden` | Enables ignoring hidden files | `false` -|`follow-symlinks` | Follow symlinks instead of ignoring them | `false` -|`parents` | Enables reading ignore files from parent directories | `false` -|`ignore` | Enables reading `.ignore` files | `false` -|`git-ignore` | Enables reading `.gitignore` files | `false` -|`git-global` | Enables reading global `.gitignore`, whose path is specified in git's config: `core.excludesfile` option | `false` -|`git-exclude` | Enables reading `.git/info/exclude` files | `false` -|`flatten-dirs` | Enables flattening single child directories | `true` - - ### `[editor.auto-pairs]` Section Enables automatic insertion of pairs to parentheses, brackets, etc. Can be a @@ -312,7 +293,7 @@ Options for rendering whitespace with visible characters. Use `:set whitespace.r | Key | Description | Default | |-----|-------------|---------| -| `render` | Whether to render whitespace. May either be `all` or `none`, or a table with sub-keys `space`, `nbsp`, `nnbsp`, `tab`, and `newline` | `"none"` | +| `render` | Whether to render whitespace. May either be `all` or `none`, or a table with sub-keys `space`, `nbsp`, `nnbsp`, `tab`, and `newline` | `none` | | `characters` | Literal characters to use when rendering whitespace. Sub-keys may be any of `tab`, `space`, `nbsp`, `nnbsp`, `newline` or `tabpad` | See example below | Example @@ -344,7 +325,7 @@ Options for rendering vertical indent guides. | Key | Description | Default | | --- | --- | --- | | `render` | Whether to render indent guides | `false` | -| `character` | Literal character to use for rendering the indent guide | `"│"` | +| `character` | Literal character to use for rendering the indent guide | `│` | | `skip-levels` | Number of indent levels to skip | `0` | Example: @@ -422,7 +403,7 @@ Options for soft wrapping lines that exceed the view width: | `enable` | Whether soft wrapping is enabled. | `false` | | `max-wrap` | Maximum free space left at the end of the line. | `20` | | `max-indent-retain` | Maximum indentation to carry over when soft wrapping a line. | `40` | -| `wrap-indicator` | Text inserted before soft wrapped lines, highlighted with `ui.virtual.wrap` | `"↪ "` | +| `wrap-indicator` | Text inserted before soft wrapped lines, highlighted with `ui.virtual.wrap` | `↪ ` | | `wrap-at-text-width` | Soft wrap at `text-width` instead of using the full viewport size. | `false` | Example: diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index f753541a..63bc55f6 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -15,7 +15,6 @@ | bitbake | ✓ | | | | | `bitbake-language-server` | | blade | ✓ | ✓ | | | ✓ | | | blueprint | ✓ | | | | | `blueprint-compiler` | -| bovex | ✓ | | | | ✓ | | | c | ✓ | ✓ | ✓ | ✓ | ✓ | `clangd` | | c-sharp | ✓ | ✓ | | ✓ | | `OmniSharp` | | cabal | | | | | | `haskell-language-server-wrapper` | @@ -58,7 +57,6 @@ | earthfile | ✓ | ✓ | ✓ | | | `earthlyls` | | edoc | ✓ | | | | | | | eex | ✓ | | | | | | -| eiffel | ✓ | ✓ | ✓ | | | `eiffel-language-server` | | ejs | ✓ | | | | | | | elisp | ✓ | | | ✓ | | | | elixir | ✓ | ✓ | ✓ | ✓ | ✓ | `elixir-ls`, `expert` | @@ -137,17 +135,16 @@ | json | ✓ | ✓ | ✓ | | ✓ | `vscode-json-language-server` | | json-ld | ✓ | ✓ | ✓ | | | `vscode-json-language-server` | | json5 | ✓ | | | | | | -| jsonc | ✓ | | ✓ | | ✓ | `vscode-json-language-server` | +| jsonc | ✓ | | ✓ | | | `vscode-json-language-server` | | jsonnet | ✓ | | | | | `jsonnet-language-server` | | jsx | ✓ | ✓ | ✓ | ✓ | ✓ | `typescript-language-server` | | julia | ✓ | ✓ | ✓ | | | `julia` | | just | ✓ | ✓ | ✓ | ✓ | | `just-lsp` | -| kcl | ✓ | | | | | `kcl-language-server` | | kconfig | ✓ | | ✓ | | | | | kdl | ✓ | ✓ | ✓ | ✓ | | | | koka | ✓ | | ✓ | | | `koka` | | kotlin | ✓ | ✓ | ✓ | ✓ | | `kotlin-language-server` | -| koto | ✓ | ✓ | ✓ | | ✓ | `koto-ls` | +| koto | ✓ | ✓ | ✓ | | | `koto-ls` | | latex | ✓ | ✓ | | | | `texlab` | | ld | ✓ | | ✓ | | | | | ldif | ✓ | | | | | | @@ -171,18 +168,16 @@ | mermaid | ✓ | | | | | | | meson | ✓ | | ✓ | | | `mesonlsp` | | mint | | | | | | `mint` | -| miseconfig | ✓ | ✓ | ✓ | | | `taplo`, `tombi` | | mojo | ✓ | ✓ | ✓ | | | `pixi` | | move | ✓ | | | | | | | msbuild | ✓ | | ✓ | | | | | nasm | ✓ | ✓ | | | | `asm-lsp` | -| nearley | ✓ | | | | ✓ | | | nestedtext | ✓ | ✓ | ✓ | | | | | nginx | ✓ | | | | | | | nickel | ✓ | | ✓ | | | `nls` | | nim | ✓ | ✓ | ✓ | | | `nimlangserver` | | nix | ✓ | ✓ | ✓ | | ✓ | `nil`, `nixd` | -| nu | ✓ | ✓ | ✓ | | | `nu` | +| nu | ✓ | | | | | `nu` | | nunjucks | ✓ | | | | | | | ocaml | ✓ | | ✓ | | | `ocamllsp` | | ocaml-interface | ✓ | | | | | `ocamllsp` | @@ -278,7 +273,7 @@ | typespec | ✓ | ✓ | ✓ | | | `tsp-server` | | typst | ✓ | | | ✓ | | `tinymist` | | ungrammar | ✓ | | | | | | -| unison | ✓ | ✓ | ✓ | ✓ | ✓ | | +| unison | ✓ | ✓ | ✓ | | | | | uxntal | ✓ | | | | | | | v | ✓ | ✓ | ✓ | | | `v-analyzer` | | vala | ✓ | ✓ | | | | `vala-language-server` | diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index 3d2ce4e3..e416e813 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -1,7 +1,5 @@ | Name | Description | | --- | --- | -| `:exit`, `:x`, `:xit` | Write changes to disk if the buffer is modified and then quit. Accepts an optional path (:exit some/path.txt). | -| `:exit!`, `:x!`, `:xit!` | Force write changes to disk, creating necessary subdirectories, if the buffer is modified and then quit. Accepts an optional path (:exit! some/path.txt). | | `:quit`, `:q` | Close the current view. | | `:quit!`, `:q!` | Force close the current view, ignoring unsaved changes. | | `:open`, `:o`, `:edit`, `:e` | Open a file from disk into the current view. | @@ -23,12 +21,12 @@ | `:line-ending` | Set the document's default line ending. Options: crlf, lf. | | `:earlier`, `:ear` | Jump back to an earlier point in edit history. Accepts a number of steps or a time span. | | `:later`, `:lat` | Jump to a later point in edit history. Accepts a number of steps or a time span. | -| `:write-quit`, `:wq` | Write changes to disk and close the current view. Accepts an optional path (:wq some/path.txt) | -| `:write-quit!`, `:wq!` | Write changes to disk and close the current view forcefully. Accepts an optional path (:wq! some/path.txt) | +| `:write-quit`, `:wq`, `:x` | Write changes to disk and close the current view. Accepts an optional path (:wq some/path.txt) | +| `:write-quit!`, `:wq!`, `:x!` | Write changes to disk and close the current view forcefully. Accepts an optional path (:wq! some/path.txt) | | `:write-all`, `:wa` | Write changes from all buffers to disk. | | `:write-all!`, `:wa!` | Forcefully write changes from all buffers to disk creating necessary subdirectories. | | `:write-quit-all`, `:wqa`, `:xa` | Write changes from all buffers to disk and close all views. | -| `:write-quit-all!`, `:wqa!`, `:xa!` | Forcefully write changes from all buffers to disk, creating necessary subdirectories, and close all views (ignoring unsaved changes). | +| `:write-quit-all!`, `:wqa!`, `:xa!` | Write changes from all buffers to disk and close all views forcefully (ignoring unsaved changes). | | `:quit-all`, `:qa` | Close all views. | | `:quit-all!`, `:qa!` | Force close all views ignoring unsaved changes. | | `:cquit`, `:cq` | Quit with exit code (default 1). Accepts an optional integer exit code (:cq 2). | diff --git a/book/src/themes.md b/book/src/themes.md index 353a4684..8140120b 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -2,17 +2,6 @@ To use a theme add `theme = "<name>"` to the top of your [`config.toml`](./configuration.md) file, or select it during runtime using `:theme <name>`. -Separate themes can be configured for light and dark modes. On terminals supporting [mode 2031 dark/light detection](https://github.com/contour-terminal/contour/blob/master/docs/vt-extensions/color-palette-update-notifications.md), the theme mode is detected from the terminal. - -```toml -[theme] -dark = "catppuccin_frappe" -light = "catppuccin_latte" -## Optional. Used if the terminal doesn't declare a preference. -## Defaults to the theme set for `dark` if not specified. -# fallback = "catppuccin_frappe" -``` - ## Creating a theme Create a file with the name of your theme as the file name (i.e `mytheme.toml`) and place it in your `themes` directory (i.e `~/.config/helix/themes` or `%AppData%\helix\themes` on Windows). The directory might have to be created beforehand. @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1759381078, - "narHash": "sha256-gTrEEp5gEspIcCOx9PD8kMaF1iEmfBcTbO0Jag2QhQs=", + "lastModified": 1740560979, + "narHash": "sha256-Vr3Qi346M+8CjedtbyUevIGDZW8LcA1fTG0ugPY/Hic=", "owner": "nixos", "repo": "nixpkgs", - "rev": "7df7ff7d8e00218376575f0acdcc5d66741351ee", + "rev": "5135c59491985879812717f4c9fea69604e7f26f", "type": "github" }, "original": { @@ -29,11 +29,11 @@ ] }, "locked": { - "lastModified": 1759631821, - "narHash": "sha256-V8A1L0FaU/aSXZ1QNJScxC12uP4hANeRBgI4YdhHeRM=", + "lastModified": 1740623427, + "narHash": "sha256-3SdPQrZoa4odlScFDUHd4CUPQ/R1gtH4Mq9u8CBiK8M=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "1d7cbdaad90f8a5255a89a6eddd8af24dc89cafe", + "rev": "d342e8b5fd88421ff982f383c853f0fc78a847ab", "type": "github" }, "original": { @@ -16,7 +16,13 @@ ... }: let inherit (nixpkgs) lib; - eachSystem = lib.genAttrs lib.systems.flakeExposed; + systems = [ + "x86_64-linux" + "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" + ]; + eachSystem = lib.genAttrs systems; pkgsFor = eachSystem (system: import nixpkgs { localSystem.system = system; @@ -71,7 +77,8 @@ rust-bin.nightly.latest.rust-analyzer ] ++ (lib.optional (stdenv.isx86_64 && stdenv.isLinux) cargo-tarpaulin) - ++ (lib.optional stdenv.isLinux lldb); + ++ (lib.optional stdenv.isLinux lldb) + ++ (lib.optional stdenv.isDarwin darwin.apple_sdk.frameworks.CoreFoundation); shellHook = '' export RUST_BACKTRACE="1" export RUSTFLAGS="''${RUSTFLAGS:-""} ${commonRustFlagsEnv} ${platformRustFlagsEnv}" diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index 4309cc14..21b18f31 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -30,9 +30,9 @@ unicode-segmentation.workspace = true # For now lets lock the version to avoid rendering glitches # when installing without `--locked` unicode-width = "=0.1.12" -unicode-general-category = "1.1" +unicode-general-category = "1.0" slotmap.workspace = true -tree-house = { workspace = true, features = ["fixtures"] } +tree-house.workspace = true once_cell = "1.21" arc-swap = "1" regex = "1" @@ -55,7 +55,7 @@ textwrap = "0.16.2" nucleo.workspace = true parking_lot.workspace = true -globset.workspace = true +globset = "0.4.16" regex-cursor = "0.1.5" [dev-dependencies] diff --git a/helix-core/src/auto_pairs.rs b/helix-core/src/auto_pairs.rs index 85329040..5811186c 100644 --- a/helix-core/src/auto_pairs.rs +++ b/helix-core/src/auto_pairs.rs @@ -1,11 +1,9 @@ //! When typing the opening character of one of the possible pairs defined below, //! this module provides the functionality to insert the paired closing character. -use crate::{graphemes, movement::Direction, Range, Rope, Selection, Tendril, Transaction}; +use crate::{graphemes, movement::Direction, Change, Deletion, Range, Rope, Tendril}; use std::collections::HashMap; -use smallvec::SmallVec; - // Heavily based on https://github.com/codemirror/closebrackets/ pub const DEFAULT_PAIRS: &[(char, char)] = &[ ('(', ')'), @@ -106,37 +104,128 @@ impl Default for AutoPairs { } } -// insert hook: -// Fn(doc, selection, char) => Option<Transaction> -// problem is, we want to do this per range, so we can call default handler for some ranges -// so maybe ret Vec<Option<Change>> -// but we also need to be able to return transactions... -// -// to simplify, maybe return Option<Transaction> and just reimplement the default - // [TODO] // * delete implementation where it erases the whole bracket (|) -> | // * change to multi character pairs to handle cases like placing the cursor in the // middle of triple quotes, and more exotic pairs like Jinja's {% %} #[must_use] -pub fn hook(doc: &Rope, selection: &Selection, ch: char, pairs: &AutoPairs) -> Option<Transaction> { - log::trace!("autopairs hook selection: {:#?}", selection); +pub fn hook_insert( + doc: &Rope, + range: &Range, + ch: char, + pairs: &AutoPairs, +) -> Option<(Change, Range)> { + log::trace!("autopairs hook range: {:#?}", range); if let Some(pair) = pairs.get(ch) { if pair.same() { - return Some(handle_same(doc, selection, pair)); + return handle_insert_same(doc, range, pair); } else if pair.open == ch { - return Some(handle_open(doc, selection, pair)); + return handle_insert_open(doc, range, pair); } else if pair.close == ch { // && char_at pos == close - return Some(handle_close(doc, selection, pair)); + return handle_insert_close(doc, range, pair); } + } else if ch.is_whitespace() { + return handle_insert_whitespace(doc, range, ch, pairs); } None } +#[must_use] +pub fn hook_delete(doc: &Rope, range: &Range, pairs: &AutoPairs) -> Option<(Deletion, Range)> { + log::trace!("autopairs delete hook range: {:#?}", range); + + let text = doc.slice(..); + let cursor = range.cursor(text); + + let cur = doc.get_char(cursor)?; + let prev = prev_char(doc, cursor)?; + + // check for whitespace surrounding a pair + if doc.len_chars() >= 4 && prev.is_whitespace() && cur.is_whitespace() { + let second_prev = doc.get_char(graphemes::nth_prev_grapheme_boundary(text, cursor, 2))?; + let second_next = doc.get_char(graphemes::next_grapheme_boundary(text, cursor))?; + log::debug!("second_prev: {}, second_next: {}", second_prev, second_next); + + if let Some(pair) = pairs.get(second_prev) { + if pair.open == second_prev && pair.close == second_next { + return handle_delete(doc, range); + } + } + } + + let pair = pairs.get(cur)?; + + if pair.open != prev || pair.close != cur { + return None; + } + + handle_delete(doc, range) +} + +pub fn handle_delete(doc: &Rope, range: &Range) -> Option<(Deletion, Range)> { + let text = doc.slice(..); + let cursor = range.cursor(text); + + let end_next = graphemes::next_grapheme_boundary(text, cursor); + let end_prev = graphemes::prev_grapheme_boundary(text, cursor); + + let delete = (end_prev, end_next); + let size_delete = end_next - end_prev; + let next_head = graphemes::next_grapheme_boundary(text, range.head) - size_delete; + + // if the range is a single grapheme cursor, we do not want to shrink the + // range, just move it, so we only subtract the size of the closing pair char + let next_anchor = match (range.direction(), range.is_single_grapheme(text)) { + // single grapheme forward needs to move, but only the width of the + // character under the cursor, which is the closer + (Direction::Forward, true) => range.anchor - (end_next - cursor), + (Direction::Backward, true) => range.anchor - (cursor - end_prev), + + (Direction::Forward, false) => range.anchor, + (Direction::Backward, false) => range.anchor - size_delete, + }; + + let next_range = Range::new(next_anchor, next_head); + + log::trace!( + "auto pair delete: {:?}, range: {:?}, next_range: {:?}, text len: {}", + delete, + range, + next_range, + text.len_chars() + ); + + Some((delete, next_range)) +} + +fn handle_insert_whitespace( + doc: &Rope, + range: &Range, + ch: char, + pairs: &AutoPairs, +) -> Option<(Change, Range)> { + let text = doc.slice(..); + let cursor = range.cursor(text); + let cur = doc.get_char(cursor)?; + let prev = prev_char(doc, cursor)?; + let pair = pairs.get(cur)?; + + if pair.open != prev || pair.close != cur { + return None; + } + + let whitespace_pair = Pair { + open: ch, + close: ch, + }; + + handle_insert_same(doc, range, &whitespace_pair) +} + fn prev_char(doc: &Rope, pos: usize) -> Option<char> { if pos == 0 { return None; @@ -146,7 +235,7 @@ fn prev_char(doc: &Rope, pos: usize) -> Option<char> { } /// calculate what the resulting range should be for an auto pair insertion -fn get_next_range(doc: &Rope, start_range: &Range, offset: usize, len_inserted: usize) -> Range { +fn get_next_range(doc: &Rope, start_range: &Range, len_inserted: usize) -> Range { // When the character under the cursor changes due to complete pair // insertion, we must look backward a grapheme and then add the length // of the insertion to put the resulting cursor in the right place, e.g. @@ -165,10 +254,7 @@ fn get_next_range(doc: &Rope, start_range: &Range, offset: usize, len_inserted: // inserting at the very end of the document after the last newline if start_range.head == doc.len_chars() && start_range.anchor == doc.len_chars() { - return Range::new( - start_range.anchor + offset + 1, - start_range.head + offset + 1, - ); + return Range::new(start_range.anchor + 1, start_range.head + 1); } let doc_slice = doc.slice(..); @@ -177,7 +263,7 @@ fn get_next_range(doc: &Rope, start_range: &Range, offset: usize, len_inserted: // just skip over graphemes if len_inserted == 0 { let end_anchor = if single_grapheme { - graphemes::next_grapheme_boundary(doc_slice, start_range.anchor) + offset + graphemes::next_grapheme_boundary(doc_slice, start_range.anchor) // even for backward inserts with multiple grapheme selections, // we want the anchor to stay where it is so that the relative @@ -185,42 +271,38 @@ fn get_next_range(doc: &Rope, start_range: &Range, offset: usize, len_inserted: // // foo([) wor]d -> insert ) -> foo()[ wor]d } else { - start_range.anchor + offset + start_range.anchor }; return Range::new( end_anchor, - graphemes::next_grapheme_boundary(doc_slice, start_range.head) + offset, + graphemes::next_grapheme_boundary(doc_slice, start_range.head), ); } // trivial case: only inserted a single-char opener, just move the selection if len_inserted == 1 { let end_anchor = if single_grapheme || start_range.direction() == Direction::Backward { - start_range.anchor + offset + 1 + start_range.anchor + 1 } else { - start_range.anchor + offset + start_range.anchor }; - return Range::new(end_anchor, start_range.head + offset + 1); + return Range::new(end_anchor, start_range.head + 1); } // If the head = 0, then we must be in insert mode with a backward // cursor, which implies the head will just move let end_head = if start_range.head == 0 || start_range.direction() == Direction::Backward { - start_range.head + offset + 1 + start_range.head + 1 } else { // We must have a forward cursor, which means we must move to the // other end of the grapheme to get to where the new characters // are inserted, then move the head to where it should be let prev_bound = graphemes::prev_grapheme_boundary(doc_slice, start_range.head); - log::trace!( - "prev_bound: {}, offset: {}, len_inserted: {}", - prev_bound, - offset, - len_inserted - ); - prev_bound + offset + len_inserted + log::trace!("prev_bound: {}, len_inserted: {}", prev_bound, len_inserted); + + prev_bound + len_inserted }; let end_anchor = match (start_range.len(), start_range.direction()) { @@ -239,7 +321,7 @@ fn get_next_range(doc: &Rope, start_range: &Range, offset: usize, len_inserted: // if we are appending, the anchor stays where it is; only offset // for multiple range insertions } else { - start_range.anchor + offset + start_range.anchor } } @@ -248,13 +330,11 @@ fn get_next_range(doc: &Rope, start_range: &Range, offset: usize, len_inserted: // if we're backward, then the head is at the first char // of the typed char, so we need to add the length of // the closing char - graphemes::prev_grapheme_boundary(doc.slice(..), start_range.anchor) - + len_inserted - + offset + graphemes::prev_grapheme_boundary(doc.slice(..), start_range.anchor) + len_inserted } else { // when we are inserting in front of a selection, we need to move // the anchor over by however many characters were inserted overall - start_range.anchor + offset + len_inserted + start_range.anchor + len_inserted } } }; @@ -262,112 +342,76 @@ fn get_next_range(doc: &Rope, start_range: &Range, offset: usize, len_inserted: Range::new(end_anchor, end_head) } -fn handle_open(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction { - let mut end_ranges = SmallVec::with_capacity(selection.len()); - let mut offs = 0; - - let transaction = Transaction::change_by_selection(doc, selection, |start_range| { - let cursor = start_range.cursor(doc.slice(..)); - let next_char = doc.get_char(cursor); - let len_inserted; - - // Since auto pairs are currently limited to single chars, we're either - // inserting exactly one or two chars. When arbitrary length pairs are - // added, these will need to be changed. - let change = match next_char { - Some(_) if !pair.should_close(doc, start_range) => { - len_inserted = 1; - let mut tendril = Tendril::new(); - tendril.push(pair.open); - (cursor, cursor, Some(tendril)) - } - _ => { - // insert open & close - let pair_str = Tendril::from_iter([pair.open, pair.close]); - len_inserted = 2; - (cursor, cursor, Some(pair_str)) - } - }; +fn handle_insert_open(doc: &Rope, range: &Range, pair: &Pair) -> Option<(Change, Range)> { + let cursor = range.cursor(doc.slice(..)); + let next_char = doc.get_char(cursor); + let len_inserted; + + // Since auto pairs are currently limited to single chars, we're either + // inserting exactly one or two chars. When arbitrary length pairs are + // added, these will need to be changed. + let change = match next_char { + Some(_) if !pair.should_close(doc, range) => { + return None; + } + _ => { + // insert open & close + let pair_str = Tendril::from_iter([pair.open, pair.close]); + len_inserted = 2; + (cursor, cursor, Some(pair_str)) + } + }; - let next_range = get_next_range(doc, start_range, offs, len_inserted); - end_ranges.push(next_range); - offs += len_inserted; + let next_range = get_next_range(doc, range, len_inserted); + let result = (change, next_range); - change - }); + log::debug!("auto pair change: {:#?}", &result); - let t = transaction.with_selection(Selection::new(end_ranges, selection.primary_index())); - log::debug!("auto pair transaction: {:#?}", t); - t + Some(result) } -fn handle_close(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction { - let mut end_ranges = SmallVec::with_capacity(selection.len()); - let mut offs = 0; - - let transaction = Transaction::change_by_selection(doc, selection, |start_range| { - let cursor = start_range.cursor(doc.slice(..)); - let next_char = doc.get_char(cursor); - let mut len_inserted = 0; +fn handle_insert_close(doc: &Rope, range: &Range, pair: &Pair) -> Option<(Change, Range)> { + let cursor = range.cursor(doc.slice(..)); + let next_char = doc.get_char(cursor); - let change = if next_char == Some(pair.close) { - // return transaction that moves past close - (cursor, cursor, None) // no-op - } else { - len_inserted = 1; - let mut tendril = Tendril::new(); - tendril.push(pair.close); - (cursor, cursor, Some(tendril)) - }; + let change = if next_char == Some(pair.close) { + // return transaction that moves past close + (cursor, cursor, None) // no-op + } else { + return None; + }; - let next_range = get_next_range(doc, start_range, offs, len_inserted); - end_ranges.push(next_range); - offs += len_inserted; + let next_range = get_next_range(doc, range, 0); + let result = (change, next_range); - change - }); + log::debug!("auto pair change: {:#?}", &result); - let t = transaction.with_selection(Selection::new(end_ranges, selection.primary_index())); - log::debug!("auto pair transaction: {:#?}", t); - t + Some(result) } /// handle cases where open and close is the same, or in triples ("""docstring""") -fn handle_same(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction { - let mut end_ranges = SmallVec::with_capacity(selection.len()); - - let mut offs = 0; - - let transaction = Transaction::change_by_selection(doc, selection, |start_range| { - let cursor = start_range.cursor(doc.slice(..)); - let mut len_inserted = 0; - let next_char = doc.get_char(cursor); - - let change = if next_char == Some(pair.open) { - // return transaction that moves past close - (cursor, cursor, None) // no-op - } else { - let mut pair_str = Tendril::new(); - pair_str.push(pair.open); - - // for equal pairs, don't insert both open and close if either - // side has a non-pair char - if pair.should_close(doc, start_range) { - pair_str.push(pair.close); - } +fn handle_insert_same(doc: &Rope, range: &Range, pair: &Pair) -> Option<(Change, Range)> { + let cursor = range.cursor(doc.slice(..)); + let mut len_inserted = 0; + let next_char = doc.get_char(cursor); + + let change = if next_char == Some(pair.open) { + // return transaction that moves past close + (cursor, cursor, None) // no-op + } else { + if !pair.should_close(doc, range) { + return None; + } - len_inserted += pair_str.chars().count(); - (cursor, cursor, Some(pair_str)) - }; + let pair_str = Tendril::from_iter([pair.open, pair.close]); + len_inserted = 2; + (cursor, cursor, Some(pair_str)) + }; - let next_range = get_next_range(doc, start_range, offs, len_inserted); - end_ranges.push(next_range); - offs += len_inserted; + let next_range = get_next_range(doc, range, len_inserted); + let result = (change, next_range); - change - }); + log::debug!("auto pair change: {:#?}", &result); - let t = transaction.with_selection(Selection::new(end_ranges, selection.primary_index())); - log::debug!("auto pair transaction: {:#?}", t); - t + Some(result) } diff --git a/helix-core/src/indent.rs b/helix-core/src/indent.rs index bdf0f405..55454ebc 100644 --- a/helix-core/src/indent.rs +++ b/helix-core/src/indent.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, collections::HashMap}; +use std::{borrow::Cow, collections::HashMap, iter}; use helix_stdx::rope::RopeSliceExt; use tree_house::TREE_SITTER_MATCH_LIMIT; @@ -214,10 +214,7 @@ fn whitespace_with_same_width(text: RopeSlice) -> String { if grapheme == "\t" { s.push('\t'); } else { - s.extend(std::iter::repeat_n( - ' ', - grapheme_width(&Cow::from(grapheme)), - )); + s.extend(std::iter::repeat(' ').take(grapheme_width(&Cow::from(grapheme)))); } } s @@ -246,10 +243,10 @@ pub fn normalize_indentation( original_len += 1; } if indent_style == IndentStyle::Tabs { - dst.extend(std::iter::repeat_n('\t', len / tab_width)); + dst.extend(iter::repeat('\t').take(len / tab_width)); len %= tab_width; } - dst.extend(std::iter::repeat_n(' ', len)); + dst.extend(iter::repeat(' ').take(len)); original_len } diff --git a/helix-core/src/object.rs b/helix-core/src/object.rs index e0c02d0a..02e72859 100644 --- a/helix-core/src/object.rs +++ b/helix-core/src/object.rs @@ -25,38 +25,59 @@ pub fn expand_selection(syntax: &Syntax, text: RopeSlice, selection: Selection) } pub fn shrink_selection(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection { - select_node_impl( - syntax, - text, - selection, - |cursor| { - cursor.goto_first_child(); - }, - None, - ) + selection.transform(move |range| { + let (from, to) = range.into_byte_range(text); + let mut cursor = syntax.walk(); + cursor.reset_to_byte_range(from, to); + + if let Some(node) = cursor + .into_iter() + .find(|node| node.is_named() && node.is_contained_within(from..to)) + { + return Range::from_node(node, text, range.direction()); + } + + range + }) } pub fn select_next_sibling(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection { - select_node_impl( - syntax, - text, - selection, - |cursor| { - while !cursor.goto_next_sibling() { - if !cursor.goto_parent() { - break; - } + selection.transform(move |range| { + let (from, to) = range.into_byte_range(text); + let mut cursor = syntax.walk(); + cursor.reset_to_byte_range(from, to); + + while !cursor.goto_next_sibling() { + if !cursor.goto_parent() { + return range; } - }, - Some(Direction::Forward), - ) + } + + Range::from_node(cursor.node(), text, Direction::Forward) + }) +} + +pub fn select_prev_sibling(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection { + selection.transform(move |range| { + let (from, to) = range.into_byte_range(text); + let mut cursor = syntax.walk(); + cursor.reset_to_byte_range(from, to); + + while !cursor.goto_previous_sibling() { + if !cursor.goto_parent() { + return range; + } + } + + Range::from_node(cursor.node(), text, Direction::Backward) + }) } pub fn select_all_siblings(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection { let mut cursor = syntax.walk(); selection.transform_iter(move |range| { let (from, to) = range.into_byte_range(text); - cursor.reset_to_byte_range(from as u32, to as u32); + cursor.reset_to_byte_range(from, to); if !cursor.goto_parent_with(|parent| parent.child_count() > 1) { return vec![range].into_iter(); @@ -70,7 +91,7 @@ pub fn select_all_children(syntax: &Syntax, text: RopeSlice, selection: Selectio let mut cursor = syntax.walk(); selection.transform_iter(move |range| { let (from, to) = range.into_byte_range(text); - cursor.reset_to_byte_range(from as u32, to as u32); + cursor.reset_to_byte_range(from, to); select_children(&mut cursor, text, range).into_iter() }) } @@ -88,47 +109,3 @@ fn select_children(cursor: &mut TreeCursor, text: RopeSlice, range: Range) -> Ve vec![range] } } - -pub fn select_prev_sibling(syntax: &Syntax, text: RopeSlice, selection: Selection) -> Selection { - select_node_impl( - syntax, - text, - selection, - |cursor| { - while !cursor.goto_previous_sibling() { - if !cursor.goto_parent() { - break; - } - } - }, - Some(Direction::Backward), - ) -} - -fn select_node_impl<F>( - syntax: &Syntax, - text: RopeSlice, - selection: Selection, - motion: F, - direction: Option<Direction>, -) -> Selection -where - F: Fn(&mut TreeCursor), -{ - let cursor = &mut syntax.walk(); - - selection.transform(|range| { - let from = text.char_to_byte(range.from()) as u32; - let to = text.char_to_byte(range.to()) as u32; - - cursor.reset_to_byte_range(from, to); - - motion(cursor); - - let node = cursor.node(); - let from = text.byte_to_char(node.start_byte() as usize); - let to = text.byte_to_char(node.end_byte() as usize); - - Range::new(from, to).with_direction(direction.unwrap_or_else(|| range.direction())) - }) -} diff --git a/helix-core/src/position.rs b/helix-core/src/position.rs index e70cb949..3f888c57 100644 --- a/helix-core/src/position.rs +++ b/helix-core/src/position.rs @@ -262,14 +262,7 @@ pub fn visual_offset_from_anchor( pub fn pos_at_coords(text: RopeSlice, coords: Position, limit_before_line_ending: bool) -> usize { let Position { mut row, col } = coords; if limit_before_line_ending { - let lines = text.len_lines() - 1; - - row = row.min(if crate::line_ending::get_line_ending(&text).is_some() { - // if the last line is empty, don't jump to it - lines - 1 - } else { - lines - }); + row = row.min(text.len_lines() - 1); }; let line_start = text.line_to_char(row); let line_end = if limit_before_line_ending { diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs index 5bde08e3..328b65d6 100644 --- a/helix-core/src/selection.rs +++ b/helix-core/src/selection.rs @@ -387,8 +387,11 @@ impl Range { /// Converts this char range into an in order byte range, discarding /// direction. - pub fn into_byte_range(&self, text: RopeSlice) -> (usize, usize) { - (text.char_to_byte(self.from()), text.char_to_byte(self.to())) + pub fn into_byte_range(&self, text: RopeSlice) -> (u32, u32) { + ( + text.char_to_byte(self.from()) as u32, + text.char_to_byte(self.to()) as u32, + ) } } @@ -700,22 +703,161 @@ impl Selection { pub fn contains(&self, other: &Selection) -> bool { is_subset::<true>(self.range_bounds(), other.range_bounds()) } + + /// returns true if self has at least one range that overlaps with at least one range from other + pub fn overlaps(&self, other: &Selection) -> bool { + let (mut iter_self, mut iter_other) = (self.iter(), other.iter()); + let (mut ele_self, mut ele_other) = (iter_self.next(), iter_other.next()); + + loop { + match (ele_self, ele_other) { + (Some(ra), Some(rb)) => { + if ra.overlaps(rb) { + return true; + } else if ra.from() > rb.from() { + ele_self = iter_self.next(); + } else { + ele_other = iter_other.next(); + } + } + _ => return false, + } + } + } + + /// Returns the given selection with the overlapping portions of `other` + /// cut out. If one range from this selection is equal to one from `other`, + /// this range is removed. If this results in an entirely empty selection, + /// `None` is returned. + pub fn without(self, other: &Selection) -> Option<Self> { + if other.contains(&self) { + return None; + } + + let mut primary_index = self.primary_index; + let mut ranges = smallvec!(); + let (mut iter_self, mut iter_other) = (self.into_iter(), other.iter()); + let (mut ele_self, mut ele_other) = (iter_self.next(), iter_other.next()); + let mut cur_index = 0; + + loop { + match (ele_self, ele_other) { + (Some(ra), Some(rb)) => { + if !ra.overlaps(rb) { + // there's no overlap and it's on the left of rb + if ra.to() <= rb.from() { + ranges.push(ra); + ele_self = iter_self.next(); + cur_index += 1; + + // otherwise it must be on the right, so move rb forward + } else { + ele_other = iter_other.next(); + } + + continue; + } + + // otherwise there is overlap, so truncate or split + if rb.contains_range(&ra) { + ele_self = iter_self.next(); + cur_index += 1; + continue; + } + + // [ ra ] + // [ rb ] + if ra.from() <= rb.from() && ra.to() <= rb.to() && ra.to() >= rb.from() { + let new = if ra.direction() == Direction::Backward { + Range::new(rb.from(), ra.head) + } else { + Range::new(ra.anchor, rb.from()) + }; + + ranges.push(new); + ele_self = iter_self.next(); + cur_index += 1; + + // [ ra ] + // [ rb ] + } else if ra.from() >= rb.from() && ra.to() >= rb.to() && ra.from() <= rb.to() { + let new = if ra.direction() == Direction::Backward { + Range::new(ra.anchor, rb.to() + 1) + } else { + Range::new(rb.to(), ra.head) + }; + + // don't settle on the new range yet because the next + // rb could chop off the other end of ra + ele_self = Some(new); + ele_other = iter_other.next(); + + // [ ra ] + // [ rb ] + } else if ra.from() < rb.from() && ra.to() > rb.to() { + // we must split the range into two + let left = if ra.direction() == Direction::Backward { + Range::new(rb.from(), ra.head) + } else { + Range::new(ra.anchor, rb.from()) + }; + + let right = if ra.direction() == Direction::Backward { + Range::new(ra.anchor, rb.to()) + } else { + Range::new(rb.to(), ra.head) + }; + + // We do NOT push right onto the results right away. + // We must put it back into the iterator and check it + // again in case a further range splits it again. + ranges.push(left); + ele_other = iter_other.next(); + + // offset the primary index whenever we split + if cur_index < primary_index { + primary_index += 1; + } + + cur_index += 1; + ele_self = Some(right); + } + } + // the rest just get included as is + (Some(range), None) => { + ranges.push(range); + ele_self = iter_self.next(); + cur_index += 1; + } + // exhausted `self`, nothing left to do + (None, _) => { + break; + } + } + } + + if ranges.is_empty() { + return None; + } + + Some(Selection::new(ranges, primary_index)) + } } impl<'a> IntoIterator for &'a Selection { type Item = &'a Range; type IntoIter = std::slice::Iter<'a, Range>; - fn into_iter(self) -> std::slice::Iter<'a, Range> { + fn into_iter(self) -> Self::IntoIter { self.ranges().iter() } } impl IntoIterator for Selection { type Item = Range; - type IntoIter = smallvec::IntoIter<[Range; 1]>; + type IntoIter = smallvec::IntoIter<[Self::Item; 1]>; - fn into_iter(self) -> smallvec::IntoIter<[Range; 1]> { + fn into_iter(self) -> Self::IntoIter { self.ranges.into_iter() } } @@ -882,6 +1024,7 @@ pub fn split_on_matches(text: RopeSlice, selection: &Selection, regex: &rope::Re #[cfg(test)] mod test { use super::*; + use crate::test; use crate::Rope; #[test] @@ -972,7 +1115,7 @@ mod test { } #[test] - fn test_overlaps() { + fn test_range_overlaps() { fn overlaps(a: (usize, usize), b: (usize, usize)) -> bool { Range::new(a.0, a.1).overlaps(&Range::new(b.0, b.1)) } @@ -1023,6 +1166,160 @@ mod test { } #[test] + fn test_selection_overlaps() { + fn overlaps(a: &[(usize, usize)], b: &[(usize, usize)]) -> bool { + let a = Selection::new( + a.iter() + .map(|(anchor, head)| Range::new(*anchor, *head)) + .collect(), + 0, + ); + let b = Selection::new( + b.iter() + .map(|(anchor, head)| Range::new(*anchor, *head)) + .collect(), + 0, + ); + a.overlaps(&b) + } + + // Two non-zero-width ranges, no overlap. + assert!(!overlaps(&[(0, 3)], &[(3, 6)])); + assert!(!overlaps(&[(0, 3)], &[(6, 3)])); + assert!(!overlaps(&[(3, 0)], &[(3, 6)])); + assert!(!overlaps(&[(3, 0)], &[(6, 3)])); + assert!(!overlaps(&[(3, 6)], &[(0, 3)])); + assert!(!overlaps(&[(3, 6)], &[(3, 0)])); + assert!(!overlaps(&[(6, 3)], &[(0, 3)])); + assert!(!overlaps(&[(6, 3)], &[(3, 0)])); + + // more ranges in one or the other, no overlap + assert!(!overlaps(&[(6, 3), (9, 6)], &[(3, 0)])); + assert!(!overlaps(&[(6, 3), (6, 9)], &[(3, 0)])); + assert!(!overlaps(&[(3, 6), (9, 6)], &[(3, 0)])); + assert!(!overlaps(&[(3, 6), (6, 9)], &[(3, 0)])); + assert!(!overlaps(&[(6, 3), (9, 6)], &[(0, 3)])); + assert!(!overlaps(&[(6, 3), (6, 9)], &[(0, 3)])); + assert!(!overlaps(&[(3, 6), (9, 6)], &[(0, 3)])); + assert!(!overlaps(&[(3, 6), (6, 9)], &[(0, 3)])); + + assert!(!overlaps(&[(6, 3)], &[(3, 0), (9, 6)])); + assert!(!overlaps(&[(6, 3)], &[(3, 0), (6, 9)])); + assert!(!overlaps(&[(3, 6)], &[(3, 0), (9, 6)])); + assert!(!overlaps(&[(3, 6)], &[(3, 0), (6, 9)])); + assert!(!overlaps(&[(6, 3)], &[(0, 3), (9, 6)])); + assert!(!overlaps(&[(6, 3)], &[(0, 3), (6, 9)])); + assert!(!overlaps(&[(3, 6)], &[(0, 3), (9, 6)])); + assert!(!overlaps(&[(3, 6)], &[(0, 3), (6, 9)])); + + // Two non-zero-width ranges, overlap. + assert!(overlaps(&[(0, 4)], &[(3, 6)])); + assert!(overlaps(&[(0, 4)], &[(6, 3)])); + assert!(overlaps(&[(4, 0)], &[(3, 6)])); + assert!(overlaps(&[(4, 0)], &[(6, 3)])); + assert!(overlaps(&[(3, 6)], &[(0, 4)])); + assert!(overlaps(&[(3, 6)], &[(4, 0)])); + assert!(overlaps(&[(6, 3)], &[(0, 4)])); + assert!(overlaps(&[(6, 3)], &[(4, 0)])); + + // Two non-zero-width ranges, overlap, extra from one or the other + assert!(overlaps(&[(0, 4), (7, 10)], &[(3, 6)])); + assert!(overlaps(&[(0, 4), (7, 10)], &[(6, 3)])); + assert!(overlaps(&[(4, 0), (7, 10)], &[(3, 6)])); + assert!(overlaps(&[(4, 0), (7, 10)], &[(6, 3)])); + assert!(overlaps(&[(3, 6), (7, 10)], &[(0, 4)])); + assert!(overlaps(&[(3, 6), (7, 10)], &[(4, 0)])); + assert!(overlaps(&[(6, 3), (7, 10)], &[(0, 4)])); + assert!(overlaps(&[(6, 3), (7, 10)], &[(4, 0)])); + assert!(overlaps(&[(0, 4), (10, 7)], &[(3, 6)])); + assert!(overlaps(&[(0, 4), (10, 7)], &[(6, 3)])); + assert!(overlaps(&[(4, 0), (10, 7)], &[(3, 6)])); + assert!(overlaps(&[(4, 0), (10, 7)], &[(6, 3)])); + assert!(overlaps(&[(3, 6), (10, 7)], &[(0, 4)])); + assert!(overlaps(&[(3, 6), (10, 7)], &[(4, 0)])); + assert!(overlaps(&[(6, 3), (10, 7)], &[(0, 4)])); + assert!(overlaps(&[(6, 3), (10, 7)], &[(4, 0)])); + + assert!(overlaps(&[(0, 4)], &[(3, 6), (7, 10)])); + assert!(overlaps(&[(0, 4)], &[(6, 3), (7, 10)])); + assert!(overlaps(&[(4, 0)], &[(3, 6), (7, 10)])); + assert!(overlaps(&[(4, 0)], &[(6, 3), (7, 10)])); + assert!(overlaps(&[(3, 6)], &[(0, 4), (7, 10)])); + assert!(overlaps(&[(3, 6)], &[(4, 0), (7, 10)])); + assert!(overlaps(&[(6, 3)], &[(0, 4), (7, 10)])); + assert!(overlaps(&[(6, 3)], &[(4, 0), (7, 10)])); + assert!(overlaps(&[(0, 4)], &[(3, 6), (10, 7)])); + assert!(overlaps(&[(0, 4)], &[(6, 3), (10, 7)])); + assert!(overlaps(&[(4, 0)], &[(3, 6), (10, 7)])); + assert!(overlaps(&[(4, 0)], &[(6, 3), (10, 7)])); + assert!(overlaps(&[(3, 6)], &[(0, 4), (10, 7)])); + assert!(overlaps(&[(3, 6)], &[(4, 0), (10, 7)])); + assert!(overlaps(&[(6, 3)], &[(0, 4), (10, 7)])); + assert!(overlaps(&[(6, 3)], &[(4, 0), (10, 7)])); + + // Zero-width and non-zero-width range, no overlap. + assert!(!overlaps(&[(0, 3)], &[(3, 3)])); + assert!(!overlaps(&[(3, 0)], &[(3, 3)])); + assert!(!overlaps(&[(3, 3)], &[(0, 3)])); + assert!(!overlaps(&[(3, 3)], &[(3, 0)])); + + assert!(!overlaps(&[(0, 3), (7, 10)], &[(3, 3)])); + assert!(!overlaps(&[(3, 0), (7, 10)], &[(3, 3)])); + assert!(!overlaps(&[(3, 3), (7, 10)], &[(0, 3)])); + assert!(!overlaps(&[(3, 3), (7, 10)], &[(3, 0)])); + + assert!(!overlaps(&[(0, 3)], &[(3, 3), (7, 10)])); + assert!(!overlaps(&[(3, 0)], &[(3, 3), (7, 10)])); + assert!(!overlaps(&[(3, 3)], &[(0, 3), (7, 10)])); + assert!(!overlaps(&[(3, 3)], &[(3, 0), (7, 10)])); + + // Zero-width and non-zero-width range, overlap. + assert!(overlaps(&[(1, 4)], &[(1, 1)])); + assert!(overlaps(&[(4, 1)], &[(1, 1)])); + assert!(overlaps(&[(1, 1)], &[(1, 4)])); + assert!(overlaps(&[(1, 1)], &[(4, 1)])); + + assert!(overlaps(&[(1, 4)], &[(3, 3)])); + assert!(overlaps(&[(4, 1)], &[(3, 3)])); + assert!(overlaps(&[(3, 3)], &[(1, 4)])); + assert!(overlaps(&[(3, 3)], &[(4, 1)])); + + assert!(overlaps(&[(1, 4), (7, 10)], &[(1, 1)])); + assert!(overlaps(&[(4, 1), (7, 10)], &[(1, 1)])); + assert!(overlaps(&[(1, 1), (7, 10)], &[(1, 4)])); + assert!(overlaps(&[(1, 1), (7, 10)], &[(4, 1)])); + + assert!(overlaps(&[(1, 4), (7, 10)], &[(3, 3)])); + assert!(overlaps(&[(4, 1), (7, 10)], &[(3, 3)])); + assert!(overlaps(&[(3, 3), (7, 10)], &[(1, 4)])); + assert!(overlaps(&[(3, 3), (7, 10)], &[(4, 1)])); + + assert!(overlaps(&[(1, 4)], &[(1, 1), (7, 10)])); + assert!(overlaps(&[(4, 1)], &[(1, 1), (7, 10)])); + assert!(overlaps(&[(1, 1)], &[(1, 4), (7, 10)])); + assert!(overlaps(&[(1, 1)], &[(4, 1), (7, 10)])); + + assert!(overlaps(&[(1, 4)], &[(3, 3), (7, 10)])); + assert!(overlaps(&[(4, 1)], &[(3, 3), (7, 10)])); + assert!(overlaps(&[(3, 3)], &[(1, 4), (7, 10)])); + assert!(overlaps(&[(3, 3)], &[(4, 1), (7, 10)])); + + // Two zero-width ranges, no overlap. + assert!(!overlaps(&[(0, 0)], &[(1, 1)])); + assert!(!overlaps(&[(1, 1)], &[(0, 0)])); + + assert!(!overlaps(&[(0, 0), (2, 2)], &[(1, 1)])); + assert!(!overlaps(&[(0, 0), (2, 2)], &[(1, 1)])); + assert!(!overlaps(&[(1, 1)], &[(0, 0), (2, 2)])); + assert!(!overlaps(&[(1, 1)], &[(0, 0), (2, 2)])); + + // Two zero-width ranges, overlap. + assert!(overlaps(&[(1, 1)], &[(1, 1)])); + assert!(overlaps(&[(1, 1), (2, 2)], &[(1, 1)])); + assert!(overlaps(&[(1, 1)], &[(1, 1), (2, 2)])); + } + + #[test] fn test_grapheme_aligned() { let r = Rope::from_str("\r\nHi\r\n"); let s = r.slice(..); @@ -1378,9 +1675,15 @@ mod test { // multiple matches assert!(contains(vec!((1, 1), (2, 2)), vec!((1, 1), (2, 2)))); - // smaller set can't contain bigger + // extra items out of range assert!(!contains(vec!((1, 1)), vec!((1, 1), (2, 2)))); + // one big range can contain multiple smaller ranges + assert!(contains( + vec!((1, 10)), + vec!((1, 1), (2, 2), (3, 3), (3, 5), (7, 10)) + )); + assert!(contains( vec!((1, 1), (2, 4), (5, 6), (7, 9), (10, 13)), vec!((3, 4), (7, 9)) @@ -1393,4 +1696,143 @@ mod test { vec!((1, 2), (3, 4), (7, 9)) )); } + + #[test] + fn test_selection_without() { + let without = |one, two, expected: Option<_>| { + println!("one: {:?}", one); + println!("two: {:?}", two); + println!("expected: {:?}", expected); + + let (one_text, one_sel) = test::print(one); + let (two_text, two_sel) = test::print(two); + assert_eq!(one_text, two_text); // sanity + let actual_sel = one_sel.without(&two_sel); + + let expected_sel = expected.map(|exp| { + let (expected_text, expected_sel) = test::print(exp); + assert_eq!(two_text, expected_text); + expected_sel + }); + let actual = actual_sel + .as_ref() + .map(|sel| test::plain(two_text.to_string(), sel)); + + println!("actual: {:?}\n\n", actual); + + assert_eq!( + expected_sel, + actual_sel, + "expected: {:?}, got: {:?}", + expected_sel + .as_ref() + .map(|sel| test::plain(two_text.to_string(), sel)), + actual, + ); + }; + + without( + "#[foo bar baz|]#", + "foo #[bar|]# baz", + Some("#[foo |]#bar#( baz|)#"), + ); + + without("#[foo bar baz|]#", "#[foo bar baz|]#", None); + without("#[foo bar|]# baz", "#[foo bar baz|]#", None); + without("foo #[bar|]# baz", "#[foo bar baz|]#", None); + + // direction is preserved + without( + "#[|foo bar baz]#", + "foo #[|bar]# baz", + Some("#[|foo ]#bar#(| baz)#"), + ); + + // preference for direction is given to the left + without( + "#[|foo bar baz]#", + "foo #[bar|]# baz", + Some("#[|foo ]#bar#(| baz)#"), + ); + + // disjoint ranges on the right are ignored + without( + "#[foo bar|]# baz", + "foo bar #[baz|]#", + Some("#[foo bar|]# baz"), + ); + without( + "#[foo bar|]# baz", + "foo bar#[ baz|]#", + Some("#[foo bar|]# baz"), + ); + without( + "#(foo|)# #[bar|]# baz", + "foo#[ b|]#ar ba#(z|)#", + Some("#(foo|)# b#[ar|]# baz"), + ); + + // ranges contained by those one on the right are removed + without( + "#[foo bar|]# #(b|)#az", + "foo bar#[ b|]#a#(z|)#", + Some("#[foo bar|]# baz"), + ); + without( + "#[foo|]# bar #(baz|)#", + "foo bar#[ b|]#a#(z|)#", + Some("#[foo|]# bar b#(a|)#z"), + ); + without( + "#[foo bar|]# #(b|)#az", + "foo bar #[b|]#a#(z|)#", + Some("#[foo bar|]# baz"), + ); + without( + "#[foo bar|]# #(b|)#a#(z|)#", + "foo bar #[b|]#a#(z|)#", + Some("#[foo bar|]# baz"), + ); + without( + "#[foo bar|]# #(b|)#a#(z|)#", + "foo bar #[b|]#a#(z|)#", + Some("#[foo bar|]# baz"), + ); + + // more than one range intersected by a single range on the right + without( + "#[foo bar|]# #(baz|)#", + "foo b#[ar ba|]#z", + Some("#[foo b|]#ar ba#(z|)#"), + ); + + // partial overlap + without( + "#[foo bar|]# baz", + "foo #[bar baz|]#", + Some("#[foo |]#bar baz"), + ); + without( + "#[foo bar|]# baz", + "foo#[ bar baz|]#", + Some("#[foo|]# bar baz"), + ); + without( + "#[foo bar|]# baz", + "foo ba#[r baz|]#", + Some("#[foo ba|]#r baz"), + ); + without( + "foo ba#[r baz|]#", + "#[foo bar|]# baz", + Some("foo bar#[ baz|]#"), + ); + + // primary selection is moved - preference given to the left of a split + without( + "#(|foo)# #(|bar baz)# #[|quux]#", + "f#(o|)#o ba#[r b|]#az q#(uu|)#x", + Some("#(|f)#o#(|o)# #(|ba)#r b#(|az)# #[|q]#uu#(|x)#"), + ); + } } diff --git a/helix-core/src/snippets.rs b/helix-core/src/snippets.rs index 477c9e75..3dd3b9c3 100644 --- a/helix-core/src/snippets.rs +++ b/helix-core/src/snippets.rs @@ -1,6 +1,6 @@ mod active; mod elaborate; -pub mod parser; +mod parser; mod render; #[derive(PartialEq, Eq, Hash, Debug, PartialOrd, Ord, Clone, Copy)] diff --git a/helix-core/src/snippets/elaborate.rs b/helix-core/src/snippets/elaborate.rs index b17c149f..012d1db7 100644 --- a/helix-core/src/snippets/elaborate.rs +++ b/helix-core/src/snippets/elaborate.rs @@ -361,7 +361,7 @@ impl Transform { } } FormatItem::Conditional(i, ref if_, ref else_) => { - if cap.get_group(i).is_none_or(|mat| mat.is_empty()) { + if cap.get_group(i).map_or(true, |mat| mat.is_empty()) { buf.push_str(else_) } else { buf.push_str(if_) diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 4bc177ef..1845686a 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -90,7 +90,7 @@ impl LanguageData { Ok(Some(config)) } - pub fn syntax_config(&self, loader: &Loader) -> Option<&SyntaxConfig> { + fn syntax_config(&self, loader: &Loader) -> Option<&SyntaxConfig> { self.syntax .get_or_init(|| { Self::compile_syntax_config(&self.config, loader) @@ -238,7 +238,7 @@ impl LanguageData { } } -pub fn reconfigure_highlights(config: &SyntaxConfig, recognized_names: &[String]) { +fn reconfigure_highlights(config: &SyntaxConfig, recognized_names: &[String]) { config.configure(move |capture_name| { let capture_parts: Vec<_> = capture_name.split('.').collect(); @@ -512,7 +512,7 @@ impl FileTypeGlobMatcher { #[derive(Debug)] pub struct Syntax { - pub inner: tree_house::Syntax, + inner: tree_house::Syntax, } const PARSE_TIMEOUT: Duration = Duration::from_millis(500); // half a second is pretty generous @@ -562,15 +562,15 @@ impl Syntax { self.inner.tree_for_byte_range(start, end) } - pub fn named_descendant_for_byte_range(&self, start: u32, end: u32) -> Option<Node<'_>> { + pub fn named_descendant_for_byte_range(&self, start: u32, end: u32) -> Option<Node> { self.inner.named_descendant_for_byte_range(start, end) } - pub fn descendant_for_byte_range(&self, start: u32, end: u32) -> Option<Node<'_>> { + pub fn descendant_for_byte_range(&self, start: u32, end: u32) -> Option<Node> { self.inner.descendant_for_byte_range(start, end) } - pub fn walk(&self) -> TreeCursor<'_> { + pub fn walk(&self) -> TreeCursor { self.inner.walk() } @@ -1073,7 +1073,7 @@ fn node_is_visible(node: &Node) -> bool { node.is_missing() || (node.is_named() && node.grammar().node_kind_is_visible(node.kind_id())) } -fn format_anonymous_node_kind(kind: &str) -> Cow<'_, str> { +fn format_anonymous_node_kind(kind: &str) -> Cow<str> { if kind.contains('"') { Cow::Owned(kind.replace('"', "\\\"")) } else { @@ -1130,6 +1130,7 @@ fn pretty_print_tree_impl<W: fmt::Write>( } /// Finds the child of `node` which contains the given byte range. + pub fn child_for_byte_range<'a>(node: &Node<'a>, range: ops::Range<u32>) -> Option<Node<'a>> { for child in node.children() { let child_range = child.byte_range(); @@ -1203,24 +1204,7 @@ mod test { ); let language = LOADER.language_for_name("rust").unwrap(); - dbg!(language); let grammar = LOADER.get_config(language).unwrap().grammar; - dbg!(grammar); - let syntax = Syntax::new(source.slice(..), language, &LOADER).unwrap(); - let mut h = syntax.highlighter( - "fn main() { 4 + 2; }".into(), - &LOADER, - 0.."fn main() { 4 + 2; }".len() as u32, - ); - - for n in 0..5 { - dbg!(h.active_highlights().collect::<Vec<_>>()); - dbg!(h.next_event_offset()); - let (e, h) = h.advance(); - dbg!(h.collect::<Vec<_>>(), e); - // panic!() - } - let query = Query::new(grammar, query_str, |_, _| Ok(())).unwrap(); let textobject = TextObjectQuery::new(query); let syntax = Syntax::new(source.slice(..), language, &LOADER).unwrap(); @@ -1385,24 +1369,4 @@ mod test { source.len(), ); } - #[test] - fn highlight() { - let source = Rope::from_str(r#"assert_eq!(0, Some(0));"#); - let loader = crate::config::default_lang_loader(); - loader.set_scopes(vec!["punctuation".to_string()]); - let language = loader.language_for_name("rust").unwrap(); - - let syntax = Syntax::new(source.slice(..), language, &loader).unwrap(); - println!( - "{}", - tree_house::fixtures::highlighter_fixture( - "", - &loader, - |_| "punct".to_string(), - &syntax.inner, - source.slice(..), - .., - ) - ); - } } diff --git a/helix-core/src/syntax/config.rs b/helix-core/src/syntax/config.rs index d2e03078..f9fba3d1 100644 --- a/helix-core/src/syntax/config.rs +++ b/helix-core/src/syntax/config.rs @@ -270,7 +270,6 @@ pub enum LanguageServerFeature { WorkspaceSymbols, // Symbols, use bitflags, see above? Diagnostics, - PullDiagnostics, RenameSymbol, InlayHints, DocumentColors, @@ -295,7 +294,6 @@ impl Display for LanguageServerFeature { DocumentSymbols => "document-symbols", WorkspaceSymbols => "workspace-symbols", Diagnostics => "diagnostics", - PullDiagnostics => "pull-diagnostics", RenameSymbol => "rename-symbol", InlayHints => "inlay-hints", DocumentColors => "document-colors", diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs index 37be2e2e..b419ccf8 100644 --- a/helix-core/src/transaction.rs +++ b/helix-core/src/transaction.rs @@ -361,7 +361,6 @@ impl ChangeSet { pos += s.chars().count(); } } - println!("=>\n{text}"); } true } @@ -521,9 +520,52 @@ impl ChangeSet { pos } - pub fn changes_iter(&self) -> ChangeIterator<'_> { + pub fn changes_iter(&self) -> ChangeIterator { ChangeIterator::new(self) } + + pub fn from_change(doc: &Rope, change: Change) -> Self { + Self::from_changes(doc, std::iter::once(change)) + } + + /// Generate a ChangeSet from a set of changes. + pub fn from_changes<I>(doc: &Rope, changes: I) -> Self + where + I: Iterator<Item = Change>, + { + let len = doc.len_chars(); + + let (lower, upper) = changes.size_hint(); + let size = upper.unwrap_or(lower); + let mut changeset = ChangeSet::with_capacity(2 * size + 1); // rough estimate + + let mut last = 0; + for (from, to, tendril) in changes { + // Verify ranges are ordered and not overlapping + debug_assert!(last <= from); + // Verify ranges are correct + debug_assert!( + from <= to, + "Edit end must end before it starts (should {from} <= {to})" + ); + + // Retain from last "to" to current "from" + changeset.retain(from - last); + let span = to - from; + match tendril { + Some(text) => { + changeset.insert(text); + changeset.delete(span); + } + None => changeset.delete(span), + } + last = to; + } + + changeset.retain(len - last); + + changeset + } } /// Transaction represents a single undoable unit of changes. Several changes can be grouped into @@ -617,38 +659,7 @@ impl Transaction { where I: Iterator<Item = Change>, { - let len = doc.len_chars(); - - let (lower, upper) = changes.size_hint(); - let size = upper.unwrap_or(lower); - let mut changeset = ChangeSet::with_capacity(2 * size + 1); // rough estimate - - let mut last = 0; - for (from, to, tendril) in changes { - // Verify ranges are ordered and not overlapping - debug_assert!(last <= from); - // Verify ranges are correct - debug_assert!( - from <= to, - "Edit end must end before it starts (should {from} <= {to})" - ); - - // Retain from last "to" to current "from" - changeset.retain(from - last); - let span = to - from; - match tendril { - Some(text) => { - changeset.insert(text); - changeset.delete(span); - } - None => changeset.delete(span), - } - last = to; - } - - changeset.retain(len - last); - - Self::from(changeset) + Self::from(ChangeSet::from_changes(doc, changes)) } /// Generate a transaction from a set of potentially overlapping deletions @@ -737,9 +748,60 @@ impl Transaction { ) } + /// Generate a transaction with a change per selection range, which + /// generates a new selection as well. Each range is operated upon by + /// the given function and can optionally produce a new range. If none + /// is returned by the function, that range is mapped through the change + /// as usual. + pub fn change_by_and_with_selection<F>(doc: &Rope, selection: &Selection, mut f: F) -> Self + where + F: FnMut(&Range) -> (Change, Option<Range>), + { + let mut end_ranges = SmallVec::with_capacity(selection.len()); + let mut offset = 0; + + let transaction = Transaction::change_by_selection(doc, selection, |start_range| { + let ((from, to, replacement), end_range) = f(start_range); + let mut change_size = to as isize - from as isize; + + if let Some(ref text) = replacement { + change_size = text.chars().count() as isize - change_size; + } else { + change_size = -change_size; + } + + let new_range = if let Some(end_range) = end_range { + end_range + } else { + let changeset = ChangeSet::from_change(doc, (from, to, replacement.clone())); + start_range.map(&changeset) + }; + + let offset_range = Range::new( + (new_range.anchor as isize + offset) as usize, + (new_range.head as isize + offset) as usize, + ); + + end_ranges.push(offset_range); + offset += change_size; + + log::trace!( + "from: {}, to: {}, replacement: {:?}, offset: {}", + from, + to, + replacement, + offset + ); + + (from, to, replacement) + }); + + transaction.with_selection(Selection::new(end_ranges, selection.primary_index())) + } + /// Generate a transaction with a deletion per selection range. /// Compared to using `change_by_selection` directly these ranges may overlap. - /// In that case they are merged + /// In that case they are merged. pub fn delete_by_selection<F>(doc: &Rope, selection: &Selection, f: F) -> Self where F: FnMut(&Range) -> Deletion, @@ -747,6 +809,59 @@ impl Transaction { Self::delete(doc, selection.iter().map(f)) } + /// Generate a transaction with a delete per selection range, which + /// generates a new selection as well. Each range is operated upon by + /// the given function and can optionally produce a new range. If none + /// is returned by the function, that range is mapped through the change + /// as usual. + /// + /// Compared to using `change_by_and_with_selection` directly these ranges + /// may overlap. In that case they are merged. + pub fn delete_by_and_with_selection<F>(doc: &Rope, selection: &Selection, mut f: F) -> Self + where + F: FnMut(&Range) -> (Deletion, Option<Range>), + { + let mut end_ranges = SmallVec::with_capacity(selection.len()); + let mut offset = 0; + let mut last = 0; + + let transaction = Transaction::delete_by_selection(doc, selection, |start_range| { + let ((from, to), end_range) = f(start_range); + + // must account for possibly overlapping deletes + let change_size = if last > from { to - last } else { to - from }; + + let new_range = if let Some(end_range) = end_range { + end_range + } else { + let changeset = ChangeSet::from_change(doc, (from, to, None)); + start_range.map(&changeset) + }; + + let offset_range = Range::new( + new_range.anchor.saturating_sub(offset), + new_range.head.saturating_sub(offset), + ); + + log::trace!( + "delete from: {}, to: {}, offset: {}, new_range: {:?}, offset_range: {:?}", + from, + to, + offset, + new_range, + offset_range + ); + + end_ranges.push(offset_range); + offset += change_size; + last = to; + + (from, to) + }); + + transaction.with_selection(Selection::new(end_ranges, selection.primary_index())) + } + /// Insert text at each selection head. pub fn insert(doc: &Rope, selection: &Selection, text: Tendril) -> Self { Self::change_by_selection(doc, selection, |range| { @@ -754,7 +869,7 @@ impl Transaction { }) } - pub fn changes_iter(&self) -> ChangeIterator<'_> { + pub fn changes_iter(&self) -> ChangeIterator { self.changes.changes_iter() } } diff --git a/helix-dap/Cargo.toml b/helix-dap/Cargo.toml index 000ea5a8..8033c757 100644 --- a/helix-dap/Cargo.toml +++ b/helix-dap/Cargo.toml @@ -26,7 +26,7 @@ slotmap.workspace = true futures-executor.workspace = true futures-util.workspace = true tokio-stream.workspace = true -sonic-rs.workspace = true + [dev-dependencies] fern = "0.7" diff --git a/helix-dap/src/client.rs b/helix-dap/src/client.rs index fe4af188..e5824a7f 100644 --- a/helix-dap/src/client.rs +++ b/helix-dap/src/client.rs @@ -231,11 +231,7 @@ impl Client { } fn next_request_id(&self) -> u64 { - // > The `seq` for the first message sent by a client or debug adapter - // > is 1, and for each subsequent message is 1 greater than the - // > previous message sent by that actor - // <https://microsoft.github.io/debug-adapter-protocol/specification#Base_Protocol_ProtocolMessage> - self.request_counter.fetch_add(1, Ordering::Relaxed) + 1 + self.request_counter.fetch_add(1, Ordering::Relaxed) } // Internal, called by specific DAP commands when resuming diff --git a/helix-dap/src/lib.rs b/helix-dap/src/lib.rs index 4cb95315..16c84f66 100644 --- a/helix-dap/src/lib.rs +++ b/helix-dap/src/lib.rs @@ -13,7 +13,7 @@ use thiserror::Error; #[derive(Error, Debug)] pub enum Error { #[error("failed to parse: {0}")] - Parse(Box<dyn std::error::Error + Send + Sync>), + Parse(#[from] serde_json::Error), #[error("IO Error: {0}")] IO(#[from] std::io::Error), #[error("request {0} timed out")] @@ -29,18 +29,6 @@ pub enum Error { } pub type Result<T> = core::result::Result<T, Error>; -impl From<serde_json::Error> for Error { - fn from(value: serde_json::Error) -> Self { - Self::Parse(Box::new(value)) - } -} - -impl From<sonic_rs::Error> for Error { - fn from(value: sonic_rs::Error) -> Self { - Self::Parse(Box::new(value)) - } -} - #[derive(Debug)] pub enum Request { RunInTerminal(<requests::RunInTerminal as types::Request>::Arguments), diff --git a/helix-dap/src/transport.rs b/helix-dap/src/transport.rs index fdd60226..8ca408df 100644 --- a/helix-dap/src/transport.rs +++ b/helix-dap/src/transport.rs @@ -125,14 +125,12 @@ impl Transport { info!("[{}] <- DAP {}", id, msg); - // NOTE: We avoid using `?` here, since it would return early on error - // and skip clearing `content`. By returning the result directly instead, - // we ensure `content.clear()` is always called. - let output = sonic_rs::from_slice(content).map_err(Into::into); + // try parsing as output (server response) or call (server request) + let output: serde_json::Result<Payload> = serde_json::from_str(msg); content.clear(); - output + Ok(output?) } async fn recv_server_error( diff --git a/helix-loader/src/lib.rs b/helix-loader/src/lib.rs index 705e016b..9872b77a 100644 --- a/helix-loader/src/lib.rs +++ b/helix-loader/src/lib.rs @@ -64,6 +64,7 @@ fn prioritize_runtime_dirs() -> Vec<PathBuf> { if let Some(dir) = std::option_env!("HELIX_DEFAULT_RUNTIME") { rt_dirs.push(dir.into()); } + // fallback to location of the executable being run // canonicalize the path in case the executable is symlinked let exe_rt_dir = std::env::current_exe() @@ -72,7 +73,6 @@ fn prioritize_runtime_dirs() -> Vec<PathBuf> { .and_then(|path| path.parent().map(|path| path.to_path_buf().join(RT_DIR))) .unwrap(); rt_dirs.push(exe_rt_dir); - rt_dirs.push(PathBuf::from("/usr/lib/helix/runtime/")); rt_dirs } diff --git a/helix-lsp-types/Cargo.toml b/helix-lsp-types/Cargo.toml index 26f004b2..f0905de2 100644 --- a/helix-lsp-types/Cargo.toml +++ b/helix-lsp-types/Cargo.toml @@ -22,8 +22,8 @@ license = "MIT" [dependencies] bitflags.workspace = true -serde = { version = "1.0.228", features = ["derive"] } -serde_json = "1.0.145" +serde = { version = "1.0.219", features = ["derive"] } +serde_json = "1.0.143" url = {version = "2.5.4", features = ["serde"]} [features] diff --git a/helix-lsp-types/src/code_action.rs b/helix-lsp-types/src/code_action.rs index ed9532f0..6cc39e0d 100644 --- a/helix-lsp-types/src/code_action.rs +++ b/helix-lsp-types/src/code_action.rs @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; -use std::{borrow::Cow, marker::StructuralPartialEq, ops::DerefPure}; +use std::borrow::Cow; #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] #[serde(untagged)] pub enum CodeActionProviderCapability { @@ -129,7 +129,6 @@ pub struct CodeActionParams { /// response for CodeActionRequest pub type CodeActionResponse = Vec<CodeActionOrCommand>; -#[allow(clippy::large_enum_variant)] // TODO: In a separate PR attempt the `Box<CodeAction>` pattern. #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] #[serde(untagged)] pub enum CodeActionOrCommand { @@ -149,23 +148,8 @@ impl From<CodeAction> for CodeActionOrCommand { } } -#[derive(Debug, Eq, PartialOrd, Hash, Clone, Deserialize, Serialize)] -pub struct CodeActionKind(pub Cow<'static, str>); - -impl std::ops::Deref for CodeActionKind { - type Target = str; - - fn deref(&self) -> &Self::Target { - self.as_str() - } -} -impl PartialEq for CodeActionKind { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } -} -impl StructuralPartialEq for CodeActionKind {} -unsafe impl DerefPure for CodeActionKind {} +#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] +pub struct CodeActionKind(Cow<'static, str>); impl CodeActionKind { /// Empty kind. @@ -308,9 +292,6 @@ pub struct CodeAction { /// @since 3.16.0 #[serde(skip_serializing_if = "Option::is_none")] pub data: Option<Value>, - - #[serde(skip_serializing_if = "Option::is_none")] - pub group: Option<String>, } #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] diff --git a/helix-lsp-types/src/completion.rs b/helix-lsp-types/src/completion.rs index 793252de..7c006bdb 100644 --- a/helix-lsp-types/src/completion.rs +++ b/helix-lsp-types/src/completion.rs @@ -24,7 +24,7 @@ impl InsertTextFormat { /// The kind of a completion entry. #[derive(Eq, PartialEq, Clone, Copy, Serialize, Deserialize)] #[serde(transparent)] -pub struct CompletionItemKind(pub i32); +pub struct CompletionItemKind(i32); lsp_enum! { impl CompletionItemKind { pub const TEXT: CompletionItemKind = CompletionItemKind(1); diff --git a/helix-lsp-types/src/document_symbols.rs b/helix-lsp-types/src/document_symbols.rs index a88e7376..3f482e16 100644 --- a/helix-lsp-types/src/document_symbols.rs +++ b/helix-lsp-types/src/document_symbols.rs @@ -98,8 +98,6 @@ pub struct DocumentSymbol { /// The range that should be selected and revealed when this symbol is being picked, e.g the name of a function. /// Must be contained by the the `range`. pub selection_range: Range, - /// For sticky context. Default to selection_range. - pub sticky_range: Option<Range>, /// Children of this symbol, e.g. properties of a class. #[serde(skip_serializing_if = "Option::is_none")] pub children: Option<Vec<DocumentSymbol>>, diff --git a/helix-lsp-types/src/lib.rs b/helix-lsp-types/src/lib.rs index 187369ed..fd668de5 100644 --- a/helix-lsp-types/src/lib.rs +++ b/helix-lsp-types/src/lib.rs @@ -15,7 +15,8 @@ able to parse any URI, such as `urn:isbn:0451450523`. */ #![allow(non_upper_case_globals)] -#![feature(deref_pure_trait, structural_match)] +#![forbid(unsafe_code)] + use bitflags::bitflags; use std::{collections::HashMap, fmt::Debug}; @@ -71,9 +72,6 @@ macro_rules! lsp_enum { $(#[$attr])* pub const $name: $enum_type = $value; )* - pub const ALL: &[$typ] = &[ - $($value,)+ - ]; } impl std::fmt::Debug for $typ { @@ -212,16 +210,6 @@ pub enum NumberOrString { Number(i32), String(String), } -impl From<i32> for NumberOrString { - fn from(v: i32) -> Self { - Self::Number(v) - } -} -impl From<&i32> for NumberOrString { - fn from(&v: &i32) -> Self { - Self::Number(v) - } -} /* ----------------- Cancel support ----------------- */ @@ -586,7 +574,7 @@ pub struct TextDocumentEdit { /// /// @since 3.16.0 - support for AnnotatedTextEdit. This is guarded by the /// client capability `workspace.workspaceEdit.changeAnnotationSupport` - pub edits: Vec<SnippetTextEdit>, + pub edits: Vec<OneOf<TextEdit, AnnotatedTextEdit>>, } /// Additional information that describes document changes. @@ -709,18 +697,6 @@ pub struct DeleteFile { pub options: Option<DeleteFileOptions>, } -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SnippetTextEdit { - pub range: Range, - pub new_text: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub insert_text_format: Option<InsertTextFormat>, - /// The annotation id if this is an annotated - #[serde(skip_serializing_if = "Option::is_none")] - pub annotation_id: Option<ChangeAnnotationIdentifier>, -} - /// A workspace edit represents changes to many resources managed in the workspace. /// The edit should either provide `changes` or `documentChanges`. /// If the client can handle versioned document edits and if `documentChanges` are present, @@ -1265,7 +1241,7 @@ pub enum FailureHandlingKind { /// A symbol kind. #[derive(Eq, PartialEq, Copy, Clone, Serialize, Deserialize)] #[serde(transparent)] -pub struct SymbolKind(pub i32); +pub struct SymbolKind(i32); lsp_enum! { impl SymbolKind { pub const FILE: SymbolKind = SymbolKind(1); @@ -1294,19 +1270,6 @@ impl SymbolKind { pub const EVENT: SymbolKind = SymbolKind(24); pub const OPERATOR: SymbolKind = SymbolKind(25); pub const TYPE_PARAMETER: SymbolKind = SymbolKind(26); - - pub const MACRO: SymbolKind = SymbolKind(50); - pub const PROC_MACRO: SymbolKind = SymbolKind(51); - pub const BUILTIN_ATTRIBUTE: SymbolKind = SymbolKind(52); - pub const ATTRIBUTE: SymbolKind = SymbolKind(53); - pub const DERIVE: SymbolKind = SymbolKind(54); - pub const DERIVE_HELPER: SymbolKind = SymbolKind(55); - pub const TYPE_ALIAS: SymbolKind = SymbolKind(56); - pub const LOCAL: SymbolKind = SymbolKind(57); - pub const LABEL: SymbolKind = SymbolKind(58); - pub const LIFETIME: SymbolKind = SymbolKind(59); - pub const VALUE: SymbolKind = SymbolKind(60); - } } @@ -2591,7 +2554,7 @@ impl PublishDiagnosticsParams { } } -#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone, Hash)] +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] #[serde(untagged)] pub enum Documentation { String(String), @@ -2608,14 +2571,14 @@ pub enum Documentation { /// <pre><code>```${language} /// ${value} /// ```</code></pre> -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize, Hash)] +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] #[serde(untagged)] pub enum MarkedString { String(String), LanguageString(LanguageString), } -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize, Hash)] +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] pub struct LanguageString { pub language: String, pub value: String, @@ -2734,7 +2697,7 @@ pub struct ApplyWorkspaceEditResponse { /// /// Please note that `MarkupKinds` must not start with a `$`. This kinds /// are reserved for internal usage. -#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone, Hash)] +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] #[serde(rename_all = "lowercase")] pub enum MarkupKind { /// Plain text is supported as a content format @@ -2766,7 +2729,7 @@ pub enum MarkupKind { /// /// Please *Note* that clients might sanitize the return markdown. A client could decide to /// remove HTML from the markdown to avoid script execution. -#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone, Hash)] +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] pub struct MarkupContent { pub kind: MarkupKind, pub value: String, diff --git a/helix-lsp-types/src/progress.rs b/helix-lsp-types/src/progress.rs index 61552fdb..41fa74f9 100644 --- a/helix-lsp-types/src/progress.rs +++ b/helix-lsp-types/src/progress.rs @@ -40,6 +40,14 @@ pub struct WorkDoneProgressCancelParams { pub token: ProgressToken, } +/// Options to signal work done progress support in server capabilities. +#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressOptions { + #[serde(skip_serializing_if = "Option::is_none")] + pub work_done_progress: Option<bool>, +} + /// An optional token that a server can use to report work done progress #[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] #[serde(rename_all = "camelCase")] diff --git a/helix-lsp-types/src/semantic_tokens.rs b/helix-lsp-types/src/semantic_tokens.rs index b4448aa7..842558ba 100644 --- a/helix-lsp-types/src/semantic_tokens.rs +++ b/helix-lsp-types/src/semantic_tokens.rs @@ -153,7 +153,7 @@ pub struct SemanticToken { } impl SemanticToken { - pub fn deserialize_tokens<'de, D>(deserializer: D) -> Result<Vec<SemanticToken>, D::Error> + fn deserialize_tokens<'de, D>(deserializer: D) -> Result<Vec<SemanticToken>, D::Error> where D: serde::Deserializer<'de>, { @@ -177,7 +177,7 @@ impl SemanticToken { ) } - pub fn serialize_tokens<S>(tokens: &[SemanticToken], serializer: S) -> Result<S::Ok, S::Error> + fn serialize_tokens<S>(tokens: &[SemanticToken], serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer, { @@ -192,7 +192,7 @@ impl SemanticToken { seq.end() } - pub fn deserialize_tokens_opt<'de, D>( + fn deserialize_tokens_opt<'de, D>( deserializer: D, ) -> Result<Option<Vec<SemanticToken>>, D::Error> where @@ -208,7 +208,7 @@ impl SemanticToken { Ok(Option::<Wrapper>::deserialize(deserializer)?.map(|wrapper| wrapper.tokens)) } - pub fn serialize_tokens_opt<S>( + fn serialize_tokens_opt<S>( data: &Option<Vec<SemanticToken>>, serializer: S, ) -> Result<S::Ok, S::Error> diff --git a/helix-lsp-types/src/workspace_diagnostic.rs b/helix-lsp-types/src/workspace_diagnostic.rs index c24690f0..485dcc2b 100644 --- a/helix-lsp-types/src/workspace_diagnostic.rs +++ b/helix-lsp-types/src/workspace_diagnostic.rs @@ -37,7 +37,7 @@ pub struct PreviousResultId { /// Parameters of the workspace diagnostic request. /// /// @since 3.17.0 -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize, Default)] +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct WorkspaceDiagnosticParams { /// The additional identifier provided during registration. diff --git a/helix-lsp-types/src/workspace_symbols.rs b/helix-lsp-types/src/workspace_symbols.rs index 68e78f83..9ba80895 100644 --- a/helix-lsp-types/src/workspace_symbols.rs +++ b/helix-lsp-types/src/workspace_symbols.rs @@ -36,8 +36,8 @@ pub struct WorkspaceSymbolClientCapabilities { pub resolve_support: Option<WorkspaceSymbolResolveSupportCapability>, } +/// The parameters of a Workspace Symbol Request. #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] pub struct WorkspaceSymbolParams { #[serde(flatten)] pub partial_result_params: PartialResultParams, @@ -47,24 +47,6 @@ pub struct WorkspaceSymbolParams { /// A non-empty query string pub query: String, - - pub search_scope: Option<WorkspaceSymbolSearchScope>, - - pub search_kind: Option<WorkspaceSymbolSearchKind>, -} - -#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] -#[serde(rename_all = "camelCase")] -pub enum WorkspaceSymbolSearchScope { - Workspace, - WorkspaceAndDependencies, -} - -#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] -#[serde(rename_all = "camelCase")] -pub enum WorkspaceSymbolSearchKind { - OnlyTypes, - AllSymbols, } #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml index 6156be9a..20c3e78b 100644 --- a/helix-lsp/Cargo.toml +++ b/helix-lsp/Cargo.toml @@ -21,14 +21,13 @@ helix-lsp-types = { path = "../helix-lsp-types" } anyhow = "1.0" futures-executor.workspace = true futures-util.workspace = true -globset.workspace = true +globset = "0.4.16" log = "0.4" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -tokio = { version = "1.48", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } +tokio = { version = "1.47", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } tokio-stream.workspace = true parking_lot.workspace = true arc-swap = "1" slotmap.workspace = true thiserror.workspace = true -sonic-rs.workspace = true diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs index 22a8dd89..afb3b3a5 100644 --- a/helix-lsp/src/client.rs +++ b/helix-lsp/src/client.rs @@ -372,7 +372,6 @@ impl Client { Some(OneOf::Left(true) | OneOf::Right(_)) ), LanguageServerFeature::Diagnostics => true, // there's no extra server capability - LanguageServerFeature::PullDiagnostics => capabilities.diagnostic_provider.is_some(), LanguageServerFeature::RenameSymbol => matches!( capabilities.rename_provider, Some(OneOf::Left(true)) | Some(OneOf::Right(_)) @@ -603,9 +602,6 @@ impl Client { did_rename: Some(true), ..Default::default() }), - diagnostic: Some(lsp::DiagnosticWorkspaceClientCapabilities { - refresh_support: Some(true), - }), ..Default::default() }), text_document: Some(lsp::TextDocumentClientCapabilities { @@ -683,10 +679,6 @@ impl Client { }), ..Default::default() }), - diagnostic: Some(lsp::DiagnosticClientCapabilities { - dynamic_registration: Some(false), - related_document_support: Some(true), - }), publish_diagnostics: Some(lsp::PublishDiagnosticsClientCapabilities { version_support: Some(true), tag_support: Some(lsp::TagSupport { @@ -1237,32 +1229,6 @@ impl Client { Some(self.call::<lsp::request::RangeFormatting>(params)) } - pub fn text_document_diagnostic( - &self, - text_document: lsp::TextDocumentIdentifier, - previous_result_id: Option<String>, - ) -> Option<impl Future<Output = Result<lsp::DocumentDiagnosticReportResult>>> { - let capabilities = self.capabilities(); - - // Return early if the server does not support pull diagnostic. - let identifier = match capabilities.diagnostic_provider.as_ref()? { - lsp::DiagnosticServerCapabilities::Options(cap) => cap.identifier.clone(), - lsp::DiagnosticServerCapabilities::RegistrationOptions(cap) => { - cap.diagnostic_options.identifier.clone() - } - }; - - let params = lsp::DocumentDiagnosticParams { - text_document, - identifier, - previous_result_id, - work_done_progress_params: lsp::WorkDoneProgressParams::default(), - partial_result_params: lsp::PartialResultParams::default(), - }; - - Some(self.call::<lsp::request::DocumentDiagnosticRequest>(params)) - } - pub fn text_document_document_highlight( &self, text_document: lsp::TextDocumentIdentifier, @@ -1503,7 +1469,6 @@ impl Client { query, work_done_progress_params: lsp::WorkDoneProgressParams::default(), partial_result_params: lsp::PartialResultParams::default(), - ..Default::default() }; Some(self.call::<lsp::request::WorkspaceSymbolRequest>(params)) diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 259980dd..567e8a70 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -37,7 +37,7 @@ pub enum Error { #[error("protocol error: {0}")] Rpc(#[from] jsonrpc::Error), #[error("failed to parse: {0}")] - Parse(Box<dyn std::error::Error + Send + Sync>), + Parse(#[from] serde_json::Error), #[error("IO Error: {0}")] IO(#[from] std::io::Error), #[error("request {0} timed out")] @@ -52,18 +52,6 @@ pub enum Error { Other(#[from] anyhow::Error), } -impl From<serde_json::Error> for Error { - fn from(value: serde_json::Error) -> Self { - Self::Parse(Box::new(value)) - } -} - -impl From<sonic_rs::Error> for Error { - fn from(value: sonic_rs::Error) -> Self { - Self::Parse(Box::new(value)) - } -} - #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub enum OffsetEncoding { /// UTF-8 code units aka bytes @@ -475,7 +463,6 @@ pub enum MethodCall { RegisterCapability(lsp::RegistrationParams), UnregisterCapability(lsp::UnregistrationParams), ShowDocument(lsp::ShowDocumentParams), - WorkspaceDiagnosticRefresh, } impl MethodCall { @@ -507,7 +494,6 @@ impl MethodCall { let params: lsp::ShowDocumentParams = params.parse()?; Self::ShowDocument(params) } - lsp::request::WorkspaceDiagnosticRefresh::METHOD => Self::WorkspaceDiagnosticRefresh, _ => { return Err(Error::Unhandled); } @@ -1082,103 +1068,4 @@ mod tests { assert!(transaction.apply(&mut source)); assert_eq!(source, "[\n \"🇺🇸\",\n \"🎄\",\n]"); } - #[test] - fn rahh() { - use helix_lsp_types::*; - let th = [ - TextEdit { - range: Range { - start: Position { - line: 1, - character: 0, - }, - end: Position { - line: 1, - character: 4, - }, - }, - new_text: "".into(), - }, - TextEdit { - range: Range { - start: Position { - line: 2, - character: 0, - }, - end: Position { - line: 3, - character: 1, - }, - }, - new_text: "".into(), - }, - TextEdit { - range: Range { - start: Position { - line: 3, - character: 9, - }, - end: Position { - line: 3, - character: 9, - }, - }, - new_text: "let new =\n".into(), - }, - TextEdit { - range: Range { - start: Position { - line: 3, - character: 20, - }, - end: Position { - line: 3, - character: 29, - }, - }, - new_text: "".into(), - }, - TextEdit { - range: Range { - start: Position { - line: 3, - character: 56, - }, - end: Position { - line: 4, - character: 24, - }, - }, - new_text: "".into(), - }, - TextEdit { - range: Range { - start: Position { - line: 6, - character: 1, - }, - end: Position { - line: 6, - character: 1, - }, - }, - new_text: "\n".into(), - }, - ]; - let mut source = Rope::from_str( - "impl Editor { // 0 - pub fn open(f: &Path) { // 1 -// 2 - let new = std::fs::read_to_string(f) // 3 - .map_err(anyhow::Error::from)?; // 4 - } -}", - ); - println!("{}", source); - - let transaction = - generate_transaction_from_edits(&source, th.to_vec(), OffsetEncoding::Utf8); - assert!(transaction.apply(&mut source)); - println!("{}", source); - } } diff --git a/helix-lsp/src/transport.rs b/helix-lsp/src/transport.rs index fa4966c4..088c617b 100644 --- a/helix-lsp/src/transport.rs +++ b/helix-lsp/src/transport.rs @@ -98,7 +98,7 @@ impl Transport { buffer.clear(); if reader.read_line(buffer).await? == 0 { return Err(Error::StreamClosed); - } + }; // debug!("<- header {:?}", buffer); @@ -133,14 +133,12 @@ impl Transport { info!("{language_server_name} <- {msg}"); - // NOTE: We avoid using `?` here, since it would return early on error - // and skip clearing `content`. By returning the result directly instead, - // we ensure `content.clear()` is always called. - let output = sonic_rs::from_slice(content).map_err(Into::into); + // try parsing as output (server response) or call (server request) + let output: serde_json::Result<ServerMessage> = serde_json::from_str(msg); content.clear(); - output + Ok(output?) } async fn recv_server_error( diff --git a/helix-stdx/Cargo.toml b/helix-stdx/Cargo.toml index 66d02925..3d5c3285 100644 --- a/helix-stdx/Cargo.toml +++ b/helix-stdx/Cargo.toml @@ -26,7 +26,7 @@ unicode-segmentation.workspace = true windows-sys = { version = "0.61", features = ["Win32_Foundation", "Win32_Security", "Win32_Security_Authorization", "Win32_Storage_FileSystem", "Win32_System_Threading"] } [target.'cfg(unix)'.dependencies] -rustix = { version = "1.1", features = ["fs"] } +rustix = { version = "1.0", features = ["fs"] } [dev-dependencies] tempfile.workspace = true diff --git a/helix-stdx/src/env.rs b/helix-stdx/src/env.rs index 9e7781a0..6f9a091e 100644 --- a/helix-stdx/src/env.rs +++ b/helix-stdx/src/env.rs @@ -85,7 +85,7 @@ fn find_brace_end(src: &[u8]) -> Option<usize> { None } -fn expand_impl(src: &OsStr, mut resolve: impl FnMut(&OsStr) -> Option<OsString>) -> Cow<'_, OsStr> { +fn expand_impl(src: &OsStr, mut resolve: impl FnMut(&OsStr) -> Option<OsString>) -> Cow<OsStr> { use regex_automata::meta::Regex; static REGEX: Lazy<Regex> = Lazy::new(|| { @@ -157,7 +157,7 @@ fn expand_impl(src: &OsStr, mut resolve: impl FnMut(&OsStr) -> Option<OsString>) /// * `${<var>:-<default>}`, `${<var>-<default>}` /// * `${<var>:=<default>}`, `${<var>=default}` /// -pub fn expand<S: AsRef<OsStr> + ?Sized>(src: &S) -> Cow<'_, OsStr> { +pub fn expand<S: AsRef<OsStr> + ?Sized>(src: &S) -> Cow<OsStr> { expand_impl(src.as_ref(), |var| std::env::var_os(var)) } diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index ab9f166b..4585aaad 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -54,14 +54,14 @@ anyhow = "1" once_cell = "1.21" tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] } -tui = { path = "../helix-tui", package = "helix-tui", default-features = false, features = ["termina", "crossterm"] } +tui = { path = "../helix-tui", package = "helix-tui", default-features = false, features = ["termina"] } termina = { workspace = true, features = ["event-stream"] } signal-hook = "0.3" tokio-stream = "0.1" futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false } arc-swap = { version = "1.7.1" } termini = "1" -indexmap = "2.12" +indexmap = "2.11" # Logging fern = "0.7" @@ -70,11 +70,7 @@ log = "0.4" # File picker nucleo.workspace = true -# MSRV: update once the MSRV is >=1.85 -ignore = "=0.4.23" -grep-regex = "=0.1.13" -grep-searcher = "=0.1.14" -grep-matcher = "=0.1.7" +ignore = "0.4" # markdown doc rendering pulldown-cmark = { version = "0.13", default-features = false } # file type detection @@ -91,15 +87,15 @@ toml.workspace = true serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } -dashmap = "6.0" -tree-house = { workspace = true, features = ["fixtures"] } +# ripgrep for global search +grep-regex = "0.1.13" +grep-searcher = "0.1.14" -[target.'cfg(windows)'.dependencies] -crossterm = { version = "0.28", features = ["event-stream"] } +dashmap = "6.0" [target.'cfg(not(windows))'.dependencies] # https://github.com/vorner/signal-hook/issues/100 signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] } -libc = "0.2.177" +libc = "0.2.175" [build-dependencies] helix-loader = { path = "../helix-loader" } diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 8c1db649..c402633c 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -36,7 +36,6 @@ use std::{ sync::Arc, }; -#[cfg_attr(windows, allow(unused_imports))] use anyhow::{Context, Error}; #[cfg(not(windows))] @@ -44,27 +43,18 @@ use {signal_hook::consts::signal, signal_hook_tokio::Signals}; #[cfg(windows)] type Signals = futures_util::stream::Empty<()>; -#[cfg(all(not(windows), not(feature = "integration")))] +#[cfg(not(feature = "integration"))] use tui::backend::TerminaBackend; -#[cfg(all(windows, not(feature = "integration")))] -use tui::backend::CrosstermBackend; - #[cfg(feature = "integration")] use tui::backend::TestBackend; -#[cfg(all(not(windows), not(feature = "integration")))] +#[cfg(not(feature = "integration"))] type TerminalBackend = TerminaBackend; -#[cfg(all(windows, not(feature = "integration")))] -type TerminalBackend = CrosstermBackend<std::io::Stdout>; + #[cfg(feature = "integration")] type TerminalBackend = TestBackend; -#[cfg(not(windows))] -type TerminalEvent = termina::Event; -#[cfg(windows)] -type TerminalEvent = crossterm::event::Event; - type Terminal = tui::terminal::Terminal<TerminalBackend>; pub struct Application { @@ -77,8 +67,6 @@ pub struct Application { signals: Signals, jobs: Jobs, lsp_progress: LspProgressMap, - - theme_mode: Option<theme::Mode>, } #[cfg(feature = "integration")] @@ -114,18 +102,15 @@ impl Application { theme_parent_dirs.extend(helix_loader::runtime_dirs().iter().cloned()); let theme_loader = theme::Loader::new(&theme_parent_dirs); - #[cfg(all(not(windows), not(feature = "integration")))] + #[cfg(not(feature = "integration"))] let backend = TerminaBackend::new((&config.editor).into()) .context("failed to create terminal backend")?; - #[cfg(all(windows, not(feature = "integration")))] - let backend = CrosstermBackend::new(std::io::stdout(), (&config.editor).into()); #[cfg(feature = "integration")] let backend = TestBackend::new(120, 150); - let theme_mode = backend.get_theme_mode(); let terminal = Terminal::new(backend)?; - let area = terminal.size(); + let area = terminal.size().expect("couldn't get terminal size"); let mut compositor = Compositor::new(area); let config = Arc::new(ArcSwap::from_pointee(config)); let handlers = handlers::setup(config.clone()); @@ -142,7 +127,6 @@ impl Application { &mut editor, &config.load(), terminal.backend().supports_true_color(), - theme_mode, ); let keys = Box::new(Map::new(Arc::clone(&config), |config: &Config| { @@ -262,7 +246,6 @@ impl Application { signals, jobs: Jobs::new(), lsp_progress: LspProgressMap::new(), - theme_mode, }; Ok(app) @@ -303,7 +286,7 @@ impl Application { pub async fn event_loop<S>(&mut self, input_stream: &mut S) where - S: Stream<Item = std::io::Result<TerminalEvent>> + Unpin, + S: Stream<Item = std::io::Result<termina::Event>> + Unpin, { self.render().await; @@ -316,7 +299,7 @@ impl Application { pub async fn event_loop_until_idle<S>(&mut self, input_stream: &mut S) -> bool where - S: Stream<Item = std::io::Result<TerminalEvent>> + Unpin, + S: Stream<Item = std::io::Result<termina::Event>> + Unpin, { loop { if self.editor.should_close() { @@ -421,7 +404,6 @@ impl Application { &mut self.editor, &default_config, self.terminal.backend().supports_true_color(), - self.theme_mode, ); // Re-parse any open documents with the new language config. @@ -455,18 +437,12 @@ impl Application { } /// Load the theme set in configuration - fn load_configured_theme( - editor: &mut Editor, - config: &Config, - terminal_true_color: bool, - mode: Option<theme::Mode>, - ) { + fn load_configured_theme(editor: &mut Editor, config: &Config, terminal_true_color: bool) { let true_color = terminal_true_color || config.editor.true_color || crate::true_color(); let theme = config .theme .as_ref() - .and_then(|theme_config| { - let theme = theme_config.choose(mode); + .and_then(|theme| { editor .theme_loader .load(theme) @@ -542,7 +518,7 @@ impl Application { } // redraw the terminal - let area = self.terminal.size(); + let area = self.terminal.size().expect("couldn't get terminal size"); self.compositor.resize(area); self.terminal.clear().expect("couldn't clear terminal"); @@ -683,10 +659,7 @@ impl Application { false } - pub async fn handle_terminal_events(&mut self, event: std::io::Result<TerminalEvent>) { - #[cfg(not(windows))] - use termina::escape::csi; - + pub async fn handle_terminal_events(&mut self, event: std::io::Result<termina::Event>) { let mut cx = crate::compositor::Context { editor: &mut self.editor, jobs: &mut self.jobs, @@ -694,54 +667,23 @@ impl Application { }; // Handle key events let should_redraw = match event.unwrap() { - #[cfg(not(windows))] termina::Event::WindowResized(termina::WindowSize { rows, cols, .. }) => { self.terminal .resize(Rect::new(0, 0, cols, rows)) .expect("Unable to resize terminal"); - let area = self.terminal.size(); + let area = self.terminal.size().expect("couldn't get terminal size"); self.compositor.resize(area); self.compositor .handle_event(&Event::Resize(cols, rows), &mut cx) } - #[cfg(not(windows))] // Ignore keyboard release events. termina::Event::Key(termina::event::KeyEvent { kind: termina::event::KeyEventKind::Release, .. }) => false, - #[cfg(not(windows))] - termina::Event::Csi(csi::Csi::Mode(csi::Mode::ReportTheme(mode))) => { - Self::load_configured_theme( - &mut self.editor, - &self.config.load(), - self.terminal.backend().supports_true_color(), - Some(mode.into()), - ); - true - } - #[cfg(windows)] - TerminalEvent::Resize(width, height) => { - self.terminal - .resize(Rect::new(0, 0, width, height)) - .expect("Unable to resize terminal"); - - let area = self.terminal.size(); - - self.compositor.resize(area); - - self.compositor - .handle_event(&Event::Resize(width, height), &mut cx) - } - #[cfg(windows)] - // Ignore keyboard release events. - crossterm::event::Event::Key(crossterm::event::KeyEvent { - kind: crossterm::event::KeyEventKind::Release, - .. - }) => false, event => self.compositor.handle_event(&event.into(), &mut cx), }; @@ -1103,26 +1045,6 @@ impl Application { let result = self.handle_show_document(params, offset_encoding); Ok(json!(result)) } - Ok(MethodCall::WorkspaceDiagnosticRefresh) => { - let language_server = language_server!().id(); - - let documents: Vec<_> = self - .editor - .documents - .values() - .filter(|x| x.supports_language_server(language_server)) - .map(|x| x.id()) - .collect(); - - for document in documents { - handlers::diagnostics::request_document_diagnostics( - &mut self.editor, - document, - ); - } - - Ok(serde_json::Value::Null) - } }; let language_server = language_server!(); @@ -1210,27 +1132,15 @@ impl Application { self.terminal.restore() } - #[cfg(all(not(feature = "integration"), not(windows)))] - pub fn event_stream(&self) -> impl Stream<Item = std::io::Result<TerminalEvent>> + Unpin { - use termina::{escape::csi, Terminal as _}; + #[cfg(not(feature = "integration"))] + pub fn event_stream(&self) -> impl Stream<Item = std::io::Result<termina::Event>> + Unpin { + use termina::Terminal as _; let reader = self.terminal.backend().terminal().event_reader(); - termina::EventStream::new(reader, |event| { - // Accept either non-escape sequences or theme mode updates. - !event.is_escape() - || matches!( - event, - termina::Event::Csi(csi::Csi::Mode(csi::Mode::ReportTheme(_))) - ) - }) - } - - #[cfg(all(not(feature = "integration"), windows))] - pub fn event_stream(&self) -> impl Stream<Item = std::io::Result<TerminalEvent>> + Unpin { - crossterm::event::EventStream::new() + termina::EventStream::new(reader, |event| !event.is_escape()) } #[cfg(feature = "integration")] - pub fn event_stream(&self) -> impl Stream<Item = std::io::Result<TerminalEvent>> + Unpin { + pub fn event_stream(&self) -> impl Stream<Item = std::io::Result<termina::Event>> + Unpin { use std::{ pin::Pin, task::{Context, Poll}, @@ -1240,7 +1150,7 @@ impl Application { pub struct DummyEventStream; impl Stream for DummyEventStream { - type Item = std::io::Result<TerminalEvent>; + type Item = std::io::Result<termina::Event>; fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { Poll::Pending @@ -1252,7 +1162,7 @@ impl Application { pub async fn run<S>(&mut self, input_stream: &mut S) -> Result<i32, Error> where - S: Stream<Item = std::io::Result<TerminalEvent>> + Unpin, + S: Stream<Item = std::io::Result<termina::Event>> + Unpin, { self.terminal.claim()?; diff --git a/helix-term/src/args.rs b/helix-term/src/args.rs index 090c1192..9b1b4409 100644 --- a/helix-term/src/args.rs +++ b/helix-term/src/args.rs @@ -102,7 +102,6 @@ impl Args { } } } - "+" => line_number = usize::MAX, arg if arg.starts_with('+') => { match arg[1..].parse::<usize>() { Ok(n) => line_number = n.saturating_sub(1), diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 430d4430..c74c7429 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -530,6 +530,7 @@ impl MappableCommand { select_prev_sibling, "Select previous sibling the in syntax tree", select_all_siblings, "Select all siblings of the current node", select_all_children, "Select all children of the current node", + expand_selection_around, "Expand selection to parent syntax node, but exclude the selection you started with", jump_forward, "Jump forward on jumplist", jump_backward, "Jump backward on jumplist", save_selection, "Save current selection to jumplist", @@ -3870,7 +3871,6 @@ fn goto_column_impl(cx: &mut Context, movement: Movement) { let pos = graphemes::nth_next_grapheme_boundary(text, line_start, count - 1).min(line_end); range.put_cursor(text, pos, movement == Movement::Extend) }); - push_jump(view, doc); doc.set_selection(view.id, selection); } @@ -3892,7 +3892,6 @@ fn goto_last_modification(cx: &mut Context) { .selection(view.id) .clone() .transform(|range| range.put_cursor(text, pos, cx.editor.mode == Mode::Select)); - push_jump(view, doc); doc.set_selection(view.id, selection); } } @@ -3944,7 +3943,7 @@ fn goto_first_diag(cx: &mut Context) { Some(diag) => Selection::single(diag.range.start, diag.range.end), None => return, }; - push_jump(view, doc); + doc.set_selection(view.id, selection); view.diagnostics_handler .immediately_show_diagnostic(doc, view.id); @@ -3956,7 +3955,7 @@ fn goto_last_diag(cx: &mut Context) { Some(diag) => Selection::single(diag.range.start, diag.range.end), None => return, }; - push_jump(view, doc); + doc.set_selection(view.id, selection); view.diagnostics_handler .immediately_show_diagnostic(doc, view.id); @@ -3980,7 +3979,6 @@ fn goto_next_diag(cx: &mut Context) { Some(diag) => Selection::single(diag.range.start, diag.range.end), None => return, }; - push_jump(view, doc); doc.set_selection(view.id, selection); view.diagnostics_handler .immediately_show_diagnostic(doc, view.id); @@ -4010,11 +4008,11 @@ fn goto_prev_diag(cx: &mut Context) { Some(diag) => Selection::single(diag.range.end, diag.range.start), None => return, }; - push_jump(view, doc); doc.set_selection(view.id, selection); view.diagnostics_handler .immediately_show_diagnostic(doc, view.id); }; + cx.editor.apply_motion(motion) } @@ -4041,7 +4039,6 @@ fn goto_first_change_impl(cx: &mut Context, reverse: bool) { }; if hunk != Hunk::NONE { let range = hunk_range(hunk, doc.text().slice(..)); - push_jump(view, doc); doc.set_selection(view.id, Selection::single(range.anchor, range.head)); } } @@ -4097,7 +4094,6 @@ fn goto_next_change_impl(cx: &mut Context, direction: Direction) { } }); - push_jump(view, doc); doc.set_selection(view.id, selection) }; cx.editor.apply_motion(motion); @@ -4135,16 +4131,6 @@ pub mod insert { } } - // The default insert hook: simply insert the character - #[allow(clippy::unnecessary_wraps)] // need to use Option<> because of the Hook signature - fn insert(doc: &Rope, selection: &Selection, ch: char) -> Option<Transaction> { - let cursors = selection.clone().cursors(doc.slice(..)); - let mut t = Tendril::new(); - t.push(ch); - let transaction = Transaction::insert(doc, &cursors, t); - Some(transaction) - } - use helix_core::auto_pairs; use helix_view::editor::SmartTabConfig; @@ -4154,15 +4140,25 @@ pub mod insert { let selection = doc.selection(view.id); let auto_pairs = doc.auto_pairs(cx.editor); - let transaction = auto_pairs - .as_ref() - .and_then(|ap| auto_pairs::hook(text, selection, c, ap)) - .or_else(|| insert(text, selection, c)); + let insert_char = |range: Range, ch: char| { + let cursor = range.cursor(text.slice(..)); + let t = Tendril::from_iter([ch]); + ((cursor, cursor, Some(t)), None) + }; - let (view, doc) = current!(cx.editor); - if let Some(t) = transaction { - doc.apply(&t, view.id); - } + let transaction = Transaction::change_by_and_with_selection(text, selection, |range| { + auto_pairs + .as_ref() + .and_then(|ap| { + auto_pairs::hook_insert(text, range, c, ap) + .map(|(change, range)| (change, Some(range))) + .or_else(|| Some(insert_char(*range, c))) + }) + .unwrap_or_else(|| insert_char(*range, c)) + }); + + let doc = doc_mut!(cx.editor, &doc.id()); + doc.apply(&transaction, view.id); helix_event::dispatch(PostInsertChar { c, cx }); } @@ -4406,82 +4402,96 @@ pub mod insert { doc.apply(&transaction, view.id); } + fn dedent(doc: &Document, range: &Range) -> Option<Deletion> { + let text = doc.text().slice(..); + let pos = range.cursor(text); + let line_start_pos = text.line_to_char(range.cursor_line(text)); + + // consider to delete by indent level if all characters before `pos` are indent units. + let fragment = Cow::from(text.slice(line_start_pos..pos)); + + if fragment.is_empty() || !fragment.chars().all(|ch| ch == ' ' || ch == '\t') { + return None; + } + + if text.get_char(pos.saturating_sub(1)) == Some('\t') { + // fast path, delete one char + return Some((graphemes::nth_prev_grapheme_boundary(text, pos, 1), pos)); + } + + let tab_width = doc.tab_width(); + let indent_width = doc.indent_width(); + + let width: usize = fragment + .chars() + .map(|ch| { + if ch == '\t' { + tab_width + } else { + // it can be none if it still meet control characters other than '\t' + // here just set the width to 1 (or some value better?). + ch.width().unwrap_or(1) + } + }) + .sum(); + + // round down to nearest unit + let mut drop = width % indent_width; + + // if it's already at a unit, consume a whole unit + if drop == 0 { + drop = indent_width + }; + + let mut chars = fragment.chars().rev(); + let mut start = pos; + + for _ in 0..drop { + // delete up to `drop` spaces + match chars.next() { + Some(' ') => start -= 1, + _ => break, + } + } + + Some((start, pos)) // delete! + } + pub fn delete_char_backward(cx: &mut Context) { let count = cx.count(); let (view, doc) = current_ref!(cx.editor); let text = doc.text().slice(..); - let tab_width = doc.tab_width(); - let indent_width = doc.indent_width(); - let auto_pairs = doc.auto_pairs(cx.editor); - let transaction = - Transaction::delete_by_selection(doc.text(), doc.selection(view.id), |range| { + let transaction = Transaction::delete_by_and_with_selection( + doc.text(), + doc.selection(view.id), + |range| { let pos = range.cursor(text); + + log::debug!("cursor: {}, len: {}", pos, text.len_chars()); + if pos == 0 { - return (pos, pos); - } - let line_start_pos = text.line_to_char(range.cursor_line(text)); - // consider to delete by indent level if all characters before `pos` are indent units. - let fragment = Cow::from(text.slice(line_start_pos..pos)); - if !fragment.is_empty() && fragment.chars().all(|ch| ch == ' ' || ch == '\t') { - if text.get_char(pos.saturating_sub(1)) == Some('\t') { - // fast path, delete one char - (graphemes::nth_prev_grapheme_boundary(text, pos, 1), pos) - } else { - let width: usize = fragment - .chars() - .map(|ch| { - if ch == '\t' { - tab_width - } else { - // it can be none if it still meet control characters other than '\t' - // here just set the width to 1 (or some value better?). - ch.width().unwrap_or(1) - } - }) - .sum(); - let mut drop = width % indent_width; // round down to nearest unit - if drop == 0 { - drop = indent_width - }; // if it's already at a unit, consume a whole unit - let mut chars = fragment.chars().rev(); - let mut start = pos; - for _ in 0..drop { - // delete up to `drop` spaces - match chars.next() { - Some(' ') => start -= 1, - _ => break, - } - } - (start, pos) // delete! - } - } else { - match ( - text.get_char(pos.saturating_sub(1)), - text.get_char(pos), - auto_pairs, - ) { - (Some(_x), Some(_y), Some(ap)) - if range.is_single_grapheme(text) - && ap.get(_x).is_some() - && ap.get(_x).unwrap().open == _x - && ap.get(_x).unwrap().close == _y => - // delete both autopaired characters - { - ( - graphemes::nth_prev_grapheme_boundary(text, pos, count), - graphemes::nth_next_grapheme_boundary(text, pos, count), - ) - } - _ => - // delete 1 char - { - (graphemes::nth_prev_grapheme_boundary(text, pos, count), pos) - } - } + return ((pos, pos), None); } - }); - let (view, doc) = current!(cx.editor); + + dedent(doc, range) + .map(|dedent| (dedent, None)) + .or_else(|| { + auto_pairs::hook_delete(doc.text(), range, doc.auto_pairs(cx.editor)?) + .map(|(delete, new_range)| (delete, Some(new_range))) + }) + .unwrap_or_else(|| { + ( + (graphemes::nth_prev_grapheme_boundary(text, pos, count), pos), + None, + ) + }) + }, + ); + + log::debug!("delete_char_backward transaction: {:?}", transaction); + + let doc = doc_mut!(cx.editor, &doc.id()); doc.apply(&transaction, view.id); } @@ -5452,6 +5462,10 @@ fn reverse_selection_contents(cx: &mut Context) { // tree sitter node selection +const EXPAND_KEY: &str = "expand"; +const EXPAND_AROUND_BASE_KEY: &str = "expand_around_base"; +const PARENTS_KEY: &str = "parents"; + fn expand_selection(cx: &mut Context) { let motion = |editor: &mut Editor| { let (view, doc) = current!(editor); @@ -5459,42 +5473,154 @@ fn expand_selection(cx: &mut Context) { if let Some(syntax) = doc.syntax() { let text = doc.text().slice(..); - let current_selection = doc.selection(view.id); + let current_selection = doc.selection(view.id).clone(); let selection = object::expand_selection(syntax, text, current_selection.clone()); // check if selection is different from the last one - if *current_selection != selection { - // save current selection so it can be restored using shrink_selection - view.object_selections.push(current_selection.clone()); + if current_selection != selection { + let prev_selections = doc + .view_data_mut(view.id) + .object_selections + .entry(EXPAND_KEY) + .or_default(); - doc.set_selection(view.id, selection); + // save current selection so it can be restored using shrink_selection + prev_selections.push(current_selection); + doc.set_selection_clear(view.id, selection, false); } } }; + cx.editor.apply_motion(motion); } fn shrink_selection(cx: &mut Context) { let motion = |editor: &mut Editor| { let (view, doc) = current!(editor); - let current_selection = doc.selection(view.id); + let current_selection = doc.selection(view.id).clone(); + let prev_expansions = doc + .view_data_mut(view.id) + .object_selections + .entry(EXPAND_KEY) + .or_default(); + // try to restore previous selection - if let Some(prev_selection) = view.object_selections.pop() { - if current_selection.contains(&prev_selection) { - doc.set_selection(view.id, prev_selection); - return; - } else { - // clear existing selection as they can't be shrunk to anyway - view.object_selections.clear(); + if let Some(prev_selection) = prev_expansions.pop() { + // allow shrinking the selection only if current selection contains the previous object selection + doc.set_selection_clear(view.id, prev_selection, false); + + // Do a corresponding pop of the parents from `expand_selection_around` + doc.view_data_mut(view.id) + .object_selections + .entry(PARENTS_KEY) + .and_modify(|parents| { + parents.pop(); + }); + + // need to do this again because borrowing + let prev_expansions = doc + .view_data_mut(view.id) + .object_selections + .entry(EXPAND_KEY) + .or_default(); + + // if we've emptied out the previous expansions, then clear out the + // base history as well so it doesn't get used again erroneously + if prev_expansions.is_empty() { + doc.view_data_mut(view.id) + .object_selections + .entry(EXPAND_AROUND_BASE_KEY) + .and_modify(|base| { + base.clear(); + }); } + + return; } + // if not previous selection, shrink to first child if let Some(syntax) = doc.syntax() { let text = doc.text().slice(..); - let selection = object::shrink_selection(syntax, text, current_selection.clone()); - doc.set_selection(view.id, selection); + let selection = object::shrink_selection(syntax, text, current_selection); + doc.set_selection_clear(view.id, selection, false); } }; + + cx.editor.apply_motion(motion); +} + +fn expand_selection_around(cx: &mut Context) { + let motion = |editor: &mut Editor| { + let (view, doc) = current!(editor); + + if doc.syntax().is_some() { + // [NOTE] we do this pop and push dance because if we don't take + // ownership of the objects, then we require multiple + // mutable references to the view's object selections + let mut parents_selection = doc + .view_data_mut(view.id) + .object_selections + .entry(PARENTS_KEY) + .or_default() + .pop(); + + let mut base_selection = doc + .view_data_mut(view.id) + .object_selections + .entry(EXPAND_AROUND_BASE_KEY) + .or_default() + .pop(); + + let current_selection = doc.selection(view.id).clone(); + + if parents_selection.is_none() || base_selection.is_none() { + parents_selection = Some(current_selection.clone()); + base_selection = Some(current_selection.clone()); + } + + let text = doc.text().slice(..); + let syntax = doc.syntax().unwrap(); + + let outside_selection = + object::expand_selection(syntax, text, parents_selection.clone().unwrap()); + + let target_selection = match outside_selection + .clone() + .without(&base_selection.clone().unwrap()) + { + Some(sel) => sel, + None => outside_selection.clone(), + }; + + // check if selection is different from the last one + if target_selection != current_selection { + // save current selection so it can be restored using shrink_selection + doc.view_data_mut(view.id) + .object_selections + .entry(EXPAND_KEY) + .or_default() + .push(current_selection); + + doc.set_selection_clear(view.id, target_selection, false); + } + + let parents = doc + .view_data_mut(view.id) + .object_selections + .entry(PARENTS_KEY) + .or_default(); + + parents.push(parents_selection.unwrap()); + parents.push(outside_selection); + + doc.view_data_mut(view.id) + .object_selections + .entry(EXPAND_AROUND_BASE_KEY) + .or_default() + .push(base_selection.unwrap()); + } + }; + cx.editor.apply_motion(motion); } @@ -5512,6 +5638,7 @@ where doc.set_selection(view.id, selection); } }; + cx.editor.apply_motion(motion); } @@ -5613,8 +5740,6 @@ fn match_brackets(cx: &mut Context) { doc.set_selection(view.id, selection); } -// - fn jump_forward(cx: &mut Context) { let count = cx.count(); let config = cx.editor.config(); @@ -5920,7 +6045,6 @@ fn goto_ts_object_impl(cx: &mut Context, object: &'static str, direction: Direct } }); - push_jump(view, doc); doc.set_selection(view.id, selection); } else { editor.set_status("Syntax-tree is not available in current buffer"); diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 0494db3e..929774c7 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -100,7 +100,7 @@ struct PickerDiagnostic { diag: lsp::Diagnostic, } -fn location_to_file_location(location: &Location) -> Option<FileLocation<'_>> { +fn location_to_file_location(location: &Location) -> Option<FileLocation> { let path = location.uri.as_path()?; let line = Some(( location.range.start.line as usize, @@ -589,7 +589,7 @@ struct CodeActionOrCommandItem { impl ui::menu::Item for CodeActionOrCommandItem { type Data = (); - fn format(&self, _data: &Self::Data) -> Row<'_> { + fn format(&self, _data: &Self::Data) -> Row { match &self.lsp_item { lsp::CodeActionOrCommand::CodeAction(action) => action.title.as_str().into(), lsp::CodeActionOrCommand::Command(command) => command.title.as_str().into(), @@ -1146,7 +1146,7 @@ pub fn rename_symbol(cx: &mut Context) { let Some(language_server) = doc .language_servers_with_feature(LanguageServerFeature::RenameSymbol) - .find(|ls| language_server_id.is_none_or(|id| id == ls.id())) + .find(|ls| language_server_id.map_or(true, |id| id == ls.id())) else { cx.editor .set_error("No configured language server supports symbol renaming"); diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 867ca4ac..d26b4705 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -68,44 +68,6 @@ impl CommandCompleter { } } -fn exit(cx: &mut compositor::Context, args: Args, event: PromptEvent) -> anyhow::Result<()> { - if event != PromptEvent::Validate { - return Ok(()); - } - - if doc!(cx.editor).is_modified() { - write_impl( - cx, - args.first(), - WriteOptions { - force: false, - auto_format: !args.has_flag(WRITE_NO_FORMAT_FLAG.name), - }, - )?; - } - cx.block_try_flush_writes()?; - quit(cx, Args::default(), event) -} - -fn force_exit(cx: &mut compositor::Context, args: Args, event: PromptEvent) -> anyhow::Result<()> { - if event != PromptEvent::Validate { - return Ok(()); - } - - if doc!(cx.editor).is_modified() { - write_impl( - cx, - args.first(), - WriteOptions { - force: true, - auto_format: !args.has_flag(WRITE_NO_FORMAT_FLAG.name), - }, - )?; - } - cx.block_try_flush_writes()?; - quit(cx, Args::default(), event) -} - fn quit(cx: &mut compositor::Context, _args: Args, event: PromptEvent) -> anyhow::Result<()> { log::debug!("quitting..."); @@ -2715,30 +2677,6 @@ const WRITE_NO_FORMAT_FLAG: Flag = Flag { pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { - name: "exit", - aliases: &["x", "xit"], - doc: "Write changes to disk if the buffer is modified and then quit. Accepts an optional path (:exit some/path.txt).", - fun: exit, - completer: CommandCompleter::positional(&[completers::filename]), - signature: Signature { - positionals: (0, Some(1)), - flags: &[WRITE_NO_FORMAT_FLAG], - ..Signature::DEFAULT - }, - }, - TypableCommand { - name: "exit!", - aliases: &["x!", "xit!"], - doc: "Force write changes to disk, creating necessary subdirectories, if the buffer is modified and then quit. Accepts an optional path (:exit! some/path.txt).", - fun: force_exit, - completer: CommandCompleter::positional(&[completers::filename]), - signature: Signature { - positionals: (0, Some(1)), - flags: &[WRITE_NO_FORMAT_FLAG], - ..Signature::DEFAULT - }, - }, - TypableCommand { name: "quit", aliases: &["q"], doc: "Close the current view.", @@ -2972,7 +2910,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ }, TypableCommand { name: "write-quit", - aliases: &["wq"], + aliases: &["wq", "x"], doc: "Write changes to disk and close the current view. Accepts an optional path (:wq some/path.txt)", fun: write_quit, completer: CommandCompleter::positional(&[completers::filename]), @@ -2984,7 +2922,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ }, TypableCommand { name: "write-quit!", - aliases: &["wq!"], + aliases: &["wq!", "x!"], doc: "Write changes to disk and close the current view forcefully. Accepts an optional path (:wq! some/path.txt)", fun: force_write_quit, completer: CommandCompleter::positional(&[completers::filename]), @@ -3033,7 +2971,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { name: "write-quit-all!", aliases: &["wqa!", "xa!"], - doc: "Forcefully write changes from all buffers to disk, creating necessary subdirectories, and close all views (ignoring unsaved changes).", + doc: "Write changes from all buffers to disk and close all views forcefully (ignoring unsaved changes).", fun: force_write_all_quit, completer: CommandCompleter::none(), signature: Signature { @@ -3802,7 +3740,7 @@ pub(super) fn command_mode(cx: &mut Context) { cx.push_layer(Box::new(prompt)); } -fn command_line_doc(input: &str) -> Option<Cow<'_, str>> { +fn command_line_doc(input: &str) -> Option<Cow<str>> { let (command, _, _) = command_line::split(input); let command = TYPABLE_COMMAND_MAP.get(command)?; diff --git a/helix-term/src/config.rs b/helix-term/src/config.rs index dd051984..bcba8d8e 100644 --- a/helix-term/src/config.rs +++ b/helix-term/src/config.rs @@ -1,7 +1,7 @@ use crate::keymap; use crate::keymap::{merge_keys, KeyTrie}; use helix_loader::merge_toml_values; -use helix_view::{document::Mode, theme}; +use helix_view::document::Mode; use serde::Deserialize; use std::collections::HashMap; use std::fmt::Display; @@ -11,7 +11,7 @@ use toml::de::Error as TomlError; #[derive(Debug, Clone, PartialEq)] pub struct Config { - pub theme: Option<theme::Config>, + pub theme: Option<String>, pub keys: HashMap<Mode, KeyTrie>, pub editor: helix_view::editor::Config, } @@ -19,7 +19,7 @@ pub struct Config { #[derive(Debug, Clone, PartialEq, Deserialize)] #[serde(deny_unknown_fields)] pub struct ConfigRaw { - pub theme: Option<theme::Config>, + pub theme: Option<String>, pub keys: Option<HashMap<Mode, KeyTrie>>, pub editor: Option<toml::Value>, } diff --git a/helix-term/src/handlers.rs b/helix-term/src/handlers.rs index 18297bfe..25cab6a3 100644 --- a/helix-term/src/handlers.rs +++ b/helix-term/src/handlers.rs @@ -1,13 +1,11 @@ use std::sync::Arc; use arc_swap::ArcSwap; -use diagnostics::PullAllDocumentsDiagnosticHandler; use helix_event::AsyncHook; use crate::config::Config; use crate::events; use crate::handlers::auto_save::AutoSaveHandler; -use crate::handlers::diagnostics::PullDiagnosticsHandler; use crate::handlers::signature_help::SignatureHelpHandler; pub use helix_view::handlers::{word_index, Handlers}; @@ -16,7 +14,7 @@ use self::document_colors::DocumentColorsHandler; mod auto_save; pub mod completion; -pub mod diagnostics; +mod diagnostics; mod document_colors; mod prompt; mod signature_help; @@ -30,8 +28,6 @@ pub fn setup(config: Arc<ArcSwap<Config>>) -> Handlers { let auto_save = AutoSaveHandler::new().spawn(); let document_colors = DocumentColorsHandler::default().spawn(); let word_index = word_index::Handler::spawn(); - let pull_diagnostics = PullDiagnosticsHandler::default().spawn(); - let pull_all_documents_diagnostics = PullAllDocumentsDiagnosticHandler::default().spawn(); let handlers = Handlers { completions: helix_view::handlers::completion::CompletionHandler::new(event_tx), @@ -39,8 +35,6 @@ pub fn setup(config: Arc<ArcSwap<Config>>) -> Handlers { auto_save, document_colors, word_index, - pull_diagnostics, - pull_all_documents_diagnostics, }; helix_view::handlers::register_hooks(&handlers); diff --git a/helix-term/src/handlers/completion/item.rs b/helix-term/src/handlers/completion/item.rs index 136d72db..7a473b02 100644 --- a/helix-term/src/handlers/completion/item.rs +++ b/helix-term/src/handlers/completion/item.rs @@ -67,7 +67,6 @@ impl LspCompletionItem { } } -#[allow(clippy::large_enum_variant)] // TODO: In a separate PR attempt the `Box<LspCompletionItem>` pattern. #[derive(Debug, PartialEq, Clone)] pub enum CompletionItem { Lsp(LspCompletionItem), diff --git a/helix-term/src/handlers/completion/request.rs b/helix-term/src/handlers/completion/request.rs index fd65cd4d..29cd8e42 100644 --- a/helix-term/src/handlers/completion/request.rs +++ b/helix-term/src/handlers/completion/request.rs @@ -87,7 +87,7 @@ impl helix_event::AsyncHook for CompletionHandler { if self .trigger .or(self.in_flight) - .is_none_or(|trigger| trigger.doc != doc || trigger.view != view) + .map_or(true, |trigger| trigger.doc != doc || trigger.view != view) { self.trigger = Some(Trigger { pos: trigger_pos, diff --git a/helix-term/src/handlers/diagnostics.rs b/helix-term/src/handlers/diagnostics.rs index aa154eb6..3e44d416 100644 --- a/helix-term/src/handlers/diagnostics.rs +++ b/helix-term/src/handlers/diagnostics.rs @@ -1,28 +1,12 @@ -use futures_util::stream::FuturesUnordered; -use std::collections::HashSet; -use std::mem; -use std::time::Duration; -use tokio::time::Instant; -use tokio_stream::StreamExt; - -use helix_core::diagnostic::DiagnosticProvider; -use helix_core::syntax::config::LanguageServerFeature; -use helix_core::Uri; -use helix_event::{cancelable_future, register_hook, send_blocking}; -use helix_lsp::{lsp, LanguageServerId}; +use helix_event::{register_hook, send_blocking}; use helix_view::document::Mode; -use helix_view::events::{ - DiagnosticsDidChange, DocumentDidChange, DocumentDidOpen, LanguageServerInitialized, -}; +use helix_view::events::DiagnosticsDidChange; use helix_view::handlers::diagnostics::DiagnosticEvent; -use helix_view::handlers::lsp::{PullAllDocumentsDiagnosticsEvent, PullDiagnosticsEvent}; use helix_view::handlers::Handlers; -use helix_view::{DocumentId, Editor}; use crate::events::OnModeSwitch; -use crate::job; -pub(super) fn register_hooks(handlers: &Handlers) { +pub(super) fn register_hooks(_handlers: &Handlers) { register_hook!(move |event: &mut DiagnosticsDidChange<'_>| { if event.editor.mode != Mode::Insert { for (view, _) in event.editor.tree.views_mut() { @@ -37,265 +21,4 @@ pub(super) fn register_hooks(handlers: &Handlers) { } Ok(()) }); - - let tx = handlers.pull_diagnostics.clone(); - let tx_all_documents = handlers.pull_all_documents_diagnostics.clone(); - register_hook!(move |event: &mut DocumentDidChange<'_>| { - if event - .doc - .has_language_server_with_feature(LanguageServerFeature::PullDiagnostics) - && !event.ghost_transaction - { - // Cancel the ongoing request, if present. - event.doc.pull_diagnostic_controller.cancel(); - let document_id = event.doc.id(); - send_blocking(&tx, PullDiagnosticsEvent { document_id }); - - let inter_file_dependencies_language_servers = event - .doc - .language_servers_with_feature(LanguageServerFeature::PullDiagnostics) - .filter(|language_server| { - language_server - .capabilities() - .diagnostic_provider - .as_ref() - .is_some_and(|diagnostic_provider| match diagnostic_provider { - lsp::DiagnosticServerCapabilities::Options(options) => { - options.inter_file_dependencies - } - - lsp::DiagnosticServerCapabilities::RegistrationOptions(options) => { - options.diagnostic_options.inter_file_dependencies - } - }) - }) - .map(|language_server| language_server.id()) - .collect(); - - send_blocking( - &tx_all_documents, - PullAllDocumentsDiagnosticsEvent { - language_servers: inter_file_dependencies_language_servers, - }, - ); - } - Ok(()) - }); - - register_hook!(move |event: &mut DocumentDidOpen<'_>| { - request_document_diagnostics(event.editor, event.doc); - - Ok(()) - }); - - register_hook!(move |event: &mut LanguageServerInitialized<'_>| { - let doc_ids: Vec<_> = event.editor.documents.keys().copied().collect(); - - for doc_id in doc_ids { - request_document_diagnostics(event.editor, doc_id); - } - - Ok(()) - }); -} - -#[derive(Debug, Default)] -pub(super) struct PullDiagnosticsHandler { - document_ids: HashSet<DocumentId>, -} - -impl helix_event::AsyncHook for PullDiagnosticsHandler { - type Event = PullDiagnosticsEvent; - - fn handle_event( - &mut self, - event: Self::Event, - _timeout: Option<tokio::time::Instant>, - ) -> Option<tokio::time::Instant> { - self.document_ids.insert(event.document_id); - Some(Instant::now() + Duration::from_millis(250)) - } - - fn finish_debounce(&mut self) { - let document_ids = mem::take(&mut self.document_ids); - job::dispatch_blocking(move |editor, _| { - for document_id in document_ids { - request_document_diagnostics(editor, document_id); - } - }) - } -} - -#[derive(Debug, Default)] -pub(super) struct PullAllDocumentsDiagnosticHandler { - language_servers: HashSet<LanguageServerId>, -} - -impl helix_event::AsyncHook for PullAllDocumentsDiagnosticHandler { - type Event = PullAllDocumentsDiagnosticsEvent; - - fn handle_event( - &mut self, - event: Self::Event, - _timeout: Option<tokio::time::Instant>, - ) -> Option<tokio::time::Instant> { - self.language_servers.extend(&event.language_servers); - Some(Instant::now() + Duration::from_secs(1)) - } - - fn finish_debounce(&mut self) { - let language_servers = mem::take(&mut self.language_servers); - job::dispatch_blocking(move |editor, _| { - let documents: Vec<_> = editor.documents.keys().copied().collect(); - - for document in documents { - request_document_diagnostics_for_language_severs( - editor, - document, - language_servers.clone(), - ); - } - }) - } -} - -fn request_document_diagnostics_for_language_severs( - editor: &mut Editor, - doc_id: DocumentId, - language_servers: HashSet<LanguageServerId>, -) { - let Some(doc) = editor.document_mut(doc_id) else { - return; - }; - - let cancel = doc.pull_diagnostic_controller.restart(); - - let mut futures: FuturesUnordered<_> = language_servers - .iter() - .filter_map(|x| doc.language_servers().find(|y| &y.id() == x)) - .filter_map(|language_server| { - let future = language_server - .text_document_diagnostic(doc.identifier(), doc.previous_diagnostic_id.clone())?; - - let identifier = language_server - .capabilities() - .diagnostic_provider - .as_ref() - .and_then(|diagnostic_provider| match diagnostic_provider { - lsp::DiagnosticServerCapabilities::Options(options) => { - options.identifier.clone() - } - lsp::DiagnosticServerCapabilities::RegistrationOptions(options) => { - options.diagnostic_options.identifier.clone() - } - }); - - let language_server_id = language_server.id(); - let provider = DiagnosticProvider::Lsp { - server_id: language_server_id, - identifier, - }; - let uri = doc.uri()?; - - Some(async move { - let result = future.await; - - (result, provider, uri) - }) - }) - .collect(); - - if futures.is_empty() { - return; - } - - tokio::spawn(async move { - let mut retry_language_servers = HashSet::new(); - loop { - match cancelable_future(futures.next(), &cancel).await { - Some(Some((Ok(result), provider, uri))) => { - job::dispatch(move |editor, _| { - handle_pull_diagnostics_response(editor, result, provider, uri, doc_id); - }) - .await; - } - Some(Some((Err(err), DiagnosticProvider::Lsp { server_id, .. }, _))) => { - let parsed_cancellation_data = if let helix_lsp::Error::Rpc(error) = err { - error.data.and_then(|data| { - serde_json::from_value::<lsp::DiagnosticServerCancellationData>(data) - .ok() - }) - } else { - log::error!("Pull diagnostic request failed: {err}"); - continue; - }; - if parsed_cancellation_data.is_some_and(|data| data.retrigger_request) { - retry_language_servers.insert(server_id); - } - } - Some(None) => break, - // The request was cancelled. - None => return, - } - } - - if !retry_language_servers.is_empty() { - tokio::time::sleep(Duration::from_millis(500)).await; - - job::dispatch(move |editor, _| { - request_document_diagnostics_for_language_severs( - editor, - doc_id, - retry_language_servers, - ); - }) - .await; - } - }); -} - -pub fn request_document_diagnostics(editor: &mut Editor, doc_id: DocumentId) { - let Some(doc) = editor.document(doc_id) else { - return; - }; - - let language_servers = doc - .language_servers_with_feature(LanguageServerFeature::PullDiagnostics) - .map(|language_servers| language_servers.id()) - .collect(); - - request_document_diagnostics_for_language_severs(editor, doc_id, language_servers); -} - -fn handle_pull_diagnostics_response( - editor: &mut Editor, - result: lsp::DocumentDiagnosticReportResult, - provider: DiagnosticProvider, - uri: Uri, - document_id: DocumentId, -) { - match result { - lsp::DocumentDiagnosticReportResult::Report(report) => { - let result_id = match report { - lsp::DocumentDiagnosticReport::Full(report) => { - editor.handle_lsp_diagnostics( - &provider, - uri, - None, - report.full_document_diagnostic_report.items, - ); - - report.full_document_diagnostic_report.result_id - } - lsp::DocumentDiagnosticReport::Unchanged(report) => { - Some(report.unchanged_document_diagnostic_report.result_id) - } - }; - - if let Some(doc) = editor.document_mut(document_id) { - doc.previous_diagnostic_id = result_id; - }; - } - lsp::DocumentDiagnosticReportResult::Partial(_) => {} - }; } diff --git a/helix-term/src/health.rs b/helix-term/src/health.rs index 52112bf9..dbf25e60 100644 --- a/helix-term/src/health.rs +++ b/helix-term/src/health.rs @@ -365,8 +365,8 @@ fn probe_parser(grammar_name: &str) -> std::io::Result<()> { write!(stdout, "Tree-sitter parser: ")?; match helix_loader::grammar::get_language(grammar_name) { - Ok(Some(_)) => writeln!(stdout, "{}", "✓".green()), - Ok(None) | Err(_) => writeln!(stdout, "{}", "None".yellow()), + Ok(_) => writeln!(stdout, "{}", "✓".green()), + Err(_) => writeln!(stdout, "{}", "None".yellow()), } } diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index 5bbbd3f4..45e1ad12 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -87,6 +87,7 @@ pub fn default() -> HashMap<Mode, KeyTrie> { ";" => collapse_selection, "A-;" => flip_selections, "A-o" | "A-up" => expand_selection, + "A-O" => expand_selection_around, "A-i" | "A-down" => shrink_selection, "A-I" | "A-S-down" => select_all_children, "A-p" | "A-left" => select_prev_sibling, diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs index bdca0c01..c1404d4f 100644 --- a/helix-term/src/main.rs +++ b/helix-term/src/main.rs @@ -56,27 +56,26 @@ USAGE: hx [FLAGS] [files]... ARGS: - <files>... Set the input file to use, position can also be specified via file[:row[:col]] + <files>... Sets the input file to use, position can also be specified via file[:row[:col]] FLAGS: - -h, --help Print help information - --tutor Load the tutorial - --health [CATEGORY] Check for potential errors in editor setup + -h, --help Prints help information + --tutor Loads the tutorial + --health [CATEGORY] Checks for potential errors in editor setup CATEGORY can be a language or one of 'clipboard', 'languages', 'all-languages' or 'all'. 'languages' is filtered according to user config, 'all-languages' and 'all' are not. If not specified, the default is the same as 'all', but with languages filtering. - -g, --grammar {{fetch|build}} Fetch or builds tree-sitter grammars listed in languages.toml - -c, --config <file> Specify a file to use for configuration - -v Increase logging verbosity each use for up to 3 times - --log <file> Specify a file to use for logging + -g, --grammar {{fetch|build}} Fetches or builds tree-sitter grammars listed in languages.toml + -c, --config <file> Specifies a file to use for configuration + -v Increases logging verbosity each use for up to 3 times + --log <file> Specifies a file to use for logging (default file: {}) - -V, --version Print version information - --vsplit Split all given files vertically into different windows - --hsplit Split all given files horizontally into different windows + -V, --version Prints version information + --vsplit Splits all given files vertically into different windows + --hsplit Splits all given files horizontally into different windows -w, --working-dir <path> Specify an initial working directory - +[N] Open the first given file at line number N, or the last line, if - N is not specified. + +N Open the first given file at line number N ", env!("CARGO_PKG_NAME"), VERSION_AND_GIT_HASH, diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index c0d3294f..e17762bf 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -1,9 +1,9 @@ -use crate::handlers::completion::LspCompletionItem; use crate::ui::{menu, Markdown, Menu, Popup, PromptEvent}; use crate::{ compositor::{Component, Context, Event, EventResult}, handlers::completion::{ - trigger_auto_completion, CompletionItem, CompletionResponse, ResolveHandler, + trigger_auto_completion, CompletionItem, CompletionResponse, LspCompletionItem, + ResolveHandler, }, }; use helix_core::snippets::{ActiveSnippet, RenderedSnippet, Snippet}; @@ -28,7 +28,7 @@ use std::cmp::Reverse; impl menu::Item for CompletionItem { type Data = Style; - fn format(&self, dir_style: &Self::Data) -> menu::Row<'_> { + fn format(&self, dir_style: &Self::Data) -> menu::Row { let deprecated = match self { CompletionItem::Lsp(LspCompletionItem { item, .. }) => { item.deprecated.unwrap_or_default() diff --git a/helix-term/src/ui/document.rs b/helix-term/src/ui/document.rs index de85268a..524d829c 100644 --- a/helix-term/src/ui/document.rs +++ b/helix-term/src/ui/document.rs @@ -214,7 +214,7 @@ impl<'a> TextRenderer<'a> { let tab_width = doc.tab_width(); let tab = if ws_render.tab() == WhitespaceRenderValue::All { std::iter::once(ws_chars.tab) - .chain(std::iter::repeat_n(ws_chars.tabpad, tab_width - 1)) + .chain(std::iter::repeat(ws_chars.tabpad).take(tab_width - 1)) .collect() } else { " ".repeat(tab_width) diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs index 41cf96ac..76e50229 100644 --- a/helix-term/src/ui/menu.rs +++ b/helix-term/src/ui/menu.rs @@ -13,7 +13,7 @@ pub trait Item: Sync + Send + 'static { /// Additional editor state that is used for label calculation. type Data: Sync + Send + 'static; - fn format(&self, data: &Self::Data) -> Row<'_>; + fn format(&self, data: &Self::Data) -> Row; } pub type MenuCallback<T> = Box<dyn Fn(&mut Editor, Option<&T>, MenuEvent)>; diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 58b6fc00..089f8e97 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -185,22 +185,6 @@ pub fn raw_regex_prompt( cx.push_layer(Box::new(prompt)); } -/// We want to exclude files that the editor can't handle yet -fn get_excluded_types() -> ignore::types::Types { - use ignore::types::TypesBuilder; - let mut type_builder = TypesBuilder::new(); - type_builder - .add( - "compressed", - "*.{zip,gz,bz2,zst,lzo,sz,tgz,tbz2,lz,lz4,lzma,lzo,z,Z,xz,7z,rar,cab}", - ) - .expect("Invalid type definition"); - type_builder.negate("all"); - type_builder - .build() - .expect("failed to build excluded_types") -} - #[derive(Debug)] pub struct FilePickerData { root: PathBuf, @@ -209,7 +193,7 @@ pub struct FilePickerData { type FilePicker = Picker<PathBuf, FilePickerData>; pub fn file_picker(editor: &Editor, root: PathBuf) -> FilePicker { - use ignore::WalkBuilder; + use ignore::{types::TypesBuilder, WalkBuilder}; use std::time::Instant; let config = editor.config(); @@ -224,8 +208,7 @@ pub fn file_picker(editor: &Editor, root: PathBuf) -> FilePicker { let absolute_root = root.canonicalize().unwrap_or_else(|_| root.clone()); let mut walk_builder = WalkBuilder::new(&root); - - let mut files = walk_builder + walk_builder .hidden(config.file_picker.hidden) .parents(config.file_picker.parents) .ignore(config.file_picker.ignore) @@ -235,18 +218,31 @@ pub fn file_picker(editor: &Editor, root: PathBuf) -> FilePicker { .git_exclude(config.file_picker.git_exclude) .sort_by_file_name(|name1, name2| name1.cmp(name2)) .max_depth(config.file_picker.max_depth) - .filter_entry(move |entry| filter_picker_entry(entry, &absolute_root, dedup_symlinks)) - .add_custom_ignore_filename(helix_loader::config_dir().join("ignore")) - .add_custom_ignore_filename(".helix/ignore") - .types(get_excluded_types()) + .filter_entry(move |entry| filter_picker_entry(entry, &absolute_root, dedup_symlinks)); + + walk_builder.add_custom_ignore_filename(helix_loader::config_dir().join("ignore")); + walk_builder.add_custom_ignore_filename(".helix/ignore"); + + // We want to exclude files that the editor can't handle yet + let mut type_builder = TypesBuilder::new(); + type_builder + .add( + "compressed", + "*.{zip,gz,bz2,zst,lzo,sz,tgz,tbz2,lz,lz4,lzma,lzo,z,Z,xz,7z,rar,cab}", + ) + .expect("Invalid type definition"); + type_builder.negate("all"); + let excluded_types = type_builder .build() - .filter_map(|entry| { - let entry = entry.ok()?; - if !entry.file_type()?.is_file() { - return None; - } - Some(entry.into_path()) - }); + .expect("failed to build excluded_types"); + walk_builder.types(excluded_types); + let mut files = walk_builder.build().filter_map(|entry| { + let entry = entry.ok()?; + if !entry.file_type()?.is_file() { + return None; + } + Some(entry.into_path()) + }); log::debug!("file_picker init {:?}", Instant::now().duration_since(now)); let columns = [PickerColumn::new( @@ -308,7 +304,7 @@ type FileExplorer = Picker<(PathBuf, bool), (PathBuf, Style)>; pub fn file_explorer(root: PathBuf, editor: &Editor) -> Result<FileExplorer, std::io::Error> { let directory_style = editor.theme.get("ui.text.directory"); - let directory_content = directory_content(&root, editor)?; + let directory_content = directory_content(&root)?; let columns = [PickerColumn::new( "path", @@ -354,64 +350,24 @@ pub fn file_explorer(root: PathBuf, editor: &Editor) -> Result<FileExplorer, std Ok(picker) } -fn directory_content(root: &Path, editor: &Editor) -> Result<Vec<(PathBuf, bool)>, std::io::Error> { - use ignore::WalkBuilder; - - let config = editor.config(); - - let mut walk_builder = WalkBuilder::new(root); - - let mut content: Vec<(PathBuf, bool)> = walk_builder - .hidden(config.file_explorer.hidden) - .parents(config.file_explorer.parents) - .ignore(config.file_explorer.ignore) - .follow_links(config.file_explorer.follow_symlinks) - .git_ignore(config.file_explorer.git_ignore) - .git_global(config.file_explorer.git_global) - .git_exclude(config.file_explorer.git_exclude) - .max_depth(Some(1)) - .add_custom_ignore_filename(helix_loader::config_dir().join("ignore")) - .add_custom_ignore_filename(".helix/ignore") - .types(get_excluded_types()) - .build() - .filter_map(|entry| { - entry - .map(|entry| { - let is_dir = entry - .file_type() - .is_some_and(|file_type| file_type.is_dir()); - let mut path = entry.path().to_path_buf(); - if is_dir && path != root && config.file_explorer.flatten_dirs { - while let Some(single_child_directory) = get_child_if_single_dir(&path) { - path = single_child_directory; - } - } - (path, is_dir) - }) - .ok() - .filter(|entry| entry.0 != root) +fn directory_content(path: &Path) -> Result<Vec<(PathBuf, bool)>, std::io::Error> { + let mut content: Vec<_> = std::fs::read_dir(path)? + .flatten() + .map(|entry| { + ( + entry.path(), + std::fs::metadata(entry.path()).is_ok_and(|metadata| metadata.is_dir()), + ) }) .collect(); content.sort_by(|(path1, is_dir1), (path2, is_dir2)| (!is_dir1, path1).cmp(&(!is_dir2, path2))); - - if root.parent().is_some() { - content.insert(0, (root.join(".."), true)); + if path.parent().is_some() { + content.insert(0, (path.join(".."), true)); } - Ok(content) } -fn get_child_if_single_dir(path: &Path) -> Option<PathBuf> { - let mut entries = path.read_dir().ok()?; - let entry = entries.next()?.ok()?; - if entries.next().is_none() && entry.file_type().is_ok_and(|file_type| file_type.is_dir()) { - Some(entry.path()) - } else { - None - } -} - pub mod completers { use super::Utf8PathBuf; use crate::ui::prompt::Completion; @@ -784,27 +740,3 @@ pub mod completers { completions } } - -#[cfg(test)] -mod tests { - use std::fs::{create_dir, File}; - - use super::*; - - #[test] - fn test_get_child_if_single_dir() { - let root = tempfile::tempdir().unwrap(); - - assert_eq!(get_child_if_single_dir(root.path()), None); - - let dir = root.path().join("dir1"); - create_dir(&dir).unwrap(); - - assert_eq!(get_child_if_single_dir(root.path()), Some(dir)); - - let file = root.path().join("file"); - File::create(file).unwrap(); - - assert_eq!(get_child_if_single_dir(root.path()), None); - } -} diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 4f77f8b9..11d3c04c 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -610,15 +610,11 @@ impl<T: 'static + Send + Sync, D: 'static + Send + Sync> Picker<T, D> { let preview = std::fs::metadata(&path) .and_then(|metadata| { if metadata.is_dir() { - let files = super::directory_content(&path, editor)?; + let files = super::directory_content(&path)?; let file_names: Vec<_> = files .iter() - .filter_map(|(file_path, is_dir)| { - let name = file_path - .strip_prefix(&path) - .map(|p| Some(p.as_os_str())) - .unwrap_or_else(|_| file_path.file_name())? - .to_string_lossy(); + .filter_map(|(path, is_dir)| { + let name = path.file_name()?.to_string_lossy(); if *is_dir { Some((format!("{}/", name), true)) } else { @@ -900,7 +896,7 @@ impl<T: 'static + Send + Sync, D: 'static + Send + Sync> Picker<T, D> { if let Some((preview, range)) = self.get_preview(cx.editor) { let doc = match preview.document() { Some(doc) - if range.is_none_or(|(start, end)| { + if range.map_or(true, |(start, end)| { start <= end && end <= doc.text().len_lines() }) => { @@ -1048,23 +1044,23 @@ impl<I: 'static + Send + Sync, D: 'static + Send + Sync> Component for Picker<I, let close_fn = |picker: &mut Self| { // if the picker is very large don't store it as last_picker to avoid // excessive memory consumption - let callback: compositor::Callback = - if picker.matcher.snapshot().item_count() > 1_000_000 { - Box::new(|compositor: &mut Compositor, _ctx| { - // remove the layer - compositor.pop(); - }) - } else { - // stop streaming in new items in the background, really we should - // be restarting the stream somehow once the picker gets - // reopened instead (like for an FS crawl) that would also remove the - // need for the special case above but that is pretty tricky - picker.version.fetch_add(1, atomic::Ordering::Relaxed); - Box::new(|compositor: &mut Compositor, _ctx| { - // remove the layer - compositor.last_picker = compositor.pop(); - }) - }; + let callback: compositor::Callback = if picker.matcher.snapshot().item_count() > 100_000 + { + Box::new(|compositor: &mut Compositor, _ctx| { + // remove the layer + compositor.pop(); + }) + } else { + // stop streaming in new items in the background, really we should + // be restarting the stream somehow once the picker gets + // reopened instead (like for an FS crawl) that would also remove the + // need for the special case above but that is pretty tricky + picker.version.fetch_add(1, atomic::Ordering::Relaxed); + Box::new(|compositor: &mut Compositor, _ctx| { + // remove the layer + compositor.last_picker = compositor.pop(); + }) + }; EventResult::Consumed(Some(callback)) }; diff --git a/helix-term/src/ui/statusline.rs b/helix-term/src/ui/statusline.rs index 88c75fe1..aad3d532 100644 --- a/helix-term/src/ui/statusline.rs +++ b/helix-term/src/ui/statusline.rs @@ -1,5 +1,7 @@ +use std::borrow::Cow; + use helix_core::indent::IndentStyle; -use helix_core::{coords_at_pos, encoding, unicode::width::UnicodeWidthStr, Position}; +use helix_core::{coords_at_pos, encoding, Position}; use helix_lsp::lsp::DiagnosticSeverity; use helix_view::document::DEFAULT_LANGUAGE_NAME; use helix_view::{ @@ -167,16 +169,18 @@ where let visible = context.focused; let config = context.editor.config(); let modenames = &config.statusline.mode; - let mode_str = match context.editor.mode() { - Mode::Insert => &modenames.insert, - Mode::Select => &modenames.select, - Mode::Normal => &modenames.normal, - }; let content = if visible { - format!(" {mode_str} ") + Cow::Owned(format!( + " {} ", + match context.editor.mode() { + Mode::Insert => &modenames.insert, + Mode::Select => &modenames.select, + Mode::Normal => &modenames.normal, + } + )) } else { // If not focused, explicitly leave an empty space instead of returning None. - " ".repeat(mode_str.width() + 2) + Cow::Borrowed(" ") }; let style = if visible && config.color_modes { match context.editor.mode() { diff --git a/helix-term/tests/test/auto_pairs.rs b/helix-term/tests/test/auto_pairs.rs index c921e2ae..8048d97f 100644 --- a/helix-term/tests/test/auto_pairs.rs +++ b/helix-term/tests/test/auto_pairs.rs @@ -16,10 +16,119 @@ fn matching_pairs() -> impl Iterator<Item = &'static (char, char)> { async fn insert_basic() -> anyhow::Result<()> { for pair in DEFAULT_PAIRS { test(( - format!("#[{}|]#", LINE_END), + "#[\n|]#", format!("i{}", pair.0), - format!("{}#[|{}]#{}", pair.0, pair.1, LINE_END), - LineFeedHandling::AsIs, + format!("{}#[|{}]#", pair.0, pair.1), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn insert_whitespace() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!("{}#[|{}]#", pair.0, pair.1), + "i ", + format!("{} #[| ]#{}", pair.0, pair.1), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn insert_whitespace_multi() -> anyhow::Result<()> { + for pair in differing_pairs() { + test(( + format!( + indoc! {"\ + {open}#[|{close}]# + {open}#(|{open})#{close}{close} + {open}{open}#(|{close}{close})# + foo#(|\n)# + "}, + open = pair.0, + close = pair.1, + ), + "i ", + format!( + indoc! {"\ + {open} #[| ]#{close} + {open} #(|{open})#{close}{close} + {open}{open} #(| {close}{close})# + foo #(|\n)# + "}, + open = pair.0, + close = pair.1, + ), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn append_whitespace_multi() -> anyhow::Result<()> { + for pair in differing_pairs() { + test(( + format!( + indoc! {"\ + #[|{open}]#{close} + #(|{open})#{open}{close}{close} + #(|{open}{open})#{close}{close} + #(|foo)# + "}, + open = pair.0, + close = pair.1, + ), + "a ", + format!( + indoc! {"\ + #[{open} |]#{close} + #({open} {open}|)#{close}{close} + #({open}{open} |)#{close}{close} + #(foo \n|)# + "}, + open = pair.0, + close = pair.1, + ), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn insert_whitespace_no_pair() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + // sanity check - do not insert extra whitespace unless immediately + // surrounded by a pair + test(( + format!("{} #[|{}]#", pair.0, pair.1), + "i ", + format!("{} #[|{}]#", pair.0, pair.1), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn insert_whitespace_no_matching_pair() -> anyhow::Result<()> { + for pair in differing_pairs() { + // sanity check - verify whitespace does not insert unless both pairs + // are matches, i.e. no two different openers + test(( + format!("{}#[|{}]#", pair.0, pair.0), + "i ", + format!("{} #[|{}]#", pair.0, pair.0), )) .await?; } @@ -567,3 +676,760 @@ async fn append_inside_nested_pair_multi() -> anyhow::Result<()> { Ok(()) } + +#[tokio::test(flavor = "multi_thread")] +async fn delete_basic() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!("{}#[|{}]#{}", pair.0, pair.1, LINE_END), + "i<backspace>", + format!("#[|{}]#", LINE_END), + LineFeedHandling::AsIs, + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_multi() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!( + indoc! {"\ + {open}#[|{close}]# + {open}#(|{close})# + {open}#(|{close})# + "}, + open = pair.0, + close = pair.1, + ), + "i<backspace>", + indoc! {"\ + #[|\n]# + #(|\n)# + #(|\n)# + "}, + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_whitespace() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!("{} #[| ]#{}", pair.0, pair.1), + "i<backspace>", + format!("{}#[|{}]#", pair.0, pair.1), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_whitespace_after_word() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!("foo{} #[| ]#{}", pair.0, pair.1), + "i<backspace>", + format!("foo{}#[|{}]#", pair.0, pair.1), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_whitespace_multi() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!( + indoc! {"\ + {open} #[| ]#{close} + {open} #(|{open})#{close}{close} + {open}{open} #(| {close}{close})# + foo #(|\n)# + "}, + open = pair.0, + close = pair.1, + ), + "i<backspace>", + format!( + indoc! {"\ + {open}#[|{close}]# + {open}#(|{open})#{close}{close} + {open}{open}#(|{close}{close})# + foo#(|\n)# + "}, + open = pair.0, + close = pair.1, + ), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_append_whitespace_multi() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!( + indoc! {"\ + #[{open} |]# {close} + #({open} |)#{open}{close}{close} + #({open}{open} |)# {close}{close} + #(foo |)# + "}, + open = pair.0, + close = pair.1, + ), + "a<backspace>", + format!( + indoc! {"\ + #[{open}{close}|]# + #({open}{open}|)#{close}{close} + #({open}{open}{close}|)#{close} + #(foo\n|)# + "}, + open = pair.0, + close = pair.1, + ), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_whitespace_no_pair() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!("{} #[|{}]#", pair.0, pair.1), + "i<backspace>", + format!("{} #[|{}]#", pair.0, pair.1), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_whitespace_no_matching_pair() -> anyhow::Result<()> { + for pair in differing_pairs() { + test(( + format!("{} #[|{}]#", pair.0, pair.0), + "i<backspace>", + format!("{}#[|{}]#", pair.0, pair.0), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_configured_multi_byte_chars() -> anyhow::Result<()> { + // NOTE: these are multi-byte Unicode characters + let pairs = hashmap!('„' => '“', '‚' => '‘', '「' => '」'); + + let config = Config { + editor: helix_view::editor::Config { + auto_pairs: AutoPairConfig::Pairs(pairs.clone()), + ..Default::default() + }, + ..Default::default() + }; + + for (open, close) in pairs.iter() { + test_with_config( + AppBuilder::new().with_config(config.clone()), + ( + format!("{}#[|{}]#{}", open, close, LINE_END), + "i<backspace>", + format!("#[|{}]#", LINE_END), + LineFeedHandling::AsIs, + ), + ) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_after_word() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + &format!("foo{}#[|{}]#", pair.0, pair.1), + "i<backspace>", + "foo#[|\n]#", + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn insert_then_delete() -> anyhow::Result<()> { + for pair in differing_pairs() { + test(( + "#[\n|]#\n", + format!("ofoo{}<backspace>", pair.0), + "\nfoo#[\n|]#\n", + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn insert_then_delete_whitespace() -> anyhow::Result<()> { + for pair in differing_pairs() { + test(( + "foo#[\n|]#", + format!("i{}<space><backspace><backspace>", pair.0), + "foo#[|\n]#", + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn insert_then_delete_multi() -> anyhow::Result<()> { + for pair in differing_pairs() { + test(( + indoc! {"\ + through a day#[\n|]# + in and out of weeks#(\n|)# + over a year#(\n|)# + "}, + format!("i{}<space><backspace><backspace>", pair.0), + indoc! {"\ + through a day#[|\n]# + in and out of weeks#(|\n)# + over a year#(|\n)# + "}, + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn append_then_delete() -> anyhow::Result<()> { + for pair in differing_pairs() { + test(( + "fo#[o|]#", + format!("a{}<space><backspace><backspace>", pair.0), + "fo#[o\n|]#", + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn append_then_delete_multi() -> anyhow::Result<()> { + for pair in differing_pairs() { + test(( + indoc! {"\ + #[through a day|]# + #(in and out of weeks|)# + #(over a year|)# + "}, + format!("a{}<space><backspace><backspace>", pair.0), + indoc! {"\ + #[through a day\n|]# + #(in and out of weeks\n|)# + #(over a year\n|)# + "}, + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_before_word() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + // sanity check unclosed pair delete + test(( + format!("{}#[|f]#oo{}", pair.0, LINE_END), + "i<backspace>", + format!("#[|f]#oo{}", LINE_END), + )) + .await?; + + // deleting the closing pair should NOT delete the whole pair + test(( + format!("{}{}#[|f]#oo{}", pair.0, pair.1, LINE_END), + "i<backspace>", + format!("{}#[|f]#oo{}", pair.0, LINE_END), + )) + .await?; + + // deleting whole pair before word + test(( + format!("{}#[|{}]#foo{}", pair.0, pair.1, LINE_END), + "i<backspace>", + format!("#[|f]#oo{}", LINE_END), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_before_word_selection() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + // sanity check unclosed pair delete + test(( + format!("{}#[|foo]#{}", pair.0, LINE_END), + "i<backspace>", + format!("#[|foo]#{}", LINE_END), + )) + .await?; + + // deleting the closing pair should NOT delete the whole pair + test(( + format!("{}{}#[|foo]#{}", pair.0, pair.1, LINE_END), + "i<backspace>", + format!("{}#[|foo]#{}", pair.0, LINE_END), + )) + .await?; + + // deleting whole pair before word + test(( + format!("{}#[|{}foo]#{}", pair.0, pair.1, LINE_END), + "i<backspace>", + format!("#[|foo]#{}", LINE_END), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_before_word_selection_trailing_word() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!("foo{}#[|{} wor]#{}", pair.0, pair.1, LINE_END), + "i<backspace>", + format!("foo#[| wor]#{}", LINE_END), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_before_eol() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!( + "{eol}{open}#[|{close}]#{eol}", + eol = LINE_END, + open = pair.0, + close = pair.1 + ), + "i<backspace>", + format!("{0}#[|{0}]#", LINE_END), + LineFeedHandling::AsIs, + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_auto_pairs_disabled() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test_with_config( + AppBuilder::new().with_config(Config { + editor: helix_view::editor::Config { + auto_pairs: AutoPairConfig::Enable(false), + ..Default::default() + }, + ..Default::default() + }), + ( + format!("{}#[|{}]#{}", pair.0, pair.1, LINE_END), + "i<backspace>", + format!("#[|{}]#{}", pair.1, LINE_END), + ), + ) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_before_multi_code_point_graphemes() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!("hello {}#[|👨👩👧👦]# goodbye{}", pair.1, LINE_END), + "i<backspace>", + format!("hello #[|👨👩👧👦]# goodbye{}", LINE_END), + )) + .await?; + + test(( + format!( + "hello {}{}#[|👨👩👧👦]# goodbye{}", + pair.0, pair.1, LINE_END + ), + "i<backspace>", + format!("hello {}#[|👨👩👧👦]# goodbye{}", pair.0, LINE_END), + )) + .await?; + + test(( + format!( + "hello {}#[|{}]#👨👩👧👦 goodbye{}", + pair.0, pair.1, LINE_END + ), + "i<backspace>", + format!("hello #[|👨👩👧👦]# goodbye{}", LINE_END), + )) + .await?; + + test(( + format!( + "hello {}#[|{}👨👩👧👦]# goodbye{}", + pair.0, pair.1, LINE_END + ), + "i<backspace>", + format!("hello #[|👨👩👧👦]# goodbye{}", LINE_END), + )) + .await?; + } + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_at_end_of_document() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(TestCase { + in_text: format!("{}{}{}", LINE_END, pair.0, pair.1), + in_selection: Selection::single(LINE_END.len() + 1, LINE_END.len() + 2), + in_keys: String::from("i<backspace>"), + out_text: String::from(LINE_END), + out_selection: Selection::single(LINE_END.len(), LINE_END.len()), + line_feed_handling: LineFeedHandling::AsIs, + }) + .await?; + + test(TestCase { + in_text: format!("foo{}{}{}", LINE_END, pair.0, pair.1), + in_selection: Selection::single(LINE_END.len() + 4, LINE_END.len() + 5), + in_keys: String::from("i<backspace>"), + out_text: format!("foo{}", LINE_END), + out_selection: Selection::single(3 + LINE_END.len(), 3 + LINE_END.len()), + line_feed_handling: LineFeedHandling::AsIs, + }) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_nested_open_inside_pair() -> anyhow::Result<()> { + for pair in differing_pairs() { + test(( + format!( + "{open}{open}#[|{close}]#{close}{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + "i<backspace>", + format!( + "{open}#[|{close}]#{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_nested_open_inside_pair_multi() -> anyhow::Result<()> { + for outer_pair in DEFAULT_PAIRS { + for inner_pair in DEFAULT_PAIRS { + if inner_pair.0 == outer_pair.0 { + continue; + } + + test(( + format!( + "{outer_open}{inner_open}#[|{inner_close}]#{outer_close}{eol}{outer_open}{inner_open}#(|{inner_close})#{outer_close}{eol}{outer_open}{inner_open}#(|{inner_close})#{outer_close}{eol}", + outer_open = outer_pair.0, + outer_close = outer_pair.1, + inner_open = inner_pair.0, + inner_close = inner_pair.1, + eol = LINE_END + ), + "i<backspace>", + format!( + "{outer_open}#[|{outer_close}]#{eol}{outer_open}#(|{outer_close})#{eol}{outer_open}#(|{outer_close})#{eol}", + outer_open = outer_pair.0, + outer_close = outer_pair.1, + eol = LINE_END + ), + )) + .await?; + } + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_append_basic() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!( + "#[{eol}{open}|]#{close}{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + "a<backspace>", + format!("#[{eol}{eol}|]#", eol = LINE_END), + LineFeedHandling::AsIs, + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_append_multi_range() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!( + "#[ {open}|]#{close}{eol}#( {open}|)#{close}{eol}#( {open}|)#{close}{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + "a<backspace>", + format!("#[ {eol}|]##( {eol}|)##( {eol}|)#", eol = LINE_END), + LineFeedHandling::AsIs, + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_append_end_of_word() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!( + "fo#[o{open}|]#{close}{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + "a<backspace>", + format!("fo#[o{}|]#", LINE_END), + LineFeedHandling::AsIs, + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_mixed_dedent() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!( + indoc! {"\ + bar = {}#[|{}]# + #(|\n)# + foo#(|\n)# + "}, + pair.0, pair.1, + ), + "i<backspace>", + indoc! {"\ + bar = #[|\n]# + #(|\n)# + fo#(|\n)# + "}, + )) + .await?; + + test(( + format!( + indoc! {"\ + bar = {}#[|{}woop]# + #(|word)# + fo#(|o)# + "}, + pair.0, pair.1, + ), + "i<backspace>", + indoc! {"\ + bar = #[|woop]# + #(|word)# + f#(|o)# + "}, + )) + .await?; + + // delete from the right with append + test(( + format!( + indoc! {"\ + bar = #[|woop{}]#{} + #(| )#word + #(|fo)#o + "}, + pair.0, pair.1, + ), + "a<backspace>", + indoc! {"\ + bar = #[woop\n|]# + #(w|)#ord + #(fo|)# + "}, + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_append_end_of_word_multi() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!( + "fo#[o{open}|]#{close}{eol}fo#(o{open}|)#{close}{eol}fo#(o{open}|)#{close}{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + "a<backspace>", + format!("fo#[o{eol}|]#fo#(o{eol}|)#fo#(o{eol}|)#", eol = LINE_END), + LineFeedHandling::AsIs, + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_append_inside_nested_pair() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!( + "f#[oo{open}{open}|]#{close}{close}{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + "a<backspace>", + format!( + "f#[oo{open}{close}|]#{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_append_middle_of_word() -> anyhow::Result<()> { + for pair in DEFAULT_PAIRS { + test(( + format!( + "f#[oo{open}{open}|]#{close}{close}{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + "a<backspace>", + format!( + "f#[oo{open}{close}|]#{eol}", + open = pair.0, + close = pair.1, + eol = LINE_END + ), + )) + .await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn delete_append_inside_nested_pair_multi() -> anyhow::Result<()> { + for outer_pair in DEFAULT_PAIRS { + for inner_pair in DEFAULT_PAIRS { + if inner_pair.0 == outer_pair.0 { + continue; + } + + test(( + format!( + "f#[oo{outer_open}{inner_open}|]#{inner_close}{outer_close}{eol}f#(oo{outer_open}{inner_open}|)#{inner_close}{outer_close}{eol}f#(oo{outer_open}{inner_open}|)#{inner_close}{outer_close}{eol}", + outer_open = outer_pair.0, + outer_close = outer_pair.1, + inner_open = inner_pair.0, + inner_close = inner_pair.1, + eol = LINE_END + ), + "a<backspace>", + format!( + "f#[oo{outer_open}{outer_close}|]#{eol}f#(oo{outer_open}{outer_close}|)#{eol}f#(oo{outer_open}{outer_close}|)#{eol}", + outer_open = outer_pair.0, + outer_close = outer_pair.1, + eol = LINE_END + ), + )) + .await?; + } + } + + Ok(()) +} diff --git a/helix-term/tests/test/commands/movement.rs b/helix-term/tests/test/commands/movement.rs index 5868fa49..684f1dca 100644 --- a/helix-term/tests/test/commands/movement.rs +++ b/helix-term/tests/test/commands/movement.rs @@ -948,3 +948,198 @@ async fn match_bracket() -> anyhow::Result<()> { Ok(()) } + +#[tokio::test(flavor = "multi_thread")] +async fn expand_shrink_selection() -> anyhow::Result<()> { + let tests = vec![ + // single range + ( + indoc! {r##" + Some(#[thing|]#) + "##}, + "<A-o><A-o>", + indoc! {r##" + #[Some(thing)|]# + "##}, + ), + // multi range + ( + indoc! {r##" + Some(#[thing|]#) + Some(#(other_thing|)#) + "##}, + "<A-o>", + indoc! {r##" + Some#[(thing)|]# + Some#((other_thing)|)# + "##}, + ), + // multi range collision merges + ( + indoc! {r##" + ( + Some(#[thing|]#), + Some(#(other_thing|)#), + ) + "##}, + "<A-o><A-o><A-o>", + indoc! {r##" + #[( + Some(thing), + Some(other_thing), + )|]# + "##}, + ), + // multi range collision merges, then shrinks back to original + ( + indoc! {r##" + ( + Some(#[thing|]#), + Some(#(other_thing|)#), + ) + "##}, + "<A-o><A-o><A-o><A-i>", + indoc! {r##" + ( + #[Some(thing)|]#, + #(Some(other_thing)|)#, + ) + "##}, + ), + ( + indoc! {r##" + ( + Some(#[thing|]#), + Some(#(other_thing|)#), + ) + "##}, + "<A-o><A-o><A-o><A-i><A-i>", + indoc! {r##" + ( + Some#[(thing)|]#, + Some#((other_thing)|)#, + ) + "##}, + ), + ( + indoc! {r##" + ( + Some(#[thing|]#), + Some(#(other_thing|)#), + ) + "##}, + "<A-o><A-o><A-o><A-i><A-i><A-i>", + indoc! {r##" + ( + Some(#[thing|]#), + Some(#(other_thing|)#), + ) + "##}, + ), + // shrink with no expansion history defaults to first child + ( + indoc! {r##" + #[( + Some(thing), + Some(other_thing), + )|]# + "##}, + "<A-i>", + indoc! {r##" + ( + #[Some(thing)|]#, + Some(other_thing), + ) + "##}, + ), + // any movement cancels selection history and falls back to first child + ( + indoc! {r##" + ( + Some(#[thing|]#), + Some(#(other_thing|)#), + ) + + "##}, + "<A-o><A-o><A-o>jkvkkk<A-i>", + indoc! {r##" + ( + #[|Some(thing)]#, + Some(other_thing), + ) + + "##}, + ), + ]; + + for test in tests { + test_with_config(AppBuilder::new().with_file("foo.rs", None), test).await?; + } + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn expand_selection_around() -> anyhow::Result<()> { + let tests = vec![ + // single cursor stays single cursor, first goes to end of current + // node, then parent + ( + indoc! {r##" + Some(#[thing|]#) + "##}, + "<A-O><A-O>", + indoc! {r##" + #[Some(|]#thing#()|)# + "##}, + ), + // shrinking restores previous selection + ( + indoc! {r##" + Some(#[thing|]#) + "##}, + "<A-O><A-O><A-i><A-i>", + indoc! {r##" + Some(#[thing|]#) + "##}, + ), + // multi range collision merges expand as normal, except with the + // original selection removed from the result + ( + indoc! {r##" + ( + Some(#[thing|]#), + Some(#(other_thing|)#), + ) + "##}, + "<A-O><A-O><A-O>", + indoc! {r##" + #[( + Some(|]#thing#(), + Some(|)#other_thing#(), + )|)# + "##}, + ), + ( + indoc! {r##" + ( + Some(#[thing|]#), + Some(#(other_thing|)#), + ) + "##}, + "<A-O><A-O><A-O><A-i><A-i><A-i>", + indoc! {r##" + ( + Some(#[thing|]#), + Some(#(other_thing|)#), + ) + "##}, + ), + ]; + + for test in tests { + test_with_config(AppBuilder::new().with_file("foo.rs", None), test).await?; + } + + Ok(()) +} diff --git a/helix-term/tests/test/commands/write.rs b/helix-term/tests/test/commands/write.rs index 4f44cd36..0cf09e1e 100644 --- a/helix-term/tests/test/commands/write.rs +++ b/helix-term/tests/test/commands/write.rs @@ -10,100 +10,6 @@ use helix_view::doc; use super::*; #[tokio::test(flavor = "multi_thread")] -async fn test_exit_w_buffer_w_path() -> anyhow::Result<()> { - let mut file = tempfile::NamedTempFile::new()?; - let mut app = helpers::AppBuilder::new() - .with_file(file.path(), None) - .build()?; - // Check for write operation on given path and edited buffer - test_key_sequence( - &mut app, - Some("iBecause of the obvious threat to untold numbers of citizens due to the crisis that is even now developing, this radio station will remain on the air day and night.<ret><esc>:x<ret>"), - None, - true, - ) - .await?; - - reload_file(&mut file).unwrap(); - let mut file_content = String::new(); - file.as_file_mut().read_to_string(&mut file_content)?; - - assert_eq!( - LineFeedHandling::Native.apply("Because of the obvious threat to untold numbers of citizens due to the crisis that is even now developing, this radio station will remain on the air day and night.\n"), - file_content - ); - - Ok(()) -} - -#[tokio::test(flavor = "multi_thread")] -async fn test_exit_wo_buffer_w_path() -> anyhow::Result<()> { - let mut file = tempfile::NamedTempFile::new()?; - let mut app = helpers::AppBuilder::new() - .with_file(file.path(), None) - .build()?; - - helpers::run_event_loop_until_idle(&mut app).await; - - file.as_file_mut() - .write_all("extremely important content".as_bytes())?; - file.as_file_mut().flush()?; - file.as_file_mut().sync_all()?; - - test_key_sequence(&mut app, Some(":x<ret>"), None, true).await?; - - reload_file(&mut file).unwrap(); - let mut file_content = String::new(); - file.read_to_string(&mut file_content)?; - // check that nothing is written to file - assert_eq!("extremely important content", file_content); - - Ok(()) -} - -#[tokio::test(flavor = "multi_thread")] -async fn test_exit_wo_buffer_wo_path() -> anyhow::Result<()> { - test_key_sequence( - &mut AppBuilder::new().build()?, - Some(":x<ret>"), - Some(&|app| { - assert!(!app.editor.is_err()); - }), - true, - ) - .await?; - - Ok(()) -} - -#[tokio::test(flavor = "multi_thread")] -async fn test_exit_w_buffer_wo_file() -> anyhow::Result<()> { - let mut file = tempfile::NamedTempFile::new()?; - test_key_sequence( - // try to write without destination - &mut AppBuilder::new().build()?, - Some("itest<esc>:x<ret>"), - None, - false, - ) - .await?; - test_key_sequence( - // try to write with path succeeds - &mut AppBuilder::new().build()?, - Some(format!("iMicCheck<esc>:x {}<ret>", file.path().to_string_lossy()).as_ref()), - Some(&|app| { - assert!(!app.editor.is_err()); - }), - true, - ) - .await?; - - helpers::assert_file_has_content(&mut file, &LineFeedHandling::Native.apply("MicCheck"))?; - - Ok(()) -} - -#[tokio::test(flavor = "multi_thread")] async fn test_write_quit_fail() -> anyhow::Result<()> { let file = helpers::new_readonly_tempfile()?; let mut app = helpers::AppBuilder::new() @@ -238,7 +144,7 @@ async fn test_overwrite_protection() -> anyhow::Result<()> { file.as_file_mut().flush()?; file.as_file_mut().sync_all()?; - test_key_sequence(&mut app, Some("iOverwriteData<esc>:x<ret>"), None, false).await?; + test_key_sequence(&mut app, Some(":x<ret>"), None, false).await?; reload_file(&mut file).unwrap(); let mut file_content = String::new(); diff --git a/helix-term/tests/test/helpers.rs b/helix-term/tests/test/helpers.rs index 567422c3..60143aaa 100644 --- a/helix-term/tests/test/helpers.rs +++ b/helix-term/tests/test/helpers.rs @@ -10,12 +10,8 @@ use helix_core::{diagnostic::Severity, test, Selection, Transaction}; use helix_term::{application::Application, args::Args, config::Config, keymap::merge_keys}; use helix_view::{current_ref, doc, editor::LspConfig, input::parse_macro, Editor}; use tempfile::NamedTempFile; -use tokio_stream::wrappers::UnboundedReceiverStream; - -#[cfg(windows)] -use crossterm::event::{Event, KeyEvent}; -#[cfg(not(windows))] use termina::event::{Event, KeyEvent}; +use tokio_stream::wrappers::UnboundedReceiverStream; /// Specify how to set up the input text with line feeds #[derive(Clone, Debug)] diff --git a/helix-tui/Cargo.toml b/helix-tui/Cargo.toml index bcf890f5..c0820dd7 100644 --- a/helix-tui/Cargo.toml +++ b/helix-tui/Cargo.toml @@ -12,7 +12,7 @@ repository.workspace = true homepage.workspace = true [features] -default = ["termina", "crossterm"] +default = ["termina"] [dependencies] helix-view = { path = "../helix-view", features = ["term"] } @@ -25,6 +25,3 @@ termina = { workspace = true, optional = true } termini = "1.0" once_cell = "1.21" log = "~0.4" - -[target.'cfg(windows)'.dependencies] -crossterm = { version = "0.28", optional = true } diff --git a/helix-tui/src/backend/crossterm.rs b/helix-tui/src/backend/crossterm.rs deleted file mode 100644 index 3b53c21f..00000000 --- a/helix-tui/src/backend/crossterm.rs +++ /dev/null @@ -1,454 +0,0 @@ -use crate::{backend::Backend, buffer::Cell, terminal::Config}; -use crossterm::{ - cursor::{Hide, MoveTo, SetCursorStyle, Show}, - event::{ - DisableBracketedPaste, DisableFocusChange, DisableMouseCapture, EnableBracketedPaste, - EnableFocusChange, EnableMouseCapture, KeyboardEnhancementFlags, - PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags, - }, - execute, queue, - style::{ - Attribute as CAttribute, Color as CColor, Colors, Print, SetAttribute, SetBackgroundColor, - SetColors, SetForegroundColor, - }, - terminal::{self, Clear, ClearType}, - Command, -}; -use helix_view::graphics::{Color, CursorKind, Modifier, Rect, UnderlineStyle}; -use once_cell::sync::OnceCell; -use std::{ - fmt, - io::{self, Write}, -}; -use termini::TermInfo; - -fn term_program() -> Option<String> { - // Some terminals don't set $TERM_PROGRAM - match std::env::var("TERM_PROGRAM") { - Err(_) => std::env::var("TERM").ok(), - Ok(term_program) => Some(term_program), - } -} -fn vte_version() -> Option<usize> { - std::env::var("VTE_VERSION").ok()?.parse().ok() -} -fn reset_cursor_approach(terminfo: TermInfo) -> String { - let mut reset_str = "\x1B[0 q".to_string(); - - if let Some(termini::Value::Utf8String(se_str)) = terminfo.extended_cap("Se") { - reset_str.push_str(se_str); - }; - - reset_str.push_str( - terminfo - .utf8_string_cap(termini::StringCapability::CursorNormal) - .unwrap_or(""), - ); - - reset_str -} - -/// Describes terminal capabilities like extended underline, truecolor, etc. -#[derive(Clone, Debug)] -struct Capabilities { - /// Support for undercurled, underdashed, etc. - has_extended_underlines: bool, - /// Support for resetting the cursor style back to normal. - reset_cursor_command: String, -} - -impl Default for Capabilities { - fn default() -> Self { - Self { - has_extended_underlines: false, - reset_cursor_command: "\x1B[0 q".to_string(), - } - } -} - -impl Capabilities { - /// Detect capabilities from the terminfo database located based - /// on the $TERM environment variable. If detection fails, returns - /// a default value where no capability is supported, or just undercurl - /// if config.undercurl is set. - pub fn from_env_or_default(config: &Config) -> Self { - match termini::TermInfo::from_env() { - Err(_) => Capabilities { - has_extended_underlines: config.force_enable_extended_underlines, - ..Capabilities::default() - }, - Ok(t) => Capabilities { - // Smulx, VTE: https://unix.stackexchange.com/a/696253/246284 - // Su (used by kitty): https://sw.kovidgoyal.net/kitty/underlines - // WezTerm supports underlines but a lot of distros don't properly install its terminfo - has_extended_underlines: config.force_enable_extended_underlines - || t.extended_cap("Smulx").is_some() - || t.extended_cap("Su").is_some() - || vte_version() >= Some(5102) - || matches!(term_program().as_deref(), Some("WezTerm")), - reset_cursor_command: reset_cursor_approach(t), - }, - } - } -} - -/// Terminal backend supporting a wide variety of terminals -pub struct CrosstermBackend<W: Write> { - buffer: W, - config: Config, - capabilities: Capabilities, - supports_keyboard_enhancement_protocol: OnceCell<bool>, - mouse_capture_enabled: bool, - supports_bracketed_paste: bool, -} - -impl<W> CrosstermBackend<W> -where - W: Write, -{ - pub fn new(buffer: W, config: Config) -> CrosstermBackend<W> { - // helix is not usable without colors, but crossterm will disable - // them by default if NO_COLOR is set in the environment. Override - // this behaviour. - crossterm::style::force_color_output(true); - CrosstermBackend { - buffer, - capabilities: Capabilities::from_env_or_default(&config), - config, - supports_keyboard_enhancement_protocol: OnceCell::new(), - mouse_capture_enabled: false, - supports_bracketed_paste: true, - } - } - - #[inline] - fn supports_keyboard_enhancement_protocol(&self) -> bool { - *self.supports_keyboard_enhancement_protocol - .get_or_init(|| { - use std::time::Instant; - - let now = Instant::now(); - let supported = matches!(terminal::supports_keyboard_enhancement(), Ok(true)); - log::debug!( - "The keyboard enhancement protocol is {}supported in this terminal (checked in {:?})", - if supported { "" } else { "not " }, - Instant::now().duration_since(now) - ); - supported - }) - } -} - -impl<W> Write for CrosstermBackend<W> -where - W: Write, -{ - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - self.buffer.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.buffer.flush() - } -} - -impl<W> Backend for CrosstermBackend<W> -where - W: Write, -{ - fn claim(&mut self) -> io::Result<()> { - terminal::enable_raw_mode()?; - execute!( - self.buffer, - terminal::EnterAlternateScreen, - EnableFocusChange - )?; - match execute!(self.buffer, EnableBracketedPaste,) { - Err(err) if err.kind() == io::ErrorKind::Unsupported => { - log::warn!("Bracketed paste is not supported on this terminal."); - self.supports_bracketed_paste = false; - } - Err(err) => return Err(err), - Ok(_) => (), - }; - execute!(self.buffer, terminal::Clear(terminal::ClearType::All))?; - if self.config.enable_mouse_capture { - execute!(self.buffer, EnableMouseCapture)?; - self.mouse_capture_enabled = true; - } - if self.supports_keyboard_enhancement_protocol() { - execute!( - self.buffer, - PushKeyboardEnhancementFlags( - KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES - | KeyboardEnhancementFlags::REPORT_ALTERNATE_KEYS - ) - )?; - } - Ok(()) - } - - fn reconfigure(&mut self, config: Config) -> io::Result<()> { - if self.mouse_capture_enabled != config.enable_mouse_capture { - if config.enable_mouse_capture { - execute!(self.buffer, EnableMouseCapture)?; - } else { - execute!(self.buffer, DisableMouseCapture)?; - } - self.mouse_capture_enabled = config.enable_mouse_capture; - } - self.config = config; - - Ok(()) - } - - fn restore(&mut self) -> io::Result<()> { - // reset cursor shape - self.buffer - .write_all(self.capabilities.reset_cursor_command.as_bytes())?; - if self.config.enable_mouse_capture { - execute!(self.buffer, DisableMouseCapture)?; - } - if self.supports_keyboard_enhancement_protocol() { - execute!(self.buffer, PopKeyboardEnhancementFlags)?; - } - if self.supports_bracketed_paste { - execute!(self.buffer, DisableBracketedPaste,)?; - } - execute!( - self.buffer, - DisableFocusChange, - terminal::LeaveAlternateScreen - )?; - terminal::disable_raw_mode() - } - - fn draw<'a, I>(&mut self, content: I) -> io::Result<()> - where - I: Iterator<Item = (u16, u16, &'a Cell)>, - { - let mut fg = Color::Reset; - let mut bg = Color::Reset; - let mut underline_color = Color::Reset; - let mut underline_style = UnderlineStyle::Reset; - let mut modifier = Modifier::empty(); - let mut last_pos: Option<(u16, u16)> = None; - for (x, y, cell) in content { - // Move the cursor if the previous location was not (x - 1, y) - if !matches!(last_pos, Some(p) if x == p.0 + 1 && y == p.1) { - queue!(self.buffer, MoveTo(x, y))?; - } - last_pos = Some((x, y)); - if cell.modifier != modifier { - let diff = ModifierDiff { - from: modifier, - to: cell.modifier, - }; - diff.queue(&mut self.buffer)?; - modifier = cell.modifier; - } - if cell.fg != fg || cell.bg != bg { - queue!( - self.buffer, - SetColors(Colors::new(cell.fg.into(), cell.bg.into())) - )?; - fg = cell.fg; - bg = cell.bg; - } - - let mut new_underline_style = cell.underline_style; - if self.capabilities.has_extended_underlines { - if cell.underline_color != underline_color { - let color = CColor::from(cell.underline_color); - queue!(self.buffer, SetUnderlineColor(color))?; - underline_color = cell.underline_color; - } - } else { - match new_underline_style { - UnderlineStyle::Reset | UnderlineStyle::Line => (), - _ => new_underline_style = UnderlineStyle::Line, - } - } - - if new_underline_style != underline_style { - let attr = CAttribute::from(new_underline_style); - queue!(self.buffer, SetAttribute(attr))?; - underline_style = new_underline_style; - } - - queue!(self.buffer, Print(&cell.symbol))?; - } - - queue!( - self.buffer, - SetUnderlineColor(CColor::Reset), - SetForegroundColor(CColor::Reset), - SetBackgroundColor(CColor::Reset), - SetAttribute(CAttribute::Reset) - ) - } - - fn hide_cursor(&mut self) -> io::Result<()> { - execute!(self.buffer, Hide) - } - - fn show_cursor(&mut self, kind: CursorKind) -> io::Result<()> { - let shape = match kind { - CursorKind::Block => SetCursorStyle::SteadyBlock, - CursorKind::Bar => SetCursorStyle::SteadyBar, - CursorKind::Underline => SetCursorStyle::SteadyUnderScore, - CursorKind::Hidden => unreachable!(), - }; - execute!(self.buffer, Show, shape) - } - - fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> { - execute!(self.buffer, MoveTo(x, y)) - } - - fn clear(&mut self) -> io::Result<()> { - execute!(self.buffer, Clear(ClearType::All)) - } - - fn size(&self) -> io::Result<Rect> { - let (width, height) = - terminal::size().map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?; - - Ok(Rect::new(0, 0, width, height)) - } - - fn flush(&mut self) -> io::Result<()> { - self.buffer.flush() - } - - fn supports_true_color(&self) -> bool { - false - } - - fn get_theme_mode(&self) -> Option<helix_view::theme::Mode> { - None - } -} - -#[derive(Debug)] -struct ModifierDiff { - pub from: Modifier, - pub to: Modifier, -} - -impl ModifierDiff { - fn queue<W>(&self, mut w: W) -> io::Result<()> - where - W: io::Write, - { - //use crossterm::Attribute; - let removed = self.from - self.to; - if removed.contains(Modifier::REVERSED) { - queue!(w, SetAttribute(CAttribute::NoReverse))?; - } - if removed.contains(Modifier::BOLD) { - queue!(w, SetAttribute(CAttribute::NormalIntensity))?; - if self.to.contains(Modifier::DIM) { - queue!(w, SetAttribute(CAttribute::Dim))?; - } - } - if removed.contains(Modifier::ITALIC) { - queue!(w, SetAttribute(CAttribute::NoItalic))?; - } - if removed.contains(Modifier::DIM) { - queue!(w, SetAttribute(CAttribute::NormalIntensity))?; - } - if removed.contains(Modifier::CROSSED_OUT) { - queue!(w, SetAttribute(CAttribute::NotCrossedOut))?; - } - if removed.contains(Modifier::SLOW_BLINK) || removed.contains(Modifier::RAPID_BLINK) { - queue!(w, SetAttribute(CAttribute::NoBlink))?; - } - if removed.contains(Modifier::HIDDEN) { - queue!(w, SetAttribute(CAttribute::NoHidden))?; - } - - let added = self.to - self.from; - if added.contains(Modifier::REVERSED) { - queue!(w, SetAttribute(CAttribute::Reverse))?; - } - if added.contains(Modifier::BOLD) { - queue!(w, SetAttribute(CAttribute::Bold))?; - } - if added.contains(Modifier::ITALIC) { - queue!(w, SetAttribute(CAttribute::Italic))?; - } - if added.contains(Modifier::DIM) { - queue!(w, SetAttribute(CAttribute::Dim))?; - } - if added.contains(Modifier::CROSSED_OUT) { - queue!(w, SetAttribute(CAttribute::CrossedOut))?; - } - if added.contains(Modifier::SLOW_BLINK) { - queue!(w, SetAttribute(CAttribute::SlowBlink))?; - } - if added.contains(Modifier::RAPID_BLINK) { - queue!(w, SetAttribute(CAttribute::RapidBlink))?; - } - if added.contains(Modifier::HIDDEN) { - queue!(w, SetAttribute(CAttribute::Hidden))?; - } - - Ok(()) - } -} - -/// Crossterm uses semicolon as a separator for colors -/// this is actually not spec compliant (although commonly supported) -/// However the correct approach is to use colons as a separator. -/// This usually doesn't make a difference for emulators that do support colored underlines. -/// However terminals that do not support colored underlines will ignore underlines colors with colons -/// while escape sequences with semicolons are always processed which leads to weird visual artifacts. -/// See [this nvim issue](https://github.com/neovim/neovim/issues/9270) for details -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct SetUnderlineColor(pub CColor); - -impl Command for SetUnderlineColor { - fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result { - let color = self.0; - - if color == CColor::Reset { - write!(f, "\x1b[59m")?; - return Ok(()); - } - f.write_str("\x1b[58:")?; - - let res = match color { - CColor::Black => f.write_str("5:0"), - CColor::DarkGrey => f.write_str("5:8"), - CColor::Red => f.write_str("5:9"), - CColor::DarkRed => f.write_str("5:1"), - CColor::Green => f.write_str("5:10"), - CColor::DarkGreen => f.write_str("5:2"), - CColor::Yellow => f.write_str("5:11"), - CColor::DarkYellow => f.write_str("5:3"), - CColor::Blue => f.write_str("5:12"), - CColor::DarkBlue => f.write_str("5:4"), - CColor::Magenta => f.write_str("5:13"), - CColor::DarkMagenta => f.write_str("5:5"), - CColor::Cyan => f.write_str("5:14"), - CColor::DarkCyan => f.write_str("5:6"), - CColor::White => f.write_str("5:15"), - CColor::Grey => f.write_str("5:7"), - CColor::Rgb { r, g, b } => write!(f, "2::{}:{}:{}", r, g, b), - CColor::AnsiValue(val) => write!(f, "5:{}", val), - _ => Ok(()), - }; - res?; - write!(f, "m")?; - Ok(()) - } - - #[cfg(windows)] - fn execute_winapi(&self) -> io::Result<()> { - Err(std::io::Error::new( - std::io::ErrorKind::Other, - "SetUnderlineColor not supported by winapi.", - )) - } -} diff --git a/helix-tui/src/backend/mod.rs b/helix-tui/src/backend/mod.rs index 368a1b66..3f0ec355 100644 --- a/helix-tui/src/backend/mod.rs +++ b/helix-tui/src/backend/mod.rs @@ -6,16 +6,11 @@ use crate::{buffer::Cell, terminal::Config}; use helix_view::graphics::{CursorKind, Rect}; -#[cfg(all(feature = "termina", not(windows)))] +#[cfg(feature = "termina")] mod termina; -#[cfg(all(feature = "termina", not(windows)))] +#[cfg(feature = "termina")] pub use self::termina::TerminaBackend; -#[cfg(all(feature = "termina", windows))] -mod crossterm; -#[cfg(all(feature = "termina", windows))] -pub use self::crossterm::CrosstermBackend; - mod test; pub use self::test::TestBackend; @@ -44,5 +39,4 @@ pub trait Backend { /// Flushes the terminal buffer fn flush(&mut self) -> Result<(), io::Error>; fn supports_true_color(&self) -> bool; - fn get_theme_mode(&self) -> Option<helix_view::theme::Mode>; } diff --git a/helix-tui/src/backend/termina.rs b/helix-tui/src/backend/termina.rs index ad1c7c68..52912161 100644 --- a/helix-tui/src/backend/termina.rs +++ b/helix-tui/src/backend/termina.rs @@ -3,7 +3,7 @@ use std::io::{self, Write as _}; use helix_view::{ editor::KittyKeyboardProtocolConfig, graphics::{CursorKind, Rect, UnderlineStyle}, - theme::{self, Color, Modifier}, + theme::{Color, Modifier}, }; use termina::{ escape::{ @@ -52,7 +52,6 @@ struct Capabilities { synchronized_output: bool, true_color: bool, extended_underlines: bool, - theme_mode: Option<theme::Mode>, } #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] @@ -149,13 +148,11 @@ impl TerminaBackend { // If we only receive the device attributes then we know it is not. write!( terminal, - "{}{}{}{}{}{}{}", + "{}{}{}{}{}{}", // Synchronized output Csi::Mode(csi::Mode::QueryDecPrivateMode(csi::DecPrivateMode::Code( csi::DecPrivateModeCode::SynchronizedOutput ))), - // Mode 2031 theme updates. Query the current theme. - Csi::Mode(csi::Mode::QueryTheme), // True color and while we're at it, extended underlines: // <https://github.com/termstandard/colors?tab=readme-ov-file#querying-the-terminal> Csi::Sgr(csi::Sgr::Background(TEST_COLOR.into())), @@ -187,9 +184,6 @@ impl TerminaBackend { })) => { capabilities.synchronized_output = true; } - Event::Csi(Csi::Mode(csi::Mode::ReportTheme(mode))) => { - capabilities.theme_mode = Some(mode.into()); - } Event::Dcs(dcs::Dcs::Response { value: dcs::DcsResponse::GraphicRendition(sgrs), .. @@ -326,11 +320,6 @@ impl TerminaBackend { } } - if self.capabilities.theme_mode.is_some() { - // Enable mode 2031 theme mode notifications: - write!(self.terminal, "{}", decset!(Theme))?; - } - Ok(()) } @@ -343,11 +332,6 @@ impl TerminaBackend { )?; } - if self.capabilities.theme_mode.is_some() { - // Mode 2031 theme notifications. - write!(self.terminal, "{}", decreset!(Theme))?; - } - Ok(()) } @@ -566,10 +550,6 @@ impl Backend for TerminaBackend { fn supports_true_color(&self) -> bool { self.capabilities.true_color } - - fn get_theme_mode(&self) -> Option<theme::Mode> { - self.capabilities.theme_mode - } } impl Drop for TerminaBackend { diff --git a/helix-tui/src/backend/test.rs b/helix-tui/src/backend/test.rs index b048cefc..37b5ff5c 100644 --- a/helix-tui/src/backend/test.rs +++ b/helix-tui/src/backend/test.rs @@ -160,8 +160,4 @@ impl Backend for TestBackend { fn supports_true_color(&self) -> bool { false } - - fn get_theme_mode(&self) -> Option<helix_view::theme::Mode> { - None - } } diff --git a/helix-tui/src/terminal.rs b/helix-tui/src/terminal.rs index 5e4007fc..72f38d71 100644 --- a/helix-tui/src/terminal.rs +++ b/helix-tui/src/terminal.rs @@ -73,14 +73,6 @@ where viewport: Viewport, } -/// Default terminal size: 80 columns, 24 lines -pub const DEFAULT_TERMINAL_SIZE: Rect = Rect { - x: 0, - y: 0, - width: 80, - height: 24, -}; - impl<B> Terminal<B> where B: Backend, @@ -88,7 +80,7 @@ where /// Wrapper around Terminal initialization. Each buffer is initialized with a blank string and /// default colors for the foreground and the background pub fn new(backend: B) -> io::Result<Terminal<B>> { - let size = backend.size().unwrap_or(DEFAULT_TERMINAL_SIZE); + let size = backend.size()?; Terminal::with_options( backend, TerminalOptions { @@ -167,7 +159,7 @@ where /// Queries the backend for size and resizes if it doesn't match the previous size. pub fn autoresize(&mut self) -> io::Result<Rect> { - let size = self.size(); + let size = self.size()?; if size != self.viewport.area { self.resize(size)?; }; @@ -243,7 +235,7 @@ where } /// Queries the real size of the backend. - pub fn size(&self) -> Rect { - self.backend.size().unwrap_or(DEFAULT_TERMINAL_SIZE) + pub fn size(&self) -> io::Result<Rect> { + self.backend.size() } } diff --git a/helix-tui/src/widgets/table.rs b/helix-tui/src/widgets/table.rs index 5f4667b7..57f44883 100644 --- a/helix-tui/src/widgets/table.rs +++ b/helix-tui/src/widgets/table.rs @@ -37,14 +37,15 @@ pub struct Cell<'a> { impl Cell<'_> { /// Set the `Style` of this cell. pub fn style(mut self, style: Style) -> Self { - self.set_style(style); + self.style = style; + self.content.set_style(style); self } /// Set the `Style` of this cell. pub fn set_style(&mut self, style: Style) { self.style = style; - self.content.patch_style(style); + self.content.set_style(style); } } diff --git a/helix-vcs/Cargo.toml b/helix-vcs/Cargo.toml index 3c9b1c7f..e51222a2 100644 --- a/helix-vcs/Cargo.toml +++ b/helix-vcs/Cargo.toml @@ -17,7 +17,7 @@ tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "p parking_lot.workspace = true arc-swap = { version = "1.7.1" } -gix = { version = "0.74.1", features = ["attributes", "status"], default-features = false, optional = true } +gix = { version = "0.73.0", features = ["attributes", "status"], default-features = false, optional = true } imara-diff = "0.2.0" anyhow = "1" diff --git a/helix-vcs/src/diff.rs b/helix-vcs/src/diff.rs index d87f3ce7..cc97ef85 100644 --- a/helix-vcs/src/diff.rs +++ b/helix-vcs/src/diff.rs @@ -72,7 +72,7 @@ impl DiffHandle { } /// Load the actual diff - pub fn load(&self) -> Diff<'_> { + pub fn load(&self) -> Diff { Diff { diff: self.diff.read(), inverted: self.inverted, diff --git a/helix-vcs/src/diff/line_cache.rs b/helix-vcs/src/diff/line_cache.rs index 187ac540..4a03a8f5 100644 --- a/helix-vcs/src/diff/line_cache.rs +++ b/helix-vcs/src/diff/line_cache.rs @@ -128,7 +128,7 @@ impl InternedRopeLines { /// Returns the `InternedInput` for performing the diff. /// If `diff_base` or `doc` is so large that performing a diff could slow the editor /// this function returns `None`. - pub fn interned_lines(&self) -> Option<&InternedInput<RopeSlice<'_>>> { + pub fn interned_lines(&self) -> Option<&InternedInput<RopeSlice>> { if self.is_too_large() { None } else { diff --git a/helix-vcs/src/diff/worker.rs b/helix-vcs/src/diff/worker.rs index 0caab36f..3471b4cb 100644 --- a/helix-vcs/src/diff/worker.rs +++ b/helix-vcs/src/diff/worker.rs @@ -102,7 +102,7 @@ struct EventAccumulator { render_lock: Option<RenderLock>, } -impl EventAccumulator { +impl<'a> EventAccumulator { fn new() -> EventAccumulator { EventAccumulator { diff_base: None, diff --git a/helix-vcs/src/git.rs b/helix-vcs/src/git.rs index 6544c35c..1be71afa 100644 --- a/helix-vcs/src/git.rs +++ b/helix-vcs/src/git.rs @@ -162,7 +162,7 @@ fn status(repo: &Repository, f: impl Fn(Result<FileChange>) -> bool) -> Result<( } => { let path = work_dir.join(rela_path.to_path()?); match status { - EntryStatus::Conflict { .. } => FileChange::Conflict { path }, + EntryStatus::Conflict(_) => FileChange::Conflict { path }, EntryStatus::Change(Change::Removed) => FileChange::Deleted { path }, EntryStatus::Change(Change::Modification { .. }) => { FileChange::Modified { path } diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index 24dd0f2a..ab8c9fe5 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -12,7 +12,7 @@ homepage.workspace = true [features] default = [] -term = ["termina", "crossterm"] +term = ["termina"] unicode-lines = [] [dependencies] @@ -56,11 +56,10 @@ kstring = "2.0" [target.'cfg(windows)'.dependencies] clipboard-win = { version = "5.4", features = ["std"] } -crossterm = { version = "0.28", optional = true } [target.'cfg(unix)'.dependencies] libc = "0.2" -rustix = { version = "1.1", features = ["fs"] } +rustix = { version = "1.0", features = ["fs"] } [dev-dependencies] helix-tui = { path = "../helix-tui" } diff --git a/helix-view/src/annotations/diagnostics.rs b/helix-view/src/annotations/diagnostics.rs index dc141462..be36cd01 100644 --- a/helix-view/src/annotations/diagnostics.rs +++ b/helix-view/src/annotations/diagnostics.rs @@ -186,7 +186,7 @@ impl<'a> InlineDiagnosticAccumulator<'a> { .doc .diagnostics .get(self.idx) - .is_none_or(|diag| diag.range.start != grapheme.char_idx) + .map_or(true, |diag| diag.range.start != grapheme.char_idx) { return false; } diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index e52dbe0f..c0672001 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -204,14 +204,11 @@ pub struct Document { pub readonly: bool, - pub previous_diagnostic_id: Option<String>, - /// Annotations for LSP document color swatches pub color_swatches: Option<DocumentColorSwatches>, // NOTE: ideally this would live on the handler for color swatches. This is blocked on a // large refactor that would make `&mut Editor` available on the `DocumentDidChange` event. pub color_swatch_controller: TaskController, - pub pull_diagnostic_controller: TaskController, // NOTE: this field should eventually go away - we should use the Editor's syn_loader instead // of storing a copy on every doc. Then we can remove the surrounding `Arc` and use the @@ -731,8 +728,6 @@ impl Document { color_swatches: None, color_swatch_controller: TaskController::new(), syn_loader, - previous_diagnostic_id: None, - pull_diagnostic_controller: TaskController::new(), } } @@ -980,7 +975,7 @@ impl Document { }; let identifier = self.path().map(|_| self.identifier()); - let language_servers: Vec<_> = self.language_servers.values().cloned().collect(); + let language_servers = self.language_servers.clone(); // mark changes up to now as saved let current_rev = self.get_current_revision(); @@ -1124,7 +1119,7 @@ impl Document { text: text.clone(), }; - for language_server in language_servers { + for (_, language_server) in language_servers { if !language_server.is_initialized() { continue; } @@ -1325,15 +1320,27 @@ impl Document { Ok(()) } - /// Select text within the [`Document`]. - pub fn set_selection(&mut self, view_id: ViewId, selection: Selection) { + /// Select text within the [`Document`], optionally clearing the previous selection state. + pub fn set_selection_clear(&mut self, view_id: ViewId, selection: Selection, clear_prev: bool) { // TODO: use a transaction? self.selections .insert(view_id, selection.ensure_invariants(self.text().slice(..))); + helix_event::dispatch(SelectionDidChange { doc: self, view: view_id, - }) + }); + + if clear_prev { + self.view_data + .entry(view_id) + .and_modify(|view_data| view_data.object_selections.clear()); + } + } + + /// Select text within the [`Document`]. + pub fn set_selection(&mut self, view_id: ViewId, selection: Selection) { + self.set_selection_clear(view_id, selection, true); } /// Find the origin selection of the text in a document, i.e. where @@ -1525,6 +1532,12 @@ impl Document { apply_inlay_hint_changes(padding_after_inlay_hints); } + // clear out all associated view object selections, as they are no + // longer valid + self.view_data + .values_mut() + .for_each(|view_data| view_data.object_selections.clear()); + helix_event::dispatch(DocumentDidChange { doc: self, view: view_id, @@ -1660,7 +1673,7 @@ impl Document { let savepoint_idx = self .savepoints .iter() - .position(|savepoint_ref| std::ptr::eq(savepoint_ref.as_ptr(), savepoint)) + .position(|savepoint_ref| savepoint_ref.as_ptr() == savepoint as *const _) .expect("Savepoint must belong to this document"); let savepoint_ref = self.savepoints.remove(savepoint_idx); @@ -1967,13 +1980,13 @@ impl Document { &self.selections } - fn view_data(&self, view_id: ViewId) -> &ViewData { + pub fn view_data(&self, view_id: ViewId) -> &ViewData { self.view_data .get(&view_id) .expect("This should only be called after ensure_view_init") } - fn view_data_mut(&mut self, view_id: ViewId) -> &mut ViewData { + pub fn view_data_mut(&mut self, view_id: ViewId) -> &mut ViewData { self.view_data.entry(view_id).or_default() } @@ -2289,15 +2302,15 @@ impl Document { pub fn reset_all_inlay_hints(&mut self) { self.inlay_hints = Default::default(); } - - pub fn has_language_server_with_feature(&self, feature: LanguageServerFeature) -> bool { - self.language_servers_with_feature(feature).next().is_some() - } } +/// Stores data needed for views that are tied to this specific Document. #[derive(Debug, Default)] pub struct ViewData { view_position: ViewPosition, + + /// used to store previous selections of tree-sitter objects + pub object_selections: HashMap<&'static str, Vec<Selection>>, } #[derive(Clone, Debug)] @@ -2348,6 +2361,7 @@ mod test { Arc::new(ArcSwap::from_pointee(syntax::Loader::default())), ); let view = ViewId::default(); + doc.ensure_view_init(view); doc.set_selection(view, Selection::single(0, 0)); let transaction = @@ -2386,7 +2400,9 @@ mod test { Arc::new(ArcSwap::new(Arc::new(Config::default()))), Arc::new(ArcSwap::from_pointee(syntax::Loader::default())), ); + let view = ViewId::default(); + doc.ensure_view_init(view); doc.set_selection(view, Selection::single(5, 5)); // insert diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 7f8cff9c..162d2b1f 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -221,49 +221,6 @@ impl Default for FilePickerConfig { } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case", default, deny_unknown_fields)] -pub struct FileExplorerConfig { - /// IgnoreOptions - /// Enables ignoring hidden files. - /// Whether to hide hidden files in file explorer and global search results. Defaults to false. - pub hidden: bool, - /// Enables following symlinks. - /// Whether to follow symbolic links in file picker and file or directory completions. Defaults to false. - pub follow_symlinks: bool, - /// Enables reading ignore files from parent directories. Defaults to false. - pub parents: bool, - /// Enables reading `.ignore` files. - /// Whether to hide files listed in .ignore in file picker and global search results. Defaults to false. - pub ignore: bool, - /// Enables reading `.gitignore` files. - /// Whether to hide files listed in .gitignore in file picker and global search results. Defaults to false. - pub git_ignore: bool, - /// Enables reading global .gitignore, whose path is specified in git's config: `core.excludefile` option. - /// Whether to hide files listed in global .gitignore in file picker and global search results. Defaults to false. - pub git_global: bool, - /// Enables reading `.git/info/exclude` files. - /// Whether to hide files listed in .git/info/exclude in file picker and global search results. Defaults to false. - pub git_exclude: bool, - /// Whether to flatten single-child directories in file explorer. Defaults to true. - pub flatten_dirs: bool, -} - -impl Default for FileExplorerConfig { - fn default() -> Self { - Self { - hidden: false, - follow_symlinks: false, - parents: false, - ignore: false, - git_ignore: false, - git_global: false, - git_exclude: false, - flatten_dirs: true, - } - } -} - fn serialize_alphabet<S>(alphabet: &[char], serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, @@ -361,7 +318,6 @@ pub struct Config { /// Whether to display infoboxes. Defaults to true. pub auto_info: bool, pub file_picker: FilePickerConfig, - pub file_explorer: FileExplorerConfig, /// Configuration of the statusline elements pub statusline: StatusLineConfig, /// Shape for cursor in each mode @@ -1082,7 +1038,6 @@ impl Default for Config { completion_trigger_len: 2, auto_info: true, file_picker: FilePickerConfig::default(), - file_explorer: FileExplorerConfig::default(), statusline: StatusLineConfig::default(), cursor_shape: CursorShapeConfig::default(), true_color: false, @@ -1644,7 +1599,7 @@ impl Editor { doc.language_servers.iter().filter(|(name, doc_ls)| { language_servers .get(*name) - .is_none_or(|ls| ls.id() != doc_ls.id()) + .map_or(true, |ls| ls.id() != doc_ls.id()) }); for (_, language_server) in doc_language_servers_not_in_registry { @@ -1654,7 +1609,7 @@ impl Editor { let language_servers_not_in_doc = language_servers.iter().filter(|(name, ls)| { doc.language_servers .get(*name) - .is_none_or(|doc_ls| ls.id() != doc_ls.id()) + .map_or(true, |doc_ls| ls.id() != doc_ls.id()) }); for (_, language_server) in language_servers_not_in_doc { diff --git a/helix-view/src/graphics.rs b/helix-view/src/graphics.rs index 3a4eee3d..7625e8b5 100644 --- a/helix-view/src/graphics.rs +++ b/helix-view/src/graphics.rs @@ -315,34 +315,6 @@ impl From<Color> for termina::style::ColorSpec { } } -#[cfg(all(feature = "term", windows))] -impl From<Color> for crossterm::style::Color { - fn from(color: Color) -> Self { - use crossterm::style::Color as CColor; - - match color { - Color::Reset => CColor::Reset, - Color::Black => CColor::Black, - Color::Red => CColor::DarkRed, - Color::Green => CColor::DarkGreen, - Color::Yellow => CColor::DarkYellow, - Color::Blue => CColor::DarkBlue, - Color::Magenta => CColor::DarkMagenta, - Color::Cyan => CColor::DarkCyan, - Color::Gray => CColor::DarkGrey, - Color::LightRed => CColor::Red, - Color::LightGreen => CColor::Green, - Color::LightBlue => CColor::Blue, - Color::LightYellow => CColor::Yellow, - Color::LightMagenta => CColor::Magenta, - Color::LightCyan => CColor::Cyan, - Color::LightGray => CColor::Grey, - Color::White => CColor::White, - Color::Indexed(i) => CColor::AnsiValue(i), - Color::Rgb(r, g, b) => CColor::Rgb { r, g, b }, - } - } -} #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum UnderlineStyle { Reset, @@ -382,20 +354,6 @@ impl From<UnderlineStyle> for termina::style::Underline { } } -#[cfg(all(feature = "term", windows))] -impl From<UnderlineStyle> for crossterm::style::Attribute { - fn from(style: UnderlineStyle) -> Self { - match style { - UnderlineStyle::Line => crossterm::style::Attribute::Underlined, - UnderlineStyle::Curl => crossterm::style::Attribute::Undercurled, - UnderlineStyle::Dotted => crossterm::style::Attribute::Underdotted, - UnderlineStyle::Dashed => crossterm::style::Attribute::Underdashed, - UnderlineStyle::DoubleLine => crossterm::style::Attribute::DoubleUnderlined, - UnderlineStyle::Reset => crossterm::style::Attribute::NoUnderline, - } - } -} - bitflags! { /// Modifier changes the way a piece of text is displayed. /// diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index 7506e515..c2cbc0da 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -69,7 +69,7 @@ pub fn diagnostic<'doc>( .iter() .take_while(|d| { d.line == line - && d.provider.language_server_id().is_none_or(|id| { + && d.provider.language_server_id().map_or(true, |id| { doc.language_servers_with_feature(LanguageServerFeature::Diagnostics) .any(|ls| ls.id() == id) }) diff --git a/helix-view/src/handlers.rs b/helix-view/src/handlers.rs index 6f3ad1ed..6aba17d6 100644 --- a/helix-view/src/handlers.rs +++ b/helix-view/src/handlers.rs @@ -24,8 +24,6 @@ pub struct Handlers { pub auto_save: Sender<AutoSaveEvent>, pub document_colors: Sender<lsp::DocumentColorsEvent>, pub word_index: word_index::Handler, - pub pull_diagnostics: Sender<lsp::PullDiagnosticsEvent>, - pub pull_all_documents_diagnostics: Sender<lsp::PullAllDocumentsDiagnosticsEvent>, } impl Handlers { diff --git a/helix-view/src/handlers/lsp.rs b/helix-view/src/handlers/lsp.rs index 96ab4626..c1041b2a 100644 --- a/helix-view/src/handlers/lsp.rs +++ b/helix-view/src/handlers/lsp.rs @@ -1,5 +1,4 @@ use std::collections::btree_map::Entry; -use std::collections::HashSet; use std::fmt::Display; use crate::editor::Action; @@ -31,14 +30,6 @@ pub enum SignatureHelpEvent { RequestComplete { open: bool }, } -pub struct PullDiagnosticsEvent { - pub document_id: DocumentId, -} - -pub struct PullAllDocumentsDiagnosticsEvent { - pub language_servers: HashSet<LanguageServerId>, -} - #[derive(Debug)] pub struct ApplyEditError { pub kind: ApplyEditErrorKind, @@ -364,7 +355,7 @@ impl Editor { && diagnostic .source .as_ref() - .is_none_or(|source| !unchanged_diag_sources.contains(source)) + .map_or(true, |source| !unchanged_diag_sources.contains(source)) }; let diagnostics = Self::doc_diagnostics_with_filter( &self.language_servers, diff --git a/helix-view/src/input.rs b/helix-view/src/input.rs index 539680a6..6b3a9756 100644 --- a/helix-view/src/input.rs +++ b/helix-view/src/input.rs @@ -569,113 +569,6 @@ impl From<KeyEvent> for termina::event::KeyEvent { } } -#[cfg(all(feature = "term", windows))] -impl From<crossterm::event::Event> for Event { - fn from(event: crossterm::event::Event) -> Self { - match event { - crossterm::event::Event::Key(key) => Self::Key(key.into()), - crossterm::event::Event::Mouse(mouse) => Self::Mouse(mouse.into()), - crossterm::event::Event::Resize(w, h) => Self::Resize(w, h), - crossterm::event::Event::FocusGained => Self::FocusGained, - crossterm::event::Event::FocusLost => Self::FocusLost, - crossterm::event::Event::Paste(s) => Self::Paste(s), - } - } -} - -#[cfg(all(feature = "term", windows))] -impl From<crossterm::event::MouseEvent> for MouseEvent { - fn from( - crossterm::event::MouseEvent { - kind, - column, - row, - modifiers, - }: crossterm::event::MouseEvent, - ) -> Self { - Self { - kind: kind.into(), - column, - row, - modifiers: modifiers.into(), - } - } -} - -#[cfg(all(feature = "term", windows))] -impl From<crossterm::event::MouseEventKind> for MouseEventKind { - fn from(kind: crossterm::event::MouseEventKind) -> Self { - match kind { - crossterm::event::MouseEventKind::Down(button) => Self::Down(button.into()), - crossterm::event::MouseEventKind::Up(button) => Self::Up(button.into()), - crossterm::event::MouseEventKind::Drag(button) => Self::Drag(button.into()), - crossterm::event::MouseEventKind::Moved => Self::Moved, - crossterm::event::MouseEventKind::ScrollDown => Self::ScrollDown, - crossterm::event::MouseEventKind::ScrollUp => Self::ScrollUp, - crossterm::event::MouseEventKind::ScrollLeft => Self::ScrollLeft, - crossterm::event::MouseEventKind::ScrollRight => Self::ScrollRight, - } - } -} - -#[cfg(all(feature = "term", windows))] -impl From<crossterm::event::MouseButton> for MouseButton { - fn from(button: crossterm::event::MouseButton) -> Self { - match button { - crossterm::event::MouseButton::Left => MouseButton::Left, - crossterm::event::MouseButton::Right => MouseButton::Right, - crossterm::event::MouseButton::Middle => MouseButton::Middle, - } - } -} - -#[cfg(all(feature = "term", windows))] -impl From<crossterm::event::KeyEvent> for KeyEvent { - fn from( - crossterm::event::KeyEvent { - code, modifiers, .. - }: crossterm::event::KeyEvent, - ) -> Self { - if code == crossterm::event::KeyCode::BackTab { - // special case for BackTab -> Shift-Tab - let mut modifiers: KeyModifiers = modifiers.into(); - modifiers.insert(KeyModifiers::SHIFT); - Self { - code: KeyCode::Tab, - modifiers, - } - } else { - Self { - code: code.into(), - modifiers: modifiers.into(), - } - } - } -} - -#[cfg(all(feature = "term", windows))] -impl From<KeyEvent> for crossterm::event::KeyEvent { - fn from(KeyEvent { code, modifiers }: KeyEvent) -> Self { - if code == KeyCode::Tab && modifiers.contains(KeyModifiers::SHIFT) { - // special case for Shift-Tab -> BackTab - let mut modifiers = modifiers; - modifiers.remove(KeyModifiers::SHIFT); - crossterm::event::KeyEvent { - code: crossterm::event::KeyCode::BackTab, - modifiers: modifiers.into(), - kind: crossterm::event::KeyEventKind::Press, - state: crossterm::event::KeyEventState::NONE, - } - } else { - crossterm::event::KeyEvent { - code: code.into(), - modifiers: modifiers.into(), - kind: crossterm::event::KeyEventKind::Press, - state: crossterm::event::KeyEventState::NONE, - } - } - } -} pub fn parse_macro(keys_str: &str) -> anyhow::Result<Vec<KeyEvent>> { use anyhow::Context; let mut keys_res: anyhow::Result<_> = Ok(Vec::new()); diff --git a/helix-view/src/keyboard.rs b/helix-view/src/keyboard.rs index 53d85889..c3831143 100644 --- a/helix-view/src/keyboard.rs +++ b/helix-view/src/keyboard.rs @@ -60,53 +60,6 @@ impl From<termina::event::Modifiers> for KeyModifiers { } } -#[cfg(all(feature = "term", windows))] -impl From<KeyModifiers> for crossterm::event::KeyModifiers { - fn from(key_modifiers: KeyModifiers) -> Self { - use crossterm::event::KeyModifiers as CKeyModifiers; - - let mut result = CKeyModifiers::NONE; - - if key_modifiers.contains(KeyModifiers::SHIFT) { - result.insert(CKeyModifiers::SHIFT); - } - if key_modifiers.contains(KeyModifiers::CONTROL) { - result.insert(CKeyModifiers::CONTROL); - } - if key_modifiers.contains(KeyModifiers::ALT) { - result.insert(CKeyModifiers::ALT); - } - if key_modifiers.contains(KeyModifiers::SUPER) { - result.insert(CKeyModifiers::SUPER); - } - - result - } -} - -#[cfg(all(feature = "term", windows))] -impl From<crossterm::event::KeyModifiers> for KeyModifiers { - fn from(val: crossterm::event::KeyModifiers) -> Self { - use crossterm::event::KeyModifiers as CKeyModifiers; - - let mut result = KeyModifiers::NONE; - - if val.contains(CKeyModifiers::SHIFT) { - result.insert(KeyModifiers::SHIFT); - } - if val.contains(CKeyModifiers::CONTROL) { - result.insert(KeyModifiers::CONTROL); - } - if val.contains(CKeyModifiers::ALT) { - result.insert(KeyModifiers::ALT); - } - if val.contains(CKeyModifiers::SUPER) { - result.insert(KeyModifiers::SUPER); - } - - result - } -} /// Represents a media key (as part of [`KeyCode::Media`]). #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)] pub enum MediaKeyCode { @@ -184,51 +137,6 @@ impl From<termina::event::MediaKeyCode> for MediaKeyCode { } } -#[cfg(all(feature = "term", windows))] -impl From<MediaKeyCode> for crossterm::event::MediaKeyCode { - fn from(media_key_code: MediaKeyCode) -> Self { - use crossterm::event::MediaKeyCode as CMediaKeyCode; - - match media_key_code { - MediaKeyCode::Play => CMediaKeyCode::Play, - MediaKeyCode::Pause => CMediaKeyCode::Pause, - MediaKeyCode::PlayPause => CMediaKeyCode::PlayPause, - MediaKeyCode::Reverse => CMediaKeyCode::Reverse, - MediaKeyCode::Stop => CMediaKeyCode::Stop, - MediaKeyCode::FastForward => CMediaKeyCode::FastForward, - MediaKeyCode::Rewind => CMediaKeyCode::Rewind, - MediaKeyCode::TrackNext => CMediaKeyCode::TrackNext, - MediaKeyCode::TrackPrevious => CMediaKeyCode::TrackPrevious, - MediaKeyCode::Record => CMediaKeyCode::Record, - MediaKeyCode::LowerVolume => CMediaKeyCode::LowerVolume, - MediaKeyCode::RaiseVolume => CMediaKeyCode::RaiseVolume, - MediaKeyCode::MuteVolume => CMediaKeyCode::MuteVolume, - } - } -} - -#[cfg(all(feature = "term", windows))] -impl From<crossterm::event::MediaKeyCode> for MediaKeyCode { - fn from(val: crossterm::event::MediaKeyCode) -> Self { - use crossterm::event::MediaKeyCode as CMediaKeyCode; - - match val { - CMediaKeyCode::Play => MediaKeyCode::Play, - CMediaKeyCode::Pause => MediaKeyCode::Pause, - CMediaKeyCode::PlayPause => MediaKeyCode::PlayPause, - CMediaKeyCode::Reverse => MediaKeyCode::Reverse, - CMediaKeyCode::Stop => MediaKeyCode::Stop, - CMediaKeyCode::FastForward => MediaKeyCode::FastForward, - CMediaKeyCode::Rewind => MediaKeyCode::Rewind, - CMediaKeyCode::TrackNext => MediaKeyCode::TrackNext, - CMediaKeyCode::TrackPrevious => MediaKeyCode::TrackPrevious, - CMediaKeyCode::Record => MediaKeyCode::Record, - CMediaKeyCode::LowerVolume => MediaKeyCode::LowerVolume, - CMediaKeyCode::RaiseVolume => MediaKeyCode::RaiseVolume, - CMediaKeyCode::MuteVolume => MediaKeyCode::MuteVolume, - } - } -} /// Represents a media key (as part of [`KeyCode::Modifier`]). #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)] pub enum ModifierKeyCode { @@ -310,53 +218,6 @@ impl From<termina::event::ModifierKeyCode> for ModifierKeyCode { } } -#[cfg(all(feature = "term", windows))] -impl From<ModifierKeyCode> for crossterm::event::ModifierKeyCode { - fn from(modifier_key_code: ModifierKeyCode) -> Self { - use crossterm::event::ModifierKeyCode as CModifierKeyCode; - - match modifier_key_code { - ModifierKeyCode::LeftShift => CModifierKeyCode::LeftShift, - ModifierKeyCode::LeftControl => CModifierKeyCode::LeftControl, - ModifierKeyCode::LeftAlt => CModifierKeyCode::LeftAlt, - ModifierKeyCode::LeftSuper => CModifierKeyCode::LeftSuper, - ModifierKeyCode::LeftHyper => CModifierKeyCode::LeftHyper, - ModifierKeyCode::LeftMeta => CModifierKeyCode::LeftMeta, - ModifierKeyCode::RightShift => CModifierKeyCode::RightShift, - ModifierKeyCode::RightControl => CModifierKeyCode::RightControl, - ModifierKeyCode::RightAlt => CModifierKeyCode::RightAlt, - ModifierKeyCode::RightSuper => CModifierKeyCode::RightSuper, - ModifierKeyCode::RightHyper => CModifierKeyCode::RightHyper, - ModifierKeyCode::RightMeta => CModifierKeyCode::RightMeta, - ModifierKeyCode::IsoLevel3Shift => CModifierKeyCode::IsoLevel3Shift, - ModifierKeyCode::IsoLevel5Shift => CModifierKeyCode::IsoLevel5Shift, - } - } -} - -#[cfg(all(feature = "term", windows))] -impl From<crossterm::event::ModifierKeyCode> for ModifierKeyCode { - fn from(val: crossterm::event::ModifierKeyCode) -> Self { - use crossterm::event::ModifierKeyCode as CModifierKeyCode; - - match val { - CModifierKeyCode::LeftShift => ModifierKeyCode::LeftShift, - CModifierKeyCode::LeftControl => ModifierKeyCode::LeftControl, - CModifierKeyCode::LeftAlt => ModifierKeyCode::LeftAlt, - CModifierKeyCode::LeftSuper => ModifierKeyCode::LeftSuper, - CModifierKeyCode::LeftHyper => ModifierKeyCode::LeftHyper, - CModifierKeyCode::LeftMeta => ModifierKeyCode::LeftMeta, - CModifierKeyCode::RightShift => ModifierKeyCode::RightShift, - CModifierKeyCode::RightControl => ModifierKeyCode::RightControl, - CModifierKeyCode::RightAlt => ModifierKeyCode::RightAlt, - CModifierKeyCode::RightSuper => ModifierKeyCode::RightSuper, - CModifierKeyCode::RightHyper => ModifierKeyCode::RightHyper, - CModifierKeyCode::RightMeta => ModifierKeyCode::RightMeta, - CModifierKeyCode::IsoLevel3Shift => ModifierKeyCode::IsoLevel3Shift, - CModifierKeyCode::IsoLevel5Shift => ModifierKeyCode::IsoLevel5Shift, - } - } -} /// Represents a key. #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)] pub enum KeyCode { @@ -490,76 +351,3 @@ impl From<termina::event::KeyCode> for KeyCode { } } } - -#[cfg(all(feature = "term", windows))] -impl From<KeyCode> for crossterm::event::KeyCode { - fn from(key_code: KeyCode) -> Self { - use crossterm::event::KeyCode as CKeyCode; - - match key_code { - KeyCode::Backspace => CKeyCode::Backspace, - KeyCode::Enter => CKeyCode::Enter, - KeyCode::Left => CKeyCode::Left, - KeyCode::Right => CKeyCode::Right, - KeyCode::Up => CKeyCode::Up, - KeyCode::Down => CKeyCode::Down, - KeyCode::Home => CKeyCode::Home, - KeyCode::End => CKeyCode::End, - KeyCode::PageUp => CKeyCode::PageUp, - KeyCode::PageDown => CKeyCode::PageDown, - KeyCode::Tab => CKeyCode::Tab, - KeyCode::Delete => CKeyCode::Delete, - KeyCode::Insert => CKeyCode::Insert, - KeyCode::F(f_number) => CKeyCode::F(f_number), - KeyCode::Char(character) => CKeyCode::Char(character), - KeyCode::Null => CKeyCode::Null, - KeyCode::Esc => CKeyCode::Esc, - KeyCode::CapsLock => CKeyCode::CapsLock, - KeyCode::ScrollLock => CKeyCode::ScrollLock, - KeyCode::NumLock => CKeyCode::NumLock, - KeyCode::PrintScreen => CKeyCode::PrintScreen, - KeyCode::Pause => CKeyCode::Pause, - KeyCode::Menu => CKeyCode::Menu, - KeyCode::KeypadBegin => CKeyCode::KeypadBegin, - KeyCode::Media(media_key_code) => CKeyCode::Media(media_key_code.into()), - KeyCode::Modifier(modifier_key_code) => CKeyCode::Modifier(modifier_key_code.into()), - } - } -} - -#[cfg(all(feature = "term", windows))] -impl From<crossterm::event::KeyCode> for KeyCode { - fn from(val: crossterm::event::KeyCode) -> Self { - use crossterm::event::KeyCode as CKeyCode; - - match val { - CKeyCode::Backspace => KeyCode::Backspace, - CKeyCode::Enter => KeyCode::Enter, - CKeyCode::Left => KeyCode::Left, - CKeyCode::Right => KeyCode::Right, - CKeyCode::Up => KeyCode::Up, - CKeyCode::Down => KeyCode::Down, - CKeyCode::Home => KeyCode::Home, - CKeyCode::End => KeyCode::End, - CKeyCode::PageUp => KeyCode::PageUp, - CKeyCode::PageDown => KeyCode::PageDown, - CKeyCode::Tab => KeyCode::Tab, - CKeyCode::BackTab => unreachable!("BackTab should have been handled on KeyEvent level"), - CKeyCode::Delete => KeyCode::Delete, - CKeyCode::Insert => KeyCode::Insert, - CKeyCode::F(f_number) => KeyCode::F(f_number), - CKeyCode::Char(character) => KeyCode::Char(character), - CKeyCode::Null => KeyCode::Null, - CKeyCode::Esc => KeyCode::Esc, - CKeyCode::CapsLock => KeyCode::CapsLock, - CKeyCode::ScrollLock => KeyCode::ScrollLock, - CKeyCode::NumLock => KeyCode::NumLock, - CKeyCode::PrintScreen => KeyCode::PrintScreen, - CKeyCode::Pause => KeyCode::Pause, - CKeyCode::Menu => KeyCode::Menu, - CKeyCode::KeypadBegin => KeyCode::KeypadBegin, - CKeyCode::Media(media_key_code) => KeyCode::Media(media_key_code.into()), - CKeyCode::Modifier(modifier_key_code) => KeyCode::Modifier(modifier_key_code.into()), - } - } -} diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index 173a40f3..e2e10932 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -35,75 +35,6 @@ pub static BASE16_DEFAULT_THEME: Lazy<Theme> = Lazy::new(|| Theme { ..Theme::from(BASE16_DEFAULT_THEME_DATA.clone()) }); -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum Mode { - Dark, - Light, -} - -#[cfg(feature = "term")] -impl From<termina::escape::csi::ThemeMode> for Mode { - fn from(mode: termina::escape::csi::ThemeMode) -> Self { - match mode { - termina::escape::csi::ThemeMode::Dark => Self::Dark, - termina::escape::csi::ThemeMode::Light => Self::Light, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Config { - light: String, - dark: String, - /// A theme to choose when the terminal did not declare either light or dark mode. - /// When not specified the dark theme is preferred. - fallback: Option<String>, -} - -impl Config { - pub fn choose(&self, preference: Option<Mode>) -> &str { - match preference { - Some(Mode::Light) => &self.light, - Some(Mode::Dark) => &self.dark, - None => self.fallback.as_ref().unwrap_or(&self.dark), - } - } -} - -impl<'de> Deserialize<'de> for Config { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: serde::Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(untagged, deny_unknown_fields, rename_all = "kebab-case")] - enum InnerConfig { - Constant(String), - Adaptive { - dark: String, - light: String, - fallback: Option<String>, - }, - } - - let inner = InnerConfig::deserialize(deserializer)?; - - let (light, dark, fallback) = match inner { - InnerConfig::Constant(theme) => (theme.clone(), theme.clone(), None), - InnerConfig::Adaptive { - light, - dark, - fallback, - } => (light, dark, fallback), - }; - - Ok(Self { - light, - dark, - fallback, - }) - } -} #[derive(Clone, Debug)] pub struct Loader { /// Theme directories to search from highest to lowest priority diff --git a/helix-view/src/tree.rs b/helix-view/src/tree.rs index d596b35a..aba947a2 100644 --- a/helix-view/src/tree.rs +++ b/helix-view/src/tree.rs @@ -441,7 +441,7 @@ impl Tree { } } - pub fn traverse(&self) -> Traverse<'_> { + pub fn traverse(&self) -> Traverse { Traverse::new(self) } diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index aecf09a6..d275befb 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -137,8 +137,6 @@ pub struct View { // uses two docs because we want to be able to swap between the // two last modified docs which we need to manually keep track of pub last_modified_docs: [Option<DocumentId>; 2], - /// used to store previous selections of tree-sitter objects - pub object_selections: Vec<Selection>, /// all gutter-related configuration settings, used primarily for gutter rendering pub gutters: GutterConfig, /// A mapping between documents and the last history revision the view was updated at. @@ -175,7 +173,6 @@ impl View { jumps: JumpList::new((doc, Selection::point(0))), // TODO: use actual sel docs_access_history: Vec::new(), last_modified_docs: [None, None], - object_selections: Vec::new(), gutters, doc_revisions: HashMap::new(), diagnostics_handler: DiagnosticsHandler::new(), diff --git a/languages.toml b/languages.toml index 2d1074aa..a6197f57 100644 --- a/languages.toml +++ b/languages.toml @@ -38,7 +38,6 @@ docker-compose-langserver = { command = "docker-compose-langserver", args = ["-- dot-language-server = { command = "dot-language-server", args = ["--stdio"] } dts-lsp = { command = "dts-lsp" } earthlyls = { command = "earthlyls" } -eiffel-language-server = {command = "eiffel-language-server"} elixir-ls = { command = "elixir-ls", config = { elixirLS.dialyzerEnabled = false } } elm-language-server = { command = "elm-language-server" } elp = { command = "elp", args = ["server"] } @@ -284,10 +283,6 @@ args = ["lsp"] command = "docker-language-server" args = ["start", "--stdio"] -[language-server.kcl-lsp] -command = "kcl-language-server" -args = ["server", "--stdio"] - [[language]] name = "rust" scope = "source.rust" @@ -344,7 +339,7 @@ args = { attachCommands = [ "platform select remote-gdb-server", "platform conne [[grammar]] name = "rust" -source = { git = "https://github.com/tree-sitter/tree-sitter-rust", rev = "261b20226c04ef601adbdf185a800512a5f66291" } +source = { git = "https://github.com/tree-sitter/tree-sitter-rust", rev = "1f63b33efee17e833e0ea29266dd3d713e27e321" } [[language]] name = "sway" @@ -428,17 +423,6 @@ name = "textproto" source = { git = "https://github.com/PorterAtGoogle/tree-sitter-textproto", rev = "568471b80fd8793d37ed01865d8c2208a9fefd1b"} [[language]] -name = "eiffel" -scope = "source.eiffel" -file-types = ["e"] -comment-token = "--" -language-servers = ["eiffel-language-server"] - -[[grammar]] -name = "eiffel" -source = { git = "https://github.com/imustafin/tree-sitter-eiffel", rev = "d934fb44f1d22bb76be6b56a7b2425ab3b1daf8b" } - -[[language]] name = "elixir" scope = "source.elixir" injection-regex = "(elixir|ex)" @@ -665,7 +649,7 @@ args = { console = "internalConsole", attachCommands = [ "platform select remote [[grammar]] name = "c" -source = { git = "https://github.com/tree-sitter/tree-sitter-c", rev = "7fa1be1b694b6e763686793d97da01f36a0e5c12" } +source = { git = "https://github.com/tree-sitter/tree-sitter-c", rev = "7175a6dd5fc1cee660dce6fe23f6043d75af424a" } [[language]] name = "cpp" @@ -910,7 +894,7 @@ args = { program = "{0}", skipFiles = [ "<node_internals>/**" ] } [[grammar]] name = "javascript" -source = { git = "https://github.com/tree-sitter/tree-sitter-javascript", rev = "3a837b6f3658ca3618f2022f8707e29739c91364" } +source = { git = "https://github.com/tree-sitter/tree-sitter-javascript", rev = "f772967f7b7bc7c28f845be2420a38472b16a8ee" } [[language]] name = "jsx" @@ -940,7 +924,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "typescript" -source = { git = "https://github.com/tree-sitter/tree-sitter-typescript", rev = "75b3874edb2dc714fb1fd77a32013d0f8699989f", subpath = "typescript" } +source = { git = "https://github.com/tree-sitter/tree-sitter-typescript", rev = "b1bf4825d9eaa0f3bdeb1e52f099533328acfbdf", subpath = "typescript" } [[language]] name = "typespec" @@ -973,7 +957,7 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "tsx" -source = { git = "https://github.com/tree-sitter/tree-sitter-typescript", rev = "75b3874edb2dc714fb1fd77a32013d0f8699989f", subpath = "tsx" } +source = { git = "https://github.com/tree-sitter/tree-sitter-typescript", rev = "b1bf4825d9eaa0f3bdeb1e52f099533328acfbdf", subpath = "tsx" } [[language]] name = "css" @@ -1169,7 +1153,6 @@ file-types = [ { glob = "sway/config" }, { glob = ".tmux.conf" }, { glob = "tmux.conf" }, - { glob = ".sh_history" }, { glob = ".bash_history" }, { glob = ".bash_login" }, { glob = ".bash_logout" }, @@ -1184,9 +1167,6 @@ file-types = [ { glob = ".zimrc" }, { glob = "APKBUILD" }, { glob = ".bash_aliases" }, - { glob = "bash_completion" }, - { glob = "bash-completion/completions/*" }, - { glob = "bash_completion.d/*" }, { glob = ".Renviron" }, { glob = ".xprofile" }, { glob = ".xsession" }, @@ -1304,7 +1284,7 @@ name = "lean" scope = "source.lean" injection-regex = "lean" file-types = ["lean"] -roots = [ "lakefile.lean", "lakefile.toml" ] +roots = [ "lakefile.lean" ] comment-token = "--" block-comment-tokens = { start = "/-", end = "-/" } language-servers = [ "lean" ] @@ -1541,7 +1521,6 @@ file-types = [ { glob = ".gem/credentials" }, { glob = ".kube/config" }, { glob = ".kube/kuberc" }, - { glob = "yarn.lock" }, "sublime-syntax" ] comment-token = "#" @@ -1569,7 +1548,7 @@ name = "haskell" scope = "source.haskell" injection-regex = "hs|haskell" file-types = ["hs", "hs-boot", "hsc"] -roots = ["Setup.hs", "stack.yaml", "cabal.project", "hie.yaml"] +roots = ["Setup.hs", "stack.yaml", "cabal.project"] shebangs = ["runhaskell", "stack"] comment-token = "--" block-comment-tokens = { start = "{-", end = "-}" } @@ -1761,8 +1740,8 @@ source = { git = "https://github.com/tree-sitter-perl/tree-sitter-pod", rev = "0 [[language]] name = "racket" scope = "source.racket" -file-types = ["rkt", "rktd", "rktl", "scrbl", "zuo"] -shebangs = ["racket", "zuo"] +file-types = ["rkt", "rktd", "rktl", "scrbl"] +shebangs = ["racket"] comment-token = ";" indent = { tab-width = 2, unit = " " } block-comment-tokens = { start = "#|", end = "|#" } @@ -1875,7 +1854,7 @@ injection-regex = "mail|eml|email" [[grammar]] name = "mail" -source = { git = "https://codeberg.org/ficd/tree-sitter-mail", rev = "8e60f38efbae1cc5f22833ae13c5500dd0f3b12f" } +source = { git = "https://github.com/ficcdaf/tree-sitter-mail", rev = "8e60f38efbae1cc5f22833ae13c5500dd0f3b12f" } [[language]] name = "markdown" @@ -2062,7 +2041,7 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-regex", rev = "e1cf [[language]] name = "git-config" scope = "source.gitconfig" -file-types = ["gitconfig", { glob = ".gitmodules" }, { glob = "gitconfig" }, { glob = ".gitconfig" }, { glob = ".git/config" }, { glob = ".config/git/config" }] +file-types = ["gitconfig", { glob = ".gitmodules" }, { glob = ".gitconfig" }, { glob = ".git/config" }, { glob = ".config/git/config" }] injection-regex = "git-config" comment-token = "#" indent = { tab-width = 4, unit = "\t" } @@ -2433,7 +2412,7 @@ language-servers = [ "nu-lsp" ] [[grammar]] name = "nu" -source = { git = "https://github.com/nushell/tree-sitter-nu", rev = "cc4624fbc6ec3563d98fbe8f215a8b8e10b16f32" } +source = { git = "https://github.com/nushell/tree-sitter-nu", rev = "358c4f509eb97f0148bbd25ad36acc729819b9c1" } [[language]] name = "vala" @@ -3000,89 +2979,73 @@ name = "xml" scope = "source.xml" injection-regex = "xml" file-types = [ - "ascx", + "xml", + "mobileconfig", + "plist", + "xib", + "storyboard", + "svg", + "xsd", + "gml", + "xaml", + "gir", + "rss", "atom", - "axaml", + "opml", + "policy", + "ascx", "axml", + "axaml", "bpmn", - "checkstyle", "cpt", "csl", "csproj.user", "dita", "ditamap", "dtml", - "fods", - "fodt", "fxml", - "gir", - "glif", - "gml", - "gpx", "iml", "isml", "jmx", - "kml", "launch", "menu", - "mobileconfig", - "mpd", - "musicxml", "mxml", - "ncx", "nuspec", - "opml", "osc", "osm", - "plist", - "policy", "pt", "publishsettings", "pubxml", "pubxml.user", "rbxlx", "rbxmx", - "resx", "rng", - "rss", "shproj", - "smil", - "storyboard", - "sublime-snippet", - "svg", "tld", + { glob = "*.tm[Tt]heme" }, "tmx", - "ui", "vbproj.user", "vcxproj", "vcxproj.filters", - "wixproj", "wsdl", "wxi", "wxs", - "xaml", "xbl", - "xib", "xlf", "xliff", - "xml", - "xmp", - "xoml", "xpdl", - "xrc", - "xsd", + "xul", + "xoml", + "musicxml", + "glif", + "ui", + "sublime-snippet", "xsl", "mpd", "smil", "gpx", "fodt", "fods", - "itermcolors", - "terminal", - "xul", - { glob = "*.tm[Ll]anguage" }, - { glob = "*.tm[Pp]references" }, - { glob = "*.tm[Tt]heme" }, ] block-comment-tokens = { start = "<!--", end = "-->" } indent = { tab-width = 2, unit = " " } @@ -3748,25 +3711,6 @@ name = "jjtemplate" source = { git = "https://github.com/bryceberger/tree-sitter-jjtemplate", rev = "4313eda8ac31c60e550e3ad5841b100a0a686715" } [[language]] -name = "miseconfig" -scope = "source.miseconfig" -injection-regex = "miseconfig" -grammar = "toml" -file-types = [ - { glob = "mise.toml" }, - { glob = ".mise.toml" }, - { glob = "mise.*.toml" }, - { glob = ".mise.*.toml" }, - { glob = "mise/config.toml" }, - { glob = ".mise/config.toml" }, - { glob = ".config/mise.toml" }, - { glob = ".config/mise/conf.d/*.toml" }, -] -comment-token = "#" -language-servers = [ "taplo", "tombi" ] -indent = { tab-width = 2, unit = " " } - -[[language]] name = "jq" scope = "source.jq" injection-regex = "jq" @@ -4232,7 +4176,7 @@ language-servers = ["pest-language-server"] [[grammar]] name = "pest" -source = { git = "https://github.com/pest-parser/tree-sitter-pest", rev = "c19629a0c50e6ca2485c3b154b1dde841a08d169" } +source = { git = "https://github.com/pest-parser/tree-sitter-pest", rev = "a8a98a824452b1ec4da7f508386a187a2f234b85" } [[language]] name = "elisp" @@ -4263,7 +4207,7 @@ language-servers = [ "ember-language-server", ] indent = { tab-width = 2, unit = " " } -grammar = "glimmer-javascript" +grammar = "javascript" [language.auto-pairs] '<' = '>' @@ -4272,10 +4216,6 @@ grammar = "glimmer-javascript" "(" = ")" '"' = '"' -[[grammar]] -name = "glimmer-javascript" -source = { git = "https://github.com/ember-tooling/tree-sitter-glimmer-javascript", rev = "5cc865a2a0a77cbfaf5062c8fcf2a9919bd54f87" } - [[language]] name = "gts" scope = "source.gts" @@ -4291,7 +4231,7 @@ language-servers = [ "ember-language-server", ] indent = { tab-width = 2, unit = " " } -grammar = "glimmer-typescript" +grammar = "typescript" [language.auto-pairs] '<' = '>' @@ -4300,10 +4240,6 @@ grammar = "glimmer-typescript" "(" = ")" '"' = '"' -[[grammar]] -name = "glimmer-typescript" -source = { git = "https://github.com/ember-tooling/tree-sitter-glimmer-typescript", rev = "12d98944c1d5077b957cbdb90d663a7c4d50118c" } - [[language]] name = "gherkin" scope = "source.feature" @@ -4434,7 +4370,7 @@ formatter = {command = "koto", args = ["--format"]} [[grammar]] name = "koto" -source = { git = "https://github.com/koto-lang/tree-sitter-koto", rev = "633744bca404ae4edb961a3c2d7bc947a987afa4" } +source = { git = "https://github.com/koto-lang/tree-sitter-koto", rev = "2ffc77c14f0ac1674384ff629bfc207b9c57ed89" } [[language]] name = "gpr" @@ -4896,7 +4832,7 @@ indent = { tab-width = 2, unit = " " } block-comment-tokens = { start = "<!--", end = "-->" } word-completion.trigger-length = 4 -[[language]] +[[language]] name = "slisp" scope = "source.sl" injection-regex = "sl" @@ -4907,48 +4843,3 @@ indent = { tab-width = 2, unit = " " } [[grammar]] name = "slisp" source = { git = "https://github.com/xenogenics/tree-sitter-slisp", rev = "29f9c6707ce9dfc2fc915d175ec720b207f179f3" } - -[[language]] -name = "nearley" -scope = "source.nearley" -file-types = ["ne"] -comment-token = "#" -indent = { tab-width = 2, unit = " " } - -[[grammar]] -name = "nearley" -source = { git = "https://github.com/mi2ebi/tree-sitter-nearley", rev = "12d01113e194c8e83f6341aab8c2a5f21db9cac9" } - -[[language]] -name = "kcl" -scope = "source.kcl" -injection-regex = "kcl" -file-types = ["kcl"] -comment-tokens = "//" -indent = { tab-width = 2, unit = " " } -formatter = { command = "zoo" , args = ["kcl", "fmt", "-"] } -language-servers = [ "kcl-lsp" ] -block-comment-tokens = { start = "/*", end = "*/"} - -[[grammar]] -name = "kcl" -source = { git = "https://github.com/KittyCAD/tree-sitter-kcl", rev = "8905e0bdbf5870b50bc3f24345f1af27746f42e8"} - -[[language]] -name = "bovex" -scope = "source.bovex" -file-types = ["bovex", "bibvex"] -comment-tokens = [] -block-comment-tokens = [{start = "(*", end = "*)"}, {start = "[*", end = "*]"}] -indent = {tab-width = 2, unit = " "} -[language.auto-pairs] -'(' = ')' -'[' = ']' -'{' = '}' -'"' = '"' -'“' = '”' -'‘' = '’' - -[[grammar]] -name = "bovex" -source = { git = "https://github.com/mi2ebi/tree-sitter-bovex", rev = "de7657a9cc3525b9b77c6d268da09dad5b1346b0" } diff --git a/runtime/queries/_javascript/tags.scm b/runtime/queries/_javascript/tags.scm index 9c350cd2..a7bbd311 100644 --- a/runtime/queries/_javascript/tags.scm +++ b/runtime/queries/_javascript/tags.scm @@ -25,7 +25,7 @@ (comment)* @doc . [ - (function_expression + (function name: (identifier) @name) (function_declaration name: (identifier) @name) @@ -44,7 +44,7 @@ (lexical_declaration (variable_declarator name: (identifier) @name - value: [(arrow_function) (function_expression)]) @definition.function) + value: [(arrow_function) (function)]) @definition.function) (#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$") (#select-adjacent! @doc @definition.function) ) @@ -55,7 +55,7 @@ (variable_declaration (variable_declarator name: (identifier) @name - value: [(arrow_function) (function_expression)]) @definition.function) + value: [(arrow_function) (function)]) @definition.function) (#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$") (#select-adjacent! @doc @definition.function) ) @@ -66,12 +66,12 @@ (member_expression property: (property_identifier) @name) ] - right: [(arrow_function) (function_expression)] + right: [(arrow_function) (function)] ) @definition.function (pair key: (property_identifier) @name - value: [(arrow_function) (function_expression)]) @definition.function + value: [(arrow_function) (function)]) @definition.function ( (call_expression diff --git a/runtime/queries/bovex/highlights.scm b/runtime/queries/bovex/highlights.scm deleted file mode 100644 index cc4ffe0a..00000000 --- a/runtime/queries/bovex/highlights.scm +++ /dev/null @@ -1,88 +0,0 @@ -[(code_comment) (layout_comment)] @comment.block - -(do_decl "do" @keyword.control) -(val_decl "val" @keyword.storage.type) -(fun_decl ["fun" "and"] @keyword.storage.type) -(datatype_decl ["datatype" "and"] @keyword.storage.type) -(datatype_arm "of" @keyword.storage.type) -(object_decl ["object" "of"] @keyword.storage.type) -(type_decl "type" @keyword.storage.type) -(local_decl ["local" "in" "end"] @keyword.storage.modifier) -(open_decl "open" @keyword.control) -(import_decl "import" @keyword.control.import) -(with_expr ["with" "without"] @keyword.operator) -(orelse_expr ["orelse" "otherwise"] @keyword.operator) -(andalso_expr ["andalso" "andthen"] @keyword.operator) -(fn_expr ["fn" "as"] @keyword.function) -(if_expr ["if" "then" "else"] @keyword.control.conditional) -(case_expr ["case" "of"] @keyword.control) -(fail_expr "fail" @keyword.control) -(let_expr ["let" "in" "end"] @keyword.storage.modifier) -(pat "as" @keyword.operator) - -(boolean_lit) @constant.builtin.boolean -(numeric_lit) @constant.numeric.integer -(float_lit) @constant.numeric.float -(string_lit) @string.quoted.double -(backslash_escape) @constant.character.escape - -["=" ":" ","] @punctuation.delimiter -["->" "=>"] @operator -["(" ")" "[" "]" "{" "}"] @punctuation.bracket - -[(ident) (label)] @variable.other -(type_ident) @type -(atomic_pat (ident) @variable.other) -(pat (app_pat (atomic_pat (ident) @variable.parameter))) - -(type_var) @type.parameter -(atomic_type (type_ident) @type.builtin) -[(record_type) (product_type) (app_type) (arrow_type)] @type - -(atomic_expr (ident) @variable.other) -(project_expr) @variable.member -(field_binding (label) @variable.member.private) -(field_binding (expr) @variable.other) -(record_pat (ident) @variable.member.private) - -(app_expr - (app_expr (atomic_expr (ident) @function.call)) - (atomic_expr)) -(app_expr - _ - [":=" "@" "::" "o" "==" "!=" "==." "!=." - "<" "<=" ">" ">=" "<." "<=." ">." ">=." - "+" "-" "+." "-." "*" "*." "/" "/." "div" "mod" - "shl" "shr" "andb" "xorb" "orb"] @operator - _) - -(app_expr - (app_expr (atomic_expr (ident) @function.builtin (#eq? @function.builtin "b"))) - (atomic_expr (layout_lit (layout_content (layout_text) @markup.bold)))) -(app_expr - (app_expr (atomic_expr (ident) @function.builtin (#eq? @function.builtin "it"))) - (atomic_expr (layout_lit (layout_content (layout_text) @markup.italic)))) -(app_expr - (app_expr (atomic_expr (ident) @function.builtin (#eq? @function.builtin "rm"))) - (atomic_expr (layout_lit))) -(app_expr - (app_expr (atomic_expr (ident) @function.builtin (#match? @function.builtin "^(tt|courier|fixedersys)$"))) - (atomic_expr (layout_lit (layout_content (layout_text) @markup.raw.inline)))) -(app_expr - (app_expr (atomic_expr (ident) @function.builtin (#eq? @function.builtin "title"))) - (atomic_expr (layout_lit (layout_content (layout_text) @markup.heading.1)))) -(app_expr - (app_expr (atomic_expr (ident) @function.builtin (#eq? @function.builtin "section"))) - (atomic_expr (layout_lit (layout_content (layout_text) @markup.heading.2)))) -(app_expr - (app_expr (atomic_expr (ident) @function.builtin (#eq? @function.builtin "subsection"))) - (atomic_expr (layout_lit (layout_content (layout_text) @markup.heading.3)))) -(app_expr - (app_expr (atomic_expr (ident) @function.builtin (#eq? @function.builtin "subsubsection"))) - (atomic_expr (layout_lit (layout_content (layout_text) @markup.heading.4)))) -(app_expr - (app_expr (atomic_expr (ident) @function.builtin (#eq? @function.builtin "paragraph"))) - (atomic_expr (layout_lit (layout_content (layout_text) @markup.heading.5)))) -(app_expr - (app_expr (atomic_expr (ident) @function.builtin (#eq? @function.builtin "blockquote"))) - (atomic_expr (layout_lit (layout_content (layout_text) @markup.quote)))) diff --git a/runtime/queries/bovex/rainbows.scm b/runtime/queries/bovex/rainbows.scm deleted file mode 100644 index f00c454f..00000000 --- a/runtime/queries/bovex/rainbows.scm +++ /dev/null @@ -1,11 +0,0 @@ -["(" ")" "[" "]" "{" "}"] @rainbow.bracket -[ - (tuple_expr) - (record_expr) - (layout_lit) - (layout_antiquote) - (tuple_pat) - (record_pat) - (atomic_type) - (record_type) -] @rainbow.scope diff --git a/runtime/queries/ecma/highlights.scm b/runtime/queries/ecma/highlights.scm index 4ba74a4b..67052596 100644 --- a/runtime/queries/ecma/highlights.scm +++ b/runtime/queries/ecma/highlights.scm @@ -161,7 +161,7 @@ ; Function and method definitions ;-------------------------------- -(function_expression +(function name: (identifier) @function) (function_declaration name: (identifier) @function) @@ -172,27 +172,27 @@ (pair key: (property_identifier) @function.method - value: [(function_expression) (arrow_function)]) + value: [(function) (arrow_function)]) (pair key: (private_property_identifier) @function.method.private - value: [(function_expression) (arrow_function)]) + value: [(function) (arrow_function)]) (assignment_expression left: (member_expression property: (property_identifier) @function.method) - right: [(function_expression) (arrow_function)]) + right: [(function) (arrow_function)]) (assignment_expression left: (member_expression property: (private_property_identifier) @function.method.private) - right: [(function_expression) (arrow_function)]) + right: [(function) (arrow_function)]) (variable_declarator name: (identifier) @function - value: [(function_expression) (arrow_function)]) + value: [(function) (arrow_function)]) (assignment_expression left: (identifier) @function - right: [(function_expression) (arrow_function)]) + right: [(function) (arrow_function)]) ; Function and method parameters ;------------------------------- diff --git a/runtime/queries/ecma/injections.scm b/runtime/queries/ecma/injections.scm index 71163c5c..8430994d 100644 --- a/runtime/queries/ecma/injections.scm +++ b/runtime/queries/ecma/injections.scm @@ -26,7 +26,7 @@ ((call_expression function: (identifier) @_template_function_name - arguments: (template_string (string_fragment) @injection.content)) + arguments: (template_string) @injection.content) (#eq? @_template_function_name "gql") (#set! injection.language "graphql")) diff --git a/runtime/queries/ecma/locals.scm b/runtime/queries/ecma/locals.scm index 594a5f50..345cf177 100644 --- a/runtime/queries/ecma/locals.scm +++ b/runtime/queries/ecma/locals.scm @@ -3,14 +3,10 @@ [ (statement_block) + (function) (arrow_function) - (function_expression) (function_declaration) (method_definition) - (for_statement) - (for_in_statement) - (catch_clause) - (finally_clause) ] @local.scope ; Definitions diff --git a/runtime/queries/ecma/textobjects.scm b/runtime/queries/ecma/textobjects.scm index 08c0307b..a19eb25b 100644 --- a/runtime/queries/ecma/textobjects.scm +++ b/runtime/queries/ecma/textobjects.scm @@ -1,7 +1,7 @@ (function_declaration body: (_) @function.inside) @function.around -(function_expression +(function body: (_) @function.inside) @function.around (arrow_function diff --git a/runtime/queries/eiffel/highlights.scm b/runtime/queries/eiffel/highlights.scm deleted file mode 100644 index 90b0cfdb..00000000 --- a/runtime/queries/eiffel/highlights.scm +++ /dev/null @@ -1,108 +0,0 @@ -[ - "alias" - "convert" - "inherit" - "redefine" - "undefine" - "rename" - "select" - "note" - "create" -] @keyword.control.import - -["export"] @keyword.control.export - -[ - "do" - "end" - "once" - "attribute" -] @keyword.control - -[ - "class" - "local" -] @keyword.storage.type - -[ - "feature" - "agent" -] @keyword.function - -[ - "frozen" - "deferred" - "detachable" - "expanded" - "attached" - "old" - "like" -] @keyword.storage.modifier - -(conditional ["if" "elseif" "end"] @keyword.control.conditional) -(else_part ["else"] @keyword.control.conditional) -(then_part ["then"] @keyword.control.conditional) - -(conditional_expression ["if" "else" "elseif" "end"] @keyword.control.conditional) -(else_part_expression ["else"] @keyword.control.conditional) -(then_part_expression ["then"] @keyword.control.conditional) - -(multi_branch "inspect" @keyword.control.conditional) -(when_part ["when" "then"] @keyword.control.conditional) - -(multi_branch_expression "inspect" @keyword.control.conditional) -(when_part_expression ["when" "then"] @keyword.control.conditional) - -(quantifier_loop ["∀" "∃" ":" "¦"] @keyword.control.repeat) -(quantifier_loop_body ["all" "some"] @keyword.control.repeat) -(iteration ["across" "as"] @keyword.control.repeat) -(initialization "from" @keyword.control.repeat) -(exit_condition "until" @keyword.control.repeat) -(loop_body "loop" @keyword.control.repeat) -(variant "variant" @keyword.control.repeat) -(loop (invariant "invariant" @keyword.control.repeat)) -(loop ["⟳" ":" "¦" "⟲"]@keyword.control.repeat) -(loop "end" @keyword.control.repeat) - -[ - "require" - "ensure" - "invariant" - "check" -] @keyword.control.exception - -["(" ")" "[" "]" "<<" ">>"] @punctuation.bracket -["," ":" ";"] @punctuation.delimiter - -[ - (unary) - ":=" - (binary_caret) - (binary_mul_div) - (binary_plus_minus) - (binary_comparison) - (binary_and) - (binary_or) - (binary_implies) - (comparison) - (unary_not) -] @operator - -(result) @variable.builtin -(anchored (call (_) @variable)) -[(verbatim_string) (basic_manifest_string)] @string -[(integer_constant) (real_constant)] @constant.numeric -(boolean_constant) @constant.builtin.boolean -(void) @constant.builtin -(current) @variable.builtin -(extended_feature_name (identifier) @function.method) - -(iteration (identifier) @variable) -(quantifier_loop (identifier) @variable) -(entity_declaration_group (identifier) @variable) - -(class_name) @type -(formal_generic) @type.parameter - -(comment) @comment.line -(header_comment) @comment.line.documentation diff --git a/runtime/queries/eiffel/indents.scm b/runtime/queries/eiffel/indents.scm deleted file mode 100644 index 5be4cb42..00000000 --- a/runtime/queries/eiffel/indents.scm +++ /dev/null @@ -1,30 +0,0 @@ -[ - (notes) - (class_declaration) - (inheritance) - (feature_adaptation) - (creation_clause) - (converters) - - (feature_declaration) - - (attribute_or_routine) - - (precondition) - (local_declarations) - (feature_body) - - (check) - (multi_branch) - (multi_branch_expression) - (conditional) - (conditional_expression) - (loop) - (quantifier_loop) - (iteration) - - (postcondition) - (rescue) - - (invariant) -] @indent diff --git a/runtime/queries/eiffel/textobjects.scm b/runtime/queries/eiffel/textobjects.scm deleted file mode 100644 index 34693a02..00000000 --- a/runtime/queries/eiffel/textobjects.scm +++ /dev/null @@ -1,15 +0,0 @@ -[ - (comment)+ - (header_comment)+ -] @comment.around -[ - (comment) - (header_comment) -] @comment.inside -(formal_arguments) @parameter.around -(entity_declaration_group) @parameter.inside -(attribute_or_routine) @function.around -(feature_body) @function.inside -(class_declaration) @class.around -(feature_clause) @class.inside - diff --git a/runtime/queries/jjconfig/injections.scm b/runtime/queries/jjconfig/injections.scm index 4cc78fde..c553c3b4 100644 --- a/runtime/queries/jjconfig/injections.scm +++ b/runtime/queries/jjconfig/injections.scm @@ -8,18 +8,3 @@ (table (bare_key) @table-name (#any-of? @table-name "revsets" "revset-aliases") [(pair (_) ((string) @injection.content (#set! injection.language "jjrevset"))) (comment)]) - -; Injections for aliases that contain inline scripts. (see `jj util exec --help`) -; This pattern currently relies on the language having the same name as its -; interpreter, which is often the case (sh, bash, python, fish, nu...) -; It also assumes the interpreter accepts the inline script with the "-c" flag. -(table - (bare_key) @table-name (#eq? @table-name "aliases") - (pair (_) (array . - (string) @util (#eq? @util "\"util\"") . (string) @exec (#eq? @exec "\"exec\"") . (string) @dd (#eq? @dd "\"--\"") . - (string) @injection.language . - ; There are many possibilities to combine "-c" with other short flags, but by - ; far the most common one should be the "-e" flag, which makes the script - ; return early when an error occurs. - (string) @dc (#any-of? @dc "\"-c\"" "\"-ce\"" "\"-ec\"") . - (string) @injection.content))) diff --git a/runtime/queries/jsonc/rainbows.scm b/runtime/queries/jsonc/rainbows.scm deleted file mode 100644 index 41269219..00000000 --- a/runtime/queries/jsonc/rainbows.scm +++ /dev/null @@ -1 +0,0 @@ -; inherits: json diff --git a/runtime/queries/jsonnet/injections.scm b/runtime/queries/jsonnet/injections.scm deleted file mode 100644 index 321c90ad..00000000 --- a/runtime/queries/jsonnet/injections.scm +++ /dev/null @@ -1,2 +0,0 @@ -((comment) @injection.content - (#set! injection.language "comment")) diff --git a/runtime/queries/kcl/highlights.scm b/runtime/queries/kcl/highlights.scm deleted file mode 100644 index 61c24ade..00000000 --- a/runtime/queries/kcl/highlights.scm +++ /dev/null @@ -1,57 +0,0 @@ -;; Maps AST nodes (left) to highlighting classes (right) -;; See https://docs.helix-editor.com/themes.html#scopes -;; for the supported scopes. -;; Don't forget to run the command `hx --grammar fetch` to fetch the grammars, -;; and `hx --grammar build` to build any out-of-date grammars. - -"fn" @keyword.function -"return" @keyword.control.return -"import" @keyword.control.import -"export" @keyword.control.import -[ - "if" - "else" - ] @keyword.control.conditional -(identifier) @variable - -;; highlight type names -(type_name - (identifier) @type -) @type - -(fn_call - callee: (identifier) @function - (labeledArg - label: (identifier) @variable.parameter - ) -) - - -;; operators -(binary_operator) @operator -(prefix_operator) @operator - -;; punctuation - -; ".." @punctuation.special - -"(" @punctuation.bracket -")" @punctuation.bracket -"[" @punctuation.bracket -"]" @punctuation.bracket -"{" @punctuation.bracket -"}" @punctuation.bracket - -; "." @punctuation.delimiter -"," @punctuation.delimiter -; ":" @punctuation.delimiter -; ";" @punctuation.delimiter - -;; literals -(boolean) @constant.builtin.boolean -(string) @string -(number) @constant.numeric - -;; comments -(shebang) @keyword.directive -(comment) @comment diff --git a/runtime/queries/kdl/highlights.scm b/runtime/queries/kdl/highlights.scm index 9ba420a9..78e5acf4 100644 --- a/runtime/queries/kdl/highlights.scm +++ b/runtime/queries/kdl/highlights.scm @@ -1,15 +1,5 @@ -[ - (single_line_comment) - (multi_line_comment) - - (node_comment) - (node_field_comment) - - ; these do not show up as comments in Helix as they are also highlighted as - ; normal nodes - (node . (node_comment)) - (node_field . (node_field_comment)) -] @comment +(single_line_comment) @comment +(multi_line_comment) @comment (node (identifier) @variable) diff --git a/runtime/queries/koto/highlights.scm b/runtime/queries/koto/highlights.scm index bdc01440..b1dd990e 100644 --- a/runtime/queries/koto/highlights.scm +++ b/runtime/queries/koto/highlights.scm @@ -105,7 +105,7 @@ start: (identifier) @function) (chain - (lookup (identifier)) @variable.other.member) + lookup: (identifier) @variable.other.member) (call function: (identifier)) @function diff --git a/runtime/queries/koto/rainbows.scm b/runtime/queries/koto/rainbows.scm deleted file mode 100644 index 2e2dab5e..00000000 --- a/runtime/queries/koto/rainbows.scm +++ /dev/null @@ -1,11 +0,0 @@ -[ - (args) - (call_args) - (index) - (list) - (map) - (parenthesized) - (tuple) -] @rainbow.scope - -["(" ")" "[" "]" "{" "}"] @rainbow.bracket diff --git a/runtime/queries/miseconfig/highlights.scm b/runtime/queries/miseconfig/highlights.scm deleted file mode 100644 index b55e36da..00000000 --- a/runtime/queries/miseconfig/highlights.scm +++ /dev/null @@ -1 +0,0 @@ -; inherits: toml diff --git a/runtime/queries/miseconfig/indents.scm b/runtime/queries/miseconfig/indents.scm deleted file mode 100644 index b55e36da..00000000 --- a/runtime/queries/miseconfig/indents.scm +++ /dev/null @@ -1 +0,0 @@ -; inherits: toml diff --git a/runtime/queries/miseconfig/injections.scm b/runtime/queries/miseconfig/injections.scm deleted file mode 100644 index 01da52cb..00000000 --- a/runtime/queries/miseconfig/injections.scm +++ /dev/null @@ -1,34 +0,0 @@ -; inherits: toml - -; This part covers simple tasks where only the command(s) to run -; are specified as a string or array of strings, e.g. -; -; [tasks] -; simple = "simple-command arg1 arg2" -; many-simple = [ -; "simple-command-1", -; "simple-command-2", -; ] -; -(table - (bare_key) @table-name (#eq? @table-name "tasks") - (pair (_) [ - ((string) @injection.shebang @injection.content (#set! injection.language "bash")) - ((array (string) @injection.shebang @injection.content (#set! injection.language "bash"))) - ]) -) - -; This part covers advanced tasks which are specified as a table. -; Only the "run" key is subject to injections. -; -; [tasks.foo] -; description = "This is regular text." -; run = "this is bash" -; -(table - (dotted_key (bare_key) @table-name (#eq? @table-name "tasks")) - (pair (bare_key) @key-name (#eq? @key-name "run") [ - ((string) @injection.shebang @injection.content (#set! injection.language "bash")) - ((array (string) @injection.shebang @injection.content (#set! injection.language "bash"))) - ]) -) diff --git a/runtime/queries/miseconfig/textobjects.scm b/runtime/queries/miseconfig/textobjects.scm deleted file mode 100644 index b55e36da..00000000 --- a/runtime/queries/miseconfig/textobjects.scm +++ /dev/null @@ -1 +0,0 @@ -; inherits: toml diff --git a/runtime/queries/nearley/highlights.scm b/runtime/queries/nearley/highlights.scm deleted file mode 100644 index 7cc0b6e4..00000000 --- a/runtime/queries/nearley/highlights.scm +++ /dev/null @@ -1,43 +0,0 @@ - -(comment) @comment.line - -(string) @string -(string "i" @keyword.modifier) - -(identifier) @variable.other -(rule_name (identifier) @function) -(rule (generic (identifier) @function)) - -(directive_name) @keyword.directive -(directive_value (identifier) @constant) -(directive_value (string) @string) - -(token) @constant - -(generic - "<" @punctuation.bracket - (identifier) @type.parameter - ">" @punctuation.bracket -) - -(group "(" @punctuation.bracket ")" @punctuation.bracket) - -(charset) @string.regexp -(wildcard) @keyword - -(quantifier) @function.builtin - -(macro_name - "[" @punctuation.bracket - (identifier) @variable.parameter - "]" @punctuation.bracket -) -(macro_arg) @variable.parameter - -(rule "->" @operator) -(rule_body "|" @operator) - -(cont_block "@{%" @keyword.directive "%}" @keyword.directive) -(cont_inline "{%" @keyword.directive "%}" @keyword.directive) - -(ifdef) @keyword.directive diff --git a/runtime/queries/nearley/injections.scm b/runtime/queries/nearley/injections.scm deleted file mode 100644 index d8168304..00000000 --- a/runtime/queries/nearley/injections.scm +++ /dev/null @@ -1,2 +0,0 @@ -((cont) @injection.content - (#set! injection.language "javascript")) diff --git a/runtime/queries/nearley/rainbows.scm b/runtime/queries/nearley/rainbows.scm deleted file mode 100644 index 5de4f8e1..00000000 --- a/runtime/queries/nearley/rainbows.scm +++ /dev/null @@ -1,3 +0,0 @@ -((group) @rainbow.scope) - -["(" ")"] @rainbow.bracket diff --git a/runtime/queries/nu/folds.scm b/runtime/queries/nu/folds.scm deleted file mode 100644 index 53607745..00000000 --- a/runtime/queries/nu/folds.scm +++ /dev/null @@ -1,10 +0,0 @@ -[ - (attribute_list) - (block) - (command_list) - (parameter_bracks) - (record_body) - (val_list) - (val_table) - (val_closure) -] @fold diff --git a/runtime/queries/nu/highlights.scm b/runtime/queries/nu/highlights.scm index 27583f2f..66a30584 100644 --- a/runtime/queries/nu/highlights.scm +++ b/runtime/queries/nu/highlights.scm @@ -1,410 +1,284 @@ -; --- -; keywords +;;; --- +;;; keywords [ - "let" - "mut" - "const" -] @keyword + "def" + "alias" + "export-env" + "export" + "extern" + "module" -[ - "if" - "else" - "match" -] @keyword.control.conditional + "let" + "let-env" + "mut" + "const" -[ - "loop" - "while" -] @keyword.control.repeat + "hide-env" -"def" @keyword.function + "source" + "source-env" -[ - "try" - "catch" - "error" -] @keyword.control.exception + "overlay" + "register" -[ - "module" - "use" -] @keyword.control.import + "loop" + "while" + "error" -[ - "alias" - "export-env" - "export" - "extern" -] @keyword.storage.modifier + "do" + "if" + "else" + "try" + "catch" + "match" -(decl_use - "use" @keyword.control.import) + "break" + "continue" + "return" + +] @keyword + +(hide_mod "hide" @keyword) +(decl_use "use" @keyword) (ctrl_for - "for" @keyword.control.repeat - "in" @keyword.control.repeat) + "for" @keyword + "in" @keyword +) +(overlay_list "list" @keyword.storage.modifier) +(overlay_hide "hide" @keyword.storage.modifier) +(overlay_new "new" @keyword.storage.modifier) +(overlay_use + "use" @keyword.storage.modifier + "as" @keyword +) +(ctrl_error "make" @keyword.storage.modifier) -; --- -; literals +;;; --- +;;; literals (val_number) @constant.numeric - (val_duration - unit: _ @variable.parameter) - + unit: [ + "ns" "µs" "us" "ms" "sec" "min" "hr" "day" "wk" + ] @variable.parameter +) (val_filesize - unit: _ @variable.parameter) - + unit: [ + "b" "B" + + "kb" "kB" "Kb" "KB" + "mb" "mB" "Mb" "MB" + "gb" "gB" "Gb" "GB" + "tb" "tB" "Tb" "TB" + "pb" "pB" "Pb" "PB" + "eb" "eB" "Eb" "EB" + + "kib" "kiB" "kIB" "kIb" "Kib" "KIb" "KIB" + "mib" "miB" "mIB" "mIb" "Mib" "MIb" "MIB" + "gib" "giB" "gIB" "gIb" "Gib" "GIb" "GIB" + "tib" "tiB" "tIB" "tIb" "Tib" "TIb" "TIB" + "pib" "piB" "pIB" "pIb" "Pib" "PIb" "PIB" + "eib" "eiB" "eIB" "eIb" "Eib" "EIb" "EIB" + ] @variable.parameter +) (val_binary - [ - "0b" - "0o" - "0x" - ] @constant.numeric - "[" @punctuation.bracket - digit: [ - "," @punctuation.delimiter - (hex_digit) @constant.numeric - ] - "]" @punctuation.bracket) @constant.numeric - -(val_bool) @constant.builtin.boolean - + [ + "0b" + "0o" + "0x" + ] @constant.numeric + "[" @punctuation.bracket + digit: [ + "," @punctuation.delimiter + (hex_digit) @constant.number + ] + "]" @punctuation.bracket +) @constant.numeric +(val_bool) @constant.builtin (val_nothing) @constant.builtin - (val_string) @string - -arg_str: (val_string) @variable.parameter - -file_path: (val_string) @variable.parameter - -(val_date) @constant.numeric - +(val_date) @constant.number (inter_escape_sequence) @constant.character.escape - (escape_sequence) @constant.character.escape - -(val_interpolated - [ +(val_interpolated [ "$\"" "$\'" "\"" "\'" - ] @string) - +] @string) (unescaped_interpolated_content) @string - (escaped_interpolated_content) @string +(expr_interpolated ["(" ")"] @variable.parameter) -(expr_interpolated - [ - "(" - ")" - ] @variable.parameter) - -(raw_string_begin) @punctuation.special - -(raw_string_end) @punctuation.special - -; --- -; operators -(expr_binary - opr: _ @operator) - -(where_predicate - opr: _ @operator) - -(assignment - [ +;;; --- +;;; operators +(expr_binary [ + "+" + "-" + "*" + "/" + "mod" + "//" + "++" + "**" + "==" + "!=" + "<" + "<=" + ">" + ">=" + "=~" + "!~" + "and" + "or" + "xor" + "bit-or" + "bit-xor" + "bit-and" + "bit-shl" + "bit-shr" + "in" + "not-in" + "starts-with" + "ends-with" +] @operator ) + +(where_command [ + "+" + "-" + "*" + "/" + "mod" + "//" + "++" + "**" + "==" + "!=" + "<" + "<=" + ">" + ">=" + "=~" + "!~" + "and" + "or" + "xor" + "bit-or" + "bit-xor" + "bit-and" + "bit-shl" + "bit-shr" + "in" + "not-in" + "starts-with" + "ends-with" +] @operator) + +(assignment [ "=" "+=" "-=" "*=" "/=" "++=" - ] @operator) +] @operator) -(expr_unary - [ - "not" - "-" - ] @operator) +(expr_unary ["not" "-"] @operator) -(val_range - [ +(val_range [ ".." "..=" "..<" - ] @operator) +] @operator) -[ - "=>" - "=" - "|" -] @operator +["=>" "=" "|"] @operator [ - "o>" - "out>" - "e>" - "err>" - "e+o>" - "err+out>" - "o+e>" - "out+err>" - "o>>" - "out>>" - "e>>" - "err>>" - "e+o>>" - "err+out>>" - "o+e>>" - "out+err>>" - "e>|" - "err>|" - "e+o>|" - "err+out>|" - "o+e>|" - "out+err>|" -] @operator - -; --- -; punctuation + "o>" "out>" + "e>" "err>" + "e+o>" "err+out>" + "o+e>" "out+err>" +] @special + +;;; --- +;;; punctuation [ - "," - ";" -] @punctuation.special - -(param_long_flag - "--" @punctuation.delimiter) - -(long_flag - "--" @punctuation.delimiter) - -(short_flag - "-" @punctuation.delimiter) - -(long_flag - "=" @punctuation.special) - -(short_flag - "=" @punctuation.special) - -(param_short_flag - "-" @punctuation.delimiter) - -(param_rest - "..." @punctuation.delimiter) - -(param_type - ":" @punctuation.special) - -(param_value - "=" @punctuation.special) - -(param_cmd - "@" @punctuation.special) - -(attribute - "@" @punctuation.special) - -(param_opt - "?" @punctuation.special) - -(returns - "->" @punctuation.special) + "," + ";" +] @punctuation.delimiter + +(param_short_flag "-" @punctuation.delimiter) +(param_long_flag ["--"] @punctuation.delimiter) +(long_flag ["--"] @punctuation.delimiter) +(param_rest "..." @punctuation.delimiter) +(param_type [":"] @punctuation.special) +(param_value ["="] @punctuation.special) +(param_cmd ["@"] @punctuation.special) +(param_opt ["?"] @punctuation.special) [ - "(" - ")" - "{" - "}" - "[" - "]" - "...[" - "...(" - "...{" + "(" ")" + "{" "}" + "[" "]" ] @punctuation.bracket (val_record - (record_entry - ":" @punctuation.delimiter)) - -key: (identifier) @property - -; --- -; identifiers + (record_entry ":" @punctuation.delimiter)) +;;; --- +;;; identifiers (param_rest - name: (_) @variable.parameter) - + name: (_) @variable.parameter) (param_opt - name: (_) @variable.parameter) - + name: (_) @variable.parameter) (parameter - param_name: (_) @variable.parameter) - + param_name: (_) @variable.parameter) (param_cmd - (cmd_identifier) @string) - -(param_long_flag - (long_flag_identifier) @attribute) - -(param_short_flag - (param_short_flag_identifier) @attribute) - -(attribute - (attribute_identifier) @attribute) - -(short_flag - (short_flag_identifier) @attribute) + (cmd_identifier) @string) +(param_long_flag) @variable.parameter +(param_short_flag) @variable.parameter -(long_flag_identifier) @attribute +(short_flag) @variable.parameter +(long_flag) @variable.parameter -(scope_pattern - (wild_card) @function) +(scope_pattern [(wild_card) @function]) (cmd_identifier) @function -(decl_def . "def" - (val_string - (string_content) @function - ) -) - -; generated with Nu 0.107.0 -; help commands -; | where $it.command_type == built-in and $it.category != core -; | each {$'"($in.name | split row " " | $in.0)"'} -; | uniq -; | str join ' ' -(command - head: (cmd_identifier) @function.builtin - (#any-of? @function.builtin - "all" "ansi" "any" "append" "ast" "bits" "bytes" "cal" "cd" "char" "chunk-by" "chunks" "clear" "collect" "columns" "compact" "complete" "config" "cp" "date" "debug" "decode" "default" "detect" "drop" "du" "each" "encode" "enumerate" "every" "exec" "exit" "explain" "explore" "fill" "filter" "find" "first" "flatten" "format" "from" "generate" "get" "glob" "grid" "group-by" "hash" "headers" "histogram" "history" "http" "input" "insert" "inspect" "interleave" "into" "is-empty" "is-not-empty" "is-terminal" "items" "job" "join" "keybindings" "kill" "last" "length" "let-env" "lines" "load-env" "ls" "math" "merge" "metadata" "mkdir" "mktemp" "move" "mv" "nu-check" "nu-highlight" "open" "panic" "par-each" "parse" "path" "plugin" "port" "prepend" "print" "ps" "query" "random" "reduce" "reject" "rename" "reverse" "rm" "roll" "rotate" "run-external" "save" "schema" "select" "seq" "shuffle" "skip" "sleep" "slice" "sort" "sort-by" "split" "start" "stor" "str" "sys" "table" "take" "tee" "term" "timeit" "to" "touch" "transpose" "tutor" "ulimit" "uname" "uniq" "uniq-by" "update" "upsert" "url" "values" "version" "view" "watch" "which" "whoami" "window" "with-env" "wrap" "zip")) - -(command - head: (cmd_identifier) @keyword.control.repeat - (#any-of? @keyword.control.repeat "break" "continue" "return")) - -(command - head: (cmd_identifier) @keyword - (#any-of? @keyword "do" "source" "source-env" "hide" "hide-env")) - (command - head: (cmd_identifier) @keyword - . - arg_str: (val_string) @keyword.control.import - (#any-of? @keyword "overlay" "error")) - -(command - head: (cmd_identifier) @cmd - arg_str: (val_string) @keyword - (#eq? @cmd "overlay") - (#eq? @keyword "as")) - -(command - "^" @punctuation.delimiter - head: (_) @function) - -"where" @function.builtin + "^" @punctuation.delimiter + head: (_) @function +) -(where_predicate - [ - "?" - "!" - ] @punctuation.delimiter) +"where" @function (path - [ - "." - "?" - "!" - ]? @punctuation.delimiter) @variable.parameter - -(stmt_let - (identifier) @variable) + ["." "?"] @punctuation.delimiter +) @variable.parameter -(val_variable - "$"? @punctuation.special - "...$"? @punctuation.special +(val_variable + "$" @variable.parameter [ - (identifier) @variable - "in" @special - "nu" @namespace - "env" @constant - ]) @none - -(val_cellpath - "$" @punctuation.special) - -(record_entry - ":" @punctuation.special) - -; --- -; types -(flat_type) @type - + (identifier) @namespace + "in" + "nu" + "env" + "nothing" + ] @special +) +;;; --- +;;; types +(flat_type) @type.builtin (list_type - "list" @type.enum - [ - "<" - ">" - ] @punctuation.bracket) - + "list" @type.enum + ["<" ">"] @punctuation.bracket +) (collection_type - [ - "record" - "table" - ] @type.enum - "<" @punctuation.bracket - key: (_) @variable.parameter - [ - "," - ":" - ] @punctuation.special - ">" @punctuation.bracket) - -(composite_type - "oneof" @type.enum - [ - "<" - ">" - ] @punctuation.bracket) - -[(comment) (shebang)] @comment - -((comment)+ @comment.documentation - . - (decl_def)) - -(parameter - (comment) @comment.documentation) - -(command - head: ((cmd_identifier) @function.builtin - (#match? @function.builtin "^\\s*(find|parse|split|str)$")) - flag: (_ - name: (_) @attribute - (#any-of? @attribute "r" "regex")) - . - arg: (_ - (string_content) @string.regexp)) - -(_ - opr: [ - "=~" - "!~" - "like" - "not-like" - ] - rhs: (_ - (string_content) @string.regexp)) + ["record" "table"] @type.enum + "<" @punctuation.bracket + key: (_) @variable.parameter + ["," ":"] @punctuation.delimiter + ">" @punctuation.bracket +) -(command - head: ((_) @function - (#any-of? @function "nu" "$nu.current-exe")) - flag: (_ - name: (_) @attribute - (#any-of? @attribute "c" "e" "commands" "execute")) - . - arg: (_ - (string_content) @string.code)) +(shebang) @comment +(comment) @comment diff --git a/runtime/queries/nu/indents.scm b/runtime/queries/nu/indents.scm deleted file mode 100644 index 5a1f109b..00000000 --- a/runtime/queries/nu/indents.scm +++ /dev/null @@ -1,18 +0,0 @@ -[ - (expr_parenthesized) - (parameter_bracks) - (ctrl_match) - - (val_record) - (val_list) - (val_closure) - (val_table) - - (block) -] @indent - -[ - "}" - "]" - ")" -] @outdent diff --git a/runtime/queries/nu/injections.scm b/runtime/queries/nu/injections.scm index 8005ffdc..690ff9a8 100644 --- a/runtime/queries/nu/injections.scm +++ b/runtime/queries/nu/injections.scm @@ -1,50 +1,7 @@ ((comment) @injection.content - (#set! injection.language "comment")) - -(command - head: ((cmd_identifier) @_cmd - (#match? @_cmd "^\\s*(find|parse|split|str)$")) - flag: (_ - name: (_) @_flag - (#any-of? @_flag "r" "regex")) - . - arg: (_ - (string_content) @injection.content - (#set! injection.language "regex"))) - -(_ - opr: [ - "=~" - "!~" - "like" - "not-like" - ] - rhs: (_ - (string_content) @injection.content - (#set! injection.language "regex"))) - -(command - head: (_) @_cmd - (#any-of? @_cmd "nu" "$nu.current-exe") - flag: (_ - name: (_) @_flag - (#any-of? @_flag "c" "e" "commands" "execute")) - . - arg: (_ - (string_content) @injection.content - (#set! injection.language "nu"))) + (#set! injection.language "comment")) (command head: (cmd_identifier) @_command (#any-of? @_command "jq" "jaq") - . - arg: (_ (string_content) @injection.content) - (#set! injection.language "jq") -) - -(command - head: (cmd_identifier) @_command (#eq? @_command "fish") - flag: (short_flag "-") @_flag (#match? @_flag "^-.*c$") - . - arg: (_ (string_content) @injection.content) - (#set! injection.language "fish") -) + arg: (val_string) @injection.content + (#set! injection.language "jq")) diff --git a/runtime/queries/nu/textobjects.scm b/runtime/queries/nu/textobjects.scm deleted file mode 100644 index ddf92ee2..00000000 --- a/runtime/queries/nu/textobjects.scm +++ /dev/null @@ -1,78 +0,0 @@ -; (stmt_let) @assignment.outer - -; (stmt_mut) @assignment.outer - -; (stmt_const) @assignment.outer - -; (stmt_let -; value: (_) @assignment.inner) - -; (stmt_mut -; value: (_) @assignment.inner) - -; (stmt_const -; value: (_) @assignment.inner) - -; (block) @block.outer - -(comment) @comment.around - -; (pipeline) @pipeline.outer - -; (pipe_element) @pipeline.inner - -(decl_def) @function.around - -(decl_def - body: (_) @function.inside) - -; (ctrl_for) @loop.outer - -; (ctrl_loop) @loop.outer - -; (ctrl_while) @loop.outer - -; (ctrl_for -; body: (_) @loop.inner) - -; (ctrl_loop -; body: (_) @loop.inner) - -; (ctrl_while -; body: (_) @loop.inner) - -; Conditional inner counts the last one, rather than the current one. -; (ctrl_if -; then_branch: (_) @conditional.inner -; else_block: (_)? @conditional.inner) @conditional.outer - -(parameter) @parameter.around - -; (command -; head: (_) @call.inner) @call.outer - -; (where_command -; predicate: (_) @call.inner) @call.outer - -; define pipeline first, because it should only match as a fallback -; e.g., `let a = date now` should match the whole assignment. -; But a standalone `date now` should also match a statement -; (pipeline) @statement.outer - -; (stmt_let) @statement.outer - -; (stmt_mut) @statement.outer - -; (stmt_const) @statement.outer - -; (ctrl_if) @statement.outer - -; (ctrl_try) @statement.outer - -; (ctrl_match) @statement.outer - -; (ctrl_while) @statement.outer - -; (ctrl_loop) @statement.outer - -; (val_number) @number.inner diff --git a/runtime/queries/pest/highlights.scm b/runtime/queries/pest/highlights.scm index 430382c9..9d6f13c2 100644 --- a/runtime/queries/pest/highlights.scm +++ b/runtime/queries/pest/highlights.scm @@ -39,14 +39,11 @@ ] @operator [ - "ANY" - "DROP" - "EOI" - "NEWLINE" + "PUSH" "PEEK" - "PEEK_ALL" "POP" - "POP_ALL" - "PUSH" "SOI" + "EOI" + "ANY" ] @keyword + diff --git a/runtime/queries/python/highlights.scm b/runtime/queries/python/highlights.scm index ad45d495..a8ec18c8 100644 --- a/runtime/queries/python/highlights.scm +++ b/runtime/queries/python/highlights.scm @@ -75,9 +75,6 @@ (lambda_parameters (identifier) @variable.parameter) -(keyword_argument - name: (identifier) @variable.parameter) - ; - Builtin ((identifier) @variable.builtin (#any-of? @variable.builtin "self" "cls")) diff --git a/runtime/queries/python/locals.scm b/runtime/queries/python/locals.scm index 955ebc52..24800870 100644 --- a/runtime/queries/python/locals.scm +++ b/runtime/queries/python/locals.scm @@ -45,6 +45,3 @@ (identifier) @local.reference -; don't make the name of kwargs locals -(keyword_argument - name: (identifier) @variable.parameter) diff --git a/runtime/queries/rust/highlights.scm b/runtime/queries/rust/highlights.scm index cc8380cb..3a4448ba 100644 --- a/runtime/queries/rust/highlights.scm +++ b/runtime/queries/rust/highlights.scm @@ -79,7 +79,11 @@ ; Types ; ------- -(type_parameter +(type_parameters + (type_identifier) @type.parameter) +(constrained_type_parameter + left: (type_identifier) @type.parameter) +(optional_type_parameter name: (type_identifier) @type.parameter) ((type_arguments (type_identifier) @constant) (#match? @constant "^[A-Z_]+$")) @@ -112,7 +116,6 @@ ; Comments ; ------- -(shebang) @comment (line_comment) @comment.line (block_comment) @comment.block @@ -240,6 +243,10 @@ (type_cast_expression "as" @keyword.operator) +((generic_type + type: (type_identifier) @keyword) + (#eq? @keyword "use")) + [ (crate) (super) diff --git a/runtime/queries/scheme/highlights.scm b/runtime/queries/scheme/highlights.scm index 288fcfe9..772dcbf5 100644 --- a/runtime/queries/scheme/highlights.scm +++ b/runtime/queries/scheme/highlights.scm @@ -33,37 +33,6 @@ . (symbol) @function) -(list - . - (symbol) @function.builtin - (#any-of? @function.builtin - "caar" "cadr" "call-with-input-file" "call-with-output-file" "cdar" "cddr" "list" - "open-input-file" "open-output-file" "with-input-from-file" "with-output-to-file" "*" "+" "-" - "/" "<" "<=" "=" ">" ">=" "abs" "acos" "angle" "append" "apply" "asin" "assoc" "assq" "assv" - "atan" "boolean?" "caaaar" "caaadr" "caaar" "caadar" "caaddr" "caadr" "cadaar" "cadadr" "cadar" - "caddar" "cadddr" "caddr" "call-with-current-continuation" "call-with-values" "car" "cdaaar" - "cdaadr" "cdaar" "cdadar" "cdaddr" "cdadr" "cddaar" "cddadr" "cddar" "cdddar" "cddddr" "cdddr" - "cdr" "ceiling" "char->integer" "char-alphabetic?" "char-ci<=?" "char-ci<?" "char-ci=?" - "char-ci>=?" "char-ci>?" "char-downcase" "char-lower-case?" "char-numeric?" "char-ready?" - "char-upcase" "char-upper-case?" "char-whitespace?" "char<=?" "char<?" "char=?" "char>=?" - "char>?" "char?" "close-input-port" "close-output-port" "complex?" "cons" "cos" - "current-error-port" "current-input-port" "current-output-port" "denominator" "display" - "dynamic-wind" "eof-object?" "eq?" "equal?" "eqv?" "eval" "even?" "exact->inexact" "exact?" "exp" - "expt" "floor" "flush-output" "for-each" "force" "gcd" "imag-part" "inexact->exact" "inexact?" - "input-port?" "integer->char" "integer?" "interaction-environment" "lcm" "length" "list->string" - "list->vector" "list-ref" "list-tail" "list?" "load" "log" "magnitude" "make-polar" - "make-rectangular" "make-string" "make-vector" "map" "max" "member" "memq" "memv" "min" "modulo" - "negative?" "newline" "not" "null-environment" "null?" "number->string" "number?" "numerator" - "odd?" "output-port?" "pair?" "peek-char" "positive?" "procedure?" "quotient" "rational?" - "rationalize" "read" "read-char" "real-part" "real?" "remainder" "reverse" "round" - "scheme-report-environment" "set-car!" "set-cdr!" "sin" "sqrt" "string" "string->list" - "string->number" "string->symbol" "string-append" "string-ci<=?" "string-ci<?" "string-ci=?" - "string-ci>=?" "string-ci>?" "string-copy" "string-fill!" "string-length" "string-ref" - "string-set!" "string<=?" "string<?" "string=?" "string>=?" "string>?" "string?" "substring" - "symbol->string" "symbol?" "tan" "transcript-off" "transcript-on" "truncate" "values" "vector" - "vector->list" "vector-fill!" "vector-length" "vector-ref" "vector-set!" "vector?" "write" - "write-char" "zero?")) - ; special forms (list @@ -77,7 +46,7 @@ . (list (symbol) @variable) - (#any-of? @_f "lambda" "λ" "define-values")) + (#any-of? @_f "lambda" "λ")) (list . @@ -101,7 +70,7 @@ ; operators ((symbol) @operator - (#any-of? @operator "+" "-" "*" "/" "=" ">" "<" ">=" "<=")) + (#match? @operator "^(\\+|-|\\*|/|=|>|<|>=|<=)$")) ; library @@ -125,14 +94,19 @@ (list . ((symbol) @keyword.conditional - (#any-of? @keyword.conditional "if" "cond" "case" "when" "unless"))) + (#match? @keyword.conditional "^(if|cond|case|when|unless)$" + ))) (list . (symbol) @keyword - (#any-of? @keyword - "define-syntax" "let*" "lambda" "λ" "case-lambda" "case" "=>" "quote-splicing" "unquote-splicing" - "set!" "let" "letrec" "letrec-syntax" "let-values" "let*-values" "do" "else" "define" "cond" - "syntax-rules" "unquote" "begin" "quote" "let-syntax" "and" "if" "quasiquote" "letrec" "delay" - "or" "when" "unless" "identifier-syntax" "assert" "library" "export" "import" "rename" "only" - "except" "prefix" "define-values")) + (#match? @keyword + "^(define-syntax|let\\*|lambda|λ|case-lambda|case|=>|quote-splicing|unquote-splicing|set!|let|letrec|letrec-syntax|let-values|let\\*-values|do|else|define|cond|syntax-rules|unquote|begin|quote|let-syntax|and|if|quasiquote|letrec|delay|or|when|unless|identifier-syntax|assert|library|export|import|rename|only|except|prefix)$" + )) + +(list + . + (symbol) @function.builtin + (#match? @function.builtin + "^(caar|cadr|call-with-input-file|call-with-output-file|cdar|cddr|list|open-input-file|open-output-file|with-input-from-file|with-output-to-file|\\*|\\+|-|/|<|<=|=|>|>=|abs|acos|angle|append|apply|asin|assoc|assq|assv|atan|boolean\\?|caaaar|caaadr|caaar|caadar|caaddr|caadr|cadaar|cadadr|cadar|caddar|cadddr|caddr|call-with-current-continuation|call-with-values|car|cdaaar|cdaadr|cdaar|cdadar|cdaddr|cdadr|cddaar|cddadr|cddar|cdddar|cddddr|cdddr|cdr|ceiling|char->integer|char-alphabetic\\?|char-ci<=\\?|char-ci<\\?|char-ci=\\?|char-ci>=\\?|char-ci>\\?|char-downcase|char-lower-case\\?|char-numeric\\?|char-ready\\?|char-upcase|char-upper-case\\?|char-whitespace\\?|char<=\\?|char<\\?|char=\\?|char>=\\?|char>\\?|char\\?|close-input-port|close-output-port|complex\\?|cons|cos|current-error-port|current-input-port|current-output-port|denominator|display|dynamic-wind|eof-object\\?|eq\\?|equal\\?|eqv\\?|eval|even\\?|exact->inexact|exact\\?|exp|expt|floor|flush-output|for-each|force|gcd|imag-part|inexact->exact|inexact\\?|input-port\\?|integer->char|integer\\?|interaction-environment|lcm|length|list->string|list->vector|list-ref|list-tail|list\\?|load|log|magnitude|make-polar|make-rectangular|make-string|make-vector|map|max|member|memq|memv|min|modulo|negative\\?|newline|not|null-environment|null\\?|number->string|number\\?|numerator|odd\\?|output-port\\?|pair\\?|peek-char|positive\\?|procedure\\?|quotient|rational\\?|rationalize|read|read-char|real-part|real\\?|remainder|reverse|round|scheme-report-environment|set-car!|set-cdr!|sin|sqrt|string|string->list|string->number|string->symbol|string-append|string-ci<=\\?|string-ci<\\?|string-ci=\\?|string-ci>=\\?|string-ci>\\?|string-copy|string-fill!|string-length|string-ref|string-set!|string<=\\?|string<\\?|string=\\?|string>=\\?|string>\\?|string\\?|substring|symbol->string|symbol\\?|tan|transcript-off|transcript-on|truncate|values|vector|vector->list|vector-fill!|vector-length|vector-ref|vector-set!|vector\\?|write|write-char|zero\\?)$" + )) diff --git a/runtime/queries/svelte/injections.scm b/runtime/queries/svelte/injections.scm index c94373c1..b0903f61 100644 --- a/runtime/queries/svelte/injections.scm +++ b/runtime/queries/svelte/injections.scm @@ -1,4 +1,7 @@ -; inherits html +((style_element + (raw_text) @injection.content) + (#set! injection.language "css")) + ((style_element (start_tag (attribute @@ -11,7 +14,7 @@ (#set! injection.language "scss")) ((svelte_raw_text) @injection.content - (#set! injection.language "typescript")) + (#set! injection.language "javascript")) ((script_element (start_tag diff --git a/runtime/queries/unison/rainbows.scm b/runtime/queries/unison/rainbows.scm deleted file mode 100644 index 1721dc55..00000000 --- a/runtime/queries/unison/rainbows.scm +++ /dev/null @@ -1,10 +0,0 @@ -[ - (literal_list) - (parenthesized_or_tuple_pattern) -] @rainbow.scope - -[ - "(" ")" - "{" "}" - "[" "]" -] @rainbow.bracket diff --git a/runtime/queries/unison/tags.scm b/runtime/queries/unison/tags.scm deleted file mode 100644 index 2834748a..00000000 --- a/runtime/queries/unison/tags.scm +++ /dev/null @@ -1,10 +0,0 @@ -(term_definition - name: (regular_identifier) @name) @definition.function - -(type_declaration - (type_kw) - (type_constructor - ((type_name (regular_identifier) @name)) @definition.type)) - -(ability_declaration - (ability_name) @type _) @definition.type diff --git a/runtime/themes/andromeda.toml b/runtime/themes/andromeda.toml deleted file mode 100644 index c9364e13..00000000 --- a/runtime/themes/andromeda.toml +++ /dev/null @@ -1,186 +0,0 @@ - -# Interface colors -"ui.background" = { bg = "background" } -"ui.background.separator" = { fg = "muted" } -"ui.cursor" = { fg = "background", bg = "cursor" } -"ui.cursor.normal" = { fg = "background", bg = "cursor" } -"ui.cursor.insert" = { fg = "background", bg = "accent" } -"ui.cursor.select" = { fg = "background", bg = "purple" } -"ui.cursor.match" = { fg = "background", bg = "yellow" } -"ui.cursor.primary" = { fg = "background", bg = "cursor" } -"ui.cursor.primary.normal" = { fg = "background", bg = "cursor" } -"ui.cursor.primary.insert" = { fg = "background", bg = "accent" } -"ui.cursor.primary.select" = { fg = "background", bg = "purple" } - -"ui.gutter" = { bg = "background" } -"ui.gutter.selected" = { bg = "line_highlight" } -"ui.linenr" = { fg = "line_numbers" } -"ui.linenr.selected" = { fg = "accent", modifiers = ["bold"] } - -"ui.statusline" = { fg = "foreground", bg = "background" } -"ui.statusline.inactive" = { fg = "muted", bg = "background" } -"ui.statusline.normal" = { fg = "background", bg = "accent" } -"ui.statusline.insert" = { fg = "background", bg = "green" } -"ui.statusline.select" = { fg = "background", bg = "purple" } - -"ui.popup" = { fg = "foreground", bg = "popup_bg" } -"ui.popup.info" = { fg = "foreground", bg = "popup_bg" } -"ui.window" = { fg = "muted" } -"ui.help" = { fg = "foreground", bg = "popup_bg" } - -"ui.text" = { fg = "foreground" } -"ui.text.focus" = { fg = "accent", modifiers = ["bold"] } -"ui.text.inactive" = { fg = "muted" } -"ui.text.info" = { fg = "foreground" } - -"ui.virtual.ruler" = { bg = "line_highlight" } -"ui.virtual.whitespace" = { fg = "muted" } -"ui.virtual.indent-guide" = { fg = "muted" } -"ui.virtual.inlay-hint" = { fg = "hint" } -"ui.virtual.jump-label" = { fg = "white", bg = "background" } - -"ui.menu" = { fg = "foreground", bg = "popup_bg" } -"ui.menu.selected" = { fg = "background", bg = "accent" } -"ui.menu.scroll" = { fg = "muted", bg = "background" } - -"ui.selection" = { bg = "selection_background" } -"ui.selection.primary" = { bg = "selection_background" } -"ui.highlight" = { bg = "line_highlight" } -"ui.cursorline.primary" = { bg = "line_highlight" } -"ui.cursorline.secondary" = { bg = "line_highlight" } - -# Diagnostics -"warning" = { fg = "warning" } -"error" = { fg = "error" } -"info" = { fg = "info" } -"hint" = { fg = "hint" } -"diagnostic" = { modifiers = ["underlined"] } -"diagnostic.hint" = { fg = "hint", modifiers = ["underlined"] } -"diagnostic.info" = { fg = "info", modifiers = ["underlined"] } -"diagnostic.warning" = { fg = "warning", modifiers = ["underlined"] } -"diagnostic.error" = { fg = "error", modifiers = ["underlined"] } -"diagnostic.unnecessary" = { fg = "muted", modifiers = ["dim"] } - -# Syntax highlighting -"comment" = { fg = "comment", modifiers = ["italic"] } -"constant" = { fg = "red" } -"constant.character" = { fg = "green" } -"constant.character.escape" = { fg = "yellow" } -"constant.numeric" = { fg = "orange" } -"constant.builtin" = { fg = "red" } - -"string" = { fg = "green" } -"string.regexp" = { fg = "blue" } -"string.special" = { fg = "yellow" } - -"type" = { fg = "yellow" } -"type.builtin" = { fg = "yellow" } -"type.enum" = { fg = "yellow" } -"type.parameter" = { fg = "orange" } - -"constructor" = { fg = "red" } -"function" = { fg = "yellow" } -"function.builtin" = { fg = "yellow" } -"function.method" = { fg = "yellow" } -"function.macro" = { fg = "purple" } - -"variable" = { fg = "cyan" } -"variable.builtin" = { fg = "red" } -"variable.parameter" = { fg = "orange" } -"variable.other.member" = { fg = "cyan" } - -"keyword" = { fg = "purple" } -"keyword.control" = { fg = "purple" } -"keyword.control.conditional" = { fg = "purple" } -"keyword.control.repeat" = { fg = "purple" } -"keyword.control.import" = { fg = "purple" } -"keyword.control.return" = { fg = "purple" } -"keyword.control.exception" = { fg = "purple" } -"keyword.operator" = { fg = "red" } -"keyword.directive" = { fg = "purple" } -"keyword.function" = { fg = "purple" } -"keyword.storage" = { fg = "purple" } -"keyword.storage.type" = { fg = "purple" } -"keyword.storage.modifier" = { fg = "purple" } - -"operator" = { fg = "red" } -"punctuation" = { fg = "foreground" } -"punctuation.delimiter" = { fg = "foreground" } -"punctuation.bracket" = { fg = "foreground" } -"punctuation.special" = { fg = "hot_pink" } - -"tag" = { fg = "hot_pink" } -"attribute" = { fg = "orange" } -"namespace" = { fg = "yellow" } -"module" = { fg = "yellow" } -"special" = { fg = "hot_pink" } - -# Markup -"markup.heading" = { fg = "hot_pink", modifiers = ["bold"] } -"markup.heading.marker" = { fg = "hot_pink" } -"markup.list" = { fg = "yellow" } -"markup.list.marker" = { fg = "hot_pink" } -"markup.bold" = { fg = "orange", modifiers = ["bold"] } -"markup.italic" = { fg = "purple", modifiers = ["italic"] } -"markup.strikethrough" = { modifiers = ["crossed_out"] } -"markup.link.url" = { fg = "blue", modifiers = ["underlined"] } -"markup.link.text" = { fg = "cyan" } -"markup.quote" = { fg = "comment", modifiers = ["italic"] } -"markup.raw" = { fg = "green" } -"markup.raw.block" = { fg = "green" } - -# Diff -"diff.plus" = { fg = "diff_add" } -"diff.minus" = { fg = "diff_delete" } -"diff.delta" = { fg = "diff_change" } - -# Color palette -[palette] -# Main colors -white = "#FFFFFF" -background = "#23262E" -foreground = "#D5CED9" -cursor = "#FFFFFF" - -# UI colors -line_highlight = "#2e323d" -selection_background = "#3D4352" -line_numbers = "#746f77" -muted = "#746f77" -popup_bg = "#20232A" - -# Accent colors -accent = "#00e8c6" # Cyan -cyan = "#00e8c6" # Cyan -orange = "#f39c12" # Orange -yellow = "#FFE66D" # Yellow -purple = "#c74ded" # Purple -hot_pink = "#f92672" # Hot Pink -blue = "#7cb7ff" # Blue -red = "#ee5d43" # Red -green = "#96E072" # Green - -# Syntax colors -comment = "#A0A1A7" -string = "#96E072" -number = "#f39c12" -keyword = "#c74ded" -function = "#FFE66D" -variable = "#00e8c6" -type = "#FFE66D" -constant = "#ee5d43" -operator = "#ee5d43" -tag = "#f92672" -attribute = "#f39c12" -punctuation = "#D5CED9" - -# Diagnostic colors -error = "#FC644D" -warning = "#FF9F2E" -info = "#00b0ff" -hint = "#746f77" - -# Diff colors -diff_add = "#96E072" -diff_delete = "#FC644D" -diff_change = "#FFE66D" diff --git a/runtime/themes/darcula.toml b/runtime/themes/darcula.toml index 2b98684c..5b83afba 100644 --- a/runtime/themes/darcula.toml +++ b/runtime/themes/darcula.toml @@ -88,8 +88,6 @@ "warning" = "orange" "error" = "red" -rainbow = ["rainbow_gold", "rainbow_blue", "rainbow_orange", "rainbow_purple", "rainbow_khaki", "rainbow_turquoise"] - [palette] grey00 = "#181818" # Default Background grey01 = "#282828" # Lighter Background (Used for status bars, line number and folding marks) @@ -110,11 +108,3 @@ grey = "#808080" darkgreen = "#629755" lightblue = "#6897bb" blue = "#104158" - -# Rainbow bracket colors -rainbow_gold = "#FFD700" -rainbow_blue = "#1E90FF" -rainbow_orange = "#FF8C00" -rainbow_purple = "#9370DB" -rainbow_khaki = "#F0E68C" -rainbow_turquoise = "#00CED1" diff --git a/runtime/themes/doom-one.toml b/runtime/themes/doom-one.toml index 60dbd874..8daa9346 100644 --- a/runtime/themes/doom-one.toml +++ b/runtime/themes/doom-one.toml @@ -11,7 +11,6 @@ "ui.selection" = { bg = "bg_highlight" } "ui.selection.primary" = { bg = "bg_highlight" } "ui.virtual.ruler" = { bg = "bg_highlight" } -"ui.virtual.jump-label" = { fg = "cyan", modifiers = ["bold"] } # Markdown Highlighting "markup.raw" = { fg = "blue", bg = "bg" } @@ -103,7 +102,7 @@ # Popups for documentation or file picker "ui.popup" = { fg = "fg", bg = "bg" } -"ui.popup.info" = { fg = "fg", bg = "bg_alt" } +"ui.popup.info" = { fg = "fg", bg = "bg" } "ui.menu" = { fg = "fg", bg = "bg" } "ui.menu.selected" = { fg = "cyan", bg = "bg_highlight" } diff --git a/runtime/themes/licenses/zenburn.license b/runtime/themes/licenses/zenburn.license deleted file mode 100644 index f288702d..00000000 --- a/runtime/themes/licenses/zenburn.license +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - <program> Copyright (C) <year> <name of author> - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -<https://www.gnu.org/licenses/>. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -<https://www.gnu.org/licenses/why-not-lgpl.html>. diff --git a/runtime/themes/nord.toml b/runtime/themes/nord.toml index db7b6190..e2872d4f 100644 --- a/runtime/themes/nord.toml +++ b/runtime/themes/nord.toml @@ -5,7 +5,7 @@ ## SYNTAX HIGHLIGHTING # Constants -"constant" = "nord4" +"constant" = "nord4" "constant.builtin" = "nord9" "constant.builtin.boolean" = "nord9" "constant.builtin.character" = "nord15" @@ -110,7 +110,7 @@ "ui.linenr.selected" = "nord5" # Cursor -"ui.cursor" = { fg = "nord4", modifiers = ["reversed"] } +"ui.cursor" = { fg = "nord4", modifiers = [ "reversed" ] } "ui.cursorcolumn.primary" = { bg = "nord1" } "ui.cursorline.primary" = { bg = "nord1" } "ui.cursor.match" = { bg = "nord3" } @@ -119,7 +119,7 @@ "ui.highlight" = { fg = "nord8", bg = "nord2" } # Statusline -"ui.statusline" = { bg = "nord1" } +"ui.statusline" = { bg = "nord1" } "ui.statusline.inactive" = { fg = "nord8", bg = "nord1" } "ui.statusline.insert" = { fg = "nord1", bg = "nord6" } "ui.statusline.normal" = { fg = "nord1", bg = "nord8" } @@ -136,9 +136,7 @@ # Bufferline "ui.bufferline" = { fg = "nord5", bg = "nord1" } -"ui.bufferline.active" = { fg = "nord6", bg = "nord2", underline = { color = "nord8", style = "line" }, modifiers = [ - "italic", -] } +"ui.bufferline.active" = { fg = "nord6", bg = "nord2", underline = { color = "nord8", style = "line" }, modifiers = [ "italic" ] } # Markup "markup.heading" = "nord8" @@ -149,51 +147,48 @@ "markup.link.text" = "nord8" "markup.raw" = "nord7" -# Rainbow brackets -rainbow = ["nord13", "nord15", "nord14", "nord12"] - [palette] # Polar Night is made up of four darker colors that are commonly used for base elements like backgrounds or text color in bright ambiance designs. # # The origin color or the Polar Night palette -nord0 = "#2e3440" +nord0 = "#2e3440" # A brighter shade color based on nord0 -nord1 = "#3B4252" +nord1 = "#3B4252" # An even more brighter shade color of nord0 -nord2 = "#434C5E" +nord2 = "#434C5E" # The brightest shade color based on nord0 -nord3 = "#4C566A" +nord3 = "#4C566A" # 10% brighter for comments, see https://github.com/nordtheme/nord/issues/94 -nord3_bright = "#616e88" +nord3_bright = "#616e88" # Snow Storm is made up of three bright colors that are commonly used for text colors or base UI elements in bright ambiance designs. # The origin color or the Snow Storm palette -nord4 = "#D8DEE9" +nord4 = "#D8DEE9" # A brighter shade color of nord4 -nord5 = "#E5E9F0" +nord5 = "#E5E9F0" # The brightest shade color based on nord4 -nord6 = "#ECEFF4" +nord6 = "#ECEFF4" # Frost can be described as the heart palette of Nord, a group of four bluish colors that are commonly used for primary UI component and text highlighting and essential code syntax elements. # # A calm and highly contrasted color reminiscent of frozen polar water -nord7 = "#8FBCBB" +nord7 = "#8FBCBB" # The bright and shiny primary accent color reminiscent of pure and clear ice -nord8 = "#88C0D0" +nord8 = "#88C0D0" # A more darkened and less saturated color reminiscent of arctic waters -nord9 = "#81A1C1" +nord9 = "#81A1C1" # A dark and intensive color reminiscent of the deep arctic ocean -nord10 = "#5E81AC" +nord10 = "#5E81AC" # Aurora consists of five colorful components reminiscent of the "Aurora borealis", sometimes referred to as polar lights or northern lights. # # Red -nord11 = "#BF616A" +nord11 = "#BF616A" # Orange -nord12 = "#D08770" +nord12 = "#D08770" # Yellow -nord13 = "#EBCB8B" +nord13 = "#EBCB8B" # Green -nord14 = "#A3BE8C" +nord14 = "#A3BE8C" # Purple -nord15 = "#B48EAD" +nord15 = "#B48EAD" diff --git a/runtime/themes/ttox_soft.toml b/runtime/themes/ttox_soft.toml deleted file mode 100644 index b4fe71cb..00000000 --- a/runtime/themes/ttox_soft.toml +++ /dev/null @@ -1,37 +0,0 @@ -# Author : Samuel Guyah <[email protected]> - -"ui.selection" = { fg = "white", bg = "gray" } -"ui.cursor" = { fg = "black", bg = "light-gray" } -"ui.cursor.primary" = { fg = "black", bg = "light-gray" } -"ui.cursor.match" = { modifiers = ["underlined"] } -"ui.background.separator" = "gray" -"ui.linenr" = "gray" -"ui.linenr.selected" = { fg = "white", bg = "gray" } -"ui.statusline" = { bg = "black", fg = "white" } -"ui.menu" = { fg = "white", bg = "black" } -"ui.menu.selected" = { bg = "light-gray", fg = "black" } -"ui.popup" = { fg = "white", bg = "black" } -"ui.help" = { fg = "white", bg = "black" } -"ui.virtual.ruler" = { underline = { style = "line" } } -"ui.bufferline" = { fg = "white", bg = "black" } -"ui.bufferline.active" = { fg = "black", bg = "white" } -"ui.bufferline.background" = { bg = "black" } - - -"string" = { fg = "light-green" } -"constant" = { fg = "light-cyan" } -"comment" = { fg = "light-magenta" } - -"diff.plus" = "green" -"diff.minus" = "red" -"diff.delta" = "gray" - -"warning" = { fg = "light-yellow" } -"error" = { fg = "light-red" } -"hint" = { fg = "light-blue" } - -"diagnostic.warning" = { fg = "light-yellow" } -"diagnostic.error" = { fg = "light-red" } -"diagnostic.hint" = { fg = "light-blue" } -"diagnostic.unnecessary" = { modifiers = ["dim"] } -"diagnostic.deprecated" = { modifiers = ["crossed_out"] } diff --git a/runtime/themes/zenburn.toml b/runtime/themes/zenburn.toml index c40f4cdf..002db10f 100644 --- a/runtime/themes/zenburn.toml +++ b/runtime/themes/zenburn.toml @@ -1,278 +1,66 @@ -# Port of Vim's Zenburn theme (https://github.com/jnurmine/Zenburn/) -# based on theli-ua's Helix port (https://github.com/theli-ua/helix/tree/zenburn) -# Author: Jakob Jordan <jakobjordan(at)posteo.de> -# License: GNU GPL <http://www.gnu.org/licenses/gpl.html> +# A unofficial port of VIM's zenburn theme: https://github.com/jnurmine/Zenburn/ -# "attribute" -"type" = "zb-type-fg" -"type.builtin" = { fg = "zb-type-fg", modifiers = ["bold"] } -"type.parameter" = { fg = "zb-typedef-fg", modifiers = ["bold"] } -"type.enum" = { fg = "zb-structure-fg", modifiers = ["bold"] } -# "type.enum.variant" -"constructor" = "zb-type-fg" -"constant" = { fg = "zb-constant-fg", modifiers = ["bold"] } -# "constant.builtin" -"constant.builtin.boolean" = "zb-boolean-fg" -"constant.character" = { fg = "zb-character-fg", modifiers = ["bold"] } -# "constant.character.escape" -"constant.numeric.integer" = { fg = "zb-number-fg" } -"constant.numeric.float" = { fg = "zb-float-fg" } -"string" = "zb-string-fg" -# "string.regexp" -# "string.special" -# "string.special.path" -# "string.special.url" -# "string.special.symbol" -"comment" = "zb-comment-fg" -# "comment.line" -"comment.line.documentation" = { fg = "zb-specialcomment-fg", modifiers = ["bold"] } -# "comment.block" -"comment.block.documentation" = { fg = "zb-specialcomment-fg", modifiers = ["bold"] } -"variable" = "zb-identifier-fg" -"variable.builtin" = { modifiers = ["bold"] } -# "variable.parameter" -# "variable.other" -# "variable.other.member" -# "variable.other.member.private" -"label" = { fg = "zb-label-fg", underline = { style = 'line' } } -# "punctuation" -"punctuation.delimiter" = "zb-delimiter-fg" -# "punctuation.bracket" -"punctuation.special" = "zb-special-fg" -"keyword" = { fg = "zb-keyword-fg", modifiers = ["bold"] } -# "keyword.control" -"keyword.control.conditional" = { fg = "zb-conditional-fg", modifiers = ["bold"] } -"keyword.control.repeat" = { fg = "zb-repeat-fg", modifiers = ["bold"] } -"keyword.control.import" = { fg = "zb-preproc-fg", modifiers = ["bold"] } -# "keyword.control.return" -"keyword.control.exception" = { fg = "zb-exception-fg", modifiers = ["bold"] } -# "keyword.operator" -# "keyword.directive" -# "keyword.function" -# "keyword.storage" -"keyword.storage.type" = { fg = "zb-storageclass-fg", modifiers = ["bold"] } -# "keyword.storage.modifier" -"operator" = "zb-operator-fg" -"function" = "zb-function-fg" -"function.builtin" = { fg = "zb-function-fg", modifiers = ["bold"] } -# "function.method" -# "function.method.private" -"function.macro" = { fg = "zb-macro-fg", modifiers = ["bold"] } -# "function.special" -"tag" = { fg = "zb-tag-fg", modifiers = ["bold"] } -# "tag.builtin" -"namespace" = { fg = "zb-include-fg", modifiers = ["bold"] } -"special" = "zb-special-fg" -# "markup" -"markup.heading" = { fg = "zb-constant-fg", modifiers = ["bold"] } -# "markup.heading.marker" -# "markup.heading.1" -# "markup.heading.2" -# "markup.heading.3" -# "markup.heading.4" -# "markup.heading.5" -# "markup.heading.6" -"markup.list" = "zb-number-fg" -# "markup.list.unnumbered" -# "markup.list.numbered" -# "markup.list.checked" -# "markup.list.unchecked" -"markup.bold" = { modifiers = ["bold"] } -"markup.italic" = { modifiers = ["italic"] } -"markup.strikethrough" = { modifiers = ["crossed_out"] } -"markup.link" = { underline.style = "line" } -# "markup.link.url" -# "markup.link.label" -# "markup.link.text" = "zb-cyan" -"markup.quote" = "zb-comment-fg" -"markup.raw" = "zb-delimiter-fg" -# "markup.raw.inline" -# "markup.raw.block" -# "diff" -"diff.plus" = { fg = "zb-diffadd-fg", bg = "zb-diffadd-bg", modifiers = ["bold"] } -"diff.plus.gutter" = "zb-diffadd-fg" -"diff.minus" = { fg = "zb-diffdelete-fg", bg = "zb-diffdelete-bg" } -"diff.minus.gutter" = "zb-string-fg" -"diff.delta" = { bg = "zb-diffchange-bg" } -# "diff.delta.moved" -# "diff.delta.conflict" -"diff.delta.gutter" = "zb-normal-fg" +"ui.background" = { bg = "bg" } +"ui.menu" = { fg = "#9f9f9f", bg = "uibg" } +"ui.menu.selected" = { fg = "#d0d0a0", bg = "#242424", modifiers = ["bold"] } +"ui.linenr" = { fg = "#9fafaf", bg = "#262626"} +"ui.linenr.selected" = { modifiers = ["bold"]} +"ui.popup" = { bg = "uibg" } +"ui.selection" = { bg = "#304a3d" } +"ui.selection.primary" = { bg = "#2f2f2f" } +"comment" = { fg = "comment" } +"comment.block.documentation" = { fg = "comment", modifiers = ["bold"] } +"comment.line.documentation" = { fg = "comment", modifiers = ["bold"] } +"ui.virtual.inlay-hint" = { fg = "#9f9f9f" } +"ui.statusline" = { bg = "statusbg", fg = "#ccdc90" } +"ui.statusline.inactive" = { fg = '#2e3330', bg = '#88b090' } +"ui.cursor" = { fg = "#000d18", bg = "#8faf9f", modifiers = ["bold"] } +"ui.text" = { fg = "normal"} +"operator" = { fg = "#f0efd0" , modifiers = []} +"variable" = "normal" +"variable.builtin" = {fg = "constant", modifiers = ["bold"]} +"constant.numeric" = "numeric" +"constant" = { fg = "constant", modifiers = ["bold"] } +"type" = { fg = "#dfdfbf", modifiers = ["bold"] } +"ui.cursor.match" = { fg = "#343434", bg = "#284f28", modifiers = ["bold"] } +"string" = "#cc9393" +"variable.other.member" = "#efef8f" +"constant.character.escape" = { fg = "#dca3a3", modifiers = ["bold"]} +"function" = "#efef8f" +"function.macro" = { fg = "#ffcfaf", modifiers = ["bold"] } +"special" = "#cfbfaf" +"keyword" = { fg = "#f0dfaf", modifiers = ["bold"]} +"keyword.storage-class" = { fg = "#c3bf9f", modifiers = ["bold"]} +"label" = { fg = "#dfcfaf", modifiers = ["underlined"] } +"ui.help" = { fg = "white", bg = "black" } +"ui.virtual.ruler" = { bg = "#484848" } +"ui.virtual.whitespace" = { fg = "#5b605e", modifiers = ["bold"]} -"ui.background" = { bg = "zb-normal-bg" } -# "ui.background.separator" -"ui.cursor" = { fg = "zb-cursor-fg", bg = "zb-cursor-bg", modifiers = ["bold"] } -# "ui.cursor.normal" -# "ui.cursor.insert" -# "ui.cursor.select" -"ui.cursor.match" = { fg = "zb-matchparen-fg", bg = "zb-matchparen-bg", modifiers = ["bold"] } -# "ui.cursor.primary" -# "ui.cursor.primary.normal" -# "ui.cursor.primary.insert" -# "ui.cursor.primary.select" -# "ui.debug.breakpoint" -# "ui.debug.active" -"ui.gutter" = { bg = "zb-linenr-bg" } -# ui.gutter.selected Gutter for the line the cursor is on -"ui.linenr" = { fg = "zb-linenr-fg", bg = "zb-linenr-bg" } -"ui.linenr.selected" = { fg = "zb-cursorlinenr-fg", bg = "zb-cursorlinenr-bg", modifiers = ["bold"] } -"ui.statusline" = { bg = "zb-statusline-fg", fg = "zb-statusline-bg", modifiers = ["bold"] } -"ui.statusline.inactive" = { bg = "zb-statuslinenc-fg", fg = "zb-statuslinenc-bg", modifiers = [] } -# "ui.statusline.normal" -# "ui.statusline.insert" -# "ui.statusline.select" -# "ui.statusline.separator" -# "ui.bufferline" -# "ui.bufferline.active" -# "ui.bufferline.background" -"ui.popup" = { fg = "zb-pmenu-fg", bg = "zb-pmenu-bg" } -# "ui.popup.info" -# "ui.picker.header" -# "ui.picker.header.column" -# "ui.picker.header.column.active" -# "ui.window" = "zb-lineno" -"ui.help" = { fg = "zb-pmenu-fg", bg = "zb-pmenu-bg" } -"ui.text" = "zb-normal-fg" -"ui.text.focus" = { modifiers = ["bold"] } -# "ui.text.inactive" -"ui.text.info" = { fg = "zb-pmenu-fg", bg = "zb-pmenu-bg" } -"ui.virtual.ruler" = { bg = "zb-colorcolumn-bg" } -"ui.virtual.whitespace" = { fg = "zb-nontext-fg", modifiers = ["bold"] } -"ui.virtual.indent-guide" = { fg = "zb-colorcolumn-bg" } -# "ui.virtual.inlay-hint" -# "ui.virtual.inlay-hint.parameter" -# "ui.virtual.inlay-hint.type" -# "ui.virtual.wrap" -"ui.virtual.jump-label" = { modifiers = ["bold"] } -"ui.menu" = { fg = "zb-pmenu-fg", bg = "zb-pmenu-bg" } -"ui.menu.selected" = { fg = "zb-pmenusel-fg", bg = "zb-pmenusel-bg", modifiers = ["bold"] } -# "ui.menu.scroll" -"ui.selection" = { bg = "#373737" } -"ui.selection.primary" = { bg = "zb-visual-bg" } -# "ui.highlight" -# "ui.highlight.frameline" -"ui.cursorline.primary" = { bg = "zb-cursorline-bg" } -# "ui.cursorline.secondary" -"ui.cursorcolumn.primary" = { bg = "zb-cursorcolumn-bg" } -# "ui.cursorcolumn.secondary" -"warning" = { fg = "zb-error-fg", modifiers = ["bold"] } -"error" = { fg = "zb-error-fg", modifiers = ["bold"] } -"info" = { fg = "zb-todo-fg", modifiers = ["bold"] } -"hint" = { fg = "zb-todo-fg", modifiers = ["bold"] } -# "diagnostic" -"diagnostic.hint" = { fg = "zb-todo-fg", bg = "zb-todo-bg", modifiers = ["bold"] } -"diagnostic.info" = { fg = "zb-todo-fg", bg = "zb-todo-bg", modifiers = ["bold"] } -"diagnostic.warning" = { fg = "zb-error-fg", bg = "zb-error-bg", modifiers = ["bold"] } -"diagnostic.error" = { fg = "zb-error-fg", bg = "zb-error-bg", modifiers = ["bold"] } -"diagnostic.unnecessary" = { fg = "zb-todo-fg", bg = "zb-todo-bg", modifiers = ["bold"] } -"diagnostic.deprecated"= { fg = "zb-todo-fg", bg = "zb-todo-bg", modifiers = ["bold"] } +"punctuation.delimiter" = "#8f8f8f" -[palette] -"zb-boolean-fg" = "#dca3a3" -"zb-character-fg" = "#dca3a3" # gui=bold -"zb-comment-fg" = "#7f9f7f" -"zb-conditional-fg" = "#f0dfaf" # gui=bold -"zb-constant-fg" = "#dca3a3" # gui=bold -"zb-cursor-fg" = "#000d18" -"zb-cursor-bg" = "#8faf9f" # gui=bold -"zb-debug-fg" = "#bca3a3" # gui=bold -"zb-define-fg" = "#ffcfaf" # gui=bold -"zb-delimiter-fg" = "#8f8f8f" -"zb-diffadd-fg" = "#709080" -"zb-diffadd-bg" = "#313c36" # gui=bold -"zb-diffchange-bg" = "#333333" -"zb-diffdelete-fg" = "#333333" -"zb-diffdelete-bg" = "#464646" -"zb-difftext-fg" = "#ecbcbc" -"zb-difftext-bg" = "#41363c" # gui=bold -"zb-directory-fg" = "#9fafaf" # gui=bold -"zb-errormsg-fg" = "#80d4aa" -"zb-errormsg-bg" = "#2f2f2f" # gui=bold -"zb-exception-fg" = "#c3bf9f" # gui=bold -"zb-float-fg" = "#c0bed1" -# "zb-foldcolumn-fg" = "#93b3a3" -# "zb-foldcolumn-bg" = "#3f4040" -# "zb-folded-fg" = "#93b3a3" -# "zb-folded-bg" = "#3f4040" -"zb-function-fg" = "#efef8f" -"zb-identifier-fg" = "#efdcbc" -"zb-incsearch-fg" = "#f8f893" -"zb-incsearch-bg" = "#385f38" -"zb-keyword-fg" = "#f0dfaf" # gui=bold -"zb-macro-fg" = "#ffcfaf" # gui=bold -"zb-modemsg-fg" = "#ffcfaf" # gui=none -"zb-moremsg-fg" = "#ffffff" # gui=bold -"zb-number-fg" = "#8cd0d3" -"zb-operator-fg" = "#f0efd0" -"zb-pmenusbar-fg" = "#000000" -"zb-pmenusbar-bg" = "#2e3330" -"zb-pmenuthumb-fg" = "#040404" -"zb-pmenuthumb-bg" = "#a0afa0" -"zb-precondit-fg" = "#dfaf8f" # gui=bold -"zb-preproc-fg" = "#ffcfaf" # gui=bold -"zb-question-fg" = "#ffffff" # gui=bold -"zb-repeat-fg" = "#ffd7a7" # gui=bold -"zb-search-fg" = "#ffffe0" -"zb-search-bg" = "#284f28" -"zb-signcolumn-fg" = "#9fafaf" # gui=bold -"zb-specialchar-fg" = "#dca3a3" # gui=bold -"zb-specialcomment-fg" = "#82a282" # gui=bold -"zb-special-fg" = "#cfbfaf" -"zb-specialkey-fg" = "#9ece9e" -"zb-statement-fg" = "#e3ceab" # gui=none -"zb-statusline-fg" = "#313633" -"zb-statusline-bg" = "#ccdc90" -"zb-statuslinenc-fg" = "#2e3330" -"zb-statuslinenc-bg" = "#88b090" -"zb-storageclass-fg" = "#c3bf9f" # gui=bold -"zb-string-fg" = "#cc9393" -"zb-structure-fg" = "#efefaf" # gui=bold -"zb-tag-fg" = "#e89393" # gui=bold -"zb-title-fg" = "#efefef" # gui=bold -"zb-todo-fg" = "#dfdfdf" # gui=bold -"zb-todo-bg" = "#575757" -"zb-typedef-fg" = "#dfe4cf" # gui=bold -"zb-type-fg" = "#dfdfbf" # gui=bold -"zb-underlined-fg" = "#dcdccc" # gui=underline -"zb-vertsplit-fg" = "#2e3330" -"zb-vertsplit-bg" = "#688060" -# "zb-visualnos-fg" = "#333333" -# "zb-visualnos-bg" = "#f18c96" # gui=bold,underline -"zb-warningmsg-fg" = "#ffffff" -"zb-warningmsg-bg" = "#333333" # gui=bold -"zb-wildmenu-fg" = "#cbecd0" -"zb-wildmenu-bg" = "#2c302d" # gui=underline +"ui.virtual.indent-guide" = "#4f4f4f" + +"diff.plus" = {fg = "#709080"} +"diff.delta" = {fg = "#464646"} +"diff.minus" = {fg = "#cc9393"} -"zb-normal-fg" = "#dcdccc" -"zb-normal-bg" = "#3f3f3f" -"zb-conceal-fg" = "#8f8f8f" -"zb-conceal-bg" = "#484848" -"zb-colorcolumn-bg" = "#484848" -"zb-cursorline-bg" = "#434443" -"zb-cursorlinenr-fg" = "#d2d39b" -"zb-cursorlinenr-bg" = "#262626" -"zb-cursorcolumn-bg" = "#4f4f4f" -"zb-foldcolumn-bg" = "#333333" -"zb-folded-bg" = "#333333" -"zb-linenr-fg" = "#9fafaf" -"zb-linenr-bg" = "#262626" -"zb-nontext-fg" = "#5b605e" # gui=bold -"zb-pmenu-fg" = "#9f9f9f" -"zb-pmenu-bg" = "#2c2e2e" -"zb-pmenusel-fg" = "#d0d0a0" -"zb-pmenusel-bg" = "#242424" # gui=bold -"zb-matchparen-fg" = "#ffffe0" -"zb-matchparen-bg" = "#284f28" # gui=bold -"zb-signcolumn-bg" = "#343434" -"zb-specialkey-bg" = "#444444" -"zb-tabline-fg" = "#d0d0b8" -"zb-tabline-bg" = "#222222" # gui=none -"zb-tablinesel-fg" = "#f0f0b0" -"zb-tablinesel-bg" = "#333333" # gui=bold -"zb-tablinefill-fg" = "#dccdcc" -"zb-tablinefill-bg" = "#101010" # gui=none -"zb-visual-bg" = "#2f2f2f" -"zb-visualnos-bg" = "#2f2f2f" -"zb-error-fg" = "#e37170" -"zb-error-bg" = "#3d3535" # gui=bold -"zb-include-fg" = "#dfaf8f" # gui=bold -"zb-label-fg" = "#dfcfaf" # gui=underline +"diagnostic" = {bg = "statusbg"} +"diagnostic.error" = { fg = "errorfg", bg = "errorbg"} +"diagnostic.unnecessary" = { modifiers = ["dim"] } +"diagnostic.deprecated" = { modifiers = ["crossed_out"] } +"ui.gutter" = { bg = "statusbg" } +"hint" = {fg = "numeric", bg = "statusbg"} +"warning" = "numeric" +"error" = "errorfg" + +[palette] +comment = "#7f9f7f" +bg = "#3f3f3f" +uibg = "#2c2e2e" +constant = "#dca3a3" +normal = "#dcdccc" +todo = "#dfdfdf" +errorfg = "#e37170" +errorbg = "#3d3535" +statusbg = "#313633" +numeric = "#8cd0d3" diff --git a/runtime/tutor b/runtime/tutor index 30c0f102..54a4dde2 100644 --- a/runtime/tutor +++ b/runtime/tutor @@ -337,7 +337,7 @@ 1. Move the cursor to the line marked '-->' below. 2. Type 2w to move 2 words forward. 3. Type 3e to move to the end of the third word forward. - 4. Type 2b to move 2 words backwards. + 4. Type 2b to move 2 words backwards 5. Try the above with different numbers. --> This is just a line with words you can move around in. @@ -755,7 +755,7 @@ 1. Move the cursor to the line marked '-->' below. 2. Type w to select "watermelons" and then y to yank it. 3. Select "oranges" with w. - 4. Type R to replace "oranges" with "watermelons". + 4. Type R to replace "oranges" with "watermelons" --> I like watermelons because oranges are refreshing. diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 00000000..74c6fc7a --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.82.0" +components = ["rustfmt", "rust-src", "clippy"] |