diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a1ef53bdf353..21bb51b2ef6d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,6 +8,9 @@ on: schedule: - cron: "00 01 * * *" +env: + MSRV: "1.76" + jobs: check: name: Check (msrv) @@ -18,7 +21,9 @@ jobs: uses: actions/checkout@v4 - name: Install MSRV toolchain - uses: dtolnay/rust-toolchain@1.76 + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.MSRV }} - uses: Swatinem/rust-cache@v2 with: @@ -39,7 +44,9 @@ jobs: uses: actions/checkout@v4 - name: Install MSRV toolchain - uses: dtolnay/rust-toolchain@1.76 + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.MSRV }} - uses: Swatinem/rust-cache@v2 with: @@ -71,8 +78,9 @@ jobs: uses: actions/checkout@v4 - name: Install MSRV toolchain - uses: dtolnay/rust-toolchain@1.76 + uses: dtolnay/rust-toolchain@master with: + toolchain: ${{ env.MSRV }} components: rustfmt, clippy - uses: Swatinem/rust-cache@v2 @@ -99,7 +107,9 @@ jobs: uses: actions/checkout@v4 - name: Install MSRV toolchain - uses: dtolnay/rust-toolchain@1.76 + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.MSRV }} - uses: Swatinem/rust-cache@v2 with: diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 39dc089825a1..d5ccb0be86aa 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -16,8 +16,8 @@ jobs: - name: Setup mdBook uses: peaceiris/actions-mdbook@v2 with: - mdbook-version: 'latest' - # mdbook-version: '0.4.8' + # mdbook-version: 'latest' + mdbook-version: '0.4.43' - run: mdbook build book diff --git a/Cargo.lock b/Cargo.lock index 6cc73ebf0a25..9cae3e3edaba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -136,9 +136,9 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] name = "cc" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" +checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" dependencies = [ "shlex", ] @@ -479,9 +479,9 @@ checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "gix" -version = "0.67.0" +version = "0.68.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d3e78ddac368d3e3bfbc2862bc2aafa3d89f1b15fed898d9761e1ec6f3f17f" +checksum = "b04c66359b5e17f92395abc433861df0edf48f39f3f590818d1d7217327dd6a1" dependencies = [ "gix-actor", "gix-attributes", @@ -522,28 +522,28 @@ dependencies = [ "gix-worktree", "once_cell", "smallvec", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-actor" -version = "0.33.0" +version = "0.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59226ef06661c756e664b46b1d3b2c198f6adc5407a484c086d0171108a70027" +checksum = "32b24171f514cef7bb4dfb72a0b06dacf609b33ba8ad2489d4c4559a03b7afb3" dependencies = [ "bstr", "gix-date", "gix-utils", "itoa", - "thiserror 1.0.69", + "thiserror 2.0.3", "winnow", ] [[package]] name = "gix-attributes" -version = "0.23.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31a102d201ef0e5a848458a82292581e7641e52f0f52e693b6cbdd05a652c029" +checksum = "ddf9bf852194c0edfe699a2d36422d2c1f28f73b7c6d446c3f0ccd3ba232cadc" dependencies = [ "bstr", "gix-glob", @@ -552,33 +552,33 @@ dependencies = [ "gix-trace", "kstring", "smallvec", - "thiserror 1.0.69", + "thiserror 2.0.3", "unicode-bom", ] [[package]] name = "gix-bitmap" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f78312288bd02052be5dbc2ecbc342c9f4eb791986d86c0a5c06b92dc72efa" +checksum = "d48b897b4bbc881aea994b4a5bbb340a04979d7be9089791304e04a9fbc66b53" dependencies = [ - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-chunk" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28b58ba04f0c004722344390af9dbc85888fbb84be1981afb934da4114d4cf" +checksum = "c6ffbeb3a5c0b8b84c3fe4133a6f8c82fa962f4caefe8d0762eced025d3eb4f7" dependencies = [ - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-command" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c201d2b9e9cce2365a6638fd0a966f751ed92d74be5c0727ac331e6a29ef5846" +checksum = "6d7d6b8f3a64453fd7e8191eb80b351eb7ac0839b40a1237cd2c137d5079fe53" dependencies = [ "bstr", "gix-path", @@ -588,23 +588,23 @@ dependencies = [ [[package]] name = "gix-commitgraph" -version = "0.25.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41db900b189e62dc61575f06fdf1a3b6901d264a99be9d32b286af6b2e3984e1" +checksum = "a8da6591a7868fb2b6dabddea6b09988b0b05e0213f938dbaa11a03dd7a48d85" dependencies = [ "bstr", "gix-chunk", "gix-features", "gix-hash", "memmap2", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-config" -version = "0.41.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bedd1bf1c7b994be9d57207e8e0de79016c05e2e8701d3015da906e65ac445e" +checksum = "6649b406ca1f99cb148959cf00468b231f07950f8ec438cc0903cda563606f19" dependencies = [ "bstr", "gix-config-value", @@ -616,41 +616,41 @@ dependencies = [ "memchr", "once_cell", "smallvec", - "thiserror 1.0.69", + "thiserror 2.0.3", "unicode-bom", "winnow", ] [[package]] name = "gix-config-value" -version = "0.14.9" +version = "0.14.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3de3fdca9c75fa4b83a76583d265fa49b1de6b088ebcd210749c24ceeb74660" +checksum = "49aaeef5d98390a3bcf9dbc6440b520b793d1bf3ed99317dc407b02be995b28e" dependencies = [ "bitflags", "bstr", "gix-path", "libc", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-date" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d10d543ac13c97292a15e8e8b7889cd006faf739777437ed95362504b8fe81a0" +checksum = "691142b1a34d18e8ed6e6114bc1a2736516c5ad60ef3aa9bd1b694886e3ca92d" dependencies = [ "bstr", "itoa", "jiff", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-diff" -version = "0.47.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9850fd0c15af113db6f9e130d13091ba0d3754e570a2afdff9e2f3043da260e" +checksum = "a327be31a392144b60ab0b1c863362c32a1c8f7effdfa2141d5d5b6b916ef3bf" dependencies = [ "bstr", "gix-command", @@ -664,14 +664,14 @@ dependencies = [ "gix-traverse", "gix-worktree", "imara-diff", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-dir" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbf6c29bf17baf3996d4925fad5e10c1a12eac9b3a0d8475d89292e0e5ba34a3" +checksum = "acd6a0618958f9cce78a32724f8e06c4f4a57ca7080f645736d53676dc9b4db9" dependencies = [ "bstr", "gix-discover", @@ -684,14 +684,14 @@ dependencies = [ "gix-trace", "gix-utils", "gix-worktree", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-discover" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c522e31f458f50af09dfb014e10873c5378f702f8049c96f508989aad59671f6" +checksum = "83bf6dfa4e266a4a9becb4d18fc801f92c3f7cc6c433dd86fdadbcf315ffb6ef" dependencies = [ "bstr", "dunce", @@ -700,14 +700,14 @@ dependencies = [ "gix-path", "gix-ref", "gix-sec", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-features" -version = "0.39.0" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e0eb9efdf96c35c0bed7596d1bef2d4ce6360a1d09738001f9d3e402aa7ba3e" +checksum = "7d85d673f2e022a340dba4713bed77ef2cf4cd737d2f3e0f159d45e0935fd81f" dependencies = [ "crc32fast", "flate2", @@ -718,15 +718,15 @@ dependencies = [ "once_cell", "prodash", "sha1_smol", - "thiserror 1.0.69", + "thiserror 2.0.3", "walkdir", ] [[package]] name = "gix-filter" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b37f82359a4485770ed8993ae715ced1bf674f2a63e45f5a0786d38310665ea" +checksum = "5108cc58d58b27df10ac4de7f31b2eb96d588a33e5eba23739b865f5d8db7995" dependencies = [ "bstr", "encoding_rs", @@ -740,7 +740,7 @@ dependencies = [ "gix-trace", "gix-utils", "smallvec", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] @@ -756,9 +756,9 @@ dependencies = [ [[package]] name = "gix-glob" -version = "0.17.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "254b5101cf7facc00d9b5ff564cf46302ca76695cca23d33bc958a707b6fc857" +checksum = "aaf69a6bec0a3581567484bf99a4003afcaf6c469fd4214352517ea355cf3435" dependencies = [ "bitflags", "bstr", @@ -768,12 +768,12 @@ dependencies = [ [[package]] name = "gix-hash" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "952c3a29f1bc1007cc901abce7479943abfa42016db089de33d0a4fa3c85bfe8" +checksum = "0b5eccc17194ed0e67d49285e4853307e4147e95407f91c1c3e4a13ba9f4e4ce" dependencies = [ "faster-hex", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] @@ -789,9 +789,9 @@ dependencies = [ [[package]] name = "gix-ignore" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba55a9b582dc26a639875497615959a8127ac5c37b2426dc50f037fada33a4b7" +checksum = "b6b1fb24d2a4af0aa7438e2771d60c14a80cf2c9bd55c29cf1712b841f05bb8a" dependencies = [ "bstr", "gix-glob", @@ -802,9 +802,9 @@ dependencies = [ [[package]] name = "gix-index" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27619009ca1ea33fd885041273f5fa5a09163a5c1d22a913b28d7b985e66fe29" +checksum = "270645fd20556b64c8ffa1540d921b281e6994413a0ca068596f97e9367a257a" dependencies = [ "bitflags", "bstr", @@ -825,7 +825,7 @@ dependencies = [ "memmap2", "rustix", "smallvec", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] @@ -841,9 +841,9 @@ dependencies = [ [[package]] name = "gix-object" -version = "0.45.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a77b6e7753d298553d9ae8b1744924481e7a49170983938bb578dccfbc6fc1a" +checksum = "65d93e2bbfa83a307e47f45e45de7b6c04d7375a8bd5907b215f4bf45237d879" dependencies = [ "bstr", "gix-actor", @@ -855,15 +855,15 @@ dependencies = [ "gix-validate", "itoa", "smallvec", - "thiserror 1.0.69", + "thiserror 2.0.3", "winnow", ] [[package]] name = "gix-odb" -version = "0.64.0" +version = "0.65.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb86aadf7f1b2f980601b4fc94309706f9700f8008f935dc512d556c9e60f61" +checksum = "93bed6e1b577c25a6bb8e6ecbf4df525f29a671ddf5f2221821a56a8dbeec4e3" dependencies = [ "arc-swap", "gix-date", @@ -877,14 +877,14 @@ dependencies = [ "gix-quote", "parking_lot", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-pack" -version = "0.54.0" +version = "0.55.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "363e6e59a855ba243672408139db68e2478126cdcfeabb420777df4a1f20026b" +checksum = "9b91fec04d359544fecbb8e85117ec746fbaa9046ebafcefb58cb74f20dc76d4" dependencies = [ "clru", "gix-chunk", @@ -895,39 +895,39 @@ dependencies = [ "gix-path", "memmap2", "smallvec", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-packetline-blocking" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "decace940e8ba8e29d29b73b843a6cbae67503887f3e5fb7e688d0f4f6ee0757" +checksum = "ce9004ce1bc00fd538b11c1ec8141a1558fb3af3d2b7ac1ac5c41881f9e42d2a" dependencies = [ "bstr", "faster-hex", "gix-trace", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-path" -version = "0.10.12" +version = "0.10.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c04e5a94fdb56b1e91eb7df2658ad16832428b8eeda24ff1a0f0288de2bce554" +checksum = "afc292ef1a51e340aeb0e720800338c805975724c1dfbd243185452efd8645b7" dependencies = [ "bstr", "gix-trace", "home", "once_cell", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-pathspec" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70f02bf7625dbf15bf9fedbeace2ac1ce1c5177806bdbc24c441d664c75c00e4" +checksum = "4c472dfbe4a4e96fcf7efddcd4771c9037bb4fdea2faaabf2f4888210c75b81e" dependencies = [ "bitflags", "bstr", @@ -935,25 +935,25 @@ dependencies = [ "gix-config-value", "gix-glob", "gix-path", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-quote" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f89f9a1525dcfd9639e282ea939f5ab0d09d93cf2b90c1fc6104f1b9582a8e49" +checksum = "64a1e282216ec2ab2816cd57e6ed88f8009e634aec47562883c05ac8a7009a63" dependencies = [ "bstr", "gix-utils", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-ref" -version = "0.48.0" +version = "0.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47385e71fa2d9da8c35e642ef4648808ddf0a52bc93425879088c706dfeaea2" +checksum = "1eae462723686272a58f49501015ef7c0d67c3e042c20049d8dd9c7eff92efde" dependencies = [ "gix-actor", "gix-features", @@ -966,29 +966,29 @@ dependencies = [ "gix-utils", "gix-validate", "memmap2", - "thiserror 1.0.69", + "thiserror 2.0.3", "winnow", ] [[package]] name = "gix-refspec" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0022038a09d80d9abf773be8efcbb502868d97f6972b8633bfb52ab6edaac442" +checksum = "00c056bb747868c7eb0aeb352c9f9181ab8ca3d0a2550f16470803500c6c413d" dependencies = [ "bstr", "gix-hash", "gix-revision", "gix-validate", "smallvec", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-revision" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee8eb4088fece3562af4a5d751e069f90e93345524ad730512185234c4b55f1" +checksum = "44488e0380847967bc3e3cacd8b22652e02ea1eb58afb60edd91847695cd2d8d" dependencies = [ "bstr", "gix-commitgraph", @@ -996,14 +996,14 @@ dependencies = [ "gix-hash", "gix-object", "gix-revwalk", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-revwalk" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c9a9496da98d36ff19063a8576bf09a87425583b709a56dc5594fffa9d39b2" +checksum = "510026fc32f456f8f067d8f37c34088b97a36b2229d88a6a5023ef179fcb109d" dependencies = [ "gix-commitgraph", "gix-date", @@ -1011,14 +1011,14 @@ dependencies = [ "gix-hashtable", "gix-object", "smallvec", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-sec" -version = "0.10.9" +version = "0.10.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2007538eda296445c07949cf04f4a767307d887184d6b3e83e2d636533ddc6e" +checksum = "a8b876ef997a955397809a2ec398d6a45b7a55b4918f2446344330f778d14fd6" dependencies = [ "bitflags", "gix-path", @@ -1028,9 +1028,9 @@ dependencies = [ [[package]] name = "gix-status" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57414886e750161b4c86d8bca6b2d15bcc87f37ddc46684bb05cebbd29390543" +checksum = "201396192ee4c4dd9e8a84fed4b0d2b33d639fca815fb99b0f653dfeddf38585" dependencies = [ "bstr", "filetime", @@ -1046,14 +1046,14 @@ dependencies = [ "gix-pathspec", "gix-worktree", "portable-atomic", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-submodule" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed099621873cd36c580fc822176a32a7e50fef15a5c2ed81aaa087296f0497a" +checksum = "a2455f8c0fcb6ebe2a6e83c8f522d30615d763eb2ef7a23c7d929f9476e89f5c" dependencies = [ "bstr", "gix-config", @@ -1061,7 +1061,7 @@ dependencies = [ "gix-pathspec", "gix-refspec", "gix-url", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] @@ -1086,9 +1086,9 @@ checksum = "04bdde120c29f1fc23a24d3e115aeeea3d60d8e65bab92cc5f9d90d9302eb952" [[package]] name = "gix-traverse" -version = "0.42.0" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f20f1b13cc4fa6ba92b24e6aa0c2fb6a34beb4458ef88c6300212db504e818df" +checksum = "3ff2ec9f779680f795363db1c563168b32b8d6728ec58564c628e85c92d29faf" dependencies = [ "bitflags", "gix-commitgraph", @@ -1098,19 +1098,19 @@ dependencies = [ "gix-object", "gix-revwalk", "smallvec", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-url" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e7c297c3265015c133a2c02199610b6e1373a09dc4be057d0c1b5285737f06" +checksum = "e09f97db3618fb8e473d7d97e77296b50aaee0ddcd6a867f07443e3e87391099" dependencies = [ "bstr", "gix-features", "gix-path", - "thiserror 1.0.69", + "thiserror 2.0.3", "url", ] @@ -1127,19 +1127,19 @@ dependencies = [ [[package]] name = "gix-validate" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e187b263461bc36cea17650141567753bc6207d036cedd1de6e81a52f277ff68" +checksum = "cd520d09f9f585b34b32aba1d0b36ada89ab7fefb54a8ca3fe37fc482a750937" dependencies = [ "bstr", - "thiserror 1.0.69", + "thiserror 2.0.3", ] [[package]] name = "gix-worktree" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d345e5b523550fe4fa0e912bf957de752011ccfc87451968fda1b624318f29c" +checksum = "756dbbe15188fa22540d5eab941f8f9cf511a5364d5aec34c88083c09f4bea13" dependencies = [ "bstr", "gix-attributes", @@ -1757,15 +1757,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.164" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", "windows-targets 0.52.6", @@ -2084,9 +2084,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -2612,9 +2612,9 @@ checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] name = "url" -version = "2.5.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", diff --git a/book/src/commands.md b/book/src/commands.md index 047a30a91c83..ee507276b51f 100644 --- a/book/src/commands.md +++ b/book/src/commands.md @@ -1,5 +1,16 @@ # Commands -Command mode can be activated by pressing `:`. The built-in commands are: +- [Typable commands](#typable-commands) +- [Static commands](#static-commands) + +## Typable commands + +Typable commands are used from command mode and may take arguments. Command mode can be activated by pressing `:`. The built-in typable commands are: {{#include ./generated/typable-cmd.md}} + +## Static Commands + +Static commands take no arguments and can be bound to keys. Static commands can also be executed from the command picker (`?`). The built-in static commands are: + +{{#include ./generated/static-cmd.md}} diff --git a/book/src/editor.md b/book/src/editor.md index 06f8800c2538..1f70c5b5b68e 100644 --- a/book/src/editor.md +++ b/book/src/editor.md @@ -31,6 +31,7 @@ | `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` | | `gutters` | Gutters to display: Available are `diagnostics` and `diff` and `line-numbers` and `spacer`, note that `diagnostics` also includes other features like breakpoints, 1-width padding will be inserted if gutters is non-empty | `["diagnostics", "spacer", "line-numbers", "spacer", "diff"]` | | `auto-completion` | Enable automatic pop up of auto-completion | `true` | | `path-completion` | Enable filepath completion. Show files and directories if an existing path at the cursor was recognized, either absolute or relative to the current opened document or current working directory (if the buffer is not yet saved). Defaults to true. | `true` | @@ -58,7 +59,7 @@ ### `[editor.clipboard-provider]` Section -Helix can be configured wither to use a builtin clipboard configuration or to use +Helix can be configured either to use a builtin clipboard configuration or to use a provided command. For instance, setting it to use OSC 52 termcodes, the configuration would be: @@ -151,7 +152,7 @@ The following statusline elements can be configured: [^1]: By default, a progress spinner is shown in the statusline beside the file path. -[^2]: You may also have to activate them in the LSP config for them to appear, not just in Helix. Inlay hints in Helix are still being improved on and may be a little bit laggy/janky under some circumstances. Please report any bugs you see so we can fix them! +[^2]: You may also have to activate them in the language server config for them to appear, not just in Helix. Inlay hints in Helix are still being improved on and may be a little bit laggy/janky under some circumstances. Please report any bugs you see so we can fix them! ### `[editor.cursor-shape]` Section diff --git a/book/src/generated/lang-support.md b/book/src/generated/lang-support.md index d85cebf06872..0c3bf78e336d 100644 --- a/book/src/generated/lang-support.md +++ b/book/src/generated/lang-support.md @@ -1,4 +1,4 @@ -| Language | Syntax Highlighting | Treesitter Textobjects | Auto Indent | Default LSP | +| Language | Syntax Highlighting | Treesitter Textobjects | Auto Indent | Default language servers | | --- | --- | --- | --- | --- | | ada | ✓ | ✓ | | `ada_language_server` | | adl | ✓ | ✓ | ✓ | | @@ -78,6 +78,7 @@ | gomod | ✓ | | | `gopls` | | gotmpl | ✓ | | | `gopls` | | gowork | ✓ | | | `gopls` | +| gpr | ✓ | | | `ada_language_server` | | graphql | ✓ | ✓ | | `graphql-lsp` | | groovy | ✓ | | | | | gts | ✓ | ✓ | ✓ | `typescript-language-server`, `vscode-eslint-language-server`, `ember-language-server` | @@ -133,7 +134,7 @@ | mermaid | ✓ | | | | | meson | ✓ | | ✓ | `mesonlsp` | | mint | | | | `mint` | -| mojo | ✓ | ✓ | ✓ | `mojo-lsp-server` | +| mojo | ✓ | ✓ | ✓ | `magic` | | move | ✓ | | | | | msbuild | ✓ | | ✓ | | | nasm | ✓ | ✓ | | | @@ -207,6 +208,7 @@ | tact | ✓ | ✓ | ✓ | | | task | ✓ | | | | | tcl | ✓ | | ✓ | | +| teal | ✓ | | | | | templ | ✓ | | | `templ` | | textproto | ✓ | ✓ | ✓ | | | tfvars | ✓ | | ✓ | `terraform-ls` | @@ -224,6 +226,7 @@ | uxntal | ✓ | | | | | v | ✓ | ✓ | ✓ | `v-analyzer` | | vala | ✓ | ✓ | | `vala-language-server` | +| vento | ✓ | | | | | verilog | ✓ | ✓ | | `svlangserver` | | vhdl | ✓ | | | `vhdl_ls` | | vhs | ✓ | | | | diff --git a/book/src/generated/static-cmd.md b/book/src/generated/static-cmd.md new file mode 100644 index 000000000000..4d838a10999d --- /dev/null +++ b/book/src/generated/static-cmd.md @@ -0,0 +1,294 @@ +| Name | Description | Default keybinds | +| --- | --- | --- | +| `no_op` | Do nothing | | +| `move_char_left` | Move left | normal: `` h ``, `` ``, insert: `` `` | +| `move_char_right` | Move right | normal: `` l ``, `` ``, insert: `` `` | +| `move_line_up` | Move up | normal: `` gk `` | +| `move_line_down` | Move down | normal: `` gj `` | +| `move_visual_line_up` | Move up | normal: `` k ``, `` ``, insert: `` `` | +| `move_visual_line_down` | Move down | normal: `` j ``, `` ``, insert: `` `` | +| `extend_char_left` | Extend left | select: `` h ``, `` `` | +| `extend_char_right` | Extend right | select: `` l ``, `` `` | +| `extend_line_up` | Extend up | select: `` gk `` | +| `extend_line_down` | Extend down | select: `` gj `` | +| `extend_visual_line_up` | Extend up | select: `` k ``, `` `` | +| `extend_visual_line_down` | Extend down | select: `` j ``, `` `` | +| `copy_selection_on_next_line` | Copy selection on next line | normal: `` C ``, select: `` C `` | +| `copy_selection_on_prev_line` | Copy selection on previous line | normal: `` ``, select: `` `` | +| `move_next_word_start` | Move to start of next word | normal: `` w `` | +| `move_prev_word_start` | Move to start of previous word | normal: `` b `` | +| `move_next_word_end` | Move to end of next word | normal: `` e `` | +| `move_prev_word_end` | Move to end of previous word | | +| `move_next_long_word_start` | Move to start of next long word | normal: `` W `` | +| `move_prev_long_word_start` | Move to start of previous long word | normal: `` B `` | +| `move_next_long_word_end` | Move to end of next long word | normal: `` E `` | +| `move_prev_long_word_end` | Move to end of previous long word | | +| `move_next_sub_word_start` | Move to start of next sub word | | +| `move_prev_sub_word_start` | Move to start of previous sub word | | +| `move_next_sub_word_end` | Move to end of next sub word | | +| `move_prev_sub_word_end` | Move to end of previous sub word | | +| `move_parent_node_end` | Move to end of the parent node | normal: `` `` | +| `move_parent_node_start` | Move to beginning of the parent node | normal: `` `` | +| `extend_next_word_start` | Extend to start of next word | select: `` w `` | +| `extend_prev_word_start` | Extend to start of previous word | select: `` b `` | +| `extend_next_word_end` | Extend to end of next word | select: `` e `` | +| `extend_prev_word_end` | Extend to end of previous word | | +| `extend_next_long_word_start` | Extend to start of next long word | select: `` W `` | +| `extend_prev_long_word_start` | Extend to start of previous long word | select: `` B `` | +| `extend_next_long_word_end` | Extend to end of next long word | select: `` E `` | +| `extend_prev_long_word_end` | Extend to end of prev long word | | +| `extend_next_sub_word_start` | Extend to start of next sub word | | +| `extend_prev_sub_word_start` | Extend to start of previous sub word | | +| `extend_next_sub_word_end` | Extend to end of next sub word | | +| `extend_prev_sub_word_end` | Extend to end of prev sub word | | +| `extend_parent_node_end` | Extend to end of the parent node | select: `` `` | +| `extend_parent_node_start` | Extend to beginning of the parent node | select: `` `` | +| `find_till_char` | Move till next occurrence of char | normal: `` t `` | +| `find_next_char` | Move to next occurrence of char | normal: `` f `` | +| `extend_till_char` | Extend till next occurrence of char | select: `` t `` | +| `extend_next_char` | Extend to next occurrence of char | select: `` f `` | +| `till_prev_char` | Move till previous occurrence of char | normal: `` T `` | +| `find_prev_char` | Move to previous occurrence of char | normal: `` F `` | +| `extend_till_prev_char` | Extend till previous occurrence of char | select: `` T `` | +| `extend_prev_char` | Extend to previous occurrence of char | select: `` F `` | +| `repeat_last_motion` | Repeat last motion | normal: `` ``, select: `` `` | +| `replace` | Replace with new char | normal: `` r ``, select: `` r `` | +| `switch_case` | Switch (toggle) case | normal: `` ~ ``, select: `` ~ `` | +| `switch_to_uppercase` | Switch to uppercase | normal: `` ``, select: `` `` | +| `switch_to_lowercase` | Switch to lowercase | normal: `` ` ``, select: `` ` `` | +| `page_up` | Move page up | normal: `` ``, `` Z ``, `` z ``, `` ``, `` Z ``, `` z ``, select: `` ``, `` Z ``, `` z ``, `` ``, `` Z ``, `` z ``, insert: `` `` | +| `page_down` | Move page down | normal: `` ``, `` Z ``, `` z ``, `` ``, `` Z ``, `` z ``, select: `` ``, `` Z ``, `` z ``, `` ``, `` Z ``, `` z ``, insert: `` `` | +| `half_page_up` | Move half page up | | +| `half_page_down` | Move half page down | | +| `page_cursor_up` | Move page and cursor up | | +| `page_cursor_down` | Move page and cursor down | | +| `page_cursor_half_up` | Move page and cursor half up | normal: `` ``, `` Z ``, `` z ``, `` Z ``, `` z ``, select: `` ``, `` Z ``, `` z ``, `` Z ``, `` z `` | +| `page_cursor_half_down` | Move page and cursor half down | normal: `` ``, `` Z ``, `` z ``, `` Z ``, `` z ``, select: `` ``, `` Z ``, `` z ``, `` Z ``, `` z `` | +| `select_all` | Select whole document | normal: `` % ``, select: `` % `` | +| `select_regex` | Select all regex matches inside selections | normal: `` s ``, select: `` s `` | +| `split_selection` | Split selections on regex matches | normal: `` S ``, select: `` S `` | +| `split_selection_on_newline` | Split selection on newlines | normal: `` ``, select: `` `` | +| `merge_selections` | Merge selections | normal: `` ``, select: `` `` | +| `merge_consecutive_selections` | Merge consecutive selections | normal: `` ``, select: `` `` | +| `search` | Search for regex pattern | normal: `` / ``, `` Z/ ``, `` z/ ``, select: `` / ``, `` Z/ ``, `` z/ `` | +| `rsearch` | Reverse search for regex pattern | normal: `` ? ``, `` Z? ``, `` z? ``, select: `` ? ``, `` Z? ``, `` z? `` | +| `search_next` | Select next search match | normal: `` n ``, `` Zn ``, `` zn ``, select: `` Zn ``, `` zn `` | +| `search_prev` | Select previous search match | normal: `` N ``, `` ZN ``, `` zN ``, select: `` ZN ``, `` zN `` | +| `extend_search_next` | Add next search match to selection | select: `` n `` | +| `extend_search_prev` | Add previous search match to selection | select: `` N `` | +| `search_selection` | Use current selection as search pattern | normal: `` ``, select: `` `` | +| `search_selection_detect_word_boundaries` | Use current selection as the search pattern, automatically wrapping with `\b` on word boundaries | normal: `` * ``, select: `` * `` | +| `make_search_word_bounded` | Modify current search to make it word bounded | | +| `global_search` | Global search in workspace folder | normal: `` / ``, select: `` / `` | +| `extend_line` | Select current line, if already selected, extend to another line based on the anchor | | +| `extend_line_below` | Select current line, if already selected, extend to next line | normal: `` x ``, select: `` x `` | +| `extend_line_above` | Select current line, if already selected, extend to previous line | | +| `select_line_above` | Select current line, if already selected, extend or shrink line above based on the anchor | | +| `select_line_below` | Select current line, if already selected, extend or shrink line below based on the anchor | | +| `extend_to_line_bounds` | Extend selection to line bounds | normal: `` X ``, select: `` X `` | +| `shrink_to_line_bounds` | Shrink selection to line bounds | normal: `` ``, select: `` `` | +| `delete_selection` | Delete selection | normal: `` d ``, select: `` d `` | +| `delete_selection_noyank` | Delete selection without yanking | normal: `` ``, select: `` `` | +| `change_selection` | Change selection | normal: `` c ``, select: `` c `` | +| `change_selection_noyank` | Change selection without yanking | normal: `` ``, select: `` `` | +| `collapse_selection` | Collapse selection into single cursor | normal: `` ; ``, select: `` ; `` | +| `flip_selections` | Flip selection cursor and anchor | normal: `` ``, select: `` `` | +| `ensure_selections_forward` | Ensure all selections face forward | normal: `` ``, select: `` `` | +| `insert_mode` | Insert before selection | normal: `` i ``, select: `` i `` | +| `append_mode` | Append after selection | normal: `` a ``, select: `` a `` | +| `command_mode` | Enter command mode | normal: `` : ``, select: `` : `` | +| `file_picker` | Open file picker | normal: `` f ``, select: `` f `` | +| `file_picker_in_current_buffer_directory` | Open file picker at current buffer's directory | | +| `file_picker_in_current_directory` | Open file picker at current working directory | normal: `` F ``, select: `` F `` | +| `code_action` | Perform code action | normal: `` a ``, select: `` a `` | +| `buffer_picker` | Open buffer picker | normal: `` b ``, select: `` b `` | +| `jumplist_picker` | Open jumplist picker | normal: `` j ``, select: `` j `` | +| `symbol_picker` | Open symbol picker | normal: `` s ``, select: `` s `` | +| `changed_file_picker` | Open changed file picker | normal: `` g ``, select: `` g `` | +| `select_references_to_symbol_under_cursor` | Select symbol references | normal: `` h ``, select: `` h `` | +| `workspace_symbol_picker` | Open workspace symbol picker | normal: `` S ``, select: `` S `` | +| `diagnostics_picker` | Open diagnostic picker | normal: `` d ``, select: `` d `` | +| `workspace_diagnostics_picker` | Open workspace diagnostic picker | normal: `` D ``, select: `` D `` | +| `last_picker` | Open last picker | normal: `` ' ``, select: `` ' `` | +| `insert_at_line_start` | Insert at start of line | normal: `` I ``, select: `` I `` | +| `insert_at_line_end` | Insert at end of line | normal: `` A ``, select: `` A `` | +| `open_below` | Open new line below selection | normal: `` o ``, select: `` o `` | +| `open_above` | Open new line above selection | normal: `` O ``, select: `` O `` | +| `normal_mode` | Enter normal mode | normal: `` ``, select: `` v ``, insert: `` `` | +| `select_mode` | Enter selection extend mode | normal: `` v `` | +| `exit_select_mode` | Exit selection mode | select: `` `` | +| `goto_definition` | Goto definition | normal: `` gd ``, select: `` gd `` | +| `goto_declaration` | Goto declaration | normal: `` gD ``, select: `` gD `` | +| `add_newline_above` | Add newline above | normal: `` [ ``, select: `` [ `` | +| `add_newline_below` | Add newline below | normal: `` ] ``, select: `` ] `` | +| `goto_type_definition` | Goto type definition | normal: `` gy ``, select: `` gy `` | +| `goto_implementation` | Goto implementation | normal: `` gi ``, select: `` gi `` | +| `goto_file_start` | Goto line number else file start | normal: `` gg ``, select: `` gg `` | +| `goto_file_end` | Goto file end | | +| `goto_file` | Goto files/URLs in selections | normal: `` gf ``, select: `` gf `` | +| `goto_file_hsplit` | Goto files in selections (hsplit) | normal: `` f ``, `` wf ``, select: `` f ``, `` wf `` | +| `goto_file_vsplit` | Goto files in selections (vsplit) | normal: `` F ``, `` wF ``, select: `` F ``, `` wF `` | +| `goto_reference` | Goto references | normal: `` gr ``, select: `` gr `` | +| `goto_window_top` | Goto window top | normal: `` gt ``, select: `` gt `` | +| `goto_window_center` | Goto window center | normal: `` gc ``, select: `` gc `` | +| `goto_window_bottom` | Goto window bottom | normal: `` gb ``, select: `` gb `` | +| `goto_last_accessed_file` | Goto last accessed file | normal: `` ga ``, select: `` ga `` | +| `goto_last_modified_file` | Goto last modified file | normal: `` gm ``, select: `` gm `` | +| `goto_last_modification` | Goto last modification | normal: `` g. ``, select: `` g. `` | +| `goto_line` | Goto line | normal: `` G ``, select: `` G `` | +| `goto_last_line` | Goto last line | normal: `` ge ``, select: `` ge `` | +| `goto_first_diag` | Goto first diagnostic | normal: `` [D ``, select: `` [D `` | +| `goto_last_diag` | Goto last diagnostic | normal: `` ]D ``, select: `` ]D `` | +| `goto_next_diag` | Goto next diagnostic | normal: `` ]d ``, select: `` ]d `` | +| `goto_prev_diag` | Goto previous diagnostic | normal: `` [d ``, select: `` [d `` | +| `goto_next_change` | Goto next change | normal: `` ]g ``, select: `` ]g `` | +| `goto_prev_change` | Goto previous change | normal: `` [g ``, select: `` [g `` | +| `goto_first_change` | Goto first change | normal: `` [G ``, select: `` [G `` | +| `goto_last_change` | Goto last change | normal: `` ]G ``, select: `` ]G `` | +| `goto_line_start` | Goto line start | normal: `` gh ``, `` ``, select: `` gh ``, insert: `` `` | +| `goto_line_end` | Goto line end | normal: `` gl ``, `` ``, select: `` gl `` | +| `goto_next_buffer` | Goto next buffer | normal: `` gn ``, select: `` gn `` | +| `goto_previous_buffer` | Goto previous buffer | normal: `` gp ``, select: `` gp `` | +| `goto_line_end_newline` | Goto newline at line end | insert: `` `` | +| `goto_first_nonwhitespace` | Goto first non-blank in line | normal: `` gs ``, select: `` gs `` | +| `trim_selections` | Trim whitespace from selections | normal: `` _ ``, select: `` _ `` | +| `extend_to_line_start` | Extend to line start | select: `` `` | +| `extend_to_first_nonwhitespace` | Extend to first non-blank in line | | +| `extend_to_line_end` | Extend to line end | select: `` `` | +| `extend_to_line_end_newline` | Extend to line end | | +| `signature_help` | Show signature help | | +| `smart_tab` | Insert tab if all cursors have all whitespace to their left; otherwise, run a separate command. | insert: `` `` | +| `insert_tab` | Insert tab char | insert: `` `` | +| `insert_newline` | Insert newline char | insert: `` ``, `` `` | +| `delete_char_backward` | Delete previous char | insert: `` ``, `` ``, `` `` | +| `delete_char_forward` | Delete next char | insert: `` ``, `` `` | +| `delete_word_backward` | Delete previous word | insert: `` ``, `` `` | +| `delete_word_forward` | Delete next word | insert: `` ``, `` `` | +| `kill_to_line_start` | Delete till start of line | insert: `` `` | +| `kill_to_line_end` | Delete till end of line | insert: `` `` | +| `undo` | Undo change | normal: `` u ``, select: `` u `` | +| `redo` | Redo change | normal: `` U ``, select: `` U `` | +| `earlier` | Move backward in history | normal: `` ``, select: `` `` | +| `later` | Move forward in history | normal: `` ``, select: `` `` | +| `commit_undo_checkpoint` | Commit changes to new checkpoint | insert: `` `` | +| `yank` | Yank selection | normal: `` y ``, select: `` y `` | +| `yank_to_clipboard` | Yank selections to clipboard | normal: `` y ``, select: `` y `` | +| `yank_to_primary_clipboard` | Yank selections to primary clipboard | | +| `yank_joined` | Join and yank selections | | +| `yank_joined_to_clipboard` | Join and yank selections to clipboard | | +| `yank_main_selection_to_clipboard` | Yank main selection to clipboard | normal: `` Y ``, select: `` Y `` | +| `yank_joined_to_primary_clipboard` | Join and yank selections to primary clipboard | | +| `yank_main_selection_to_primary_clipboard` | Yank main selection to primary clipboard | | +| `replace_with_yanked` | Replace with yanked text | normal: `` R ``, select: `` R `` | +| `replace_selections_with_clipboard` | Replace selections by clipboard content | normal: `` R ``, select: `` R `` | +| `replace_selections_with_primary_clipboard` | Replace selections by primary clipboard | | +| `paste_after` | Paste after selection | normal: `` p ``, select: `` p `` | +| `paste_before` | Paste before selection | normal: `` P ``, select: `` P `` | +| `paste_clipboard_after` | Paste clipboard after selections | normal: `` p ``, select: `` p `` | +| `paste_clipboard_before` | Paste clipboard before selections | normal: `` P ``, select: `` P `` | +| `paste_primary_clipboard_after` | Paste primary clipboard after selections | | +| `paste_primary_clipboard_before` | Paste primary clipboard before selections | | +| `indent` | Indent selection | normal: `` ``, select: `` `` | +| `unindent` | Unindent selection | normal: `` ``, select: `` `` | +| `format_selections` | Format selection | normal: `` = ``, select: `` = `` | +| `join_selections` | Join lines inside selection | normal: `` J ``, select: `` J `` | +| `join_selections_space` | Join lines inside selection and select spaces | normal: `` ``, select: `` `` | +| `keep_selections` | Keep selections matching regex | normal: `` K ``, select: `` K `` | +| `remove_selections` | Remove selections matching regex | normal: `` ``, select: `` `` | +| `align_selections` | Align selections in column | normal: `` & ``, select: `` & `` | +| `keep_primary_selection` | Keep primary selection | normal: `` , ``, select: `` , `` | +| `remove_primary_selection` | Remove primary selection | normal: `` ``, select: `` `` | +| `completion` | Invoke completion popup | insert: `` `` | +| `hover` | Show docs for item under cursor | normal: `` k ``, select: `` k `` | +| `toggle_comments` | Comment/uncomment selections | normal: `` ``, `` c ``, select: `` ``, `` c `` | +| `toggle_line_comments` | Line comment/uncomment selections | normal: `` ``, select: `` `` | +| `toggle_block_comments` | Block comment/uncomment selections | normal: `` C ``, select: `` C `` | +| `rotate_selections_forward` | Rotate selections forward | normal: `` ) ``, select: `` ) `` | +| `rotate_selections_backward` | Rotate selections backward | normal: `` ( ``, select: `` ( `` | +| `rotate_selection_contents_forward` | Rotate selection contents forward | normal: `` ``, select: `` `` | +| `rotate_selection_contents_backward` | Rotate selections contents backward | normal: `` ``, select: `` `` | +| `reverse_selection_contents` | Reverse selections contents | | +| `expand_selection` | Expand selection to parent syntax node | normal: `` ``, `` ``, select: `` ``, `` `` | +| `shrink_selection` | Shrink selection to previously expanded syntax node | normal: `` ``, `` ``, select: `` ``, `` `` | +| `select_next_sibling` | Select next sibling in the syntax tree | normal: `` ``, `` ``, select: `` ``, `` `` | +| `select_prev_sibling` | Select previous sibling the in syntax tree | normal: `` ``, `` ``, select: `` ``, `` `` | +| `select_all_siblings` | Select all siblings of the current node | normal: `` ``, select: `` `` | +| `select_all_children` | Select all children of the current node | normal: `` ``, `` ``, select: `` ``, `` `` | +| `jump_forward` | Jump forward on jumplist | normal: `` ``, `` ``, select: `` ``, `` `` | +| `jump_backward` | Jump backward on jumplist | normal: `` ``, select: `` `` | +| `save_selection` | Save current selection to jumplist | normal: `` ``, select: `` `` | +| `jump_view_right` | Jump to right split | normal: `` l ``, `` wl ``, `` ``, `` ``, `` w ``, `` w ``, select: `` l ``, `` wl ``, `` ``, `` ``, `` w ``, `` w `` | +| `jump_view_left` | Jump to left split | normal: `` h ``, `` wh ``, `` ``, `` ``, `` w ``, `` w ``, select: `` h ``, `` wh ``, `` ``, `` ``, `` w ``, `` w `` | +| `jump_view_up` | Jump to split above | normal: `` k ``, `` ``, `` wk ``, `` ``, `` w ``, `` w ``, select: `` k ``, `` ``, `` wk ``, `` ``, `` w ``, `` w `` | +| `jump_view_down` | Jump to split below | normal: `` j ``, `` wj ``, `` ``, `` ``, `` w ``, `` w ``, select: `` j ``, `` wj ``, `` ``, `` ``, `` w ``, `` w `` | +| `swap_view_right` | Swap with right split | normal: `` L ``, `` wL ``, select: `` L ``, `` wL `` | +| `swap_view_left` | Swap with left split | normal: `` H ``, `` wH ``, select: `` H ``, `` wH `` | +| `swap_view_up` | Swap with split above | normal: `` K ``, `` wK ``, select: `` K ``, `` wK `` | +| `swap_view_down` | Swap with split below | normal: `` J ``, `` wJ ``, select: `` J ``, `` wJ `` | +| `transpose_view` | Transpose splits | normal: `` t ``, `` wt ``, `` ``, `` w ``, select: `` t ``, `` wt ``, `` ``, `` w `` | +| `rotate_view` | Goto next window | normal: `` w ``, `` ww ``, `` ``, `` w ``, select: `` w ``, `` ww ``, `` ``, `` w `` | +| `rotate_view_reverse` | Goto previous window | | +| `hsplit` | Horizontal bottom split | normal: `` s ``, `` ws ``, `` ``, `` w ``, select: `` s ``, `` ws ``, `` ``, `` w `` | +| `hsplit_new` | Horizontal bottom split scratch buffer | normal: `` ns ``, `` wns ``, `` n ``, `` wn ``, select: `` ns ``, `` wns ``, `` n ``, `` wn `` | +| `vsplit` | Vertical right split | normal: `` v ``, `` wv ``, `` ``, `` w ``, select: `` v ``, `` wv ``, `` ``, `` w `` | +| `vsplit_new` | Vertical right split scratch buffer | normal: `` nv ``, `` wnv ``, `` n ``, `` wn ``, select: `` nv ``, `` wnv ``, `` n ``, `` wn `` | +| `wclose` | Close window | normal: `` q ``, `` wq ``, `` ``, `` w ``, select: `` q ``, `` wq ``, `` ``, `` w `` | +| `wonly` | Close windows except current | normal: `` o ``, `` wo ``, `` ``, `` w ``, select: `` o ``, `` wo ``, `` ``, `` w `` | +| `select_register` | Select register | normal: `` " ``, select: `` " `` | +| `insert_register` | Insert register | insert: `` `` | +| `align_view_middle` | Align view middle | normal: `` Zm ``, `` zm ``, select: `` Zm ``, `` zm `` | +| `align_view_top` | Align view top | normal: `` Zt ``, `` zt ``, select: `` Zt ``, `` zt `` | +| `align_view_center` | Align view center | normal: `` Zc ``, `` Zz ``, `` zc ``, `` zz ``, select: `` Zc ``, `` Zz ``, `` zc ``, `` zz `` | +| `align_view_bottom` | Align view bottom | normal: `` Zb ``, `` zb ``, select: `` Zb ``, `` zb `` | +| `scroll_up` | Scroll view up | normal: `` Zk ``, `` zk ``, `` Z ``, `` z ``, select: `` Zk ``, `` zk ``, `` Z ``, `` z `` | +| `scroll_down` | Scroll view down | normal: `` Zj ``, `` zj ``, `` Z ``, `` z ``, select: `` Zj ``, `` zj ``, `` Z ``, `` z `` | +| `match_brackets` | Goto matching bracket | normal: `` mm ``, select: `` mm `` | +| `surround_add` | Surround add | normal: `` ms ``, select: `` ms `` | +| `surround_replace` | Surround replace | normal: `` mr ``, select: `` mr `` | +| `surround_delete` | Surround delete | normal: `` md ``, select: `` md `` | +| `select_textobject_around` | Select around object | normal: `` ma ``, select: `` ma `` | +| `select_textobject_inner` | Select inside object | normal: `` mi ``, select: `` mi `` | +| `goto_next_function` | Goto next function | normal: `` ]f ``, select: `` ]f `` | +| `goto_prev_function` | Goto previous function | normal: `` [f ``, select: `` [f `` | +| `goto_next_class` | Goto next type definition | normal: `` ]t ``, select: `` ]t `` | +| `goto_prev_class` | Goto previous type definition | normal: `` [t ``, select: `` [t `` | +| `goto_next_parameter` | Goto next parameter | normal: `` ]a ``, select: `` ]a `` | +| `goto_prev_parameter` | Goto previous parameter | normal: `` [a ``, select: `` [a `` | +| `goto_next_comment` | Goto next comment | normal: `` ]c ``, select: `` ]c `` | +| `goto_prev_comment` | Goto previous comment | normal: `` [c ``, select: `` [c `` | +| `goto_next_test` | Goto next test | normal: `` ]T ``, select: `` ]T `` | +| `goto_prev_test` | Goto previous test | normal: `` [T ``, select: `` [T `` | +| `goto_next_entry` | Goto next pairing | normal: `` ]e ``, select: `` ]e `` | +| `goto_prev_entry` | Goto previous pairing | normal: `` [e ``, select: `` [e `` | +| `goto_next_paragraph` | Goto next paragraph | normal: `` ]p ``, select: `` ]p `` | +| `goto_prev_paragraph` | Goto previous paragraph | normal: `` [p ``, select: `` [p `` | +| `dap_launch` | Launch debug target | normal: `` Gl ``, select: `` Gl `` | +| `dap_restart` | Restart debugging session | normal: `` Gr ``, select: `` Gr `` | +| `dap_toggle_breakpoint` | Toggle breakpoint | normal: `` Gb ``, select: `` Gb `` | +| `dap_continue` | Continue program execution | normal: `` Gc ``, select: `` Gc `` | +| `dap_pause` | Pause program execution | normal: `` Gh ``, select: `` Gh `` | +| `dap_step_in` | Step in | normal: `` Gi ``, select: `` Gi `` | +| `dap_step_out` | Step out | normal: `` Go ``, select: `` Go `` | +| `dap_next` | Step to next | normal: `` Gn ``, select: `` Gn `` | +| `dap_variables` | List variables | normal: `` Gv ``, select: `` Gv `` | +| `dap_terminate` | End debug session | normal: `` Gt ``, select: `` Gt `` | +| `dap_edit_condition` | Edit breakpoint condition on current line | normal: `` G ``, select: `` G `` | +| `dap_edit_log` | Edit breakpoint log message on current line | normal: `` G ``, select: `` G `` | +| `dap_switch_thread` | Switch current thread | normal: `` Gst ``, select: `` Gst `` | +| `dap_switch_stack_frame` | Switch stack frame | normal: `` Gsf ``, select: `` Gsf `` | +| `dap_enable_exceptions` | Enable exception breakpoints | normal: `` Ge ``, select: `` Ge `` | +| `dap_disable_exceptions` | Disable exception breakpoints | normal: `` GE ``, select: `` GE `` | +| `shell_pipe` | Pipe selections through shell command | normal: `` \| ``, select: `` \| `` | +| `shell_pipe_to` | Pipe selections into shell command ignoring output | normal: `` ``, select: `` `` | +| `shell_insert_output` | Insert shell command output before selections | normal: `` ! ``, select: `` ! `` | +| `shell_append_output` | Append shell command output after selections | normal: `` ``, select: `` `` | +| `shell_keep_pipe` | Filter selections with shell predicate | normal: `` $ ``, select: `` $ `` | +| `suspend` | Suspend and return to shell | normal: `` ``, select: `` `` | +| `rename_symbol` | Rename symbol | normal: `` r ``, select: `` r `` | +| `increment` | Increment item under cursor | normal: `` ``, select: `` `` | +| `decrement` | Decrement item under cursor | normal: `` ``, select: `` `` | +| `record_macro` | Record macro | normal: `` Q ``, select: `` Q `` | +| `replay_macro` | Replay macro | normal: `` q ``, select: `` q `` | +| `command_palette` | Open command palette | normal: `` ? ``, select: `` ? `` | +| `goto_word` | Jump to a two-character label | normal: `` gw `` | +| `extend_to_word` | Extend to a two-character label | select: `` gw `` | diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index 7d3622256b3d..f0d9a0f492a5 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -16,7 +16,7 @@ | `:write-buffer-close`, `:wbc` | Write changes to disk and closes the buffer. Accepts an optional path (:write-buffer-close some/path.txt) | | `:write-buffer-close!`, `:wbc!` | Force write changes to disk creating necessary subdirectories and closes the buffer. Accepts an optional path (:write-buffer-close! some/path.txt) | | `:new`, `:n` | Create a new scratch buffer. | -| `:format`, `:fmt` | Format the file using the LSP formatter. | +| `:format`, `:fmt` | Format the file using an external formatter or language server. | | `:indent-style` | Set the indentation style for editing. ('t' for tabs or 1-16 for number of spaces.) | | `: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. | diff --git a/book/src/keymap.md b/book/src/keymap.md index 28113ea0b0a7..2797eaee2908 100644 --- a/book/src/keymap.md +++ b/book/src/keymap.md @@ -160,7 +160,8 @@ Search commands all operate on the `/` register by default. To use a different r | `?` | Search for previous pattern | `rsearch` | | `n` | Select next search match | `search_next` | | `N` | Select previous search match | `search_prev` | -| `*` | Use current selection as the search pattern | `search_selection` | +| `*` | Use current selection as the search pattern, automatically wrapping with `\b` on word boundaries | `search_selection_detect_word_boundaries` | +| `Alt-*` | Use current selection as the search pattern | `search_selection` | ### Minor modes diff --git a/book/src/languages.md b/book/src/languages.md index 2a1c6d652f18..a70b4789158b 100644 --- a/book/src/languages.md +++ b/book/src/languages.md @@ -13,7 +13,7 @@ There are three possible locations for a `languages.toml` file: 2. In your [configuration directory](./configuration.md). This overrides values from the built-in language configuration. For example, to disable - auto-LSP-formatting in Rust: + auto-formatting for Rust: ```toml # in /helix/languages.toml @@ -128,7 +128,7 @@ These are the available options for a language server. | ---- | ----------- | | `command` | The name or path of the language server binary to execute. Binaries must be in `$PATH` | | `args` | A list of arguments to pass to the language server binary | -| `config` | LSP initialization options | +| `config` | Language server initialization options | | `timeout` | The maximum time a request to the language server may take, in seconds. Defaults to `20` | | `environment` | Any environment variables that will be used when starting the language server `{ "KEY1" = "Value1", "KEY2" = "Value2" }` | | `required-root-patterns` | A list of `glob` patterns to look for in the working directory. The language server is started if at least one of them is found. | diff --git a/book/src/pickers.md b/book/src/pickers.md index 4149e560b941..67a195a65e31 100644 --- a/book/src/pickers.md +++ b/book/src/pickers.md @@ -4,7 +4,7 @@ Helix has a variety of pickers, which are interactive windows used to select var ### Filtering Picker Results -Most pickers perform fuzzy matching using [fzf syntax](https://github.com/junegunn/fzf?tab=readme-ov-file#search-syntax). Two exceptions are the global search picker, which uses regex, and the workspace symbol picker, which passes search terms to the LSP. Note that OR operations (`|`) are not currently supported. +Most pickers perform fuzzy matching using [fzf syntax](https://github.com/junegunn/fzf?tab=readme-ov-file#search-syntax). Two exceptions are the global search picker, which uses regex, and the workspace symbol picker, which passes search terms to the language server. Note that OR operations (`|`) are not currently supported. If a picker shows multiple columns, you may apply the filter to a specific column by prefixing the column name with `%`. Column names can be shortened to any prefix, so `%p`, `%pa` or `%pat` all mean the same as `%path`. For example, a query of `helix %p .toml !lang` in the global search picker searches for the term "helix" within files with paths ending in ".toml" but not including "lang". diff --git a/book/src/remapping.md b/book/src/remapping.md index 41e20f84ba0c..e3baee13fc02 100644 --- a/book/src/remapping.md +++ b/book/src/remapping.md @@ -72,8 +72,22 @@ t = ":run-shell-command cargo test" ## Special keys and modifiers -Ctrl, Shift and Alt modifiers are encoded respectively with the prefixes -`C-`, `S-` and `A-`. Special keys are encoded as follows: +Ctrl, Shift and Alt modifiers are encoded respectively with the prefixes `C-`, `S-` and `A-`. + +The [Super key](https://en.wikipedia.org/wiki/Super_key_(keyboard_button)) - the Windows/Linux +key or the Command key on Mac keyboards - is also supported when using a terminal emulator that +supports the [enhanced keyboard protocol](https://github.com/helix-editor/helix/wiki/Terminal-Support#enhanced-keyboard-protocol). +The super key is encoded with prefixes `Meta-`, `Cmd-` or `Win-`. These are all synonyms for the +super modifier - binding a key with a `Win-` modifier will mean it can be used with the +Windows/Linux key or the Command key. + +```toml +[keys.normal] +C-s = ":write" # Ctrl and 's' to write +Cmd-s = ":write" # Cmd or Win or Meta and 's' to write +``` + +Special keys are encoded as follows: | Key name | Representation | | --- | --- | diff --git a/book/src/themes.md b/book/src/themes.md index 4e0142dddd95..40e12330e425 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -309,8 +309,8 @@ These scopes are used for theming the editor interface: | `ui.virtual.whitespace` | Visible whitespace characters | | `ui.virtual.indent-guide` | Vertical indent width guides | | `ui.virtual.inlay-hint` | Default style for inlay hints of all kinds | -| `ui.virtual.inlay-hint.parameter` | Style for inlay hints of kind `parameter` (LSPs are not required to set a kind) | -| `ui.virtual.inlay-hint.type` | Style for inlay hints of kind `type` (LSPs are not required to set a kind) | +| `ui.virtual.inlay-hint.parameter` | Style for inlay hints of kind `parameter` (language servers are not required to set a kind) | +| `ui.virtual.inlay-hint.type` | Style for inlay hints of kind `type` (language servers are not required to set a kind) | | `ui.virtual.wrap` | Soft-wrap indicator (see the [`editor.soft-wrap` config][editor-section]) | | `ui.virtual.jump-label` | Style for virtual jump labels | | `ui.menu` | Code and command completion menus | diff --git a/book/theme/index.hbs b/book/theme/index.hbs index 0a0bc55019cb..0a46ac64915a 100644 --- a/book/theme/index.hbs +++ b/book/theme/index.hbs @@ -1,5 +1,5 @@ - + @@ -52,15 +52,17 @@ {{/if}} - - -
+ - + + + + +
- - -
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 86caff717a63..df33d6e52c25 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -59,10 +59,16 @@ the default value (e.g. to `10240` from `256`) by running `ulimit -n 10240`. ## Minimum Stable Rust Version (MSRV) Policy -Helix follows the MSRV of Firefox. -The current MSRV and future changes to the MSRV are listed in the [Firefox documentation]. +Helix keeps an intentionally low MSRV for the sake of easy building and packaging +downstream. We follow [Firefox's MSRV policy]. Once Firefox's MSRV increases we +may bump ours as well, but be sure to check that popular distributions like Ubuntu +package the new MSRV version. When increasing the MSRV, update these three places: -[Firefox documentation]: https://firefox-source-docs.mozilla.org/writing-rust-code/update-policy.html +* the `workspace.package.rust-version` key in `Cargo.toml` in the repository root +* the `env.MSRV` key at the top of `.github/workflows/build.yml` +* the `toolchain.channel` key in `rust-toolchain.toml` + +[Firefox's MSRV policy]: https://firefox-source-docs.mozilla.org/writing-rust-code/update-policy.html [good-first-issue]: https://github.com/helix-editor/helix/labels/E-easy [log-file]: https://github.com/helix-editor/helix/wiki/FAQ#access-the-log-file [architecture.md]: ./architecture.md diff --git a/helix-core/Cargo.toml b/helix-core/Cargo.toml index d7f9d7206c98..c86fbea7839b 100644 --- a/helix-core/Cargo.toml +++ b/helix-core/Cargo.toml @@ -39,7 +39,7 @@ bitflags = "2.6" ahash = "0.8.11" hashbrown = { version = "0.14.5", features = ["raw"] } dunce = "1.0" -url = "2.5.3" +url = "2.5.4" log = "0.4" serde = { version = "1.0", features = ["derive"] } diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 4270218746ae..d63d05fa9360 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -9,7 +9,7 @@ use crate::{ use helix_stdx::rope::RopeSliceExt; use std::borrow::Cow; -pub const DEFAULT_COMMENT_TOKEN: &str = "//"; +pub const DEFAULT_COMMENT_TOKEN: &str = "#"; /// Returns the longest matching comment token of the given line (if it exists). pub fn get_comment_token<'a, S: AsRef>( @@ -147,10 +147,7 @@ pub fn find_block_comments( let mut only_whitespace = true; let mut comment_changes = Vec::with_capacity(selection.len()); let default_tokens = tokens.first().cloned().unwrap_or_default(); - // TODO: check if this can be removed on MSRV bump - #[allow(clippy::redundant_clone)] let mut start_token = default_tokens.start.clone(); - #[allow(clippy::redundant_clone)] let mut end_token = default_tokens.end.clone(); let mut tokens = tokens.to_vec(); @@ -376,12 +373,12 @@ mod test { let transaction = toggle_line_comments(&doc, &selection, None); transaction.apply(&mut doc); - assert_eq!(doc, " // 1\n\n // 2\n // 3"); + assert_eq!(doc, " # 1\n\n # 2\n # 3"); } #[test] fn uncomment() { - let mut doc = Rope::from(" // 1\n\n // 2\n // 3"); + let mut doc = Rope::from(" # 1\n\n # 2\n # 3"); let mut selection = Selection::single(0, doc.len_chars() - 1); let transaction = toggle_line_comments(&doc, &selection, None); @@ -394,7 +391,7 @@ mod test { #[test] fn uncomment_0_margin_comments() { - let mut doc = Rope::from(" //1\n\n //2\n //3"); + let mut doc = Rope::from(" #1\n\n #2\n #3"); let mut selection = Selection::single(0, doc.len_chars() - 1); let transaction = toggle_line_comments(&doc, &selection, None); @@ -407,7 +404,7 @@ mod test { #[test] fn uncomment_0_margin_comments_with_no_space() { - let mut doc = Rope::from("//"); + let mut doc = Rope::from("#"); let mut selection = Selection::single(0, doc.len_chars() - 1); let transaction = toggle_line_comments(&doc, &selection, None); diff --git a/helix-core/src/graphemes.rs b/helix-core/src/graphemes.rs index 91f11e620343..4ca85d315cc1 100644 --- a/helix-core/src/graphemes.rs +++ b/helix-core/src/graphemes.rs @@ -346,7 +346,7 @@ pub struct RopeGraphemes<'a> { cursor: GraphemeCursor, } -impl<'a> fmt::Debug for RopeGraphemes<'a> { +impl fmt::Debug for RopeGraphemes<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RopeGraphemes") .field("text", &self.text) @@ -358,7 +358,7 @@ impl<'a> fmt::Debug for RopeGraphemes<'a> { } } -impl<'a> RopeGraphemes<'a> { +impl RopeGraphemes<'_> { #[must_use] pub fn new(slice: RopeSlice) -> RopeGraphemes { let mut chunks = slice.chunks(); @@ -423,7 +423,7 @@ pub struct RevRopeGraphemes<'a> { cursor: GraphemeCursor, } -impl<'a> fmt::Debug for RevRopeGraphemes<'a> { +impl fmt::Debug for RevRopeGraphemes<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RevRopeGraphemes") .field("text", &self.text) @@ -435,7 +435,7 @@ impl<'a> fmt::Debug for RevRopeGraphemes<'a> { } } -impl<'a> RevRopeGraphemes<'a> { +impl RevRopeGraphemes<'_> { #[must_use] pub fn new(slice: RopeSlice) -> RevRopeGraphemes { let (mut chunks, mut cur_chunk_start, _, _) = slice.chunks_at_byte(slice.len_bytes()); @@ -542,7 +542,7 @@ impl<'a> From<&'a str> for GraphemeStr<'a> { } } -impl<'a> From for GraphemeStr<'a> { +impl From for GraphemeStr<'_> { fn from(g: String) -> Self { let len = g.len(); let ptr = Box::into_raw(g.into_bytes().into_boxed_slice()) as *mut u8; diff --git a/helix-core/src/indent.rs b/helix-core/src/indent.rs index ae26c13e0799..3faae53ec131 100644 --- a/helix-core/src/indent.rs +++ b/helix-core/src/indent.rs @@ -386,7 +386,7 @@ enum IndentCaptureType<'a> { Align(RopeSlice<'a>), } -impl<'a> IndentCaptureType<'a> { +impl IndentCaptureType<'_> { fn default_scope(&self) -> IndentScope { match self { IndentCaptureType::Indent | IndentCaptureType::IndentAlways => IndentScope::Tail, diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs index a382a71861c1..e29fcc94cec2 100644 --- a/helix-core/src/selection.rs +++ b/helix-core/src/selection.rs @@ -660,7 +660,7 @@ impl Selection { pub fn fragments<'a>( &'a self, text: RopeSlice<'a>, - ) -> impl DoubleEndedIterator> + ExactSizeIterator> + 'a + ) -> impl DoubleEndedIterator> + ExactSizeIterator> { self.ranges.iter().map(move |range| range.fragment(text)) } @@ -744,7 +744,7 @@ pub struct LineRangeIter<'a> { text: RopeSlice<'a>, } -impl<'a> Iterator for LineRangeIter<'a> { +impl Iterator for LineRangeIter<'_> { type Item = (usize, usize); fn next(&mut self) -> Option { diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 3de470f7c508..03a46172b8b6 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -621,7 +621,7 @@ pub enum CapturedNode<'a> { Grouped(Vec>), } -impl<'a> CapturedNode<'a> { +impl CapturedNode<'_> { pub fn start_byte(&self) -> usize { match self { Self::Single(n) => n.start_byte(), @@ -1854,7 +1854,7 @@ struct HighlightIterLayer<'a> { depth: u32, } -impl<'a> fmt::Debug for HighlightIterLayer<'a> { +impl fmt::Debug for HighlightIterLayer<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("HighlightIterLayer").finish() } @@ -2111,7 +2111,7 @@ impl HighlightConfiguration { } } -impl<'a> HighlightIterLayer<'a> { +impl HighlightIterLayer<'_> { // First, sort scope boundaries by their byte offset in the document. At a // given position, emit scope endings before scope beginnings. Finally, emit // scope boundaries from deeper layers first. @@ -2249,7 +2249,7 @@ fn intersect_ranges( result } -impl<'a> HighlightIter<'a> { +impl HighlightIter<'_> { fn emit_event( &mut self, offset: usize, @@ -2304,7 +2304,7 @@ impl<'a> HighlightIter<'a> { } } -impl<'a> Iterator for HighlightIter<'a> { +impl Iterator for HighlightIter<'_> { type Item = Result; fn next(&mut self) -> Option { diff --git a/helix-core/src/syntax/tree_cursor.rs b/helix-core/src/syntax/tree_cursor.rs index bec4a1c6c773..d82ea74dbfff 100644 --- a/helix-core/src/syntax/tree_cursor.rs +++ b/helix-core/src/syntax/tree_cursor.rs @@ -217,7 +217,7 @@ impl<'a> TreeCursor<'a> { /// Returns an iterator over the children of the node the TreeCursor is on /// at the time this is called. - pub fn children(&'a mut self) -> ChildIter { + pub fn children(&'a mut self) -> ChildIter<'a> { let parent = self.node(); ChildIter { @@ -229,7 +229,7 @@ impl<'a> TreeCursor<'a> { /// Returns an iterator over the named children of the node the TreeCursor is on /// at the time this is called. - pub fn named_children(&'a mut self) -> ChildIter { + pub fn named_children(&'a mut self) -> ChildIter<'a> { let parent = self.node(); ChildIter { diff --git a/helix-core/src/text_annotations.rs b/helix-core/src/text_annotations.rs index ff28a8dd236e..9704c3d6b892 100644 --- a/helix-core/src/text_annotations.rs +++ b/helix-core/src/text_annotations.rs @@ -211,7 +211,7 @@ impl Layer<'_, A, M> { } impl<'a, A, M> From<(&'a [A], M)> for Layer<'a, A, M> { - fn from((annotations, metadata): (&'a [A], M)) -> Layer { + fn from((annotations, metadata): (&'a [A], M)) -> Layer<'a, A, M> { Layer { annotations, current_index: Cell::new(0), diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs index c5c94b750529..450b47365ecb 100644 --- a/helix-core/src/transaction.rs +++ b/helix-core/src/transaction.rs @@ -769,7 +769,7 @@ impl<'a> ChangeIterator<'a> { } } -impl<'a> Iterator for ChangeIterator<'a> { +impl Iterator for ChangeIterator<'_> { type Item = Change; fn next(&mut self) -> Option { diff --git a/helix-lsp-types/Cargo.lock b/helix-lsp-types/Cargo.lock deleted file mode 100644 index 11ac87521802..000000000000 --- a/helix-lsp-types/Cargo.lock +++ /dev/null @@ -1,176 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "form_urlencoded" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "idna" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "itoa" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" - -[[package]] -name = "lsp-types" -version = "0.95.1" -dependencies = [ - "bitflags", - "serde", - "serde_json", - "serde_repr", - "url", -] - -[[package]] -name = "percent-encoding" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" - -[[package]] -name = "proc-macro2" -version = "1.0.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "ryu" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" - -[[package]] -name = "serde" -version = "1.0.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_repr" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "syn" -version = "1.0.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - -[[package]] -name = "unicode-bidi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" - -[[package]] -name = "unicode-ident" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "url" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] diff --git a/helix-lsp-types/Cargo.toml b/helix-lsp-types/Cargo.toml index cb6b943074bd..0460c10199a5 100644 --- a/helix-lsp-types/Cargo.toml +++ b/helix-lsp-types/Cargo.toml @@ -25,7 +25,7 @@ bitflags = "2.6.0" serde = { version = "1.0.215", features = ["derive"] } serde_json = "1.0.133" serde_repr = "0.1" -url = {version = "2.5.3", features = ["serde"]} +url = {version = "2.5.4", features = ["serde"]} [features] default = [] diff --git a/helix-lsp-types/src/completion.rs b/helix-lsp-types/src/completion.rs index 2555228a7c22..7c006bdb62ad 100644 --- a/helix-lsp-types/src/completion.rs +++ b/helix-lsp-types/src/completion.rs @@ -497,7 +497,6 @@ pub struct CompletionItem { /// insertText is ignored. /// /// Most editors support two different operation when accepting a completion item. One is to insert a - /// completion text and the other is to replace an existing text with a completion text. Since this can /// usually not predetermined by a server it can report both ranges. Clients need to signal support for /// `InsertReplaceEdits` via the `textDocument.completion.insertReplaceSupport` client capability diff --git a/helix-lsp/src/jsonrpc.rs b/helix-lsp/src/jsonrpc.rs index f415dde0be4b..9ff57cde941f 100644 --- a/helix-lsp/src/jsonrpc.rs +++ b/helix-lsp/src/jsonrpc.rs @@ -137,7 +137,7 @@ impl Serialize for Version { struct VersionVisitor; -impl<'v> Visitor<'v> for VersionVisitor { +impl Visitor<'_> for VersionVisitor { type Value = Version; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { diff --git a/helix-parsec/src/lib.rs b/helix-parsec/src/lib.rs index 846d02d614fd..0ec44436fdbf 100644 --- a/helix-parsec/src/lib.rs +++ b/helix-parsec/src/lib.rs @@ -43,7 +43,7 @@ pub trait Parser<'a> { #[doc(hidden)] impl<'a, F, T> Parser<'a> for F where - F: Fn(&'a str) -> ParseResult, + F: Fn(&'a str) -> ParseResult<'a, T>, { type Output = T; diff --git a/helix-stdx/Cargo.toml b/helix-stdx/Cargo.toml index d18740efad14..84313b5b0e80 100644 --- a/helix-stdx/Cargo.toml +++ b/helix-stdx/Cargo.toml @@ -19,7 +19,7 @@ which = "7.0" regex-cursor = "0.1.4" bitflags = "2.6" once_cell = "1.19" -regex-automata = "0.4.8" +regex-automata = "0.4.9" [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.59", features = ["Win32_Foundation", "Win32_Security", "Win32_Security_Authorization", "Win32_Storage_FileSystem", "Win32_System_Threading"] } diff --git a/helix-stdx/src/env.rs b/helix-stdx/src/env.rs index d29a98fdebed..6e14c7a875ae 100644 --- a/helix-stdx/src/env.rs +++ b/helix-stdx/src/env.rs @@ -7,6 +7,7 @@ use std::{ use once_cell::sync::Lazy; +// We keep the CWD as a static so that we can access it in places where we don't have access to the Editor static CWD: RwLock> = RwLock::new(None); // Get the current working directory. @@ -36,12 +37,12 @@ pub fn current_working_dir() -> PathBuf { cwd } -pub fn set_current_working_dir(path: impl AsRef) -> std::io::Result<()> { +pub fn set_current_working_dir(path: impl AsRef) -> std::io::Result> { let path = crate::path::canonicalize(path); std::env::set_current_dir(&path)?; let mut cwd = CWD.write().unwrap(); - *cwd = Some(path); - Ok(()) + + Ok(cwd.replace(path)) } pub fn env_var_is_set(env_var_name: &str) -> bool { diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index 1c399a47c063..fb9d48babffe 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -60,7 +60,7 @@ thiserror.workspace = true # opening URLs open = "5.3.1" -url = "2.5.3" +url = "2.5.4" # config toml = "0.8" @@ -74,7 +74,7 @@ grep-searcher = "0.1.14" [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.164" +libc = "0.2.167" [target.'cfg(target_os = "macos")'.dependencies] crossterm = { version = "0.28", features = ["event-stream", "use-dev-tty", "libc"] } diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 040161d6c5ee..19b24a2f755d 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -174,7 +174,7 @@ impl Application { nr_of_files += 1; if file.is_dir() { return Err(anyhow::anyhow!( - "expected a path to file, found a directory. (to open a directory pass it as first argument)" + "expected a path to file, but found a directory: {file:?}. (to open a directory pass it as first argument)" )); } else { // If the user passes in either `--vsplit` or @@ -188,6 +188,7 @@ impl Application { Some(Layout::Horizontal) => Action::HorizontalSplit, None => Action::Load, }; + let old_id = editor.document_id_by_path(&file); let doc_id = match editor.open(&file, action) { // Ignore irregular files during application init. Err(DocumentOpenError::IrregularFile) => { @@ -195,6 +196,11 @@ impl Application { continue; } Err(err) => return Err(anyhow::anyhow!(err)), + // We can't open more than 1 buffer for 1 file, in this case we already have opened this file previously + Ok(doc_id) if old_id == Some(doc_id) => { + nr_of_files -= 1; + doc_id + } Ok(doc_id) => doc_id, }; // with Action::Load all documents have the same view diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index e2e06b1eda87..783ca43bf0cd 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -98,7 +98,7 @@ pub struct Context<'a> { pub jobs: &'a mut Jobs, } -impl<'a> Context<'a> { +impl Context<'_> { /// Push a new component onto the compositor. pub fn push_layer(&mut self, component: Box) { self.callback @@ -353,6 +353,7 @@ impl MappableCommand { extend_search_next, "Add next search match to selection", extend_search_prev, "Add previous search match to selection", search_selection, "Use current selection as search pattern", + search_selection_detect_word_boundaries, "Use current selection as the search pattern, automatically wrapping with `\\b` on word boundaries", make_search_word_bounded, "Modify current search to make it word bounded", global_search, "Global search in workspace folder", extend_line, "Select current line, if already selected, extend to another line based on the anchor", @@ -1289,7 +1290,6 @@ fn goto_file_impl(cx: &mut Context, action: Action) { // rarely so in practice) so that gf on quoted/braced path works (not sure about this // but apparently that is how gf has worked historically in helix) let path = find_paths(search_range, true) - .inspect(|mat| println!("{mat:?} {:?}", pos - search_start)) .take_while(|range| search_start + range.start <= pos + 1) .find(|range| pos <= search_start + range.end) .map(|range| Cow::from(search_range.byte_slice(range))); @@ -2247,14 +2247,53 @@ fn extend_search_prev(cx: &mut Context) { } fn search_selection(cx: &mut Context) { + search_selection_impl(cx, false) +} + +fn search_selection_detect_word_boundaries(cx: &mut Context) { + search_selection_impl(cx, true) +} + +fn search_selection_impl(cx: &mut Context, detect_word_boundaries: bool) { + fn is_at_word_start(text: RopeSlice, index: usize) -> bool { + let ch = text.char(index); + if index == 0 { + return char_is_word(ch); + } + let prev_ch = text.char(index - 1); + + !char_is_word(prev_ch) && char_is_word(ch) + } + + fn is_at_word_end(text: RopeSlice, index: usize) -> bool { + if index == 0 || index == text.len_chars() { + return false; + } + let ch = text.char(index); + let prev_ch = text.char(index - 1); + + char_is_word(prev_ch) && !char_is_word(ch) + } + let register = cx.register.unwrap_or('/'); let (view, doc) = current!(cx.editor); - let contents = doc.text().slice(..); + let text = doc.text().slice(..); let regex = doc .selection(view.id) .iter() - .map(|selection| regex::escape(&selection.fragment(contents))) + .map(|selection| { + let add_boundary_prefix = + detect_word_boundaries && is_at_word_start(text, selection.from()); + let add_boundary_suffix = + detect_word_boundaries && is_at_word_end(text, selection.to()); + + let prefix = if add_boundary_prefix { "\\b" } else { "" }; + let suffix = if add_boundary_suffix { "\\b" } else { "" }; + + let word = regex::escape(&selection.fragment(text)); + format!("{}{}{}", prefix, word, suffix) + }) .collect::>() // Collect into hashset to deduplicate identical regexes .into_iter() .collect::>() @@ -3423,40 +3462,42 @@ fn open(cx: &mut Context, open: Open) { let selection = doc.selection(view.id); let mut ranges = SmallVec::with_capacity(selection.len()); - let mut offs = 0; let mut transaction = Transaction::change_by_selection(contents, selection, |range| { - let cursor_line = text.char_to_line(match open { + // the line number, where the cursor is currently + let curr_line_num = text.char_to_line(match open { Open::Below => graphemes::prev_grapheme_boundary(text, range.to()), Open::Above => range.from(), }); - let new_line = match open { - // adjust position to the end of the line (next line - 1) - Open::Below => cursor_line + 1, - // adjust position to the end of the previous line (current line - 1) - Open::Above => cursor_line, + // the next line number, where the cursor will be, after finishing the transaction + let next_new_line_num = match open { + Open::Below => curr_line_num + 1, + Open::Above => curr_line_num, }; - let line_num = new_line.saturating_sub(1); + let above_next_new_line_num = next_new_line_num.saturating_sub(1); + + let continue_comment_token = if doc.config.load().continue_comments { + doc.language_config() + .and_then(|config| config.comment_tokens.as_ref()) + .and_then(|tokens| comment::get_comment_token(text, tokens, curr_line_num)) + } else { + None + }; // Index to insert newlines after, as well as the char width // to use to compensate for those inserted newlines. - let (line_end_index, line_end_offset_width) = if new_line == 0 { + let (above_next_line_end_index, above_next_line_end_width) = if next_new_line_num == 0 { (0, 0) } else { ( - line_end_char_index(&text, line_num), + line_end_char_index(&text, above_next_new_line_num), doc.line_ending.len_chars(), ) }; - let continue_comment_token = doc - .language_config() - .and_then(|config| config.comment_tokens.as_ref()) - .and_then(|tokens| comment::get_comment_token(text, tokens, cursor_line)); - - let line = text.line(cursor_line); + let line = text.line(curr_line_num); let indent = match line.first_non_whitespace_char() { Some(pos) if continue_comment_token.is_some() => line.slice(..pos).to_string(), _ => indent::indent_for_newline( @@ -3466,26 +3507,36 @@ fn open(cx: &mut Context, open: Open) { &doc.indent_style, doc.tab_width(), text, - line_num, - line_end_index, - cursor_line, + above_next_new_line_num, + above_next_line_end_index, + curr_line_num, ), }; let indent_len = indent.len(); let mut text = String::with_capacity(1 + indent_len); - text.push_str(doc.line_ending.as_str()); - text.push_str(&indent); - if let Some(token) = continue_comment_token { - text.push_str(token); - text.push(' '); + if open == Open::Above && next_new_line_num == 0 { + text.push_str(&indent); + if let Some(token) = continue_comment_token { + text.push_str(token); + text.push(' '); + } + text.push_str(doc.line_ending.as_str()); + } else { + text.push_str(doc.line_ending.as_str()); + text.push_str(&indent); + + if let Some(token) = continue_comment_token { + text.push_str(token); + text.push(' '); + } } let text = text.repeat(count); // calculate new selection ranges - let pos = offs + line_end_index + line_end_offset_width; + let pos = above_next_line_end_index + above_next_line_end_width; let comment_len = continue_comment_token .map(|token| token.len() + 1) // `+ 1` for the extra space added .unwrap_or_default(); @@ -3498,9 +3549,11 @@ fn open(cx: &mut Context, open: Open) { )); } - offs += text.chars().count(); - - (line_end_index, line_end_index, Some(text.into())) + ( + above_next_line_end_index, + above_next_line_end_index, + Some(text.into()), + ) }); transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index())); @@ -3926,27 +3979,22 @@ pub mod insert { let curr = contents.get_char(pos).unwrap_or(' '); let current_line = text.char_to_line(pos); - let line_is_only_whitespace = text - .line(current_line) - .chars() - .all(|char| char.is_ascii_whitespace()); + let line_start = text.line_to_char(current_line); let mut new_text = String::new(); - let continue_comment_token = doc - .language_config() - .and_then(|config| config.comment_tokens.as_ref()) - .and_then(|tokens| comment::get_comment_token(text, tokens, current_line)); - - // If the current line is all whitespace, insert a line ending at the beginning of - // the current line. This makes the current line empty and the new line contain the - // indentation of the old line. - let (from, to, local_offs) = if line_is_only_whitespace { - let line_start = text.line_to_char(current_line); - new_text.push_str(doc.line_ending.as_str()); - - (line_start, line_start, new_text.chars().count()) + let continue_comment_token = if doc.config.load().continue_comments { + doc.language_config() + .and_then(|config| config.comment_tokens.as_ref()) + .and_then(|tokens| comment::get_comment_token(text, tokens, current_line)) } else { + None + }; + + let (from, to, local_offs) = if let Some(idx) = + text.slice(line_start..pos).last_non_whitespace_char() + { + let first_trailing_whitespace_char = (line_start + idx + 1).min(pos); let line = text.line(current_line); let indent = match line.first_non_whitespace_char() { @@ -3999,20 +4047,34 @@ pub mod insert { new_text.chars().count() }; - (pos, pos, local_offs) + ( + first_trailing_whitespace_char, + pos, + // Note that `first_trailing_whitespace_char` is at least `pos` so the + // unsigned subtraction (`pos - first_trailing_whitespace_char`) cannot + // underflow. + local_offs as isize - (pos - first_trailing_whitespace_char) as isize, + ) + } else { + // If the current line is all whitespace, insert a line ending at the beginning of + // the current line. This makes the current line empty and the new line contain the + // indentation of the old line. + new_text.push_str(doc.line_ending.as_str()); + + (line_start, line_start, new_text.chars().count() as isize) }; let new_range = if range.cursor(text) > range.anchor { // when appending, extend the range by local_offs Range::new( range.anchor + global_offs, - range.head + local_offs + global_offs, + (range.head as isize + local_offs) as usize + global_offs, ) } else { // when inserting, slide the range by local_offs Range::new( - range.anchor + local_offs + global_offs, - range.head + local_offs + global_offs, + (range.anchor as isize + local_offs) as usize + global_offs, + (range.head as isize + local_offs) as usize + global_offs, ) }; diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 7402a06f3233..49864abb683e 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -9,6 +9,7 @@ use super::*; use helix_core::fuzzy::fuzzy_match; use helix_core::indent::MAX_INDENT; use helix_core::{line_ending, shellwords::Shellwords}; +use helix_stdx::path::home_dir; use helix_view::document::{read_to_string, DEFAULT_LANGUAGE_NAME}; use helix_view::editor::{CloseError, ConfigEvent}; use serde_json::Value; @@ -456,13 +457,15 @@ fn format( } let (view, doc) = current!(cx.editor); - if let Some(format) = doc.format() { - let callback = make_format_callback(doc.id(), doc.version(), view.id, format, None); - cx.jobs.callback(callback); - } + let format = doc.format().context( + "A formatter isn't available, and no language server provides formatting capabilities", + )?; + let callback = make_format_callback(doc.id(), doc.version(), view.id, format, None); + cx.jobs.callback(callback); Ok(()) } + fn set_indent_style( cx: &mut compositor::Context, args: &[Cow], @@ -1087,18 +1090,23 @@ fn change_current_directory( return Ok(()); } - let dir = args - .first() - .context("target directory not provided")? - .as_ref(); - let dir = helix_stdx::path::expand_tilde(Path::new(dir)); + let dir = match args.first().map(AsRef::as_ref) { + Some("-") => cx + .editor + .last_cwd + .clone() + .ok_or(anyhow!("No previous working directory"))?, + Some(input_path) => helix_stdx::path::expand_tilde(Path::new(input_path)).to_path_buf(), + None => home_dir()?, + }; - helix_stdx::env::set_current_working_dir(dir)?; + cx.editor.last_cwd = helix_stdx::env::set_current_working_dir(dir)?; cx.editor.set_status(format!( "Current working directory is now {}", helix_stdx::env::current_working_dir().display() )); + Ok(()) } @@ -2636,7 +2644,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { name: "format", aliases: &["fmt"], - doc: "Format the file using the LSP formatter.", + doc: "Format the file using an external formatter or language server.", fun: format, signature: CommandSignature::none(), }, diff --git a/helix-term/src/compositor.rs b/helix-term/src/compositor.rs index 3dcb5f2bfcbc..a57fd6177c47 100644 --- a/helix-term/src/compositor.rs +++ b/helix-term/src/compositor.rs @@ -27,7 +27,7 @@ pub struct Context<'a> { pub jobs: &'a mut Jobs, } -impl<'a> Context<'a> { +impl Context<'_> { /// Waits on all pending jobs, and then tries to flush all pending write /// operations for all documents. pub fn block_try_flush_writes(&mut self) -> anyhow::Result<()> { diff --git a/helix-term/src/health.rs b/helix-term/src/health.rs index e59fd74dc1f0..54789b8997a6 100644 --- a/helix-term/src/health.rs +++ b/helix-term/src/health.rs @@ -154,7 +154,7 @@ pub fn languages_all() -> std::io::Result<()> { } }; - let mut headings = vec!["Language", "LSP", "DAP", "Formatter"]; + let mut headings = vec!["Language", "Language servers", "Debug adapter", "Formatter"]; for feat in TsFeature::all() { headings.push(feat.short_title()) diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index 5a3e8eed42da..c6cefd927574 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -140,7 +140,8 @@ pub fn default() -> HashMap { "?" => rsearch, "n" => search_next, "N" => search_prev, - "*" => search_selection, + "*" => search_selection_detect_word_boundaries, + "A-*" => search_selection, "u" => undo, "U" => redo, diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs index a3a27a07626a..516bfd7c31b1 100644 --- a/helix-term/src/main.rs +++ b/helix-term/src/main.rs @@ -154,8 +154,7 @@ FLAGS: }); // TODO: use the thread local executor to spawn the application task separately from the work pool - let mut app = - Application::new(args, config, lang_loader).context("unable to create new application")?; + let mut app = Application::new(args, config, lang_loader).context("unable to start Helix")?; let exit_code = app.run(&mut EventStream::new()).await?; diff --git a/helix-term/src/ui/document.rs b/helix-term/src/ui/document.rs index ae00ea149490..d1a74e7e2bc4 100644 --- a/helix-term/src/ui/document.rs +++ b/helix-term/src/ui/document.rs @@ -522,8 +522,6 @@ impl<'a> TextRenderer<'a> { self.surface.set_style(area, style); } - /// Sets the style of an area **within the text viewport* this accounts - /// both for the renderers vertical offset and its viewport #[allow(clippy::too_many_arguments)] pub fn set_string_truncated( &mut self, diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs index ffe3ebb3cbf5..612832ce1221 100644 --- a/helix-term/src/ui/menu.rs +++ b/helix-term/src/ui/menu.rs @@ -346,10 +346,6 @@ impl Component for Menu { let win_height = area.height as usize; - const fn div_ceil(a: usize, b: usize) -> usize { - (a + b - 1) / b - } - let rows = options .iter() .map(|option| option.format(&self.editor_data)); @@ -390,7 +386,7 @@ impl Component for Menu { let scroll_style = theme.get("ui.menu.scroll"); if !fits { - let scroll_height = div_ceil(win_height.pow(2), len).min(win_height); + let scroll_height = win_height.pow(2).div_ceil(len).min(win_height); let scroll_line = (win_height - scroll_height) * scroll / std::cmp::max(1, len.saturating_sub(win_height)); diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index ecf8111ab387..df8d52ebd2f8 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -72,7 +72,7 @@ impl<'a> From<&'a Path> for PathOrId<'a> { } } -impl<'a> From for PathOrId<'a> { +impl From for PathOrId<'_> { fn from(v: DocumentId) -> Self { Self::Id(v) } diff --git a/helix-term/src/ui/popup.rs b/helix-term/src/ui/popup.rs index 2cefaf61b58f..db77492db8d6 100644 --- a/helix-term/src/ui/popup.rs +++ b/helix-term/src/ui/popup.rs @@ -344,12 +344,8 @@ impl Component for Popup { let fits = len <= win_height; let scroll_style = cx.editor.theme.get("ui.menu.scroll"); - const fn div_ceil(a: usize, b: usize) -> usize { - (a + b - 1) / b - } - if !fits { - let scroll_height = div_ceil(win_height.pow(2), len).min(win_height); + let scroll_height = win_height.pow(2).div_ceil(len).min(win_height); let scroll_line = (win_height - scroll_height) * scroll / std::cmp::max(1, len.saturating_sub(win_height)); diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index 6ba2fcb9e251..8c7a7bafaf2d 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -233,15 +233,7 @@ impl Prompt { position } Movement::StartOfLine => 0, - Movement::EndOfLine => { - let mut cursor = - GraphemeCursor::new(self.line.len().saturating_sub(1), self.line.len(), false); - if let Ok(Some(pos)) = cursor.next_boundary(&self.line, 0) { - pos - } else { - self.cursor - } - } + Movement::EndOfLine => self.line.len(), Movement::None => self.cursor, } } @@ -415,7 +407,8 @@ impl Prompt { let cols = std::cmp::max(1, area.width / max_len); let col_width = (area.width.saturating_sub(cols)) / cols; - let height = ((self.completion.len() as u16 + cols - 1) / cols) + let height = (self.completion.len() as u16) + .div_ceil(cols) .min(10) // at most 10 rows (or less) .min(area.height.saturating_sub(1)); diff --git a/helix-term/src/ui/text_decorations/diagnostics.rs b/helix-term/src/ui/text_decorations/diagnostics.rs index 0bb0026f7cda..fb82bcf54c23 100644 --- a/helix-term/src/ui/text_decorations/diagnostics.rs +++ b/helix-term/src/ui/text_decorations/diagnostics.rs @@ -98,20 +98,29 @@ impl Renderer<'_, '_> { fn draw_eol_diagnostic(&mut self, diag: &Diagnostic, row: u16, col: usize) -> u16 { let style = self.styles.severity_style(diag.severity()); let width = self.renderer.viewport.width; - if !self.renderer.column_in_bounds(col + 1, 1) { - return 0; + let start_col = (col - self.renderer.offset.col) as u16; + let mut end_col = start_col; + let mut draw_col = (col + 1) as u16; + + for line in diag.message.lines() { + if !self.renderer.column_in_bounds(draw_col as usize, 1) { + break; + } + + (end_col, _) = self.renderer.set_string_truncated( + self.renderer.viewport.x + draw_col, + row, + line, + width.saturating_sub(draw_col) as usize, + |_| style, + true, + false, + ); + + draw_col = end_col - self.renderer.viewport.x + 2; // double space between lines } - let col = (col - self.renderer.offset.col) as u16; - let (new_col, _) = self.renderer.set_string_truncated( - self.renderer.viewport.x + col + 1, - row, - &diag.message, - width.saturating_sub(col + 1) as usize, - |_| style, - true, - false, - ); - new_col - col + + end_col - start_col } fn draw_diagnostic(&mut self, diag: &Diagnostic, col: u16, next_severity: Option) { diff --git a/helix-term/tests/test/commands.rs b/helix-term/tests/test/commands.rs index f71ae308d641..32badaa415fe 100644 --- a/helix-term/tests/test/commands.rs +++ b/helix-term/tests/test/commands.rs @@ -2,6 +2,7 @@ use helix_term::application::Application; use super::*; +mod insert; mod movement; mod write; diff --git a/helix-term/tests/test/commands/insert.rs b/helix-term/tests/test/commands/insert.rs new file mode 100644 index 000000000000..f7aa4a020fb4 --- /dev/null +++ b/helix-term/tests/test/commands/insert.rs @@ -0,0 +1,246 @@ +use super::*; + +#[tokio::test(flavor = "multi_thread")] +async fn insert_newline_trim_trailing_whitespace() -> anyhow::Result<()> { + // Trailing whitespace is trimmed. + test(( + indoc! {"\ + hello·······#[| + ]#world + "} + .replace('·', " "), + "i", + indoc! {"\ + hello + #[| + ]#world + "} + .replace('·', " "), + )) + .await?; + + // Whitespace that would become trailing is trimmed too. + test(( + indoc! {"\ + hello········#[|w]#orld + "} + .replace('·', " "), + "i", + indoc! {"\ + hello + #[|w]#orld + "} + .replace('·', " "), + )) + .await?; + + // Only whitespace before the cursor is trimmed. + test(( + indoc! {"\ + hello········#[|·]#····world + "} + .replace('·', " "), + "i", + indoc! {"\ + hello + #[|·]#····world + "} + .replace('·', " "), + )) + .await?; + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn insert_newline_continue_line_comment() -> anyhow::Result<()> { + // `insert_newline` continues a single line comment + test(( + indoc! {"\ + // Hello world!#[| + ]# + "}, + ":lang rusti", + indoc! {"\ + // Hello world! + // #[| + ]# + "}, + )) + .await?; + + // The comment is not continued if the cursor is before the comment token. (Note that we + // are entering insert-mode with `I`.) + test(( + indoc! {"\ + // Hello world!#[| + ]# + "}, + ":lang rustI", + indoc! {"\ + \n#[/|]#/ Hello world! + "}, + )) + .await?; + + // `insert_newline` again clears the whitespace on the first continued comment and continues + // the comment again. + test(( + indoc! {"\ + // Hello world! + // #[| + ]# + "}, + ":lang rusti", + indoc! {"\ + // Hello world! + // + // #[| + ]# + "}, + )) + .await?; + + // Line comment continuation and trailing whitespace is also trimmed when using + // `insert_newline` in the middle of a comment. + test(( + indoc! {"\ + //·hello····#[|·]#····world + "} + .replace('·', " "), + ":lang rusti", + indoc! {"\ + //·hello + //·#[|·]#····world + "} + .replace('·', " "), + )) + .await?; + + Ok(()) +} + +/// NOTE: Language is set to markdown to check if the indentation is correct for the new line +#[tokio::test(flavor = "multi_thread")] +async fn test_open_above() -> anyhow::Result<()> { + // `O` is pressed in the first line + test(( + indoc! {"Helix #[is|]# cool"}, + ":lang markdownO", + indoc! {"\ + #[\n|]# + Helix is cool + "}, + )) + .await?; + + // `O` is pressed in the first line, but the current line has some indentation + test(( + indoc! {"\ + ··This line has 2 spaces in front of it#[\n|]# + "} + .replace('·', " "), + ":lang markdownOa", + indoc! {"\ + ··a#[\n|]# + ··This line has 2 spaces in front of it + "} + .replace('·', " "), + )) + .await?; + + // `O` is pressed but *not* in the first line + test(( + indoc! {"\ + I use + b#[t|]#w. + "}, + ":lang markdownOarch", + indoc! {"\ + I use + arch#[\n|]# + btw. + "}, + )) + .await?; + + // `O` is pressed but *not* in the first line and the line has some indentation + test(( + indoc! {"\ + I use + ····b#[t|]#w. + "} + .replace("·", " "), + ":lang markdownOhelix", + indoc! {"\ + I use + ····helix#[\n|]# + ····btw. + "} + .replace("·", " "), + )) + .await?; + + Ok(()) +} + +/// NOTE: To make the `open_above` comment-aware, we're setting the language for each test to rust. +#[tokio::test(flavor = "multi_thread")] +async fn test_open_above_with_comments() -> anyhow::Result<()> { + // `O` is pressed in the first line inside a line comment + test(( + indoc! {"// a commen#[t|]#"}, + ":lang rustO", + indoc! {"\ + // #[\n|]# + // a comment + "}, + )) + .await?; + + // `O` is pressed in the first line inside a line comment, but with indentation + test(( + indoc! {"····// a comm#[e|]#nt"}.replace("·", " "), + ":lang rustO", + indoc! {"\ + ····// #[\n|]# + ····// a comment + "} + .replace("·", " "), + )) + .await?; + + // `O` is pressed but not in the first line but inside a line comment + test(( + indoc! {"\ + fn main() { } + // yeetus deletus#[\n|]# + "}, + ":lang rustO", + indoc! {"\ + fn main() { } + // #[\n|]# + // yeetus deletus + "}, + )) + .await?; + + // `O` is pressed but not in the first line but inside a line comment and with indentation + test(( + indoc! {"\ + fn main() { } + ····// yeetus deletus#[\n|]# + "} + .replace("·", " "), + ":lang rustO", + indoc! {"\ + fn main() { } + ····// #[\n|]# + ····// yeetus deletus + "} + .replace("·", " "), + )) + .await?; + + Ok(()) +} diff --git a/helix-term/tests/test/languages/yaml.rs b/helix-term/tests/test/languages/yaml.rs index 10e1861d475b..1d95964005fe 100644 --- a/helix-term/tests/test/languages/yaml.rs +++ b/helix-term/tests/test/languages/yaml.rs @@ -795,7 +795,7 @@ async fn auto_indent() -> anyhow::Result<()> { "##}, "i", indoc! {"\ - foo: + foo: #[|b]#ar "}, ), diff --git a/helix-tui/src/text.rs b/helix-tui/src/text.rs index a5e8a68af8fc..c4313e15fc12 100644 --- a/helix-tui/src/text.rs +++ b/helix-tui/src/text.rs @@ -212,7 +212,7 @@ impl<'a> From> for Span<'a> { #[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct Spans<'a>(pub Vec>); -impl<'a> Spans<'a> { +impl Spans<'_> { /// Returns the width of the underlying string. /// /// ## Examples diff --git a/helix-tui/src/widgets/block.rs b/helix-tui/src/widgets/block.rs index 8b8141ea931b..ee7aa7573a9e 100644 --- a/helix-tui/src/widgets/block.rs +++ b/helix-tui/src/widgets/block.rs @@ -123,7 +123,7 @@ impl<'a> Block<'a> { } } -impl<'a> Widget for Block<'a> { +impl Widget for Block<'_> { fn render(self, area: Rect, buf: &mut Buffer) { if area.area() == 0 { return; diff --git a/helix-tui/src/widgets/paragraph.rs b/helix-tui/src/widgets/paragraph.rs index 79beb0516228..73153a077e03 100644 --- a/helix-tui/src/widgets/paragraph.rs +++ b/helix-tui/src/widgets/paragraph.rs @@ -129,7 +129,7 @@ impl<'a> Paragraph<'a> { } } -impl<'a> Widget for Paragraph<'a> { +impl Widget for Paragraph<'_> { fn render(mut self, area: Rect, buf: &mut Buffer) { buf.set_style(area, self.style); let text_area = match self.block.take() { diff --git a/helix-tui/src/widgets/reflow.rs b/helix-tui/src/widgets/reflow.rs index 67c4db443892..ff102eb1954f 100644 --- a/helix-tui/src/widgets/reflow.rs +++ b/helix-tui/src/widgets/reflow.rs @@ -39,7 +39,7 @@ impl<'a, 'b> WordWrapper<'a, 'b> { } } -impl<'a, 'b> LineComposer<'a> for WordWrapper<'a, 'b> { +impl<'a> LineComposer<'a> for WordWrapper<'a, '_> { fn next_line(&mut self) -> Option<(&[StyledGrapheme<'a>], u16)> { if self.max_line_width == 0 { return None; @@ -152,7 +152,7 @@ impl<'a, 'b> LineTruncator<'a, 'b> { } } -impl<'a, 'b> LineComposer<'a> for LineTruncator<'a, 'b> { +impl<'a> LineComposer<'a> for LineTruncator<'a, '_> { fn next_line(&mut self) -> Option<(&[StyledGrapheme<'a>], u16)> { if self.max_line_width == 0 { return None; diff --git a/helix-tui/src/widgets/table.rs b/helix-tui/src/widgets/table.rs index 3564871deec3..9c67a376fdea 100644 --- a/helix-tui/src/widgets/table.rs +++ b/helix-tui/src/widgets/table.rs @@ -34,7 +34,7 @@ pub struct Cell<'a> { style: Style, } -impl<'a> Cell<'a> { +impl Cell<'_> { /// Set the `Style` of this cell. pub fn style(mut self, style: Style) -> Self { self.style = style; @@ -351,7 +351,7 @@ impl TableState { } // impl<'a> StatefulWidget for Table<'a> { -impl<'a> Table<'a> { +impl Table<'_> { // type State = TableState; pub fn render_table( @@ -486,7 +486,7 @@ fn render_cell(buf: &mut Buffer, cell: &Cell, area: Rect, truncate: bool) { } } -impl<'a> Widget for Table<'a> { +impl Widget for Table<'_> { fn render(self, area: Rect, buf: &mut Buffer) { let mut state = TableState::default(); Table::render_table(self, area, buf, &mut state, false); diff --git a/helix-vcs/Cargo.toml b/helix-vcs/Cargo.toml index 919df04acc3e..8d3f55a66eb4 100644 --- a/helix-vcs/Cargo.toml +++ b/helix-vcs/Cargo.toml @@ -19,7 +19,7 @@ tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "p parking_lot = "0.12" arc-swap = { version = "1.7.1" } -gix = { version = "0.67.0", features = ["attributes", "status"], default-features = false, optional = true } +gix = { version = "0.68.0", features = ["attributes", "status"], default-features = false, optional = true } imara-diff = "0.1.7" anyhow = "1" diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index 6bbe1586855f..6f71fa05204f 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -32,7 +32,7 @@ tempfile = "3.14" # Conversion traits once_cell = "1.20" -url = "2.5.3" +url = "2.5.4" arc-swap = { version = "1.7.1" } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 3b49de508994..e7257675620c 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -305,6 +305,9 @@ pub struct Config { /// Whether to instruct the LSP to replace the entire word when applying a completion /// or to only insert new text pub completion_replace: bool, + /// `true` if helix should automatically add a line comment token if you're currently in a comment + /// and press `enter`. + pub continue_comments: bool, /// Whether to display infoboxes. Defaults to true. pub auto_info: bool, pub file_picker: FilePickerConfig, @@ -986,6 +989,7 @@ impl Default for Config { }, text_width: 80, completion_replace: false, + continue_comments: true, workspace_lsp_roots: Vec::new(), default_line_ending: LineEndingConfig::default(), insert_final_newline: true, @@ -1074,6 +1078,7 @@ pub struct Editor { redraw_timer: Pin>, last_motion: Option, pub last_completion: Option, + pub last_cwd: Option, pub exit_code: i32, @@ -1207,6 +1212,7 @@ impl Editor { redraw_timer: Box::pin(sleep(Duration::MAX)), last_motion: None, last_completion: None, + last_cwd: None, config, auto_pairs, exit_code: 0, @@ -1717,10 +1723,14 @@ impl Editor { Ok(doc_id) } + pub fn document_id_by_path(&self, path: &Path) -> Option { + self.document_by_path(path).map(|doc| doc.id) + } + // ??? possible use for integration tests pub fn open(&mut self, path: &Path, action: Action) -> Result { let path = helix_stdx::path::canonicalize(path); - let id = self.document_by_path(&path).map(|doc| doc.id); + let id = self.document_id_by_path(&path); let id = if let Some(id) = id { id diff --git a/helix-view/src/input.rs b/helix-view/src/input.rs index 5f5067eac9f8..d359db703424 100644 --- a/helix-view/src/input.rs +++ b/helix-view/src/input.rs @@ -162,7 +162,12 @@ pub(crate) mod keys { impl fmt::Display for KeyEvent { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result { f.write_fmt(format_args!( - "{}{}{}", + "{}{}{}{}", + if self.modifiers.contains(KeyModifiers::SUPER) { + "Meta-" + } else { + "" + }, if self.modifiers.contains(KeyModifiers::SHIFT) { "S-" } else { @@ -312,6 +317,10 @@ impl UnicodeWidthStr for KeyEvent { if self.modifiers.contains(KeyModifiers::CONTROL) { width += 2; } + if self.modifiers.contains(KeyModifiers::SUPER) { + // "-Meta" + width += 5; + } width } @@ -387,6 +396,23 @@ impl std::str::FromStr for KeyEvent { .then_some(KeyCode::F(function)) .ok_or_else(|| anyhow!("Invalid function key '{}'", function))? } + // Checking that the last token is empty ensures that this branch is only taken if + // `-` is used as a code. For example this branch will not be taken for `S-` (which is + // missing a code). + _ if s.ends_with('-') && tokens.last().is_some_and(|t| t.is_empty()) => { + if s == "-" { + return Ok(KeyEvent { + code: KeyCode::Char('-'), + modifiers: KeyModifiers::empty(), + }); + } else { + let suggestion = format!("{}-{}", s.trim_end_matches('-'), keys::MINUS); + return Err(anyhow!( + "Key '-' cannot be used with modifiers, use '{}' instead", + suggestion + )); + } + } invalid => return Err(anyhow!("Invalid key code '{}'", invalid)), }; @@ -396,6 +422,7 @@ impl std::str::FromStr for KeyEvent { "S" => KeyModifiers::SHIFT, "A" => KeyModifiers::ALT, "C" => KeyModifiers::CONTROL, + "Meta" | "Cmd" | "Win" => KeyModifiers::SUPER, _ => return Err(anyhow!("Invalid key modifier '{}-'", token)), }; @@ -661,6 +688,13 @@ mod test { modifiers: KeyModifiers::NONE } ); + assert_eq!( + str::parse::("-").unwrap(), + KeyEvent { + code: KeyCode::Char('-'), + modifiers: KeyModifiers::NONE, + } + ); } #[test] @@ -709,6 +743,28 @@ mod test { modifiers: KeyModifiers::NONE } ); + + assert_eq!( + str::parse::("Meta-c").unwrap(), + KeyEvent { + code: KeyCode::Char('c'), + modifiers: KeyModifiers::SUPER + } + ); + assert_eq!( + str::parse::("Win-s").unwrap(), + KeyEvent { + code: KeyCode::Char('s'), + modifiers: KeyModifiers::SUPER + } + ); + assert_eq!( + str::parse::("Cmd-d").unwrap(), + KeyEvent { + code: KeyCode::Char('d'), + modifiers: KeyModifiers::SUPER + } + ); } #[test] @@ -721,6 +777,7 @@ mod test { assert!(str::parse::("FU").is_err()); assert!(str::parse::("123").is_err()); assert!(str::parse::("S--").is_err()); + assert!(str::parse::("S-").is_err()); assert!(str::parse::("S-percent").is_err()); } diff --git a/helix-view/src/keyboard.rs b/helix-view/src/keyboard.rs index 080bce8ddc2a..d816a52ef78e 100644 --- a/helix-view/src/keyboard.rs +++ b/helix-view/src/keyboard.rs @@ -7,6 +7,7 @@ bitflags! { const SHIFT = 0b0000_0001; const CONTROL = 0b0000_0010; const ALT = 0b0000_0100; + const SUPER = 0b0000_1000; const NONE = 0b0000_0000; } } @@ -27,6 +28,9 @@ impl From for crossterm::event::KeyModifiers { if key_modifiers.contains(KeyModifiers::ALT) { result.insert(CKeyModifiers::ALT); } + if key_modifiers.contains(KeyModifiers::SUPER) { + result.insert(CKeyModifiers::SUPER); + } result } @@ -48,6 +52,9 @@ impl From for KeyModifiers { if val.contains(CKeyModifiers::ALT) { result.insert(KeyModifiers::ALT); } + if val.contains(CKeyModifiers::SUPER) { + result.insert(KeyModifiers::SUPER); + } result } diff --git a/helix-view/src/register.rs b/helix-view/src/register.rs index 3f7844cd6d7f..d286a85ccafe 100644 --- a/helix-view/src/register.rs +++ b/helix-view/src/register.rs @@ -5,7 +5,7 @@ use arc_swap::access::DynAccess; use helix_core::NATIVE_LINE_ENDING; use crate::{ - clipboard::{ClipboardProvider, ClipboardType}, + clipboard::{ClipboardError, ClipboardProvider, ClipboardType}, Editor, }; @@ -238,6 +238,10 @@ fn read_from_clipboard<'a>( RegisterValues::new(iter::once(contents.into())) } } + Err(ClipboardError::ReadingNotSupported) => match saved_values { + Some(values) => RegisterValues::new(values.iter().map(Cow::from).rev()), + None => RegisterValues::new(iter::empty()), + }, Err(err) => { log::error!( "Failed to read {} clipboard: {err}", @@ -307,13 +311,13 @@ impl<'a> Iterator for RegisterValues<'a> { } } -impl<'a> DoubleEndedIterator for RegisterValues<'a> { +impl DoubleEndedIterator for RegisterValues<'_> { fn next_back(&mut self) -> Option { self.iter.next_back() } } -impl<'a> ExactSizeIterator for RegisterValues<'a> { +impl ExactSizeIterator for RegisterValues<'_> { fn len(&self) -> usize { self.iter.len() } diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index 9dc326444b9b..fca47413c1e1 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -280,7 +280,7 @@ fn build_theme_values( for (name, style_value) in values { let mut style = Style::default(); if let Err(err) = palette.parse_style(&mut style, style_value) { - warnings.push(err); + warnings.push(format!("Failed to parse style for key {name:?}. {err}")); } // these are used both as UI and as highlights diff --git a/helix-view/src/tree.rs b/helix-view/src/tree.rs index be8bd4e5bcf5..aba947a218cc 100644 --- a/helix-view/src/tree.rs +++ b/helix-view/src/tree.rs @@ -705,7 +705,7 @@ impl<'a> Iterator for Traverse<'a> { } } -impl<'a> DoubleEndedIterator for Traverse<'a> { +impl DoubleEndedIterator for Traverse<'_> { fn next_back(&mut self) -> Option { loop { let key = self.stack.pop()?; diff --git a/languages.toml b/languages.toml index 0acb7f420663..426778b4cb72 100644 --- a/languages.toml +++ b/languages.toml @@ -62,7 +62,7 @@ marksman = { command = "marksman", args = ["server"] } metals = { command = "metals", config = { "isHttpEnabled" = true, metals = { inlayHints = { typeParameters = {enable = true} , hintsInPatternMatch = {enable = true} } } } } mesonlsp = { command = "mesonlsp", args = ["--lsp"] } mint = { command = "mint", args = ["ls"] } -mojo-lsp = { command = "mojo-lsp-server" } +mojo-lsp = { command = "magic", args = ["run", "mojo-lsp-server"] } nil = { command = "nil" } nimlangserver = { command = "nimlangserver" } nimlsp = { command = "nimlsp" } @@ -123,6 +123,7 @@ tinymist = { command = "tinymist" } pkgbuild-language-server = { command = "pkgbuild-language-server" } helm_ls = { command = "helm_ls", args = ["serve"] } ember-language-server = { command = "ember-language-server", args = ["--stdio"] } +teal-language-server = { command = "teal-language-server" } [language-server.ansible-language-server] command = "ansible-language-server" @@ -411,7 +412,7 @@ language-servers = [ "mojo-lsp" ] comment-token = "#" indent = { tab-width = 4, unit = " " } auto-format = true -formatter = { command = "mojo", args = ["format", "-q", "-"]} +formatter = { command = "magic", args = ["run", "mojo" , "format", "-q", "-"]} [[grammar]] name = "mojo" @@ -1297,6 +1298,20 @@ language-servers = [ "lua-language-server" ] name = "lua" source = { git = "https://github.com/tree-sitter-grammars/tree-sitter-lua", rev = "88e446476a1e97a8724dff7a23e2d709855077f2" } +[[grammar]] +name = "teal" +source = { git = "https://github.com/euclidianAce/tree-sitter-teal", rev = "3db655924b2ff1c54fdf6371b5425ea6b5dccefe" } + +[[language]] +name = "teal" +scope = "source.tl" +injection-regex = "teal" +file-types = ["tl"] +comment-tokens = "--" +block-comment-tokens = { start = "--[[", end = "--]]" } +roots = [ "tlconfig.lua" ] +language-servers = [ "teal-lsp" ] + [[language]] name = "svelte" scope = "source.svelte" @@ -2271,7 +2286,7 @@ indent = { tab-width = 4, unit = "\t" } [[grammar]] name = "v" -source = {git = "https://github.com/v-analyzer/v-analyzer", subpath = "tree_sitter_v", rev = "e14fdf6e661b10edccc744102e4ccf0b187aa8ad"} +source = {git = "https://github.com/vlang/v-analyzer", subpath = "tree_sitter_v", rev = "e14fdf6e661b10edccc744102e4ccf0b187aa8ad"} [[language]] name = "verilog" @@ -2540,11 +2555,11 @@ source = { git = "https://github.com/sourcegraph/tree-sitter-jsonnet", rev = "04 name = "ada" scope = "source.ada" injection-regex = "ada" -file-types = ["adb", "ads", "gpr"] +file-types = ["adb", "ads"] roots = ["alire.toml"] comment-token = "--" indent = { tab-width = 3, unit = " " } -language-servers = ["ada-language-server", "ada-gpr-language-server"] +language-servers = ["ada-language-server"] [[grammar]] @@ -3168,7 +3183,7 @@ indent = { tab-width = 4, unit = " " } [[grammar]] name = "just" -source = { git = "https://github.com/poliorcetics/tree-sitter-just", rev = "6e28fa6cba511c694247cd802d1c3b14f8d34dbb" } +source = { git = "https://github.com/poliorcetics/tree-sitter-just", rev = "180bb15d64c63585c4f65c551350048f21987bcb" } [[language]] name = "gn" @@ -3463,7 +3478,11 @@ source = { git = "https://github.com/urbit-pilled/tree-sitter-hoon", rev = "1d5d [[language]] name = "hocon" scope = "source.conf" -file-types = ["conf"] +file-types = [ + { glob = "**/src/*/resources/**/*.conf" }, + { glob = "*scalafmt*.conf" }, + { glob = "*scalafix*.conf" }, +] comment-token = "#" auto-format = true indent = { tab-width = 2, unit = " " } @@ -3942,3 +3961,28 @@ indent = { tab-width = 4, unit = " " } [[grammar]] name = "amber" source = { git = "https://github.com/amber-lang/tree-sitter-amber", rev = "c6df3ec2ec243ed76550c525e7ac3d9a10c6c814" } + +[[language]] +name = "gpr" +scope = "source.gpr" +injection-regex = "gpr" +file-types = ["gpr"] +roots = ["alire.toml"] +comment-token = "--" +indent = { tab-width = 3, unit = " " } +language-servers = ["ada-gpr-language-server"] + +[[grammar]] +name = "gpr" +source = { git = "https://github.com/brownts/tree-sitter-gpr", rev = "cea857d3c18d1385d1f5b66cd09ea1e44173945c" } + +[[language]] +name = "vento" +scope = "text.html.vto" +file-types = ["vto"] +block-comment-tokens = { start = "{{#", end = "#}}" } +indent = { tab-width = 4, unit = " " } + +[[grammar]] +name = "vento" +source = { git = "https://github.com/ventojs/tree-sitter-vento", rev = "3321077d7446c1b3b017c294fd56ce028ed817fe" } diff --git a/pr.md b/pr.md deleted file mode 100644 index 0ea65a5adfb3..000000000000 --- a/pr.md +++ /dev/null @@ -1,24 +0,0 @@ -Syntax symbol pickers -== - -This adds two new symbol picker commands that use tree-sitter rather than LSP. We run a new `symbols.scm` query across the file and extract tagged things like function definitions, types, classes, etc. For languages with unambiguous syntax this behaves roughly the same as the LSP symbol picker (`s`). It's less precise though since we don't have semantic info about the language. For example it can easily produce false positives for C/C++ because of preprocessor magic. - -The hope is to start introducing LSP-like features for navigation that can work without installing or running a language server. I made these two pickers in particular because I don't like LSP equivalents in ErlangLS - the document symbol picker can take a long time to show up during boot and the workspace symbol picker only searches for module names. The other motivation is to have some navigation features in cases when running a language server is too cumbersome - either to set up or because of resource constraints. For example `clangd` needs a fair amount of setup (`compile_commands.json`) that you might not want to do when quickly reading through a codebase. - -GitHub already uses tree-sitter like this to provide [imprecise code navigation](https://docs.github.com/en/repositories/working-with-files/using-files/navigating-code-on-github#about-navigating-code-on-github). It should be possible to find definitions and references as well like `gd` and `gr` - this is left as a follow-up. - -This PR also adds commands that either open the LSP symbol picker or the syntax one if a language server is not available. This way you can customize a language to not use the LSP symbol pickers, for example: - -```toml -[[language]] -name = "erlang" -language-servers = [{ name = "erlang-ls", except-features = ["document-symbols", "workspace-symbols"] }] -``` - -and `s` will use the syntax symbol picker, while `s` on a Rust file will still prefer the language server. - ---- - -Outstanding question - how closely should we try to match LSP symbol kind? Not at all? Should we have markup specific symbol kinds? (For example see markdown's `symbols.scm`). - -Also this PR needs docs on writing `symbols.scm` queries. diff --git a/runtime/queries/comment/highlights.scm b/runtime/queries/comment/highlights.scm index 8d1232453a31..e88288d5d621 100644 --- a/runtime/queries/comment/highlights.scm +++ b/runtime/queries/comment/highlights.scm @@ -21,10 +21,10 @@ ; Error level tags ((tag (name) @error) - (#match? @error "^(BUG|FIXME|ISSUE|XXX|FIX|SAFETY|FIXIT|FAILED|DEBUG|INVARIANT)$")) + (#match? @error "^(BUG|FIXME|ISSUE|XXX|FIX|SAFETY|FIXIT|FAILED|DEBUG|INVARIANT|COMPLIANCE)$")) ("text" @error - (#match? @error "^(BUG|FIXME|ISSUE|XXX|FIX|SAFETY|FIXIT|FAILED|DEBUG|INVARIANT)$")) + (#match? @error "^(BUG|FIXME|ISSUE|XXX|FIX|SAFETY|FIXIT|FAILED|DEBUG|INVARIANT|COMPLIANCE)$")) (tag (name) @ui.text diff --git a/runtime/queries/gpr/highlights.scm b/runtime/queries/gpr/highlights.scm new file mode 100644 index 000000000000..9d24928b1353 --- /dev/null +++ b/runtime/queries/gpr/highlights.scm @@ -0,0 +1,51 @@ +[ "abstract" "all" "at" + "case" + "end" "extends" "external" "external_as_list" + "for" + "is" + "limited" + "null" + "others" + "package" + ;; "project" + "renames" + "type" + "use" + "when" + "with" + ] @keyword + +;; Avoid highlighting Project in Project'Project_Dir +(project_declaration "project" @keyword) + +;; highlight qualifiers as keywords (not all qualifiers are actual keywords) +(project_qualifier _ @keyword) + +[":=" "&" "|" "=>"] @operator + +(comment) @comment +(string_literal) @string +(numeric_literal) @constant.numeric + +;; Type +(typed_string_declaration name: (identifier) @type) +(variable_declaration type: (name (identifier) @type .)) + +;; Variable +(variable_declaration name: (identifier) @variable) +(variable_reference (name (identifier) @variable .) .) + +;; Function +(builtin_function_call name: _ @function.builtin) + +;; Attribute +(attribute_declaration name: (identifier) @attribute) +(attribute_reference (identifier) @attribute) + +;; Package +(variable_reference (name (identifier) @function .) "'") +(package_declaration + [ name: (identifier) @function + endname: (identifier) @function + origname: (name (identifier) @function .) + basename: (name (identifier) @function .)]) diff --git a/runtime/queries/just/highlights.scm b/runtime/queries/just/highlights.scm index 258fadb9e1da..97a997619b49 100644 --- a/runtime/queries/just/highlights.scm +++ b/runtime/queries/just/highlights.scm @@ -3,6 +3,7 @@ [ "export" "import" + "unexport" ] @keyword.control.import "mod" @keyword.directive @@ -18,6 +19,11 @@ "else" ] @keyword.control.conditional +[ + "&&" + "||" +] @operator + ; Variables (value @@ -31,6 +37,9 @@ (shell_variable_name) @variable +(unexport + name: (identifier) @variable) + ; Functions (recipe diff --git a/runtime/queries/teal/folds.scm b/runtime/queries/teal/folds.scm new file mode 100644 index 000000000000..e756719a4f90 --- /dev/null +++ b/runtime/queries/teal/folds.scm @@ -0,0 +1,15 @@ +[ +(do_statement) +(numeric_for_statement) +(generic_for_statement) +(while_statement) +(repeat_statement) +(if_statement) +(function_statement) +(record_declaration) +(interface_declaration) +(enum_declaration) +(anon_function) +(table_constructor) +] @fold + diff --git a/runtime/queries/teal/highlights.scm b/runtime/queries/teal/highlights.scm new file mode 100644 index 000000000000..0aa41b19a247 --- /dev/null +++ b/runtime/queries/teal/highlights.scm @@ -0,0 +1,170 @@ + +;; Primitives +(boolean) @constant.builtin.boolean +(comment) @comment +(shebang_comment) @comment +(identifier) @variable +((identifier) @variable.builtin + (#eq? @variable.builtin "self")) +(nil) @constant.builtin +(number) @constant.numeric +(string) @string +(table_constructor ["{" "}"] @constructor) +(varargs "..." @constant.builtin) +[ "," "." ":" ";" ] @punctuation.delimiter + +(escape_sequence) @constant.character.escape +(format_specifier) @constant.character.escape + +;; Basic statements/Keywords +[ "if" "then" "elseif" "else" ] @keyword.control.conditional +[ "for" "while" "repeat" "until" "do" ] @keyword.control.repeat +[ "end" ] @keyword +[ "in" ] @keyword.operator +[ "local" ] @keyword.storage.type +[ (break) (goto) ] @keyword.control +[ "return" ] @keyword.control.return +(label) @label + +;; Global isn't a real keyword, but it gets special treatment in these places +(var_declaration "global" @keyword.storage.type) +(type_declaration "global" @keyword.storage.type) +(function_statement "global" @keyword.storage.type) +(record_declaration "global" @keyword.storage.type) +(interface_declaration "global" @keyword.storage.type) +(enum_declaration "global" @keyword.storage.type) + +(macroexp_statement "macroexp" @keyword) + +;; Ops +(bin_op (op) @operator) +(unary_op (op) @operator) +[ "=" "as" ] @operator + +;; Functions +(function_statement + "function" @keyword.function + . name: (_) @function) +(anon_function + "function" @keyword.function) +(function_body "end" @keyword.function) + +(arg name: (identifier) @variable.parameter) + +(function_signature + (arguments + . (arg name: (identifier) @variable.builtin)) + (#eq? @variable.builtin "self")) + +(typeargs + "<" @punctuation.bracket + . (_) @type.parameter + . ("," . (_) @type.parameter)* + . ">" @punctuation.bracket) + +(function_call + (identifier) @function . (arguments)) +(function_call + (index (_) key: (identifier) @function) . (arguments)) +(function_call + (method_index (_) key: (identifier) @function) . (arguments)) + +;; Types + +; Contextual keywords in record bodies +(record_declaration + . [ "record" ] @keyword.storage.type + name: (identifier) @type) +(anon_record . "record" @keyword.storage.type) +(record_body + (record_declaration + . [ "record" ] @keyword.storage.type + . name: (identifier) @type)) +(record_body + (enum_declaration + . [ "enum" ] @keyword.storage.type + . name: (identifier) @type.enum)) +(record_body + (interface_declaration + . [ "interface" ] @keyword.storage.type + . name: (identifier) @type)) +(record_body + (typedef + . "type" @keyword.storage.type + . name: (identifier) @type . "=")) +(record_body + (macroexp_declaration + . [ "macroexp" ] @keyword.storage.type)) +(record_body (metamethod "metamethod" @keyword.storage.modifier)) +(record_body (userdata) @keyword.storage.modifier) + +; Contextual keywords in interface bodies +(interface_declaration + . [ "interface" ] @keyword.storage.type + name: (identifier) @type) +(anon_interface . "interface" @keyword.storage.type) +(interface_body + (record_declaration + . [ "record" ] @keyword.storage.type + . name: (identifier) @type)) +(interface_body + (enum_declaration + . [ "enum" ] @keyword.storage.type + . name: (identifier) @type.enum)) +(interface_body + (interface_declaration + . [ "interface" ] @keyword.storage.type + . name: (identifier) @type)) +(interface_body + (typedef + . "type" @keyword.storage.type + . name: (identifier) @type . "=")) +(interface_body + (macroexp_declaration + . [ "macroexp" ] @keyword.storage.type)) +(interface_body (metamethod "metamethod" @keyword.storage.modifier)) +(interface_body (userdata) @keyword.storage.modifier) + +(enum_declaration + "enum" @keyword.storage.type + name: (identifier) @type.enum) + +(type_declaration "type" @keyword.storage.type) +(type_declaration (identifier) @type) +(simple_type) @type +(type_index) @type +(type_union "|" @operator) +(function_type "function" @type) + +;; The rest of it +(var_declaration + declarators: (var_declarators + (var name: (identifier) @variable))) +(var_declaration + declarators: (var_declarators + (var + "<" @punctuation.bracket + . attribute: (attribute) @attribute + . ">" @punctuation.bracket))) +[ "(" ")" "[" "]" "{" "}" ] @punctuation.bracket + +;; Only highlight format specifiers in calls to string.format +;; string.format('...') +;(function_call +; called_object: (index +; (identifier) @base +; key: (identifier) @entry) +; arguments: (arguments . +; (string (format_specifier) @string.escape)) +; +; (#eq? @base "string") +; (#eq? @entry "format")) + +;; ('...'):format() +;(function_call +; called_object: (method_index +; (string (format_specifier) @string.escape) +; key: (identifier) @func-name) +; (#eq? @func-name "format")) + + diff --git a/runtime/queries/teal/locals.scm b/runtime/queries/teal/locals.scm new file mode 100644 index 000000000000..879aa71c1a3a --- /dev/null +++ b/runtime/queries/teal/locals.scm @@ -0,0 +1,25 @@ + +(var_declaration + declarators: (var_declarators + (var (identifier)) @local.definition)) + +(var_assignment + variables: (assignment_variables + (var (identifier) @local.definition))) + +(arg name: (identifier) @local.definition) + +(anon_function) @local.scope +((function_statement + (function_name) @local.definition) @local.scope) + +(program) @local.scope +(if_statement) @local.scope +(generic_for_statement (for_body) @local.scope) +(numeric_for_statement (for_body) @local.scope) +(repeat_statement) @local.scope +(while_statement (while_body) @local.scope) +(do_statement) @local.scope + +(identifier) @local.reference + diff --git a/runtime/queries/vento/highlights.scm b/runtime/queries/vento/highlights.scm new file mode 100644 index 000000000000..4b0ba563f7ae --- /dev/null +++ b/runtime/queries/vento/highlights.scm @@ -0,0 +1,13 @@ +(comment) @comment + +(keyword) @keyword + +(tag + [ + "{{" + "{{-" + "}}" + "-}}" + ] @punctuation.bracket) + +"|>" @operator diff --git a/runtime/queries/vento/injections.scm b/runtime/queries/vento/injections.scm new file mode 100644 index 000000000000..2df984012480 --- /dev/null +++ b/runtime/queries/vento/injections.scm @@ -0,0 +1,6 @@ +((content) @injection.content + (#set! injection.language "html") + (#set! injection.combined)) + +((code) @injection.content + (#set! injection.language "javascript")) diff --git a/runtime/themes/catppuccin_mocha.toml b/runtime/themes/catppuccin_mocha.toml index 3c030762e3e2..76e65c62f7be 100644 --- a/runtime/themes/catppuccin_mocha.toml +++ b/runtime/themes/catppuccin_mocha.toml @@ -52,6 +52,8 @@ "markup.list" = "mauve" "markup.bold" = { modifiers = ["bold"] } "markup.italic" = { modifiers = ["italic"] } +"markup.list.unchecked" = "overlay2" +"markup.list.checked" = "green" "markup.link.url" = { fg = "blue", modifiers = ["italic", "underlined"] } "markup.link.text" = "blue" "markup.raw" = "flamingo" diff --git a/runtime/themes/flexoki_light.toml b/runtime/themes/flexoki_light.toml index 8badd922232c..5f8604e9f94b 100644 --- a/runtime/themes/flexoki_light.toml +++ b/runtime/themes/flexoki_light.toml @@ -26,6 +26,8 @@ "ui.menu.selected" = { bg = "ui", fg = "tx" } "ui.debug" = { fg = "or", bg = "bg" } "ui.highlight.frameline" = { bg = "ye" } +"ui.bufferline" = { fg = "tx-2", bg = "bg-2"} +"ui.bufferline.active" = { fg = "ye", bg = "bg-2" } "diagnostic.hint" = { underline = { color = "bl", style = "curl" } } "diagnostic.info" = { underline = { color = "bl", style = "curl" } } "diagnostic.warning" = { underline = { color = "ye", style = "curl" } } @@ -36,7 +38,6 @@ "info" = { fg = "ye", modifiers = ["bold"] } "warning" = { fg = "or", modifiers = ["bold"] } "error" = { fg = "re", modifiers = ["bold"] } - "attribute" = "ye" "type" = "ye" "constructor" = "gr" @@ -62,7 +63,6 @@ "function" = "or" "tag" = "bl" "namespace" = "re" - "markup.heading" = "or" "markup.list" = "ye" "markup.bold" = { fg = "or", modifiers = ["bold"] } @@ -88,6 +88,7 @@ ui = "#E6E4D9" bg-2 = "#F2F0E5" bg = "#FFFCF0" + re = "#AF3029" or = "#BC5215" ye = "#AD8301" diff --git a/runtime/themes/vintage.toml b/runtime/themes/vintage.toml new file mode 100644 index 000000000000..2aea81cbf32b --- /dev/null +++ b/runtime/themes/vintage.toml @@ -0,0 +1,102 @@ +# Vintage Theme for the Helix Editor +# Author: rojebd +# Repo: https://github.com/rojebd/vintage +# This theme is vintage inspired +# Info: I made this theme one afternoon because my bus was late and I stayed home :) + +attribute = "#a7bf67" +keyword = "#A4A2B4" +"keyword.directive" = "light-gray" +namespace = "#7095bf" +punctuation = "white" +"punctuation.delimeter" = "white" +operator = "muddy" +special = "pink" +"variable.other.member" = "green" +variable = "green" +"variable.parameter" = "light-green" +"variable.builtin" = "light-green" +type = "#efbe4c" +"type.builtin" = "#efbe4c" +constructor = "#c19ef7" +function = "muddy" +"function.macro" = "muddy" +"function.builtin" = "#db985e" +tag = "#d37a78" +comment = "light-gray" +constant = "#A5C4D4" +"constant.builtin" = "bright-yellow" +string = "#d6a560" +"constant.numeric" = "#b577b0" +"constant.character.escape" = "#c95c56" +label = "#abcc8a" + +"markup.heading" = "bright-pink" +"markup.bold" = { fg = "markdown-bold", modifiers = ["bold"] } +"markup.italic" = { fg = "markdown-italic", modifiers = ["italic"] } +"markup.strikethrough" = { fg = "bright-pink", modifiers = ["crossed_out", "bold"] } +"markup.link.url" = { fg = "blueish", modifiers = ["underlined"] } +"markup.link.text" = "orange" +"markup.raw" = "gray" + +"diff.plus" = { fg = "bright-green", modifiers = ["bold"] } +"diff.minus" = { fg = "redish", modifiers = ["bold"] } +"diff.delta" = { fg = "blueish", modifiers = ["bold"] } + +"ui.background" = { bg = "background" } +"ui.background.separator" = { fg = "white" } +"ui.linenr" = { fg = "#747575" } +"ui.linenr.selected" = { fg = "#c7dddd" } +"ui.statusline" = { fg = "black", bg = "gray" } +"ui.statusline.inactive" = { fg = "gray", bg = "#3c3836" } +"ui.popup" = { bg = "#3b3b3d" } +"ui.window" = { fg = "yellow" } +"ui.help" = { bg = "#35353a", fg = "light-gray" } + +"ui.text" = { fg = "light-gray" } +"ui.text.focus" = { fg = "#83c679" } +"ui.text.inactive" = "#93a56f" +"ui.virtual" = { fg = "yellow" } +"ui.virtual.indent-guide" = { fg = "#5b5b5a" } +"ui.virtual.ruler" = { bg = "#363638" } + +"ui.selection" = { fg = "white", bg = "gray" } +"ui.selection.primary" = { fg = "white", bg = "gray" } +"ui.cursor.match" = { fg = "white", bg = "gray" } +"ui.cursor" = { modifiers = ["reversed"] } +"ui.cursorline.primary" = { bg = "#3b3b3f" } + +"ui.debug" = { fg = "#634450" } +"ui.debug.breakpoint" = { fg = "redish" } +"ui.debug.active" = { fg = "blueish" } +"ui.menu" = { fg = "gray", bg = "black" } +"ui.menu.selected" = { fg = "black", bg = "gray" } + +"diagnostic.hint" = { underline = { color = "bright-yellow", style = "curl" } } +"diagnostic.info" = { underline = { color = "bright-yellow", style = "curl" } } +"diagnostic.warning" = { underline = { color = "bright-yellow", style = "curl" } } +"diagnostic.error" = { underline = { color = "bright-pink", style = "curl" } } + +warning = "bright-yellow" +error = "bright-pink" +info = "bright-yellow" +hint = "bright-yellow" + +[palette] +bright-pink = "#DE6468" +background = "#1f1f21" +green = "#778e61" +light-green = "#9B9B7A" +brown = "#BAA587" +pink = "#D9AE94" +yellow = "#F1DCA7" +bright-yellow = "#FFCB69" +orange = "#E8AC65" +muddy = "#D08C60" +markdown-italic = "#80a552" +markdown-bold = "#6faa75" +dark-brown = "#B58463" +purple-ish = "#997B66" +bright-green = "#4F6F52" +blueish = "#3876BF" +redish = "#B80000" diff --git a/runtime/themes/voxed.toml b/runtime/themes/voxed.toml index c2be9afefe5f..fff0bfbaf4af 100644 --- a/runtime/themes/voxed.toml +++ b/runtime/themes/voxed.toml @@ -1,3 +1,9 @@ +# Voxed theme for the Helix Editor +# Author: rojebd +# Repo: https://github.com/rojebd/voxed +# Version: 1.0 +# Info: This is a theme I made one afternoon because I was bored + attribute = "buff" keyword = "sglow" "keyword.directive" = "defineish" @@ -43,6 +49,7 @@ label = "yellow" "ui.background.separator" = { fg = "sglow" } "ui.linenr" = { fg = "light-grey", modifiers = ["italic"] } "ui.linenr.selected" = { fg = "bpink", modifiers = ["bold"] } + "ui.statusline" = { fg = "black", bg = "light-grey", modifiers = ["bold"] } "ui.statusline.inactive" = { fg = "black", bg = "bgrey-two" } "ui.popup" = { fg = "bgrey", bg = "#25262B" } @@ -54,7 +61,8 @@ label = "yellow" "ui.text.inactive" = "bgrey" "ui.virtual" = { fg = "blue" } "ui.virtual.ruler" = { bg = "bgrey-two" } -"ui.virtual.indent-guide" = { fg = "bpink" } +"ui.virtual.indent-guide" = { fg = "gray" } + "ui.selection" = { bg = "maize" } "ui.selection.primary" = { fg = "white", bg = "bgrey" } @@ -62,7 +70,8 @@ label = "yellow" "ui.cursor.insert" = { bg = "white" } "ui.cursor.match" = { fg = "#212121", bg = "#6C6999" } "ui.cursor" = { bg = "bgrey-two", modifiers = ["reversed"] } -"ui.cursorline.primary" = { bg = "white" } +"ui.cursorline.primary" = { bg = "#44414c" } + "ui.highlight" = { bg = "white" } "ui.highlight.frameline" = { bg = "#634450" } "ui.debug" = { fg = "#634450" } @@ -75,8 +84,6 @@ label = "yellow" "diagnostic.info" = { underline = { color = "sglow", style = "curl" } } "diagnostic.warning" = { underline = { color = "redish", style = "curl" } } "diagnostic.error" = { underline = { color = "bpink", style = "curl" } } -"diagnostic.unnecessary" = { modifiers = ["dim"] } -"diagnostic.deprecated" = { modifiers = ["crossed_out"] } warning = "bpink" error = "bsienna" diff --git a/xtask/src/docgen.rs b/xtask/src/docgen.rs index 18c145d50fe7..6b9ebfa3d269 100644 --- a/xtask/src/docgen.rs +++ b/xtask/src/docgen.rs @@ -1,12 +1,18 @@ use crate::helpers; use crate::path; use crate::DynError; + +use helix_term::commands::MappableCommand; use helix_term::commands::TYPABLE_COMMAND_LIST; use helix_term::health::TsFeature; +use helix_term::ui::EditorView; +use helix_view::document::Mode; + use std::collections::HashSet; use std::fs; pub const TYPABLE_COMMANDS_MD_OUTPUT: &str = "typable-cmd.md"; +pub const STATIC_COMMANDS_MD_OUTPUT: &str = "static-cmd.md"; pub const LANG_SUPPORT_MD_OUTPUT: &str = "lang-support.md"; fn md_table_heading(cols: &[String]) -> String { @@ -48,6 +54,68 @@ pub fn typable_commands() -> Result { Ok(md) } +pub fn static_commands() -> Result { + let mut md = String::new(); + let keymap = EditorView::default().keymaps.map(); + let keymaps = [ + ("normal", keymap[&Mode::Normal].reverse_map()), + ("select", keymap[&Mode::Select].reverse_map()), + ("insert", keymap[&Mode::Insert].reverse_map()), + ]; + + md.push_str(&md_table_heading(&[ + "Name".to_owned(), + "Description".to_owned(), + "Default keybinds".to_owned(), + ])); + + for cmd in MappableCommand::STATIC_COMMAND_LIST { + let keymap_strings: Vec<_> = keymaps + .iter() + .map(|(mode, keymap)| { + let bindings = keymap + .get(cmd.name()) + .map(|bindings| { + let mut bind_strings: Vec<_> = bindings + .iter() + .map(|bind| { + let keys = &bind + .iter() + .map(|key| key.key_sequence_format()) + .collect::() + // escape | so it doesn't get rendered as a column separator + .replace('|', "\\|"); + format!("`` {} ``", keys) + }) + .collect(); + // sort for stable output. sorting by length puts simple + // keybindings first and groups similar keys together + bind_strings.sort_by_key(|s| (s.len(), s.to_owned())); + bind_strings.join(", ") + }) + .unwrap_or_default(); + + (mode, bindings) + }) + .collect(); + + let keymap_string = keymap_strings + .iter() + .filter(|(_, bindings)| !bindings.is_empty()) + .map(|(mode, bindings)| format!("{}: {}", mode, bindings)) + .collect::>() + .join(", "); + + md.push_str(&md_table_row(&[ + md_mono(cmd.name()), + cmd.doc().to_owned(), + keymap_string, + ])); + } + + Ok(md) +} + pub fn lang_features() -> Result { let mut md = String::new(); let ts_features = TsFeature::all(); @@ -59,7 +127,7 @@ pub fn lang_features() -> Result { .map(|t| t.long_title().to_string()) .collect::>(), ); - cols.push("Default LSP".to_owned()); + cols.push("Default language servers".to_owned()); md.push_str(&md_table_heading(&cols)); let config = helpers::lang_config(); diff --git a/xtask/src/main.rs b/xtask/src/main.rs index fcb462f252d5..39de89182077 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -9,14 +9,17 @@ use std::{env, error::Error}; type DynError = Box; pub mod tasks { - use crate::docgen::{lang_features, typable_commands, write}; - use crate::docgen::{LANG_SUPPORT_MD_OUTPUT, TYPABLE_COMMANDS_MD_OUTPUT}; + use crate::docgen::{lang_features, static_commands, typable_commands, write}; + use crate::docgen::{ + LANG_SUPPORT_MD_OUTPUT, STATIC_COMMANDS_MD_OUTPUT, TYPABLE_COMMANDS_MD_OUTPUT, + }; use crate::querycheck::query_check; use crate::theme_check::theme_check; use crate::DynError; pub fn docgen() -> Result<(), DynError> { write(TYPABLE_COMMANDS_MD_OUTPUT, &typable_commands()?); + write(STATIC_COMMANDS_MD_OUTPUT, &static_commands()?); write(LANG_SUPPORT_MD_OUTPUT, &lang_features()?); Ok(()) }