on 7078e84 help sign in
234 files changed+4262−10457
since splitsnapshots
unifiedsplit
.envrc−1 .github/ISSUE_TEMPLATE/bug_report.yaml−10 .github/workflows/build.yml+7−15 .github/workflows/cachix.yml+3−3 .github/workflows/gh-pages.yml+5−5 .github/workflows/release.yml+13−13 CHANGELOG.md−260 Cargo.lock+609−538 Cargo.toml+1−14 README.md+1−1 VERSION+1 book/custom.css+1−1 book/src/configuration.md+9−27 book/src/generated/lang-support.md+11−25 book/src/generated/typable-cmd.md+1−4 book/src/guides/adding_languages.md−2 book/src/guides/indent.md+43−319 book/src/guides/injection.md+1−1 book/src/install.md+6−30 book/src/keymap.md+14−15 book/src/languages.md+1−3 book/src/themes.md+1−9 book/src/usage.md+2−2 book/theme/index.hbs+15−18 contrib/Helix.appdata.xml−15 contrib/Helix.desktop+1−3 docs/CONTRIBUTING.md+3−10 docs/releases.md+5−12 flake.lock+35−12 flake.nix+24−27 grammars.nix+21−24 helix-core/Cargo.toml+14−18 helix-core/src/diagnostic.rs−4 helix-core/src/fuzzy.rs−43 helix-core/src/graphemes.rs+1−1 helix-core/src/indent.rs+141−404 helix-core/src/lib.rs−1 helix-core/src/path.rs+2−2 helix-core/src/syntax.rs+8−24 helix-core/src/transaction.rs+14−73 helix-core/src/wrap.rs+1−3 helix-core/tests/data/indent/cpp.cpp−48 helix-core/tests/data/indent/indent.rs+1 helix-core/tests/data/indent/languages.toml−13 helix-core/tests/indent.rs+23−151 helix-dap/Cargo.toml+9−11 helix-event/Cargo.toml−16 helix-event/src/lib.rs−8 helix-event/src/redraw.rs−49 helix-loader/Cargo.toml+11−12 helix-loader/build.rs+4−14 helix-loader/src/lib.rs+4−13 helix-lsp/Cargo.toml+14−15 helix-lsp/src/client.rs+13−87 helix-lsp/src/lib.rs+28−32 helix-parsec/Cargo.toml+7−8 helix-term/Cargo.toml+25−30 helix-term/src/application.rs+75−111 helix-term/src/args.rs−29 helix-term/src/commands.rs+147−328 helix-term/src/commands/dap.rs+4−13 helix-term/src/commands/lsp.rs+2−12 helix-term/src/commands/typed.rs+661−855 helix-term/src/compositor.rs−12 helix-term/src/health.rs+16−44 helix-term/src/keymap.rs+14−14 helix-term/src/main.rs+1−17 helix-term/src/ui/completion.rs+1−17 helix-term/src/ui/document.rs+24−60 helix-term/src/ui/editor.rs+46−91 helix-term/src/ui/fuzzy_match.rs+239 helix-term/src/ui/fuzzy_match/test.rs+47 helix-term/src/ui/lsp.rs+1−3 helix-term/src/ui/markdown.rs+5−12 helix-term/src/ui/menu.rs+40−58 helix-term/src/ui/mod.rs+145−88 helix-term/src/ui/picker.rs+319−353 helix-term/src/ui/popup.rs+7−27 helix-term/tests/integration.rs+1 helix-term/tests/test/commands.rs−46 helix-term/tests/test/commands/write.rs+3−122 helix-term/tests/test/helpers.rs+1−9 helix-term/tests/test/movement.rs−39 helix-term/tests/test/picker.rs+80 helix-term/tests/test/splits.rs+3−3 helix-tui/Cargo.toml+15−15 helix-tui/src/backend/crossterm.rs+33−51 helix-tui/src/buffer.rs+2−2 helix-tui/src/terminal.rs+14 helix-vcs/Cargo.toml+10−12 helix-vcs/src/diff.rs+19−6 helix-vcs/src/diff/worker.rs+9−3 helix-vcs/src/diff/worker/test.rs+5−1 helix-vcs/src/git.rs+5−5 helix-view/Cargo.toml+18−21 helix-view/src/clipboard.rs+2−7 helix-view/src/document.rs+40−72 helix-view/src/editor.rs+71−103 helix-view/src/gutter.rs+5−4 helix-view/src/handlers/dap.rs+3−1 helix-view/src/input.rs+1−65 helix-view/src/register.rs+10−12 helix-view/src/theme.rs−6 languages.toml+196−433 logo.svg+1−1 runtime/queries/_typescript/highlights.scm+3−5 runtime/queries/_typescript/locals.scm−17 runtime/queries/agda/highlights.scm−124 runtime/queries/bash/indents.scm−1 runtime/queries/blueprint/highlights.scm−5 runtime/queries/c/indents.scm+1−18 runtime/queries/comment/highlights.scm+8−8 runtime/queries/common-lisp/indents.scm−1 runtime/queries/dart/highlights.scm+1−3 runtime/queries/dbml/highlights.scm−44 runtime/queries/fsharp/locals.scm−25 runtime/queries/gas/highlights.scm−21 runtime/queries/gas/injections.scm−2 runtime/queries/gas/textobjects.scm−2 runtime/queries/gemini/highlights.scm−26 runtime/queries/gleam/highlights.scm+5−16 runtime/queries/gn/highlights.scm−42 runtime/queries/gn/injections.scm−15 runtime/queries/gn/locals.scm−16 runtime/queries/go/highlights.scm+5−13 runtime/queries/go/locals.scm+2−10 runtime/queries/haskell/highlights.scm+11−24 runtime/queries/janet/highlights.scm−1 runtime/queries/json5/highlights.scm−11 runtime/queries/kdl/highlights.scm+4−4 runtime/queries/kdl/indents.scm−3 runtime/queries/kdl/textobjects.scm−27 runtime/queries/kotlin/highlights.scm+1−4 runtime/queries/kotlin/locals.scm−15 runtime/queries/log/highlights.scm−10 runtime/queries/lpf/highlights.scm−19 runtime/queries/markdown.inline/injections.scm+1−4 runtime/queries/nix/injections.scm−14 runtime/queries/ocaml/highlights.scm−2 runtime/queries/perl/highlights.scm+2 runtime/queries/perl/indents.scm−29 runtime/queries/perl/injections.scm−2 runtime/queries/perl/textobjects.scm−14 runtime/queries/pod/highlights.scm−61 runtime/queries/purescript/highlights.scm+1−164 runtime/queries/purescript/injections.scm+1−2 runtime/queries/purescript/locals.scm+1−4 runtime/queries/purescript/textobjects.scm−13 runtime/queries/python/highlights.scm−6 runtime/queries/python/indents.scm−9 runtime/queries/racket/indents.scm−1 runtime/queries/robot/highlights.scm+13−51 runtime/queries/ron/highlights.scm+1−43 runtime/queries/ron/indents.scm+1−12 runtime/queries/ron/injections.scm+1−2 runtime/queries/rust/highlights.scm−7 runtime/queries/rust/indents.scm+2−69 runtime/queries/rust/injections.scm−6 runtime/queries/rust/locals.scm+1−14 runtime/queries/rust/textobjects.scm+1−4 runtime/queries/scheme/highlights.scm−5 runtime/queries/scheme/indents.scm−43 runtime/queries/slint/highlights.scm+72−118 runtime/queries/slint/indents.scm+5−6 runtime/queries/slint/injections.scm−2 runtime/queries/slint/locals.scm+1−1 runtime/queries/smali/folds.scm−12 runtime/queries/smali/highlights.scm−216 runtime/queries/smali/indents.scm−31 runtime/queries/smali/injections.scm−2 runtime/queries/smali/locals.scm−42 runtime/queries/sql/highlights.scm+231−317 runtime/queries/strace/highlights.scm−8 runtime/queries/templ/highlights.scm−99 runtime/queries/templ/injections.scm−4 runtime/queries/typst/highlights.scm−77 runtime/queries/typst/injections.scm−6 runtime/queries/unison/highlights.scm+6−21 runtime/queries/yaml/injections.scm−52 runtime/queries/yuck/highlights.scm+1−1 runtime/themes/README.md−8 runtime/themes/autumn.toml+65−62 runtime/themes/autumn_night.toml+6−6 runtime/themes/catppuccin_frappe.toml−2 runtime/themes/catppuccin_latte.toml−2 runtime/themes/catppuccin_macchiato.toml−2 runtime/themes/catppuccin_mocha.toml−11 runtime/themes/cyan_light.toml−154 runtime/themes/darcula-solid.toml+4−1 runtime/themes/darcula.toml+4−10 runtime/themes/dracula.toml−2 runtime/themes/everblush.toml−1 runtime/themes/gruber-darker.toml−114 runtime/themes/horizon-dark.toml−80 runtime/themes/jellybeans.toml+1−1 runtime/themes/licenses/everforest.LICENSE−21 runtime/themes/licenses/modus_vivendi.LICENSE−5 runtime/themes/licenses/modus_vivendi_deuteranopia.LICENSE−5 runtime/themes/licenses/modus_vivendi_tinted.LICENSE−5 runtime/themes/licenses/modus_vivendi_tritanopia.LICENSE−5 runtime/themes/licenses/poimandres.LICENSE−21 runtime/themes/licenses/serika-syntax.LICENSE−21 runtime/themes/licenses/sonokai.LICENSE−21 runtime/themes/licenses/starlight.LICENSE−24 runtime/themes/material_darker.toml−20 runtime/themes/material_deep_ocean.toml−123 runtime/themes/material_oceanic.toml−21 runtime/themes/material_palenight.toml−19 runtime/themes/modus_operandi.toml−194 runtime/themes/modus_operandi_deuteranopia.toml−46 runtime/themes/modus_operandi_tinted.toml−45 runtime/themes/modus_operandi_tritanopia.toml−73 runtime/themes/modus_vivendi.toml−242 runtime/themes/modus_vivendi_deuteranopia.toml−158 runtime/themes/modus_vivendi_tinted.toml−144 runtime/themes/modus_vivendi_tritanopia.toml−186 runtime/themes/molokai.toml+1−1 runtime/themes/monokai.toml−5 runtime/themes/naysayer.toml+2−2 runtime/themes/nightfox.toml+2−2 runtime/themes/noctis.toml+26−26 runtime/themes/nord-night.toml−23 runtime/themes/nord.toml+13−23 runtime/themes/onedark.toml−1 runtime/themes/papercolor-dark.toml+116−67 runtime/themes/papercolor-light.toml+103−194 runtime/themes/poimandres.toml−113 runtime/themes/poimandres_storm.toml−19 runtime/themes/rose_pine.toml+29−31 runtime/themes/starlight.toml−113 runtime/themes/zenburn.toml+1−1 runtime/tutor+3−157 rust-toolchain.toml+2−2 xtask/Cargo.toml+6−12
.envrc−1
@@ -1,6 +1,5 @@
11watch_file shell.nix
22watch_file flake.lock
3−watch_file rust-toolchain.toml
43
54# try to use flakes, if it fails use normal nix (ie. shell.nix)
65use flake || use nix
.github/ISSUE_TEMPLATE/bug_report.yaml−10
@@ -55,16 +55,6 @@ body:
5555 placeholder: wezterm 20220101-133340-7edc5b5a
5656 validations:
5757 required: true
58− - type: input
59− id: installation-method
60− attributes:
61− label: Installation Method
62− description: >
63− How you installed Helix - from a package manager like Homebrew or the
64− AUR, built from source, downloaded a binary from the releases page, etc.
65− placeholder: "source / brew / nixpkgs / flake / releases page"
66− validations:
67− required: true
6858 - type: input
6959 id: helix-version
7060 attributes:
.github/workflows/build.yml+7−15
@@ -14,7 +14,7 @@ jobs:
1414 runs-on: ubuntu-latest
1515 steps:
1616 - name: Checkout sources
17− uses: actions/checkout@v4
17+ uses: actions/checkout@v3
1818 - name: Install stable toolchain
1919 uses: helix-editor/rust-toolchain@v1
2020 with:
@@ -22,8 +22,6 @@ jobs:
2222 override: true
2323
2424 - uses: Swatinem/rust-cache@v2
25− with:
26− shared-key: "build"
2725
2826 - name: Run cargo check
2927 run: cargo check
@@ -36,14 +34,12 @@ jobs:
3634 HELIX_LOG_LEVEL: info
3735 steps:
3836 - name: Checkout sources
39− uses: actions/checkout@v4
37+ uses: actions/checkout@v3
4038
4139 - name: Install stable toolchain
42− uses: dtolnay/rust-toolchain@1.70
40+ uses: dtolnay/rust-toolchain@1.65
4341
4442 - uses: Swatinem/rust-cache@v2
45− with:
46− shared-key: "build"
4743
4844 - name: Cache test tree-sitter grammar
4945 uses: actions/cache@v3
@@ -67,16 +63,14 @@ jobs:
6763 runs-on: ubuntu-latest
6864 steps:
6965 - name: Checkout sources
70− uses: actions/checkout@v4
66+ uses: actions/checkout@v3
7167
7268 - name: Install stable toolchain
73− uses: dtolnay/rust-toolchain@1.70
69+ uses: dtolnay/rust-toolchain@1.65
7470 with:
7571 components: rustfmt, clippy
7672
7773 - uses: Swatinem/rust-cache@v2
78− with:
79− shared-key: "build"
8074
8175 - name: Run cargo fmt
8276 run: cargo fmt --all --check
@@ -94,14 +88,12 @@ jobs:
9488 runs-on: ubuntu-latest
9589 steps:
9690 - name: Checkout sources
97− uses: actions/checkout@v4
91+ uses: actions/checkout@v3
9892
9993 - name: Install stable toolchain
100− uses: dtolnay/rust-toolchain@1.70
94+ uses: dtolnay/rust-toolchain@1.65
10195
10296 - uses: Swatinem/rust-cache@v2
103− with:
104− shared-key: "build"
10597
10698 - name: Validate queries
10799 run: cargo xtask query-check
.github/workflows/cachix.yml+3−3
@@ -11,13 +11,13 @@ jobs:
1111 runs-on: ubuntu-latest
1212 steps:
1313 - name: Checkout sources
14− uses: actions/checkout@v4
14+ uses: actions/checkout@v3
1515
1616 - name: Install nix
17− uses: cachix/install-nix-action@v24
17+ uses: cachix/install-nix-action@v22
1818
1919 - name: Authenticate with Cachix
20− uses: cachix/cachix-action@v13
20+ uses: cachix/cachix-action@v12
2121 with:
2222 name: helix
2323 authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
.github/workflows/gh-pages.yml+5−5
@@ -11,7 +11,7 @@ jobs:
1111 deploy:
1212 runs-on: ubuntu-latest
1313 steps:
14− - uses: actions/checkout@v4
14+ - uses: actions/checkout@v3
1515
1616 - name: Setup mdBook
1717 uses: peaceiris/actions-mdbook@v1
@@ -26,16 +26,16 @@ jobs:
2626 OUTDIR=$(basename ${{ github.ref }})
2727 echo "OUTDIR=$OUTDIR" >> $GITHUB_ENV
2828
29− - name: Deploy stable
29+ - name: Deploy
3030 uses: peaceiris/actions-gh-pages@v3
31− if: startswith(github.ref, 'refs/tags/')
3231 with:
3332 github_token: ${{ secrets.GITHUB_TOKEN }}
3433 publish_dir: ./book/book
34+ destination_dir: ./${{ env.OUTDIR }}
3535
36− - name: Deploy
36+ - name: Deploy stable
3737 uses: peaceiris/actions-gh-pages@v3
38+ if: startswith(github.ref, 'refs/tags/')
3839 with:
3940 github_token: ${{ secrets.GITHUB_TOKEN }}
4041 publish_dir: ./book/book
41− destination_dir: ./${{ env.OUTDIR }}
.github/workflows/release.yml+13−13
@@ -23,7 +23,7 @@ jobs:
2323 runs-on: ubuntu-latest
2424 steps:
2525 - name: Checkout sources
26− uses: actions/checkout@v4
26+ uses: actions/checkout@v3
2727
2828 - name: Install stable toolchain
2929 uses: dtolnay/rust-toolchain@stable
@@ -36,7 +36,7 @@ jobs:
3636 - name: Bundle grammars
3737 run: tar cJf grammars.tar.xz -C runtime/grammars/sources .
3838
39− - uses: actions/upload-artifact@v4
39+ - uses: actions/upload-artifact@v3
4040 with:
4141 name: grammars
4242 path: grammars.tar.xz
@@ -70,11 +70,11 @@ jobs:
7070 rust: stable
7171 target: aarch64-unknown-linux-gnu
7272 cross: true
73− # - build: riscv64-linux
74− # os: ubuntu-latest
75− # rust: stable
76− # target: riscv64gc-unknown-linux-gnu
77− # cross: true
73+ - build: riscv64-linux
74+ os: ubuntu-latest
75+ rust: stable
76+ target: riscv64gc-unknown-linux-gnu
77+ cross: true
7878 - build: x86_64-macos
7979 os: macos-latest
8080 rust: stable
@@ -103,10 +103,10 @@ jobs:
103103
104104 steps:
105105 - name: Checkout sources
106− uses: actions/checkout@v4
106+ uses: actions/checkout@v3
107107
108108 - name: Download grammars
109− uses: actions/download-artifact@v4
109+ uses: actions/download-artifact@v3
110110
111111 - name: Move grammars under runtime
112112 if: "!startsWith(matrix.os, 'windows')"
@@ -220,7 +220,7 @@ jobs:
220220 fi
221221 cp -r runtime dist
222222
223− - uses: actions/upload-artifact@v4
223+ - uses: actions/upload-artifact@v3
224224 with:
225225 name: bins-${{ matrix.build }}
226226 path: dist
@@ -231,9 +231,9 @@ jobs:
231231 runs-on: ubuntu-latest
232232 steps:
233233 - name: Checkout sources
234− uses: actions/checkout@v4
234+ uses: actions/checkout@v3
235235
236− - uses: actions/download-artifact@v4
236+ - uses: actions/download-artifact@v3
237237
238238 - name: Build archive
239239 shell: bash
@@ -288,7 +288,7 @@ jobs:
288288 overwrite: true
289289
290290 - name: Upload binaries as artifact
291− uses: actions/upload-artifact@v4
291+ uses: actions/upload-artifact@v3
292292 if: env.preview == 'true'
293293 with:
294294 name: release
CHANGELOG.md−260
@@ -1,263 +1,3 @@
1−# 23.10 (2023-10-24)
2−
3−A big shout out to all the contributors! We had 118 contributors in this release.
4−
5−Breaking changes:
6−
7−- Support multiple language servers per language ([#2507](https://github.com/helix-editor/helix/pull/2507))
8− - This is a breaking change to language configuration
9−
10−Features:
11−
12−- Support multiple language servers per language ([#2507](https://github.com/helix-editor/helix/pull/2507), [#7082](https://github.com/helix-editor/helix/pull/7082), [#7286](https://github.com/helix-editor/helix/pull/7286), [#8374](https://github.com/helix-editor/helix/pull/8374))
13−- Add a statusline element for the selected register ([#7222](https://github.com/helix-editor/helix/pull/7222))
14−- Add `%`, `#`, `.`, `*` and `+` special registers ([#6985](https://github.com/helix-editor/helix/pull/6985))
15−- Add initial support for LSP DidChangeWatchedFiles notifications ([#7665](https://github.com/helix-editor/helix/pull/7665))
16−- Search buffer contents in `global_search` ([#5652](https://github.com/helix-editor/helix/pull/5652))
17−- Add a "smart tab" command that intelligently jumps the cursor on tab ([#4443](https://github.com/helix-editor/helix/pull/4443))
18−- Add a statusline element for whether a file is read-only ([#7222](https://github.com/helix-editor/helix/pull/7222), [#7875](https://github.com/helix-editor/helix/pull/7875))
19−- Syntax highlight regex prompts ([#7738](https://github.com/helix-editor/helix/pull/7738))
20−- Allow defining alignment in indent queries ([#5355](https://github.com/helix-editor/helix/pull/5355))
21−- Show visual feedback in `surround_replace` ([#7588](https://github.com/helix-editor/helix/pull/7588))
22−- Switch to Nucleo for fuzzy matching ([#7814](https://github.com/helix-editor/helix/pull/7814), [#8148](https://github.com/helix-editor/helix/pull/8148), [#8192](https://github.com/helix-editor/helix/pull/8192), [#8194](https://github.com/helix-editor/helix/pull/8194))
23−- Insert a trailing newline on write ([#8157](https://github.com/helix-editor/helix/pull/8157))
24−- Add a `-w`/`--working-dir` CLI flag for specifying a working directory on startup ([#8223](https://github.com/helix-editor/helix/pull/8223), [#8498](https://github.com/helix-editor/helix/pull/8498), [#8520](https://github.com/helix-editor/helix/pull/8520))
25−- Accept a `+N` CLI argument to set the first file's line number ([#8521](https://github.com/helix-editor/helix/pull/8521))
26−- Accept Helix-specific ignore files in `.helix/ignore` and `~/.config/helix/ignore` ([#8099](https://github.com/helix-editor/helix/pull/8099))
27−
28−Commands:
29−
30−- `merge_selections` (`A-minus`) - merge all selections into one selection that covers all ranges ([#7053](https://github.com/helix-editor/helix/pull/7053))
31−- `move_prev_long_word_end` and `extend_prev_long_word_end` - move/extend to the end of the previous WORD ([#6905](https://github.com/helix-editor/helix/pull/6905))
32−- `reverse_selection_contents` - swaps the values of each selection so they are reversed ([#7329](https://github.com/helix-editor/helix/pull/7329))
33−- Add `:rl` and `:rla` aliases for `:reload` and `:reload-all` ([#7158](https://github.com/helix-editor/helix/pull/7158))
34−- `yank_joined` - join the selections and yank to the selected register ([#7195](https://github.com/helix-editor/helix/pull/7195))
35−- `:write-all!` (`:wa!`) - forcibly write all buffers to disk and create any necessary subdirectories ([#7577](https://github.com/helix-editor/helix/pull/7577))
36−- `:redraw` - clear re-render the UI ([#6949](https://github.com/helix-editor/helix/pull/6949))
37−- `:tree-sitter-highlight-name` - show the theme scope name of the highlight under the cursor ([#8170](https://github.com/helix-editor/helix/pull/8170))
38−
39−Usability improvements:
40−
41−- Allow cycling option values at runtime ([#4411](https://github.com/helix-editor/helix/pull/4411), [#7240](https://github.com/helix-editor/helix/pull/7240), [#7877](https://github.com/helix-editor/helix/pull/7877))
42−- Exit gracefully on termination signals ([#7236](https://github.com/helix-editor/helix/pull/7236))
43−- Add plaintext matching fallback to tree-sitter pair matching ([#4288](https://github.com/helix-editor/helix/pull/4288))
44−- Persist register selection in pending keymaps ([0e08349](https://github.com/helix-editor/helix/commit/0e08349))
45−- Propagate the count and register to command palette commands ([b394997](https://github.com/helix-editor/helix/commit/b394997))
46−- Auto indent on `insert_at_line_start` ([#5837](https://github.com/helix-editor/helix/pull/5837))
47−- Add a config option to control whether LSP completions are automatically inserted on preview ([#7189](https://github.com/helix-editor/helix/pull/7189))
48−- Add a config option for default line endings ([#5621](https://github.com/helix-editor/helix/pull/5621), [#7357](https://github.com/helix-editor/helix/pull/7357))
49−- Allow ANSI colors in themes ([#5119](https://github.com/helix-editor/helix/pull/5119))
50−- Match pairs that don't form a standalone tree-sitter node ([#7242](https://github.com/helix-editor/helix/pull/7242))
51−- Allow indent sizes of up to 16 columns ([#7429](https://github.com/helix-editor/helix/pull/7429))
52−- Improve performance of mapping positions through changes ([#7408](https://github.com/helix-editor/helix/pull/7408), [8d39a81](https://github.com/helix-editor/helix/commit/8d39a81), [#7471](https://github.com/helix-editor/helix/pull/7471))
53−- Mark buffers created from stdin as modified ([#7431](https://github.com/helix-editor/helix/pull/7431))
54−- Forcibly shut down uninitialized language servers ([#7449](https://github.com/helix-editor/helix/pull/7449))
55−- Add filename completer for shell prompts ([#7569](https://github.com/helix-editor/helix/pull/7569))
56−- Allow binding F13-F24 ([#7672](https://github.com/helix-editor/helix/pull/7672))
57−- Resolve LSP code actions ([#7677](https://github.com/helix-editor/helix/pull/7677), [#8421](https://github.com/helix-editor/helix/pull/8421))
58−- Save an undo checkpoint before accepting completions ([#7747](https://github.com/helix-editor/helix/pull/7747))
59−- Include gitignored files in debugger completions ([#7936](https://github.com/helix-editor/helix/pull/7936))
60−- Make editor remember the last search register ([#5244](https://github.com/helix-editor/helix/pull/5244))
61−- Open directories with `goto_file` ([#7909](https://github.com/helix-editor/helix/pull/7909))
62−- Use relative path to open buffer in `goto_file` (`gf`) ([#7965](https://github.com/helix-editor/helix/pull/7965))
63−- Support `default` color in themes ([#8083](https://github.com/helix-editor/helix/pull/8083), [#8114](https://github.com/helix-editor/helix/pull/8114))
64−- Toggle between relative and absolute line numbers when the terminal loses focus ([#7955](https://github.com/helix-editor/helix/pull/7955))
65−- Lower default idle-timeout to 250ms ([060e73a](https://github.com/helix-editor/helix/commit/060e73a))
66−- Allow theming diff gutters separately from other diff colors ([#8343](https://github.com/helix-editor/helix/pull/8343))
67−- Style bold/italic/strikethrough in markdown doc popups ([#8385](https://github.com/helix-editor/helix/pull/8385))
68−- Maintain the cursor position and view when splitting with `:hsplit`/`:vsplit` ([#8109](https://github.com/helix-editor/helix/pull/8109))
69−- Accept `-` in macros outside of `<`/`>` ([#8475](https://github.com/helix-editor/helix/pull/8475))
70−- Show all language servers for each language in `--health` ([#7315](https://github.com/helix-editor/helix/pull/7315))
71−- Don't break on hyphens in `:reflow` ([#8569](https://github.com/helix-editor/helix/pull/8569))
72−
73−Fixes:
74−
75−- Update diagnostics correctly on language server exit ([#7111](https://github.com/helix-editor/helix/pull/7111))
76−- Fix off-by-one in `select_references_to_symbol_under_cursor` ([#7132](https://github.com/helix-editor/helix/pull/7132))
77−- Extend selection with repeat-last-motion only if the original motion extended the selection ([#7159](https://github.com/helix-editor/helix/pull/7159))
78−- Fix undefined behavior in the diff gutter ([#7227](https://github.com/helix-editor/helix/pull/7227))
79−- Check that tab width is non-zero ([#7178](https://github.com/helix-editor/helix/pull/7178))
80−- Fix styles being overwritten in table rows with multiple cells ([#7281](https://github.com/helix-editor/helix/pull/7281))
81−- Add file for `--log` CLI arg in help text ([#7307](https://github.com/helix-editor/helix/pull/7307))
82−- Fix underflow when repeating a completion that has a negative shift position ([#7322](https://github.com/helix-editor/helix/pull/7322))
83−- Prefer longer matches in `select_next_sibling` and `select_prev_sibling` ([#7332](https://github.com/helix-editor/helix/pull/7332))
84−- Preview scratch buffers in the jumplist picker ([#7331](https://github.com/helix-editor/helix/pull/7331))
85−- Fix chunking by bytes in tree-sitter parsing ([#7417](https://github.com/helix-editor/helix/pull/7417))
86−- Discard LSP publishDiagnostic from uninitialized servers ([#7467](https://github.com/helix-editor/helix/pull/7467))
87−- Use negotiated position encoding for LSP workspace edits ([#7469](https://github.com/helix-editor/helix/pull/7469))
88−- Fix error message for unknown gutter types in config ([#7534](https://github.com/helix-editor/helix/pull/7534))
89−- Fix `:log-open` when `--log` CLI arg is specified ([#7573](https://github.com/helix-editor/helix/pull/7573), [#7585](https://github.com/helix-editor/helix/pull/7585))
90−- Fix debouncing of LSP messages to fix the last message sticking around ([#7538](https://github.com/helix-editor/helix/pull/7538), [#8023](https://github.com/helix-editor/helix/pull/8023))
91−- Fix crash when the current working directory is deleted ([#7185](https://github.com/helix-editor/helix/pull/7185))
92−- Fix piping to Helix on macOS ([#5468](https://github.com/helix-editor/helix/pull/5468))
93−- Fix crash when parsing overlapping injections ([#7621](https://github.com/helix-editor/helix/pull/7621))
94−- Clear the statusline when the prompt is visible ([#7646](https://github.com/helix-editor/helix/pull/7646))
95−- Fix range formatting error message typo ([#7823](https://github.com/helix-editor/helix/pull/7823))
96−- Skip rendering gutters when gutter width exceeds view width ([#7821](https://github.com/helix-editor/helix/pull/7821))
97−- Center the picker preview using visual lines ([#7837](https://github.com/helix-editor/helix/pull/7837))
98−- Align view correctly for background buffers opened with `A-ret` ([#7691](https://github.com/helix-editor/helix/pull/7691))
99−- Fix cursor resetting to block when quitting via a keybind ([#7931](https://github.com/helix-editor/helix/pull/7931))
100−- Remove path completions for the `:new` command ([#8010](https://github.com/helix-editor/helix/pull/8010))
101−- Use binary path resolved by `which` for formatter commands ([#8064](https://github.com/helix-editor/helix/pull/8064))
102−- Handle crossterm's `hidden` modifier ([#8120](https://github.com/helix-editor/helix/pull/8120))
103−- Clear completion when switching between windows with the mouse ([#8118](https://github.com/helix-editor/helix/pull/8118))
104−- Eagerly remove the last picker (`<space>'`) when the picker has many items ([#8127](https://github.com/helix-editor/helix/pull/8127))
105−- Fix find commands for buffers with non-LF line-endings ([#8111](https://github.com/helix-editor/helix/pull/8111))
106−- Detect the tmux clipboard provider on macOS ([#8182](https://github.com/helix-editor/helix/pull/8182))
107−- Fix syntax highlighting in dynamic picker preview pane ([#8206](https://github.com/helix-editor/helix/pull/8206))
108−- Recognize HTML code tags with attributes as code in markdown previews ([#8397](https://github.com/helix-editor/helix/pull/8397))
109−- Fix multicursor snippet placeholder directions ([#8423](https://github.com/helix-editor/helix/pull/8423))
110−- Only show diagnostic highlights when diagnostics are enabled for a language server ([#8551](https://github.com/helix-editor/helix/pull/8551))
111−
112−Themes:
113−
114−- Improve the selection color in `ferra` ([#7138](https://github.com/helix-editor/helix/pull/7138))
115−- Add `variable.other.member` theming to `spacebones_light` ([#7125](https://github.com/helix-editor/helix/pull/7125))
116−- Update `autumn` and theme the soft-wrap indicator ([#7229](https://github.com/helix-editor/helix/pull/7229))
117−- Add `gruvbox_dark_soft` ([#7139](https://github.com/helix-editor/helix/pull/7139))
118−- Add `merionette` ([#7186](https://github.com/helix-editor/helix/pull/7186))
119−- Add `zed_onedark` and `zed_onelight` ([#7250](https://github.com/helix-editor/helix/pull/7250))
120−- Use light-gray for `onedarker` inlay hint theming ([#7433](https://github.com/helix-editor/helix/pull/7433))
121−- Update the Nord theme to follow the style guidelines ([#7490](https://github.com/helix-editor/helix/pull/7490))
122−- Tune `dark_plus` inlay hint colors ([#7611](https://github.com/helix-editor/helix/pull/7611))
123−- Add `naysayer` ([#7570](https://github.com/helix-editor/helix/pull/7570))
124−- Add `kaolin-dark`, `kaolin-light` and `kaolin-valley-dark` ([#7151](https://github.com/helix-editor/helix/pull/7151))
125−- Fix selection highlighting in gruvbox variants ([#7717](https://github.com/helix-editor/helix/pull/7717))
126−- Add soft-wrap indicator to `gruvbox` ([#7736](https://github.com/helix-editor/helix/pull/7736))
127−- Add missing palette definitions in `everforest_dark` ([#7739](https://github.com/helix-editor/helix/pull/7739))
128−- Increase diagnostics clarity in `pop-dark` ([#7702](https://github.com/helix-editor/helix/pull/7702))
129−- Add `vim_dark_high_contrast` ([#7785](https://github.com/helix-editor/helix/pull/7785))
130−- Add `new_moon` ([#7834](https://github.com/helix-editor/helix/pull/7834))
131−- Add `yellowed` ([#7849](https://github.com/helix-editor/helix/pull/7849))
132−- Improve comment readability for `autumn` ([#7939](https://github.com/helix-editor/helix/pull/7939))
133−- Distinguish active bufferline buffer in `monokai` ([#7983](https://github.com/helix-editor/helix/pull/7983))
134−- Update ruler colors in `nord` ([#7995](https://github.com/helix-editor/helix/pull/7995))
135−- Update Catppuccin themes ([#8102](https://github.com/helix-editor/helix/pull/8102))
136−- Add text focus scope and diagnostics undercurls for `nord` ([#8165](https://github.com/helix-editor/helix/pull/8165))
137−- Add material theme collection ([#8211](https://github.com/helix-editor/helix/pull/8211))
138−- Improve indent line color in `dracula` ([#8266](https://github.com/helix-editor/helix/pull/8266))
139−- Clean up and refactor `papercolor` to use inheritance ([#8276](https://github.com/helix-editor/helix/pull/8276))
140−- Fix `zenburn` inlay hint color ([#8278](https://github.com/helix-editor/helix/pull/8278)a)
141−- Fix picker crash when previewing an invalid range ([e9d0bd7](https://github.com/helix-editor/helix/commit/e9d0bd7))
142−- Correctly center items in the picker preview ([13d4463](https://github.com/helix-editor/helix/commit/13d4463))
143−- Add `cyan_light` ([#8293](https://github.com/helix-editor/helix/pull/8293), [#8587](https://github.com/helix-editor/helix/pull/8587))
144−- Theme HTML tags in `onedark` ([#8409](https://github.com/helix-editor/helix/pull/8409))
145−- Refine `darcula` and `darcula-solid` themes ([#8412](https://github.com/helix-editor/helix/pull/8412))
146−- Improve `nord` highlights ([#8414](https://github.com/helix-editor/helix/pull/8414))
147−- Add `nord-night` ([#8549](https://github.com/helix-editor/helix/pull/8549))
148−
149−New languages:
150−
151−- Blueprint ([#7213](https://github.com/helix-editor/helix/pull/7213), [#8161](https://github.com/helix-editor/helix/pull/8161))
152−- Forth ([#7256](https://github.com/helix-editor/helix/pull/7256), [#7334](https://github.com/helix-editor/helix/pull/7334))
153−- t32 ([#7140](https://github.com/helix-editor/helix/pull/7140), [#7811](https://github.com/helix-editor/helix/pull/7811))
154−- WebC ([#7290](https://github.com/helix-editor/helix/pull/7290))
155−- Persistent DSL for Haskell ([#7261](https://github.com/helix-editor/helix/pull/7261))
156−- F# ([#7619](https://github.com/helix-editor/helix/pull/7619), [#8024](https://github.com/helix-editor/helix/pull/8024))
157−- Wren ([#7765](https://github.com/helix-editor/helix/pull/7765), [#7819](https://github.com/helix-editor/helix/pull/7819))
158−- Unison ([#7724](https://github.com/helix-editor/helix/pull/7724))
159−- Todo.txt ([#7835](https://github.com/helix-editor/helix/pull/7835))
160−- Jinja and Handlebars ([#7233](https://github.com/helix-editor/helix/pull/7233))
161−- Pod ([#7907](https://github.com/helix-editor/helix/pull/7907))
162−- Strace ([#7928](https://github.com/helix-editor/helix/pull/7928))
163−- Gemini ([#8070](https://github.com/helix-editor/helix/pull/8070))
164−- GNU Assembler (GAS) ([#8291](https://github.com/helix-editor/helix/pull/8291))
165−- JSON5 ([#8473](https://github.com/helix-editor/helix/pull/8473))
166−- TEMPL ([#8540](https://github.com/helix-editor/helix/pull/8540))
167−
168−Updated languages and queries:
169−
170−- Add one to the ruler numbers for git-commit ([#7072](https://github.com/helix-editor/helix/pull/7072))
171−- Recognize XAML files as XML ([#7083](https://github.com/helix-editor/helix/pull/7083))
172−- Recognize `Cargo.lock` as TOML ([#7095](https://github.com/helix-editor/helix/pull/7095))
173−- Use Rust grammar for Cairo ([c6d1430](https://github.com/helix-editor/helix/commit/c6d1430))
174−- Update tree-sitter-nickel ([#7059](https://github.com/helix-editor/helix/pull/7059), [#7551](https://github.com/helix-editor/helix/pull/7551))
175−- Tune auto-pair characters for Nickel ([#7059](https://github.com/helix-editor/helix/pull/7059))
176−- Recognize `Vagrantfile` as Ruby ([#7112](https://github.com/helix-editor/helix/pull/7112))
177−- Recognize hidden justfiles as Just ([#7088](https://github.com/helix-editor/helix/pull/7088))
178−- Update Java and TypeScript highlight queries ([#7145](https://github.com/helix-editor/helix/pull/7145))
179−- Recognize `.zimrc` as Bash ([#7146](https://github.com/helix-editor/helix/pull/7146))
180−- Recognize `.gir` as XML ([#7152](https://github.com/helix-editor/helix/pull/7152))
181−- Update tree-sitter-scala ([#7147](https://github.com/helix-editor/helix/pull/7147))
182−- Recognize make file-type as Makefile ([#7212](https://github.com/helix-editor/helix/pull/7212))
183−- Update tree-sitter-verilog ([#7262](https://github.com/helix-editor/helix/pull/7262))
184−- Update tree-sitter-cpp ([#7285](https://github.com/helix-editor/helix/pull/7285))
185−- Support core mode for delve debugger ([#7300](https://github.com/helix-editor/helix/pull/7300))
186−- Add Fortran comment injections ([#7305](https://github.com/helix-editor/helix/pull/7305))
187−- Switch Vue language server to `vue-language-server` ([#7312](https://github.com/helix-editor/helix/pull/7312))
188−- Update tree-sitter-sql ([#7387](https://github.com/helix-editor/helix/pull/7387), [#8464](https://github.com/helix-editor/helix/pull/8464))
189−- Replace the MATLAB tre-sitter grammar ([#7388](https://github.com/helix-editor/helix/pull/7388), [#7442](https://github.com/helix-editor/helix/pull/7442), [#7491](https://github.com/helix-editor/helix/pull/7491), [#7493](https://github.com/helix-editor/helix/pull/7493), [#7511](https://github.com/helix-editor/helix/pull/7511), [#7532](https://github.com/helix-editor/helix/pull/7532), [#8040](https://github.com/helix-editor/helix/pull/8040))
190−- Highlight TOML table headers ([#7441](https://github.com/helix-editor/helix/pull/7441))
191−- Recognize `cppm` file-type as C++ ([#7492](https://github.com/helix-editor/helix/pull/7492))
192−- Refactor ecma language queries into private and public queries ([#7207](https://github.com/helix-editor/helix/pull/7207))
193−- Update tree-sitter-dart ([#7576](https://github.com/helix-editor/helix/pull/7576))
194−- Add shebang for nushell files ([#7606](https://github.com/helix-editor/helix/pull/7606))
195−- Recognize systemd files as INI ([#7592](https://github.com/helix-editor/helix/pull/7592))
196−- Update TypeScript, TSX and Svelte grammars ([#6874](https://github.com/helix-editor/helix/pull/6874))
197−- Enable inlay hints in the Svelte language server ([#7622](https://github.com/helix-editor/helix/pull/7622))
198−- Recognize `Brewfile`s as Ruby ([#7629](https://github.com/helix-editor/helix/pull/7629))
199−- Add more file-types for R ([#7633](https://github.com/helix-editor/helix/pull/7633))
200−- Switch tree-sitter-perl to official upstream parser ([#7644](https://github.com/helix-editor/helix/pull/7644), [#7947](https://github.com/helix-editor/helix/pull/7947))
201−- Fix predicate typo in comment highlights ([#7732](https://github.com/helix-editor/helix/pull/7732))
202−- Update tree-sitter-prql ([#7771](https://github.com/helix-editor/helix/pull/7771))
203−- Recognize `.gitf` as JSON ([#7781](https://github.com/helix-editor/helix/pull/7781))
204−- Switch V language server to `v-analyzer` ([#7760](https://github.com/helix-editor/helix/pull/7760))
205−- Add protobuf language servers ([#7796](https://github.com/helix-editor/helix/pull/7796))
206−- Update tree-sitter-zig ([#7803](https://github.com/helix-editor/helix/pull/7803))
207−- Update tree-sitter-hare ([#7784](https://github.com/helix-editor/helix/pull/7784))
208−- Add Java indent queries ([#7844](https://github.com/helix-editor/helix/pull/7844))
209−- Update tree-sitter-scheme ([979933b](https://github.com/helix-editor/helix/commit/979933b))
210−- Recognize `scm` as Scheme instead of TSQ ([5707151](https://github.com/helix-editor/helix/commit/5707151))
211−- Update tree-sitter-git-commit ([#7831](https://github.com/helix-editor/helix/pull/7831))
212−- Update JavaScript, TypeScript and TSX grammars ([#7852](https://github.com/helix-editor/helix/pull/7852))
213−- Update tree-sitter-nu ([#7873](https://github.com/helix-editor/helix/pull/7873))
214−- Fix YAML indentation ([#6768](https://github.com/helix-editor/helix/pull/6768))
215−- Add `csharp-ls`, Pyright, Pylyzer and add roots for Python ([#7897](https://github.com/helix-editor/helix/pull/7897), [#8032](https://github.com/helix-editor/helix/pull/8032))
216−- Update tree-sitter-slint ([#7893](https://github.com/helix-editor/helix/pull/7893))
217−- Recognize more ZSH file-types as Bash ([#7930](https://github.com/helix-editor/helix/pull/7930))
218−- Recognize `star` extension as Starlark ([#7922](https://github.com/helix-editor/helix/pull/7922))
219−- Fix inline HTML tag highlighting in markdown ([#7960](https://github.com/helix-editor/helix/pull/7960))
220−- Update tree-sitter-robot ([#7970](https://github.com/helix-editor/helix/pull/7970))
221−- Highlight Dart 3 `sealed` and `base` keywords ([#7974](https://github.com/helix-editor/helix/pull/7974))
222−- Add configuration for `ltex-ls` to the default `languages.toml` ([#7838](https://github.com/helix-editor/helix/pull/7838))
223−- Update tree-sitter-strace ([#8087](https://github.com/helix-editor/helix/pull/8087))
224−- Update tree-sitter-gleam, enable auto-format ([#8085](https://github.com/helix-editor/helix/pull/8085))
225−- Update tree-sitter-esdl ([#8222](https://github.com/helix-editor/helix/pull/8222))
226−- Expand ignore file-types ([#8220](https://github.com/helix-editor/helix/pull/8220))
227−- Recognize feed related formats as XML ([#8232](https://github.com/helix-editor/helix/pull/8232))
228−- Improve YAML injections ([#8217](https://github.com/helix-editor/helix/pull/8217))
229−- Add shebangs for TypeScript, Julia, Java and OCaml ([95e994a](https://github.com/helix-editor/helix/commit/95e994a))
230−- Highlight abbreviations in Scheme ([ef23847](https://github.com/helix-editor/helix/commit/ef23847))
231−- Remove backtic auto-pair in OCaml ([#8260](https://github.com/helix-editor/helix/pull/8260))
232−- Recognize `flake.lock` as JSON ([#8304](https://github.com/helix-editor/helix/pull/8304))
233−- Add Python test script injection for Nix ([b4494e1](https://github.com/helix-editor/helix/commit/b4494e1))
234−- Fix Nix comment injection precedence ([37e48f4](https://github.com/helix-editor/helix/commit/37e48f4))
235−- Recognize editorconfig files as INI ([#8308](https://github.com/helix-editor/helix/pull/8308))
236−- Recognize `.babelrc` as JSON ([#8309](https://github.com/helix-editor/helix/pull/8309))
237−- Switch Purescript to its own tree-sitter parser ([#8306](https://github.com/helix-editor/helix/pull/8306), [#8338](https://github.com/helix-editor/helix/pull/8338), [#8527](https://github.com/helix-editor/helix/pull/8527))
238−- Update Unison highlights ([#8315](https://github.com/helix-editor/helix/pull/8315))
239−- Recognize `.webmanifest` as JSON ([#8342](https://github.com/helix-editor/helix/pull/8342))
240−- Recognize polkit policy files as XML ([#8369](https://github.com/helix-editor/helix/pull/8369))
241−- Recognize polkit rules files as JavaScript ([#8370](https://github.com/helix-editor/helix/pull/8370))
242−- Update Go highlight queries ([#8399](https://github.com/helix-editor/helix/pull/8399))
243−- Add shebangs for Makefiles ([#8410](https://github.com/helix-editor/helix/pull/8410))
244−- Add file-type associations from VSCode ([#8388](https://github.com/helix-editor/helix/pull/8388))
245−- Add validation to JSON/CSS language server configs ([#8433](https://github.com/helix-editor/helix/pull/8433))
246−- Add a configuration for the tailwind language server ([#8442](https://github.com/helix-editor/helix/pull/8442))
247−- Add a configuration for the ansible language server ([#7973](https://github.com/helix-editor/helix/pull/7973))
248−- Add a configuration for the GraphQL language server ([#8492](https://github.com/helix-editor/helix/pull/8492))
249−- Indent while statements in Bash ([#8528](https://github.com/helix-editor/helix/pull/8528))
250−- Update tree-sitter-haskell and queries ([#8558](https://github.com/helix-editor/helix/pull/8558))
251−
252−Packaging:
253−
254−- Add an overlay to the Nix flake ([#7078](https://github.com/helix-editor/helix/pull/7078))
255−- Check for `git` before fetching or building grammars ([#7320](https://github.com/helix-editor/helix/pull/7320))
256−- Refactor Nix flake to use Crane ([#7763](https://github.com/helix-editor/helix/pull/7763))
257−- Remove the aarch64 appimage from the release CI ([#7832](https://github.com/helix-editor/helix/pull/7832))
258−- Add desktop and icon files to Nix flake output ([#7979](https://github.com/helix-editor/helix/pull/7979))
259−- Build flake packages with the latest stable Rust ([#8133](https://github.com/helix-editor/helix/pull/8133))
260−
2611# 23.05 (2023-05-18)
2622
263323.05 is a smaller release focusing on fixes. There were 88 contributors in this release. Thank you all!
Cargo.lock+609−538
@@ -19,22 +19,41 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
1919
2020[[package]]
2121name = "ahash"
22−version = "0.8.6"
22+version = "0.7.6"
23+source = "registry+https://github.com/rust-lang/crates.io-index"
24+checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
25+dependencies = [
26+ "getrandom",
27+ "once_cell",
28+ "version_check",
29+]
30+
31+[[package]]
32+name = "ahash"
33+version = "0.8.3"
2334source = "registry+https://github.com/rust-lang/crates.io-index"
24−checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
35+checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
2536dependencies = [
2637 "cfg-if",
2738 "getrandom",
2839 "once_cell",
2940 "version_check",
30− "zerocopy",
3141]
3242
3343[[package]]
3444name = "aho-corasick"
35−version = "1.1.2"
45+version = "0.7.20"
3646source = "registry+https://github.com/rust-lang/crates.io-index"
37−checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
47+checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
48+dependencies = [
49+ "memchr",
50+]
51+
52+[[package]]
53+name = "aho-corasick"
54+version = "1.0.2"
55+source = "registry+https://github.com/rust-lang/crates.io-index"
56+checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41"
3857dependencies = [
3958 "memchr",
4059]
@@ -62,9 +81,9 @@ dependencies = [
6281
6382[[package]]
6483name = "anyhow"
65−version = "1.0.76"
84+version = "1.0.72"
6685source = "registry+https://github.com/rust-lang/crates.io-index"
67−checksum = "59d2a3357dde987206219e78ecfbbb6e8dad06cbb65292758d3270e6254f7355"
86+checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854"
6887
6988[[package]]
7089name = "arc-swap"
@@ -88,7 +107,7 @@ dependencies = [
88107 "cc",
89108 "cfg-if",
90109 "libc",
91− "miniz_oxide",
110+ "miniz_oxide 0.7.1",
92111 "object",
93112 "rustc-demangle",
94113]
@@ -101,15 +120,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
101120
102121[[package]]
103122name = "bitflags"
104−version = "2.4.1"
123+version = "2.3.3"
105124source = "registry+https://github.com/rust-lang/crates.io-index"
106−checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
125+checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
107126
108127[[package]]
109128name = "bstr"
110−version = "1.8.0"
129+version = "1.6.0"
111130source = "registry+https://github.com/rust-lang/crates.io-index"
112−checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c"
131+checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05"
113132dependencies = [
114133 "memchr",
115134 "regex-automata",
@@ -131,6 +150,12 @@ version = "3.12.0"
131150source = "registry+https://github.com/rust-lang/crates.io-index"
132151checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
133152
153+[[package]]
154+name = "bytecount"
155+version = "0.6.3"
156+source = "registry+https://github.com/rust-lang/crates.io-index"
157+checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c"
158+
134159[[package]]
135160name = "bytes"
136161version = "1.4.0"
@@ -145,12 +170,9 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
145170
146171[[package]]
147172name = "cc"
148−version = "1.0.84"
173+version = "1.0.79"
149174source = "registry+https://github.com/rust-lang/crates.io-index"
150−checksum = "0f8e7c90afad890484a21653d08b6e209ae34770fb5ee298f9c699fcc1e5c856"
151−dependencies = [
152− "libc",
153−]
175+checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
154176
155177[[package]]
156178name = "cfg-if"
@@ -171,23 +193,25 @@ dependencies = [
171193
172194[[package]]
173195name = "chrono"
174−version = "0.4.31"
196+version = "0.4.26"
175197source = "registry+https://github.com/rust-lang/crates.io-index"
176−checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
198+checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
177199dependencies = [
178200 "android-tzdata",
179201 "iana-time-zone",
180202 "num-traits",
181− "windows-targets 0.48.0",
203+ "winapi",
182204]
183205
184206[[package]]
185207name = "clipboard-win"
186−version = "5.0.0"
208+version = "4.5.0"
187209source = "registry+https://github.com/rust-lang/crates.io-index"
188−checksum = "c57002a5d9be777c1ef967e33674dac9ebd310d8893e4e3437b14d5f0f6372cc"
210+checksum = "7191c27c2357d9b7ef96baac1773290d4ca63b24205b82a3fd8a0637afcf0362"
189211dependencies = [
190212 "error-code",
213+ "str-buf",
214+ "winapi",
191215]
192216
193217[[package]]
@@ -221,12 +245,6 @@ version = "0.8.4"
221245source = "registry+https://github.com/rust-lang/crates.io-index"
222246checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
223247
224−[[package]]
225−name = "cov-mark"
226−version = "1.1.0"
227−source = "registry+https://github.com/rust-lang/crates.io-index"
228−checksum = "9ffa3d3e0138386cd4361f63537765cac7ee40698028844635a54495a92f67f3"
229−
230248[[package]]
231249name = "crc32fast"
232250version = "1.3.2"
@@ -236,56 +254,13 @@ dependencies = [
236254 "cfg-if",
237255]
238256
239−[[package]]
240−name = "crossbeam-channel"
241−version = "0.5.8"
242−source = "registry+https://github.com/rust-lang/crates.io-index"
243−checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
244−dependencies = [
245− "cfg-if",
246− "crossbeam-utils",
247−]
248−
249−[[package]]
250−name = "crossbeam-deque"
251−version = "0.8.3"
252−source = "registry+https://github.com/rust-lang/crates.io-index"
253−checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
254−dependencies = [
255− "cfg-if",
256− "crossbeam-epoch",
257− "crossbeam-utils",
258−]
259−
260−[[package]]
261−name = "crossbeam-epoch"
262−version = "0.9.15"
263−source = "registry+https://github.com/rust-lang/crates.io-index"
264−checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
265−dependencies = [
266− "autocfg",
267− "cfg-if",
268− "crossbeam-utils",
269− "memoffset",
270− "scopeguard",
271−]
272−
273−[[package]]
274−name = "crossbeam-utils"
275−version = "0.8.16"
276−source = "registry+https://github.com/rust-lang/crates.io-index"
277−checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
278−dependencies = [
279− "cfg-if",
280−]
281−
282257[[package]]
283258name = "crossterm"
284−version = "0.27.0"
259+version = "0.26.1"
285260source = "registry+https://github.com/rust-lang/crates.io-index"
286−checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
261+checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13"
287262dependencies = [
288− "bitflags 2.4.1",
263+ "bitflags 1.3.2",
289264 "crossterm_winapi",
290265 "filedescriptor",
291266 "futures-core",
@@ -299,9 +274,9 @@ dependencies = [
299274
300275[[package]]
301276name = "crossterm_winapi"
302−version = "0.9.1"
277+version = "0.9.0"
303278source = "registry+https://github.com/rust-lang/crates.io-index"
304−checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
279+checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c"
305280dependencies = [
306281 "winapi",
307282]
@@ -330,7 +305,7 @@ dependencies = [
330305 "proc-macro2",
331306 "quote",
332307 "scratch",
333− "syn 2.0.38",
308+ "syn 2.0.28",
334309]
335310
336311[[package]]
@@ -347,7 +322,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5"
347322dependencies = [
348323 "proc-macro2",
349324 "quote",
350− "syn 2.0.38",
325+ "syn 2.0.28",
351326]
352327
353328[[package]]
@@ -364,9 +339,9 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
364339
365340[[package]]
366341name = "encoding_rs"
367−version = "0.8.33"
342+version = "0.8.32"
368343source = "registry+https://github.com/rust-lang/crates.io-index"
369−checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
344+checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394"
370345dependencies = [
371346 "cfg-if",
372347]
@@ -388,19 +363,34 @@ checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1"
388363
389364[[package]]
390365name = "errno"
391−version = "0.3.8"
366+version = "0.3.1"
367+source = "registry+https://github.com/rust-lang/crates.io-index"
368+checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
369+dependencies = [
370+ "errno-dragonfly",
371+ "libc",
372+ "windows-sys 0.48.0",
373+]
374+
375+[[package]]
376+name = "errno-dragonfly"
377+version = "0.1.2"
392378source = "registry+https://github.com/rust-lang/crates.io-index"
393−checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
379+checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
394380dependencies = [
381+ "cc",
395382 "libc",
396− "windows-sys 0.52.0",
397383]
398384
399385[[package]]
400386name = "error-code"
401−version = "3.0.0"
387+version = "2.3.1"
402388source = "registry+https://github.com/rust-lang/crates.io-index"
403−checksum = "281e452d3bad4005426416cdba5ccfd4f5c1280e10099e21db27f7c1c28347fc"
389+checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21"
390+dependencies = [
391+ "libc",
392+ "str-buf",
393+]
404394
405395[[package]]
406396name = "etcetera"
@@ -413,15 +403,6 @@ dependencies = [
413403 "windows-sys 0.48.0",
414404]
415405
416−[[package]]
417−name = "faster-hex"
418−version = "0.9.0"
419−source = "registry+https://github.com/rust-lang/crates.io-index"
420−checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183"
421−dependencies = [
422− "serde",
423−]
424−
425406[[package]]
426407name = "fastrand"
427408version = "2.0.0"
@@ -448,36 +429,54 @@ dependencies = [
448429 "winapi",
449430]
450431
432+[[package]]
433+name = "filetime"
434+version = "0.2.21"
435+source = "registry+https://github.com/rust-lang/crates.io-index"
436+checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153"
437+dependencies = [
438+ "cfg-if",
439+ "libc",
440+ "redox_syscall 0.2.16",
441+ "windows-sys 0.48.0",
442+]
443+
451444[[package]]
452445name = "flate2"
453−version = "1.0.27"
446+version = "1.0.25"
454447source = "registry+https://github.com/rust-lang/crates.io-index"
455−checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010"
448+checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
456449dependencies = [
457450 "crc32fast",
458− "miniz_oxide",
451+ "miniz_oxide 0.6.2",
459452]
460453
454+[[package]]
455+name = "fnv"
456+version = "1.0.7"
457+source = "registry+https://github.com/rust-lang/crates.io-index"
458+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
459+
461460[[package]]
462461name = "form_urlencoded"
463−version = "1.2.1"
462+version = "1.2.0"
464463source = "registry+https://github.com/rust-lang/crates.io-index"
465−checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
464+checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
466465dependencies = [
467466 "percent-encoding",
468467]
469468
470469[[package]]
471470name = "futures-core"
472−version = "0.3.30"
471+version = "0.3.28"
473472source = "registry+https://github.com/rust-lang/crates.io-index"
474−checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
473+checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
475474
476475[[package]]
477476name = "futures-executor"
478−version = "0.3.29"
477+version = "0.3.28"
479478source = "registry+https://github.com/rust-lang/crates.io-index"
480−checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc"
479+checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
481480dependencies = [
482481 "futures-core",
483482 "futures-task",
@@ -486,15 +485,15 @@ dependencies = [
486485
487486[[package]]
488487name = "futures-task"
489−version = "0.3.30"
488+version = "0.3.28"
490489source = "registry+https://github.com/rust-lang/crates.io-index"
491−checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
490+checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
492491
493492[[package]]
494493name = "futures-util"
495−version = "0.3.30"
494+version = "0.3.28"
496495source = "registry+https://github.com/rust-lang/crates.io-index"
497−checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
496+checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
498497dependencies = [
499498 "futures-core",
500499 "futures-task",
@@ -503,6 +502,15 @@ dependencies = [
503502 "slab",
504503]
505504
505+[[package]]
506+name = "fuzzy-matcher"
507+version = "0.3.7"
508+source = "registry+https://github.com/rust-lang/crates.io-index"
509+checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94"
510+dependencies = [
511+ "thread_local",
512+]
513+
506514[[package]]
507515name = "getrandom"
508516version = "0.2.9"
@@ -522,13 +530,15 @@ checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
522530
523531[[package]]
524532name = "gix"
525−version = "0.57.0"
533+version = "0.48.0"
526534source = "registry+https://github.com/rust-lang/crates.io-index"
527−checksum = "721c7497ab24b665ed5a1eb2b3526936aa60068e61ba260651f7e77c52feec69"
535+checksum = "c1e74cea676de7f53a79f3c0365812b11f6814b81e671b8ee4abae6ca09c7881"
528536dependencies = [
529537 "gix-actor",
538+ "gix-attributes",
530539 "gix-commitgraph",
531540 "gix-config",
541+ "gix-credentials",
532542 "gix-date",
533543 "gix-diff",
534544 "gix-discover",
@@ -537,16 +547,19 @@ dependencies = [
537547 "gix-glob",
538548 "gix-hash",
539549 "gix-hashtable",
550+ "gix-ignore",
551+ "gix-index",
540552 "gix-lock",
541− "gix-macros",
553+ "gix-mailmap",
554+ "gix-negotiate",
542555 "gix-object",
543556 "gix-odb",
544557 "gix-pack",
545558 "gix-path",
559+ "gix-prompt",
546560 "gix-ref",
547561 "gix-refspec",
548562 "gix-revision",
549− "gix-revwalk",
550563 "gix-sec",
551564 "gix-tempfile",
552565 "gix-trace",
@@ -554,8 +567,10 @@ dependencies = [
554567 "gix-url",
555568 "gix-utils",
556569 "gix-validate",
570+ "gix-worktree",
571+ "log",
557572 "once_cell",
558− "parking_lot",
573+ "signal-hook",
559574 "smallvec",
560575 "thiserror",
561576 "unicode-normalization",
@@ -563,46 +578,81 @@ dependencies = [
563578
564579[[package]]
565580name = "gix-actor"
566−version = "0.29.0"
581+version = "0.23.0"
567582source = "registry+https://github.com/rust-lang/crates.io-index"
568−checksum = "886014c4865b93ce268f1d3eddd4fd3261242c3f3ee61eb36009f913016a9059"
583+checksum = "1969b77b9ee4cc1755c841987ec6f7622aaca95e952bcafb76973ae59d1b8716"
569584dependencies = [
570585 "bstr",
571586 "btoi",
572587 "gix-date",
573588 "itoa",
589+ "nom",
590+ "thiserror",
591+]
592+
593+[[package]]
594+name = "gix-attributes"
595+version = "0.14.1"
596+source = "registry+https://github.com/rust-lang/crates.io-index"
597+checksum = "e3772b0129dcd1fc73e985bbd08a1482d082097d2915cb1ee31ce8092b8e4434"
598+dependencies = [
599+ "bstr",
600+ "gix-glob",
601+ "gix-path",
602+ "gix-quote",
603+ "kstring",
604+ "log",
605+ "smallvec",
606+ "thiserror",
607+ "unicode-bom",
608+]
609+
610+[[package]]
611+name = "gix-bitmap"
612+version = "0.2.5"
613+source = "registry+https://github.com/rust-lang/crates.io-index"
614+checksum = "311e2fa997be6560c564b070c5da2d56d038b645a94e1e5796d5d85a350da33c"
615+dependencies = [
574616 "thiserror",
575− "winnow 0.5.28",
576617]
577618
578619[[package]]
579620name = "gix-chunk"
580−version = "0.4.6"
621+version = "0.4.3"
581622source = "registry+https://github.com/rust-lang/crates.io-index"
582−checksum = "2ade37ef69870de0ed966b97c57a3a947a22ff3482a52c3b99b205f77bcb08fb"
623+checksum = "39db5ed0fc0a2e9b1b8265993f7efdbc30379dec268f3b91b7af0c2de4672fdd"
583624dependencies = [
584625 "thiserror",
585626]
586627
628+[[package]]
629+name = "gix-command"
630+version = "0.2.6"
631+source = "registry+https://github.com/rust-lang/crates.io-index"
632+checksum = "bb49ab557a37b0abb2415bca2b10e541277dff0565deb5bd5e99fd95f93f51eb"
633+dependencies = [
634+ "bstr",
635+]
636+
587637[[package]]
588638name = "gix-commitgraph"
589−version = "0.23.0"
639+version = "0.17.1"
590640source = "registry+https://github.com/rust-lang/crates.io-index"
591−checksum = "e7559ea9cefee188cd88b05afcc8e3ef7a3cb4a5c647bccf06b981e591b02b77"
641+checksum = "ed42baa50075d41c1a0931074ce1a97c5797c7c6fe7591d9f1f2dcd448532c26"
592642dependencies = [
593643 "bstr",
594644 "gix-chunk",
595645 "gix-features",
596646 "gix-hash",
597− "memmap2",
647+ "memmap2 0.7.1",
598648 "thiserror",
599649]
600650
601651[[package]]
602652name = "gix-config"
603−version = "0.33.0"
653+version = "0.25.1"
604654source = "registry+https://github.com/rust-lang/crates.io-index"
605−checksum = "9c35dc7f9c00a42bbc9cfa1ca2ec0a78ad1b76ff0736d3d35dfd612962244467"
655+checksum = "817688c7005a716d9363e267913526adea402dabd947f4ba63842d10cc5132af"
606656dependencies = [
607657 "bstr",
608658 "gix-config-value",
@@ -611,32 +661,49 @@ dependencies = [
611661 "gix-path",
612662 "gix-ref",
613663 "gix-sec",
664+ "log",
614665 "memchr",
666+ "nom",
615667 "once_cell",
616668 "smallvec",
617669 "thiserror",
618670 "unicode-bom",
619− "winnow 0.5.28",
620671]
621672
622673[[package]]
623674name = "gix-config-value"
624−version = "0.14.2"
675+version = "0.12.3"
625676source = "registry+https://github.com/rust-lang/crates.io-index"
626−checksum = "39f388cb2396aee82d6f460a2e7770659bdf8854e9e5478f7d2b1324a9698284"
677+checksum = "83960be5e99266bcf55dae5a24731bbd39f643bfb68f27e939d6b06836b5b87d"
627678dependencies = [
628− "bitflags 2.4.1",
679+ "bitflags 2.3.3",
629680 "bstr",
630681 "gix-path",
631682 "libc",
632683 "thiserror",
633684]
634685
686+[[package]]
687+name = "gix-credentials"
688+version = "0.16.1"
689+source = "registry+https://github.com/rust-lang/crates.io-index"
690+checksum = "75a75565e0e6e7f80cfa4eb1b05cc448c6846ddd48dcf413a28875fbc11ee9af"
691+dependencies = [
692+ "bstr",
693+ "gix-command",
694+ "gix-config-value",
695+ "gix-path",
696+ "gix-prompt",
697+ "gix-sec",
698+ "gix-url",
699+ "thiserror",
700+]
701+
635702[[package]]
636703name = "gix-date"
637−version = "0.8.2"
704+version = "0.7.0"
638705source = "registry+https://github.com/rust-lang/crates.io-index"
639−checksum = "9d85f4a01e0d05c3de585e28bae514d4baf01655e3fc3f14ce6f30bf62405345"
706+checksum = "8e9a04a1d2387c955ec91059d56b673000dd24f3c07cad08ed253e36381782bf"
640707dependencies = [
641708 "bstr",
642709 "itoa",
@@ -646,21 +713,21 @@ dependencies = [
646713
647714[[package]]
648715name = "gix-diff"
649−version = "0.39.0"
716+version = "0.32.0"
650717source = "registry+https://github.com/rust-lang/crates.io-index"
651−checksum = "ac0e75f5afd2f6c47c800b6b0a000a08045739d0450d20482e8faa42543f62d1"
718+checksum = "aaf5d9b9b521b284ebe53ee69eee33341835ec70edc314f36b2100ea81396121"
652719dependencies = [
653− "bstr",
654720 "gix-hash",
655721 "gix-object",
722+ "imara-diff",
656723 "thiserror",
657724]
658725
659726[[package]]
660727name = "gix-discover"
661−version = "0.28.0"
728+version = "0.21.1"
662729source = "registry+https://github.com/rust-lang/crates.io-index"
663−checksum = "f0b63ce2ad81632ac1a84ac370f85a5e580c3261580bd85ea17ff35d3a0bba18"
730+checksum = "272aad20dc63dedba76615373dd8885fb5aebe4795e5b5b0aa2a24e63c82085c"
664731dependencies = [
665732 "bstr",
666733 "dunce",
@@ -673,9 +740,9 @@ dependencies = [
673740
674741[[package]]
675742name = "gix-features"
676−version = "0.37.0"
743+version = "0.31.1"
677744source = "registry+https://github.com/rust-lang/crates.io-index"
678−checksum = "befe7edea299a824504b5acc96d7a3a538125b38c42f3a8379f6912a29c90c81"
745+checksum = "06142d8cff5d17509399b04052b64d2f9b3a311d5cff0b1a32b220f62cd0d595"
679746dependencies = [
680747 "crc32fast",
681748 "flate2",
@@ -691,20 +758,20 @@ dependencies = [
691758
692759[[package]]
693760name = "gix-fs"
694−version = "0.9.0"
761+version = "0.3.0"
695762source = "registry+https://github.com/rust-lang/crates.io-index"
696−checksum = "007017ce93b819ea52c0ec68306f7d72212a2d307c3d70f1548c7141c015d0a1"
763+checksum = "bb15956bc0256594c62a2399fcf6958a02a11724217eddfdc2b49b21b6292496"
697764dependencies = [
698765 "gix-features",
699766]
700767
701768[[package]]
702769name = "gix-glob"
703−version = "0.15.0"
770+version = "0.9.1"
704771source = "registry+https://github.com/rust-lang/crates.io-index"
705−checksum = "61fb116c2516d3a1170e010118f639944a6389872c875a008960cdab2a44ac72"
772+checksum = "c18bdff83143d61e7d60da6183b87542a870d026b2a2d0b30170b8e9c0cd321a"
706773dependencies = [
707− "bitflags 2.4.1",
774+ "bitflags 2.3.3",
708775 "bstr",
709776 "gix-features",
710777 "gix-path",
@@ -712,30 +779,64 @@ dependencies = [
712779
713780[[package]]
714781name = "gix-hash"
715−version = "0.14.0"
782+version = "0.11.3"
716783source = "registry+https://github.com/rust-lang/crates.io-index"
717−checksum = "c52c3170a17b6031833cd2eb4ad7bc23f2755d06e6e70f78dec21d42e8fe1b30"
784+checksum = "a0dd58cdbe7ffa4032fc111864c80d5f8cecd9a2c9736c97ae7e5be834188272"
718785dependencies = [
719− "faster-hex",
786+ "hex",
720787 "thiserror",
721788]
722789
723790[[package]]
724791name = "gix-hashtable"
725−version = "0.5.0"
792+version = "0.2.3"
726793source = "registry+https://github.com/rust-lang/crates.io-index"
727−checksum = "40a838e6366a5e5b84668b6997ce0981b833136468e8ba949f424c0ef2927eba"
794+checksum = "9e133bc56d938eaec1c675af7c681a51de9662b0ada779f45607b967a10da77a"
728795dependencies = [
729796 "gix-hash",
730− "hashbrown 0.14.3",
797+ "hashbrown 0.14.0",
731798 "parking_lot",
732799]
733800
801+[[package]]
802+name = "gix-ignore"
803+version = "0.4.1"
804+source = "registry+https://github.com/rust-lang/crates.io-index"
805+checksum = "ca801f2d0535210f77b33e2c067d565aedecacc82f1b3dbce26da1388ebc4634"
806+dependencies = [
807+ "bstr",
808+ "gix-glob",
809+ "gix-path",
810+ "unicode-bom",
811+]
812+
813+[[package]]
814+name = "gix-index"
815+version = "0.20.0"
816+source = "registry+https://github.com/rust-lang/crates.io-index"
817+checksum = "68099abdf6ee50ae3c897e8b05de96871cbe54d52a37cdf559101f911b883562"
818+dependencies = [
819+ "bitflags 2.3.3",
820+ "bstr",
821+ "btoi",
822+ "filetime",
823+ "gix-bitmap",
824+ "gix-features",
825+ "gix-hash",
826+ "gix-lock",
827+ "gix-object",
828+ "gix-traverse",
829+ "itoa",
830+ "memmap2 0.7.1",
831+ "smallvec",
832+ "thiserror",
833+]
834+
734835[[package]]
735836name = "gix-lock"
736−version = "12.0.0"
837+version = "7.0.0"
737838source = "registry+https://github.com/rust-lang/crates.io-index"
738−checksum = "6cf112ddee94223c119a8534dad027740dc3aba3365ac5edeef8a7f6660c74db"
839+checksum = "328f50aad713ab606caeaf834459ef915ccdfbb9133ac6cd54616d601aa9249f"
739840dependencies = [
740841 "gix-tempfile",
741842 "gix-utils",
@@ -743,21 +844,38 @@ dependencies = [
743844]
744845
745846[[package]]
746−name = "gix-macros"
747−version = "0.1.2"
847+name = "gix-mailmap"
848+version = "0.15.0"
748849source = "registry+https://github.com/rust-lang/crates.io-index"
749−checksum = "fc207b64189cf71bcb17fc841ab99a5d63d0845546b611e2703ce467f659323a"
850+checksum = "1787e3c37fc43b1f7c0e3be6196c6837b3ba5f869190dfeaa444b816f0a7f34b"
750851dependencies = [
751− "proc-macro2",
752− "quote",
753− "syn 2.0.38",
852+ "bstr",
853+ "gix-actor",
854+ "gix-date",
855+ "thiserror",
856+]
857+
858+[[package]]
859+name = "gix-negotiate"
860+version = "0.4.0"
861+source = "registry+https://github.com/rust-lang/crates.io-index"
862+checksum = "4e7bce64d4452dd609f44d04b14b29da2e0ad2c45fcdf4ce1472a5f5f8ec21c2"
863+dependencies = [
864+ "bitflags 2.3.3",
865+ "gix-commitgraph",
866+ "gix-date",
867+ "gix-hash",
868+ "gix-object",
869+ "gix-revwalk",
870+ "smallvec",
871+ "thiserror",
754872]
755873
756874[[package]]
757875name = "gix-object"
758−version = "0.40.0"
876+version = "0.32.0"
759877source = "registry+https://github.com/rust-lang/crates.io-index"
760−checksum = "e4c77e47ffba92127faf632a841fce23d19547e269bd8b88e68961a70eab4e93"
878+checksum = "a953f3d7ffad16734aa3ab1d05807972c80e339d1bd9dde03e0198716b99e2a6"
761879dependencies = [
762880 "bstr",
763881 "btoi",
@@ -766,17 +884,18 @@ dependencies = [
766884 "gix-features",
767885 "gix-hash",
768886 "gix-validate",
887+ "hex",
769888 "itoa",
889+ "nom",
770890 "smallvec",
771891 "thiserror",
772− "winnow 0.5.28",
773892]
774893
775894[[package]]
776895name = "gix-odb"
777−version = "0.56.0"
896+version = "0.49.1"
778897source = "registry+https://github.com/rust-lang/crates.io-index"
779−checksum = "a3254f2005cc7553ea78e85e816a09150c6f7a64e6b7627b8d1fdc56721bea73"
898+checksum = "f6418cff00ecc2713b58c8e04bff30dda808fbba1a080e7248b299d069894a01"
780899dependencies = [
781900 "arc-swap",
782901 "gix-date",
@@ -793,19 +912,21 @@ dependencies = [
793912
794913[[package]]
795914name = "gix-pack"
796−version = "0.46.0"
915+version = "0.39.1"
797916source = "registry+https://github.com/rust-lang/crates.io-index"
798−checksum = "02ebc8cd657eec207d82d8f876ca402361308ecd3c87a47935b0299506257b4f"
917+checksum = "414935138d90043ea5898de7a93f02c2558e52652492719470e203ef26a8fd0a"
799918dependencies = [
800919 "clru",
801920 "gix-chunk",
921+ "gix-diff",
802922 "gix-features",
803923 "gix-hash",
804924 "gix-hashtable",
805925 "gix-object",
806926 "gix-path",
807927 "gix-tempfile",
808− "memmap2",
928+ "gix-traverse",
929+ "memmap2 0.7.1",
809930 "parking_lot",
810931 "smallvec",
811932 "thiserror",
@@ -813,9 +934,9 @@ dependencies = [
813934
814935[[package]]
815936name = "gix-path"
816−version = "0.10.2"
937+version = "0.8.3"
817938source = "registry+https://github.com/rust-lang/crates.io-index"
818−checksum = "10931652a3da126990ac93bce1b1c600cc99d7c268d712b6360ed52174ce1b68"
939+checksum = "dfca182d2575ded2ed38280f1ebf75cd5d3790b77e0872de07854cf085821fbe"
819940dependencies = [
820941 "bstr",
821942 "gix-trace",
@@ -824,11 +945,24 @@ dependencies = [
824945 "thiserror",
825946]
826947
948+[[package]]
949+name = "gix-prompt"
950+version = "0.5.2"
951+source = "registry+https://github.com/rust-lang/crates.io-index"
952+checksum = "8dfd363fd89a40c1e7bff9c9c1b136cd2002480f724b0c627c1bc771cd5480ec"
953+dependencies = [
954+ "gix-command",
955+ "gix-config-value",
956+ "parking_lot",
957+ "rustix 0.37.15",
958+ "thiserror",
959+]
960+
827961[[package]]
828962name = "gix-quote"
829−version = "0.4.9"
963+version = "0.4.5"
830964source = "registry+https://github.com/rust-lang/crates.io-index"
831−checksum = "6c43530cb94a7759807e6f8d180e17ac9c65673b891645c6c433831dc0cf4342"
965+checksum = "3874de636c2526de26a3405b8024b23ef1a327bebf4845d770d00d48700b6a40"
832966dependencies = [
833967 "bstr",
834968 "btoi",
@@ -837,9 +971,9 @@ dependencies = [
837971
838972[[package]]
839973name = "gix-ref"
840−version = "0.40.0"
974+version = "0.32.1"
841975source = "registry+https://github.com/rust-lang/crates.io-index"
842−checksum = "baa951b3b850d6d1be4f900768e49af20b76bf9505beac22af723d57249a2f1d"
976+checksum = "39453f4e5f23cddc2e6e4cca2ba20adfdbec29379e3ca829714dfe98ae068ccd"
843977dependencies = [
844978 "gix-actor",
845979 "gix-date",
@@ -851,16 +985,16 @@ dependencies = [
851985 "gix-path",
852986 "gix-tempfile",
853987 "gix-validate",
854− "memmap2",
988+ "memmap2 0.7.1",
989+ "nom",
855990 "thiserror",
856− "winnow 0.5.28",
857991]
858992
859993[[package]]
860994name = "gix-refspec"
861−version = "0.21.0"
995+version = "0.13.0"
862996source = "registry+https://github.com/rust-lang/crates.io-index"
863−checksum = "88c61f849d58c06e3068a0b601cf10127d2a07cdad00a725ed66cf303f76f6b3"
997+checksum = "b8e76ff1f82fba295a121e31ab02f69642994e532c45c0c899aa393f4b740302"
864998dependencies = [
865999 "bstr",
8661000 "gix-hash",
@@ -872,9 +1006,9 @@ dependencies = [
8721006
8731007[[package]]
8741008name = "gix-revision"
875−version = "0.25.0"
1009+version = "0.17.0"
8761010source = "registry+https://github.com/rust-lang/crates.io-index"
877−checksum = "bcbbf91f4200c5c76802ef5f057b96f5a336827508881fe55a780be71a794d22"
1011+checksum = "237428a7d3978e8572964e1e45d984027c2acc94df47e594baa6c4b0da7c9922"
8781012dependencies = [
8791013 "bstr",
8801014 "gix-date",
@@ -882,15 +1016,14 @@ dependencies = [
8821016 "gix-hashtable",
8831017 "gix-object",
8841018 "gix-revwalk",
885− "gix-trace",
8861019 "thiserror",
8871020]
8881021
8891022[[package]]
8901023name = "gix-revwalk"
891−version = "0.11.0"
1024+version = "0.3.0"
8921025source = "registry+https://github.com/rust-lang/crates.io-index"
893−checksum = "33ab66354d83f70f2730391747d0c75f94ef3c3dd40ebde2e206db9faaf7a0a7"
1026+checksum = "028d50fcaf8326a8f79a359490d9ca9fb4e2b51ac9ac86503560d0bcc888d2eb"
8941027dependencies = [
8951028 "gix-commitgraph",
8961029 "gix-date",
@@ -903,40 +1036,42 @@ dependencies = [
9031036
9041037[[package]]
9051038name = "gix-sec"
906−version = "0.10.2"
1039+version = "0.8.3"
9071040source = "registry+https://github.com/rust-lang/crates.io-index"
908−checksum = "a9963f38a42144253ed4d571882d7db5ef644c12e6726e4b75135597cc9d0e1a"
1041+checksum = "ede298863db2a0574a14070991710551e76d1f47c9783b62d4fcbca17f56371c"
9091042dependencies = [
910− "bitflags 2.4.1",
1043+ "bitflags 2.3.3",
9111044 "gix-path",
9121045 "libc",
913− "windows 0.52.0",
1046+ "windows",
9141047]
9151048
9161049[[package]]
9171050name = "gix-tempfile"
918−version = "12.0.0"
1051+version = "7.0.0"
9191052source = "registry+https://github.com/rust-lang/crates.io-index"
920−checksum = "e76a494bd530e1a1309188ff971825a24f159c76c2db0bf71fa5dfb469a2c915"
1053+checksum = "4fac8310c17406ea619af72f42ee46dac795110f68f41b4f4fa231b69889c6a2"
9211054dependencies = [
9221055 "gix-fs",
9231056 "libc",
9241057 "once_cell",
9251058 "parking_lot",
1059+ "signal-hook",
1060+ "signal-hook-registry",
9261061 "tempfile",
9271062]
9281063
9291064[[package]]
9301065name = "gix-trace"
931−version = "0.1.5"
1066+version = "0.1.2"
9321067source = "registry+https://github.com/rust-lang/crates.io-index"
933−checksum = "bda62acb44dd86a40c7c3762a5403cfc1ac789ea559df54085cedf79864f809e"
1068+checksum = "103eac621617be3ebe0605c9065ca51a223279a23218aaf67d10daa6e452f663"
9341069
9351070[[package]]
9361071name = "gix-traverse"
937−version = "0.36.0"
1072+version = "0.29.0"
9381073source = "registry+https://github.com/rust-lang/crates.io-index"
939−checksum = "8661fab39985c9214e56d81a63ceb5886ac948cec2fba76c39494d1e0e307ea8"
1074+checksum = "e3cdfd54598db4fae57d5ae6f52958422b2d13382d2745796bfe5c8015ffa86e"
9401075dependencies = [
9411076 "gix-commitgraph",
9421077 "gix-date",
@@ -950,9 +1085,9 @@ dependencies = [
9501085
9511086[[package]]
9521087name = "gix-url"
953−version = "0.26.0"
1088+version = "0.20.1"
9541089source = "registry+https://github.com/rust-lang/crates.io-index"
955−checksum = "10a0129c1e8b52736d7c5128300a4485dbc85863001371e2771ac1754bd89fd7"
1090+checksum = "beaede6dbc83f408b19adfd95bb52f1dbf01fb8862c3faf6c6243e2e67fcdfa1"
9561091dependencies = [
9571092 "bstr",
9581093 "gix-features",
@@ -964,71 +1099,94 @@ dependencies = [
9641099
9651100[[package]]
9661101name = "gix-utils"
967−version = "0.1.7"
1102+version = "0.1.4"
9681103source = "registry+https://github.com/rust-lang/crates.io-index"
969−checksum = "ab9277a5e32e85d53f738096d872a4a9b76067ad471894ad31bd99c8fa2da1dc"
1104+checksum = "7058c94f4164fcf5b8457d35f6d8f6e1007f9f7f938c9c7684a7e01d23c6ddde"
9701105dependencies = [
9711106 "fastrand",
9721107]
9731108
9741109[[package]]
9751110name = "gix-validate"
976−version = "0.8.2"
1111+version = "0.7.6"
9771112source = "registry+https://github.com/rust-lang/crates.io-index"
978−checksum = "f805ebbdbaa4bfd98e2ee43e6d14099b8a4d9141f5d7b8202fea4d48e44263e7"
1113+checksum = "8d092b594c8af00a3a31fe526d363ee8a51a6f29d8496cdb991ed2f01ec0ec13"
9791114dependencies = [
9801115 "bstr",
9811116 "thiserror",
9821117]
9831118
1119+[[package]]
1120+name = "gix-worktree"
1121+version = "0.21.1"
1122+source = "registry+https://github.com/rust-lang/crates.io-index"
1123+checksum = "c1363b9aa66b9e14412ac04e1f759827203f491729d92172535a8ce6cde02efa"
1124+dependencies = [
1125+ "bstr",
1126+ "filetime",
1127+ "gix-attributes",
1128+ "gix-features",
1129+ "gix-fs",
1130+ "gix-glob",
1131+ "gix-hash",
1132+ "gix-ignore",
1133+ "gix-index",
1134+ "gix-object",
1135+ "gix-path",
1136+ "io-close",
1137+ "thiserror",
1138+]
1139+
9841140[[package]]
9851141name = "globset"
986−version = "0.4.14"
1142+version = "0.4.13"
9871143source = "registry+https://github.com/rust-lang/crates.io-index"
988−checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
1144+checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d"
9891145dependencies = [
990− "aho-corasick",
1146+ "aho-corasick 1.0.2",
9911147 "bstr",
1148+ "fnv",
9921149 "log",
993− "regex-automata",
994− "regex-syntax",
1150+ "regex",
9951151]
9961152
9971153[[package]]
9981154name = "grep-matcher"
999−version = "0.1.7"
1155+version = "0.1.6"
10001156source = "registry+https://github.com/rust-lang/crates.io-index"
1001−checksum = "47a3141a10a43acfedc7c98a60a834d7ba00dfe7bec9071cbfc19b55b292ac02"
1157+checksum = "3902ca28f26945fe35cad349d776f163981d777fee382ccd6ef451126f51b319"
10021158dependencies = [
10031159 "memchr",
10041160]
10051161
10061162[[package]]
10071163name = "grep-regex"
1008−version = "0.1.12"
1164+version = "0.1.11"
10091165source = "registry+https://github.com/rust-lang/crates.io-index"
1010−checksum = "f748bb135ca835da5cbc67ca0e6955f968db9c5df74ca4f56b18e1ddbc68230d"
1166+checksum = "997598b41d53a37a2e3fc5300d5c11d825368c054420a9c65125b8fe1078463f"
10111167dependencies = [
1168+ "aho-corasick 0.7.20",
10121169 "bstr",
10131170 "grep-matcher",
10141171 "log",
1015− "regex-automata",
1016− "regex-syntax",
1172+ "regex",
1173+ "regex-syntax 0.6.29",
1174+ "thread_local",
10171175]
10181176
10191177[[package]]
10201178name = "grep-searcher"
1021−version = "0.1.13"
1179+version = "0.1.11"
10221180source = "registry+https://github.com/rust-lang/crates.io-index"
1023−checksum = "ba536ae4f69bec62d8839584dd3153d3028ef31bb229f04e09fb5a9e5a193c54"
1181+checksum = "5601c4b9f480f0c9ebb40b1f6cbf447b8a50c5369223937a6c5214368c58779f"
10241182dependencies = [
10251183 "bstr",
1184+ "bytecount",
10261185 "encoding_rs",
10271186 "encoding_rs_io",
10281187 "grep-matcher",
10291188 "log",
1030− "memchr",
1031− "memmap2",
1189+ "memmap2 0.5.10",
10321190]
10331191
10341192[[package]]
@@ -1036,36 +1194,37 @@ name = "hashbrown"
10361194version = "0.12.3"
10371195source = "registry+https://github.com/rust-lang/crates.io-index"
10381196checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
1197+dependencies = [
1198+ "ahash 0.7.6",
1199+]
10391200
10401201[[package]]
10411202name = "hashbrown"
1042−version = "0.14.3"
1203+version = "0.14.0"
10431204source = "registry+https://github.com/rust-lang/crates.io-index"
1044−checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
1205+checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
10451206dependencies = [
1046− "ahash",
1207+ "ahash 0.8.3",
10471208 "allocator-api2",
10481209]
10491210
10501211[[package]]
10511212name = "helix-core"
1052−version = "23.10.0"
1213+version = "0.6.0"
10531214dependencies = [
1054− "ahash",
1215+ "ahash 0.8.3",
10551216 "arc-swap",
1056− "bitflags 2.4.1",
1217+ "bitflags 2.3.3",
10571218 "chrono",
10581219 "dunce",
10591220 "encoding_rs",
10601221 "etcetera",
1061− "hashbrown 0.14.3",
1222+ "hashbrown 0.14.0",
10621223 "helix-loader",
10631224 "imara-diff",
10641225 "indoc",
10651226 "log",
1066− "nucleo",
10671227 "once_cell",
1068− "parking_lot",
10691228 "quickcheck",
10701229 "regex",
10711230 "ropey",
@@ -1084,7 +1243,7 @@ dependencies = [
10841243
10851244[[package]]
10861245name = "helix-dap"
1087−version = "23.10.0"
1246+version = "0.6.0"
10881247dependencies = [
10891248 "anyhow",
10901249 "fern",
@@ -1097,17 +1256,9 @@ dependencies = [
10971256 "which",
10981257]
10991258
1100−[[package]]
1101−name = "helix-event"
1102−version = "23.10.0"
1103−dependencies = [
1104− "parking_lot",
1105− "tokio",
1106−]
1107−
11081259[[package]]
11091260name = "helix-loader"
1110−version = "23.10.0"
1261+version = "0.6.0"
11111262dependencies = [
11121263 "anyhow",
11131264 "cc",
@@ -1126,7 +1277,7 @@ dependencies = [
11261277
11271278[[package]]
11281279name = "helix-lsp"
1129−version = "23.10.0"
1280+version = "0.6.0"
11301281dependencies = [
11311282 "anyhow",
11321283 "futures-executor",
@@ -1148,11 +1299,11 @@ dependencies = [
11481299
11491300[[package]]
11501301name = "helix-parsec"
1151−version = "23.10.0"
1302+version = "0.6.0"
11521303
11531304[[package]]
11541305name = "helix-term"
1155−version = "23.10.0"
1306+version = "0.6.0"
11561307dependencies = [
11571308 "anyhow",
11581309 "arc-swap",
@@ -1161,11 +1312,11 @@ dependencies = [
11611312 "crossterm",
11621313 "fern",
11631314 "futures-util",
1315+ "fuzzy-matcher",
11641316 "grep-regex",
11651317 "grep-searcher",
11661318 "helix-core",
11671319 "helix-dap",
1168− "helix-event",
11691320 "helix-loader",
11701321 "helix-lsp",
11711322 "helix-tui",
@@ -1175,9 +1326,7 @@ dependencies = [
11751326 "indoc",
11761327 "libc",
11771328 "log",
1178− "nucleo",
11791329 "once_cell",
1180− "open",
11811330 "pulldown-cmark",
11821331 "serde",
11831332 "serde_json",
@@ -1188,15 +1337,14 @@ dependencies = [
11881337 "tokio",
11891338 "tokio-stream",
11901339 "toml",
1191− "url",
11921340 "which",
11931341]
11941342
11951343[[package]]
11961344name = "helix-tui"
1197−version = "23.10.0"
1345+version = "0.6.0"
11981346dependencies = [
1199− "bitflags 2.4.1",
1347+ "bitflags 2.3.3",
12001348 "cassowary",
12011349 "crossterm",
12021350 "helix-core",
@@ -1210,13 +1358,12 @@ dependencies = [
12101358
12111359[[package]]
12121360name = "helix-vcs"
1213−version = "23.10.0"
1361+version = "0.6.0"
12141362dependencies = [
12151363 "anyhow",
12161364 "arc-swap",
12171365 "gix",
12181366 "helix-core",
1219− "helix-event",
12201367 "imara-diff",
12211368 "log",
12221369 "parking_lot",
@@ -1226,18 +1373,17 @@ dependencies = [
12261373
12271374[[package]]
12281375name = "helix-view"
1229−version = "23.10.0"
1376+version = "0.6.0"
12301377dependencies = [
12311378 "anyhow",
12321379 "arc-swap",
1233− "bitflags 2.4.1",
1380+ "bitflags 2.3.3",
12341381 "chardetng",
12351382 "clipboard-win",
12361383 "crossterm",
12371384 "futures-util",
12381385 "helix-core",
12391386 "helix-dap",
1240− "helix-event",
12411387 "helix-loader",
12421388 "helix-lsp",
12431389 "helix-tui",
@@ -1246,7 +1392,7 @@ dependencies = [
12461392 "log",
12471393 "once_cell",
12481394 "parking_lot",
1249− "rustix",
1395+ "rustix 0.38.4",
12501396 "serde",
12511397 "serde_json",
12521398 "slotmap",
@@ -1266,13 +1412,25 @@ dependencies = [
12661412 "libc",
12671413]
12681414
1415+[[package]]
1416+name = "hermit-abi"
1417+version = "0.3.2"
1418+source = "registry+https://github.com/rust-lang/crates.io-index"
1419+checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
1420+
1421+[[package]]
1422+name = "hex"
1423+version = "0.4.3"
1424+source = "registry+https://github.com/rust-lang/crates.io-index"
1425+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
1426+
12691427[[package]]
12701428name = "home"
1271−version = "0.5.5"
1429+version = "0.5.4"
12721430source = "registry+https://github.com/rust-lang/crates.io-index"
1273−checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
1431+checksum = "747309b4b440c06d57b0b25f2aee03ee9b5e5397d288c60e21fc709bb98a7408"
12741432dependencies = [
1275− "windows-sys 0.48.0",
1433+ "winapi",
12761434]
12771435
12781436[[package]]
@@ -1286,7 +1444,7 @@ dependencies = [
12861444 "iana-time-zone-haiku",
12871445 "js-sys",
12881446 "wasm-bindgen",
1289− "windows 0.48.0",
1447+ "windows",
12901448]
12911449
12921450[[package]]
@@ -1301,9 +1459,9 @@ dependencies = [
13011459
13021460[[package]]
13031461name = "idna"
1304−version = "0.5.0"
1462+version = "0.4.0"
13051463source = "registry+https://github.com/rust-lang/crates.io-index"
1306−checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
1464+checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
13071465dependencies = [
13081466 "unicode-bidi",
13091467 "unicode-normalization",
@@ -1311,16 +1469,17 @@ dependencies = [
13111469
13121470[[package]]
13131471name = "ignore"
1314−version = "0.4.21"
1472+version = "0.4.20"
13151473source = "registry+https://github.com/rust-lang/crates.io-index"
1316−checksum = "747ad1b4ae841a78e8aba0d63adbfbeaea26b517b63705d47856b73015d27060"
1474+checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492"
13171475dependencies = [
1318− "crossbeam-deque",
13191476 "globset",
1477+ "lazy_static",
13201478 "log",
13211479 "memchr",
1322− "regex-automata",
1480+ "regex",
13231481 "same-file",
1482+ "thread_local",
13241483 "walkdir",
13251484 "winapi-util",
13261485]
@@ -1331,7 +1490,7 @@ version = "0.1.5"
13311490source = "registry+https://github.com/rust-lang/crates.io-index"
13321491checksum = "e98c1d0ad70fc91b8b9654b1f33db55e59579d3b3de2bffdced0fdb810570cb8"
13331492dependencies = [
1334− "ahash",
1493+ "ahash 0.8.3",
13351494 "hashbrown 0.12.3",
13361495]
13371496
@@ -1342,32 +1501,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
13421501checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
13431502dependencies = [
13441503 "equivalent",
1345− "hashbrown 0.14.3",
1504+ "hashbrown 0.14.0",
13461505]
13471506
13481507[[package]]
13491508name = "indoc"
1350−version = "2.0.4"
1509+version = "2.0.3"
13511510source = "registry+https://github.com/rust-lang/crates.io-index"
1352−checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8"
1511+checksum = "2c785eefb63ebd0e33416dfcb8d6da0bf27ce752843a45632a67bf10d4d4b5c4"
13531512
13541513[[package]]
1355−name = "is-docker"
1356−version = "0.2.0"
1514+name = "io-close"
1515+version = "0.3.7"
13571516source = "registry+https://github.com/rust-lang/crates.io-index"
1358−checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3"
1517+checksum = "9cadcf447f06744f8ce713d2d6239bb5bde2c357a452397a9ed90c625da390bc"
13591518dependencies = [
1360− "once_cell",
1519+ "libc",
1520+ "winapi",
13611521]
13621522
13631523[[package]]
1364−name = "is-wsl"
1365−version = "0.4.0"
1524+name = "io-lifetimes"
1525+version = "1.0.10"
13661526source = "registry+https://github.com/rust-lang/crates.io-index"
1367−checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5"
1527+checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
13681528dependencies = [
1369− "is-docker",
1370− "once_cell",
1529+ "hermit-abi 0.3.2",
1530+ "libc",
1531+ "windows-sys 0.48.0",
13711532]
13721533
13731534[[package]]
@@ -1385,17 +1546,32 @@ dependencies = [
13851546 "wasm-bindgen",
13861547]
13871548
1549+[[package]]
1550+name = "kstring"
1551+version = "2.0.0"
1552+source = "registry+https://github.com/rust-lang/crates.io-index"
1553+checksum = "ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747"
1554+dependencies = [
1555+ "static_assertions",
1556+]
1557+
1558+[[package]]
1559+name = "lazy_static"
1560+version = "1.4.0"
1561+source = "registry+https://github.com/rust-lang/crates.io-index"
1562+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
1563+
13881564[[package]]
13891565name = "libc"
1390−version = "0.2.151"
1566+version = "0.2.147"
13911567source = "registry+https://github.com/rust-lang/crates.io-index"
1392−checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
1568+checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
13931569
13941570[[package]]
13951571name = "libloading"
1396−version = "0.8.1"
1572+version = "0.8.0"
13971573source = "registry+https://github.com/rust-lang/crates.io-index"
1398−checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161"
1574+checksum = "d580318f95776505201b28cf98eb1fa5e4be3b689633ba6a3e6cd880ff22d8cb"
13991575dependencies = [
14001576 "cfg-if",
14011577 "windows-sys 0.48.0",
@@ -1412,9 +1588,15 @@ dependencies = [
14121588
14131589[[package]]
14141590name = "linux-raw-sys"
1415−version = "0.4.11"
1591+version = "0.3.4"
1592+source = "registry+https://github.com/rust-lang/crates.io-index"
1593+checksum = "36eb31c1778188ae1e64398743890d0877fef36d11521ac60406b42016e8c2cf"
1594+
1595+[[package]]
1596+name = "linux-raw-sys"
1597+version = "0.4.3"
14161598source = "registry+https://github.com/rust-lang/crates.io-index"
1417−checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
1599+checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0"
14181600
14191601[[package]]
14201602name = "lock_api"
@@ -1428,15 +1610,15 @@ dependencies = [
14281610
14291611[[package]]
14301612name = "log"
1431−version = "0.4.20"
1613+version = "0.4.19"
14321614source = "registry+https://github.com/rust-lang/crates.io-index"
1433−checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
1615+checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
14341616
14351617[[package]]
14361618name = "lsp-types"
1437−version = "0.95.0"
1619+version = "0.94.1"
14381620source = "registry+https://github.com/rust-lang/crates.io-index"
1439−checksum = "158c1911354ef73e8fe42da6b10c0484cb65c7f1007f28022e847706c1ab6984"
1621+checksum = "c66bfd44a06ae10647fe3f8214762e9369fd4248df1350924b4ef9e770a85ea1"
14401622dependencies = [
14411623 "bitflags 1.3.2",
14421624 "serde",
@@ -1447,26 +1629,41 @@ dependencies = [
14471629
14481630[[package]]
14491631name = "memchr"
1450−version = "2.6.3"
1632+version = "2.5.0"
14511633source = "registry+https://github.com/rust-lang/crates.io-index"
1452−checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
1634+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
14531635
14541636[[package]]
14551637name = "memmap2"
1456−version = "0.9.0"
1638+version = "0.5.10"
14571639source = "registry+https://github.com/rust-lang/crates.io-index"
1458−checksum = "deaba38d7abf1d4cca21cc89e932e542ba2b9258664d2a9ef0e61512039c9375"
1640+checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327"
14591641dependencies = [
14601642 "libc",
14611643]
14621644
14631645[[package]]
1464−name = "memoffset"
1465−version = "0.9.0"
1646+name = "memmap2"
1647+version = "0.7.1"
14661648source = "registry+https://github.com/rust-lang/crates.io-index"
1467−checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
1649+checksum = "f49388d20533534cd19360ad3d6a7dadc885944aa802ba3995040c5ec11288c6"
14681650dependencies = [
1469− "autocfg",
1651+ "libc",
1652+]
1653+
1654+[[package]]
1655+name = "minimal-lexical"
1656+version = "0.2.1"
1657+source = "registry+https://github.com/rust-lang/crates.io-index"
1658+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
1659+
1660+[[package]]
1661+name = "miniz_oxide"
1662+version = "0.6.2"
1663+source = "registry+https://github.com/rust-lang/crates.io-index"
1664+checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
1665+dependencies = [
1666+ "adler",
14701667]
14711668
14721669[[package]]
@@ -1480,36 +1677,24 @@ dependencies = [
14801677
14811678[[package]]
14821679name = "mio"
1483−version = "0.8.9"
1680+version = "0.8.6"
14841681source = "registry+https://github.com/rust-lang/crates.io-index"
1485−checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0"
1682+checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
14861683dependencies = [
14871684 "libc",
14881685 "log",
14891686 "wasi",
1490− "windows-sys 0.48.0",
1491−]
1492−
1493−[[package]]
1494−name = "nucleo"
1495−version = "0.2.1"
1496−source = "registry+https://github.com/rust-lang/crates.io-index"
1497−checksum = "ae5331f4bcce475cf28cb29c95366c3091af4b0aa7703f1a6bc858f29718fdf3"
1498−dependencies = [
1499− "nucleo-matcher",
1500− "parking_lot",
1501− "rayon",
1687+ "windows-sys 0.45.0",
15021688]
15031689
15041690[[package]]
1505−name = "nucleo-matcher"
1506−version = "0.2.0"
1691+name = "nom"
1692+version = "7.1.3"
15071693source = "registry+https://github.com/rust-lang/crates.io-index"
1508−checksum = "1b702b402fe286162d1f00b552a046ce74365d2ac473a2607ff36ba650f9bd57"
1694+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
15091695dependencies = [
1510− "cov-mark",
15111696 "memchr",
1512− "unicode-segmentation",
1697+ "minimal-lexical",
15131698]
15141699
15151700[[package]]
@@ -1527,7 +1712,7 @@ version = "1.15.0"
15271712source = "registry+https://github.com/rust-lang/crates.io-index"
15281713checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
15291714dependencies = [
1530− "hermit-abi",
1715+ "hermit-abi 0.2.6",
15311716 "libc",
15321717]
15331718
@@ -1551,20 +1736,9 @@ dependencies = [
15511736
15521737[[package]]
15531738name = "once_cell"
1554−version = "1.19.0"
1739+version = "1.18.0"
15551740source = "registry+https://github.com/rust-lang/crates.io-index"
1556−checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
1557−
1558−[[package]]
1559−name = "open"
1560−version = "5.0.1"
1561−source = "registry+https://github.com/rust-lang/crates.io-index"
1562−checksum = "90878fb664448b54c4e592455ad02831e23a3f7e157374a8b95654731aac7349"
1563−dependencies = [
1564− "is-wsl",
1565− "libc",
1566− "pathdiff",
1567−]
1741+checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
15681742
15691743[[package]]
15701744name = "parking_lot"
@@ -1589,23 +1763,17 @@ dependencies = [
15891763 "windows-sys 0.45.0",
15901764]
15911765
1592−[[package]]
1593−name = "pathdiff"
1594−version = "0.2.1"
1595−source = "registry+https://github.com/rust-lang/crates.io-index"
1596−checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
1597−
15981766[[package]]
15991767name = "percent-encoding"
1600−version = "2.3.1"
1768+version = "2.3.0"
16011769source = "registry+https://github.com/rust-lang/crates.io-index"
1602−checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
1770+checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
16031771
16041772[[package]]
16051773name = "pin-project-lite"
1606−version = "0.2.12"
1774+version = "0.2.9"
16071775source = "registry+https://github.com/rust-lang/crates.io-index"
1608−checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05"
1776+checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
16091777
16101778[[package]]
16111779name = "pin-utils"
@@ -1615,18 +1783,18 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
16151783
16161784[[package]]
16171785name = "proc-macro2"
1618−version = "1.0.69"
1786+version = "1.0.63"
16191787source = "registry+https://github.com/rust-lang/crates.io-index"
1620−checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
1788+checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
16211789dependencies = [
16221790 "unicode-ident",
16231791]
16241792
16251793[[package]]
16261794name = "prodash"
1627−version = "28.0.0"
1795+version = "25.0.0"
16281796source = "registry+https://github.com/rust-lang/crates.io-index"
1629−checksum = "744a264d26b88a6a7e37cbad97953fa233b94d585236310bcbc88474b4092d79"
1797+checksum = "3236ce1618b6da4c7b618e0143c4d5b5dc190f75f81c49f248221382f7e9e9ae"
16301798
16311799[[package]]
16321800name = "pulldown-cmark"
@@ -1675,28 +1843,6 @@ dependencies = [
16751843 "getrandom",
16761844]
16771845
1678−[[package]]
1679−name = "rayon"
1680−version = "1.7.0"
1681−source = "registry+https://github.com/rust-lang/crates.io-index"
1682−checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
1683−dependencies = [
1684− "either",
1685− "rayon-core",
1686−]
1687−
1688−[[package]]
1689−name = "rayon-core"
1690−version = "1.11.0"
1691−source = "registry+https://github.com/rust-lang/crates.io-index"
1692−checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
1693−dependencies = [
1694− "crossbeam-channel",
1695− "crossbeam-deque",
1696− "crossbeam-utils",
1697− "num_cpus",
1698−]
1699−
17001846[[package]]
17011847name = "redox_syscall"
17021848version = "0.2.16"
@@ -1708,47 +1854,53 @@ dependencies = [
17081854
17091855[[package]]
17101856name = "redox_syscall"
1711−version = "0.4.1"
1857+version = "0.3.5"
17121858source = "registry+https://github.com/rust-lang/crates.io-index"
1713−checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
1859+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
17141860dependencies = [
17151861 "bitflags 1.3.2",
17161862]
17171863
17181864[[package]]
17191865name = "regex"
1720−version = "1.10.2"
1866+version = "1.9.1"
17211867source = "registry+https://github.com/rust-lang/crates.io-index"
1722−checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
1868+checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575"
17231869dependencies = [
1724− "aho-corasick",
1870+ "aho-corasick 1.0.2",
17251871 "memchr",
17261872 "regex-automata",
1727− "regex-syntax",
1873+ "regex-syntax 0.7.3",
17281874]
17291875
17301876[[package]]
17311877name = "regex-automata"
1732−version = "0.4.3"
1878+version = "0.3.2"
17331879source = "registry+https://github.com/rust-lang/crates.io-index"
1734−checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
1880+checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf"
17351881dependencies = [
1736− "aho-corasick",
1882+ "aho-corasick 1.0.2",
17371883 "memchr",
1738− "regex-syntax",
1884+ "regex-syntax 0.7.3",
17391885]
17401886
17411887[[package]]
17421888name = "regex-syntax"
1743−version = "0.8.2"
1889+version = "0.6.29"
1890+source = "registry+https://github.com/rust-lang/crates.io-index"
1891+checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
1892+
1893+[[package]]
1894+name = "regex-syntax"
1895+version = "0.7.3"
17441896source = "registry+https://github.com/rust-lang/crates.io-index"
1745−checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
1897+checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846"
17461898
17471899[[package]]
17481900name = "ropey"
1749−version = "1.6.1"
1901+version = "1.6.0"
17501902source = "registry+https://github.com/rust-lang/crates.io-index"
1751−checksum = "93411e420bcd1a75ddd1dc3caf18c23155eda2c090631a85af21ba19e97093b5"
1903+checksum = "53ce7a2c43a32e50d666e33c5a80251b31147bb4b49024bcab11fb6f20c671ed"
17521904dependencies = [
17531905 "smallvec",
17541906 "str_indices",
@@ -1762,15 +1914,29 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
17621914
17631915[[package]]
17641916name = "rustix"
1765−version = "0.38.28"
1917+version = "0.37.15"
17661918source = "registry+https://github.com/rust-lang/crates.io-index"
1767−checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
1919+checksum = "a0661814f891c57c930a610266415528da53c4933e6dea5fb350cbfe048a9ece"
17681920dependencies = [
1769− "bitflags 2.4.1",
1921+ "bitflags 1.3.2",
17701922 "errno",
1923+ "io-lifetimes",
17711924 "libc",
1772− "linux-raw-sys",
1773− "windows-sys 0.52.0",
1925+ "linux-raw-sys 0.3.4",
1926+ "windows-sys 0.48.0",
1927+]
1928+
1929+[[package]]
1930+name = "rustix"
1931+version = "0.38.4"
1932+source = "registry+https://github.com/rust-lang/crates.io-index"
1933+checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5"
1934+dependencies = [
1935+ "bitflags 2.3.3",
1936+ "errno",
1937+ "libc",
1938+ "linux-raw-sys 0.4.3",
1939+ "windows-sys 0.48.0",
17741940]
17751941
17761942[[package]]
@@ -1802,29 +1968,29 @@ checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1"
18021968
18031969[[package]]
18041970name = "serde"
1805−version = "1.0.193"
1971+version = "1.0.183"
18061972source = "registry+https://github.com/rust-lang/crates.io-index"
1807−checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
1973+checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c"
18081974dependencies = [
18091975 "serde_derive",
18101976]
18111977
18121978[[package]]
18131979name = "serde_derive"
1814−version = "1.0.193"
1980+version = "1.0.183"
18151981source = "registry+https://github.com/rust-lang/crates.io-index"
1816−checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
1982+checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816"
18171983dependencies = [
18181984 "proc-macro2",
18191985 "quote",
1820− "syn 2.0.38",
1986+ "syn 2.0.28",
18211987]
18221988
18231989[[package]]
18241990name = "serde_json"
1825−version = "1.0.108"
1991+version = "1.0.104"
18261992source = "registry+https://github.com/rust-lang/crates.io-index"
1827−checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
1993+checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c"
18281994dependencies = [
18291995 "itoa",
18301996 "ryu",
@@ -1839,7 +2005,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab"
18392005dependencies = [
18402006 "proc-macro2",
18412007 "quote",
1842− "syn 2.0.38",
2008+ "syn 2.0.28",
18432009]
18442010
18452011[[package]]
@@ -1910,18 +2076,18 @@ dependencies = [
19102076
19112077[[package]]
19122078name = "slotmap"
1913−version = "1.0.7"
2079+version = "1.0.6"
19142080source = "registry+https://github.com/rust-lang/crates.io-index"
1915−checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a"
2081+checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342"
19162082dependencies = [
19172083 "version_check",
19182084]
19192085
19202086[[package]]
19212087name = "smallvec"
1922−version = "1.11.2"
2088+version = "1.11.0"
19232089source = "registry+https://github.com/rust-lang/crates.io-index"
1924−checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
2090+checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
19252091
19262092[[package]]
19272093name = "smartstring"
@@ -1942,12 +2108,12 @@ checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043"
19422108
19432109[[package]]
19442110name = "socket2"
1945−version = "0.5.5"
2111+version = "0.4.9"
19462112source = "registry+https://github.com/rust-lang/crates.io-index"
1947−checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
2113+checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
19482114dependencies = [
19492115 "libc",
1950− "windows-sys 0.48.0",
2116+ "winapi",
19512117]
19522118
19532119[[package]]
@@ -1956,6 +2122,12 @@ version = "1.1.0"
19562122source = "registry+https://github.com/rust-lang/crates.io-index"
19572123checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
19582124
2125+[[package]]
2126+name = "str-buf"
2127+version = "1.0.6"
2128+source = "registry+https://github.com/rust-lang/crates.io-index"
2129+checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0"
2130+
19592131[[package]]
19602132name = "str_indices"
19612133version = "0.4.1"
@@ -1975,9 +2147,9 @@ dependencies = [
19752147
19762148[[package]]
19772149name = "syn"
1978−version = "2.0.38"
2150+version = "2.0.28"
19792151source = "registry+https://github.com/rust-lang/crates.io-index"
1980−checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
2152+checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567"
19812153dependencies = [
19822154 "proc-macro2",
19832155 "quote",
@@ -1986,14 +2158,14 @@ dependencies = [
19862158
19872159[[package]]
19882160name = "tempfile"
1989−version = "3.8.1"
2161+version = "3.7.1"
19902162source = "registry+https://github.com/rust-lang/crates.io-index"
1991−checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
2163+checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651"
19922164dependencies = [
19932165 "cfg-if",
19942166 "fastrand",
1995− "redox_syscall 0.4.1",
1996− "rustix",
2167+ "redox_syscall 0.3.5",
2168+ "rustix 0.38.4",
19972169 "windows-sys 0.48.0",
19982170]
19992171
@@ -2028,22 +2200,32 @@ dependencies = [
20282200
20292201[[package]]
20302202name = "thiserror"
2031−version = "1.0.52"
2203+version = "1.0.44"
20322204source = "registry+https://github.com/rust-lang/crates.io-index"
2033−checksum = "83a48fd946b02c0a526b2e9481c8e2a17755e47039164a86c4070446e3a4614d"
2205+checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90"
20342206dependencies = [
20352207 "thiserror-impl",
20362208]
20372209
20382210[[package]]
20392211name = "thiserror-impl"
2040−version = "1.0.52"
2212+version = "1.0.44"
20412213source = "registry+https://github.com/rust-lang/crates.io-index"
2042−checksum = "e7fbe9b594d6568a6a1443250a7e67d80b74e1e96f6d1715e1e21cc1888291d3"
2214+checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96"
20432215dependencies = [
20442216 "proc-macro2",
20452217 "quote",
2046− "syn 2.0.38",
2218+ "syn 2.0.28",
2219+]
2220+
2221+[[package]]
2222+name = "thread_local"
2223+version = "1.1.7"
2224+source = "registry+https://github.com/rust-lang/crates.io-index"
2225+checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
2226+dependencies = [
2227+ "cfg-if",
2228+ "once_cell",
20472229]
20482230
20492231[[package]]
@@ -2057,9 +2239,9 @@ dependencies = [
20572239
20582240[[package]]
20592241name = "time"
2060−version = "0.3.23"
2242+version = "0.3.20"
20612243source = "registry+https://github.com/rust-lang/crates.io-index"
2062−checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446"
2244+checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890"
20632245dependencies = [
20642246 "itoa",
20652247 "libc",
@@ -2071,15 +2253,15 @@ dependencies = [
20712253
20722254[[package]]
20732255name = "time-core"
2074−version = "0.1.1"
2256+version = "0.1.0"
20752257source = "registry+https://github.com/rust-lang/crates.io-index"
2076−checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
2258+checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
20772259
20782260[[package]]
20792261name = "time-macros"
2080−version = "0.2.10"
2262+version = "0.2.8"
20812263source = "registry+https://github.com/rust-lang/crates.io-index"
2082−checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4"
2264+checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36"
20832265dependencies = [
20842266 "time-core",
20852267]
@@ -2101,10 +2283,11 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
21012283
21022284[[package]]
21032285name = "tokio"
2104−version = "1.35.1"
2286+version = "1.29.1"
21052287source = "registry+https://github.com/rust-lang/crates.io-index"
2106−checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104"
2288+checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da"
21072289dependencies = [
2290+ "autocfg",
21082291 "backtrace",
21092292 "bytes",
21102293 "libc",
@@ -2120,13 +2303,13 @@ dependencies = [
21202303
21212304[[package]]
21222305name = "tokio-macros"
2123−version = "2.2.0"
2306+version = "2.1.0"
21242307source = "registry+https://github.com/rust-lang/crates.io-index"
2125−checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
2308+checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
21262309dependencies = [
21272310 "proc-macro2",
21282311 "quote",
2129− "syn 2.0.38",
2312+ "syn 2.0.28",
21302313]
21312314
21322315[[package]]
@@ -2171,13 +2354,13 @@ dependencies = [
21712354 "serde",
21722355 "serde_spanned",
21732356 "toml_datetime",
2174− "winnow 0.4.6",
2357+ "winnow",
21752358]
21762359
21772360[[package]]
21782361name = "tree-sitter"
21792362version = "0.20.10"
2180−source = "git+https://github.com/tree-sitter/tree-sitter?rev=ab09ae20d640711174b8da8a654f6b3dec93da1a#ab09ae20d640711174b8da8a654f6b3dec93da1a"
2363+source = "git+https://github.com/tree-sitter/tree-sitter?rev=7d4b0110a9e92161d247a051018ee42b0513e98d#7d4b0110a9e92161d247a051018ee42b0513e98d"
21812364dependencies = [
21822365 "cc",
21832366 "regex",
@@ -2218,9 +2401,13 @@ checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
22182401
22192402[[package]]
22202403name = "unicode-linebreak"
2221−version = "0.1.5"
2404+version = "0.1.4"
22222405source = "registry+https://github.com/rust-lang/crates.io-index"
2223−checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
2406+checksum = "c5faade31a542b8b35855fff6e8def199853b2da8da256da52f52f1316ee3137"
2407+dependencies = [
2408+ "hashbrown 0.12.3",
2409+ "regex",
2410+]
22242411
22252412[[package]]
22262413name = "unicode-normalization"
@@ -2239,15 +2426,15 @@ checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
22392426
22402427[[package]]
22412428name = "unicode-width"
2242−version = "0.1.11"
2429+version = "0.1.10"
22432430source = "registry+https://github.com/rust-lang/crates.io-index"
2244−checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
2431+checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
22452432
22462433[[package]]
22472434name = "url"
2248−version = "2.5.0"
2435+version = "2.4.0"
22492436source = "registry+https://github.com/rust-lang/crates.io-index"
2250−checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
2437+checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb"
22512438dependencies = [
22522439 "form_urlencoded",
22532440 "idna",
@@ -2263,9 +2450,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
22632450
22642451[[package]]
22652452name = "walkdir"
2266−version = "2.4.0"
2453+version = "2.3.3"
22672454source = "registry+https://github.com/rust-lang/crates.io-index"
2268−checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
2455+checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
22692456dependencies = [
22702457 "same-file",
22712458 "winapi-util",
@@ -2333,15 +2520,13 @@ checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
23332520
23342521[[package]]
23352522name = "which"
2336−version = "5.0.0"
2523+version = "4.4.0"
23372524source = "registry+https://github.com/rust-lang/crates.io-index"
2338−checksum = "9bf3ea8596f3a0dd5980b46430f2058dfe2c36a27ccfbb1845d6fbfcd9ba6e14"
2525+checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269"
23392526dependencies = [
23402527 "either",
2341− "home",
2528+ "libc",
23422529 "once_cell",
2343− "rustix",
2344− "windows-sys 0.48.0",
23452530]
23462531
23472532[[package]]
@@ -2384,25 +2569,6 @@ dependencies = [
23842569 "windows-targets 0.48.0",
23852570]
23862571
2387−[[package]]
2388−name = "windows"
2389−version = "0.52.0"
2390−source = "registry+https://github.com/rust-lang/crates.io-index"
2391−checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
2392−dependencies = [
2393− "windows-core",
2394− "windows-targets 0.52.0",
2395−]
2396−
2397−[[package]]
2398−name = "windows-core"
2399−version = "0.52.0"
2400−source = "registry+https://github.com/rust-lang/crates.io-index"
2401−checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
2402−dependencies = [
2403− "windows-targets 0.52.0",
2404−]
2405−
24062572[[package]]
24072573name = "windows-sys"
24082574version = "0.45.0"
@@ -2421,15 +2587,6 @@ dependencies = [
24212587 "windows-targets 0.48.0",
24222588]
24232589
2424−[[package]]
2425−name = "windows-sys"
2426−version = "0.52.0"
2427−source = "registry+https://github.com/rust-lang/crates.io-index"
2428−checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
2429−dependencies = [
2430− "windows-targets 0.52.0",
2431−]
2432−
24332590[[package]]
24342591name = "windows-targets"
24352592version = "0.42.2"
@@ -2460,21 +2617,6 @@ dependencies = [
24602617 "windows_x86_64_msvc 0.48.0",
24612618]
24622619
2463−[[package]]
2464−name = "windows-targets"
2465−version = "0.52.0"
2466−source = "registry+https://github.com/rust-lang/crates.io-index"
2467−checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
2468−dependencies = [
2469− "windows_aarch64_gnullvm 0.52.0",
2470− "windows_aarch64_msvc 0.52.0",
2471− "windows_i686_gnu 0.52.0",
2472− "windows_i686_msvc 0.52.0",
2473− "windows_x86_64_gnu 0.52.0",
2474− "windows_x86_64_gnullvm 0.52.0",
2475− "windows_x86_64_msvc 0.52.0",
2476−]
2477−
24782620[[package]]
24792621name = "windows_aarch64_gnullvm"
24802622version = "0.42.2"
@@ -2487,12 +2629,6 @@ version = "0.48.0"
24872629source = "registry+https://github.com/rust-lang/crates.io-index"
24882630checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
24892631
2490−[[package]]
2491−name = "windows_aarch64_gnullvm"
2492−version = "0.52.0"
2493−source = "registry+https://github.com/rust-lang/crates.io-index"
2494−checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
2495−
24962632[[package]]
24972633name = "windows_aarch64_msvc"
24982634version = "0.42.2"
@@ -2505,12 +2641,6 @@ version = "0.48.0"
25052641source = "registry+https://github.com/rust-lang/crates.io-index"
25062642checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
25072643
2508−[[package]]
2509−name = "windows_aarch64_msvc"
2510−version = "0.52.0"
2511−source = "registry+https://github.com/rust-lang/crates.io-index"
2512−checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
2513−
25142644[[package]]
25152645name = "windows_i686_gnu"
25162646version = "0.42.2"
@@ -2523,12 +2653,6 @@ version = "0.48.0"
25232653source = "registry+https://github.com/rust-lang/crates.io-index"
25242654checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
25252655
2526−[[package]]
2527−name = "windows_i686_gnu"
2528−version = "0.52.0"
2529−source = "registry+https://github.com/rust-lang/crates.io-index"
2530−checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
2531−
25322656[[package]]
25332657name = "windows_i686_msvc"
25342658version = "0.42.2"
@@ -2541,12 +2665,6 @@ version = "0.48.0"
25412665source = "registry+https://github.com/rust-lang/crates.io-index"
25422666checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
25432667
2544−[[package]]
2545−name = "windows_i686_msvc"
2546−version = "0.52.0"
2547−source = "registry+https://github.com/rust-lang/crates.io-index"
2548−checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
2549−
25502668[[package]]
25512669name = "windows_x86_64_gnu"
25522670version = "0.42.2"
@@ -2559,12 +2677,6 @@ version = "0.48.0"
25592677source = "registry+https://github.com/rust-lang/crates.io-index"
25602678checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
25612679
2562−[[package]]
2563−name = "windows_x86_64_gnu"
2564−version = "0.52.0"
2565−source = "registry+https://github.com/rust-lang/crates.io-index"
2566−checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
2567−
25682680[[package]]
25692681name = "windows_x86_64_gnullvm"
25702682version = "0.42.2"
@@ -2577,12 +2689,6 @@ version = "0.48.0"
25772689source = "registry+https://github.com/rust-lang/crates.io-index"
25782690checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
25792691
2580−[[package]]
2581−name = "windows_x86_64_gnullvm"
2582−version = "0.52.0"
2583−source = "registry+https://github.com/rust-lang/crates.io-index"
2584−checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
2585−
25862692[[package]]
25872693name = "windows_x86_64_msvc"
25882694version = "0.42.2"
@@ -2595,12 +2701,6 @@ version = "0.48.0"
25952701source = "registry+https://github.com/rust-lang/crates.io-index"
25962702checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
25972703
2598−[[package]]
2599−name = "windows_x86_64_msvc"
2600−version = "0.52.0"
2601−source = "registry+https://github.com/rust-lang/crates.io-index"
2602−checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
2603−
26042704[[package]]
26052705name = "winnow"
26062706version = "0.4.6"
@@ -2610,18 +2710,9 @@ dependencies = [
26102710 "memchr",
26112711]
26122712
2613−[[package]]
2614−name = "winnow"
2615−version = "0.5.28"
2616−source = "registry+https://github.com/rust-lang/crates.io-index"
2617−checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2"
2618−dependencies = [
2619− "memchr",
2620−]
2621−
26222713[[package]]
26232714name = "xtask"
2624−version = "23.10.0"
2715+version = "0.6.0"
26252716dependencies = [
26262717 "helix-core",
26272718 "helix-loader",
@@ -2629,23 +2720,3 @@ dependencies = [
26292720 "helix-view",
26302721 "toml",
26312722]
2632−
2633−[[package]]
2634−name = "zerocopy"
2635−version = "0.7.31"
2636−source = "registry+https://github.com/rust-lang/crates.io-index"
2637−checksum = "1c4061bedbb353041c12f413700357bec76df2c7e2ca8e4df8bac24c6bf68e3d"
2638−dependencies = [
2639− "zerocopy-derive",
2640−]
2641−
2642−[[package]]
2643−name = "zerocopy-derive"
2644−version = "0.7.31"
2645−source = "registry+https://github.com/rust-lang/crates.io-index"
2646−checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a"
2647−dependencies = [
2648− "proc-macro2",
2649− "quote",
2650− "syn 2.0.38",
2651−]
Cargo.toml+1−14
@@ -1,12 +1,10 @@
11[workspace]
2−resolver = "2"
32members = [
43 "helix-core",
54 "helix-view",
65 "helix-term",
76 "helix-tui",
87 "helix-lsp",
9− "helix-event",
108 "helix-dap",
119 "helix-loader",
1210 "helix-vcs",
@@ -36,15 +34,4 @@ package.helix-tui.opt-level = 2
3634package.helix-term.opt-level = 2
3735
3836[workspace.dependencies]
39−tree-sitter = { version = "0.20", git = "https://github.com/tree-sitter/tree-sitter", rev = "ab09ae20d640711174b8da8a654f6b3dec93da1a" }
40−nucleo = "0.2.0"
41−
42−[workspace.package]
43−version = "23.10.0"
44−edition = "2021"
45−authors = ["Blaž Hrastnik <blaz@mxxn.io>"]
46−categories = ["editor"]
47−repository = "https://github.com/helix-editor/helix"
48−homepage = "https://helix-editor.com"
49−license = "MPL-2.0"
50−rust-version = "1.70"
37+tree-sitter = { version = "0.20", git = "https://github.com/tree-sitter/tree-sitter", rev = "7d4b0110a9e92161d247a051018ee42b0513e98d" }
README.md+1−1
@@ -18,7 +18,7 @@
1818
1919![Screenshot](./screenshot.png)
2020
21−A [Kakoune](https://github.com/mawww/kakoune) / [Neovim](https://github.com/neovim/neovim) inspired editor, written in Rust.
21+A Kakoune / Neovim inspired editor, written in Rust.
2222
2323The editing model is very heavily based on Kakoune; during development I found
2424myself agreeing with most of Kakoune's design decisions.
VERSIONnew file+1
@@ -0,0 +1 @@
1+23.05
book/custom.css+1−1
@@ -164,7 +164,7 @@ code.hljs {
164164 --searchresults-header-fg: #5f5f71;
165165 --searchresults-border-color: #5c5c68;
166166 --searchresults-li-bg: #242430;
167− --search-mark-bg: #a2cff5;
167+ --search-mark-bg: #acff5;
168168}
169169
170170.colibri .content .header {
book/src/configuration.md+9−27
@@ -51,7 +51,7 @@ Its settings will be merged with the configuration directory `config.toml` and t
5151| `auto-completion` | Enable automatic pop up of auto-completion | `true` |
5252| `auto-format` | Enable automatic formatting on save | `true` |
5353| `auto-save` | Enable automatic saving on the focus moving away from Helix. Requires [focus event support](https://github.com/helix-editor/helix/wiki/Terminal-Support) from your terminal | `false` |
54−| `idle-timeout` | Time in milliseconds since last keypress before idle timers trigger. Used for autocompletion, set to 0 for instant | `250` |
54+| `idle-timeout` | Time in milliseconds since last keypress before idle timers trigger. Used for autocompletion, set to 0 for instant | `400` |
5555| `preview-completion-insert` | Whether to apply completion item instantly when selected | `true` |
5656| `completion-trigger-len` | The min-length of word under cursor to trigger autocompletion | `2` |
5757| `completion-replace` | Set to `true` to make completions always replace the entire word and not just the part before the cursor | `false` |
@@ -64,9 +64,6 @@ Its settings will be merged with the configuration directory `config.toml` and t
6464| `text-width` | Maximum line length. Used for the `:reflow` command and soft-wrapping if `soft-wrap.wrap-at-text-width` is set | `80` |
6565| `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml` | `[]` |
6666| `default-line-ending` | The line ending to use for new documents. Can be `native`, `lf`, `crlf`, `ff`, `cr` or `nel`. `native` uses the platform's native line ending (`crlf` on Windows, otherwise `lf`). | `native` |
67−| `insert-final-newline` | Whether to automatically insert a trailing line-ending on write if missing | `true` |
68−| `popup-border` | Draw border around `popup`, `menu`, `all`, or `none` | `none` |
69−| `indent-heuristic` | How the indentation for a newly inserted line is computed: `simple` just copies the indentation level from the previous line, `tree-sitter` computes the indentation based on the syntax tree and `hybrid` combines both approaches. If the chosen heuristic is not available, a different one will be used as a fallback (the fallback order being `hybrid` -> `tree-sitter` -> `simple`). | `hybrid`
7067
7168### `[editor.statusline]` Section
7269
@@ -168,31 +165,16 @@ All git related options are only enabled in a git repository.
168165
169166| Key | Description | Default |
170167|--|--|---------|
171−|`hidden` | Enables ignoring hidden files | `true`
172−|`follow-symlinks` | Follow symlinks instead of ignoring them | `true`
173−|`deduplicate-links` | Ignore symlinks that point at files already shown in the picker | `true`
174−|`parents` | Enables reading ignore files from parent directories | `true`
175−|`ignore` | Enables reading `.ignore` files | `true`
176−|`git-ignore` | Enables reading `.gitignore` files | `true`
177−|`git-global` | Enables reading global `.gitignore`, whose path is specified in git's config: `core.excludesfile` option | `true`
178−|`git-exclude` | Enables reading `.git/info/exclude` files | `true`
168+|`hidden` | Enables ignoring hidden files | true
169+|`follow-symlinks` | Follow symlinks instead of ignoring them | true
170+|`deduplicate-links` | Ignore symlinks that point at files already shown in the picker | true
171+|`parents` | Enables reading ignore files from parent directories | true
172+|`ignore` | Enables reading `.ignore` files | true
173+|`git-ignore` | Enables reading `.gitignore` files | true
174+|`git-global` | Enables reading global `.gitignore`, whose path is specified in git's config: `core.excludefile` option | true
175+|`git-exclude` | Enables reading `.git/info/exclude` files | true
179176|`max-depth` | Set with an integer value for maximum depth to recurse | Defaults to `None`.
180177
181−Ignore files can be placed locally as `.ignore` or put in your home directory as `~/.ignore`. They support the usual ignore and negative ignore (unignore) rules used in `.gitignore` files.
182−
183−Additionally, you can use Helix-specific ignore files by creating a local `.helix/ignore` file in the current workspace or a global `ignore` file located in your Helix config directory:
184−- Linux and Mac: `~/.config/helix/ignore`
185−- Windows: `%AppData%\helix\ignore`
186−
187−Example:
188−
189−```ini
190−# unignore in file picker and global search
191−!.github/
192−!.gitignore
193−!.gitattributes
194−```
195−
196178### `[editor.auto-pairs]` Section
197179
198180Enables automatic insertion of pairs to parentheses, brackets, etc. Can be a
book/src/generated/lang-support.md+11−25
@@ -1,6 +1,5 @@
11| Language | Syntax Highlighting | Treesitter Textobjects | Auto Indent | Default LSP |
22| --- | --- | --- | --- | --- |
3−| agda | ✓ | | | |
43| astro | ✓ | | | |
54| awk | ✓ | ✓ | | `awk-language-server` |
65| bash | ✓ | ✓ | ✓ | `bash-language-server` |
@@ -11,13 +10,13 @@
1110| blueprint | ✓ | | | `blueprint-compiler` |
1211| c | ✓ | ✓ | ✓ | `clangd` |
1312| c-sharp | ✓ | ✓ | | `OmniSharp` |
14−| cabal | | | | `haskell-language-server-wrapper` |
13+| cabal | | | | |
1514| cairo | ✓ | ✓ | ✓ | `cairo-language-server` |
1615| capnp | ✓ | | ✓ | |
1716| clojure | ✓ | | | `clojure-lsp` |
1817| cmake | ✓ | ✓ | ✓ | `cmake-language-server` |
1918| comment | ✓ | | | |
20−| common-lisp | ✓ | | ✓ | `cl-lsp` |
19+| common-lisp | ✓ | | | `cl-lsp` |
2120| cpon | ✓ | | ✓ | |
2221| cpp | ✓ | ✓ | ✓ | `clangd` |
2322| crystal | ✓ | ✓ | | `crystalline` |
@@ -25,7 +24,6 @@
2524| cue | ✓ | | | `cuelsp` |
2625| d | ✓ | ✓ | ✓ | `serve-d` |
2726| dart | ✓ | | ✓ | `dart` |
28−| dbml | ✓ | | | |
2927| devicetree | ✓ | | | |
3028| dhall | ✓ | ✓ | | `dhall-lsp-server` |
3129| diff | ✓ | | | |
@@ -46,9 +44,7 @@
4644| forth | ✓ | | | `forth-lsp` |
4745| fortran | ✓ | | ✓ | `fortls` |
4846| fsharp | ✓ | | | `fsautocomplete` |
49−| gas | ✓ | ✓ | | |
5047| gdscript | ✓ | ✓ | ✓ | |
51−| gemini | ✓ | | | |
5248| git-attributes | ✓ | | | |
5349| git-commit | ✓ | ✓ | | |
5450| git-config | ✓ | | | |
@@ -56,13 +52,12 @@
5652| git-rebase | ✓ | | | |
5753| gleam | ✓ | ✓ | | `gleam` |
5854| glsl | ✓ | ✓ | ✓ | |
59−| gn | ✓ | | | |
60−| go | ✓ | ✓ | ✓ | `gopls`, `golangci-lint-langserver` |
55+| go | ✓ | ✓ | ✓ | `gopls` |
6156| godot-resource | ✓ | | | |
6257| gomod | ✓ | | | `gopls` |
6358| gotmpl | ✓ | | | `gopls` |
6459| gowork | ✓ | | | `gopls` |
65−| graphql | ✓ | | | `graphql-lsp` |
60+| graphql | ✓ | | | |
6661| hare | ✓ | | | |
6762| haskell | ✓ | ✓ | | `haskell-language-server-wrapper` |
6863| haskell-persistent | ✓ | | | |
@@ -74,18 +69,16 @@
7469| idris | | | | `idris2-lsp` |
7570| iex | ✓ | | | |
7671| ini | ✓ | | | |
77−| janet | ✓ | | | |
7872| java | ✓ | ✓ | ✓ | `jdtls` |
7973| javascript | ✓ | ✓ | ✓ | `typescript-language-server` |
8074| jinja | ✓ | | | |
8175| jsdoc | ✓ | | | |
8276| json | ✓ | | ✓ | `vscode-json-language-server` |
83−| json5 | ✓ | | | |
8477| jsonnet | ✓ | | | `jsonnet-language-server` |
8578| jsx | ✓ | ✓ | ✓ | `typescript-language-server` |
8679| julia | ✓ | ✓ | ✓ | `julia` |
8780| just | ✓ | ✓ | ✓ | |
88−| kdl | ✓ | ✓ | ✓ | |
81+| kdl | ✓ | | | |
8982| kotlin | ✓ | | | `kotlin-language-server` |
9083| latex | ✓ | ✓ | | `texlab` |
9184| lean | ✓ | | | `lean` |
@@ -93,8 +86,6 @@
9386| llvm | ✓ | ✓ | ✓ | |
9487| llvm-mir | ✓ | ✓ | ✓ | |
9588| llvm-mir-yaml | ✓ | | ✓ | |
96−| log | ✓ | | | |
97−| lpf | ✓ | | | |
9889| lua | ✓ | ✓ | ✓ | `lua-language-server` |
9990| make | ✓ | | | |
10091| markdoc | ✓ | | | `markdoc-ls` |
@@ -109,7 +100,7 @@
109100| nickel | ✓ | | ✓ | `nls` |
110101| nim | ✓ | ✓ | ✓ | `nimlangserver` |
111102| nix | ✓ | | | `nil` |
112−| nu | ✓ | | | `nu` |
103+| nu | ✓ | | | |
113104| nunjucks | ✓ | | | |
114105| ocaml | ✓ | | ✓ | `ocamllsp` |
115106| ocaml-interface | ✓ | | | `ocamllsp` |
@@ -120,20 +111,19 @@
120111| pascal | ✓ | ✓ | | `pasls` |
121112| passwd | ✓ | | | |
122113| pem | ✓ | | | |
123−| perl | ✓ | ✓ | ✓ | `perlnavigator` |
114+| perl | ✓ | | | `perlnavigator` |
124115| php | ✓ | ✓ | ✓ | `intelephense` |
125116| po | ✓ | ✓ | | |
126−| pod | ✓ | | | |
127117| ponylang | ✓ | ✓ | ✓ | |
128118| prisma | ✓ | | | `prisma-language-server` |
129119| prolog | | | | `swipl` |
130120| protobuf | ✓ | | ✓ | `bufls`, `pb` |
131121| prql | ✓ | | | |
132−| purescript | ✓ | ✓ | | `purescript-language-server` |
122+| purescript | ✓ | | | `purescript-language-server` |
133123| python | ✓ | ✓ | ✓ | `pylsp` |
134124| qml | ✓ | | ✓ | `qmlls` |
135125| r | ✓ | | | `R` |
136−| racket | ✓ | | ✓ | `racket` |
126+| racket | ✓ | | | `racket` |
137127| regex | ✓ | | | |
138128| rego | ✓ | | | `regols` |
139129| rescript | ✓ | ✓ | | `rescript-language-server` |
@@ -145,24 +135,21 @@
145135| rust | ✓ | ✓ | ✓ | `rust-analyzer` |
146136| sage | ✓ | ✓ | | |
147137| scala | ✓ | | ✓ | `metals` |
148−| scheme | ✓ | | ✓ | |
138+| scheme | ✓ | | | |
149139| scss | ✓ | | | `vscode-css-language-server` |
150140| slint | ✓ | | ✓ | `slint-lsp` |
151−| smali | ✓ | | ✓ | |
152141| smithy | ✓ | | | `cs` |
153142| sml | ✓ | | | |
154143| solidity | ✓ | | | `solc` |
155144| sql | ✓ | | | |
156145| sshclientconfig | ✓ | | | |
157146| starlark | ✓ | ✓ | | |
158−| strace | ✓ | | | |
159147| svelte | ✓ | | ✓ | `svelteserver` |
160148| sway | ✓ | ✓ | ✓ | `forc` |
161149| swift | ✓ | | | `sourcekit-lsp` |
162150| t32 | ✓ | | | |
163151| tablegen | ✓ | ✓ | ✓ | |
164152| task | ✓ | | | |
165−| templ | ✓ | | | `templ` |
166153| tfvars | ✓ | | ✓ | `terraform-ls` |
167154| todotxt | ✓ | | | |
168155| toml | ✓ | | | `taplo` |
@@ -170,7 +157,6 @@
170157| tsx | ✓ | ✓ | ✓ | `typescript-language-server` |
171158| twig | ✓ | | | |
172159| typescript | ✓ | ✓ | ✓ | `typescript-language-server` |
173−| typst | ✓ | | | `typst-lsp` |
174160| ungrammar | ✓ | | | |
175161| unison | ✓ | | | |
176162| uxntal | ✓ | | | |
@@ -188,6 +174,6 @@
188174| wren | ✓ | ✓ | ✓ | |
189175| xit | ✓ | | | |
190176| xml | ✓ | | ✓ | |
191−| yaml | ✓ | | ✓ | `yaml-language-server`, `ansible-language-server` |
177+| yaml | ✓ | | ✓ | `yaml-language-server` |
192178| yuck | ✓ | | | |
193179| zig | ✓ | ✓ | ✓ | `zls` |
book/src/generated/typable-cmd.md+1−4
@@ -17,7 +17,7 @@
1717| `: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) |
1818| `:new`, `:n` | Create a new scratch buffer. |
1919| `:format`, `:fmt` | Format the file using the LSP formatter. |
20−| `:indent-style` | Set the indentation style for editing. ('t' for tabs or 1-16 for number of spaces.) |
20+| `:indent-style` | Set the indentation style for editing. ('t' for tabs or 1-8 for number of spaces.) |
2121| `:line-ending` | Set the document's default line ending. Options: crlf, lf. |
2222| `:earlier`, `:ear` | Jump back to an earlier point in edit history. Accepts a number of steps or a time span. |
2323| `:later`, `:lat` | Jump to a later point in edit history. Accepts a number of steps or a time span. |
@@ -55,7 +55,6 @@
5555| `:lsp-restart` | Restarts the language servers used by the current doc |
5656| `:lsp-stop` | Stops the language servers that are used by the current doc |
5757| `:tree-sitter-scopes` | Display tree sitter scopes, primarily for theming and development. |
58−| `:tree-sitter-highlight-name` | Display name of tree-sitter highlight scope under the cursor. |
5958| `:debug-start`, `:dbg` | Start a debug session from a given template with given parameters. |
6059| `:debug-remote`, `:dbg-tcp` | Connect to a debug adapter by TCP address and start a debugging session from a given template with given parameters. |
6160| `:debug-eval` | Evaluate expression in current debug context. |
@@ -84,5 +83,3 @@
8483| `:run-shell-command`, `:sh` | Run a shell command |
8584| `:reset-diff-change`, `:diffget`, `:diffg` | Reset the diff change at the cursor position. |
8685| `:clear-register` | Clear given register. If no argument is provided, clear all registers. |
87−| `:redraw` | Clear and re-render the whole UI |
88−| `:move` | Move the current buffer and its corresponding file to a different path |
book/src/guides/adding_languages.md−2
@@ -36,7 +36,6 @@ below.
36363. Refer to the
3737 [tree-sitter website](https://tree-sitter.github.io/tree-sitter/syntax-highlighting#queries)
3838 for more information on writing queries.
39−4. A list of highlight captures can be found [on the themes page](https://docs.helix-editor.com/themes.html#scopes).
4039
4140> 💡 In Helix, the first matching query takes precedence when evaluating
4241> queries, which is different from other editors such as Neovim where the last
@@ -52,4 +51,3 @@ below.
5251 grammars.
5352- If a parser is causing a segfault, or you want to remove it, make sure to
5453 remove the compiled parser located at `runtime/grammars/<name>.so`.
55−- If you are attempting to add queries and Helix is unable to locate them, ensure that the environment variable `HELIX_RUNTIME` is set to the location of the `runtime` folder you're developing in.
book/src/guides/indent.md+43−319
@@ -1,308 +1,76 @@
11# Adding indent queries
22
3−Helix uses tree-sitter to correctly indent new lines. This requires a tree-
4−sitter grammar and an `indent.scm` query file placed in `runtime/queries/
5−{language}/indents.scm`. The indentation for a line is calculated by traversing
6−the syntax tree from the lowest node at the beginning of the new line (see
7−[Indent queries](#indent-queries)). Each of these nodes contributes to the total
8−indent when it is captured by the query (in what way depends on the name of
9−the capture.
3+Helix uses tree-sitter to correctly indent new lines. This requires
4+a tree-sitter grammar and an `indent.scm` query file placed in
5+`runtime/queries/{language}/indents.scm`. The indentation for a line
6+is calculated by traversing the syntax tree from the lowest node at the
7+beginning of the new line. Each of these nodes contributes to the total
8+indent when it is captured by the query (in what way depends on the name
9+of the capture).
1010
1111Note that it matters where these added indents begin. For example,
1212multiple indent level increases that start on the same line only increase
13−the total indent level by 1. See [Capture types](#capture-types).
13+the total indent level by 1.
1414
15−By default, Helix uses the `hybrid` indentation heuristic. This means that
16−indent queries are not used to compute the expected absolute indentation of a
17−line but rather the expected difference in indentation between the new and an
18−already existing line. This difference is then added to the actual indentation
19−of the already existing line. Since this makes errors in the indent queries
20−harder to find, it is recommended to disable it when testing via
21−`:set indent-heuristic tree-sitter`. The rest of this guide assumes that
22−the `tree-sitter` heuristic is used.
15+## Scopes
2316
24−## Indent queries
25−
26−When Helix is inserting a new line through `o`, `O`, or `<ret>`, to determine
27−the indent level for the new line, the query in `indents.scm` is run on the
28−document. The starting position of the query is the end of the line above where
29−a new line will be inserted.
30−
31−For `o`, the inserted line is the line below the cursor, so that starting
32−position of the query is the end of the current line.
33−
34−```rust
35−fn need_hero(some_hero: Hero, life: Life) -> {
36− matches!(some_hero, Hero { // ←─────────────────╮
37− strong: true,//←╮ ↑ ↑ │
38− fast: true, // │ │ ╰── query start │
39− sure: true, // │ ╰───── cursor ├─ traversal
40− soon: true, // ╰──────── new line inserted │ start node
41− }) && // │
42−// ↑ │
43−// ╰───────────────────────────────────────────────╯
44− some_hero > life
45−}
46−```
47−
48−For `O`, the newly inserted line is the *current* line, so the starting position
49−of the query is the end of the line above the cursor.
50−
51−```rust
52−fn need_hero(some_hero: Hero, life: Life) -> { // ←─╮
53− matches!(some_hero, Hero { // ←╮ ↑ │
54− strong: true,// ↑ ╭───╯ │ │
55− fast: true, // │ │ query start ─╯ │
56− sure: true, // ╰───┼ cursor ├─ traversal
57− soon: true, // ╰ new line inserted │ start node
58− }) && // │
59− some_hero > life // │
60−} // ←──────────────────────────────────────────────╯
61−```
62−
63−From this starting node, the syntax tree is traversed up until the root node.
64−Each indent capture is collected along the way, and then combined according to
65−their [capture types](#capture-types) and [scopes](#scopes) to a final indent
66−level for the line.
67−
68−### Capture types
69−
70−- `@indent` (default scope `tail`):
71− Increase the indent level by 1. Multiple occurrences in the same line *do not*
72− stack. If there is at least one `@indent` and one `@outdent` capture on the
73− same line, the indent level isn't changed at all.
74−- `@outdent` (default scope `all`):
75− Decrease the indent level by 1. The same rules as for `@indent` apply.
76−- `@indent.always` (default scope `tail`):
77− Increase the indent level by 1. Multiple occurrences on the same line *do*
78− stack. The final indent level is `@indent.always` – `@outdent.always`. If
79− an `@indent` and an `@indent.always` are on the same line, the `@indent` is
80− ignored.
81−- `@outdent.always` (default scope `all`):
82− Decrease the indent level by 1. The same rules as for `@indent.always` apply.
83−- `@align` (default scope `all`):
84− Align everything inside this node to some anchor. The anchor is given
85− by the start of the node captured by `@anchor` in the same pattern.
86− Every pattern with an `@align` should contain exactly one `@anchor`.
87− Indent (and outdent) for nodes below (in terms of their starting line)
88− the `@align` node is added to the indentation required for alignment.
89−- `@extend`:
90− Extend the range of this node to the end of the line and to lines that are
91− indented more than the line that this node starts on. This is useful for
92− languages like Python, where for the purpose of indentation some nodes (like
93− functions or classes) should also contain indented lines that follow them.
94−- `@extend.prevent-once`:
95− Prevents the first extension of an ancestor of this node. For example, in Python
96− a return expression always ends the block that it is in. Note that this only
97− stops the extension of the next `@extend` capture. If multiple ancestors are
98− captured, only the extension of the innermost one is prevented. All other
99− ancestors are unaffected (regardless of whether the innermost ancestor would
100− actually have been extended).
101−
102−#### `@indent` / `@outdent`
103−
104−Consider this example:
105−
106−```rust
107−fn shout(things: Vec<Thing>) {
108− // ↑
109− // ├───────────────────────╮ indent level
110− // @indent ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄
111− // │
112− let it_all = |out| { things.filter(|thing| { // │ 1
113− // ↑ ↑ │
114− // ├───────────────────────┼─────┼┄┄┄┄┄┄┄┄┄┄┄┄┄┄
115− // @indent @indent │
116− // │ 2
117− thing.can_do_with(out) // │
118− })}; // ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄
119− //↑↑↑ │ 1
120−} //╰┼┴──────────────────────────────────────────────┴┄┄┄┄┄┄┄┄┄┄┄┄┄┄
121−// 3x @outdent
122−```
123−
124−```scm
125−((block) @indent)
126−["}" ")"] @outdent
127−```
128−
129−Note how on the second line, we have two blocks begin on the same line. In this
130−case, since both captures occur on the same line, they are combined and only
131−result in a net increase of 1. Also note that the closing `}`s are part of the
132−`@indent` captures, but the 3 `@outdent`s also combine into 1 and result in that
133−line losing one indent level.
134−
135−#### `@extend` / `@extend.prevent-once`
136−
137−For an example of where `@extend` can be useful, consider Python, which is
138−whitespace-sensitive.
139−
140−```scm
141−]
142− (parenthesized_expression)
143− (function_definition)
144− (class_definition)
145−] @indent
146−
147−```
148−
149−```python
150−class Hero:
151− def __init__(self, strong, fast, sure, soon):# ←─╮
152− self.is_strong = strong # │
153− self.is_fast = fast # ╭─── query start │
154− self.is_sure = sure # │ ╭─ cursor │
155− self.is_soon = soon # │ │ │
156− # ↑ ↑ │ │ │
157− # │ ╰──────╯ │ │
158− # ╰─────────────────────╯ │
159− # ├─ traversal
160− def need_hero(self, life): # │ start node
161− return ( # │
162− self.is_strong # │
163− and self.is_fast # │
164− and self.is_sure # │
165− and self.is_soon # │
166− and self > life # │
167− ) # ←─────────────────────────────────────────╯
168−```
169−
170−Without braces to catch the scope of the function, the smallest descendant of
171−the cursor on a line feed ends up being the entire inside of the class. Because
172−of this, it will miss the entire function node and its indent capture, leading
173−to an indent level one too small.
174−
175−To address this case, `@extend` tells helix to "extend" the captured node's span
176−to the line feed and every consecutive line that has a greater indent level than
177−the line of the node.
178−
179−```scm
180−(parenthesized_expression) @indent
181−
182−]
183− (function_definition)
184− (class_definition)
185−] @indent @extend
186−
187−```
188−
189−```python
190−class Hero:
191− def __init__(self, strong, fast, sure, soon):# ←─╮
192− self.is_strong = strong # │
193− self.is_fast = fast # ╭─── query start ├─ traversal
194− self.is_sure = sure # │ ╭─ cursor │ start node
195− self.is_soon = soon # │ │ ←───────────────╯
196− # ↑ ↑ │ │
197− # │ ╰──────╯ │
198− # ╰─────────────────────╯
199− def need_hero(self, life):
200− return (
201− self.is_strong
202− and self.is_fast
203− and self.is_sure
204− and self.is_soon
205− and self > life
206− )
207−```
208−
209−Furthermore, there are some cases where extending to everything with a greater
210−indent level may not be desirable. Consider the `need_hero` function above. If
211−our cursor is on the last line of the returned expression.
212−
213−```python
214−class Hero:
215− def __init__(self, strong, fast, sure, soon):
216− self.is_strong = strong
217− self.is_fast = fast
218− self.is_sure = sure
219− self.is_soon = soon
220−
221− def need_hero(self, life):
222− return (
223− self.is_strong
224− and self.is_fast
225− and self.is_sure
226− and self.is_soon
227− and self > life
228− ) # ←─── cursor
229− #←────────── where cursor should go on new line
230−```
17+Added indents don't always apply to the whole node. For example, in most
18+cases when a node should be indented, we actually only want everything
19+except for its first line to be indented. For this, there are several
20+scopes (more scopes may be added in the future if required):
23121
232−In Python, the are a few tokens that will always end a scope, such as a return
233−statement. Since the scope ends, so should the indent level. But because the
234−function span is extended to every line with a greater indent level, a new line
235−would just continue on the same level. And an `@outdent` would not help us here
236−either, since it would cause everything in the parentheses to become outdented
237−as well.
22+- `all`:
23+This scope applies to the whole captured node. This is only different from
24+`tail` when the captured node is the first node on its line.
23825
239−To help, we need to signal an end to the extension. We can do this with
240−`@extend.prevent-once`.
26+- `tail`:
27+This scope applies to everything except for the first line of the
28+captured node.
24129
30+Every capture type has a default scope which should do the right thing
31+in most situations. When a different scope is required, this can be
32+changed by using a `#set!` declaration anywhere in the pattern:
24233```scm
243−(parenthesized_expression) @indent
244−
245−]
246− (function_definition)
247− (class_definition)
248−] @indent @extend
249−
250−(return_statement) @extend.prevent-once
34+(assignment_expression
35+ right: (_) @indent
36+ (#set! "scope" "all"))
25137```
25238
253−#### `@indent.always` / `@outdent.always`
254−
255−As mentioned before, normally if there is more than one `@indent` or `@outdent`
256−capture on the same line, they are combined.
39+## Capture types
25740
258−Sometimes, there are cases when you may want to ensure that every indent capture
259−is additive, regardless of how many occur on the same line. Consider this
260−example in YAML.
41+- `@indent` (default scope `tail`):
42+Increase the indent level by 1. Multiple occurrences in the same line
43+don't stack. If there is at least one `@indent` and one `@outdent`
44+capture on the same line, the indent level isn't changed at all.
26145
262−```yaml
263− - foo: bar
264−# ↑ ↑
265−# │ ╰─────────────── start of map
266−# ╰───────────────── start of list element
267− baz: quux # ←─── cursor
268− # ←───────────── where the cursor should go on a new line
269− garply: waldo
270− - quux:
271− bar: baz
272− xyzzy: thud
273− fred: plugh
274−```
46+- `@outdent` (default scope `all`):
47+Decrease the indent level by 1. The same rules as for `@indent` apply.
27548
276−In YAML, you often have lists of maps. In these cases, the syntax is such that
277−the list element and the map both start on the same line. But we really do want
278−to start an indentation for each of these so that subsequent keys in the map
279−hang over the list and align properly. This is where `@indent.always` helps.
49+- `@extend`:
50+Extend the range of this node to the end of the line and to lines that
51+are indented more than the line that this node starts on. This is useful
52+for languages like Python, where for the purpose of indentation some nodes
53+(like functions or classes) should also contain indented lines that follow them.
28054
281−```scm
282−((block_sequence_item) @item @indent.always @extend
283− (#not-one-line? @item))
55+- `@extend.prevent-once`:
56+Prevents the first extension of an ancestor of this node. For example, in Python
57+a return expression always ends the block that it is in. Note that this only stops the
58+extension of the next `@extend` capture. If multiple ancestors are captured,
59+only the extension of the innermost one is prevented. All other ancestors are unaffected
60+(regardless of whether the innermost ancestor would actually have been extended).
28461
285−((block_mapping_pair
286− key: (_) @key
287− value: (_) @val
288− (#not-same-line? @key @val)
289− ) @indent.always @extend
290−)
291−```
29262
29363## Predicates
29464
29565In some cases, an S-expression cannot express exactly what pattern should be matched.
29666For that, tree-sitter allows for predicates to appear anywhere within a pattern,
29767similar to how `#set!` declarations work:
298−
29968```scm
30069(some_kind
30170 (child_kind) @indent
30271 (#predicate? arg1 arg2 ...)
30372)
30473```
305−
30674The number of arguments depends on the predicate that's used.
30775Each argument is either a capture (`@name`) or a string (`"some string"`).
30876The following predicates are supported by tree-sitter:
@@ -323,47 +91,3 @@ argument (a string).
32391
32492- `#same-line?`/`#not-same-line?`:
32593The captures given by the 2 arguments must/must not start on the same line.
326−
327−- `#one-line?`/`#not-one-line?`:
328−The captures given by the fist argument must/must span a total of one line.
329−
330−### Scopes
331−
332−Added indents don't always apply to the whole node. For example, in most
333−cases when a node should be indented, we actually only want everything
334−except for its first line to be indented. For this, there are several
335−scopes (more scopes may be added in the future if required):
336−
337−- `tail`:
338−This scope applies to everything except for the first line of the
339−captured node.
340−- `all`:
341−This scope applies to the whole captured node. This is only different from
342−`tail` when the captured node is the first node on its line.
343−
344−For example, imagine we have the following function
345−
346−```rust
347−fn aha() { // ←─────────────────────────────────────╮
348− let take = "on me"; // ←──────────────╮ scope: │
349− let take = "me on"; // ├─ "tail" ├─ (block) @indent
350− let ill = be_gone_days(1 || 2); // │ │
351−} // ←───────────────────────────────────┴──────────┴─ "}" @outdent
352− // scope: "all"
353−```
354−
355−We can write the following query with the `#set!` declaration:
356−
357− ```scm
358− ((block) @indent
359− (#set! "scope" "tail"))
360− ("}" @outdent
361− (#set! "scope" "all"))
362− ```
363−
364−As we can see, the "tail" scope covers the node, except for the first line.
365−Everything up to and including the closing brace gets an indent level of 1.
366−Then, on the closing brace, we encounter an outdent with a scope of "all", which
367−means the first line is included, and the indent level is cancelled out on this
368−line. (Note these scopes are the defaults for `@indent` and `@outdent`—they are
369−written explicitly for demonstration.)
book/src/guides/injection.md+1−1
@@ -1,7 +1,7 @@
11# Adding Injection Queries
22
33Writing language injection queries allows one to highlight a specific node as a different language.
4−In addition to the [standard][upstream-docs] language injection options used by tree-sitter, there
4+In addition to the [standard](upstream-docs) language injection options used by tree-sitter, there
55are a few Helix specific extensions that allow for more control.
66
77And example of a simple query that would highlight all strings as bash in Nix:
book/src/install.md+6−30
@@ -13,7 +13,6 @@
1313 - [AppImage](#appimage)
1414- [macOS](#macos)
1515 - [Homebrew Core](#homebrew-core)
16− - [MacPorts](#macports)
1716- [Windows](#windows)
1817 - [Winget](#winget)
1918 - [Scoop](#scoop)
@@ -65,7 +64,10 @@ sudo apt install helix
6564
6665### Fedora/RHEL
6766
67+Enable the `COPR` repository for Helix:
68+
6869```sh
70+sudo dnf copr enable varlad/helix
6971sudo dnf install helix
7072```
7173
@@ -131,12 +133,6 @@ chmod +x helix-*.AppImage # change permission for executable mode
131133brew install helix
132134```
133135
134−### MacPorts
135−
136−```sh
137−port install helix
138−```
139−
140136## Windows
141137
142138Install on Windows using [Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/), [Scoop](https://scoop.sh/), [Chocolatey](https://chocolatey.org/)
@@ -228,7 +224,7 @@ Or, create a symbolic link:
228224ln -Ts $PWD/runtime ~/.config/helix/runtime
229225```
230226
231−If the above command fails to create a symbolic link because the file exists either move `~/.config/helix/runtime` to a new location or delete it, then run the symlink command above again.
227+If the above command fails to create a symbolic link because the file exists either move `~/.config/helix/runtime` to a new location or delete it, then run the symlink command above again.
232228
233229#### Windows
234230
@@ -261,32 +257,12 @@ following order:
2612571. `runtime/` sibling directory to `$CARGO_MANIFEST_DIR` directory (this is intended for
262258 developing and testing helix only).
2632592. `runtime/` subdirectory of OS-dependent helix user config directory.
264−3. `$HELIX_RUNTIME`
265−4. Distribution-specific fallback directory (set at compile time—not run time—
266− with the `HELIX_DEFAULT_RUNTIME` environment variable)
267−5. `runtime/` subdirectory of path to Helix executable.
260+3. `$HELIX_RUNTIME`.
261+4. `runtime/` subdirectory of path to Helix executable.
268262
269263This order also sets the priority for selecting which file will be used if multiple runtime
270264directories have files with the same name.
271265
272−#### Note to packagers
273−
274−If you are making a package of Helix for end users, to provide a good out of
275−the box experience, you should set the `HELIX_DEFAULT_RUNTIME` environment
276−variable at build time (before invoking `cargo build`) to a directory which
277−will store the final runtime files after installation. For example, say you want
278−to package the runtime into `/usr/lib/helix/runtime`. The rough steps a build
279−script could follow are:
280−
281−1. `export HELIX_DEFAULT_RUNTIME=/usr/lib/helix/runtime`
282−1. `cargo build --profile opt --locked --path helix-term`
283−1. `cp -r runtime $BUILD_DIR/usr/lib/helix/`
284−1. `cp target/opt/hx $BUILD_DIR/usr/bin/hx`
285−
286−This way the resulting `hx` binary will always look for its runtime directory in
287−`/usr/lib/helix/runtime` if the user has no custom runtime in `~/.config/helix`
288−or `HELIX_RUNTIME`.
289−
290266### Validating the installation
291267
292268To make sure everything is set up as expected you should run the Helix health
book/src/keymap.md+14−15
@@ -25,7 +25,7 @@
2525
2626## Normal mode
2727
28−Normal mode is the default mode when you launch helix. You can return to it from other modes by pressing the `Escape` key.
28+Normal mode is the default mode when you launch helix. Return to it from other modes by typing `Escape`.
2929
3030### Movement
3131
@@ -411,20 +411,19 @@ you to selectively add search terms to your selections.
411411
412412Keys to use within picker. Remapping currently not supported.
413413
414−| Key | Description |
415−| ----- | ------------- |
416−| `Shift-Tab`, `Up`, `Ctrl-p` | Previous entry |
417−| `Tab`, `Down`, `Ctrl-n` | Next entry |
418−| `PageUp`, `Ctrl-u` | Page up |
419−| `PageDown`, `Ctrl-d` | Page down |
420−| `Home` | Go to first entry |
421−| `End` | Go to last entry |
422−| `Enter` | Open selected |
423−| `Alt-Enter` | Open selected in the background without closing the picker |
424−| `Ctrl-s` | Open horizontally |
425−| `Ctrl-v` | Open vertically |
426−| `Ctrl-t` | Toggle preview |
427−| `Escape`, `Ctrl-c` | Close picker |
414+| Key | Description |
415+| ----- | ------------- |
416+| `Shift-Tab`, `Up`, `Ctrl-p` | Previous entry |
417+| `Tab`, `Down`, `Ctrl-n` | Next entry |
418+| `PageUp`, `Ctrl-u` | Page up |
419+| `PageDown`, `Ctrl-d` | Page down |
420+| `Home` | Go to first entry |
421+| `End` | Go to last entry |
422+| `Enter` | Open selected |
423+| `Ctrl-s` | Open horizontally |
424+| `Ctrl-v` | Open vertically |
425+| `Ctrl-t` | Toggle preview |
426+| `Escape`, `Ctrl-c` | Close picker |
428427
429428## Prompt
430429
book/src/languages.md+1−3
@@ -66,10 +66,8 @@ These configuration keys are available:
6666| `language-servers` | The Language Servers used for this language. See below for more information in the section [Configuring Language Servers for a language](#configuring-language-servers-for-a-language) |
6767| `grammar` | The tree-sitter grammar to use (defaults to the value of `name`) |
6868| `formatter` | The formatter for the language, it will take precedence over the lsp when defined. The formatter must be able to take the original file as input from stdin and write the formatted file to stdout |
69−| `soft-wrap` | [editor.softwrap](./configuration.md#editorsoft-wrap-section)
7069| `text-width` | Maximum line length. Used for the `:reflow` command and soft-wrapping if `soft-wrap.wrap-at-text-width` is set, defaults to `editor.text-width` |
7170| `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml`. Overwrites the setting of the same name in `config.toml` if set. |
72−| `persistent-diagnostic-sources` | An array of LSP diagnostic sources assumed unchanged when the language server resends the same set of diagnostics. Helix can track the position for these diagnostics internally instead. Useful for diagnostics that are recomputed on save.
7371
7472### File-type detection and the `file-types` key
7573
@@ -129,7 +127,7 @@ These are the available options for a language server.
129127| `environment` | Any environment variables that will be used when starting the language server `{ "KEY1" = "Value1", "KEY2" = "Value2" }` |
130128
131129A `format` sub-table within `config` can be used to pass extra formatting options to
132−[Document Formatting Requests](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_formatting).
130+[Document Formatting Requests](https://github.com/microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-17.md#document-formatting-request--leftwards_arrow_with_hook).
133131For example, with typescript:
134132
135133```toml
book/src/themes.md+1−9
@@ -70,7 +70,6 @@ over it and is merged into the default palette.
7070
7171| Color Name |
7272| --- |
73−| `default` |
7473| `black` |
7574| `red` |
7675| `green` |
@@ -155,7 +154,6 @@ We use a similar set of scopes as
155154
156155- `type` - Types
157156 - `builtin` - Primitive types provided by the language (`int`, `usize`)
158− - `parameter` - Generic type parameters (`T`)
159157 - `enum`
160158 - `variant`
161159- `constructor`
@@ -246,12 +244,9 @@ We use a similar set of scopes as
246244
247245- `diff` - version control changes
248246 - `plus` - additions
249− - `gutter` - gutter indicator
250247 - `minus` - deletions
251− - `gutter` - gutter indicator
252248 - `delta` - modifications
253249 - `moved` - renamed or moved files/changes
254− - `gutter` - gutter indicator
255250
256251#### Interface
257252
@@ -296,14 +291,11 @@ These scopes are used for theming the editor interface:
296291| `ui.statusline.insert` | Statusline mode during insert mode ([only if `editor.color-modes` is enabled][editor-section]) |
297292| `ui.statusline.select` | Statusline mode during select mode ([only if `editor.color-modes` is enabled][editor-section]) |
298293| `ui.statusline.separator` | Separator character in statusline |
299−| `ui.bufferline` | Style for the buffer line |
300−| `ui.bufferline.active` | Style for the active buffer in buffer line |
301−| `ui.bufferline.background` | Style for bufferline background |
302294| `ui.popup` | Documentation popups (e.g. Space + k) |
303295| `ui.popup.info` | Prompt for multiple key options |
304296| `ui.window` | Borderlines separating splits |
305297| `ui.help` | Description box for commands |
306−| `ui.text` | Default text style, command prompts, popup text, etc. |
298+| `ui.text` | Command prompts, popup text, etc. |
307299| `ui.text.focus` | The currently selected line in the picker |
308300| `ui.text.inactive` | Same as `ui.text` but when the text is inactive (e.g. suggestions) |
309301| `ui.text.info` | The key: command text in `ui.popup.info` boxes |
book/src/usage.md+2−2
@@ -59,8 +59,8 @@ Some registers have special behavior when read from and written to.
5959| `#` | Selection indices (first selection is `1`, second is `2`, etc.) | This register is not writable |
6060| `.` | Contents of the current selections | This register is not writable |
6161| `%` | Name of the current file | This register is not writable |
62−| `+` | Reads from the system clipboard | Joins and yanks to the system clipboard |
63−| `*` | Reads from the primary clipboard | Joins and yanks to the primary clipboard |
62+| `*` | Reads from the system clipboard | Joins and yanks to the system clipboard |
63+| `+` | Reads from the primary clipboard | Joins and yanks to the primary clipboard |
6464
6565When yanking multiple selections to the clipboard registers, the selections
6666are joined with newlines. Pasting from these registers will paste multiple
book/theme/index.hbs+15−18
@@ -1,11 +1,11 @@
11<!DOCTYPE HTML>
2−<html lang="{{ language }}" class="{{ default_theme }}" dir="{{ text_direction }}">
2+<html lang="{{ language }}" class="sidebar-visible no-js {{ default_theme }}">
33 <head>
44 <!-- Book generated using mdBook -->
55 <meta charset="UTF-8">
66 <title>{{ title }}</title>
77 {{#if is_print }}
8− <meta name="robots" content="noindex">
8+ <meta name="robots" content="noindex" />
99 {{/if}}
1010 {{#if base_url}}
1111 <base href="{{ base_url }}">
@@ -17,7 +17,7 @@
1717
1818 <meta name="description" content="{{ description }}">
1919 <meta name="viewport" content="width=device-width, initial-scale=1">
20− <meta name="theme-color" content="#ffffff">
20+ <meta name="theme-color" content="#ffffff" />
2121
2222 {{#if favicon_svg}}
2323 <link rel="icon" href="{{ path_to_root }}favicon.svg">
@@ -34,6 +34,8 @@
3434
3535 <!-- Fonts -->
3636 <link rel="stylesheet" href="{{ path_to_root }}FontAwesome/css/font-awesome.css">
37+ <link rel="preconnect" href="https://fonts.gstatic.com">
38+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@200;400;500;700&display=swap" rel="stylesheet">
3739 {{#if copy_fonts}}
3840 <link rel="stylesheet" href="{{ path_to_root }}fonts/fonts.css">
3941 {{/if}}
@@ -53,7 +55,7 @@
5355 <script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
5456 {{/if}}
5557 </head>
56− <body class="sidebar-visible no-js">
58+ <body>
5759 <div id="body-container">
5860 <!-- Provide site root to javascript -->
5961 <script>
@@ -83,29 +85,24 @@
8385 try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
8486 if (theme === null || theme === undefined) { theme = default_theme; }
8587 var html = document.querySelector('html');
88+ html.classList.remove('no-js')
8689 html.classList.remove('{{ default_theme }}')
8790 html.classList.add(theme);
88− var body = document.querySelector('body');
89− body.classList.remove('no-js')
90− body.classList.add('js');
91+ html.classList.add('js');
9192 </script>
9293
93− <input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
94−
9594 <!-- Hide / unhide sidebar before it is displayed -->
9695 <script>
97− var body = document.querySelector('body');
96+ var html = document.querySelector('html');
9897 var sidebar = null;
99− var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
10098 if (document.body.clientWidth >= 1080) {
10199 try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
102100 sidebar = sidebar || 'visible';
103101 } else {
104102 sidebar = 'hidden';
105103 }
106− sidebar_toggle.checked = sidebar === 'visible';
107− body.classList.remove('sidebar-visible');
108− body.classList.add("sidebar-" + sidebar);
104+ html.classList.remove('sidebar-visible');
105+ html.classList.add("sidebar-" + sidebar);
109106 </script>
110107
111108 <nav id="sidebar" class="sidebar" aria-label="Table of contents">
@@ -144,9 +141,9 @@
144141 <div id="menu-bar-hover-placeholder"></div>
145142 <div id="menu-bar" class="menu-bar sticky">
146143 <div class="left-buttons">
147− <label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
144+ <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
148145 <i class="fa fa-bars"></i>
149− </label>
146+ </button>
150147 <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
151148 <i class="fa fa-paint-brush"></i>
152149 </button>
@@ -223,7 +220,7 @@
223220 {{/previous}}
224221
225222 {{#next}}
226− <a rel="next prefetch" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
223+ <a rel="next" href="{{ path_to_root }}{{link}}" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
227224 <i class="fa fa-angle-right"></i>
228225 </a>
229226 {{/next}}
@@ -241,7 +238,7 @@
241238 {{/previous}}
242239
243240 {{#next}}
244− <a rel="next prefetch" href="{{ path_to_root }}{{link}}" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
241+ <a rel="next" href="{{ path_to_root }}{{link}}" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
245242 <i class="fa fa-angle-right"></i>
246243 </a>
247244 {{/next}}
contrib/Helix.appdata.xml−15
@@ -5,7 +5,6 @@
55 <project_license>MPL-2.0</project_license>
66 <name>Helix</name>
77 <summary>A post-modern text editor</summary>
8− <summary xml:lang="ar">مُحَرِّرُ نُصُوصٍ سَابِقٌ لِعَهدِه</summary>
98
109 <description>
1110 <p>
@@ -18,17 +17,6 @@
1817 <li>Smart, incremental syntax highlighting and code editing via tree-sitter</li>
1918 </ul>
2019 </description>
21− <description xml:lang="ar">
22− <p>
23− مُحَرِّرُ نُصُوصٍ يَعمَلُ فِي الطَّرَفِيَّة، مُستَلهَمٌ مِن Kakoune وَ Neovim وَمَكتُوبٌ بِلُغَةِ رَست البَرمَجِيَّة.
24− </p>
25− <ul>
26− <li>تَحرِيرٌ وَضعِيٌّ شَبيهٌ بِـVim</li>
27− <li>تَحدِيدَاتٌ لِلنَّصِ مُتَعَدِّدَة</li>
28− <li>دَعْمٌ مُدمَجٌ لِخَوادِمِ اللُّغَات</li>
29− <li>تَحرِيرُ التَّعلِيمَاتِ البَّرمَجِيَّةِ مَعَ تَمييزٍ لِلتَّركِيبِ النَّحُويِّ بِواسِطَةِ tree-sitter</li>
30− </ul>
31− </description>
3220
3321 <launchable type="desktop-id">Helix.desktop</launchable>
3422
@@ -48,9 +36,6 @@
4836 <content_rating type="oars-1.1" />
4937
5038 <releases>
51− <release version="23.10" date="2023-10-24">
52− <url>https://helix-editor.com/news/release-23-10-highlights/</url>
53− </release>
5439 <release version="23.05" date="2023-05-18">
5540 <url>https://github.com/helix-editor/helix/releases/tag/23.05</url>
5641 </release>
contrib/Helix.desktop+1−3
@@ -1,7 +1,6 @@
11[Desktop Entry]
22Name=Helix
33GenericName=Text Editor
4−GenericName[ar]=مُحَرِّرُ نُصُوص
54GenericName[de]=Texteditor
65GenericName[fr]=Éditeur de texte
76GenericName[ru]=Текстовый редактор
@@ -10,7 +9,7 @@ GenericName[tr]=Metin Düzenleyici
109Comment=Edit text files
1110Comment[af]=Redigeer tekslêers
1211Comment[am]=የጽሑፍ ፋይሎች ያስተካክሉ
13−Comment[ar]=مُحَرِّرُ مِلَفَّاتٍ نَصِّيَّة
12+Comment[ar]=حرّر ملفات نصية
1413Comment[az]=Mətn fayllarını redaktə edin
1514Comment[be]=Рэдагаваньне тэкставых файлаў
1615Comment[bg]=Редактиране на текстови файлове
@@ -80,7 +79,6 @@ Exec=hx %F
8079Terminal=true
8180Type=Application
8281Keywords=Text;editor;
83−Keywords[ar]=نص;نصوص;محرر;
8482Keywords[fr]=Texte;éditeur;
8583Keywords[ru]=текст;текстовый редактор;
8684Keywords[sr]=Текст;едитор;
docs/CONTRIBUTING.md+3−10
@@ -29,15 +29,9 @@ files, run
2929cargo xtask docgen
3030```
3131
32−inside the project. We use [xtask][xtask] as an ad-hoc task runner.
33−
34−To preview the book itself, install [mdbook][mdbook]. Then, run
35−
36−```shell
37−mdbook serve book
38−```
39−
40−and visit [http://localhost:3000](http://localhost:3000).
32+inside the project. We use [xtask][xtask] as an ad-hoc task runner and
33+thus do not require any dependencies other than `cargo` (You don't have
34+to `cargo install` anything either).
4135
4236# Testing
4337
@@ -64,5 +58,4 @@ The current MSRV and future changes to the MSRV are listed in the [Firefox docum
6458[architecture.md]: ./architecture.md
6559[docs]: https://docs.helix-editor.com/
6660[xtask]: https://github.com/matklad/cargo-xtask
67−[mdbook]: https://rust-lang.github.io/mdBook/guide/installation.html
6861[helpers.rs]: ../helix-term/tests/test/helpers.rs
docs/releases.md+5−12
@@ -1,23 +1,16 @@
11## Checklist
22
33Helix releases are versioned in the Calendar Versioning scheme:
4−`YY.0M(.MICRO)`, for example, `22.05` for May of 2022, or in a patch release,
5−`22.05.1`. In these instructions we'll use `<tag>` as a placeholder for the tag
6−being published.
4+`YY.0M(.MICRO)`, for example, `22.05` for May of 2022. In these instructions
5+we'll use `<tag>` as a placeholder for the tag being published.
76
87* Merge the changelog PR
98* Add new `<release>` entry in `contrib/Helix.appdata.xml` with release information according to the [AppStream spec](https://www.freedesktop.org/software/appstream/docs/sect-Metadata-Releases.html)
109* Tag and push
1110 * `git tag -s -m "<tag>" -a <tag> && git push`
1211 * Make sure to switch to master and pull first
13−* Edit the `Cargo.toml` file and change the date in the `version` field to the next planned release
14− * Due to Cargo having a strict requirement on SemVer with 3 or more version
15− numbers, a `0` is required in the micro version; however, unless we are
16− publishing a patch release after a major release, the `.0` is dropped in
17− the user facing version.
18− * Releases are planned to happen every two months, so `22.05.0` would change to `22.07.0`
19− * If we are pushing a patch/bugfix release in the same month as the previous
20− release, bump the micro version, e.g. `22.07.0` to `22.07.1`
12+* Edit the `VERSION` file and change the date to the next planned release
13+ * Releases are planned to happen every two months, so `22.05` would change to `22.07`
2114* Wait for the Release CI to finish
2215 * It will automatically turn the git tag into a GitHub release when it uploads artifacts
2316* Edit the new release
@@ -64,4 +57,4 @@ versions for convenience:
6457> release. For the full log, check out the git log.
6558
6659Typically, small changes like dependencies or documentation updates, refactors,
67−or meta changes like GitHub Actions work are left out.
60+or meta changes like GitHub Actions work are left out.
flake.lock+35−12
@@ -2,16 +2,23 @@
22 "nodes": {
33 "crane": {
44 "inputs": {
5+ "flake-compat": "flake-compat",
6+ "flake-utils": [
7+ "flake-utils"
8+ ],
59 "nixpkgs": [
610 "nixpkgs"
11+ ],
12+ "rust-overlay": [
13+ "rust-overlay"
714 ]
815 },
916 "locked": {
10− "lastModified": 1701025348,
11− "narHash": "sha256-42GHmYH+GF7VjwGSt+fVT1CQuNpGanJbNgVHTAZppUM=",
17+ "lastModified": 1688772518,
18+ "narHash": "sha256-ol7gZxwvgLnxNSZwFTDJJ49xVY5teaSvF7lzlo3YQfM=",
1219 "owner": "ipetkov",
1320 "repo": "crane",
14− "rev": "42afaeb1a0325194a7cdb526332d2cb92fddd07b",
21+ "rev": "8b08e96c9af8c6e3a2b69af5a7fa168750fcf88e",
1522 "type": "github"
1623 },
1724 "original": {
@@ -20,16 +27,32 @@
2027 "type": "github"
2128 }
2229 },
30+ "flake-compat": {
31+ "flake": false,
32+ "locked": {
33+ "lastModified": 1673956053,
34+ "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
35+ "owner": "edolstra",
36+ "repo": "flake-compat",
37+ "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
38+ "type": "github"
39+ },
40+ "original": {
41+ "owner": "edolstra",
42+ "repo": "flake-compat",
43+ "type": "github"
44+ }
45+ },
2346 "flake-utils": {
2447 "inputs": {
2548 "systems": "systems"
2649 },
2750 "locked": {
28− "lastModified": 1694529238,
29− "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
51+ "lastModified": 1689068808,
52+ "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
3053 "owner": "numtide",
3154 "repo": "flake-utils",
32− "rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
55+ "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
3356 "type": "github"
3457 },
3558 "original": {
@@ -40,11 +63,11 @@
4063 },
4164 "nixpkgs": {
4265 "locked": {
43− "lastModified": 1700794826,
44− "narHash": "sha256-RyJTnTNKhO0yqRpDISk03I/4A67/dp96YRxc86YOPgU=",
66+ "lastModified": 1690272529,
67+ "narHash": "sha256-MakzcKXEdv/I4qJUtq/k/eG+rVmyOZLnYNC2w1mB59Y=",
4568 "owner": "nixos",
4669 "repo": "nixpkgs",
47− "rev": "5a09cb4b393d58f9ed0d9ca1555016a8543c2ac8",
70+ "rev": "ef99fa5c5ed624460217c31ac4271cfb5cb2502c",
4871 "type": "github"
4972 },
5073 "original": {
@@ -72,11 +95,11 @@
7295 ]
7396 },
7497 "locked": {
75− "lastModified": 1701137803,
76− "narHash": "sha256-0LcPAdql5IhQSUXJx3Zna0dYTgdIoYO7zUrsKgiBd04=",
98+ "lastModified": 1690424156,
99+ "narHash": "sha256-Bpml+L280tHTQpwpC5/BJbU4HSvEzMvW8IZ4gAXimhE=",
77100 "owner": "oxalica",
78101 "repo": "rust-overlay",
79− "rev": "9dd940c967502f844eacea52a61e9596268d4f70",
102+ "rev": "f335a0213504c7e6481c359dc1009be9cf34432c",
80103 "type": "github"
81104 },
82105 "original": {
flake.nix+24−27
@@ -13,6 +13,8 @@
1313 };
1414 crane = {
1515 url = "github:ipetkov/crane";
16+ inputs.rust-overlay.follows = "rust-overlay";
17+ inputs.flake-utils.follows = "flake-utils";
1618 inputs.nixpkgs.follows = "nixpkgs";
1719 };
1820 };
@@ -41,6 +43,7 @@
4143 ".ignore"
4244 ".github"
4345 ".gitignore"
46+ "logo.svg"
4447 "logo_dark.svg"
4548 "logo_light.svg"
4649 "rust-toolchain.toml"
@@ -48,6 +51,7 @@
4851 "runtime"
4952 "screenshot.png"
5053 "book"
54+ "contrib"
5155 "docs"
5256 "README.md"
5357 "CHANGELOG.md"
@@ -119,32 +123,25 @@
119123 then ''$RUSTFLAGS -C link-arg=-fuse-ld=lld -C target-cpu=native -Clink-arg=-Wl,--no-rosegment''
120124 else "$RUSTFLAGS";
121125 rustToolchain = pkgs.pkgsBuildHost.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
122− craneLibMSRV = (crane.mkLib pkgs).overrideToolchain rustToolchain;
123− craneLibStable = (crane.mkLib pkgs).overrideToolchain pkgs.pkgsBuildHost.rust-bin.stable.latest.default;
124− commonArgs = {
125− inherit stdenv;
126− inherit (craneLibMSRV.crateNameFromCargoToml {cargoToml = ./helix-term/Cargo.toml;}) pname;
127− inherit (craneLibMSRV.crateNameFromCargoToml {cargoToml = ./Cargo.toml;}) version;
128− src = filteredSource;
129− # disable fetching and building of tree-sitter grammars in the helix-term build.rs
130− HELIX_DISABLE_AUTO_GRAMMAR_BUILD = "1";
131− buildInputs = [stdenv.cc.cc.lib];
132− # disable tests
133− doCheck = false;
134− meta.mainProgram = "hx";
135− };
136− cargoArtifacts = craneLibMSRV.buildDepsOnly commonArgs;
126+ craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain;
127+ commonArgs =
128+ {
129+ inherit stdenv;
130+ src = filteredSource;
131+ # disable fetching and building of tree-sitter grammars in the helix-term build.rs
132+ HELIX_DISABLE_AUTO_GRAMMAR_BUILD = "1";
133+ buildInputs = [stdenv.cc.cc.lib];
134+ # disable tests
135+ doCheck = false;
136+ meta.mainProgram = "hx";
137+ }
138+ // craneLib.crateNameFromCargoToml {cargoToml = ./helix-term/Cargo.toml;};
139+ cargoArtifacts = craneLib.buildDepsOnly commonArgs;
137140 in {
138141 packages = {
139− helix-unwrapped = craneLibStable.buildPackage (commonArgs
142+ helix-unwrapped = craneLib.buildPackage (commonArgs
140143 // {
141− cargoArtifacts = craneLibStable.buildDepsOnly commonArgs;
142− postInstall = ''
143− mkdir -p $out/share/applications $out/share/icons/hicolor/scalable/apps $out/share/icons/hicolor/256x256/apps
144− cp contrib/Helix.desktop $out/share/applications
145− cp logo.svg $out/share/icons/hicolor/scalable/apps/helix.svg
146− cp contrib/helix.png $out/share/icons/hicolor/256x256/apps
147− '';
144+ inherit cargoArtifacts;
148145 });
149146 helix = makeOverridableHelix self.packages.${system}.helix-unwrapped {};
150147 default = self.packages.${system}.helix;
@@ -154,20 +151,20 @@
154151 # Build the crate itself
155152 inherit (self.packages.${system}) helix;
156153
157− clippy = craneLibMSRV.cargoClippy (commonArgs
154+ clippy = craneLib.cargoClippy (commonArgs
158155 // {
159156 inherit cargoArtifacts;
160157 cargoClippyExtraArgs = "--all-targets -- --deny warnings";
161158 });
162159
163− fmt = craneLibMSRV.cargoFmt commonArgs;
160+ fmt = craneLib.cargoFmt commonArgs;
164161
165− doc = craneLibMSRV.cargoDoc (commonArgs
162+ doc = craneLib.cargoDoc (commonArgs
166163 // {
167164 inherit cargoArtifacts;
168165 });
169166
170− test = craneLibMSRV.cargoTest (commonArgs
167+ test = craneLib.cargoTest (commonArgs
171168 // {
172169 inherit cargoArtifacts;
173170 });
grammars.nix+21−24
@@ -5,7 +5,6 @@
55 runCommand,
66 yj,
77 includeGrammarIf ? _: true,
8− grammarOverlays ? [],
98 ...
109}: let
1110 # HACK: nix < 2.6 has a bug in the toml parser, so we convert to JSON
@@ -49,22 +48,22 @@
4948 then sourceGitHub
5049 else sourceGit;
5150 in
52− stdenv.mkDerivation {
51+ stdenv.mkDerivation rec {
5352 # see https://github.com/NixOS/nixpkgs/blob/fbdd1a7c0bc29af5325e0d7dd70e804a972eb465/pkgs/development/tools/parsing/tree-sitter/grammar.nix
5453
5554 pname = "helix-tree-sitter-${grammar.name}";
5655 version = grammar.source.rev;
5756
58− src = source;
59− sourceRoot = if builtins.hasAttr "subpath" grammar.source then
60− "source/${grammar.source.subpath}"
61− else
62− "source";
57+ src =
58+ if builtins.hasAttr "subpath" grammar.source
59+ then "${source}/${grammar.source.subpath}"
60+ else source;
6361
62+ dontUnpack = true;
6463 dontConfigure = true;
6564
6665 FLAGS = [
67− "-Isrc"
66+ "-I${src}/src"
6867 "-g"
6968 "-O3"
7069 "-fPIC"
@@ -77,13 +76,13 @@
7776 buildPhase = ''
7877 runHook preBuild
7978
80− if [[ -e src/scanner.cc ]]; then
81− $CXX -c src/scanner.cc -o scanner.o $FLAGS
82− elif [[ -e src/scanner.c ]]; then
83− $CC -c src/scanner.c -o scanner.o $FLAGS
79+ if [[ -e "$src/src/scanner.cc" ]]; then
80+ $CXX -c "$src/src/scanner.cc" -o scanner.o $FLAGS
81+ elif [[ -e "$src/src/scanner.c" ]]; then
82+ $CC -c "$src/src/scanner.c" -o scanner.o $FLAGS
8483 fi
8584
86− $CC -c src/parser.c -o parser.o $FLAGS
85+ $CC -c "$src/src/parser.c" -o parser.o $FLAGS
8786 $CXX -shared -o $NAME.so *.o
8887
8988 ls -al
@@ -106,17 +105,15 @@
106105 '';
107106 };
108107 grammarsToBuild = builtins.filter includeGrammarIf gitGrammars;
109− builtGrammars = builtins.map (grammar: {
110− inherit (grammar) name;
111− value = buildGrammar grammar;
112− }) grammarsToBuild;
113− extensibleGrammars =
114− lib.makeExtensible (self: builtins.listToAttrs builtGrammars);
115− overlayedGrammars = lib.pipe extensibleGrammars
116− (builtins.map (overlay: grammar: grammar.extend overlay) grammarOverlays);
117− grammarLinks = lib.mapAttrsToList
118− (name: artifact: "ln -s ${artifact}/${name}.so $out/${name}.so")
119− (lib.filterAttrs (n: v: lib.isDerivation v) overlayedGrammars);
108+ builtGrammars =
109+ builtins.map (grammar: {
110+ inherit (grammar) name;
111+ artifact = buildGrammar grammar;
112+ })
113+ grammarsToBuild;
114+ grammarLinks =
115+ builtins.map (grammar: "ln -s ${grammar.artifact}/${grammar.name}.so $out/${grammar.name}.so")
116+ builtGrammars;
120117in
121118 runCommand "consolidated-helix-grammars" {} ''
122119 mkdir -p $out
helix-core/Cargo.toml+14−18
@@ -1,24 +1,23 @@
11[package]
22name = "helix-core"
3+version = "0.6.0"
4+authors = ["Blaž Hrastnik <blaz@mxxn.io>"]
5+edition = "2021"
6+license = "MPL-2.0"
37description = "Helix editor core editing primitives"
8+categories = ["editor"]
9+repository = "https://github.com/helix-editor/helix"
10+homepage = "https://helix-editor.com"
411include = ["src/**/*", "README.md"]
5−version.workspace = true
6−authors.workspace = true
7−edition.workspace = true
8−license.workspace = true
9−rust-version.workspace = true
10−categories.workspace = true
11−repository.workspace = true
12−homepage.workspace = true
1312
1413[features]
1514unicode-lines = ["ropey/unicode_lines"]
1615integration = []
1716
1817[dependencies]
19−helix-loader = { path = "../helix-loader" }
18+helix-loader = { version = "0.6", path = "../helix-loader" }
2019
21−ropey = { version = "1.6.1", default-features = false, features = ["simd"] }
20+ropey = { version = "1.6.0", default-features = false, features = ["simd"] }
2221smallvec = "1.11"
2322smartstring = "1.0.1"
2423unicode-segmentation = "1.10"
@@ -27,12 +26,12 @@ unicode-general-category = "0.6"
2726# slab = "0.4.2"
2827slotmap = "1.0"
2928tree-sitter.workspace = true
30−once_cell = "1.19"
29+once_cell = "1.18"
3130arc-swap = "1"
3231regex = "1"
33−bitflags = "2.4"
34−ahash = "0.8.6"
35−hashbrown = { version = "0.14.3", features = ["raw"] }
32+bitflags = "2.3"
33+ahash = "0.8.3"
34+hashbrown = { version = "0.14.0", features = ["raw"] }
3635dunce = "1.0"
3736
3837log = "0.4"
@@ -49,9 +48,6 @@ chrono = { version = "0.4", default-features = false, features = ["alloc", "std"
4948etcetera = "0.8"
5049textwrap = "0.16.0"
5150
52−nucleo.workspace = true
53−parking_lot = "0.12"
54−
5551[dev-dependencies]
5652quickcheck = { version = "1", default-features = false }
57−indoc = "2.0.4"
53+indoc = "2.0.3"
helix-core/src/diagnostic.rs−4
@@ -39,10 +39,6 @@ pub enum DiagnosticTag {
3939#[derive(Debug, Clone)]
4040pub struct Diagnostic {
4141 pub range: Range,
42− // whether this diagnostic ends at the end of(or inside) a word
43− pub ends_at_word: bool,
44− pub starts_at_word: bool,
45− pub zero_width: bool,
4642 pub line: usize,
4743 pub message: String,
4844 pub severity: Option<Severity>,
helix-core/src/fuzzy.rsdeleted−43
@@ -1,43 +0,0 @@
1−use std::ops::DerefMut;
2−
3−use nucleo::pattern::{Atom, AtomKind, CaseMatching};
4−use nucleo::Config;
5−use parking_lot::Mutex;
6−
7−pub struct LazyMutex<T> {
8− inner: Mutex<Option<T>>,
9− init: fn() -> T,
10−}
11−
12−impl<T> LazyMutex<T> {
13− pub const fn new(init: fn() -> T) -> Self {
14− Self {
15− inner: Mutex::new(None),
16− init,
17− }
18− }
19−
20− pub fn lock(&self) -> impl DerefMut<Target = T> + '_ {
21− parking_lot::MutexGuard::map(self.inner.lock(), |val| val.get_or_insert_with(self.init))
22− }
23−}
24−
25−pub static MATCHER: LazyMutex<nucleo::Matcher> = LazyMutex::new(nucleo::Matcher::default);
26−
27−/// convenience function to easily fuzzy match
28−/// on a (relatively small list of inputs). This is not recommended for building a full tui
29−/// application that can match large numbers of matches as all matching is done on the current
30−/// thread, effectively blocking the UI
31−pub fn fuzzy_match<T: AsRef<str>>(
32− pattern: &str,
33− items: impl IntoIterator<Item = T>,
34− path: bool,
35−) -> Vec<(T, u16)> {
36− let mut matcher = MATCHER.lock();
37− matcher.config = Config::DEFAULT;
38− if path {
39− matcher.config.set_match_paths();
40− }
41− let pattern = Atom::new(pattern, CaseMatching::Smart, AtomKind::Fuzzy, false);
42− pattern.match_list(items, &mut matcher)
43−}
helix-core/src/graphemes.rs+1−1
@@ -481,7 +481,7 @@ impl<'a> From<String> for GraphemeStr<'a> {
481481 let ptr = Box::into_raw(g.into_bytes().into_boxed_slice()) as *mut u8;
482482 GraphemeStr {
483483 ptr: unsafe { NonNull::new_unchecked(ptr) },
484− len: (i32::try_from(len).unwrap() as u32) | Self::MASK_OWNED,
484+ len: i32::try_from(len).unwrap() as u32,
485485 phantom: PhantomData,
486486 }
487487 }
helix-core/src/indent.rs+141−404
@@ -1,14 +1,13 @@
1−use std::{borrow::Cow, collections::HashMap};
1+use std::collections::HashMap;
22
33use tree_sitter::{Query, QueryCursor, QueryPredicateArg};
44
55use crate::{
66 chars::{char_is_line_ending, char_is_whitespace},
7− find_first_non_whitespace_char,
8− graphemes::{grapheme_width, tab_width_at},
9− syntax::{IndentationHeuristic, LanguageConfiguration, RopeProvider, Syntax},
7+ graphemes::tab_width_at,
8+ syntax::{LanguageConfiguration, RopeProvider, Syntax},
109 tree_sitter::Node,
11− Position, Rope, RopeGraphemes, RopeSlice,
10+ Rope, RopeSlice,
1211};
1312
1413/// Enum representing indentation style.
@@ -22,7 +21,7 @@ pub enum IndentStyle {
2221
2322// 16 spaces
2423const INDENTS: &str = " ";
25−pub const MAX_INDENT: u8 = 16;
24+const MAX_INDENT: u8 = 16;
2625
2726impl IndentStyle {
2827 /// Creates an `IndentStyle` from an indentation string.
@@ -197,56 +196,6 @@ pub fn indent_level_for_line(line: RopeSlice, tab_width: usize, indent_width: us
197196 len / indent_width
198197}
199198
200−/// Create a string of tabs & spaces that has the same visual width as the given RopeSlice (independent of the tab width).
201−fn whitespace_with_same_width(text: RopeSlice) -> String {
202− let mut s = String::new();
203− for grapheme in RopeGraphemes::new(text) {
204− if grapheme == "\t" {
205− s.push('\t');
206− } else {
207− s.extend(std::iter::repeat(' ').take(grapheme_width(&Cow::from(grapheme))));
208− }
209− }
210− s
211−}
212−
213−fn add_indent_level(
214− mut base_indent: String,
215− added_indent_level: isize,
216− indent_style: &IndentStyle,
217− tab_width: usize,
218−) -> String {
219− if added_indent_level >= 0 {
220− // Adding a non-negative indent is easy, we can simply append the indent string
221− base_indent.push_str(&indent_style.as_str().repeat(added_indent_level as usize));
222− base_indent
223− } else {
224− // In this case, we want to return a prefix of `base_indent`.
225− // Since the width of a tab depends on its offset, we cannot simply iterate over
226− // the chars of `base_indent` in reverse until we have the desired indent reduction,
227− // instead we iterate over them twice in forward direction.
228− let base_indent_rope = RopeSlice::from(base_indent.as_str());
229− #[allow(deprecated)]
230− let base_indent_width =
231− crate::visual_coords_at_pos(base_indent_rope, base_indent_rope.len_chars(), tab_width)
232− .col;
233− let target_indent_width = base_indent_width
234− .saturating_sub((-added_indent_level) as usize * indent_style.indent_width(tab_width));
235− #[allow(deprecated)]
236− let char_end_idx = crate::pos_at_visual_coords(
237− base_indent_rope,
238− Position {
239− row: 0,
240− col: target_indent_width,
241− },
242− tab_width,
243− );
244− let byte_end_idx = base_indent_rope.char_to_byte(char_end_idx);
245− base_indent.truncate(byte_end_idx);
246− base_indent
247− }
248−}
249−
250199/// Computes for node and all ancestors whether they are the first node on their line.
251200/// The first entry in the return value represents the root node, the last one the node itself
252201fn get_first_in_line(mut node: Node, new_line_byte_pos: Option<usize>) -> Vec<bool> {
@@ -288,33 +237,19 @@ fn get_first_in_line(mut node: Node, new_line_byte_pos: Option<usize>) -> Vec<bo
288237/// This is usually constructed in one of 2 ways:
289238/// - Successively add indent captures to get the (added) indent from a single line
290239/// - Successively add the indent results for each line
291−/// The string that this indentation defines starts with the string contained in the align field (unless it is None), followed by:
292−/// - max(0, indent - outdent) tabs, if tabs are used for indentation
293−/// - max(0, indent - outdent)*indent_width spaces, if spaces are used for indentation
294240#[derive(Default, Debug, PartialEq, Eq, Clone)]
295−pub struct Indentation<'a> {
241+pub struct Indentation {
242+ /// The total indent (the number of indent levels) is defined as max(0, indent-outdent).
243+ /// The string that this results in depends on the indent style (spaces or tabs, etc.)
296244 indent: usize,
297245 indent_always: usize,
298246 outdent: usize,
299247 outdent_always: usize,
300− /// The alignment, as a string containing only tabs & spaces. Storing this as a string instead of e.g.
301− /// the (visual) width ensures that the alignment is preserved even if the tab width changes.
302− align: Option<RopeSlice<'a>>,
303248}
304−
305−impl<'a> Indentation<'a> {
249+impl Indentation {
306250 /// Add some other [Indentation] to this.
307− /// The added indent should be the total added indent from one line.
308− /// Indent should always be added starting from the bottom (or equivalently, the innermost tree-sitter node).
309− fn add_line(&mut self, added: Indentation<'a>) {
310− // Align overrides the indent from outer scopes.
311− if self.align.is_some() {
312− return;
313− }
314− if added.align.is_some() {
315− self.align = added.align;
316− return;
317− }
251+ /// The added indent should be the total added indent from one line
252+ fn add_line(&mut self, added: &Indentation) {
318253 self.indent += added.indent;
319254 self.indent_always += added.indent_always;
320255 self.outdent += added.outdent;
@@ -322,10 +257,8 @@ impl<'a> Indentation<'a> {
322257 }
323258
324259 /// Add an indent capture to this indent.
325− /// Only captures that apply to the same line should be added together in this way (otherwise use `add_line`)
326− /// and the captures should be added starting from the innermost tree-sitter node (currently this only matters
327− /// if multiple `@align` patterns occur on the same line).
328− fn add_capture(&mut self, added: IndentCaptureType<'a>) {
260+ /// All the captures that are added in this way should be on the same line.
261+ fn add_capture(&mut self, added: IndentCaptureType) {
329262 match added {
330263 IndentCaptureType::Indent => {
331264 if self.indent_always == 0 {
@@ -347,74 +280,43 @@ impl<'a> Indentation<'a> {
347280 self.outdent_always += 1;
348281 self.outdent = 0;
349282 }
350− IndentCaptureType::Align(align) => {
351− if self.align.is_none() {
352− self.align = Some(align);
353− }
354− }
355283 }
356284 }
357− fn net_indent(&self) -> isize {
358− (self.indent + self.indent_always) as isize
359− - ((self.outdent + self.outdent_always) as isize)
360− }
361− /// Convert `self` into a string, taking into account the computed and actual indentation of some other line.
362− fn relative_indent(
363− &self,
364− other_computed_indent: &Self,
365− other_leading_whitespace: RopeSlice,
366− indent_style: &IndentStyle,
367− tab_width: usize,
368− ) -> Option<String> {
369− if self.align == other_computed_indent.align {
370− // If self and baseline are either not aligned to anything or both aligned the same way,
371− // we can simply take `other_leading_whitespace` and add some indent / outdent to it (in the second
372− // case, the alignment should already be accounted for in `other_leading_whitespace`).
373− let indent_diff = self.net_indent() - other_computed_indent.net_indent();
374− Some(add_indent_level(
375− String::from(other_leading_whitespace),
376− indent_diff,
377− indent_style,
378− tab_width,
379− ))
285+
286+ fn as_string(&self, indent_style: &IndentStyle) -> String {
287+ let indent = self.indent_always + self.indent;
288+ let outdent = self.outdent_always + self.outdent;
289+
290+ let indent_level = if indent >= outdent {
291+ indent - outdent
380292 } else {
381− // If the alignment of both lines is different, we cannot compare their indentation in any meaningful way
382− None
383− }
384− }
385− pub fn to_string(&self, indent_style: &IndentStyle, tab_width: usize) -> String {
386− add_indent_level(
387− self.align
388− .map_or_else(String::new, whitespace_with_same_width),
389− self.net_indent(),
390− indent_style,
391− tab_width,
392− )
293+ log::warn!("Encountered more outdent than indent nodes while calculating indentation: {} outdent, {} indent", self.outdent, self.indent);
294+ 0
295+ };
296+ indent_style.as_str().repeat(indent_level)
393297 }
394298}
395299
396300/// An indent definition which corresponds to a capture from the indent query
397301#[derive(Debug)]
398−struct IndentCapture<'a> {
399− capture_type: IndentCaptureType<'a>,
302+struct IndentCapture {
303+ capture_type: IndentCaptureType,
400304 scope: IndentScope,
401305}
402−#[derive(Debug, Clone, PartialEq)]
403−enum IndentCaptureType<'a> {
306+
307+#[derive(Debug, Clone, Copy, PartialEq)]
308+enum IndentCaptureType {
404309 Indent,
405310 IndentAlways,
406311 Outdent,
407312 OutdentAlways,
408− /// Alignment given as a string of whitespace
409− Align(RopeSlice<'a>),
410313}
411314
412−impl<'a> IndentCaptureType<'a> {
315+impl IndentCaptureType {
413316 fn default_scope(&self) -> IndentScope {
414317 match self {
415318 IndentCaptureType::Indent | IndentCaptureType::IndentAlways => IndentScope::Tail,
416319 IndentCaptureType::Outdent | IndentCaptureType::OutdentAlways => IndentScope::All,
417− IndentCaptureType::Align(_) => IndentScope::All,
418320 }
419321 }
420322}
@@ -441,40 +343,51 @@ enum ExtendCapture {
441343/// each node (identified by its ID) the relevant captures (already filtered
442344/// by predicates).
443345#[derive(Debug)]
444−struct IndentQueryResult<'a> {
445− indent_captures: HashMap<usize, Vec<IndentCapture<'a>>>,
346+struct IndentQueryResult {
347+ indent_captures: HashMap<usize, Vec<IndentCapture>>,
446348 extend_captures: HashMap<usize, Vec<ExtendCapture>>,
447349}
448350
449−fn get_node_start_line(node: Node, new_line_byte_pos: Option<usize>) -> usize {
450− let mut node_line = node.start_position().row;
451− // Adjust for the new line that will be inserted
452− if new_line_byte_pos.map_or(false, |pos| node.start_byte() >= pos) {
453− node_line += 1;
454− }
455− node_line
456−}
457−fn get_node_end_line(node: Node, new_line_byte_pos: Option<usize>) -> usize {
458− let mut node_line = node.end_position().row;
459− // Adjust for the new line that will be inserted (with a strict inequality since end_byte is exclusive)
460− if new_line_byte_pos.map_or(false, |pos| node.end_byte() > pos) {
461− node_line += 1;
462− }
463− node_line
464−}
465−
466−fn query_indents<'a>(
351+fn query_indents(
467352 query: &Query,
468353 syntax: &Syntax,
469354 cursor: &mut QueryCursor,
470− text: RopeSlice<'a>,
355+ text: RopeSlice,
471356 range: std::ops::Range<usize>,
472− new_line_byte_pos: Option<usize>,
473−) -> IndentQueryResult<'a> {
357+ // Position of the (optional) newly inserted line break.
358+ // Given as (line, byte_pos)
359+ new_line_break: Option<(usize, usize)>,
360+) -> IndentQueryResult {
474361 let mut indent_captures: HashMap<usize, Vec<IndentCapture>> = HashMap::new();
475362 let mut extend_captures: HashMap<usize, Vec<ExtendCapture>> = HashMap::new();
476363 cursor.set_byte_range(range);
477364
365+ let get_node_start_line = |node: Node| {
366+ let mut node_line = node.start_position().row;
367+
368+ // Adjust for the new line that will be inserted
369+ if let Some((line, byte)) = new_line_break {
370+ if node_line == line && node.start_byte() >= byte {
371+ node_line += 1;
372+ }
373+ }
374+
375+ node_line
376+ };
377+
378+ let get_node_end_line = |node: Node| {
379+ let mut node_line = node.end_position().row;
380+
381+ // Adjust for the new line that will be inserted
382+ if let Some((line, byte)) = new_line_break {
383+ if node_line == line && node.end_byte() < byte {
384+ node_line += 1;
385+ }
386+ }
387+
388+ node_line
389+ };
390+
478391 // Iterate over all captures from the query
479392 for m in cursor.matches(query, syntax.tree().root_node(), RopeProvider(text)) {
480393 // Skip matches where not all custom predicates are fulfilled
@@ -505,8 +418,8 @@ fn query_indents<'a>(
505418 let n2 = m.nodes_for_capture_index(*capt2).next();
506419 match (n1, n2) {
507420 (Some(n1), Some(n2)) => {
508− let n1_line = get_node_start_line(n1, new_line_byte_pos);
509− let n2_line = get_node_start_line(n2, new_line_byte_pos);
421+ let n1_line = get_node_start_line(n1);
422+ let n2_line = get_node_start_line(n2);
510423 let same_line = n1_line == n2_line;
511424 same_line==(pred.operator.as_ref()=="same-line?")
512425 }
@@ -524,7 +437,7 @@ fn query_indents<'a>(
524437
525438 match node {
526439 Some(node) => {
527− let (start_line, end_line) = (get_node_start_line(node,new_line_byte_pos), get_node_end_line(node, new_line_byte_pos));
440+ let (start_line, end_line) = (get_node_start_line(node), get_node_end_line(node));
528441 let one_line = end_line == start_line;
529442 one_line != (pred.operator.as_ref() == "not-one-line?")
530443 },
@@ -545,11 +458,6 @@ fn query_indents<'a>(
545458 }) {
546459 continue;
547460 }
548− // A list of pairs (node_id, indent_capture) that are added by this match.
549− // They cannot be added to indent_captures immediately since they may depend on other captures (such as an @anchor).
550− let mut added_indent_captures: Vec<(usize, IndentCapture)> = Vec::new();
551− // The row/column position of the optional anchor in this query
552− let mut anchor: Option<tree_sitter::Node> = None;
553461 for capture in m.captures {
554462 let capture_name = query.capture_names()[capture.index as usize].as_str();
555463 let capture_type = match capture_name {
@@ -557,16 +465,6 @@ fn query_indents<'a>(
557465 "indent.always" => IndentCaptureType::IndentAlways,
558466 "outdent" => IndentCaptureType::Outdent,
559467 "outdent.always" => IndentCaptureType::OutdentAlways,
560− // The alignment will be updated to the correct value at the end, when the anchor is known.
561− "align" => IndentCaptureType::Align(RopeSlice::from("")),
562− "anchor" => {
563− if anchor.is_some() {
564− log::error!("Invalid indent query: Encountered more than one @anchor in the same match.")
565− } else {
566− anchor = Some(capture.node);
567− }
568− continue;
569− }
570468 "extend" => {
571469 extend_captures
572470 .entry(capture.node.id())
@@ -616,29 +514,11 @@ fn query_indents<'a>(
616514 }
617515 }
618516 }
619− added_indent_captures.push((capture.node.id(), indent_capture))
620− }
621− for (node_id, mut capture) in added_indent_captures {
622− // Set the anchor for all align queries.
623− if let IndentCaptureType::Align(_) = capture.capture_type {
624− let anchor = match anchor {
625− None => {
626− log::error!(
627− "Invalid indent query: @align requires an accompanying @anchor."
628− );
629− continue;
630− }
631− Some(anchor) => anchor,
632− };
633− capture.capture_type = IndentCaptureType::Align(
634− text.line(anchor.start_position().row)
635− .byte_slice(0..anchor.start_position().column),
636− );
637− }
638517 indent_captures
639− .entry(node_id)
518+ .entry(capture.node.id())
519+ // Most entries only need to contain a single IndentCapture
640520 .or_insert_with(|| Vec::with_capacity(1))
641− .push(capture);
521+ .push(indent_capture);
642522 }
643523 }
644524
@@ -719,20 +599,55 @@ fn extend_nodes<'a>(
719599 }
720600}
721601
722−/// Prepare an indent query by computing:
723−/// - The node from which to start the query (this is non-trivial due to `@extend` captures)
724−/// - The indent captures for all relevant nodes.
602+/// Use the syntax tree to determine the indentation for a given position.
603+/// This can be used in 2 ways:
604+///
605+/// - To get the correct indentation for an existing line (new_line=false), not necessarily equal to the current indentation.
606+/// - In this case, pos should be inside the first tree-sitter node on that line.
607+/// In most cases, this can just be the first non-whitespace on that line.
608+/// - To get the indentation for a new line (new_line=true). This behaves like the first usecase if the part of the current line
609+/// after pos were moved to a new line.
610+///
611+/// The indentation is determined by traversing all the tree-sitter nodes containing the position.
612+/// Each of these nodes produces some [Indentation] for:
613+///
614+/// - The line of the (beginning of the) node. This is defined by the scope `all` if this is the first node on its line.
615+/// - The line after the node. This is defined by:
616+/// - The scope `tail`.
617+/// - The scope `all` if this node is not the first node on its line.
618+/// Intuitively, `all` applies to everything contained in this node while `tail` applies to everything except for the first line of the node.
619+/// The indents from different nodes for the same line are then combined.
620+/// The result [Indentation] is simply the sum of the [Indentation] for all lines.
621+///
622+/// Specifying which line exactly an [Indentation] applies to is important because indents on the same line combine differently than indents on different lines:
623+/// ```ignore
624+/// some_function(|| {
625+/// // Both the function parameters as well as the contained block should be indented.
626+/// // Because they are on the same line, this only yields one indent level
627+/// });
628+/// ```
629+///
630+/// ```ignore
631+/// some_function(
632+/// param1,
633+/// || {
634+/// // Here we get 2 indent levels because the 'parameters' and the 'block' node begin on different lines
635+/// },
636+/// );
637+/// ```
725638#[allow(clippy::too_many_arguments)]
726−fn init_indent_query<'a, 'b>(
639+pub fn treesitter_indent_for_pos(
727640 query: &Query,
728− syntax: &'a Syntax,
729− text: RopeSlice<'b>,
641+ syntax: &Syntax,
642+ indent_style: &IndentStyle,
730643 tab_width: usize,
731644 indent_width: usize,
645+ text: RopeSlice,
732646 line: usize,
733− byte_pos: usize,
734− new_line_byte_pos: Option<usize>,
735−) -> Option<(Node<'a>, HashMap<usize, Vec<IndentCapture<'b>>>)> {
647+ pos: usize,
648+ new_line: bool,
649+) -> Option<String> {
650+ let byte_pos = text.char_to_byte(pos);
736651 // The innermost tree-sitter node which is considered for the indent
737652 // computation. It may change if some predeceding node is extended
738653 let mut node = syntax
@@ -770,12 +685,13 @@ fn init_indent_query<'a, 'b>(
770685 &mut cursor,
771686 text,
772687 query_range,
773− new_line_byte_pos,
688+ new_line.then_some((line, byte_pos)),
774689 );
775690 ts_parser.cursors.push(cursor);
776691 (query_result, deepest_preceding)
777692 })
778693 };
694+ let indent_captures = query_result.indent_captures;
779695 let extend_captures = query_result.extend_captures;
780696
781697 // Check for extend captures, potentially changing the node that the indent calculation starts with
@@ -790,68 +706,6 @@ fn init_indent_query<'a, 'b>(
790706 indent_width,
791707 );
792708 }
793− Some((node, query_result.indent_captures))
794−}
795−
796−/// Use the syntax tree to determine the indentation for a given position.
797−/// This can be used in 2 ways:
798−///
799−/// - To get the correct indentation for an existing line (new_line=false), not necessarily equal to the current indentation.
800−/// - In this case, pos should be inside the first tree-sitter node on that line.
801−/// In most cases, this can just be the first non-whitespace on that line.
802−/// - To get the indentation for a new line (new_line=true). This behaves like the first usecase if the part of the current line
803−/// after pos were moved to a new line.
804−///
805−/// The indentation is determined by traversing all the tree-sitter nodes containing the position.
806−/// Each of these nodes produces some [Indentation] for:
807−///
808−/// - The line of the (beginning of the) node. This is defined by the scope `all` if this is the first node on its line.
809−/// - The line after the node. This is defined by:
810−/// - The scope `tail`.
811−/// - The scope `all` if this node is not the first node on its line.
812−/// Intuitively, `all` applies to everything contained in this node while `tail` applies to everything except for the first line of the node.
813−/// The indents from different nodes for the same line are then combined.
814−/// The result [Indentation] is simply the sum of the [Indentation] for all lines.
815−///
816−/// Specifying which line exactly an [Indentation] applies to is important because indents on the same line combine differently than indents on different lines:
817−/// ```ignore
818−/// some_function(|| {
819−/// // Both the function parameters as well as the contained block should be indented.
820−/// // Because they are on the same line, this only yields one indent level
821−/// });
822−/// ```
823−///
824−/// ```ignore
825−/// some_function(
826−/// param1,
827−/// || {
828−/// // Here we get 2 indent levels because the 'parameters' and the 'block' node begin on different lines
829−/// },
830−/// );
831−/// ```
832−#[allow(clippy::too_many_arguments)]
833−pub fn treesitter_indent_for_pos<'a>(
834− query: &Query,
835− syntax: &Syntax,
836− tab_width: usize,
837− indent_width: usize,
838− text: RopeSlice<'a>,
839− line: usize,
840− pos: usize,
841− new_line: bool,
842−) -> Option<Indentation<'a>> {
843− let byte_pos = text.char_to_byte(pos);
844− let new_line_byte_pos = new_line.then_some(byte_pos);
845− let (mut node, mut indent_captures) = init_indent_query(
846− query,
847− syntax,
848− text,
849− tab_width,
850− indent_width,
851− line,
852− byte_pos,
853− new_line_byte_pos,
854− )?;
855709 let mut first_in_line = get_first_in_line(node, new_line.then_some(byte_pos));
856710
857711 let mut result = Indentation::default();
@@ -865,10 +719,8 @@ pub fn treesitter_indent_for_pos<'a>(
865719 // one entry for each ancestor of the node (which is what we iterate over)
866720 let is_first = *first_in_line.last().unwrap();
867721
868− // Apply all indent definitions for this node.
869− // Since we only iterate over each node once, we can remove the
870− // corresponding captures from the HashMap to avoid cloning them.
871− if let Some(definitions) = indent_captures.remove(&node.id()) {
722+ // Apply all indent definitions for this node
723+ if let Some(definitions) = indent_captures.get(&node.id()) {
872724 for definition in definitions {
873725 match definition.scope {
874726 IndentScope::All => {
@@ -886,19 +738,29 @@ pub fn treesitter_indent_for_pos<'a>(
886738 }
887739
888740 if let Some(parent) = node.parent() {
889− let node_line = get_node_start_line(node, new_line_byte_pos);
890− let parent_line = get_node_start_line(parent, new_line_byte_pos);
741+ let mut node_line = node.start_position().row;
742+ let mut parent_line = parent.start_position().row;
743+
744+ if node_line == line && new_line {
745+ // Also consider the line that will be inserted
746+ if node.start_byte() >= byte_pos {
747+ node_line += 1;
748+ }
749+ if parent.start_byte() >= byte_pos {
750+ parent_line += 1;
751+ }
752+ };
891753
892754 if node_line != parent_line {
893755 // Don't add indent for the line below the line of the query
894756 if node_line < line + (new_line as usize) {
895− result.add_line(indent_for_line_below);
757+ result.add_line(&indent_for_line_below);
896758 }
897759
898760 if node_line == parent_line + 1 {
899761 indent_for_line_below = indent_for_line;
900762 } else {
901− result.add_line(indent_for_line);
763+ result.add_line(&indent_for_line);
902764 indent_for_line_below = Indentation::default();
903765 }
904766
@@ -913,13 +775,14 @@ pub fn treesitter_indent_for_pos<'a>(
913775 if (node.start_position().row < line)
914776 || (new_line && node.start_position().row == line && node.start_byte() < byte_pos)
915777 {
916− result.add_line(indent_for_line_below);
778+ result.add_line(&indent_for_line_below);
917779 }
918− result.add_line(indent_for_line);
780+
781+ result.add_line(&indent_for_line);
919782 break;
920783 }
921784 }
922− Some(result)
785+ Some(result.as_string(indent_style))
923786}
924787
925788/// Returns the indentation for a new line.
@@ -928,7 +791,6 @@ pub fn treesitter_indent_for_pos<'a>(
928791pub fn indent_for_newline(
929792 language_config: Option<&LanguageConfiguration>,
930793 syntax: Option<&Syntax>,
931− indent_heuristic: &IndentationHeuristic,
932794 indent_style: &IndentStyle,
933795 tab_width: usize,
934796 text: RopeSlice,
@@ -937,18 +799,14 @@ pub fn indent_for_newline(
937799 current_line: usize,
938800) -> String {
939801 let indent_width = indent_style.indent_width(tab_width);
940− if let (
941− IndentationHeuristic::TreeSitter | IndentationHeuristic::Hybrid,
942− Some(query),
943− Some(syntax),
944− ) = (
945− indent_heuristic,
802+ if let (Some(query), Some(syntax)) = (
946803 language_config.and_then(|config| config.indent_query()),
947804 syntax,
948805 ) {
949806 if let Some(indent) = treesitter_indent_for_pos(
950807 query,
951808 syntax,
809+ indent_style,
952810 tab_width,
953811 indent_width,
954812 text,
@@ -956,57 +814,9 @@ pub fn indent_for_newline(
956814 line_before_end_pos,
957815 true,
958816 ) {
959− if *indent_heuristic == IndentationHeuristic::Hybrid {
960− // We want to compute the indentation not only based on the
961− // syntax tree but also on the actual indentation of a previous
962− // line. This makes indentation computation more resilient to
963− // incomplete queries, incomplete source code & differing indentation
964− // styles for the same language.
965− // However, using the indent of a previous line as a baseline may not
966− // make sense, e.g. if it has a different alignment than the new line.
967− // In order to prevent edge cases with long running times, we only try
968− // a constant number of (non-empty) lines.
969− const MAX_ATTEMPTS: usize = 4;
970− let mut num_attempts = 0;
971− for line_idx in (0..=line_before).rev() {
972− let line = text.line(line_idx);
973− let first_non_whitespace_char = match find_first_non_whitespace_char(line) {
974− Some(i) => i,
975− None => {
976− continue;
977− }
978− };
979− if let Some(indent) = (|| {
980− let computed_indent = treesitter_indent_for_pos(
981− query,
982− syntax,
983− tab_width,
984− indent_width,
985− text,
986− line_idx,
987− text.line_to_char(line_idx) + first_non_whitespace_char,
988− false,
989− )?;
990− let leading_whitespace = line.slice(0..first_non_whitespace_char);
991− indent.relative_indent(
992− &computed_indent,
993− leading_whitespace,
994− indent_style,
995− tab_width,
996− )
997− })() {
998− return indent;
999− }
1000− num_attempts += 1;
1001− if num_attempts == MAX_ATTEMPTS {
1002− break;
1003− }
1004− }
1005− }
1006− return indent.to_string(indent_style, tab_width);
817+ return indent;
1007818 };
1008819 }
1009− // Fallback in case we either don't have indent queries or they failed for some reason
1010820 let indent_level = indent_level_for_line(text.line(current_line), tab_width, indent_width);
1011821 indent_style.as_str().repeat(indent_level)
1012822}
@@ -1098,13 +908,10 @@ mod test {
1098908 ..Default::default()
1099909 };
1100910
1101− fn add_capture<'a>(
1102− mut indent: Indentation<'a>,
1103− capture: IndentCaptureType<'a>,
1104− ) -> Indentation<'a> {
911+ let add_capture = |mut indent: Indentation, capture| {
1105912 indent.add_capture(capture);
1106913 indent
1107− }
914+ };
1108915
1109916 // adding an indent to no indent makes an indent
1110917 assert_eq!(
@@ -1199,74 +1006,4 @@ mod test {
11991006 )
12001007 );
12011008 }
1202−
1203− #[test]
1204− fn test_relative_indent() {
1205− let indent_style = IndentStyle::Spaces(4);
1206− let tab_width: usize = 4;
1207− let no_align = [
1208− Indentation::default(),
1209− Indentation {
1210− indent: 1,
1211− ..Default::default()
1212− },
1213− Indentation {
1214− indent: 5,
1215− outdent: 1,
1216− ..Default::default()
1217− },
1218− ];
1219− let align = no_align.clone().map(|indent| Indentation {
1220− align: Some(RopeSlice::from("12345")),
1221− ..indent
1222− });
1223− let different_align = Indentation {
1224− align: Some(RopeSlice::from("123456")),
1225− ..Default::default()
1226− };
1227−
1228− // Check that relative and absolute indentation computation are the same when the line we compare to is
1229− // indented as we expect.
1230− let check_consistency = |indent: &Indentation, other: &Indentation| {
1231− assert_eq!(
1232− indent.relative_indent(
1233− other,
1234− RopeSlice::from(other.to_string(&indent_style, tab_width).as_str()),
1235− &indent_style,
1236− tab_width
1237− ),
1238− Some(indent.to_string(&indent_style, tab_width))
1239− );
1240− };
1241− for a in &no_align {
1242− for b in &no_align {
1243− check_consistency(a, b);
1244− }
1245− }
1246− for a in &align {
1247− for b in &align {
1248− check_consistency(a, b);
1249− }
1250− }
1251−
1252− // Relative indent computation makes no sense if the alignment differs
1253− assert_eq!(
1254− align[0].relative_indent(
1255− &no_align[0],
1256− RopeSlice::from(" "),
1257− &indent_style,
1258− tab_width
1259− ),
1260− None
1261− );
1262− assert_eq!(
1263− align[0].relative_indent(
1264− &different_align,
1265− RopeSlice::from(" "),
1266− &indent_style,
1267− tab_width
1268− ),
1269− None
1270− );
1271− }
12721009}
helix-core/src/lib.rs−1
@@ -7,7 +7,6 @@ pub mod config;
77pub mod diagnostic;
88pub mod diff;
99pub mod doc_formatter;
10−pub mod fuzzy;
1110pub mod graphemes;
1211pub mod history;
1312pub mod increment;
helix-core/src/path.rs+2−2
@@ -85,7 +85,7 @@ pub fn get_normalized_path(path: &Path) -> PathBuf {
8585///
8686/// This function is used instead of `std::fs::canonicalize` because we don't want to verify
8787/// here if the path exists, just normalize it's components.
88−pub fn get_canonicalized_path(path: &Path) -> PathBuf {
88+pub fn get_canonicalized_path(path: &Path) -> std::io::Result<PathBuf> {
8989 let path = expand_tilde(path);
9090 let path = if path.is_relative() {
9191 helix_loader::current_working_dir().join(path)
@@ -93,7 +93,7 @@ pub fn get_canonicalized_path(path: &Path) -> PathBuf {
9393 path
9494 };
9595
96− get_normalized_path(path.as_path())
96+ Ok(get_normalized_path(path.as_path()))
9797}
9898
9999pub fn get_relative_path(path: &Path) -> PathBuf {
helix-core/src/syntax.rs+8−24
@@ -101,8 +101,7 @@ pub struct LanguageConfiguration {
101101 pub file_types: Vec<FileType>, // filename extension or ends_with? <Gemfile, rb, etc>
102102 #[serde(default)]
103103 pub shebangs: Vec<String>, // interpreter(s) associated with language
104− #[serde(default)]
105− pub roots: Vec<String>, // these indicate project roots <.git, Cargo.toml>
104+ pub roots: Vec<String>, // these indicate project roots <.git, Cargo.toml>
106105 pub comment_token: Option<String>,
107106 pub text_width: Option<usize>,
108107 pub soft_wrap: Option<SoftWrap>,
@@ -155,8 +154,6 @@ pub struct LanguageConfiguration {
155154 /// Hardcoded LSP root directories relative to the workspace root, like `examples` or `tools/fuzz`.
156155 /// Falling back to the current working directory if none are configured.
157156 pub workspace_lsp_roots: Option<Vec<PathBuf>>,
158− #[serde(default)]
159− pub persistent_diagnostic_sources: Vec<String>,
160157}
161158
162159#[derive(Debug, PartialEq, Eq, Hash)]
@@ -214,7 +211,10 @@ impl<'de> Deserialize<'de> for FileType {
214211 {
215212 match map.next_entry::<String, String>()? {
216213 Some((key, suffix)) if key == "suffix" => Ok(FileType::Suffix({
217− suffix.replace('/', std::path::MAIN_SEPARATOR_STR)
214+ // FIXME: use `suffix.replace('/', std::path::MAIN_SEPARATOR_STR)`
215+ // if MSRV is updated to 1.68
216+ let mut separator = [0; 1];
217+ suffix.replace('/', std::path::MAIN_SEPARATOR.encode_utf8(&mut separator))
218218 })),
219219 Some((key, _value)) => Err(serde::de::Error::custom(format!(
220220 "unknown key in `file-types` list: {}",
@@ -444,22 +444,6 @@ pub struct IndentationConfiguration {
444444 pub unit: String,
445445}
446446
447−/// How the indentation for a newly inserted line should be determined.
448−/// If the selected heuristic is not available (e.g. because the current
449−/// language has no tree-sitter indent queries), a simpler one will be used.
450−#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
451−#[serde(rename_all = "kebab-case")]
452−pub enum IndentationHeuristic {
453− /// Just copy the indentation of the line that the cursor is currently on.
454− Simple,
455− /// Use tree-sitter indent queries to compute the expected absolute indentation level of the new line.
456− TreeSitter,
457− /// Use tree-sitter indent queries to compute the expected difference in indentation between the new line
458− /// and the line before. Add this to the actual indentation level of the line before.
459− #[default]
460− Hybrid,
461−}
462−
463447/// Configuration for auto pairs
464448#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
465449#[serde(rename_all = "kebab-case", deny_unknown_fields, untagged)]
@@ -978,7 +962,7 @@ impl Syntax {
978962 let res = syntax.update(source, source, &ChangeSet::new(source));
979963
980964 if res.is_err() {
981− log::error!("TS parser failed, disabling TS for the current buffer: {res:?}");
965+ log::error!("TS parser failed, disabeling TS for the current buffer: {res:?}");
982966 return None;
983967 }
984968 Some(syntax)
@@ -1630,7 +1614,7 @@ impl<'a> Iterator for ChunksBytes<'a> {
16301614}
16311615
16321616pub struct RopeProvider<'a>(pub RopeSlice<'a>);
1633−impl<'a> TextProvider<&'a [u8]> for RopeProvider<'a> {
1617+impl<'a> TextProvider<'a> for RopeProvider<'a> {
16341618 type I = ChunksBytes<'a>;
16351619
16361620 fn text(&mut self, node: Node) -> Self::I {
@@ -1644,7 +1628,7 @@ impl<'a> TextProvider<&'a [u8]> for RopeProvider<'a> {
16441628struct HighlightIterLayer<'a> {
16451629 _tree: Option<Tree>,
16461630 cursor: QueryCursor,
1647− captures: RefCell<iter::Peekable<QueryCaptures<'a, 'a, RopeProvider<'a>, &'a [u8]>>>,
1631+ captures: RefCell<iter::Peekable<QueryCaptures<'a, 'a, RopeProvider<'a>>>>,
16481632 config: &'a HighlightConfiguration,
16491633 highlight_end_stack: Vec<usize>,
16501634 scope_stack: Vec<LocalScope<'a>>,
helix-core/src/transaction.rs+14−73
@@ -1,7 +1,7 @@
11use ropey::RopeSlice;
22use smallvec::SmallVec;
33
4−use crate::{chars::char_is_word, Range, Rope, Selection, Tendril};
4+use crate::{Range, Rope, Selection, Tendril};
55use std::{borrow::Cow, iter::once};
66
77/// (from, to, replacement)
@@ -23,30 +23,6 @@ pub enum Operation {
2323pub enum Assoc {
2424 Before,
2525 After,
26− /// Acts like `After` if a word character is inserted
27− /// after the position, otherwise acts like `Before`
28− AfterWord,
29− /// Acts like `Before` if a word character is inserted
30− /// before the position, otherwise acts like `After`
31− BeforeWord,
32−}
33−
34−impl Assoc {
35− /// Whether to stick to gaps
36− fn stay_at_gaps(self) -> bool {
37− !matches!(self, Self::BeforeWord | Self::AfterWord)
38− }
39−
40− fn insert_offset(self, s: &str) -> usize {
41− let chars = s.chars().count();
42− match self {
43− Assoc::After => chars,
44− Assoc::AfterWord => s.chars().take_while(|&c| char_is_word(c)).count(),
45− // return position before inserted text
46− Assoc::Before => 0,
47− Assoc::BeforeWord => chars - s.chars().rev().take_while(|&c| char_is_word(c)).count(),
48− }
49− }
5026}
5127
5228#[derive(Debug, Default, Clone, PartialEq, Eq)]
@@ -439,6 +415,8 @@ impl ChangeSet {
439415 map!(|pos, _| (old_end > pos).then_some(new_pos), i);
440416 }
441417 Insert(s) => {
418+ let ins = s.chars().count();
419+
442420 // a subsequent delete means a replace, consume it
443421 if let Some((_, Delete(len))) = iter.peek() {
444422 iter.next();
@@ -446,13 +424,13 @@ impl ChangeSet {
446424 old_end = old_pos + len;
447425 // in range of replaced text
448426 map!(
449− |pos, assoc: Assoc| (old_end > pos).then(|| {
427+ |pos, assoc| (old_end > pos).then(|| {
450428 // at point or tracking before
451− if pos == old_pos && assoc.stay_at_gaps() {
429+ if pos == old_pos || assoc == Assoc::Before {
452430 new_pos
453431 } else {
454432 // place to end of insert
455− new_pos + assoc.insert_offset(s)
433+ new_pos + ins
456434 }
457435 }),
458436 i
@@ -460,15 +438,20 @@ impl ChangeSet {
460438 } else {
461439 // at insert point
462440 map!(
463− |pos, assoc: Assoc| (old_pos == pos).then(|| {
441+ |pos, assoc| (old_pos == pos).then(|| {
464442 // return position before inserted text
465− new_pos + assoc.insert_offset(s)
443+ if assoc == Assoc::Before {
444+ new_pos
445+ } else {
446+ // after text
447+ new_pos + ins
448+ }
466449 }),
467450 i
468451 );
469452 }
470453
471− new_pos += s.chars().count();
454+ new_pos += ins;
472455 }
473456 }
474457 old_pos = old_end;
@@ -901,48 +884,6 @@ mod test {
901884 let mut positions = [4, 2];
902885 cs.update_positions(positions.iter_mut().map(|pos| (pos, Assoc::After)));
903886 assert_eq!(positions, [4, 2]);
904− // stays at word boundary
905− let cs = ChangeSet {
906− changes: vec![
907− Retain(2), // <space><space>
908− Insert(" ab".into()),
909− Retain(2), // cd
910− Insert("de ".into()),
911− ],
912− len: 4,
913− len_after: 10,
914− };
915− assert_eq!(cs.map_pos(2, Assoc::BeforeWord), 3);
916− assert_eq!(cs.map_pos(4, Assoc::AfterWord), 9);
917− let cs = ChangeSet {
918− changes: vec![
919− Retain(1), // <space>
920− Insert(" b".into()),
921− Delete(1), // c
922− Retain(1), // d
923− Insert("e ".into()),
924− Delete(1), // <space>
925− ],
926− len: 5,
927− len_after: 7,
928− };
929− assert_eq!(cs.map_pos(1, Assoc::BeforeWord), 2);
930− assert_eq!(cs.map_pos(3, Assoc::AfterWord), 5);
931− let cs = ChangeSet {
932− changes: vec![
933− Retain(1), // <space>
934− Insert("a".into()),
935− Delete(2), // <space>b
936− Retain(1), // d
937− Insert("e".into()),
938− Delete(1), // f
939− Retain(1), // <space>
940− ],
941− len: 5,
942− len_after: 7,
943− };
944− assert_eq!(cs.map_pos(2, Assoc::BeforeWord), 1);
945− assert_eq!(cs.map_pos(4, Assoc::AfterWord), 4);
946887 }
947888
948889 #[test]
helix-core/src/wrap.rs+1−3
@@ -1,9 +1,7 @@
11use smartstring::{LazyCompact, SmartString};
2−use textwrap::{Options, WordSplitter::NoHyphenation};
32
43/// Given a slice of text, return the text re-wrapped to fit it
54/// within the given width.
65pub fn reflow_hard_wrap(text: &str, text_width: usize) -> SmartString<LazyCompact> {
7− let options = Options::new(text_width).word_splitter(NoHyphenation);
8− textwrap::refill(text, options).into()
6+ textwrap::refill(text, text_width).into()
97}
helix-core/tests/data/indent/cpp.cppdeleted−48
@@ -1,48 +0,0 @@
1−std::vector<std::string>
2−fn_with_many_parameters(int parm1, long parm2, float parm3, double parm4,
3− char* parm5, bool parm6);
4−
5−std::vector<std::string>
6−fn_with_many_parameters(int parm1, long parm2, float parm3, double parm4,
7− char* parm5, bool parm6) {
8− auto lambda = []() {
9− return 0;
10− };
11− auto lambda_with_a_really_long_name_that_uses_a_whole_line
12− = [](int some_more_aligned_parameters,
13− std::string parm2) {
14− do_smth();
15− };
16− if (brace_on_same_line) {
17− do_smth();
18− } else if (brace_on_next_line)
19− {
20− do_smth();
21− } else if (another_condition) {
22− do_smth();
23− }
24− else {
25− do_smth();
26− }
27− if (inline_if_statement)
28− do_smth();
29− if (another_inline_if_statement)
30− return [](int parm1, char* parm2) {
31− this_is_a_really_pointless_lambda();
32− };
33−
34− switch (var) {
35− case true:
36− return -1;
37− case false:
38− return 42;
39− }
40−}
41−
42−class MyClass : public MyBaseClass {
43−public:
44− MyClass();
45− void public_fn();
46−private:
47− super_secret_private_fn();
48−}
helix-core/tests/data/indent/indent.rsnew file+1
@@ -0,0 +1 @@
1+../../../src/indent.rs
helix-core/tests/data/indent/languages.toml−13
@@ -11,16 +11,3 @@ indent = { tab-width = 4, unit = " " }
1111[[grammar]]
1212name = "rust"
1313source = { git = "https://github.com/tree-sitter/tree-sitter-rust", rev = "0431a2c60828731f27491ee9fdefe25e250ce9c9" }
14−
15−[[language]]
16−name = "cpp"
17−scope = "source.cpp"
18−injection-regex = "cpp"
19−file-types = ["cc", "hh", "c++", "cpp", "hpp", "h", "ipp", "tpp", "cxx", "hxx", "ixx", "txx", "ino", "C", "H"]
20−roots = []
21−comment-token = "//"
22−indent = { tab-width = 2, unit = " " }
23−
24−[[grammar]]
25−name = "cpp"
26−source = { git = "https://github.com/tree-sitter/tree-sitter-cpp", rev = "2d2c4aee8672af4c7c8edff68e7dd4c07e88d2b1" }
helix-core/tests/indent.rs+23−151
@@ -1,122 +1,20 @@
11use helix_core::{
22 indent::{indent_level_for_line, treesitter_indent_for_pos, IndentStyle},
3− syntax::{Configuration, Loader},
3+ syntax::Loader,
44 Syntax,
55};
6−use ropey::Rope;
7−use std::{ops::Range, path::PathBuf, process::Command};
6+use std::path::PathBuf;
87
98#[test]
109fn test_treesitter_indent_rust() {
11− standard_treesitter_test("rust.rs", "source.rust");
10+ test_treesitter_indent("rust.rs", "source.rust");
1211}
13−
14−#[test]
15−fn test_treesitter_indent_cpp() {
16− standard_treesitter_test("cpp.cpp", "source.cpp");
17−}
18−
1912#[test]
20−fn test_treesitter_indent_rust_helix() {
21− // We pin a specific git revision to prevent unrelated changes from causing the indent tests to fail.
22− // Ideally, someone updates this once in a while and fixes any errors that occur.
23− let rev = "af382768cdaf89ff547dbd8f644a1bddd90e7c8f";
24− let files = Command::new("git")
25− .args([
26− "ls-tree",
27− "-r",
28− "--name-only",
29− "--full-tree",
30− rev,
31− "helix-term/src",
32− ])
33− .output()
34− .unwrap();
35− let files = String::from_utf8(files.stdout).unwrap();
36−
37− let ignored_files = vec![
38− // Contains many macros that tree-sitter does not parse in a meaningful way and is otherwise not very interesting
39− "helix-term/src/health.rs",
40− ];
41−
42− for file in files.split_whitespace() {
43− if ignored_files.contains(&file) {
44− continue;
45− }
46− let ignored_lines: Vec<Range<usize>> = match file {
47− "helix-term/src/application.rs" => vec![
48− // We can't handle complicated indent rules inside macros (`json!` in this case) since
49− // the tree-sitter grammar only parses them as `token_tree` and `identifier` nodes.
50− 1045..1051,
51− ],
52− "helix-term/src/commands.rs" => vec![
53− // This is broken because of the current handling of `call_expression`
54− // (i.e. having an indent query for it but outdenting again in specific cases).
55− // The indent query is needed to correctly handle multi-line arguments in function calls
56− // inside indented `field_expression` nodes (which occurs fairly often).
57− //
58− // Once we have the `@indent.always` capture type, it might be possible to just have an indent
59− // capture for the `arguments` field of a call expression. That could enable us to correctly
60− // handle this.
61− 2226..2230,
62− ],
63− "helix-term/src/commands/dap.rs" => vec![
64− // Complex `format!` macro
65− 46..52,
66− ],
67− "helix-term/src/commands/lsp.rs" => vec![
68− // Macro
69− 624..627,
70− // Return type declaration of a closure. `cargo fmt` adds an additional space here,
71− // which we cannot (yet) model with our indent queries.
72− 878..879,
73− // Same as in `helix-term/src/commands.rs`
74− 1335..1343,
75− ],
76− "helix-term/src/config.rs" => vec![
77− // Multiline string
78− 146..152,
79− ],
80− "helix-term/src/keymap.rs" => vec![
81− // Complex macro (see above)
82− 456..470,
83− // Multiline string without indent
84− 563..567,
85− ],
86− "helix-term/src/main.rs" => vec![
87− // Multiline string
88− 44..70,
89− ],
90− "helix-term/src/ui/completion.rs" => vec![
91− // Macro
92− 218..232,
93− ],
94− "helix-term/src/ui/editor.rs" => vec![
95− // The chained function calls here are not indented, probably because of the comment
96− // in between. Since `cargo fmt` doesn't even attempt to format it, there's probably
97− // no point in trying to indent this correctly.
98− 342..350,
99− ],
100− "helix-term/src/ui/lsp.rs" => vec![
101− // Macro
102− 56..61,
103− ],
104− "helix-term/src/ui/statusline.rs" => vec![
105− // Same as in `helix-term/src/commands.rs`
106− 436..442,
107− 450..456,
108− ],
109− _ => Vec::new(),
110− };
111−
112− let git_object = rev.to_string() + ":" + file;
113− let content = Command::new("git")
114− .args(["cat-file", "blob", &git_object])
115− .output()
116− .unwrap();
117− let doc = Rope::from_reader(&mut content.stdout.as_slice()).unwrap();
118− test_treesitter_indent(file, doc, "source.rust", ignored_lines);
119− }
13+fn test_treesitter_indent_rust_2() {
14+ test_treesitter_indent("indent.rs", "source.rust");
15+ // TODO Use commands.rs as indentation test.
16+ // Currently this fails because we can't align the parameters of a closure yet
17+ // test_treesitter_indent("commands.rs", "source.rust");
12018}
12119
12220#[test]
@@ -152,41 +50,20 @@ fn test_indent_level_for_line_with_spaces_and_tabs() {
15250 assert_eq!(indent_level, 2)
15351}
15452
155−fn indent_tests_dir() -> PathBuf {
53+fn test_treesitter_indent(file_name: &str, lang_scope: &str) {
15654 let mut test_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
15755 test_dir.push("tests/data/indent");
158− test_dir
159−}
16056
161−fn indent_test_path(name: &str) -> PathBuf {
162− let mut path = indent_tests_dir();
163− path.push(name);
164− path
165−}
166−
167−fn indent_tests_config() -> Configuration {
168− let mut config_path = indent_tests_dir();
169− config_path.push("languages.toml");
170− let config = std::fs::read_to_string(config_path).unwrap();
171− toml::from_str(&config).unwrap()
172−}
173−
174−fn standard_treesitter_test(file_name: &str, lang_scope: &str) {
175− let test_path = indent_test_path(file_name);
176− let test_file = std::fs::File::open(test_path).unwrap();
57+ let mut test_file = test_dir.clone();
58+ test_file.push(file_name);
59+ let test_file = std::fs::File::open(test_file).unwrap();
17760 let doc = ropey::Rope::from_reader(test_file).unwrap();
178− test_treesitter_indent(file_name, doc, lang_scope, Vec::new())
179−}
18061
181−/// Test that all the lines in the given file are indented as expected.
182−/// ignored_lines is a list of (1-indexed) line ranges that are excluded from this test.
183−fn test_treesitter_indent(
184− test_name: &str,
185− doc: Rope,
186− lang_scope: &str,
187− ignored_lines: Vec<std::ops::Range<usize>>,
188−) {
189− let loader = Loader::new(indent_tests_config());
62+ let mut config_file = test_dir;
63+ config_file.push("languages.toml");
64+ let config = std::fs::read_to_string(config_file).unwrap();
65+ let config = toml::from_str(&config).unwrap();
66+ let loader = Loader::new(config);
19067
19168 // set runtime path so we can find the queries
19269 let mut runtime = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
@@ -194,7 +71,6 @@ fn test_treesitter_indent(
19471 std::env::set_var("HELIX_RUNTIME", runtime.to_str().unwrap());
19572
19673 let language_config = loader.language_config_for_scope(lang_scope).unwrap();
197− let indent_style = IndentStyle::from_str(&language_config.indent.as_ref().unwrap().unit);
19874 let highlight_config = language_config.highlight_config(&[]).unwrap();
19975 let text = doc.slice(..);
20076 let syntax = Syntax::new(text, highlight_config, std::sync::Arc::new(loader)).unwrap();
@@ -202,27 +78,23 @@ fn test_treesitter_indent(
20278
20379 for i in 0..doc.len_lines() {
20480 let line = text.line(i);
205− if ignored_lines.iter().any(|range| range.contains(&(i + 1))) {
206− continue;
207− }
20881 if let Some(pos) = helix_core::find_first_non_whitespace_char(line) {
209− let tab_width: usize = 4;
82+ let tab_and_indent_width: usize = 4;
21083 let suggested_indent = treesitter_indent_for_pos(
21184 indent_query,
21285 &syntax,
213− tab_width,
214− indent_style.indent_width(tab_width),
86+ &IndentStyle::Spaces(tab_and_indent_width as u8),
87+ tab_and_indent_width,
88+ tab_and_indent_width,
21589 text,
21690 i,
21791 text.line_to_char(i) + pos,
21892 false,
21993 )
220− .unwrap()
221− .to_string(&indent_style, tab_width);
94+ .unwrap();
22295 assert!(
22396 line.get_slice(..pos).map_or(false, |s| s == suggested_indent),
224− "Wrong indentation for file {:?} on line {}:\n\"{}\" (original line)\n\"{}\" (suggested indentation)\n",
225− test_name,
97+ "Wrong indentation on line {}:\n\"{}\" (original line)\n\"{}\" (suggested indentation)\n",
22698 i+1,
22799 line.slice(..line.len_chars()-1),
228100 suggested_indent,
helix-dap/Cargo.toml+9−11
@@ -1,27 +1,25 @@
11[package]
22name = "helix-dap"
3+version = "0.6.0"
4+authors = ["Blaž Hrastnik <blaz@mxxn.io>"]
5+edition = "2018"
6+license = "MPL-2.0"
37description = "DAP client implementation for Helix project"
4−version.workspace = true
5−authors.workspace = true
6−edition.workspace = true
7−license.workspace = true
8−rust-version.workspace = true
9−categories.workspace = true
10−repository.workspace = true
11−homepage.workspace = true
8+categories = ["editor"]
9+repository = "https://github.com/helix-editor/helix"
10+homepage = "https://helix-editor.com"
1211
1312# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1413
1514[dependencies]
16−helix-core = { path = "../helix-core" }
17−
15+helix-core = { version = "0.6", path = "../helix-core" }
1816anyhow = "1.0"
1917log = "0.4"
2018serde = { version = "1.0", features = ["derive"] }
2119serde_json = "1.0"
2220thiserror = "1.0"
2321tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "net", "sync"] }
24−which = "5.0.0"
22+which = "4.4"
2523
2624[dev-dependencies]
2725fern = "0.6"
helix-event/Cargo.tomldeleted−16
@@ -1,16 +0,0 @@
1−[package]
2−name = "helix-event"
3−version.workspace = true
4−authors.workspace = true
5−edition.workspace = true
6−license.workspace = true
7−rust-version.workspace = true
8−categories.workspace = true
9−repository.workspace = true
10−homepage.workspace = true
11−
12−# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
13−
14−[dependencies]
15−tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "parking_lot"] }
16−parking_lot = { version = "0.12", features = ["send_guard"] }
helix-event/src/lib.rsdeleted−8
@@ -1,8 +0,0 @@
1−//! `helix-event` contains systems that allow (often async) communication between
2−//! different editor components without strongly coupling them. Currently this
3−//! crate only contains some smaller facilities but the intend is to add more
4−//! functionality in the future ( like a generic hook system)
5−
6−pub use redraw::{lock_frame, redraw_requested, request_redraw, start_frame, RenderLockGuard};
7−
8−mod redraw;
helix-event/src/redraw.rsdeleted−49
@@ -1,49 +0,0 @@
1−//! Signals that control when/if the editor redraws
2−
3−use std::future::Future;
4−
5−use parking_lot::{RwLock, RwLockReadGuard};
6−use tokio::sync::Notify;
7−
8−/// A `Notify` instance that can be used to (asynchronously) request
9−/// the editor the render a new frame.
10−static REDRAW_NOTIFY: Notify = Notify::const_new();
11−
12−/// A `RwLock` that prevents the next frame from being
13−/// drawn until an exclusive (write) lock can be acquired.
14−/// This allows asynchsonous tasks to acquire `non-exclusive`
15−/// locks (read) to prevent the next frame from being drawn
16−/// until a certain computation has finished.
17−static RENDER_LOCK: RwLock<()> = RwLock::new(());
18−
19−pub type RenderLockGuard = RwLockReadGuard<'static, ()>;
20−
21−/// Requests that the editor is redrawn. The redraws are debounced (currently to
22−/// 30FPS) so this can be called many times without causing a ton of frames to
23−/// be rendered.
24−pub fn request_redraw() {
25− REDRAW_NOTIFY.notify_one();
26−}
27−
28−/// Returns a future that will yield once a redraw has been asynchronously
29−/// requested using [`request_redraw`].
30−pub fn redraw_requested() -> impl Future<Output = ()> {
31− REDRAW_NOTIFY.notified()
32−}
33−
34−/// Wait until all locks acquired with [`lock_frame`] have been released.
35−/// This function is called before rendering and is intended to allow the frame
36−/// to wait for async computations that should be included in the current frame.
37−pub fn start_frame() {
38− drop(RENDER_LOCK.write());
39− // exhaust any leftover redraw notifications
40− let notify = REDRAW_NOTIFY.notified();
41− tokio::pin!(notify);
42− notify.enable();
43−}
44−
45−/// Acquires the render lock which will prevent the next frame from being drawn
46−/// until the returned guard is dropped.
47−pub fn lock_frame() -> RenderLockGuard {
48− RENDER_LOCK.read()
49−}
helix-loader/Cargo.toml+11−12
@@ -1,14 +1,13 @@
11[package]
22name = "helix-loader"
3−description = "Build bootstrapping for Helix crates"
4−version.workspace = true
5−authors.workspace = true
6−edition.workspace = true
7−license.workspace = true
8−rust-version.workspace = true
9−categories.workspace = true
10−repository.workspace = true
11−homepage.workspace = true
3+version = "0.6.0"
4+description = "A post-modern text editor."
5+authors = ["Blaž Hrastnik <blaz@mxxn.io>"]
6+edition = "2021"
7+license = "MPL-2.0"
8+categories = ["editor"]
9+repository = "https://github.com/helix-editor/helix"
10+homepage = "https://helix-editor.com"
1211
1312[[bin]]
1413name = "hx-loader"
@@ -20,16 +19,16 @@ serde = { version = "1.0", features = ["derive"] }
2019toml = "0.7"
2120etcetera = "0.8"
2221tree-sitter.workspace = true
23−once_cell = "1.19"
22+once_cell = "1.18"
2423log = "0.4"
25−which = "5.0.0"
24+which = "4.4"
2625
2726# TODO: these two should be on !wasm32 only
2827
2928# cloning/compiling tree-sitter grammars
3029cc = { version = "1" }
3130threadpool = { version = "1.0" }
32−tempfile = "3.8.1"
31+tempfile = "3.7.1"
3332dunce = "1.0.4"
3433
3534[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
helix-loader/build.rs+4−14
@@ -2,17 +2,7 @@ use std::borrow::Cow;
22use std::path::Path;
33use std::process::Command;
44
5−const MAJOR: &str = env!("CARGO_PKG_VERSION_MAJOR");
6−const MINOR: &str = env!("CARGO_PKG_VERSION_MINOR");
7−const PATCH: &str = env!("CARGO_PKG_VERSION_PATCH");
8−
9−fn get_calver() -> String {
10− if PATCH == "0" {
11− format!("{MAJOR}.{MINOR}")
12− } else {
13− format!("{MAJOR}.{MINOR}.{PATCH}")
14− }
15−}
5+const VERSION: &str = include_str!("../VERSION");
166
177fn main() {
188 let git_hash = Command::new("git")
@@ -22,10 +12,9 @@ fn main() {
2212 .filter(|output| output.status.success())
2313 .and_then(|x| String::from_utf8(x.stdout).ok());
2414
25− let calver = get_calver();
2615 let version: Cow<_> = match &git_hash {
27− Some(git_hash) => format!("{} ({})", calver, &git_hash[..8]).into(),
28− None => calver.into(),
16+ Some(git_hash) => format!("{} ({})", VERSION, &git_hash[..8]).into(),
17+ None => VERSION.into(),
2918 };
3019
3120 println!(
@@ -33,6 +22,7 @@ fn main() {
3322 std::env::var("TARGET").unwrap()
3423 );
3524
25+ println!("cargo:rerun-if-changed=../VERSION");
3626 println!("cargo:rustc-env=VERSION_AND_GIT_HASH={}", version);
3727
3828 if git_hash.is_none() {
helix-loader/src/lib.rs+4−13
@@ -33,9 +33,9 @@ pub fn current_working_dir() -> PathBuf {
3333 path
3434}
3535
36−pub fn set_current_working_dir(path: impl AsRef<Path>) -> std::io::Result<()> {
36+pub fn set_current_working_dir(path: PathBuf) -> std::io::Result<()> {
3737 let path = dunce::canonicalize(path)?;
38− std::env::set_current_dir(&path)?;
38+ std::env::set_current_dir(path.clone())?;
3939 let mut cwd = CWD.write().unwrap();
4040 *cwd = Some(path);
4141 Ok(())
@@ -60,8 +60,7 @@ pub fn initialize_log_file(specified_file: Option<PathBuf>) {
6060/// 1. sibling directory to `CARGO_MANIFEST_DIR` (if environment variable is set)
6161/// 2. subdirectory of user config directory (always included)
6262/// 3. `HELIX_RUNTIME` (if environment variable is set)
63−/// 4. `HELIX_DEFAULT_RUNTIME` (if environment variable is set *at build time*)
64−/// 5. subdirectory of path to helix executable (always included)
63+/// 4. subdirectory of path to helix executable (always included)
6564///
6665/// Postcondition: returns at least two paths (they might not exist).
6766fn prioritize_runtime_dirs() -> Vec<PathBuf> {
@@ -82,14 +81,6 @@ fn prioritize_runtime_dirs() -> Vec<PathBuf> {
8281 rt_dirs.push(dir.into());
8382 }
8483
85− // If this variable is set during build time, it will always be included
86− // in the lookup list. This allows downstream packagers to set a fallback
87− // directory to a location that is conventional on their distro so that they
88− // need not resort to a wrapper script or a global environment variable.
89− if let Some(dir) = std::option_env!("HELIX_DEFAULT_RUNTIME") {
90− rt_dirs.push(dir.into());
91− }
92−
9384 // fallback to location of the executable being run
9485 // canonicalize the path in case the executable is symlinked
9586 let exe_rt_dir = std::env::current_exe()
@@ -289,7 +280,7 @@ mod merge_toml_tests {
289280 let cwd = current_working_dir();
290281 assert_ne!(cwd, new_path);
291282
292− set_current_working_dir(&new_path).expect("Couldn't set new path");
283+ set_current_working_dir(new_path.clone()).expect("Couldn't set new path");
293284
294285 let cwd = current_working_dir();
295286 assert_eq!(cwd, new_path);
helix-lsp/Cargo.toml+14−15
@@ -1,32 +1,31 @@
11[package]
22name = "helix-lsp"
3+version = "0.6.0"
4+authors = ["Blaž Hrastnik <blaz@mxxn.io>"]
5+edition = "2021"
6+license = "MPL-2.0"
37description = "LSP client implementation for Helix project"
4−version.workspace = true
5−authors.workspace = true
6−edition.workspace = true
7−license.workspace = true
8−rust-version.workspace = true
9−categories.workspace = true
10−repository.workspace = true
11−homepage.workspace = true
8+categories = ["editor"]
9+repository = "https://github.com/helix-editor/helix"
10+homepage = "https://helix-editor.com"
1211
1312# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1413
1514[dependencies]
16−helix-core = { path = "../helix-core" }
17−helix-loader = { path = "../helix-loader" }
18−helix-parsec = { path = "../helix-parsec" }
15+helix-core = { version = "0.6", path = "../helix-core" }
16+helix-loader = { version = "0.6", path = "../helix-loader" }
17+helix-parsec = { version = "0.6", path = "../helix-parsec" }
1918
2019anyhow = "1.0"
2120futures-executor = "0.3"
2221futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false }
23−globset = "0.4.14"
22+globset = "0.4.13"
2423log = "0.4"
25−lsp-types = { version = "0.95" }
24+lsp-types = { version = "0.94" }
2625serde = { version = "1.0", features = ["derive"] }
2726serde_json = "1.0"
2827thiserror = "1.0"
29−tokio = { version = "1.35", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] }
28+tokio = { version = "1.29", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] }
3029tokio-stream = "0.1.14"
31−which = "5.0.0"
30+which = "4.4"
3231parking_lot = "0.12.1"
helix-lsp/src/client.rs+13−87
@@ -401,22 +401,12 @@ impl Client {
401401 &self,
402402 params: R::Params,
403403 ) -> impl Future<Output = Result<Value>>
404− where
405− R::Params: serde::Serialize,
406− {
407− self.call_with_timeout::<R>(params, self.req_timeout)
408− }
409−
410− fn call_with_timeout<R: lsp::request::Request>(
411− &self,
412− params: R::Params,
413− timeout_secs: u64,
414− ) -> impl Future<Output = Result<Value>>
415404 where
416405 R::Params: serde::Serialize,
417406 {
418407 let server_tx = self.server_tx.clone();
419408 let id = self.next_request_id();
409+ let timeout_secs = self.req_timeout;
420410
421411 async move {
422412 use std::time::Duration;
@@ -558,11 +548,6 @@ impl Client {
558548 dynamic_registration: Some(true),
559549 relative_pattern_support: Some(false),
560550 }),
561− file_operations: Some(lsp::WorkspaceFileOperationsClientCapabilities {
562− will_rename: Some(true),
563− did_rename: Some(true),
564− ..Default::default()
565− }),
566551 ..Default::default()
567552 }),
568553 text_document: Some(lsp::TextDocumentClientCapabilities {
@@ -667,7 +652,6 @@ impl Client {
667652 version: Some(String::from(VERSION_AND_GIT_HASH)),
668653 }),
669654 locale: None, // TODO
670− work_done_progress_params: lsp::WorkDoneProgressParams::default(),
671655 };
672656
673657 self.request::<lsp::request::Initialize>(params).await
@@ -716,65 +700,6 @@ impl Client {
716700 })
717701 }
718702
719− pub fn prepare_file_rename(
720− &self,
721− old_uri: &lsp::Url,
722− new_uri: &lsp::Url,
723− ) -> Option<impl Future<Output = Result<lsp::WorkspaceEdit>>> {
724− let capabilities = self.capabilities.get().unwrap();
725−
726− // Return early if the server does not support willRename feature
727− match &capabilities.workspace {
728− Some(workspace) => match &workspace.file_operations {
729− Some(op) => {
730− op.will_rename.as_ref()?;
731− }
732− _ => return None,
733− },
734− _ => return None,
735− }
736−
737− let files = vec![lsp::FileRename {
738− old_uri: old_uri.to_string(),
739− new_uri: new_uri.to_string(),
740− }];
741− let request = self.call_with_timeout::<lsp::request::WillRenameFiles>(
742− lsp::RenameFilesParams { files },
743− 5,
744− );
745−
746− Some(async move {
747− let json = request.await?;
748− let response: Option<lsp::WorkspaceEdit> = serde_json::from_value(json)?;
749− Ok(response.unwrap_or_default())
750− })
751− }
752−
753− pub fn did_file_rename(
754− &self,
755− old_uri: &lsp::Url,
756− new_uri: &lsp::Url,
757− ) -> Option<impl Future<Output = std::result::Result<(), Error>>> {
758− let capabilities = self.capabilities.get().unwrap();
759−
760− // Return early if the server does not support DidRename feature
761− match &capabilities.workspace {
762− Some(workspace) => match &workspace.file_operations {
763− Some(op) => {
764− op.did_rename.as_ref()?;
765− }
766− _ => return None,
767− },
768− _ => return None,
769− }
770−
771− let files = vec![lsp::FileRename {
772− old_uri: old_uri.to_string(),
773− new_uri: new_uri.to_string(),
774− }];
775− Some(self.notify::<lsp::notification::DidRenameFiles>(lsp::RenameFilesParams { files }))
776− }
777−
778703 // -------------------------------------------------------------------------------------------
779704 // Text document
780705 // -------------------------------------------------------------------------------------------
@@ -970,19 +895,20 @@ impl Client {
970895 ) -> Option<impl Future<Output = Result<()>>> {
971896 let capabilities = self.capabilities.get().unwrap();
972897
973− let include_text = match &capabilities.text_document_sync.as_ref()? {
974− lsp::TextDocumentSyncCapability::Options(lsp::TextDocumentSyncOptions {
975− save: options,
898+ let include_text = match &capabilities.text_document_sync {
899+ Some(lsp::TextDocumentSyncCapability::Options(lsp::TextDocumentSyncOptions {
900+ save: Some(options),
976901 ..
977− }) => match options.as_ref()? {
902+ })) => match options {
978903 lsp::TextDocumentSyncSaveOptions::Supported(true) => false,
979904 lsp::TextDocumentSyncSaveOptions::SaveOptions(lsp_types::SaveOptions {
980905 include_text,
981906 }) => include_text.unwrap_or(false),
982− lsp::TextDocumentSyncSaveOptions::Supported(false) => return None,
907+ // Supported(false)
908+ _ => return None,
983909 },
984− // see: https://github.com/microsoft/language-server-protocol/issues/288
985− lsp::TextDocumentSyncCapability::Kind(..) => false,
910+ // unsupported
911+ _ => return None,
986912 };
987913
988914 Some(self.notify::<lsp::notification::DidSaveTextDocument>(
@@ -1045,12 +971,12 @@ impl Client {
1045971 ) -> Option<impl Future<Output = Result<Value>>> {
1046972 let capabilities = self.capabilities.get().unwrap();
1047973
1048− // Return early if the server does not support resolving code actions.
1049− match capabilities.code_action_provider {
1050− Some(lsp::CodeActionProviderCapability::Options(lsp::CodeActionOptions {
974+ // Return early if the server does not support resolving code action.
975+ match capabilities.completion_provider {
976+ Some(lsp::CompletionOptions {
1051977 resolve_provider: Some(true),
1052978 ..
1053− })) => (),
979+ }) => (),
1054980 _ => return None,
1055981 }
1056982
helix-lsp/src/lib.rs+28−32
@@ -445,36 +445,36 @@ pub mod util {
445445 // the tabstop closest to the range simply replaces `head` while anchor remains in place
446446 // the remaining tabstops receive their own single-width cursor
447447 if range.head < range.anchor {
448− let last_idx = tabstops.len() - 1;
449− let last_tabstop = tabstop_anchor + tabstops[last_idx].0;
448+ let first_tabstop = tabstop_anchor + tabstops[0].1;
450449
451450 // if selection is forward but was moved to the right it is
452451 // contained entirely in the replacement text, just do a point
453452 // selection (fallback below)
454− if range.anchor > last_tabstop {
455− let range = Range::new(range.anchor, last_tabstop);
453+ if range.anchor >= first_tabstop {
454+ let range = Range::new(range.anchor, first_tabstop);
456455 mapped_selection.push(range);
457− let rem_tabstops = tabstops[..last_idx]
456+ let rem_tabstops = tabstops[1..]
458457 .iter()
459− .map(|tabstop| Range::point(tabstop_anchor + tabstop.0));
458+ .map(|tabstop| Range::point(tabstop_anchor + tabstop.1));
460459 mapped_selection.extend(rem_tabstops);
461460 continue;
462461 }
463462 } else {
464− let first_tabstop = tabstop_anchor + tabstops[0].0;
463+ let last_idx = tabstops.len() - 1;
464+ let last_tabstop = tabstop_anchor + tabstops[last_idx].1;
465465
466466 // if selection is forward but was moved to the right it is
467467 // contained entirely in the replacement text, just do a point
468468 // selection (fallback below)
469− if range.anchor < first_tabstop {
469+ if range.anchor <= last_tabstop {
470470 // we can't properly compute the the next grapheme
471471 // here because the transaction hasn't been applied yet
472472 // that is not a problem because the range gets grapheme aligned anyway
473473 // tough so just adding one will always cause head to be grapheme
474474 // aligned correctly when applied to the document
475− let range = Range::new(range.anchor, first_tabstop + 1);
475+ let range = Range::new(range.anchor, last_tabstop + 1);
476476 mapped_selection.push(range);
477− let rem_tabstops = tabstops[1..]
477+ let rem_tabstops = tabstops[..last_idx]
478478 .iter()
479479 .map(|tabstop| Range::point(tabstop_anchor + tabstop.0));
480480 mapped_selection.extend(rem_tabstops);
@@ -749,40 +749,36 @@ impl Registry {
749749 }
750750 }
751751
752− pub fn get<'a>(
753− &'a mut self,
754− language_config: &'a LanguageConfiguration,
755− doc_path: Option<&'a std::path::PathBuf>,
756− root_dirs: &'a [PathBuf],
752+ pub fn get(
753+ &mut self,
754+ language_config: &LanguageConfiguration,
755+ doc_path: Option<&std::path::PathBuf>,
756+ root_dirs: &[PathBuf],
757757 enable_snippets: bool,
758− ) -> impl Iterator<Item = (LanguageServerName, Result<Arc<Client>>)> + 'a {
759− language_config.language_servers.iter().map(
760− move |LanguageServerFeatures { name, .. }| {
758+ ) -> Result<HashMap<LanguageServerName, Arc<Client>>> {
759+ language_config
760+ .language_servers
761+ .iter()
762+ .map(|LanguageServerFeatures { name, .. }| {
761763 if let Some(clients) = self.inner.get(name) {
762764 if let Some((_, client)) = clients.iter().enumerate().find(|(i, client)| {
763765 client.try_add_doc(&language_config.roots, root_dirs, doc_path, *i == 0)
764766 }) {
765− return (name.to_owned(), Ok(client.clone()));
767+ return Ok((name.to_owned(), client.clone()));
766768 }
767769 }
768− match self.start_client(
770+ let client = self.start_client(
769771 name.clone(),
770772 language_config,
771773 doc_path,
772774 root_dirs,
773775 enable_snippets,
774− ) {
775− Ok(client) => {
776− self.inner
777− .entry(name.to_owned())
778− .or_default()
779− .push(client.clone());
780− (name.clone(), Ok(client))
781− }
782− Err(err) => (name.to_owned(), Err(err)),
783− }
784− },
785− )
776+ )?;
777+ let clients = self.inner.entry(name.clone()).or_default();
778+ clients.push(client.clone());
779+ Ok((name.clone(), client))
780+ })
781+ .collect()
786782 }
787783
788784 pub fn iter_clients(&self) -> impl Iterator<Item = &Arc<Client>> {
helix-parsec/Cargo.toml+7−8
@@ -1,14 +1,13 @@
11[package]
22name = "helix-parsec"
3+version = "0.6.0"
4+authors = ["Blaž Hrastnik <blaz@mxxn.io>"]
5+edition = "2021"
6+license = "MPL-2.0"
37description = "Parser combinators for Helix"
8+categories = ["editor"]
9+repository = "https://github.com/helix-editor/helix"
10+homepage = "https://helix-editor.com"
411include = ["src/**/*", "README.md"]
5−version.workspace = true
6−authors.workspace = true
7−edition.workspace = true
8−license.workspace = true
9−rust-version.workspace = true
10−categories.workspace = true
11−repository.workspace = true
12−homepage.workspace = true
1312
1413[dependencies]
helix-term/Cargo.toml+25−30
@@ -1,16 +1,16 @@
11[package]
22name = "helix-term"
3+version = "0.6.0"
34description = "A post-modern text editor."
5+authors = ["Blaž Hrastnik <blaz@mxxn.io>"]
6+edition = "2021"
7+license = "MPL-2.0"
8+categories = ["editor", "command-line-utilities"]
9+repository = "https://github.com/helix-editor/helix"
10+homepage = "https://helix-editor.com"
411include = ["src/**/*", "README.md"]
512default-run = "hx"
6−version.workspace = true
7−authors.workspace = true
8−edition.workspace = true
9−license.workspace = true
10−rust-version.workspace = true
11−categories.workspace = true
12−repository.workspace = true
13−homepage.workspace = true
13+rust-version = "1.65"
1414
1515[features]
1616default = ["git"]
@@ -23,22 +23,21 @@ name = "hx"
2323path = "src/main.rs"
2424
2525[dependencies]
26−helix-core = { path = "../helix-core" }
27−helix-event = { path = "../helix-event" }
28−helix-view = { path = "../helix-view" }
29−helix-lsp = { path = "../helix-lsp" }
30−helix-dap = { path = "../helix-dap" }
31−helix-vcs = { path = "../helix-vcs" }
32−helix-loader = { path = "../helix-loader" }
26+helix-core = { version = "0.6", path = "../helix-core" }
27+helix-view = { version = "0.6", path = "../helix-view" }
28+helix-lsp = { version = "0.6", path = "../helix-lsp" }
29+helix-dap = { version = "0.6", path = "../helix-dap" }
30+helix-vcs = { version = "0.6", path = "../helix-vcs" }
31+helix-loader = { version = "0.6", path = "../helix-loader" }
3332
3433anyhow = "1"
35−once_cell = "1.19"
34+once_cell = "1.18"
3635
37−which = "5.0.0"
36+which = "4.4"
3837
3938tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] }
4039tui = { path = "../helix-tui", package = "helix-tui", default-features = false, features = ["crossterm"] }
41−crossterm = { version = "0.27", features = ["event-stream"] }
40+crossterm = { version = "0.26", features = ["event-stream"] }
4241signal-hook = "0.3"
4342tokio-stream = "0.1"
4443futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false }
@@ -50,17 +49,13 @@ chrono = { version = "0.4", default-features = false, features = ["clock"] }
5049log = "0.4"
5150
5251# File picker
53−nucleo.workspace = true
52+fuzzy-matcher = "0.3"
5453ignore = "0.4"
5554# markdown doc rendering
5655pulldown-cmark = { version = "0.9", default-features = false }
5756# file type detection
5857content_inspector = "0.2.4"
5958
60−# opening URLs
61−open = "5.0.1"
62−url = "2.5.0"
63−
6459# config
6560toml = "0.7"
6661
@@ -68,20 +63,20 @@ serde_json = "1.0"
6863serde = { version = "1.0", features = ["derive"] }
6964
7065# ripgrep for global search
71−grep-regex = "0.1.12"
72−grep-searcher = "0.1.13"
66+grep-regex = "0.1.11"
67+grep-searcher = "0.1.11"
7368
7469[target.'cfg(not(windows))'.dependencies] # https://github.com/vorner/signal-hook/issues/100
7570signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }
76−libc = "0.2.151"
71+libc = "0.2.147"
7772
7873[target.'cfg(target_os = "macos")'.dependencies]
79−crossterm = { version = "0.27", features = ["event-stream", "use-dev-tty"] }
74+crossterm = { version = "0.26", features = ["event-stream", "use-dev-tty"] }
8075
8176[build-dependencies]
82−helix-loader = { path = "../helix-loader" }
77+helix-loader = { version = "0.6", path = "../helix-loader" }
8378
8479[dev-dependencies]
8580smallvec = "1.11"
86−indoc = "2.0.4"
87−tempfile = "3.8.1"
81+indoc = "2.0.3"
82+tempfile = "3.7.1"
helix-term/src/application.rs+75−111
@@ -1,7 +1,6 @@
11use arc_swap::{access::Map, ArcSwap};
22use futures_util::Stream;
33use helix_core::{
4− chars::char_is_word,
54 diagnostic::{DiagnosticTag, NumberOrString},
65 path::get_relative_path,
76 pos_at_coords, syntax, Selection,
@@ -161,21 +160,17 @@ impl Application {
161160 let path = helix_loader::runtime_file(Path::new("tutor"));
162161 editor.open(&path, Action::VerticalSplit)?;
163162 // Unset path to prevent accidentally saving to the original tutor file.
164− doc_mut!(editor).set_path(None);
163+ doc_mut!(editor).set_path(None)?;
165164 } else if !args.files.is_empty() {
166− let mut files_it = args.files.into_iter().peekable();
167−
168− // If the first file is a directory, skip it and open a picker
169− if let Some((first, _)) = files_it.next_if(|(p, _)| p.is_dir()) {
170− let picker = ui::file_picker(first, &config.load().editor);
165+ let first = &args.files[0].0; // we know it's not empty
166+ if first.is_dir() {
167+ helix_loader::set_current_working_dir(first.clone())?;
168+ editor.new_file(Action::VerticalSplit);
169+ let picker = ui::file_picker(".".into(), &config.load().editor);
171170 compositor.push(Box::new(overlaid(picker)));
172− }
173−
174− // If there are any more files specified, open them
175− if files_it.peek().is_some() {
176− let mut nr_of_files = 0;
177− for (file, pos) in files_it {
178− nr_of_files += 1;
171+ } else {
172+ let nr_of_files = args.files.len();
173+ for (i, (file, pos)) in args.files.into_iter().enumerate() {
179174 if file.is_dir() {
180175 return Err(anyhow::anyhow!(
181176 "expected a path to file, found a directory. (to open a directory pass it as first argument)"
@@ -187,7 +182,7 @@ impl Application {
187182 // option. If neither of those two arguments are passed
188183 // in, just load the files normally.
189184 let action = match args.split {
190− _ if nr_of_files == 1 => Action::VerticalSplit,
185+ _ if i == 0 => Action::VerticalSplit,
191186 Some(Layout::Vertical) => Action::VerticalSplit,
192187 Some(Layout::Horizontal) => Action::HorizontalSplit,
193188 None => Action::Load,
@@ -214,8 +209,6 @@ impl Application {
214209 // does not affect views without pos since it is at the top
215210 let (view, doc) = current!(editor);
216211 align_view(doc, view, Align::Center);
217− } else {
218− editor.new_file(Action::VerticalSplit);
219212 }
220213 } else if stdin().is_tty() || cfg!(feature = "integration") {
221214 editor.new_file(Action::VerticalSplit);
@@ -258,19 +251,22 @@ impl Application {
258251 }
259252
260253 async fn render(&mut self) {
261− if self.compositor.full_redraw {
262− self.terminal.clear().expect("Cannot clear the terminal");
263− self.compositor.full_redraw = false;
264− }
265−
266254 let mut cx = crate::compositor::Context {
267255 editor: &mut self.editor,
268256 jobs: &mut self.jobs,
269257 scroll: None,
270258 };
271259
272− helix_event::start_frame();
260+ // Acquire mutable access to the redraw_handle lock
261+ // to ensure that there are no tasks running that want to block rendering
262+ drop(cx.editor.redraw_handle.1.write().await);
273263 cx.editor.needs_redraw = false;
264+ {
265+ // exhaust any leftover redraw notifications
266+ let notify = cx.editor.redraw_handle.0.notified();
267+ tokio::pin!(notify);
268+ notify.enable();
269+ }
274270
275271 let area = self
276272 .terminal
@@ -292,7 +288,7 @@ impl Application {
292288
293289 pub async fn event_loop<S>(&mut self, input_stream: &mut S)
294290 where
295− S: Stream<Item = std::io::Result<crossterm::event::Event>> + Unpin,
291+ S: Stream<Item = crossterm::Result<crossterm::event::Event>> + Unpin,
296292 {
297293 self.render().await;
298294
@@ -305,7 +301,7 @@ impl Application {
305301
306302 pub async fn event_loop_until_idle<S>(&mut self, input_stream: &mut S) -> bool
307303 where
308− S: Stream<Item = std::io::Result<crossterm::event::Event>> + Unpin,
304+ S: Stream<Item = crossterm::Result<crossterm::event::Event>> + Unpin,
309305 {
310306 loop {
311307 if self.editor.should_close() {
@@ -558,7 +554,16 @@ impl Application {
558554 let bytes = doc_save_event.text.len_bytes();
559555
560556 if doc.path() != Some(&doc_save_event.path) {
561− doc.set_path(Some(&doc_save_event.path));
557+ if let Err(err) = doc.set_path(Some(&doc_save_event.path)) {
558+ log::error!(
559+ "error setting path for doc '{:?}': {}",
560+ doc.path(),
561+ err.to_string(),
562+ );
563+
564+ self.editor.set_error(err.to_string());
565+ return;
566+ }
562567
563568 let loader = self.editor.syn_loader.clone();
564569
@@ -594,7 +599,7 @@ impl Application {
594599 EditorEvent::LanguageServerMessage((id, call)) => {
595600 self.handle_language_server_message(call, id).await;
596601 // limit render calls for fast language server messages
597− helix_event::request_redraw();
602+ self.editor.redraw_handle.0.notify_one();
598603 }
599604 EditorEvent::DebuggerEvent(payload) => {
600605 let needs_render = self.editor.handle_debugger_message(payload).await;
@@ -602,9 +607,6 @@ impl Application {
602607 self.render().await;
603608 }
604609 }
605− EditorEvent::Redraw => {
606− self.render().await;
607− }
608610 EditorEvent::IdleTimer => {
609611 self.editor.clear_idle_timer();
610612 self.handle_idle_timeout().await;
@@ -619,7 +621,10 @@ impl Application {
619621 false
620622 }
621623
622− pub async fn handle_terminal_events(&mut self, event: std::io::Result<CrosstermEvent>) {
624+ pub async fn handle_terminal_events(
625+ &mut self,
626+ event: Result<CrosstermEvent, crossterm::ErrorKind>,
627+ ) {
623628 let mut cx = crate::compositor::Context {
624629 editor: &mut self.editor,
625630 jobs: &mut self.jobs,
@@ -718,7 +723,7 @@ impl Application {
718723 ));
719724 }
720725 }
721− Notification::PublishDiagnostics(mut params) => {
726+ Notification::PublishDiagnostics(params) => {
722727 let path = match params.uri.to_file_path() {
723728 Ok(path) => path,
724729 Err(_) => {
@@ -732,69 +737,31 @@ impl Application {
732737 return;
733738 }
734739 let offset_encoding = language_server.offset_encoding();
735− // have to inline the function because of borrow checking...
736− let doc = self.editor.documents.values_mut()
737− .find(|doc| doc.path().map(|p| p == &path).unwrap_or(false))
738− .filter(|doc| {
739− if let Some(version) = params.version {
740− if version != doc.version() {
741− log::info!("Version ({version}) is out of date for {path:?} (expected ({}), dropping PublishDiagnostic notification", doc.version());
742− return false;
743− }
740+ let doc = self.editor.document_by_path_mut(&path).filter(|doc| {
741+ if let Some(version) = params.version {
742+ if version != doc.version() {
743+ log::info!("Version ({version}) is out of date for {path:?} (expected ({}), dropping PublishDiagnostic notification", doc.version());
744+ return false;
744745 }
745− true
746− });
746+ }
747+
748+ true
749+ });
747750
748751 if let Some(doc) = doc {
749− let lang_conf = doc.language.clone();
750− let text = doc.text().clone();
751−
752− let mut unchaged_diag_sources_ = Vec::new();
753− if let Some(lang_conf) = &lang_conf {
754− if let Some(old_diagnostics) =
755− self.editor.diagnostics.get(&params.uri)
756− {
757− if !lang_conf.persistent_diagnostic_sources.is_empty() {
758− // Sort diagnostics first by severity and then by line numbers.
759− // Note: The `lsp::DiagnosticSeverity` enum is already defined in decreasing order
760− params
761− .diagnostics
762− .sort_unstable_by_key(|d| (d.severity, d.range.start));
763− }
764− for source in &lang_conf.persistent_diagnostic_sources {
765− let new_diagnostics = params
766− .diagnostics
767− .iter()
768− .filter(|d| d.source.as_ref() == Some(source));
769− let old_diagnostics = old_diagnostics
770− .iter()
771− .filter(|(d, d_server)| {
772− *d_server == server_id
773− && d.source.as_ref() == Some(source)
774− })
775− .map(|(d, _)| d);
776− if new_diagnostics.eq(old_diagnostics) {
777− unchaged_diag_sources_.push(source.clone())
778− }
779− }
780− }
781− }
752+ let lang_conf = doc.language_config();
753+ let text = doc.text();
782754
783− let unchaged_diag_sources = &unchaged_diag_sources_;
784− let diagnostics =
785− params.diagnostics.iter().filter_map(move |diagnostic| {
755+ let diagnostics = params
756+ .diagnostics
757+ .iter()
758+ .filter_map(|diagnostic| {
786759 use helix_core::diagnostic::{Diagnostic, Range, Severity::*};
787760 use lsp::DiagnosticSeverity;
788761
789− if diagnostic.source.as_ref().map_or(false, |source| {
790− unchaged_diag_sources.contains(source)
791− }) {
792− return None;
793− }
794−
795762 // TODO: convert inside server
796763 let start = if let Some(start) = lsp_pos_to_pos(
797− &text,
764+ text,
798765 diagnostic.range.start,
799766 offset_encoding,
800767 ) {
@@ -805,13 +772,14 @@ impl Application {
805772 };
806773
807774 let end = if let Some(end) =
808− lsp_pos_to_pos(&text, diagnostic.range.end, offset_encoding)
775+ lsp_pos_to_pos(text, diagnostic.range.end, offset_encoding)
809776 {
810777 end
811778 } else {
812779 log::warn!("lsp position out of bounds - {:?}", diagnostic);
813780 return None;
814781 };
782+
815783 let severity =
816784 diagnostic.severity.map(|severity| match severity {
817785 DiagnosticSeverity::ERROR => Error,
@@ -824,7 +792,7 @@ impl Application {
824792 ),
825793 });
826794
827− if let Some(lang_conf) = &lang_conf {
795+ if let Some(lang_conf) = lang_conf {
828796 if let Some(severity) = severity {
829797 if severity < lang_conf.diagnostic_severity {
830798 return None;
@@ -863,17 +831,8 @@ impl Application {
863831 Vec::new()
864832 };
865833
866− let ends_at_word = start != end
867− && end != 0
868− && text.get_char(end - 1).map_or(false, char_is_word);
869− let starts_at_word = start != end
870− && text.get_char(start).map_or(false, char_is_word);
871−
872834 Some(Diagnostic {
873835 range: Range { start, end },
874− ends_at_word,
875− starts_at_word,
876− zero_width: start == end,
877836 line: diagnostic.range.start.line as usize,
878837 message: diagnostic.message.clone(),
879838 severity,
@@ -883,33 +842,38 @@ impl Application {
883842 data: diagnostic.data.clone(),
884843 language_server_id: server_id,
885844 })
886− });
845+ })
846+ .collect();
887847
888− doc.replace_diagnostics(diagnostics, unchaged_diag_sources, server_id);
848+ doc.replace_diagnostics(diagnostics, server_id);
889849 }
890850
891− let diagnostics = params.diagnostics.into_iter().map(|d| (d, server_id));
851+ let mut diagnostics = params
852+ .diagnostics
853+ .into_iter()
854+ .map(|d| (d, server_id))
855+ .collect();
892856
893857 // Insert the original lsp::Diagnostics here because we may have no open document
894858 // for diagnosic message and so we can't calculate the exact position.
895859 // When using them later in the diagnostics picker, we calculate them on-demand.
896− let diagnostics = match self.editor.diagnostics.entry(params.uri) {
860+ match self.editor.diagnostics.entry(params.uri) {
897861 Entry::Occupied(o) => {
898862 let current_diagnostics = o.into_mut();
899863 // there may entries of other language servers, which is why we can't overwrite the whole entry
900864 current_diagnostics.retain(|(_, lsp_id)| *lsp_id != server_id);
901− current_diagnostics.extend(diagnostics);
902− current_diagnostics
865+ current_diagnostics.append(&mut diagnostics);
903866 // Sort diagnostics first by severity and then by line numbers.
867+ // Note: The `lsp::DiagnosticSeverity` enum is already defined in decreasing order
868+ current_diagnostics
869+ .sort_unstable_by_key(|(d, _)| (d.severity, d.range.start));
870+ }
871+ Entry::Vacant(v) => {
872+ diagnostics
873+ .sort_unstable_by_key(|(d, _)| (d.severity, d.range.start));
874+ v.insert(diagnostics);
904875 }
905− Entry::Vacant(v) => v.insert(diagnostics.collect()),
906876 };
907−
908− // Sort diagnostics first by severity and then by line numbers.
909− // Note: The `lsp::DiagnosticSeverity` enum is already defined in decreasing order
910− diagnostics.sort_unstable_by_key(|(d, server_id)| {
911− (d.severity, d.range.start, *server_id)
912− });
913877 }
914878 Notification::ShowMessage(params) => {
915879 log::warn!("unhandled window/showMessage: {:?}", params);
@@ -1201,7 +1165,7 @@ impl Application {
12011165
12021166 pub async fn run<S>(&mut self, input_stream: &mut S) -> Result<i32, Error>
12031167 where
1204− S: Stream<Item = std::io::Result<crossterm::event::Event>> + Unpin,
1168+ S: Stream<Item = crossterm::Result<crossterm::event::Event>> + Unpin,
12051169 {
12061170 self.claim_term().await?;
12071171
helix-term/src/args.rs−29
@@ -17,14 +17,12 @@ pub struct Args {
1717 pub log_file: Option<PathBuf>,
1818 pub config_file: Option<PathBuf>,
1919 pub files: Vec<(PathBuf, Position)>,
20− pub working_directory: Option<PathBuf>,
2120}
2221
2322impl Args {
2423 pub fn parse_args() -> Result<Args> {
2524 let mut args = Args::default();
2625 let mut argv = std::env::args().peekable();
27− let mut line_number = 0;
2826
2927 argv.next(); // skip the program, we don't care about that
3028
@@ -61,20 +59,6 @@ impl Args {
6159 Some(path) => args.log_file = Some(path.into()),
6260 None => anyhow::bail!("--log must specify a path to write"),
6361 },
64− "-w" | "--working-dir" => match argv.next().as_deref() {
65− Some(path) => {
66− args.working_directory = if Path::new(path).is_dir() {
67− Some(PathBuf::from(path))
68− } else {
69− anyhow::bail!(
70− "--working-dir specified does not exist or is not a directory"
71− )
72− }
73− }
74− None => {
75− anyhow::bail!("--working-dir must specify an initial working directory")
76− }
77− },
7862 arg if arg.starts_with("--") => {
7963 anyhow::bail!("unexpected double dash argument: {}", arg)
8064 }
@@ -89,13 +73,6 @@ impl Args {
8973 }
9074 }
9175 }
92− arg if arg.starts_with('+') => {
93− let arg = &arg[1..];
94− line_number = match arg.parse::<usize>() {
95− Ok(n) => n.saturating_sub(1),
96− _ => anyhow::bail!("bad line number after +"),
97− };
98− }
9976 arg => args.files.push(parse_file(arg)),
10077 }
10178 }
@@ -105,12 +82,6 @@ impl Args {
10582 args.files.push(parse_file(&arg));
10683 }
10784
108− if let Some(file) = args.files.first_mut() {
109− if line_number != 0 {
110− file.1.row = line_number;
111− }
112− }
113−
11485 Ok(args)
11586 }
11687}
helix-term/src/commands.rs+147−328
@@ -43,6 +43,7 @@ use helix_view::{
4343};
4444
4545use anyhow::{anyhow, bail, ensure, Context as _};
46+use fuzzy_matcher::FuzzyMatcher;
4647use insert::*;
4748use movement::Movement;
4849
@@ -59,14 +60,9 @@ use crate::{
5960};
6061
6162use crate::job::{self, Jobs};
62−use futures_util::{stream::FuturesUnordered, TryStreamExt};
63−use std::{
64− collections::{HashMap, HashSet},
65− fmt,
66− future::Future,
67− io::Read,
68− num::NonZeroUsize,
69−};
63+use futures_util::{stream::FuturesUnordered, StreamExt, TryStreamExt};
64+use std::{collections::HashMap, fmt, future::Future};
65+use std::{collections::HashSet, num::NonZeroUsize};
7066
7167use std::{
7268 borrow::Cow,
@@ -75,11 +71,11 @@ use std::{
7571
7672use once_cell::sync::Lazy;
7773use serde::de::{self, Deserialize, Deserializer};
78−use url::Url;
7974
8075use grep_regex::RegexMatcherBuilder;
8176use grep_searcher::{sinks, BinaryDetection, SearcherBuilder};
8277use ignore::{DirEntry, WalkBuilder, WalkState};
78+use tokio_stream::wrappers::UnboundedReceiverStream;
8379
8480pub type OnKeyCallback = Box<dyn FnOnce(&mut Context, KeyEvent)>;
8581
@@ -337,7 +333,7 @@ impl MappableCommand {
337333 goto_implementation, "Goto implementation",
338334 goto_file_start, "Goto line number <n> else file start",
339335 goto_file_end, "Goto file end",
340− goto_file, "Goto files/URLs in selection",
336+ goto_file, "Goto files in selection",
341337 goto_file_hsplit, "Goto files in selection (hsplit)",
342338 goto_file_vsplit, "Goto files in selection (vsplit)",
343339 goto_reference, "Goto references",
@@ -990,7 +986,6 @@ fn align_selections(cx: &mut Context) {
990986
991987 let transaction = Transaction::change(doc.text(), changes.into_iter());
992988 doc.apply(&transaction, view.id);
993− exit_select_mode(cx);
994989}
995990
996991fn goto_window(cx: &mut Context, align: Align) {
@@ -1165,10 +1160,6 @@ fn goto_file_impl(cx: &mut Context, action: Action) {
11651160 let (view, doc) = current_ref!(cx.editor);
11661161 let text = doc.text();
11671162 let selections = doc.selection(view.id);
1168− let rel_path = doc
1169− .relative_path()
1170− .map(|path| path.parent().unwrap().to_path_buf())
1171− .unwrap_or_default();
11721163 let mut paths: Vec<_> = selections
11731164 .iter()
11741165 .map(|r| text.slice(r.from()..r.to()).to_string())
@@ -1196,80 +1187,16 @@ fn goto_file_impl(cx: &mut Context, action: Action) {
11961187 .to_string(),
11971188 );
11981189 }
1199−
12001190 for sel in paths {
12011191 let p = sel.trim();
1202− if p.is_empty() {
1203− continue;
1204− }
1205−
1206− if let Ok(url) = Url::parse(p) {
1207− return open_url(cx, url, action);
1208− }
1209−
1210− let path = &rel_path.join(p);
1211− if path.is_dir() {
1212− let picker = ui::file_picker(path.into(), &cx.editor.config());
1213− cx.push_layer(Box::new(overlaid(picker)));
1214− } else if let Err(e) = cx.editor.open(path, action) {
1215− cx.editor.set_error(format!("Open file failed: {:?}", e));
1216− }
1217− }
1218−}
1219−
1220−/// Opens the given url. If the URL points to a valid textual file it is open in helix.
1221−// Otherwise, the file is open using external program.
1222−fn open_url(cx: &mut Context, url: Url, action: Action) {
1223− let doc = doc!(cx.editor);
1224− let rel_path = doc
1225− .relative_path()
1226− .map(|path| path.parent().unwrap().to_path_buf())
1227− .unwrap_or_default();
1228−
1229− if url.scheme() != "file" {
1230− return open_external_url(cx, url);
1231− }
1232−
1233− let content_type = std::fs::File::open(url.path()).and_then(|file| {
1234− // Read up to 1kb to detect the content type
1235− let mut read_buffer = Vec::new();
1236− let n = file.take(1024).read_to_end(&mut read_buffer)?;
1237− Ok(content_inspector::inspect(&read_buffer[..n]))
1238− });
1239−
1240− // we attempt to open binary files - files that can't be open in helix - using external
1241− // program as well, e.g. pdf files or images
1242− match content_type {
1243− Ok(content_inspector::ContentType::BINARY) => open_external_url(cx, url),
1244− Ok(_) | Err(_) => {
1245− let path = &rel_path.join(url.path());
1246− if path.is_dir() {
1247− let picker = ui::file_picker(path.into(), &cx.editor.config());
1248− cx.push_layer(Box::new(overlaid(picker)));
1249− } else if let Err(e) = cx.editor.open(path, action) {
1192+ if !p.is_empty() {
1193+ if let Err(e) = cx.editor.open(&PathBuf::from(p), action) {
12501194 cx.editor.set_error(format!("Open file failed: {:?}", e));
12511195 }
12521196 }
12531197 }
12541198}
12551199
1256−/// Opens URL in external program.
1257−fn open_external_url(cx: &mut Context, url: Url) {
1258− let commands = open::commands(url.as_str());
1259− cx.jobs.callback(async {
1260− for cmd in commands {
1261− let mut command = tokio::process::Command::new(cmd.get_program());
1262− command.args(cmd.get_args());
1263− if command.output().await.is_ok() {
1264− return Ok(job::Callback::Editor(Box::new(|_| {})));
1265− }
1266− }
1267− Ok(job::Callback::Editor(Box::new(move |editor| {
1268− editor.set_error("Opening URL in external program failed")
1269− })))
1270− });
1271−}
1272−
12731200fn extend_word_impl<F>(cx: &mut Context, extend_fn: F)
12741201where
12751202 F: Fn(RopeSlice, Range, usize) -> Range,
@@ -1318,65 +1245,6 @@ fn extend_next_long_word_end(cx: &mut Context) {
13181245 extend_word_impl(cx, movement::move_next_long_word_end)
13191246}
13201247
1321−/// Separate branch to find_char designed only for `<ret>` char.
1322−//
1323−// This is necessary because the one document can have different line endings inside. And we
1324−// cannot predict what character to find when <ret> is pressed. On the current line it can be `lf`
1325−// but on the next line it can be `crlf`. That's why [`find_char_impl`] cannot be applied here.
1326−fn find_char_line_ending(
1327− cx: &mut Context,
1328− count: usize,
1329− direction: Direction,
1330− inclusive: bool,
1331− extend: bool,
1332−) {
1333− let (view, doc) = current!(cx.editor);
1334− let text = doc.text().slice(..);
1335−
1336− let selection = doc.selection(view.id).clone().transform(|range| {
1337− let cursor = range.cursor(text);
1338− let cursor_line = range.cursor_line(text);
1339−
1340− // Finding the line where we're going to find <ret>. Depends mostly on
1341− // `count`, but also takes into account edge cases where we're already at the end
1342− // of a line or the beginning of a line
1343− let find_on_line = match direction {
1344− Direction::Forward => {
1345− let on_edge = line_end_char_index(&text, cursor_line) == cursor;
1346− let line = cursor_line + count - 1 + (on_edge as usize);
1347− if line >= text.len_lines() - 1 {
1348− return range;
1349− } else {
1350− line
1351− }
1352− }
1353− Direction::Backward => {
1354− let on_edge = text.line_to_char(cursor_line) == cursor && !inclusive;
1355− let line = cursor_line as isize - (count as isize - 1 + on_edge as isize);
1356− if line <= 0 {
1357− return range;
1358− } else {
1359− line as usize
1360− }
1361− }
1362− };
1363−
1364− let pos = match (direction, inclusive) {
1365− (Direction::Forward, true) => line_end_char_index(&text, find_on_line),
1366− (Direction::Forward, false) => line_end_char_index(&text, find_on_line) - 1,
1367− (Direction::Backward, true) => line_end_char_index(&text, find_on_line - 1),
1368− (Direction::Backward, false) => text.line_to_char(find_on_line),
1369− };
1370−
1371− if extend {
1372− range.put_cursor(text, pos, true)
1373− } else {
1374− Range::point(range.cursor(text)).put_cursor(text, pos, true)
1375− }
1376− });
1377− doc.set_selection(view.id, selection);
1378−}
1379−
13801248fn find_char(cx: &mut Context, direction: Direction, inclusive: bool, extend: bool) {
13811249 // TODO: count is reset to 1 before next key so we move it into the closure here.
13821250 // Would be nice to carry over.
@@ -1390,9 +1258,13 @@ fn find_char(cx: &mut Context, direction: Direction, inclusive: bool, extend: bo
13901258 KeyEvent {
13911259 code: KeyCode::Enter,
13921260 ..
1393− } => {
1394− find_char_line_ending(cx, count, direction, inclusive, extend);
1395− return;
1261+ } =>
1262+ // TODO: this isn't quite correct when CRLF is involved.
1263+ // This hack will work in most cases, since documents don't
1264+ // usually mix line endings. But we should fix it eventually
1265+ // anyway.
1266+ {
1267+ doc!(cx.editor).line_ending.as_str().chars().next().unwrap()
13961268 }
13971269
13981270 KeyEvent {
@@ -1594,7 +1466,6 @@ where
15941466 });
15951467
15961468 doc.apply(&transaction, view.id);
1597− exit_select_mode(cx);
15981469}
15991470
16001471fn switch_case(cx: &mut Context) {
@@ -1836,8 +1707,8 @@ fn select_regex(cx: &mut Context) {
18361707 "select:".into(),
18371708 Some(reg),
18381709 ui::completers::none,
1839− move |cx, regex, event| {
1840− let (view, doc) = current!(cx.editor);
1710+ move |editor, regex, event| {
1711+ let (view, doc) = current!(editor);
18411712 if !matches!(event, PromptEvent::Update | PromptEvent::Validate) {
18421713 return;
18431714 }
@@ -1858,8 +1729,8 @@ fn split_selection(cx: &mut Context) {
18581729 "split:".into(),
18591730 Some(reg),
18601731 ui::completers::none,
1861− move |cx, regex, event| {
1862− let (view, doc) = current!(cx.editor);
1732+ move |editor, regex, event| {
1733+ let (view, doc) = current!(editor);
18631734 if !matches!(event, PromptEvent::Update | PromptEvent::Validate) {
18641735 return;
18651736 }
@@ -2023,14 +1894,12 @@ fn searcher(cx: &mut Context, direction: Direction) {
20231894 .map(|comp| (0.., std::borrow::Cow::Owned(comp.clone())))
20241895 .collect()
20251896 },
2026− move |cx, regex, event| {
2027− if event == PromptEvent::Validate {
2028− cx.editor.registers.last_search_register = reg;
2029− } else if event != PromptEvent::Update {
1897+ move |editor, regex, event| {
1898+ if !matches!(event, PromptEvent::Update | PromptEvent::Validate) {
20301899 return;
20311900 }
20321901 search_impl(
2033− cx.editor,
1902+ editor,
20341903 &contents,
20351904 &regex,
20361905 Movement::Move,
@@ -2045,9 +1914,7 @@ fn searcher(cx: &mut Context, direction: Direction) {
20451914
20461915fn search_next_or_prev_impl(cx: &mut Context, movement: Movement, direction: Direction) {
20471916 let count = cx.count();
2048− let register = cx
2049− .register
2050− .unwrap_or(cx.editor.registers.last_search_register);
1917+ let register = cx.register.unwrap_or('/');
20511918 let config = cx.editor.config();
20521919 let scrolloff = config.scrolloff;
20531920 if let Some(query) = cx.editor.registers.first(register, cx.editor) {
@@ -2115,21 +1982,13 @@ fn search_selection(cx: &mut Context) {
21151982
21161983 let msg = format!("register '{}' set to '{}'", register, &regex);
21171984 match cx.editor.registers.push(register, regex) {
2118− Ok(_) => {
2119− cx.editor.registers.last_search_register = register;
2120− cx.editor.set_status(msg)
2121− }
1985+ Ok(_) => cx.editor.set_status(msg),
21221986 Err(err) => cx.editor.set_error(err.to_string()),
21231987 }
21241988}
21251989
21261990fn make_search_word_bounded(cx: &mut Context) {
2127− // Defaults to the active search register instead `/` to be more ergonomic assuming most people
2128− // would use this command following `search_selection`. This avoids selecting the register
2129− // twice.
2130− let register = cx
2131− .register
2132− .unwrap_or(cx.editor.registers.last_search_register);
1991+ let register = cx.register.unwrap_or('/');
21331992 let regex = match cx.editor.registers.first(register, cx.editor) {
21341993 Some(regex) => regex,
21351994 None => return,
@@ -2155,10 +2014,7 @@ fn make_search_word_bounded(cx: &mut Context) {
21552014
21562015 let msg = format!("register '{}' set to '{}'", register, &new_regex);
21572016 match cx.editor.registers.push(register, new_regex) {
2158− Ok(_) => {
2159− cx.editor.registers.last_search_register = register;
2160− cx.editor.set_status(msg)
2161− }
2017+ Ok(_) => cx.editor.set_status(msg),
21622018 Err(err) => cx.editor.set_error(err.to_string()),
21632019 }
21642020}
@@ -2199,11 +2055,13 @@ fn global_search(cx: &mut Context) {
21992055 }
22002056 }
22012057
2058+ let (all_matches_sx, all_matches_rx) = tokio::sync::mpsc::unbounded_channel::<FileResult>();
22022059 let config = cx.editor.config();
22032060 let smart_case = config.search.smart_case;
22042061 let file_picker_config = config.file_picker.clone();
22052062
22062063 let reg = cx.register.unwrap_or('/');
2064+
22072065 let completions = search_completions(cx, Some(reg));
22082066 ui::regex_prompt(
22092067 cx,
@@ -2216,66 +2074,52 @@ fn global_search(cx: &mut Context) {
22162074 .map(|comp| (0.., std::borrow::Cow::Owned(comp.clone())))
22172075 .collect()
22182076 },
2219− move |cx, regex, event| {
2077+ move |editor, regex, event| {
22202078 if event != PromptEvent::Validate {
22212079 return;
22222080 }
2223− cx.editor.registers.last_search_register = reg;
22242081
2225− let current_path = doc_mut!(cx.editor).path().cloned();
2226− let documents: Vec<_> = cx
2227− .editor
2082+ let documents: Vec<_> = editor
22282083 .documents()
2229− .map(|doc| (doc.path().cloned(), doc.text().to_owned()))
2084+ .map(|doc| (doc.path(), doc.text()))
22302085 .collect();
22312086
22322087 if let Ok(matcher) = RegexMatcherBuilder::new()
22332088 .case_smart(smart_case)
22342089 .build(regex.as_str())
22352090 {
2091+ let searcher = SearcherBuilder::new()
2092+ .binary_detection(BinaryDetection::quit(b'\x00'))
2093+ .build();
2094+
22362095 let search_root = helix_loader::current_working_dir();
22372096 if !search_root.exists() {
2238− cx.editor
2239− .set_error("Current working directory does not exist");
2097+ editor.set_error("Current working directory does not exist");
22402098 return;
22412099 }
22422100
2243− let (picker, injector) = Picker::stream(current_path);
2244−
22452101 let dedup_symlinks = file_picker_config.deduplicate_links;
22462102 let absolute_root = search_root
22472103 .canonicalize()
22482104 .unwrap_or_else(|_| search_root.clone());
2249− let injector_ = injector.clone();
2250−
2251− std::thread::spawn(move || {
2252− let searcher = SearcherBuilder::new()
2253− .binary_detection(BinaryDetection::quit(b'\x00'))
2254− .build();
2255−
2256− let mut walk_builder = WalkBuilder::new(search_root);
2257−
2258− walk_builder
2259− .hidden(file_picker_config.hidden)
2260− .parents(file_picker_config.parents)
2261− .ignore(file_picker_config.ignore)
2262− .follow_links(file_picker_config.follow_symlinks)
2263− .git_ignore(file_picker_config.git_ignore)
2264− .git_global(file_picker_config.git_global)
2265− .git_exclude(file_picker_config.git_exclude)
2266− .max_depth(file_picker_config.max_depth)
2267− .filter_entry(move |entry| {
2268− filter_picker_entry(entry, &absolute_root, dedup_symlinks)
2269− });
2270−
2271− walk_builder
2272− .add_custom_ignore_filename(helix_loader::config_dir().join("ignore"));
2273− walk_builder.add_custom_ignore_filename(".helix/ignore");
2274−
2275− walk_builder.build_parallel().run(|| {
2105+
2106+ WalkBuilder::new(search_root)
2107+ .hidden(file_picker_config.hidden)
2108+ .parents(file_picker_config.parents)
2109+ .ignore(file_picker_config.ignore)
2110+ .follow_links(file_picker_config.follow_symlinks)
2111+ .git_ignore(file_picker_config.git_ignore)
2112+ .git_global(file_picker_config.git_global)
2113+ .git_exclude(file_picker_config.git_exclude)
2114+ .max_depth(file_picker_config.max_depth)
2115+ .filter_entry(move |entry| {
2116+ filter_picker_entry(entry, &absolute_root, dedup_symlinks)
2117+ })
2118+ .build_parallel()
2119+ .run(|| {
22762120 let mut searcher = searcher.clone();
22772121 let matcher = matcher.clone();
2278− let injector = injector_.clone();
2122+ let all_matches_sx = all_matches_sx.clone();
22792123 let documents = &documents;
22802124 Box::new(move |entry: Result<DirEntry, ignore::Error>| -> WalkState {
22812125 let entry = match entry {
@@ -2289,24 +2133,21 @@ fn global_search(cx: &mut Context) {
22892133 _ => return WalkState::Continue,
22902134 };
22912135
2292− let mut stop = false;
22932136 let sink = sinks::UTF8(|line_num, _| {
2294− stop = injector
2295− .push(FileResult::new(entry.path(), line_num as usize - 1))
2296− .is_err();
2137+ all_matches_sx
2138+ .send(FileResult::new(entry.path(), line_num as usize - 1))
2139+ .unwrap();
22972140
2298− Ok(!stop)
2141+ Ok(true)
22992142 });
23002143 let doc = documents.iter().find(|&(doc_path, _)| {
2301− doc_path
2302− .as_ref()
2303− .map_or(false, |doc_path| doc_path == entry.path())
2144+ doc_path.map_or(false, |doc_path| doc_path == entry.path())
23042145 });
23052146
23062147 let result = if let Some((_, doc)) = doc {
23072148 // there is already a buffer for this file
23082149 // search the buffer instead of the file because it's faster
2309− // and captures new edits without requiring a save
2150+ // and captures new edits without requireing a save
23102151 if searcher.multi_line_with_matcher(&matcher) {
23112152 // in this case a continous buffer is required
23122153 // convert the rope to a string
@@ -2330,66 +2171,68 @@ fn global_search(cx: &mut Context) {
23302171 err
23312172 );
23322173 }
2333− if stop {
2334− WalkState::Quit
2335− } else {
2336− WalkState::Continue
2337− }
2174+ WalkState::Continue
23382175 })
23392176 });
2340− });
2341−
2342− cx.jobs.callback(async move {
2343− let call = move |_: &mut Editor, compositor: &mut Compositor| {
2344− let picker = Picker::with_stream(
2345− picker,
2346− injector,
2347− move |cx, FileResult { path, line_num }, action| {
2348− let doc = match cx.editor.open(path, action) {
2349− Ok(id) => doc_mut!(cx.editor, &id),
2350− Err(e) => {
2351− cx.editor.set_error(format!(
2352− "Failed to open file '{}': {}",
2353− path.display(),
2354− e
2355− ));
2356− return;
2357− }
2358− };
2359−
2360− let line_num = *line_num;
2361− let view = view_mut!(cx.editor);
2362− let text = doc.text();
2363− if line_num >= text.len_lines() {
2364− cx.editor.set_error(
2365− "The line you jumped to does not exist anymore because the file has changed.",
2366− );
2367− return;
2368− }
2369− let start = text.line_to_char(line_num);
2370− let end = text.line_to_char((line_num + 1).min(text.len_lines()));
2371−
2372− doc.set_selection(view.id, Selection::single(start, end));
2373− if action.align_view(view, doc.id()) {
2374− align_view(doc, view, Align::Center);
2375− }
2376− },
2377− )
2378− .with_preview(
2379− |_editor, FileResult { path, line_num }| {
2380− Some((path.clone().into(), Some((*line_num, *line_num))))
2381− },
2382− );
2383− compositor.push(Box::new(overlaid(picker)))
2384− };
2385− Ok(Callback::EditorCompositor(Box::new(call)))
2386− })
23872177 } else {
23882178 // Otherwise do nothing
23892179 // log::warn!("Global Search Invalid Pattern")
23902180 }
23912181 },
23922182 );
2183+
2184+ let current_path = doc_mut!(cx.editor).path().cloned();
2185+
2186+ let show_picker = async move {
2187+ let all_matches: Vec<FileResult> =
2188+ UnboundedReceiverStream::new(all_matches_rx).collect().await;
2189+ let call: job::Callback = Callback::EditorCompositor(Box::new(
2190+ move |editor: &mut Editor, compositor: &mut Compositor| {
2191+ if all_matches.is_empty() {
2192+ if !editor.is_err() {
2193+ editor.set_status("No matches found");
2194+ }
2195+ return;
2196+ }
2197+
2198+ let picker = Picker::new(
2199+ all_matches,
2200+ current_path,
2201+ move |cx, FileResult { path, line_num }, action| {
2202+ let doc = match cx.editor.open(path, action) {
2203+ Ok(id) => doc_mut!(cx.editor, &id),
2204+ Err(e) => {
2205+ cx.editor.set_error(format!(
2206+ "Failed to open file '{}': {}",
2207+ path.display(),
2208+ e
2209+ ));
2210+ return;
2211+ }
2212+ };
2213+ let line_num = *line_num;
2214+ let view = view_mut!(cx.editor);
2215+ let text = doc.text();
2216+ if line_num >= text.len_lines() {
2217+ cx.editor.set_error("The line you jumped to does not exist anymore because the file has changed.");
2218+ return;
2219+ }
2220+ let start = text.line_to_char(line_num);
2221+ let end = text.line_to_char((line_num + 1).min(text.len_lines()));
2222+
2223+ doc.set_selection(view.id, Selection::single(start, end));
2224+ if action.align_view(view, doc.id()){
2225+ align_view(doc, view, Align::Center);
2226+ }
2227+ }).with_preview(|_editor, FileResult { path, line_num }| {
2228+ Some((path.clone().into(), Some((*line_num, *line_num))))
2229+ });
2230+ compositor.push(Box::new(overlaid(picker)));
2231+ },
2232+ ));
2233+ Ok(call)
2234+ };
2235+ cx.jobs.callback(show_picker);
23932236}
23942237
23952238enum Extend {
@@ -2744,7 +2587,6 @@ fn file_picker_in_current_buffer_directory(cx: &mut Context) {
27442587 let picker = ui::file_picker(path, &cx.editor.config());
27452588 cx.push_layer(Box::new(overlaid(picker)));
27462589}
2747−
27482590fn file_picker_in_current_directory(cx: &mut Context) {
27492591 let cwd = helix_loader::current_working_dir();
27502592 if !cwd.exists() {
@@ -3053,7 +2895,6 @@ fn insert_with_indent(cx: &mut Context, cursor_fallback: IndentFallbackPos) {
30532895 let indent = indent::indent_for_newline(
30542896 language_config,
30552897 syntax,
3056− &doc.config.load().indent_heuristic,
30572898 &doc.indent_style,
30582899 tab_width,
30592900 text,
@@ -3182,7 +3023,6 @@ fn open(cx: &mut Context, open: Open) {
31823023 let indent = indent::indent_for_newline(
31833024 doc.language_config(),
31843025 doc.syntax(),
3185− &doc.config.load().indent_heuristic,
31863026 &doc.indent_style,
31873027 doc.tab_width(),
31883028 text,
@@ -3722,7 +3562,6 @@ pub mod insert {
37223562 let indent = indent::indent_for_newline(
37233563 doc.language_config(),
37243564 doc.syntax(),
3725− &doc.config.load().indent_heuristic,
37263565 &doc.indent_style,
37273566 doc.tab_width(),
37283567 text,
@@ -3968,12 +3807,12 @@ fn yank(cx: &mut Context) {
39683807}
39693808
39703809fn yank_to_clipboard(cx: &mut Context) {
3971− yank_impl(cx.editor, '+');
3810+ yank_impl(cx.editor, '*');
39723811 exit_select_mode(cx);
39733812}
39743813
39753814fn yank_to_primary_clipboard(cx: &mut Context) {
3976− yank_impl(cx.editor, '*');
3815+ yank_impl(cx.editor, '+');
39773816 exit_select_mode(cx);
39783817}
39793818
@@ -4030,13 +3869,13 @@ fn yank_joined(cx: &mut Context) {
40303869
40313870fn yank_joined_to_clipboard(cx: &mut Context) {
40323871 let line_ending = doc!(cx.editor).line_ending;
4033− yank_joined_impl(cx.editor, line_ending.as_str(), '+');
3872+ yank_joined_impl(cx.editor, line_ending.as_str(), '*');
40343873 exit_select_mode(cx);
40353874}
40363875
40373876fn yank_joined_to_primary_clipboard(cx: &mut Context) {
40383877 let line_ending = doc!(cx.editor).line_ending;
4039− yank_joined_impl(cx.editor, line_ending.as_str(), '*');
3878+ yank_joined_impl(cx.editor, line_ending.as_str(), '+');
40403879 exit_select_mode(cx);
40413880}
40423881
@@ -4053,12 +3892,12 @@ fn yank_primary_selection_impl(editor: &mut Editor, register: char) {
40533892}
40543893
40553894fn yank_main_selection_to_clipboard(cx: &mut Context) {
4056− yank_primary_selection_impl(cx.editor, '+');
3895+ yank_primary_selection_impl(cx.editor, '*');
40573896 exit_select_mode(cx);
40583897}
40593898
40603899fn yank_main_selection_to_primary_clipboard(cx: &mut Context) {
4061− yank_primary_selection_impl(cx.editor, '*');
3900+ yank_primary_selection_impl(cx.editor, '+');
40623901 exit_select_mode(cx);
40633902}
40643903
@@ -4156,27 +3995,22 @@ pub(crate) fn paste_bracketed_value(cx: &mut Context, contents: String) {
41563995 };
41573996 let (view, doc) = current!(cx.editor);
41583997 paste_impl(&[contents], doc, view, paste, count, cx.editor.mode);
4159− exit_select_mode(cx);
41603998}
41613999
41624000fn paste_clipboard_after(cx: &mut Context) {
4163− paste(cx.editor, '+', Paste::After, cx.count());
4164− exit_select_mode(cx);
4001+ paste(cx.editor, '*', Paste::After, cx.count());
41654002}
41664003
41674004fn paste_clipboard_before(cx: &mut Context) {
4168− paste(cx.editor, '+', Paste::Before, cx.count());
4169− exit_select_mode(cx);
4005+ paste(cx.editor, '*', Paste::Before, cx.count());
41704006}
41714007
41724008fn paste_primary_clipboard_after(cx: &mut Context) {
4173− paste(cx.editor, '*', Paste::After, cx.count());
4174− exit_select_mode(cx);
4009+ paste(cx.editor, '+', Paste::After, cx.count());
41754010}
41764011
41774012fn paste_primary_clipboard_before(cx: &mut Context) {
4178− paste(cx.editor, '*', Paste::Before, cx.count());
4179− exit_select_mode(cx);
4013+ paste(cx.editor, '+', Paste::Before, cx.count());
41804014}
41814015
41824016fn replace_with_yanked(cx: &mut Context) {
@@ -4214,13 +4048,11 @@ fn replace_with_yanked_impl(editor: &mut Editor, register: char, count: usize) {
42144048}
42154049
42164050fn replace_selections_with_clipboard(cx: &mut Context) {
4217− replace_with_yanked_impl(cx.editor, '+', cx.count());
4218− exit_select_mode(cx);
4051+ replace_with_yanked_impl(cx.editor, '*', cx.count());
42194052}
42204053
42214054fn replace_selections_with_primary_clipboard(cx: &mut Context) {
4222− replace_with_yanked_impl(cx.editor, '*', cx.count());
4223− exit_select_mode(cx);
4055+ replace_with_yanked_impl(cx.editor, '+', cx.count());
42244056}
42254057
42264058fn paste(editor: &mut Editor, register: char, pos: Paste, count: usize) {
@@ -4238,7 +4070,6 @@ fn paste_after(cx: &mut Context) {
42384070 Paste::After,
42394071 cx.count(),
42404072 );
4241− exit_select_mode(cx);
42424073}
42434074
42444075fn paste_before(cx: &mut Context) {
@@ -4248,7 +4079,6 @@ fn paste_before(cx: &mut Context) {
42484079 Paste::Before,
42494080 cx.count(),
42504081 );
4251− exit_select_mode(cx);
42524082}
42534083
42544084fn get_lines(doc: &Document, view_id: ViewId) -> Vec<usize> {
@@ -4287,7 +4117,6 @@ fn indent(cx: &mut Context) {
42874117 }),
42884118 );
42894119 doc.apply(&transaction, view.id);
4290− exit_select_mode(cx);
42914120}
42924121
42934122fn unindent(cx: &mut Context) {
@@ -4327,7 +4156,6 @@ fn unindent(cx: &mut Context) {
43274156 let transaction = Transaction::change(doc.text(), changes.into_iter());
43284157
43294158 doc.apply(&transaction, view.id);
4330− exit_select_mode(cx);
43314159}
43324160
43334161fn format_selections(cx: &mut Context) {
@@ -4394,9 +4222,10 @@ fn join_selections_impl(cx: &mut Context, select_space: bool) {
43944222 use movement::skip_while;
43954223 let (view, doc) = current!(cx.editor);
43964224 let text = doc.text();
4397− let slice = text.slice(..);
4225+ let slice = doc.text().slice(..);
43984226
43994227 let mut changes = Vec::new();
4228+ let fragment = Tendril::from(" ");
44004229
44014230 for selection in doc.selection(view.id) {
44024231 let (start, mut end) = selection.line_range(slice);
@@ -4412,13 +4241,9 @@ fn join_selections_impl(cx: &mut Context, select_space: bool) {
44124241 let mut end = text.line_to_char(line + 1);
44134242 end = skip_while(slice, end, |ch| matches!(ch, ' ' | '\t')).unwrap_or(end);
44144243
4415− let separator = if end == line_end_char_index(&slice, line + 1) {
4416− // the joining line contains only space-characters => don't include a whitespace when joining
4417− None
4418− } else {
4419− Some(Tendril::from(" "))
4420− };
4421− changes.push((start, end, separator));
4244+ // need to skip from start, not end
4245+ let change = (start, end, Some(fragment.clone()));
4246+ changes.push(change);
44224247 }
44234248 }
44244249
@@ -4430,6 +4255,9 @@ fn join_selections_impl(cx: &mut Context, select_space: bool) {
44304255 changes.sort_unstable_by_key(|(from, _to, _text)| *from);
44314256 changes.dedup();
44324257
4258+ // TODO: joining multiple empty lines should be replaced by a single space.
4259+ // need to merge change ranges that touch
4260+
44334261 // select inserted spaces
44344262 let transaction = if select_space {
44354263 let ranges: SmallVec<_> = changes
@@ -4441,9 +4269,9 @@ fn join_selections_impl(cx: &mut Context, select_space: bool) {
44414269 })
44424270 .collect();
44434271 let selection = Selection::new(ranges, 0);
4444− Transaction::change(text, changes.into_iter()).with_selection(selection)
4272+ Transaction::change(doc.text(), changes.into_iter()).with_selection(selection)
44454273 } else {
4446− Transaction::change(text, changes.into_iter())
4274+ Transaction::change(doc.text(), changes.into_iter())
44474275 };
44484276
44494277 doc.apply(&transaction, view.id);
@@ -4457,8 +4285,8 @@ fn keep_or_remove_selections_impl(cx: &mut Context, remove: bool) {
44574285 if remove { "remove:" } else { "keep:" }.into(),
44584286 Some(reg),
44594287 ui::completers::none,
4460− move |cx, regex, event| {
4461− let (view, doc) = current!(cx.editor);
4288+ move |editor, regex, event| {
4289+ let (view, doc) = current!(editor);
44624290 if !matches!(event, PromptEvent::Update | PromptEvent::Validate) {
44634291 return;
44644292 }
@@ -4975,19 +4803,17 @@ fn transpose_view(cx: &mut Context) {
49754803 cx.editor.transpose_view()
49764804}
49774805
4978−/// Open a new split in the given direction specified by the action.
4979−///
4980−/// Maintain the current view (both the cursor's position and view in document).
4981−fn split(editor: &mut Editor, action: Action) {
4982− let (view, doc) = current!(editor);
4806+// split helper, clear it later
4807+fn split(cx: &mut Context, action: Action) {
4808+ let (view, doc) = current!(cx.editor);
49834809 let id = doc.id();
49844810 let selection = doc.selection(view.id).clone();
49854811 let offset = view.offset;
49864812
4987− editor.switch(id, action);
4813+ cx.editor.switch(id, action);
49884814
49894815 // match the selection in the previous view
4990− let (view, doc) = current!(editor);
4816+ let (view, doc) = current!(cx.editor);
49914817 doc.set_selection(view.id, selection);
49924818 // match the view scroll offset (switch doesn't handle this fully
49934819 // since the selection is only matched after the split)
@@ -4995,7 +4821,7 @@ fn split(editor: &mut Editor, action: Action) {
49954821}
49964822
49974823fn hsplit(cx: &mut Context) {
4998− split(cx.editor, Action::HorizontalSplit);
4824+ split(cx, Action::HorizontalSplit);
49994825}
50004826
50014827fn hsplit_new(cx: &mut Context) {
@@ -5003,7 +4829,7 @@ fn hsplit_new(cx: &mut Context) {
50034829}
50044830
50054831fn vsplit(cx: &mut Context) {
5006− split(cx.editor, Action::VerticalSplit);
4832+ split(cx, Action::VerticalSplit);
50074833}
50084834
50094835fn vsplit_new(cx: &mut Context) {
@@ -5609,18 +5435,12 @@ fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) {
56095435 };
56105436
56115437 // These `usize`s cannot underflow because selection ranges cannot overlap.
5612− let anchor = to
5613− .checked_add_signed(offset)
5614− .expect("Selection ranges cannot overlap")
5615− .checked_sub(deleted_len)
5616− .expect("Selection ranges cannot overlap");
5438+ // Once the MSRV is 1.66.0 (mixed_integer_ops is stabilized), we can use checked
5439+ // arithmetic to assert this.
5440+ let anchor = (to as isize + offset - deleted_len as isize) as usize;
56175441 let new_range = Range::new(anchor, anchor + output_len).with_direction(range.direction());
56185442 ranges.push(new_range);
5619− offset = offset
5620− .checked_add_unsigned(output_len)
5621− .expect("Selection ranges cannot overlap")
5622− .checked_sub_unsigned(deleted_len)
5623− .expect("Selection ranges cannot overlap");
5443+ offset = offset + output_len as isize - deleted_len as isize;
56245444
56255445 changes.push((from, to, Some(output)));
56265446 }
@@ -5759,7 +5579,6 @@ fn increment_impl(cx: &mut Context, increment_direction: IncrementDirection) {
57595579 let transaction = Transaction::change(doc.text(), changes.into_iter());
57605580 let transaction = transaction.with_selection(new_selection);
57615581 doc.apply(&transaction, view.id);
5762− exit_select_mode(cx);
57635582 }
57645583}
57655584
helix-term/src/commands/dap.rs+4−13
@@ -8,7 +8,7 @@ use dap::{StackFrame, Thread, ThreadStates};
88use helix_core::syntax::{DebugArgumentValue, DebugConfigCompletion, DebugTemplate};
99use helix_dap::{self as dap, Client};
1010use helix_lsp::block_on;
11−use helix_view::{editor::Breakpoint, graphics::Margin};
11+use helix_view::editor::Breakpoint;
1212
1313use serde_json::{to_value, Value};
1414use tokio_stream::wrappers::UnboundedReceiverStream;
@@ -339,12 +339,8 @@ fn debug_parameter_prompt(
339339 .to_owned();
340340
341341 let completer = match field_type {
342− "filename" => |editor: &Editor, input: &str| {
343− ui::completers::filename_with_git_ignore(editor, input, false)
344− },
345− "directory" => |editor: &Editor, input: &str| {
346− ui::completers::directory_with_git_ignore(editor, input, false)
347− },
342+ "filename" => ui::completers::filename,
343+ "directory" => ui::completers::directory,
348344 _ => ui::completers::none,
349345 };
350346
@@ -581,12 +577,7 @@ pub fn dap_variables(cx: &mut Context) {
581577 }
582578
583579 let contents = Text::from(tui::text::Text::from(variables));
584− let margin = if cx.editor.popup_border() {
585− Margin::all(1)
586− } else {
587− Margin::none()
588− };
589− let popup = Popup::new("dap-variables", contents).margin(margin);
580+ let popup = Popup::new("dap-variables", contents);
590581 cx.replace_or_push_layer("dap-variables", popup);
591582}
592583
helix-term/src/commands/lsp.rs+2−12
@@ -23,7 +23,6 @@ use helix_core::{
2323use helix_view::{
2424 document::{DocumentInlayHints, DocumentInlayHintsId, Mode},
2525 editor::Action,
26− graphics::Margin,
2726 theme::Style,
2827 Document, View,
2928};
@@ -50,7 +49,7 @@ use std::{
5049/// If there is no configured language server that supports the feature, this displays a status message.
5150/// Using this macro in a context where the editor automatically queries the LSP
5251/// (instead of when the user explicitly does so via a keybind like `gd`)
53−/// will spam the "No configured language server supports \<feature>" status message confusingly.
52+/// will spam the "No configured language server supports <feature>" status message confusingly.
5453#[macro_export]
5554macro_rules! language_server_with_feature {
5655 ($editor:expr, $doc:expr, $feature:expr) => {{
@@ -745,16 +744,7 @@ pub fn code_action(cx: &mut Context) {
745744 });
746745 picker.move_down(); // pre-select the first item
747746
748− let margin = if editor.menu_border() {
749− Margin::vertical(1)
750− } else {
751− Margin::none()
752− };
753−
754− let popup = Popup::new("code-action", picker)
755− .with_scrollbar(false)
756− .margin(margin);
757−
747+ let popup = Popup::new("code-action", picker).with_scrollbar(false);
758748 compositor.replace_or_push("code-action", popup);
759749 };
760750
helix-term/src/commands/typed.rs+661−855
@@ -5,10 +5,7 @@ use crate::job::Job;
55
66use super::*;
77
8−use helix_core::fuzzy::fuzzy_match;
9−use helix_core::indent::MAX_INDENT;
10−use helix_core::{encoding, line_ending, path::get_canonicalized_path, shellwords::Shellwords};
11−use helix_lsp::{OffsetEncoding, Url};
8+use helix_core::{encoding, shellwords::Shellwords};
129use helix_view::document::DEFAULT_LANGUAGE_NAME;
1310use helix_view::editor::{Action, CloseError, ConfigEvent};
1411use serde_json::Value;
@@ -332,16 +329,12 @@ fn write_impl(
332329 path: Option<&Cow<str>>,
333330 force: bool,
334331) -> anyhow::Result<()> {
335− let config = cx.editor.config();
332+ let editor_auto_fmt = cx.editor.config().auto_format;
336333 let jobs = &mut cx.jobs;
337334 let (view, doc) = current!(cx.editor);
338335 let path = path.map(AsRef::as_ref);
339336
340− if config.insert_final_newline {
341− insert_final_newline(doc, view);
342− }
343−
344− let fmt = if config.auto_format {
337+ let fmt = if editor_auto_fmt {
345338 doc.auto_format().map(|fmt| {
346339 let callback = make_format_callback(
347340 doc.id(),
@@ -365,16 +358,6 @@ fn write_impl(
365358 Ok(())
366359}
367360
368−fn insert_final_newline(doc: &mut Document, view: &mut View) {
369− let text = doc.text();
370− if line_ending::get_line_ending(&text.slice(..)).is_none() {
371− let eof = Selection::point(text.len_chars());
372− let insert = Transaction::insert(text, &eof, doc.line_ending.as_str().into());
373− doc.apply(&insert, view.id);
374− doc.append_changes_to_history(view);
375− }
376−}
377−
378361fn write(
379362 cx: &mut compositor::Context,
380363 args: &[Cow<str>],
@@ -477,7 +460,8 @@ fn set_indent_style(
477460 cx.editor.set_status(match style {
478461 Tabs => "tabs".to_owned(),
479462 Spaces(1) => "1 space".to_owned(),
480− Spaces(n) => format!("{} spaces", n),
463+ Spaces(n) if (2..=8).contains(&n) => format!("{} spaces", n),
464+ _ => unreachable!(), // Shouldn't happen.
481465 });
482466 return Ok(());
483467 }
@@ -489,7 +473,7 @@ fn set_indent_style(
489473 Some(arg) => arg
490474 .parse::<u8>()
491475 .ok()
492− .filter(|n| (1..=MAX_INDENT).contains(n))
476+ .filter(|n| (1..=8).contains(n))
493477 .map(Spaces),
494478 _ => None,
495479 };
@@ -574,6 +558,7 @@ fn set_line_ending(
574558
575559 Ok(())
576560}
561+
577562fn earlier(
578563 cx: &mut compositor::Context,
579564 args: &[Cow<str>],
@@ -672,10 +657,11 @@ pub fn write_all_impl(
672657 write_scratch: bool,
673658) -> anyhow::Result<()> {
674659 let mut errors: Vec<&'static str> = Vec::new();
675− let config = cx.editor.config();
660+ let auto_format = cx.editor.config().auto_format;
676661 let jobs = &mut cx.jobs;
677662 let current_view = view!(cx.editor);
678663
664+ // save all documents
679665 let saves: Vec<_> = cx
680666 .editor
681667 .documents
@@ -706,35 +692,32 @@ pub fn write_all_impl(
706692 current_view.id
707693 };
708694
709− Some((doc.id(), target_view))
710− })
711− .collect();
712−
713− for (doc_id, target_view) in saves {
714− let doc = doc_mut!(cx.editor, &doc_id);
695+ let fmt = if auto_format {
696+ doc.auto_format().map(|fmt| {
697+ let callback = make_format_callback(
698+ doc.id(),
699+ doc.version(),
700+ target_view,
701+ fmt,
702+ Some((None, force)),
703+ );
704+ jobs.add(Job::with_callback(callback).wait_before_exiting());
705+ })
706+ } else {
707+ None
708+ };
715709
716− if config.insert_final_newline {
717− insert_final_newline(doc, view_mut!(cx.editor, target_view));
718− }
710+ if fmt.is_none() {
711+ return Some(doc.id());
712+ }
719713
720− let fmt = if config.auto_format {
721− doc.auto_format().map(|fmt| {
722− let callback = make_format_callback(
723− doc_id,
724− doc.version(),
725− target_view,
726− fmt,
727− Some((None, force)),
728− );
729− jobs.add(Job::with_callback(callback).wait_before_exiting());
730− })
731− } else {
732714 None
733− };
715+ })
716+ .collect();
734717
735− if fmt.is_none() {
736− cx.editor.save::<PathBuf>(doc_id, None, force)?;
737− }
718+ // manually call save for the rest of docs that don't have a formatter
719+ for id in saves {
720+ cx.editor.save::<PathBuf>(id, None, force)?;
738721 }
739722
740723 if !errors.is_empty() && !force {
@@ -921,7 +904,7 @@ fn yank_main_selection_to_clipboard(
921904 return Ok(());
922905 }
923906
924− yank_primary_selection_impl(cx.editor, '+');
907+ yank_primary_selection_impl(cx.editor, '*');
925908 Ok(())
926909}
927910
@@ -956,7 +939,7 @@ fn yank_joined_to_clipboard(
956939 let doc = doc!(cx.editor);
957940 let default_sep = Cow::Borrowed(doc.line_ending.as_str());
958941 let separator = args.first().unwrap_or(&default_sep);
959− yank_joined_impl(cx.editor, separator, '+');
942+ yank_joined_impl(cx.editor, separator, '*');
960943 Ok(())
961944}
962945
@@ -969,7 +952,7 @@ fn yank_main_selection_to_primary_clipboard(
969952 return Ok(());
970953 }
971954
972− yank_primary_selection_impl(cx.editor, '*');
955+ yank_primary_selection_impl(cx.editor, '+');
973956 Ok(())
974957}
975958
@@ -985,7 +968,7 @@ fn yank_joined_to_primary_clipboard(
985968 let doc = doc!(cx.editor);
986969 let default_sep = Cow::Borrowed(doc.line_ending.as_str());
987970 let separator = args.first().unwrap_or(&default_sep);
988− yank_joined_impl(cx.editor, separator, '*');
971+ yank_joined_impl(cx.editor, separator, '+');
989972 Ok(())
990973}
991974
@@ -998,7 +981,7 @@ fn paste_clipboard_after(
998981 return Ok(());
999982 }
1000983
1001− paste(cx.editor, '+', Paste::After, 1);
984+ paste(cx.editor, '*', Paste::After, 1);
1002985 Ok(())
1003986}
1004987
@@ -1011,7 +994,7 @@ fn paste_clipboard_before(
1011994 return Ok(());
1012995 }
1013996
1014− paste(cx.editor, '+', Paste::Before, 1);
997+ paste(cx.editor, '*', Paste::Before, 1);
1015998 Ok(())
1016999}
10171000
@@ -1024,7 +1007,7 @@ fn paste_primary_clipboard_after(
10241007 return Ok(());
10251008 }
10261009
1027− paste(cx.editor, '*', Paste::After, 1);
1010+ paste(cx.editor, '+', Paste::After, 1);
10281011 Ok(())
10291012}
10301013
@@ -1037,7 +1020,7 @@ fn paste_primary_clipboard_before(
10371020 return Ok(());
10381021 }
10391022
1040− paste(cx.editor, '*', Paste::Before, 1);
1023+ paste(cx.editor, '+', Paste::Before, 1);
10411024 Ok(())
10421025}
10431026
@@ -1050,7 +1033,7 @@ fn replace_selections_with_clipboard(
10501033 return Ok(());
10511034 }
10521035
1053− replace_with_yanked_impl(cx.editor, '+', 1);
1036+ replace_with_yanked_impl(cx.editor, '*', 1);
10541037 Ok(())
10551038}
10561039
@@ -1063,7 +1046,7 @@ fn replace_selections_with_primary_clipboard(
10631046 return Ok(());
10641047 }
10651048
1066− replace_with_yanked_impl(cx.editor, '*', 1);
1049+ replace_with_yanked_impl(cx.editor, '+', 1);
10671050 Ok(())
10681051}
10691052
@@ -1282,10 +1265,12 @@ fn reload(
12821265 }
12831266
12841267 let scrolloff = cx.editor.config().scrolloff;
1268+ let redraw_handle = cx.editor.redraw_handle.clone();
12851269 let (view, doc) = current!(cx.editor);
1286− doc.reload(view, &cx.editor.diff_providers).map(|_| {
1287− view.ensure_cursor_in_view(doc, scrolloff);
1288− })?;
1270+ doc.reload(view, &cx.editor.diff_providers, redraw_handle)
1271+ .map(|_| {
1272+ view.ensure_cursor_in_view(doc, scrolloff);
1273+ })?;
12891274 if let Some(path) = doc.path() {
12901275 cx.editor
12911276 .language_servers
@@ -1331,7 +1316,8 @@ fn reload_all(
13311316 // Ensure that the view is synced with the document's history.
13321317 view.sync_changes(doc);
13331318
1334− doc.reload(view, &cx.editor.diff_providers)?;
1319+ let redraw_handle = cx.editor.redraw_handle.clone();
1320+ doc.reload(view, &cx.editor.diff_providers, redraw_handle)?;
13351321 if let Some(path) = doc.path() {
13361322 cx.editor
13371323 .language_servers
@@ -1543,84 +1529,6 @@ fn tree_sitter_scopes(
15431529 Ok(())
15441530}
15451531
1546−fn tree_sitter_highlight_name(
1547− cx: &mut compositor::Context,
1548− _args: &[Cow<str>],
1549− event: PromptEvent,
1550−) -> anyhow::Result<()> {
1551− fn find_highlight_at_cursor(
1552− cx: &mut compositor::Context<'_>,
1553− ) -> Option<helix_core::syntax::Highlight> {
1554− use helix_core::syntax::HighlightEvent;
1555−
1556− let (view, doc) = current!(cx.editor);
1557− let syntax = doc.syntax()?;
1558− let text = doc.text().slice(..);
1559− let cursor = doc.selection(view.id).primary().cursor(text);
1560− let byte = text.char_to_byte(cursor);
1561− let node = syntax
1562− .tree()
1563− .root_node()
1564− .descendant_for_byte_range(byte, byte)?;
1565− // Query the same range as the one used in syntax highlighting.
1566− let range = {
1567− // Calculate viewport byte ranges:
1568− let row = text.char_to_line(view.offset.anchor.min(text.len_chars()));
1569− // Saturating subs to make it inclusive zero indexing.
1570− let last_line = text.len_lines().saturating_sub(1);
1571− let height = view.inner_area(doc).height;
1572− let last_visible_line = (row + height as usize).saturating_sub(1).min(last_line);
1573− let start = text.line_to_byte(row.min(last_line));
1574− let end = text.line_to_byte(last_visible_line + 1);
1575−
1576− start..end
1577− };
1578−
1579− let mut highlight = None;
1580−
1581− for event in syntax.highlight_iter(text, Some(range), None) {
1582− match event.unwrap() {
1583− HighlightEvent::Source { start, end }
1584− if start == node.start_byte() && end == node.end_byte() =>
1585− {
1586− return highlight;
1587− }
1588− HighlightEvent::HighlightStart(hl) => {
1589− highlight = Some(hl);
1590− }
1591− _ => (),
1592− }
1593− }
1594−
1595− None
1596− }
1597−
1598− if event != PromptEvent::Validate {
1599− return Ok(());
1600− }
1601−
1602− let Some(highlight) = find_highlight_at_cursor(cx) else {
1603− return Ok(());
1604− };
1605−
1606− let content = cx.editor.theme.scope(highlight.0).to_string();
1607−
1608− let callback = async move {
1609− let call: job::Callback = Callback::EditorCompositor(Box::new(
1610− move |editor: &mut Editor, compositor: &mut Compositor| {
1611− let content = ui::Markdown::new(content, editor.syn_loader.clone());
1612− let popup = Popup::new("hover", content).auto_close(true);
1613− compositor.replace_or_push("hover", popup);
1614− },
1615− ));
1616− Ok(call)
1617− };
1618−
1619− cx.jobs.callback(callback);
1620−
1621− Ok(())
1622−}
1623−
16241532fn vsplit(
16251533 cx: &mut compositor::Context,
16261534 args: &[Cow<str>],
@@ -1630,8 +1538,10 @@ fn vsplit(
16301538 return Ok(());
16311539 }
16321540
1541+ let id = view!(cx.editor).doc;
1542+
16331543 if args.is_empty() {
1634− split(cx.editor, Action::VerticalSplit);
1544+ cx.editor.switch(id, Action::VerticalSplit);
16351545 } else {
16361546 for arg in args {
16371547 cx.editor
@@ -1651,8 +1561,10 @@ fn hsplit(
16511561 return Ok(());
16521562 }
16531563
1564+ let id = view!(cx.editor).doc;
1565+
16541566 if args.is_empty() {
1655− split(cx.editor, Action::HorizontalSplit);
1567+ cx.editor.switch(id, Action::HorizontalSplit);
16561568 } else {
16571569 for arg in args {
16581570 cx.editor
@@ -1767,7 +1679,7 @@ fn tutor(
17671679 let path = helix_loader::runtime_file(Path::new("tutor"));
17681680 cx.editor.open(&path, Action::Replace)?;
17691681 // Unset path to prevent accidentally saving to the original tutor file.
1770− doc_mut!(cx.editor).set_path(None);
1682+ doc_mut!(cx.editor).set_path(None)?;
17711683 Ok(())
17721684}
17731685
@@ -2385,711 +2297,595 @@ fn clear_register(
23852297 Ok(())
23862298}
23872299
2388−fn redraw(
2389− cx: &mut compositor::Context,
2390− _args: &[Cow<str>],
2391− event: PromptEvent,
2392−) -> anyhow::Result<()> {
2393− if event != PromptEvent::Validate {
2394− return Ok(());
2395− }
2396−
2397− let callback = Box::pin(async move {
2398− let call: job::Callback =
2399− job::Callback::EditorCompositor(Box::new(|_editor, compositor| {
2400− compositor.need_full_redraw();
2401− }));
2402−
2403− Ok(call)
2404− });
2405−
2406− cx.jobs.callback(callback);
2407−
2408− Ok(())
2409−}
2410−
2411−fn move_buffer(
2412− cx: &mut compositor::Context,
2413− args: &[Cow<str>],
2414− event: PromptEvent,
2415−) -> anyhow::Result<()> {
2416− if event != PromptEvent::Validate {
2417− return Ok(());
2418− }
2419−
2420− ensure!(args.len() == 1, format!(":move takes one argument"));
2421− let doc = doc!(cx.editor);
2422−
2423− let new_path = get_canonicalized_path(&PathBuf::from(args.first().unwrap().to_string()));
2424− let old_path = doc
2425− .path()
2426− .ok_or_else(|| anyhow!("Scratch buffer cannot be moved. Use :write instead"))?
2427− .clone();
2428− let old_path_as_url = doc.url().unwrap();
2429− let new_path_as_url = Url::from_file_path(&new_path).unwrap();
2430−
2431− let edits: Vec<(
2432− helix_lsp::Result<helix_lsp::lsp::WorkspaceEdit>,
2433− OffsetEncoding,
2434− String,
2435− )> = doc
2436− .language_servers()
2437− .map(|lsp| {
2438− (
2439− lsp.prepare_file_rename(&old_path_as_url, &new_path_as_url),
2440− lsp.offset_encoding(),
2441− lsp.name().to_owned(),
2442− )
2443− })
2444− .filter(|(f, _, _)| f.is_some())
2445− .map(|(f, encoding, name)| (helix_lsp::block_on(f.unwrap()), encoding, name))
2446− .collect();
2447−
2448− for (lsp_reply, encoding, name) in edits {
2449− match lsp_reply {
2450− Ok(edit) => {
2451− if let Err(e) = apply_workspace_edit(cx.editor, encoding, &edit) {
2452− log::error!(
2453− ":move command failed to apply edits from lsp {}: {:?}",
2454− name,
2455− e
2456− );
2457− };
2458− }
2459− Err(e) => {
2460− log::error!("LSP {} failed to treat willRename request: {:?}", name, e);
2461− }
2462− };
2463− }
2464−
2465− let doc = doc_mut!(cx.editor);
2466−
2467− doc.set_path(Some(new_path.as_path()));
2468− if let Err(e) = std::fs::rename(&old_path, &new_path) {
2469− doc.set_path(Some(old_path.as_path()));
2470− bail!("Could not move file: {}", e);
2471− };
2472−
2473− doc.language_servers().for_each(|lsp| {
2474− lsp.did_file_rename(&old_path_as_url, &new_path_as_url);
2475− });
2476−
2477− cx.editor
2478− .language_servers
2479− .file_event_handler
2480− .file_changed(new_path);
2481−
2482− Ok(())
2483−}
2484−
24852300pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
2486− TypableCommand {
2487− name: "quit",
2488− aliases: &["q"],
2489− doc: "Close the current view.",
2490− fun: quit,
2491− signature: CommandSignature::none(),
2492− },
2493− TypableCommand {
2494− name: "quit!",
2495− aliases: &["q!"],
2496− doc: "Force close the current view, ignoring unsaved changes.",
2497− fun: force_quit,
2498− signature: CommandSignature::none(),
2499− },
2500− TypableCommand {
2501− name: "open",
2502− aliases: &["o"],
2503− doc: "Open a file from disk into the current view.",
2504− fun: open,
2505− signature: CommandSignature::all(completers::filename),
2506− },
2507− TypableCommand {
2508− name: "buffer-close",
2509− aliases: &["bc", "bclose"],
2510− doc: "Close the current buffer.",
2511− fun: buffer_close,
2512− signature: CommandSignature::all(completers::buffer),
2513− },
2514− TypableCommand {
2515− name: "buffer-close!",
2516− aliases: &["bc!", "bclose!"],
2517− doc: "Close the current buffer forcefully, ignoring unsaved changes.",
2518− fun: force_buffer_close,
2519− signature: CommandSignature::all(completers::buffer)
2520− },
2521− TypableCommand {
2522− name: "buffer-close-others",
2523− aliases: &["bco", "bcloseother"],
2524− doc: "Close all buffers but the currently focused one.",
2525− fun: buffer_close_others,
2526− signature: CommandSignature::none(),
2527− },
2528− TypableCommand {
2529− name: "buffer-close-others!",
2530− aliases: &["bco!", "bcloseother!"],
2531− doc: "Force close all buffers but the currently focused one.",
2532− fun: force_buffer_close_others,
2533− signature: CommandSignature::none(),
2534− },
2535− TypableCommand {
2536− name: "buffer-close-all",
2537− aliases: &["bca", "bcloseall"],
2538− doc: "Close all buffers without quitting.",
2539− fun: buffer_close_all,
2540− signature: CommandSignature::none(),
2541− },
2542− TypableCommand {
2543− name: "buffer-close-all!",
2544− aliases: &["bca!", "bcloseall!"],
2545− doc: "Force close all buffers ignoring unsaved changes without quitting.",
2546− fun: force_buffer_close_all,
2547− signature: CommandSignature::none(),
2548− },
2549− TypableCommand {
2550− name: "buffer-next",
2551− aliases: &["bn", "bnext"],
2552− doc: "Goto next buffer.",
2553− fun: buffer_next,
2554− signature: CommandSignature::none(),
2555− },
2556− TypableCommand {
2557− name: "buffer-previous",
2558− aliases: &["bp", "bprev"],
2559− doc: "Goto previous buffer.",
2560− fun: buffer_previous,
2561− signature: CommandSignature::none(),
2562− },
2563− TypableCommand {
2564− name: "write",
2565− aliases: &["w"],
2566− doc: "Write changes to disk. Accepts an optional path (:write some/path.txt)",
2567− fun: write,
2568− signature: CommandSignature::positional(&[completers::filename]),
2569− },
2570− TypableCommand {
2571− name: "write!",
2572− aliases: &["w!"],
2573− doc: "Force write changes to disk creating necessary subdirectories. Accepts an optional path (:write! some/path.txt)",
2574− fun: force_write,
2575− signature: CommandSignature::positional(&[completers::filename]),
2576− },
2577− TypableCommand {
2578− name: "write-buffer-close",
2579− aliases: &["wbc"],
2580− doc: "Write changes to disk and closes the buffer. Accepts an optional path (:write-buffer-close some/path.txt)",
2581− fun: write_buffer_close,
2582− signature: CommandSignature::positional(&[completers::filename]),
2583− },
2584− TypableCommand {
2585− name: "write-buffer-close!",
2586− aliases: &["wbc!"],
2587− doc: "Force write changes to disk creating necessary subdirectories and closes the buffer. Accepts an optional path (:write-buffer-close! some/path.txt)",
2588− fun: force_write_buffer_close,
2589− signature: CommandSignature::positional(&[completers::filename]),
2590− },
2591− TypableCommand {
2592− name: "new",
2593− aliases: &["n"],
2594− doc: "Create a new scratch buffer.",
2595− fun: new_file,
2596− signature: CommandSignature::none(),
2597− },
2598− TypableCommand {
2599− name: "format",
2600− aliases: &["fmt"],
2601− doc: "Format the file using the LSP formatter.",
2602− fun: format,
2603− signature: CommandSignature::none(),
2604− },
2605− TypableCommand {
2606− name: "indent-style",
2607− aliases: &[],
2608− doc: "Set the indentation style for editing. ('t' for tabs or 1-16 for number of spaces.)",
2609− fun: set_indent_style,
2610− signature: CommandSignature::none(),
2611− },
2612− TypableCommand {
2613− name: "line-ending",
2614− aliases: &[],
2615− #[cfg(not(feature = "unicode-lines"))]
2616− doc: "Set the document's default line ending. Options: crlf, lf.",
2617− #[cfg(feature = "unicode-lines")]
2618− doc: "Set the document's default line ending. Options: crlf, lf, cr, ff, nel.",
2619− fun: set_line_ending,
2620− signature: CommandSignature::none(),
2621− },
2622− TypableCommand {
2623− name: "earlier",
2624− aliases: &["ear"],
2625− doc: "Jump back to an earlier point in edit history. Accepts a number of steps or a time span.",
2626− fun: earlier,
2627− signature: CommandSignature::none(),
2628− },
2629− TypableCommand {
2630− name: "later",
2631− aliases: &["lat"],
2632− doc: "Jump to a later point in edit history. Accepts a number of steps or a time span.",
2633− fun: later,
2634− signature: CommandSignature::none(),
2635− },
2636− TypableCommand {
2637− name: "write-quit",
2638− aliases: &["wq", "x"],
2639− doc: "Write changes to disk and close the current view. Accepts an optional path (:wq some/path.txt)",
2640− fun: write_quit,
2641− signature: CommandSignature::positional(&[completers::filename]),
2642− },
2643− TypableCommand {
2644− name: "write-quit!",
2645− aliases: &["wq!", "x!"],
2646− doc: "Write changes to disk and close the current view forcefully. Accepts an optional path (:wq! some/path.txt)",
2647− fun: force_write_quit,
2648− signature: CommandSignature::positional(&[completers::filename]),
2649− },
2650− TypableCommand {
2651− name: "write-all",
2652− aliases: &["wa"],
2653− doc: "Write changes from all buffers to disk.",
2654− fun: write_all,
2655− signature: CommandSignature::none(),
2656− },
2657− TypableCommand {
2658− name: "write-all!",
2659− aliases: &["wa!"],
2660− doc: "Forcefully write changes from all buffers to disk creating necessary subdirectories.",
2661− fun: force_write_all,
2662− signature: CommandSignature::none(),
2663− },
2664− TypableCommand {
2665− name: "write-quit-all",
2666− aliases: &["wqa", "xa"],
2667− doc: "Write changes from all buffers to disk and close all views.",
2668− fun: write_all_quit,
2669− signature: CommandSignature::none(),
2670− },
2671− TypableCommand {
2672− name: "write-quit-all!",
2673− aliases: &["wqa!", "xa!"],
2674− doc: "Write changes from all buffers to disk and close all views forcefully (ignoring unsaved changes).",
2675− fun: force_write_all_quit,
2676− signature: CommandSignature::none(),
2677− },
2678− TypableCommand {
2679− name: "quit-all",
2680− aliases: &["qa"],
2681− doc: "Close all views.",
2682− fun: quit_all,
2683− signature: CommandSignature::none(),
2684− },
2685− TypableCommand {
2686− name: "quit-all!",
2687− aliases: &["qa!"],
2688− doc: "Force close all views ignoring unsaved changes.",
2689− fun: force_quit_all,
2690− signature: CommandSignature::none(),
2691− },
2692− TypableCommand {
2693− name: "cquit",
2694− aliases: &["cq"],
2695− doc: "Quit with exit code (default 1). Accepts an optional integer exit code (:cq 2).",
2696− fun: cquit,
2697− signature: CommandSignature::none(),
2698− },
2699− TypableCommand {
2700− name: "cquit!",
2701− aliases: &["cq!"],
2702− doc: "Force quit with exit code (default 1) ignoring unsaved changes. Accepts an optional integer exit code (:cq! 2).",
2703− fun: force_cquit,
2704− signature: CommandSignature::none(),
2705− },
2706− TypableCommand {
2707− name: "theme",
2708− aliases: &[],
2709− doc: "Change the editor theme (show current theme if no name specified).",
2710− fun: theme,
2711− signature: CommandSignature::positional(&[completers::theme]),
2712− },
2713− TypableCommand {
2714− name: "yank-join",
2715− aliases: &[],
2716− doc: "Yank joined selections. A separator can be provided as first argument. Default value is newline.",
2717− fun: yank_joined,
2718− signature: CommandSignature::none(),
2719− },
2720− TypableCommand {
2721− name: "clipboard-yank",
2722− aliases: &[],
2723− doc: "Yank main selection into system clipboard.",
2724− fun: yank_main_selection_to_clipboard,
2725− signature: CommandSignature::none(),
2726− },
2727− TypableCommand {
2728− name: "clipboard-yank-join",
2729− aliases: &[],
2730− doc: "Yank joined selections into system clipboard. A separator can be provided as first argument. Default value is newline.", // FIXME: current UI can't display long doc.
2731− fun: yank_joined_to_clipboard,
2732− signature: CommandSignature::none(),
2733− },
2734− TypableCommand {
2735− name: "primary-clipboard-yank",
2736− aliases: &[],
2737− doc: "Yank main selection into system primary clipboard.",
2738− fun: yank_main_selection_to_primary_clipboard,
2739− signature: CommandSignature::none(),
2740− },
2741− TypableCommand {
2742− name: "primary-clipboard-yank-join",
2743− aliases: &[],
2744− doc: "Yank joined selections into system primary clipboard. A separator can be provided as first argument. Default value is newline.", // FIXME: current UI can't display long doc.
2745− fun: yank_joined_to_primary_clipboard,
2746− signature: CommandSignature::none(),
2747− },
2748− TypableCommand {
2749− name: "clipboard-paste-after",
2750− aliases: &[],
2751− doc: "Paste system clipboard after selections.",
2752− fun: paste_clipboard_after,
2753− signature: CommandSignature::none(),
2754− },
2755− TypableCommand {
2756− name: "clipboard-paste-before",
2757− aliases: &[],
2758− doc: "Paste system clipboard before selections.",
2759− fun: paste_clipboard_before,
2760− signature: CommandSignature::none(),
2761− },
2762− TypableCommand {
2763− name: "clipboard-paste-replace",
2764− aliases: &[],
2765− doc: "Replace selections with content of system clipboard.",
2766− fun: replace_selections_with_clipboard,
2767− signature: CommandSignature::none(),
2768− },
2769− TypableCommand {
2770− name: "primary-clipboard-paste-after",
2771− aliases: &[],
2772− doc: "Paste primary clipboard after selections.",
2773− fun: paste_primary_clipboard_after,
2774− signature: CommandSignature::none(),
2775− },
2776− TypableCommand {
2777− name: "primary-clipboard-paste-before",
2778− aliases: &[],
2779− doc: "Paste primary clipboard before selections.",
2780− fun: paste_primary_clipboard_before,
2781− signature: CommandSignature::none(),
2782− },
2783− TypableCommand {
2784− name: "primary-clipboard-paste-replace",
2785− aliases: &[],
2786− doc: "Replace selections with content of system primary clipboard.",
2787− fun: replace_selections_with_primary_clipboard,
2788− signature: CommandSignature::none(),
2789− },
2790− TypableCommand {
2791− name: "show-clipboard-provider",
2792− aliases: &[],
2793− doc: "Show clipboard provider name in status bar.",
2794− fun: show_clipboard_provider,
2795− signature: CommandSignature::none(),
2796− },
2797− TypableCommand {
2798− name: "change-current-directory",
2799− aliases: &["cd"],
2800− doc: "Change the current working directory.",
2801− fun: change_current_directory,
2802− signature: CommandSignature::positional(&[completers::directory]),
2803− },
2804− TypableCommand {
2805− name: "show-directory",
2806− aliases: &["pwd"],
2807− doc: "Show the current working directory.",
2808− fun: show_current_directory,
2809− signature: CommandSignature::none(),
2810− },
2811− TypableCommand {
2812− name: "encoding",
2813− aliases: &[],
2814− doc: "Set encoding. Based on `https://encoding.spec.whatwg.org`.",
2815− fun: set_encoding,
2816− signature: CommandSignature::none(),
2817− },
2818− TypableCommand {
2819− name: "character-info",
2820− aliases: &["char"],
2821− doc: "Get info about the character under the primary cursor.",
2822− fun: get_character_info,
2823− signature: CommandSignature::none(),
2824− },
2825− TypableCommand {
2826− name: "reload",
2827− aliases: &["rl"],
2828− doc: "Discard changes and reload from the source file.",
2829− fun: reload,
2830− signature: CommandSignature::none(),
2831− },
2832− TypableCommand {
2833− name: "reload-all",
2834− aliases: &["rla"],
2835− doc: "Discard changes and reload all documents from the source files.",
2836− fun: reload_all,
2837− signature: CommandSignature::none(),
2838− },
2839− TypableCommand {
2840− name: "update",
2841− aliases: &["u"],
2842− doc: "Write changes only if the file has been modified.",
2843− fun: update,
2844− signature: CommandSignature::none(),
2845− },
2846− TypableCommand {
2847− name: "lsp-workspace-command",
2848− aliases: &[],
2849− doc: "Open workspace command picker",
2850− fun: lsp_workspace_command,
2851− signature: CommandSignature::positional(&[completers::lsp_workspace_command]),
2852− },
2853− TypableCommand {
2854− name: "lsp-restart",
2855− aliases: &[],
2856− doc: "Restarts the language servers used by the current doc",
2857− fun: lsp_restart,
2858− signature: CommandSignature::none(),
2859− },
2860− TypableCommand {
2861− name: "lsp-stop",
2862− aliases: &[],
2863− doc: "Stops the language servers that are used by the current doc",
2864− fun: lsp_stop,
2865− signature: CommandSignature::none(),
2866− },
2867− TypableCommand {
2868− name: "tree-sitter-scopes",
2869− aliases: &[],
2870− doc: "Display tree sitter scopes, primarily for theming and development.",
2871− fun: tree_sitter_scopes,
2872− signature: CommandSignature::none(),
2873− },
2874− TypableCommand {
2875− name: "tree-sitter-highlight-name",
2876− aliases: &[],
2877− doc: "Display name of tree-sitter highlight scope under the cursor.",
2878− fun: tree_sitter_highlight_name,
2879− signature: CommandSignature::none(),
2880− },
2881− TypableCommand {
2882− name: "debug-start",
2883− aliases: &["dbg"],
2884− doc: "Start a debug session from a given template with given parameters.",
2885− fun: debug_start,
2886− signature: CommandSignature::none(),
2887− },
2888− TypableCommand {
2889− name: "debug-remote",
2890− aliases: &["dbg-tcp"],
2891− doc: "Connect to a debug adapter by TCP address and start a debugging session from a given template with given parameters.",
2892− fun: debug_remote,
2893− signature: CommandSignature::none(),
2894− },
2895− TypableCommand {
2896− name: "debug-eval",
2897− aliases: &[],
2898− doc: "Evaluate expression in current debug context.",
2899− fun: debug_eval,
2900− signature: CommandSignature::none(),
2901− },
2902− TypableCommand {
2903− name: "vsplit",
2904− aliases: &["vs"],
2905− doc: "Open the file in a vertical split.",
2906− fun: vsplit,
2907− signature: CommandSignature::all(completers::filename)
2908− },
2909− TypableCommand {
2910− name: "vsplit-new",
2911− aliases: &["vnew"],
2912− doc: "Open a scratch buffer in a vertical split.",
2913− fun: vsplit_new,
2914− signature: CommandSignature::none(),
2915− },
2916− TypableCommand {
2917− name: "hsplit",
2918− aliases: &["hs", "sp"],
2919− doc: "Open the file in a horizontal split.",
2920− fun: hsplit,
2921− signature: CommandSignature::all(completers::filename)
2922− },
2923− TypableCommand {
2924− name: "hsplit-new",
2925− aliases: &["hnew"],
2926− doc: "Open a scratch buffer in a horizontal split.",
2927− fun: hsplit_new,
2928− signature: CommandSignature::none(),
2929− },
2930− TypableCommand {
2931− name: "tutor",
2932− aliases: &[],
2933− doc: "Open the tutorial.",
2934− fun: tutor,
2935− signature: CommandSignature::none(),
2936− },
2937− TypableCommand {
2938− name: "goto",
2939− aliases: &["g"],
2940− doc: "Goto line number.",
2941− fun: goto_line_number,
2942− signature: CommandSignature::none(),
2943− },
2944− TypableCommand {
2945− name: "set-language",
2946− aliases: &["lang"],
2947− doc: "Set the language of current buffer (show current language if no value specified).",
2948− fun: language,
2949− signature: CommandSignature::positional(&[completers::language]),
2950− },
2951− TypableCommand {
2952− name: "set-option",
2953− aliases: &["set"],
2954− doc: "Set a config option at runtime.\nFor example to disable smart case search, use `:set search.smart-case false`.",
2955− fun: set_option,
2956− // TODO: Add support for completion of the options value(s), when appropriate.
2957− signature: CommandSignature::positional(&[completers::setting]),
2958− },
2959− TypableCommand {
2960− name: "toggle-option",
2961− aliases: &["toggle"],
2962− doc: "Toggle a boolean config option at runtime.\nFor example to toggle smart case search, use `:toggle search.smart-case`.",
2963− fun: toggle_option,
2964− signature: CommandSignature::positional(&[completers::setting]),
2965− },
2966− TypableCommand {
2967− name: "get-option",
2968− aliases: &["get"],
2969− doc: "Get the current value of a config option.",
2970− fun: get_option,
2971− signature: CommandSignature::positional(&[completers::setting]),
2972− },
2973− TypableCommand {
2974− name: "sort",
2975− aliases: &[],
2976− doc: "Sort ranges in selection.",
2977− fun: sort,
2978− signature: CommandSignature::none(),
2979− },
2980− TypableCommand {
2981− name: "rsort",
2982− aliases: &[],
2983− doc: "Sort ranges in selection in reverse order.",
2984− fun: sort_reverse,
2985− signature: CommandSignature::none(),
2986− },
2987− TypableCommand {
2988− name: "reflow",
2989− aliases: &[],
2990− doc: "Hard-wrap the current selection of lines to a given width.",
2991− fun: reflow,
2992− signature: CommandSignature::none(),
2993− },
2994− TypableCommand {
2995− name: "tree-sitter-subtree",
2996− aliases: &["ts-subtree"],
2997− doc: "Display tree sitter subtree under cursor, primarily for debugging queries.",
2998− fun: tree_sitter_subtree,
2999− signature: CommandSignature::none(),
3000− },
3001− TypableCommand {
3002− name: "config-reload",
3003− aliases: &[],
3004− doc: "Refresh user config.",
3005− fun: refresh_config,
3006− signature: CommandSignature::none(),
3007− },
3008− TypableCommand {
3009− name: "config-open",
3010− aliases: &[],
3011− doc: "Open the user config.toml file.",
3012− fun: open_config,
3013− signature: CommandSignature::none(),
3014− },
3015− TypableCommand {
3016− name: "config-open-workspace",
3017− aliases: &[],
3018− doc: "Open the workspace config.toml file.",
3019− fun: open_workspace_config,
3020− signature: CommandSignature::none(),
3021− },
3022− TypableCommand {
3023− name: "log-open",
3024− aliases: &[],
3025− doc: "Open the helix log file.",
3026− fun: open_log,
3027− signature: CommandSignature::none(),
3028− },
3029− TypableCommand {
3030− name: "insert-output",
3031− aliases: &[],
3032− doc: "Run shell command, inserting output before each selection.",
3033− fun: insert_output,
3034− signature: CommandSignature::none(),
3035− },
3036− TypableCommand {
3037− name: "append-output",
3038− aliases: &[],
3039− doc: "Run shell command, appending output after each selection.",
3040− fun: append_output,
3041− signature: CommandSignature::none(),
3042− },
3043− TypableCommand {
3044− name: "pipe",
3045− aliases: &[],
3046− doc: "Pipe each selection to the shell command.",
3047− fun: pipe,
3048− signature: CommandSignature::none(),
3049− },
3050− TypableCommand {
3051− name: "pipe-to",
3052− aliases: &[],
3053− doc: "Pipe each selection to the shell command, ignoring output.",
3054− fun: pipe_to,
3055− signature: CommandSignature::none(),
3056− },
3057− TypableCommand {
3058− name: "run-shell-command",
3059− aliases: &["sh"],
3060− doc: "Run a shell command",
3061− fun: run_shell_command,
3062− signature: CommandSignature::all(completers::filename)
3063− },
3064− TypableCommand {
3065− name: "reset-diff-change",
3066− aliases: &["diffget", "diffg"],
3067− doc: "Reset the diff change at the cursor position.",
3068− fun: reset_diff_change,
3069− signature: CommandSignature::none(),
3070− },
3071− TypableCommand {
3072− name: "clear-register",
3073− aliases: &[],
3074− doc: "Clear given register. If no argument is provided, clear all registers.",
3075− fun: clear_register,
3076− signature: CommandSignature::none(),
3077− },
3078− TypableCommand {
3079− name: "redraw",
3080− aliases: &[],
3081− doc: "Clear and re-render the whole UI",
3082− fun: redraw,
3083− signature: CommandSignature::none(),
3084− },
3085− TypableCommand {
3086− name: "move",
3087− aliases: &[],
3088− doc: "Move the current buffer and its corresponding file to a different path",
3089− fun: move_buffer,
3090− signature: CommandSignature::positional(&[completers::filename]),
3091− },
3092−];
2301+ TypableCommand {
2302+ name: "quit",
2303+ aliases: &["q"],
2304+ doc: "Close the current view.",
2305+ fun: quit,
2306+ signature: CommandSignature::none(),
2307+ },
2308+ TypableCommand {
2309+ name: "quit!",
2310+ aliases: &["q!"],
2311+ doc: "Force close the current view, ignoring unsaved changes.",
2312+ fun: force_quit,
2313+ signature: CommandSignature::none(),
2314+ },
2315+ TypableCommand {
2316+ name: "open",
2317+ aliases: &["o"],
2318+ doc: "Open a file from disk into the current view.",
2319+ fun: open,
2320+ signature: CommandSignature::all(completers::filename),
2321+ },
2322+ TypableCommand {
2323+ name: "buffer-close",
2324+ aliases: &["bc", "bclose"],
2325+ doc: "Close the current buffer.",
2326+ fun: buffer_close,
2327+ signature: CommandSignature::all(completers::buffer),
2328+ },
2329+ TypableCommand {
2330+ name: "buffer-close!",
2331+ aliases: &["bc!", "bclose!"],
2332+ doc: "Close the current buffer forcefully, ignoring unsaved changes.",
2333+ fun: force_buffer_close,
2334+ signature: CommandSignature::all(completers::buffer)
2335+ },
2336+ TypableCommand {
2337+ name: "buffer-close-others",
2338+ aliases: &["bco", "bcloseother"],
2339+ doc: "Close all buffers but the currently focused one.",
2340+ fun: buffer_close_others,
2341+ signature: CommandSignature::none(),
2342+ },
2343+ TypableCommand {
2344+ name: "buffer-close-others!",
2345+ aliases: &["bco!", "bcloseother!"],
2346+ doc: "Force close all buffers but the currently focused one.",
2347+ fun: force_buffer_close_others,
2348+ signature: CommandSignature::none(),
2349+ },
2350+ TypableCommand {
2351+ name: "buffer-close-all",
2352+ aliases: &["bca", "bcloseall"],
2353+ doc: "Close all buffers without quitting.",
2354+ fun: buffer_close_all,
2355+ signature: CommandSignature::none(),
2356+ },
2357+ TypableCommand {
2358+ name: "buffer-close-all!",
2359+ aliases: &["bca!", "bcloseall!"],
2360+ doc: "Force close all buffers ignoring unsaved changes without quitting.",
2361+ fun: force_buffer_close_all,
2362+ signature: CommandSignature::none(),
2363+ },
2364+ TypableCommand {
2365+ name: "buffer-next",
2366+ aliases: &["bn", "bnext"],
2367+ doc: "Goto next buffer.",
2368+ fun: buffer_next,
2369+ signature: CommandSignature::none(),
2370+ },
2371+ TypableCommand {
2372+ name: "buffer-previous",
2373+ aliases: &["bp", "bprev"],
2374+ doc: "Goto previous buffer.",
2375+ fun: buffer_previous,
2376+ signature: CommandSignature::none(),
2377+ },
2378+ TypableCommand {
2379+ name: "write",
2380+ aliases: &["w"],
2381+ doc: "Write changes to disk. Accepts an optional path (:write some/path.txt)",
2382+ fun: write,
2383+ signature: CommandSignature::positional(&[completers::filename]),
2384+ },
2385+ TypableCommand {
2386+ name: "write!",
2387+ aliases: &["w!"],
2388+ doc: "Force write changes to disk creating necessary subdirectories. Accepts an optional path (:write! some/path.txt)",
2389+ fun: force_write,
2390+ signature: CommandSignature::positional(&[completers::filename]),
2391+ },
2392+ TypableCommand {
2393+ name: "write-buffer-close",
2394+ aliases: &["wbc"],
2395+ doc: "Write changes to disk and closes the buffer. Accepts an optional path (:write-buffer-close some/path.txt)",
2396+ fun: write_buffer_close,
2397+ signature: CommandSignature::positional(&[completers::filename]),
2398+ },
2399+ TypableCommand {
2400+ name: "write-buffer-close!",
2401+ aliases: &["wbc!"],
2402+ doc: "Force write changes to disk creating necessary subdirectories and closes the buffer. Accepts an optional path (:write-buffer-close! some/path.txt)",
2403+ fun: force_write_buffer_close,
2404+ signature: CommandSignature::positional(&[completers::filename]),
2405+ },
2406+ TypableCommand {
2407+ name: "new",
2408+ aliases: &["n"],
2409+ doc: "Create a new scratch buffer.",
2410+ fun: new_file,
2411+ // TODO: This seems to complete with a filename, but doesn't use that filename to
2412+ // set the path of the newly created buffer.
2413+ signature: CommandSignature::positional(&[completers::filename]),
2414+ },
2415+ TypableCommand {
2416+ name: "format",
2417+ aliases: &["fmt"],
2418+ doc: "Format the file using the LSP formatter.",
2419+ fun: format,
2420+ signature: CommandSignature::none(),
2421+ },
2422+ TypableCommand {
2423+ name: "indent-style",
2424+ aliases: &[],
2425+ doc: "Set the indentation style for editing. ('t' for tabs or 1-8 for number of spaces.)",
2426+ fun: set_indent_style,
2427+ signature: CommandSignature::none(),
2428+ },
2429+ TypableCommand {
2430+ name: "line-ending",
2431+ aliases: &[],
2432+ #[cfg(not(feature = "unicode-lines"))]
2433+ doc: "Set the document's default line ending. Options: crlf, lf.",
2434+ #[cfg(feature = "unicode-lines")]
2435+ doc: "Set the document's default line ending. Options: crlf, lf, cr, ff, nel.",
2436+ fun: set_line_ending,
2437+ signature: CommandSignature::none(),
2438+ },
2439+ TypableCommand {
2440+ name: "earlier",
2441+ aliases: &["ear"],
2442+ doc: "Jump back to an earlier point in edit history. Accepts a number of steps or a time span.",
2443+ fun: earlier,
2444+ signature: CommandSignature::none(),
2445+ },
2446+ TypableCommand {
2447+ name: "later",
2448+ aliases: &["lat"],
2449+ doc: "Jump to a later point in edit history. Accepts a number of steps or a time span.",
2450+ fun: later,
2451+ signature: CommandSignature::none(),
2452+ },
2453+ TypableCommand {
2454+ name: "write-quit",
2455+ aliases: &["wq", "x"],
2456+ doc: "Write changes to disk and close the current view. Accepts an optional path (:wq some/path.txt)",
2457+ fun: write_quit,
2458+ signature: CommandSignature::positional(&[completers::filename]),
2459+ },
2460+ TypableCommand {
2461+ name: "write-quit!",
2462+ aliases: &["wq!", "x!"],
2463+ doc: "Write changes to disk and close the current view forcefully. Accepts an optional path (:wq! some/path.txt)",
2464+ fun: force_write_quit,
2465+ signature: CommandSignature::positional(&[completers::filename]),
2466+ },
2467+ TypableCommand {
2468+ name: "write-all",
2469+ aliases: &["wa"],
2470+ doc: "Write changes from all buffers to disk.",
2471+ fun: write_all,
2472+ signature: CommandSignature::none(),
2473+ },
2474+ TypableCommand {
2475+ name: "write-all!",
2476+ aliases: &["wa!"],
2477+ doc: "Forcefully write changes from all buffers to disk creating necessary subdirectories.",
2478+ fun: force_write_all,
2479+ signature: CommandSignature::none(),
2480+ },
2481+ TypableCommand {
2482+ name: "write-quit-all",
2483+ aliases: &["wqa", "xa"],
2484+ doc: "Write changes from all buffers to disk and close all views.",
2485+ fun: write_all_quit,
2486+ signature: CommandSignature::none(),
2487+ },
2488+ TypableCommand {
2489+ name: "write-quit-all!",
2490+ aliases: &["wqa!", "xa!"],
2491+ doc: "Write changes from all buffers to disk and close all views forcefully (ignoring unsaved changes).",
2492+ fun: force_write_all_quit,
2493+ signature: CommandSignature::none(),
2494+ },
2495+ TypableCommand {
2496+ name: "quit-all",
2497+ aliases: &["qa"],
2498+ doc: "Close all views.",
2499+ fun: quit_all,
2500+ signature: CommandSignature::none(),
2501+ },
2502+ TypableCommand {
2503+ name: "quit-all!",
2504+ aliases: &["qa!"],
2505+ doc: "Force close all views ignoring unsaved changes.",
2506+ fun: force_quit_all,
2507+ signature: CommandSignature::none(),
2508+ },
2509+ TypableCommand {
2510+ name: "cquit",
2511+ aliases: &["cq"],
2512+ doc: "Quit with exit code (default 1). Accepts an optional integer exit code (:cq 2).",
2513+ fun: cquit,
2514+ signature: CommandSignature::none(),
2515+ },
2516+ TypableCommand {
2517+ name: "cquit!",
2518+ aliases: &["cq!"],
2519+ doc: "Force quit with exit code (default 1) ignoring unsaved changes. Accepts an optional integer exit code (:cq! 2).",
2520+ fun: force_cquit,
2521+ signature: CommandSignature::none(),
2522+ },
2523+ TypableCommand {
2524+ name: "theme",
2525+ aliases: &[],
2526+ doc: "Change the editor theme (show current theme if no name specified).",
2527+ fun: theme,
2528+ signature: CommandSignature::positional(&[completers::theme]),
2529+ },
2530+ TypableCommand {
2531+ name: "yank-join",
2532+ aliases: &[],
2533+ doc: "Yank joined selections. A separator can be provided as first argument. Default value is newline.",
2534+ fun: yank_joined,
2535+ signature: CommandSignature::none(),
2536+ },
2537+ TypableCommand {
2538+ name: "clipboard-yank",
2539+ aliases: &[],
2540+ doc: "Yank main selection into system clipboard.",
2541+ fun: yank_main_selection_to_clipboard,
2542+ signature: CommandSignature::none(),
2543+ },
2544+ TypableCommand {
2545+ name: "clipboard-yank-join",
2546+ aliases: &[],
2547+ doc: "Yank joined selections into system clipboard. A separator can be provided as first argument. Default value is newline.", // FIXME: current UI can't display long doc.
2548+ fun: yank_joined_to_clipboard,
2549+ signature: CommandSignature::none(),
2550+ },
2551+ TypableCommand {
2552+ name: "primary-clipboard-yank",
2553+ aliases: &[],
2554+ doc: "Yank main selection into system primary clipboard.",
2555+ fun: yank_main_selection_to_primary_clipboard,
2556+ signature: CommandSignature::none(),
2557+ },
2558+ TypableCommand {
2559+ name: "primary-clipboard-yank-join",
2560+ aliases: &[],
2561+ doc: "Yank joined selections into system primary clipboard. A separator can be provided as first argument. Default value is newline.", // FIXME: current UI can't display long doc.
2562+ fun: yank_joined_to_primary_clipboard,
2563+ signature: CommandSignature::none(),
2564+ },
2565+ TypableCommand {
2566+ name: "clipboard-paste-after",
2567+ aliases: &[],
2568+ doc: "Paste system clipboard after selections.",
2569+ fun: paste_clipboard_after,
2570+ signature: CommandSignature::none(),
2571+ },
2572+ TypableCommand {
2573+ name: "clipboard-paste-before",
2574+ aliases: &[],
2575+ doc: "Paste system clipboard before selections.",
2576+ fun: paste_clipboard_before,
2577+ signature: CommandSignature::none(),
2578+ },
2579+ TypableCommand {
2580+ name: "clipboard-paste-replace",
2581+ aliases: &[],
2582+ doc: "Replace selections with content of system clipboard.",
2583+ fun: replace_selections_with_clipboard,
2584+ signature: CommandSignature::none(),
2585+ },
2586+ TypableCommand {
2587+ name: "primary-clipboard-paste-after",
2588+ aliases: &[],
2589+ doc: "Paste primary clipboard after selections.",
2590+ fun: paste_primary_clipboard_after,
2591+ signature: CommandSignature::none(),
2592+ },
2593+ TypableCommand {
2594+ name: "primary-clipboard-paste-before",
2595+ aliases: &[],
2596+ doc: "Paste primary clipboard before selections.",
2597+ fun: paste_primary_clipboard_before,
2598+ signature: CommandSignature::none(),
2599+ },
2600+ TypableCommand {
2601+ name: "primary-clipboard-paste-replace",
2602+ aliases: &[],
2603+ doc: "Replace selections with content of system primary clipboard.",
2604+ fun: replace_selections_with_primary_clipboard,
2605+ signature: CommandSignature::none(),
2606+ },
2607+ TypableCommand {
2608+ name: "show-clipboard-provider",
2609+ aliases: &[],
2610+ doc: "Show clipboard provider name in status bar.",
2611+ fun: show_clipboard_provider,
2612+ signature: CommandSignature::none(),
2613+ },
2614+ TypableCommand {
2615+ name: "change-current-directory",
2616+ aliases: &["cd"],
2617+ doc: "Change the current working directory.",
2618+ fun: change_current_directory,
2619+ signature: CommandSignature::positional(&[completers::directory]),
2620+ },
2621+ TypableCommand {
2622+ name: "show-directory",
2623+ aliases: &["pwd"],
2624+ doc: "Show the current working directory.",
2625+ fun: show_current_directory,
2626+ signature: CommandSignature::none(),
2627+ },
2628+ TypableCommand {
2629+ name: "encoding",
2630+ aliases: &[],
2631+ doc: "Set encoding. Based on `https://encoding.spec.whatwg.org`.",
2632+ fun: set_encoding,
2633+ signature: CommandSignature::none(),
2634+ },
2635+ TypableCommand {
2636+ name: "character-info",
2637+ aliases: &["char"],
2638+ doc: "Get info about the character under the primary cursor.",
2639+ fun: get_character_info,
2640+ signature: CommandSignature::none(),
2641+ },
2642+ TypableCommand {
2643+ name: "reload",
2644+ aliases: &["rl"],
2645+ doc: "Discard changes and reload from the source file.",
2646+ fun: reload,
2647+ signature: CommandSignature::none(),
2648+ },
2649+ TypableCommand {
2650+ name: "reload-all",
2651+ aliases: &["rla"],
2652+ doc: "Discard changes and reload all documents from the source files.",
2653+ fun: reload_all,
2654+ signature: CommandSignature::none(),
2655+ },
2656+ TypableCommand {
2657+ name: "update",
2658+ aliases: &["u"],
2659+ doc: "Write changes only if the file has been modified.",
2660+ fun: update,
2661+ signature: CommandSignature::none(),
2662+ },
2663+ TypableCommand {
2664+ name: "lsp-workspace-command",
2665+ aliases: &[],
2666+ doc: "Open workspace command picker",
2667+ fun: lsp_workspace_command,
2668+ signature: CommandSignature::positional(&[completers::lsp_workspace_command]),
2669+ },
2670+ TypableCommand {
2671+ name: "lsp-restart",
2672+ aliases: &[],
2673+ doc: "Restarts the language servers used by the current doc",
2674+ fun: lsp_restart,
2675+ signature: CommandSignature::none(),
2676+ },
2677+ TypableCommand {
2678+ name: "lsp-stop",
2679+ aliases: &[],
2680+ doc: "Stops the language servers that are used by the current doc",
2681+ fun: lsp_stop,
2682+ signature: CommandSignature::none(),
2683+ },
2684+ TypableCommand {
2685+ name: "tree-sitter-scopes",
2686+ aliases: &[],
2687+ doc: "Display tree sitter scopes, primarily for theming and development.",
2688+ fun: tree_sitter_scopes,
2689+ signature: CommandSignature::none(),
2690+ },
2691+ TypableCommand {
2692+ name: "debug-start",
2693+ aliases: &["dbg"],
2694+ doc: "Start a debug session from a given template with given parameters.",
2695+ fun: debug_start,
2696+ signature: CommandSignature::none(),
2697+ },
2698+ TypableCommand {
2699+ name: "debug-remote",
2700+ aliases: &["dbg-tcp"],
2701+ doc: "Connect to a debug adapter by TCP address and start a debugging session from a given template with given parameters.",
2702+ fun: debug_remote,
2703+ signature: CommandSignature::none(),
2704+ },
2705+ TypableCommand {
2706+ name: "debug-eval",
2707+ aliases: &[],
2708+ doc: "Evaluate expression in current debug context.",
2709+ fun: debug_eval,
2710+ signature: CommandSignature::none(),
2711+ },
2712+ TypableCommand {
2713+ name: "vsplit",
2714+ aliases: &["vs"],
2715+ doc: "Open the file in a vertical split.",
2716+ fun: vsplit,
2717+ signature: CommandSignature::all(completers::filename)
2718+ },
2719+ TypableCommand {
2720+ name: "vsplit-new",
2721+ aliases: &["vnew"],
2722+ doc: "Open a scratch buffer in a vertical split.",
2723+ fun: vsplit_new,
2724+ signature: CommandSignature::none(),
2725+ },
2726+ TypableCommand {
2727+ name: "hsplit",
2728+ aliases: &["hs", "sp"],
2729+ doc: "Open the file in a horizontal split.",
2730+ fun: hsplit,
2731+ signature: CommandSignature::all(completers::filename)
2732+ },
2733+ TypableCommand {
2734+ name: "hsplit-new",
2735+ aliases: &["hnew"],
2736+ doc: "Open a scratch buffer in a horizontal split.",
2737+ fun: hsplit_new,
2738+ signature: CommandSignature::none(),
2739+ },
2740+ TypableCommand {
2741+ name: "tutor",
2742+ aliases: &[],
2743+ doc: "Open the tutorial.",
2744+ fun: tutor,
2745+ signature: CommandSignature::none(),
2746+ },
2747+ TypableCommand {
2748+ name: "goto",
2749+ aliases: &["g"],
2750+ doc: "Goto line number.",
2751+ fun: goto_line_number,
2752+ signature: CommandSignature::none(),
2753+ },
2754+ TypableCommand {
2755+ name: "set-language",
2756+ aliases: &["lang"],
2757+ doc: "Set the language of current buffer (show current language if no value specified).",
2758+ fun: language,
2759+ signature: CommandSignature::positional(&[completers::language]),
2760+ },
2761+ TypableCommand {
2762+ name: "set-option",
2763+ aliases: &["set"],
2764+ doc: "Set a config option at runtime.\nFor example to disable smart case search, use `:set search.smart-case false`.",
2765+ fun: set_option,
2766+ // TODO: Add support for completion of the options value(s), when appropriate.
2767+ signature: CommandSignature::positional(&[completers::setting]),
2768+ },
2769+ TypableCommand {
2770+ name: "toggle-option",
2771+ aliases: &["toggle"],
2772+ doc: "Toggle a boolean config option at runtime.\nFor example to toggle smart case search, use `:toggle search.smart-case`.",
2773+ fun: toggle_option,
2774+ signature: CommandSignature::positional(&[completers::setting]),
2775+ },
2776+ TypableCommand {
2777+ name: "get-option",
2778+ aliases: &["get"],
2779+ doc: "Get the current value of a config option.",
2780+ fun: get_option,
2781+ signature: CommandSignature::positional(&[completers::setting]),
2782+ },
2783+ TypableCommand {
2784+ name: "sort",
2785+ aliases: &[],
2786+ doc: "Sort ranges in selection.",
2787+ fun: sort,
2788+ signature: CommandSignature::none(),
2789+ },
2790+ TypableCommand {
2791+ name: "rsort",
2792+ aliases: &[],
2793+ doc: "Sort ranges in selection in reverse order.",
2794+ fun: sort_reverse,
2795+ signature: CommandSignature::none(),
2796+ },
2797+ TypableCommand {
2798+ name: "reflow",
2799+ aliases: &[],
2800+ doc: "Hard-wrap the current selection of lines to a given width.",
2801+ fun: reflow,
2802+ signature: CommandSignature::none(),
2803+ },
2804+ TypableCommand {
2805+ name: "tree-sitter-subtree",
2806+ aliases: &["ts-subtree"],
2807+ doc: "Display tree sitter subtree under cursor, primarily for debugging queries.",
2808+ fun: tree_sitter_subtree,
2809+ signature: CommandSignature::none(),
2810+ },
2811+ TypableCommand {
2812+ name: "config-reload",
2813+ aliases: &[],
2814+ doc: "Refresh user config.",
2815+ fun: refresh_config,
2816+ signature: CommandSignature::none(),
2817+ },
2818+ TypableCommand {
2819+ name: "config-open",
2820+ aliases: &[],
2821+ doc: "Open the user config.toml file.",
2822+ fun: open_config,
2823+ signature: CommandSignature::none(),
2824+ },
2825+ TypableCommand {
2826+ name: "config-open-workspace",
2827+ aliases: &[],
2828+ doc: "Open the workspace config.toml file.",
2829+ fun: open_workspace_config,
2830+ signature: CommandSignature::none(),
2831+ },
2832+ TypableCommand {
2833+ name: "log-open",
2834+ aliases: &[],
2835+ doc: "Open the helix log file.",
2836+ fun: open_log,
2837+ signature: CommandSignature::none(),
2838+ },
2839+ TypableCommand {
2840+ name: "insert-output",
2841+ aliases: &[],
2842+ doc: "Run shell command, inserting output before each selection.",
2843+ fun: insert_output,
2844+ signature: CommandSignature::none(),
2845+ },
2846+ TypableCommand {
2847+ name: "append-output",
2848+ aliases: &[],
2849+ doc: "Run shell command, appending output after each selection.",
2850+ fun: append_output,
2851+ signature: CommandSignature::none(),
2852+ },
2853+ TypableCommand {
2854+ name: "pipe",
2855+ aliases: &[],
2856+ doc: "Pipe each selection to the shell command.",
2857+ fun: pipe,
2858+ signature: CommandSignature::none(),
2859+ },
2860+ TypableCommand {
2861+ name: "pipe-to",
2862+ aliases: &[],
2863+ doc: "Pipe each selection to the shell command, ignoring output.",
2864+ fun: pipe_to,
2865+ signature: CommandSignature::none(),
2866+ },
2867+ TypableCommand {
2868+ name: "run-shell-command",
2869+ aliases: &["sh"],
2870+ doc: "Run a shell command",
2871+ fun: run_shell_command,
2872+ signature: CommandSignature::all(completers::filename)
2873+ },
2874+ TypableCommand {
2875+ name: "reset-diff-change",
2876+ aliases: &["diffget", "diffg"],
2877+ doc: "Reset the diff change at the cursor position.",
2878+ fun: reset_diff_change,
2879+ signature: CommandSignature::none(),
2880+ },
2881+ TypableCommand {
2882+ name: "clear-register",
2883+ aliases: &[],
2884+ doc: "Clear given register. If no argument is provided, clear all registers.",
2885+ fun: clear_register,
2886+ signature: CommandSignature::none(),
2887+ },
2888+ ];
30932889
30942890pub static TYPABLE_COMMAND_MAP: Lazy<HashMap<&'static str, &'static TypableCommand>> =
30952891 Lazy::new(|| {
@@ -3108,18 +2904,28 @@ pub(super) fn command_mode(cx: &mut Context) {
31082904 ":".into(),
31092905 Some(':'),
31102906 |editor: &Editor, input: &str| {
2907+ static FUZZY_MATCHER: Lazy<fuzzy_matcher::skim::SkimMatcherV2> =
2908+ Lazy::new(fuzzy_matcher::skim::SkimMatcherV2::default);
2909+
31112910 let shellwords = Shellwords::from(input);
31122911 let words = shellwords.words();
31132912
31142913 if words.is_empty() || (words.len() == 1 && !shellwords.ends_with_whitespace()) {
3115− fuzzy_match(
3116− input,
3117− TYPABLE_COMMAND_LIST.iter().map(|command| command.name),
3118− false,
3119− )
3120− .into_iter()
3121− .map(|(name, _)| (0.., name.into()))
3122− .collect()
2914+ // If the command has not been finished yet, complete commands.
2915+ let mut matches: Vec<_> = typed::TYPABLE_COMMAND_LIST
2916+ .iter()
2917+ .filter_map(|command| {
2918+ FUZZY_MATCHER
2919+ .fuzzy_match(command.name, input)
2920+ .map(|score| (command.name, score))
2921+ })
2922+ .collect();
2923+
2924+ matches.sort_unstable_by_key(|(_file, score)| std::cmp::Reverse(*score));
2925+ matches
2926+ .into_iter()
2927+ .map(|(name, _)| (0.., name.into()))
2928+ .collect()
31232929 } else {
31242930 // Otherwise, use the command's completer and the last shellword
31252931 // as completion input.
helix-term/src/compositor.rs−12
@@ -16,7 +16,6 @@ pub enum EventResult {
1616}
1717
1818use crate::job::Jobs;
19−use crate::ui::picker;
2019use helix_view::Editor;
2120
2221pub use helix_view::input::Event;
@@ -80,7 +79,6 @@ pub struct Compositor {
8079 area: Rect,
8180
8281 pub(crate) last_picker: Option<Box<dyn Component>>,
83− pub(crate) full_redraw: bool,
8482}
8583
8684impl Compositor {
@@ -89,7 +87,6 @@ impl Compositor {
8987 layers: Vec::new(),
9088 area,
9189 last_picker: None,
92− full_redraw: false,
9390 }
9491 }
9592
@@ -103,11 +100,6 @@ impl Compositor {
103100
104101 /// Add a layer to be rendered in front of all existing layers.
105102 pub fn push(&mut self, mut layer: Box<dyn Component>) {
106− // immediately clear last_picker field to avoid excessive memory
107− // consumption for picker with many items
108− if layer.id() == Some(picker::ID) {
109− self.last_picker = None;
110− }
111103 let size = self.size();
112104 // trigger required_size on init
113105 layer.required_size((size.width, size.height));
@@ -208,10 +200,6 @@ impl Compositor {
208200 .find(|component| component.id() == Some(id))
209201 .and_then(|component| component.as_any_mut().downcast_mut())
210202 }
211−
212− pub fn need_full_redraw(&mut self) {
213− self.full_redraw = true;
214− }
215203}
216204
217205// View casting, taken straight from Cursive
helix-term/src/health.rs+16−44
@@ -181,8 +181,8 @@ pub fn languages_all() -> std::io::Result<()> {
181181 .language
182182 .sort_unstable_by_key(|l| l.language_id.clone());
183183
184− let check_binary = |cmd: Option<&str>| match cmd {
185− Some(cmd) => match which::which(cmd) {
184+ let check_binary = |cmd: Option<String>| match cmd {
185+ Some(cmd) => match which::which(&cmd) {
186186 Ok(_) => column(&format!("✓ {}", cmd), Color::Green),
187187 Err(_) => column(&format!("✘ {}", cmd), Color::Red),
188188 },
@@ -192,15 +192,17 @@ pub fn languages_all() -> std::io::Result<()> {
192192 for lang in &syn_loader_conf.language {
193193 column(&lang.language_id, Color::Reset);
194194
195− let mut cmds = lang.language_servers.iter().filter_map(|ls| {
195+ // TODO multiple language servers (check binary for each supported language server, not just the first)
196+
197+ let lsp = lang.language_servers.first().and_then(|ls| {
196198 syn_loader_conf
197199 .language_server
198200 .get(&ls.name)
199− .map(|config| config.command.as_str())
201+ .map(|config| config.command.clone())
200202 });
201− check_binary(cmds.next());
203+ check_binary(lsp);
202204
203− let dap = lang.debugger.as_ref().map(|dap| dap.command.as_str());
205+ let dap = lang.debugger.as_ref().map(|dap| dap.command.to_string());
204206 check_binary(dap);
205207
206208 for ts_feat in TsFeature::all() {
@@ -211,12 +213,6 @@ pub fn languages_all() -> std::io::Result<()> {
211213 }
212214
213215 writeln!(stdout)?;
214−
215− for cmd in cmds {
216− column("", Color::Reset);
217− check_binary(Some(cmd));
218− writeln!(stdout)?;
219− }
220216 }
221217
222218 Ok(())
@@ -272,12 +268,15 @@ pub fn language(lang_str: String) -> std::io::Result<()> {
272268 }
273269 };
274270
275− probe_protocols(
271+ // TODO multiple language servers
272+ probe_protocol(
276273 "language server",
277− lang.language_servers
278− .iter()
279− .filter_map(|ls| syn_loader_conf.language_server.get(&ls.name))
280− .map(|config| config.command.as_str()),
274+ lang.language_servers.first().and_then(|ls| {
275+ syn_loader_conf
276+ .language_server
277+ .get(&ls.name)
278+ .map(|config| config.command.clone())
279+ }),
281280 )?;
282281
283282 probe_protocol(
@@ -292,33 +291,6 @@ pub fn language(lang_str: String) -> std::io::Result<()> {
292291 Ok(())
293292}
294293
295−/// Display diagnostics about multiple LSPs and DAPs.
296−fn probe_protocols<'a, I: Iterator<Item = &'a str> + 'a>(
297− protocol_name: &str,
298− server_cmds: I,
299−) -> std::io::Result<()> {
300− let stdout = std::io::stdout();
301− let mut stdout = stdout.lock();
302− let mut server_cmds = server_cmds.peekable();
303−
304− write!(stdout, "Configured {}s:", protocol_name)?;
305− if server_cmds.peek().is_none() {
306− writeln!(stdout, "{}", " None".yellow())?;
307− return Ok(());
308− }
309− writeln!(stdout)?;
310−
311− for cmd in server_cmds {
312− let (path, icon) = match which::which(cmd) {
313− Ok(path) => (path.display().to_string().green(), "✓".green()),
314− Err(_) => (format!("'{}' not found in $PATH", cmd).red(), "✘".red()),
315− };
316− writeln!(stdout, " {} {}: {}", icon, cmd, path)?;
317− }
318−
319− Ok(())
320−}
321−
322294/// Display diagnostics about LSP and DAP.
323295fn probe_protocol(protocol_name: &str, server_cmd: Option<String>) -> std::io::Result<()> {
324296 let stdout = std::io::stdout();
helix-term/src/keymap.rs+14−14
@@ -401,14 +401,14 @@ mod tests {
401401 fn merge_partial_keys() {
402402 let keymap = hashmap! {
403403 Mode::Normal => keymap!({ "Normal mode"
404− "i" => normal_mode,
405− "无" => insert_mode,
406− "z" => jump_backward,
407− "g" => { "Merge into goto mode"
408− "$" => goto_line_end,
409− "g" => delete_char_forward,
410− },
411− })
404+ "i" => normal_mode,
405+ "无" => insert_mode,
406+ "z" => jump_backward,
407+ "g" => { "Merge into goto mode"
408+ "$" => goto_line_end,
409+ "g" => delete_char_forward,
410+ },
411+ })
412412 };
413413 let mut merged_keyamp = default();
414414 merge_keys(&mut merged_keyamp, keymap.clone());
@@ -474,13 +474,13 @@ mod tests {
474474 fn order_should_be_set() {
475475 let keymap = hashmap! {
476476 Mode::Normal => keymap!({ "Normal mode"
477− "space" => { ""
478− "s" => { ""
479− "v" => vsplit,
480− "c" => hsplit,
477+ "space" => { ""
478+ "s" => { ""
479+ "v" => vsplit,
480+ "c" => hsplit,
481+ },
481482 },
482− },
483− })
483+ })
484484 };
485485 let mut merged_keyamp = default();
486486 merge_keys(&mut merged_keyamp, keymap.clone());
helix-term/src/main.rs+1−17
@@ -66,8 +66,6 @@ FLAGS:
6666 -V, --version Prints version information
6767 --vsplit Splits all given files vertically into different windows
6868 --hsplit Splits all given files horizontally into different windows
69− -w, --working-dir <path> Specify an initial working directory
70− +N Open the first given file at line number N
7169",
7270 env!("CARGO_PKG_NAME"),
7371 VERSION_AND_GIT_HASH,
@@ -76,7 +74,7 @@ FLAGS:
7674 helix_loader::default_log_file().display(),
7775 );
7876
79− let mut args = Args::parse_args().context("could not parse arguments")?;
77+ let args = Args::parse_args().context("could not parse arguments")?;
8078
8179 helix_loader::initialize_config_file(args.config_file.clone());
8280 helix_loader::initialize_log_file(args.log_file.clone());
@@ -116,20 +114,6 @@ FLAGS:
116114
117115 setup_logging(args.verbosity).context("failed to initialize logging")?;
118116
119− // Before setting the working directory, resolve all the paths in args.files
120− for (path, _) in args.files.iter_mut() {
121− *path = helix_core::path::get_canonicalized_path(path);
122− }
123−
124− // NOTE: Set the working directory early so the correct configuration is loaded. Be aware that
125− // Application::new() depends on this logic so it must be updated if this changes.
126− if let Some(path) = &args.working_directory {
127− helix_loader::set_current_working_dir(path)?;
128− } else if let Some((path, _)) = args.files.first().filter(|p| p.0.is_dir()) {
129− // If the first file is a directory, it will be the working directory unless -w was specified
130− helix_loader::set_current_working_dir(path)?;
131− }
132−
133117 let config = match Config::load_default() {
134118 Ok(config) => config,
135119 Err(ConfigLoadError::Error(err)) if err.kind() == std::io::ErrorKind::NotFound => {
helix-term/src/ui/completion.rs+1−17
@@ -2,7 +2,6 @@ use crate::compositor::{Component, Context, Event, EventResult};
22use helix_view::{
33 document::SavePoint,
44 editor::CompleteAction,
5− graphics::Margin,
65 theme::{Modifier, Style},
76 ViewId,
87};
@@ -327,18 +326,9 @@ impl Completion {
327326 }
328327 };
329328 });
330−
331− let margin = if editor.menu_border() {
332− Margin::vertical(1)
333− } else {
334− Margin::none()
335− };
336−
337329 let popup = Popup::new(Self::ID, menu)
338330 .with_scrollbar(false)
339− .ignore_escape_key(true)
340− .margin(margin);
341−
331+ .ignore_escape_key(true);
342332 let mut completion = Self {
343333 popup,
344334 start_offset,
@@ -579,12 +569,6 @@ impl Component for Completion {
579569 // clear area
580570 let background = cx.editor.theme.get("ui.popup");
581571 surface.clear_with(doc_area, background);
582−
583− if cx.editor.popup_border() {
584− use tui::widgets::{Block, Borders, Widget};
585− Widget::render(Block::default().borders(Borders::ALL), doc_area, surface);
586− }
587−
588572 markdown_doc.render(doc_area, surface, cx);
589573 }
590574}
helix-term/src/ui/document.rs+24−60
@@ -97,8 +97,7 @@ pub fn render_document(
9797 doc: &Document,
9898 offset: ViewPosition,
9999 doc_annotations: &TextAnnotations,
100− syntax_highlight_iter: impl Iterator<Item = HighlightEvent>,
101− overlay_highlight_iter: impl Iterator<Item = HighlightEvent>,
100+ highlight_iter: impl Iterator<Item = HighlightEvent>,
102101 theme: &Theme,
103102 line_decoration: &mut [Box<dyn LineDecoration + '_>],
104103 translated_positions: &mut [TranslatedPosition],
@@ -110,8 +109,7 @@ pub fn render_document(
110109 offset,
111110 &doc.text_format(viewport.width, Some(theme)),
112111 doc_annotations,
113− syntax_highlight_iter,
114− overlay_highlight_iter,
112+ highlight_iter,
115113 theme,
116114 line_decoration,
117115 translated_positions,
@@ -159,8 +157,7 @@ pub fn render_text<'t>(
159157 offset: ViewPosition,
160158 text_fmt: &TextFormat,
161159 text_annotations: &TextAnnotations,
162− syntax_highlight_iter: impl Iterator<Item = HighlightEvent>,
163− overlay_highlight_iter: impl Iterator<Item = HighlightEvent>,
160+ highlight_iter: impl Iterator<Item = HighlightEvent>,
164161 theme: &Theme,
165162 line_decorations: &mut [Box<dyn LineDecoration + '_>],
166163 translated_positions: &mut [TranslatedPosition],
@@ -181,16 +178,10 @@ pub fn render_text<'t>(
181178
182179 let (mut formatter, mut first_visible_char_idx) =
183180 DocumentFormatter::new_at_prev_checkpoint(text, text_fmt, text_annotations, offset.anchor);
184− let mut syntax_styles = StyleIter {
181+ let mut styles = StyleIter {
185182 text_style: renderer.text_style,
186183 active_highlights: Vec::with_capacity(64),
187− highlight_iter: syntax_highlight_iter,
188− theme,
189− };
190− let mut overlay_styles = StyleIter {
191− text_style: Style::default(),
192− active_highlights: Vec::with_capacity(64),
193− highlight_iter: overlay_highlight_iter,
184+ highlight_iter,
194185 theme,
195186 };
196187
@@ -202,10 +193,7 @@ pub fn render_text<'t>(
202193 };
203194 let mut is_in_indent_area = true;
204195 let mut last_line_indent_level = 0;
205− let mut syntax_style_span = syntax_styles
206− .next()
207− .unwrap_or_else(|| (Style::default(), usize::MAX));
208− let mut overlay_style_span = overlay_styles
196+ let mut style_span = styles
209197 .next()
210198 .unwrap_or_else(|| (Style::default(), usize::MAX));
211199
@@ -233,16 +221,9 @@ pub fn render_text<'t>(
233221
234222 // skip any graphemes on visual lines before the block start
235223 if pos.row < row_off {
236− if char_pos >= syntax_style_span.1 {
237− syntax_style_span = if let Some(syntax_style_span) = syntax_styles.next() {
238− syntax_style_span
239− } else {
240− break;
241− }
242− }
243− if char_pos >= overlay_style_span.1 {
244− overlay_style_span = if let Some(overlay_style_span) = overlay_styles.next() {
245− overlay_style_span
224+ if char_pos >= style_span.1 {
225+ style_span = if let Some(style_span) = styles.next() {
226+ style_span
246227 } else {
247228 break;
248229 }
@@ -279,15 +260,8 @@ pub fn render_text<'t>(
279260 }
280261
281262 // acquire the correct grapheme style
282− if char_pos >= syntax_style_span.1 {
283− syntax_style_span = syntax_styles
284− .next()
285− .unwrap_or((Style::default(), usize::MAX));
286− }
287− if char_pos >= overlay_style_span.1 {
288− overlay_style_span = overlay_styles
289− .next()
290− .unwrap_or((Style::default(), usize::MAX));
263+ if char_pos >= style_span.1 {
264+ style_span = styles.next().unwrap_or((Style::default(), usize::MAX));
291265 }
292266 char_pos += grapheme.doc_chars();
293267
@@ -301,25 +275,22 @@ pub fn render_text<'t>(
301275 pos,
302276 );
303277
304− let (syntax_style, overlay_style) =
305− if let GraphemeSource::VirtualText { highlight } = grapheme.source {
306− let mut style = renderer.text_style;
307− if let Some(highlight) = highlight {
308− style = style.patch(theme.highlight(highlight.0))
309− }
310− (style, Style::default())
278+ let grapheme_style = if let GraphemeSource::VirtualText { highlight } = grapheme.source {
279+ let style = renderer.text_style;
280+ if let Some(highlight) = highlight {
281+ style.patch(theme.highlight(highlight.0))
311282 } else {
312− (syntax_style_span.0, overlay_style_span.0)
313− };
283+ style
284+ }
285+ } else {
286+ style_span.0
287+ };
314288
315− let is_virtual = grapheme.is_virtual();
289+ let virt = grapheme.is_virtual();
316290 renderer.draw_grapheme(
317291 grapheme.grapheme,
318− GraphemeStyle {
319− syntax_style,
320− overlay_style,
321− },
322− is_virtual,
292+ grapheme_style,
293+ virt,
323294 &mut last_line_indent_level,
324295 &mut is_in_indent_area,
325296 pos,
@@ -351,11 +322,6 @@ pub struct TextRenderer<'a> {
351322 pub viewport: Rect,
352323}
353324
354−pub struct GraphemeStyle {
355− syntax_style: Style,
356− overlay_style: Style,
357−}
358−
359325impl<'a> TextRenderer<'a> {
360326 pub fn new(
361327 surface: &'a mut Surface,
@@ -429,7 +395,7 @@ impl<'a> TextRenderer<'a> {
429395 pub fn draw_grapheme(
430396 &mut self,
431397 grapheme: Grapheme,
432− grapheme_style: GraphemeStyle,
398+ mut style: Style,
433399 is_virtual: bool,
434400 last_indent_level: &mut usize,
435401 is_in_indent_area: &mut bool,
@@ -439,11 +405,9 @@ impl<'a> TextRenderer<'a> {
439405 let is_whitespace = grapheme.is_whitespace();
440406
441407 // TODO is it correct to apply the whitespace style to all unicode white spaces?
442− let mut style = grapheme_style.syntax_style;
443408 if is_whitespace {
444409 style = style.patch(self.whitespace_style);
445410 }
446− style = style.patch(grapheme_style.overlay_style);
447411
448412 let width = grapheme.width();
449413 let space = if is_virtual { " " } else { &self.space };
helix-term/src/ui/editor.rs+46−91
@@ -43,8 +43,6 @@ pub struct EditorView {
4343 pub(crate) last_insert: (commands::MappableCommand, Vec<InsertEvent>),
4444 pub(crate) completion: Option<Completion>,
4545 spinners: ProgressSpinners,
46− /// Tracks if the terminal window is focused by reaction to terminal focus events
47− terminal_focused: bool,
4846}
4947
5048#[derive(Debug, Clone)]
@@ -73,7 +71,6 @@ impl EditorView {
7371 last_insert: (commands::MappableCommand::normal_mode, Vec::new()),
7472 completion: None,
7573 spinners: ProgressSpinners::default(),
76− terminal_focused: true,
7774 }
7875 }
7976
@@ -124,20 +121,16 @@ impl EditorView {
124121 line_decorations.push(Box::new(line_decoration));
125122 }
126123
127− let syntax_highlights =
124+ let mut highlights =
128125 Self::doc_syntax_highlights(doc, view.offset.anchor, inner.height, theme);
129−
130− let mut overlay_highlights =
131− Self::empty_highlight_iter(doc, view.offset.anchor, inner.height);
132− let overlay_syntax_highlights = Self::overlay_syntax_highlights(
126+ let overlay_highlights = Self::overlay_syntax_highlights(
133127 doc,
134128 view.offset.anchor,
135129 inner.height,
136130 &text_annotations,
137131 );
138− if !overlay_syntax_highlights.is_empty() {
139− overlay_highlights =
140− Box::new(syntax::merge(overlay_highlights, overlay_syntax_highlights));
132+ if !overlay_highlights.is_empty() {
133+ highlights = Box::new(syntax::merge(highlights, overlay_highlights));
141134 }
142135
143136 for diagnostic in Self::doc_diagnostics_highlights(doc, theme) {
@@ -146,28 +139,29 @@ impl EditorView {
146139 if diagnostic.is_empty() {
147140 continue;
148141 }
149− overlay_highlights = Box::new(syntax::merge(overlay_highlights, diagnostic));
142+ highlights = Box::new(syntax::merge(highlights, diagnostic));
150143 }
151144
152− if is_focused {
145+ let highlights: Box<dyn Iterator<Item = HighlightEvent>> = if is_focused {
153146 let highlights = syntax::merge(
154− overlay_highlights,
147+ highlights,
155148 Self::doc_selection_highlights(
156149 editor.mode(),
157150 doc,
158151 view,
159152 theme,
160153 &config.cursor_shape,
161− self.terminal_focused,
162154 ),
163155 );
164156 let focused_view_elements = Self::highlight_focused_view_elements(view, doc, theme);
165157 if focused_view_elements.is_empty() {
166− overlay_highlights = Box::new(highlights)
158+ Box::new(highlights)
167159 } else {
168− overlay_highlights = Box::new(syntax::merge(highlights, focused_view_elements))
160+ Box::new(syntax::merge(highlights, focused_view_elements))
169161 }
170− }
162+ } else {
163+ Box::new(highlights)
164+ };
171165
172166 let gutter_overflow = view.gutter_offset(doc) == 0;
173167 if !gutter_overflow {
@@ -177,7 +171,7 @@ impl EditorView {
177171 view,
178172 view.area,
179173 theme,
180− is_focused & self.terminal_focused,
174+ is_focused,
181175 &mut line_decorations,
182176 );
183177 }
@@ -200,8 +194,7 @@ impl EditorView {
200194 doc,
201195 view.offset,
202196 &text_annotations,
203− syntax_highlights,
204− overlay_highlights,
197+ highlights,
205198 theme,
206199 &mut line_decorations,
207200 &mut translated_positions,
@@ -261,39 +254,27 @@ impl EditorView {
261254 .for_each(|area| surface.set_style(area, ruler_theme))
262255 }
263256
264− fn viewport_byte_range(
265− text: helix_core::RopeSlice,
266− row: usize,
267− height: u16,
268− ) -> std::ops::Range<usize> {
269− // Calculate viewport byte ranges:
270− // Saturating subs to make it inclusive zero indexing.
271− let last_line = text.len_lines().saturating_sub(1);
272− let last_visible_line = (row + height as usize).saturating_sub(1).min(last_line);
273− let start = text.line_to_byte(row.min(last_line));
274− let end = text.line_to_byte(last_visible_line + 1);
275−
276− start..end
277− }
278−
279− pub fn empty_highlight_iter(
257+ pub fn overlay_syntax_highlights(
280258 doc: &Document,
281259 anchor: usize,
282260 height: u16,
283− ) -> Box<dyn Iterator<Item = HighlightEvent>> {
261+ text_annotations: &TextAnnotations,
262+ ) -> Vec<(usize, std::ops::Range<usize>)> {
284263 let text = doc.text().slice(..);
285264 let row = text.char_to_line(anchor.min(text.len_chars()));
286265
287− // Calculate viewport byte ranges:
288− // Saturating subs to make it inclusive zero indexing.
289− let range = Self::viewport_byte_range(text, row, height);
290− Box::new(
291− [HighlightEvent::Source {
292− start: text.byte_to_char(range.start),
293− end: text.byte_to_char(range.end),
294− }]
295− .into_iter(),
296− )
266+ let range = {
267+ // Calculate viewport byte ranges:
268+ // Saturating subs to make it inclusive zero indexing.
269+ let last_line = text.len_lines().saturating_sub(1);
270+ let last_visible_line = (row + height as usize).saturating_sub(1).min(last_line);
271+ let start = text.line_to_byte(row.min(last_line));
272+ let end = text.line_to_byte(last_visible_line + 1);
273+
274+ start..end
275+ };
276+
277+ text_annotations.collect_overlay_highlights(range)
297278 }
298279
299280 /// Get syntax highlights for a document in a view represented by the first line
@@ -308,7 +289,16 @@ impl EditorView {
308289 let text = doc.text().slice(..);
309290 let row = text.char_to_line(anchor.min(text.len_chars()));
310291
311− let range = Self::viewport_byte_range(text, row, height);
292+ let range = {
293+ // Calculate viewport byte ranges:
294+ // Saturating subs to make it inclusive zero indexing.
295+ let last_line = text.len_lines().saturating_sub(1);
296+ let last_visible_line = (row + height as usize).saturating_sub(1).min(last_line);
297+ let start = text.line_to_byte(row.min(last_line));
298+ let end = text.line_to_byte(last_visible_line + 1);
299+
300+ start..end
301+ };
312302
313303 match doc.syntax() {
314304 Some(syntax) => {
@@ -341,20 +331,6 @@ impl EditorView {
341331 }
342332 }
343333
344− pub fn overlay_syntax_highlights(
345− doc: &Document,
346− anchor: usize,
347− height: u16,
348− text_annotations: &TextAnnotations,
349− ) -> Vec<(usize, std::ops::Range<usize>)> {
350− let text = doc.text().slice(..);
351− let row = text.char_to_line(anchor.min(text.len_chars()));
352−
353− let range = Self::viewport_byte_range(text, row, height);
354−
355− text_annotations.collect_overlay_highlights(range)
356− }
357−
358334 /// Get highlight spans for document diagnostics
359335 pub fn doc_diagnostics_highlights(
360336 doc: &Document,
@@ -386,7 +362,7 @@ impl EditorView {
386362 let mut warning_vec = Vec::new();
387363 let mut error_vec = Vec::new();
388364
389− for diagnostic in doc.shown_diagnostics() {
365+ for diagnostic in doc.diagnostics() {
390366 // Separate diagnostics into different Vecs by severity.
391367 let (vec, scope) = match diagnostic.severity {
392368 Some(Severity::Info) => (&mut info_vec, info),
@@ -421,7 +397,6 @@ impl EditorView {
421397 view: &View,
422398 theme: &Theme,
423399 cursor_shape_config: &CursorShapeConfig,
424− is_terminal_focused: bool,
425400 ) -> Vec<(usize, std::ops::Range<usize>)> {
426401 let text = doc.text().slice(..);
427402 let selection = doc.selection(view.id);
@@ -469,7 +444,7 @@ impl EditorView {
469444
470445 // Special-case: cursor at end of the rope.
471446 if range.head == range.anchor && range.head == text.len_chars() {
472− if !selection_is_primary || (cursor_is_block && is_terminal_focused) {
447+ if !selection_is_primary || cursor_is_block {
473448 // Bar and underline cursors are drawn by the terminal
474449 // BUG: If the editor area loses focus while having a bar or
475450 // underline cursor (eg. when a regex prompt has focus) then
@@ -492,17 +467,13 @@ impl EditorView {
492467 cursor_start
493468 };
494469 spans.push((selection_scope, range.anchor..selection_end));
495− // add block cursors
496− // skip primary cursor if terminal is unfocused - crossterm cursor is used in that case
497− if !selection_is_primary || (cursor_is_block && is_terminal_focused) {
470+ if !selection_is_primary || cursor_is_block {
498471 spans.push((cursor_scope, cursor_start..range.head));
499472 }
500473 } else {
501474 // Reverse case.
502475 let cursor_end = next_grapheme_boundary(text, range.head);
503− // add block cursors
504− // skip primary cursor if terminal is unfocused - crossterm cursor is used in that case
505− if !selection_is_primary || (cursor_is_block && is_terminal_focused) {
476+ if !selection_is_primary || cursor_is_block {
506477 spans.push((cursor_scope, range.head..cursor_end));
507478 }
508479 // non block cursors look like they exclude the cursor
@@ -1099,7 +1070,6 @@ impl EditorView {
10991070 let editor = &mut cxt.editor;
11001071
11011072 if let Some((pos, view_id)) = pos_and_view(editor, row, column, true) {
1102− let prev_view_id = view!(editor).id;
11031073 let doc = doc_mut!(editor, &view!(editor, view_id).doc);
11041074
11051075 if modifiers == KeyModifiers::ALT {
@@ -1109,10 +1079,6 @@ impl EditorView {
11091079 doc.set_selection(view_id, Selection::point(pos));
11101080 }
11111081
1112− if view_id != prev_view_id {
1113− self.clear_completion(editor);
1114− }
1115−
11161082 editor.focus(view_id);
11171083 editor.ensure_cursor_in_view(view_id);
11181084
@@ -1406,17 +1372,13 @@ impl Component for EditorView {
14061372
14071373 Event::Mouse(event) => self.handle_mouse_event(event, &mut cx),
14081374 Event::IdleTimeout => self.handle_idle_timeout(&mut cx),
1409− Event::FocusGained => {
1410− self.terminal_focused = true;
1411− EventResult::Consumed(None)
1412− }
1375+ Event::FocusGained => EventResult::Ignored(None),
14131376 Event::FocusLost => {
14141377 if context.editor.config().auto_save {
14151378 if let Err(e) = commands::typed::write_all_impl(context, false, false) {
14161379 context.editor.set_error(format!("{}", e));
14171380 }
14181381 }
1419− self.terminal_focused = false;
14201382 EventResult::Consumed(None)
14211383 }
14221384 }
@@ -1526,15 +1488,8 @@ impl Component for EditorView {
15261488
15271489 fn cursor(&self, _area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
15281490 match editor.cursor() {
1529− // all block cursors are drawn manually
1530− (pos, CursorKind::Block) => {
1531− if self.terminal_focused {
1532− (pos, CursorKind::Hidden)
1533− } else {
1534− // use crossterm cursor when terminal loses focus
1535− (pos, CursorKind::Underline)
1536− }
1537− }
1491+ // All block cursors are drawn manually
1492+ (pos, CursorKind::Block) => (pos, CursorKind::Hidden),
15381493 cursor => cursor,
15391494 }
15401495 }
helix-term/src/ui/fuzzy_match.rsnew file+239
@@ -0,0 +1,239 @@
1+use fuzzy_matcher::skim::SkimMatcherV2 as Matcher;
2+use fuzzy_matcher::FuzzyMatcher;
3+
4+#[cfg(test)]
5+mod test;
6+
7+struct QueryAtom {
8+ kind: QueryAtomKind,
9+ atom: String,
10+ ignore_case: bool,
11+ inverse: bool,
12+}
13+impl QueryAtom {
14+ fn new(atom: &str) -> Option<QueryAtom> {
15+ let mut atom = atom.to_string();
16+ let inverse = atom.starts_with('!');
17+ if inverse {
18+ atom.remove(0);
19+ }
20+
21+ let mut kind = match atom.chars().next() {
22+ Some('^') => QueryAtomKind::Prefix,
23+ Some('\'') => QueryAtomKind::Substring,
24+ _ if inverse => QueryAtomKind::Substring,
25+ _ => QueryAtomKind::Fuzzy,
26+ };
27+
28+ if atom.starts_with(['^', '\'']) {
29+ atom.remove(0);
30+ }
31+
32+ if atom.is_empty() {
33+ return None;
34+ }
35+
36+ if atom.ends_with('$') && !atom.ends_with("\\$") {
37+ atom.pop();
38+ kind = if kind == QueryAtomKind::Prefix {
39+ QueryAtomKind::Exact
40+ } else {
41+ QueryAtomKind::Postfix
42+ }
43+ }
44+
45+ Some(QueryAtom {
46+ kind,
47+ atom: atom.replace('\\', ""),
48+ // not ideal but fuzzy_matches only knows ascii uppercase so more consistent
49+ // to behave the same
50+ ignore_case: kind != QueryAtomKind::Fuzzy
51+ && atom.chars().all(|c| c.is_ascii_lowercase()),
52+ inverse,
53+ })
54+ }
55+
56+ fn indices(&self, matcher: &Matcher, item: &str, indices: &mut Vec<usize>) -> bool {
57+ // for inverse there are no indices to return
58+ // just return whether we matched
59+ if self.inverse {
60+ return self.matches(matcher, item);
61+ }
62+ let buf;
63+ let item = if self.ignore_case {
64+ buf = item.to_ascii_lowercase();
65+ &buf
66+ } else {
67+ item
68+ };
69+ let off = match self.kind {
70+ QueryAtomKind::Fuzzy => {
71+ if let Some((_, fuzzy_indices)) = matcher.fuzzy_indices(item, &self.atom) {
72+ indices.extend_from_slice(&fuzzy_indices);
73+ return true;
74+ } else {
75+ return false;
76+ }
77+ }
78+ QueryAtomKind::Substring => {
79+ if let Some(off) = item.find(&self.atom) {
80+ off
81+ } else {
82+ return false;
83+ }
84+ }
85+ QueryAtomKind::Prefix if item.starts_with(&self.atom) => 0,
86+ QueryAtomKind::Postfix if item.ends_with(&self.atom) => item.len() - self.atom.len(),
87+ QueryAtomKind::Exact if item == self.atom => 0,
88+ _ => return false,
89+ };
90+
91+ indices.extend(off..(off + self.atom.len()));
92+ true
93+ }
94+
95+ fn matches(&self, matcher: &Matcher, item: &str) -> bool {
96+ let buf;
97+ let item = if self.ignore_case {
98+ buf = item.to_ascii_lowercase();
99+ &buf
100+ } else {
101+ item
102+ };
103+ let mut res = match self.kind {
104+ QueryAtomKind::Fuzzy => matcher.fuzzy_match(item, &self.atom).is_some(),
105+ QueryAtomKind::Substring => item.contains(&self.atom),
106+ QueryAtomKind::Prefix => item.starts_with(&self.atom),
107+ QueryAtomKind::Postfix => item.ends_with(&self.atom),
108+ QueryAtomKind::Exact => item == self.atom,
109+ };
110+ if self.inverse {
111+ res = !res;
112+ }
113+ res
114+ }
115+}
116+
117+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
118+enum QueryAtomKind {
119+ /// Item is a fuzzy match of this behaviour
120+ ///
121+ /// Usage: `foo`
122+ Fuzzy,
123+ /// Item contains query atom as a continuous substring
124+ ///
125+ /// Usage `'foo`
126+ Substring,
127+ /// Item starts with query atom
128+ ///
129+ /// Usage: `^foo`
130+ Prefix,
131+ /// Item ends with query atom
132+ ///
133+ /// Usage: `foo$`
134+ Postfix,
135+ /// Item is equal to query atom
136+ ///
137+ /// Usage `^foo$`
138+ Exact,
139+}
140+
141+#[derive(Default)]
142+pub struct FuzzyQuery {
143+ first_fuzzy_atom: Option<String>,
144+ query_atoms: Vec<QueryAtom>,
145+}
146+
147+fn query_atoms(query: &str) -> impl Iterator<Item = &str> + '_ {
148+ let mut saw_backslash = false;
149+ query.split(move |c| {
150+ saw_backslash = match c {
151+ ' ' if !saw_backslash => return true,
152+ '\\' => true,
153+ _ => false,
154+ };
155+ false
156+ })
157+}
158+
159+impl FuzzyQuery {
160+ pub fn refine(&self, query: &str, old_query: &str) -> (FuzzyQuery, bool) {
161+ // TODO: we could be a lot smarter about this
162+ let new_query = Self::new(query);
163+ let mut is_refinement = query.starts_with(old_query);
164+
165+ // if the last atom is an inverse atom adding more text to it
166+ // will actually increase the number of matches and we can not refine
167+ // the matches.
168+ if is_refinement && !self.query_atoms.is_empty() {
169+ let last_idx = self.query_atoms.len() - 1;
170+ if self.query_atoms[last_idx].inverse
171+ && self.query_atoms[last_idx].atom != new_query.query_atoms[last_idx].atom
172+ {
173+ is_refinement = false;
174+ }
175+ }
176+
177+ (new_query, is_refinement)
178+ }
179+
180+ pub fn new(query: &str) -> FuzzyQuery {
181+ let mut first_fuzzy_query = None;
182+ let query_atoms = query_atoms(query)
183+ .filter_map(|atom| {
184+ let atom = QueryAtom::new(atom)?;
185+ if atom.kind == QueryAtomKind::Fuzzy && first_fuzzy_query.is_none() {
186+ first_fuzzy_query = Some(atom.atom);
187+ None
188+ } else {
189+ Some(atom)
190+ }
191+ })
192+ .collect();
193+ FuzzyQuery {
194+ first_fuzzy_atom: first_fuzzy_query,
195+ query_atoms,
196+ }
197+ }
198+
199+ pub fn fuzzy_match(&self, item: &str, matcher: &Matcher) -> Option<i64> {
200+ // use the rank of the first fuzzzy query for the rank, because merging ranks is not really possible
201+ // this behaviour matches fzf and skim
202+ let score = self
203+ .first_fuzzy_atom
204+ .as_ref()
205+ .map_or(Some(0), |atom| matcher.fuzzy_match(item, atom))?;
206+ if self
207+ .query_atoms
208+ .iter()
209+ .any(|atom| !atom.matches(matcher, item))
210+ {
211+ return None;
212+ }
213+ Some(score)
214+ }
215+
216+ pub fn fuzzy_indices(&self, item: &str, matcher: &Matcher) -> Option<(i64, Vec<usize>)> {
217+ let (score, mut indices) = self.first_fuzzy_atom.as_ref().map_or_else(
218+ || Some((0, Vec::new())),
219+ |atom| matcher.fuzzy_indices(item, atom),
220+ )?;
221+
222+ // fast path for the common case of just a single atom
223+ if self.query_atoms.is_empty() {
224+ return Some((score, indices));
225+ }
226+
227+ for atom in &self.query_atoms {
228+ if !atom.indices(matcher, item, &mut indices) {
229+ return None;
230+ }
231+ }
232+
233+ // deadup and remove duplicate matches
234+ indices.sort_unstable();
235+ indices.dedup();
236+
237+ Some((score, indices))
238+ }
239+}
helix-term/src/ui/fuzzy_match/test.rsnew file+47
@@ -0,0 +1,47 @@
1+use crate::ui::fuzzy_match::FuzzyQuery;
2+use crate::ui::fuzzy_match::Matcher;
3+
4+fn run_test<'a>(query: &str, items: &'a [&'a str]) -> Vec<String> {
5+ let query = FuzzyQuery::new(query);
6+ let matcher = Matcher::default();
7+ items
8+ .iter()
9+ .filter_map(|item| {
10+ let (_, indices) = query.fuzzy_indices(item, &matcher)?;
11+ let matched_string = indices
12+ .iter()
13+ .map(|&pos| item.chars().nth(pos).unwrap())
14+ .collect();
15+ Some(matched_string)
16+ })
17+ .collect()
18+}
19+
20+#[test]
21+fn match_single_value() {
22+ let matches = run_test("foo", &["foobar", "foo", "bar"]);
23+ assert_eq!(matches, &["foo", "foo"])
24+}
25+
26+#[test]
27+fn match_multiple_values() {
28+ let matches = run_test(
29+ "foo bar",
30+ &["foo bar", "foo bar", "bar foo", "bar", "foo"],
31+ );
32+ assert_eq!(matches, &["foobar", "foobar", "barfoo"])
33+}
34+
35+#[test]
36+fn space_escape() {
37+ let matches = run_test(r"foo\ bar", &["bar foo", "foo bar", "foobar"]);
38+ assert_eq!(matches, &["foo bar"])
39+}
40+
41+#[test]
42+fn trim() {
43+ let matches = run_test(r" foo bar ", &["bar foo", "foo bar", "foobar"]);
44+ assert_eq!(matches, &["barfoo", "foobar", "foobar"]);
45+ let matches = run_test(r" foo bar\ ", &["bar foo", "foo bar", "foobar"]);
46+ assert_eq!(matches, &["bar foo"])
47+}
helix-term/src/ui/lsp.rs+1−3
@@ -92,9 +92,7 @@ impl Component for SignatureHelp {
9292 Some(doc) => Markdown::new(doc.clone(), Arc::clone(&self.config_loader)),
9393 };
9494 let sig_doc = sig_doc.parse(Some(&cx.editor.theme));
95− let sig_doc_area = area
96− .clip_top(sig_text_area.height + 2)
97− .clip_bottom(u16::from(cx.editor.popup_border()));
95+ let sig_doc_area = area.clip_top(sig_text_area.height + 2);
9896 let sig_doc_para = Paragraph::new(sig_doc)
9997 .wrap(Wrap { trim: false })
10098 .scroll((cx.scroll.unwrap_or_default() as u16, 0));
helix-term/src/ui/markdown.rs+5−12
@@ -14,7 +14,6 @@ use helix_core::{
1414};
1515use helix_view::{
1616 graphics::{Margin, Rect, Style},
17− theme::Modifier,
1817 Theme,
1918};
2019
@@ -184,9 +183,7 @@ impl Markdown {
184183 // Transform text in `<code>` blocks into `Event::Code`
185184 let mut in_code = false;
186185 let parser = parser.filter_map(|event| match event {
187− Event::Html(tag)
188− if tag.starts_with("<code") && matches!(tag.chars().nth(5), Some(' ' | '>')) =>
189− {
186+ Event::Html(tag) if *tag == *"<code>" => {
190187 in_code = true;
191188 None
192189 }
@@ -278,21 +275,17 @@ impl Markdown {
278275 );
279276 lines.extend(tui_text.lines.into_iter());
280277 } else {
281− let style = match tags.last() {
282− Some(Tag::Heading(level, ..)) => match level {
278+ let style = if let Some(Tag::Heading(level, ..)) = tags.last() {
279+ match level {
283280 HeadingLevel::H1 => heading_styles[0],
284281 HeadingLevel::H2 => heading_styles[1],
285282 HeadingLevel::H3 => heading_styles[2],
286283 HeadingLevel::H4 => heading_styles[3],
287284 HeadingLevel::H5 => heading_styles[4],
288285 HeadingLevel::H6 => heading_styles[5],
289− },
290− Some(Tag::Emphasis) => text_style.add_modifier(Modifier::ITALIC),
291− Some(Tag::Strong) => text_style.add_modifier(Modifier::BOLD),
292− Some(Tag::Strikethrough) => {
293− text_style.add_modifier(Modifier::CROSSED_OUT)
294286 }
295− _ => text_style,
287+ } else {
288+ text_style
296289 };
297290 spans.push(Span::styled(text, style));
298291 }
helix-term/src/ui/menu.rs+40−58
@@ -1,29 +1,22 @@
1−use std::{borrow::Cow, cmp::Reverse, path::PathBuf};
1+use std::{borrow::Cow, path::PathBuf};
22
33use crate::{
44 compositor::{Callback, Component, Compositor, Context, Event, EventResult},
55 ctrl, key, shift,
66};
7−use helix_core::fuzzy::MATCHER;
8−use nucleo::pattern::{Atom, AtomKind, CaseMatching};
9−use nucleo::{Config, Utf32Str};
10−use tui::{
11− buffer::Buffer as Surface,
12− widgets::{Block, Borders, Table, Widget},
13−};
7+use tui::{buffer::Buffer as Surface, widgets::Table};
148
159pub use tui::widgets::{Cell, Row};
1610
17−use helix_view::{
18− editor::SmartTabConfig,
19− graphics::{Margin, Rect},
20− Editor,
21−};
11+use fuzzy_matcher::skim::SkimMatcherV2 as Matcher;
12+use fuzzy_matcher::FuzzyMatcher;
13+
14+use helix_view::{editor::SmartTabConfig, graphics::Rect, Editor};
2215use tui::layout::Constraint;
2316
24−pub trait Item: Sync + Send + 'static {
17+pub trait Item {
2518 /// Additional editor state that is used for label calculation.
26− type Data: Sync + Send + 'static;
19+ type Data;
2720
2821 fn format(&self, data: &Self::Data) -> Row;
2922
@@ -58,8 +51,9 @@ pub struct Menu<T: Item> {
5851
5952 cursor: Option<usize>,
6053
54+ matcher: Box<Matcher>,
6155 /// (index, score)
62− matches: Vec<(u32, u32)>,
56+ matches: Vec<(usize, i64)>,
6357
6458 widths: Vec<Constraint>,
6559
@@ -81,10 +75,11 @@ impl<T: Item> Menu<T> {
8175 editor_data: <T as Item>::Data,
8276 callback_fn: impl Fn(&mut Editor, Option<&T>, MenuEvent) + 'static,
8377 ) -> Self {
84− let matches = (0..options.len() as u32).map(|i| (i, 0)).collect();
78+ let matches = (0..options.len()).map(|i| (i, 0)).collect();
8579 Self {
8680 options,
8781 editor_data,
82+ matcher: Box::new(Matcher::default().ignore_case()),
8883 matches,
8984 cursor: None,
9085 widths: Vec::new(),
@@ -99,19 +94,20 @@ impl<T: Item> Menu<T> {
9994 pub fn score(&mut self, pattern: &str) {
10095 // reuse the matches allocation
10196 self.matches.clear();
102− let mut matcher = MATCHER.lock();
103− matcher.config = Config::DEFAULT;
104− let pattern = Atom::new(pattern, CaseMatching::Ignore, AtomKind::Fuzzy, false);
105− let mut buf = Vec::new();
106− let matches = self.options.iter().enumerate().filter_map(|(i, option)| {
107− let text = option.filter_text(&self.editor_data);
108− pattern
109− .score(Utf32Str::new(&text, &mut buf), &mut matcher)
110− .map(|score| (i as u32, score as u32))
111− });
112− self.matches.extend(matches);
113− self.matches
114− .sort_unstable_by_key(|&(i, score)| (Reverse(score), i));
97+ self.matches.extend(
98+ self.options
99+ .iter()
100+ .enumerate()
101+ .filter_map(|(index, option)| {
102+ let text = option.filter_text(&self.editor_data);
103+ // TODO: using fuzzy_indices could give us the char idx for match highlighting
104+ self.matcher
105+ .fuzzy_match(&text, pattern)
106+ .map(|score| (index, score))
107+ }),
108+ );
109+ // Order of equal elements needs to be preserved as LSP preselected items come in order of high to low priority
110+ self.matches.sort_by_key(|(_, score)| -score);
115111
116112 // reset cursor position
117113 self.cursor = None;
@@ -205,7 +201,7 @@ impl<T: Item> Menu<T> {
205201 self.cursor.and_then(|cursor| {
206202 self.matches
207203 .get(cursor)
208− .map(|(index, _score)| &self.options[*index as usize])
204+ .map(|(index, _score)| &self.options[*index])
209205 })
210206 }
211207
@@ -213,7 +209,7 @@ impl<T: Item> Menu<T> {
213209 self.cursor.and_then(|cursor| {
214210 self.matches
215211 .get(cursor)
216− .map(|(index, _score)| &mut self.options[*index as usize])
212+ .map(|(index, _score)| &mut self.options[*index])
217213 })
218214 }
219215
@@ -329,15 +325,6 @@ impl<T: Item + 'static> Component for Menu<T> {
329325 let selected = theme.get("ui.menu.selected");
330326 surface.clear_with(area, style);
331327
332− let render_borders = cx.editor.menu_border();
333−
334− let area = if render_borders {
335− Widget::render(Block::default().borders(Borders::ALL), area, surface);
336− area.inner(&Margin::vertical(1))
337− } else {
338− area
339− };
340−
341328 let scroll = self.scroll;
342329
343330 let options: Vec<_> = self
@@ -345,7 +332,7 @@ impl<T: Item + 'static> Component for Menu<T> {
345332 .iter()
346333 .map(|(index, _score)| {
347334 // (index, self.options.get(*index).unwrap()) // get_unchecked
348− &self.options[*index as usize] // get_unchecked
335+ &self.options[*index] // get_unchecked
349336 })
350337 .collect();
351338
@@ -378,19 +365,15 @@ impl<T: Item + 'static> Component for Menu<T> {
378365 false,
379366 );
380367
381− let render_borders = cx.editor.menu_border();
382−
383− if !render_borders {
384− if let Some(cursor) = self.cursor {
385− let offset_from_top = cursor - scroll;
386− let left = &mut surface[(area.left(), area.y + offset_from_top as u16)];
387− left.set_style(selected);
388− let right = &mut surface[(
389− area.right().saturating_sub(1),
390− area.y + offset_from_top as u16,
391− )];
392− right.set_style(selected);
393− }
368+ if let Some(cursor) = self.cursor {
369+ let offset_from_top = cursor - scroll;
370+ let left = &mut surface[(area.left(), area.y + offset_from_top as u16)];
371+ left.set_style(selected);
372+ let right = &mut surface[(
373+ area.right().saturating_sub(1),
374+ area.y + offset_from_top as u16,
375+ )];
376+ right.set_style(selected);
394377 }
395378
396379 let fits = len <= win_height;
@@ -405,13 +388,12 @@ impl<T: Item + 'static> Component for Menu<T> {
405388 for i in 0..win_height {
406389 cell = &mut surface[(area.right() - 1, area.top() + i as u16)];
407390
408− let half_block = if render_borders { "▌" } else { "▐" };
391+ cell.set_symbol("▐"); // right half block
409392
410393 if scroll_line <= i && i < scroll_line + scroll_height {
411394 // Draw scroll thumb
412− cell.set_symbol(half_block);
413395 cell.set_fg(scroll_style.fg.unwrap_or(helix_view::theme::Color::Reset));
414− } else if !render_borders {
396+ } else {
415397 // Draw scroll track
416398 cell.set_fg(scroll_style.bg.unwrap_or(helix_view::theme::Color::Reset));
417399 }
helix-term/src/ui/mod.rs+145−88
@@ -1,12 +1,13 @@
11mod completion;
22mod document;
33pub(crate) mod editor;
4+mod fuzzy_match;
45mod info;
56pub mod lsp;
67mod markdown;
78pub mod menu;
89pub mod overlay;
9−pub mod picker;
10+mod picker;
1011pub mod popup;
1112mod prompt;
1213mod spinner;
@@ -63,7 +64,7 @@ pub fn regex_prompt(
6364 prompt: std::borrow::Cow<'static, str>,
6465 history_register: Option<char>,
6566 completion_fn: impl FnMut(&Editor, &str) -> Vec<prompt::Completion> + 'static,
66− fun: impl Fn(&mut crate::compositor::Context, Regex, PromptEvent) + 'static,
67+ fun: impl Fn(&mut Editor, Regex, PromptEvent) + 'static,
6768) {
6869 let (view, doc) = current!(cx.editor);
6970 let doc_id = view.doc;
@@ -110,7 +111,7 @@ pub fn regex_prompt(
110111 view.jumps.push((doc_id, snapshot.clone()));
111112 }
112113
113− fun(cx, regex, event);
114+ fun(cx.editor, regex, event);
114115
115116 let (view, doc) = current!(cx.editor);
116117 view.ensure_cursor_in_view(doc, config.scrolloff);
@@ -173,13 +174,9 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> Picker
173174 .git_ignore(config.file_picker.git_ignore)
174175 .git_global(config.file_picker.git_global)
175176 .git_exclude(config.file_picker.git_exclude)
176− .sort_by_file_name(|name1, name2| name1.cmp(name2))
177177 .max_depth(config.file_picker.max_depth)
178178 .filter_entry(move |entry| filter_picker_entry(entry, &absolute_root, dedup_symlinks));
179179
180− walk_builder.add_custom_ignore_filename(helix_loader::config_dir().join("ignore"));
181− walk_builder.add_custom_ignore_filename(".helix/ignore");
182−
183180 // We want to exclude files that the editor can't handle yet
184181 let mut type_builder = TypesBuilder::new();
185182 type_builder
@@ -193,16 +190,32 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> Picker
193190 .build()
194191 .expect("failed to build excluded_types");
195192 walk_builder.types(excluded_types);
196− let mut files = walk_builder.build().filter_map(|entry| {
193+
194+ // We want files along with their modification date for sorting
195+ let files = walk_builder.build().filter_map(|entry| {
197196 let entry = entry.ok()?;
198− if !entry.file_type()?.is_file() {
199− return None;
197+ // This is faster than entry.path().is_dir() since it uses cached fs::Metadata fetched by ignore/walkdir
198+ if entry.file_type()?.is_file() {
199+ Some(entry.into_path())
200+ } else {
201+ None
200202 }
201− Some(entry.into_path())
202203 });
204+
205+ // Cap the number of files if we aren't in a git project, preventing
206+ // hangs when using the picker in your home directory
207+ let mut files: Vec<PathBuf> = if root.join(".git").exists() {
208+ files.collect()
209+ } else {
210+ // const MAX: usize = 8192;
211+ const MAX: usize = 100_000;
212+ files.take(MAX).collect()
213+ };
214+ files.sort();
215+
203216 log::debug!("file_picker init {:?}", Instant::now().duration_since(now));
204217
205− let picker = Picker::new(Vec::new(), root, move |cx, path: &PathBuf, action| {
218+ Picker::new(files, root, move |cx, path: &PathBuf, action| {
206219 if let Err(e) = cx.editor.open(path, action) {
207220 let err = if let Some(err) = e.source() {
208221 format!("{}", err)
@@ -212,41 +225,20 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> Picker
212225 cx.editor.set_error(err);
213226 }
214227 })
215− .with_preview(|_editor, path| Some((path.clone().into(), None)));
216− let injector = picker.injector();
217− let timeout = std::time::Instant::now() + std::time::Duration::from_millis(30);
218−
219− let mut hit_timeout = false;
220− for file in &mut files {
221− if injector.push(file).is_err() {
222− break;
223− }
224− if std::time::Instant::now() >= timeout {
225− hit_timeout = true;
226− break;
227− }
228− }
229− if hit_timeout {
230− std::thread::spawn(move || {
231− for file in files {
232− if injector.push(file).is_err() {
233− break;
234− }
235− }
236− });
237− }
238− picker
228+ .with_preview(|_editor, path| Some((path.clone().into(), None)))
239229}
240230
241231pub mod completers {
242232 use crate::ui::prompt::Completion;
243− use helix_core::fuzzy::fuzzy_match;
233+ use fuzzy_matcher::skim::SkimMatcherV2 as Matcher;
234+ use fuzzy_matcher::FuzzyMatcher;
244235 use helix_core::syntax::LanguageServerFeature;
245236 use helix_view::document::SCRATCH_BUFFER_NAME;
246237 use helix_view::theme;
247238 use helix_view::{editor::Config, Editor};
248239 use once_cell::sync::Lazy;
249240 use std::borrow::Cow;
241+ use std::cmp::Reverse;
250242
251243 pub type Completer = fn(&Editor, &str) -> Vec<Completion>;
252244
@@ -255,16 +247,31 @@ pub mod completers {
255247 }
256248
257249 pub fn buffer(editor: &Editor, input: &str) -> Vec<Completion> {
258− let names = editor.documents.values().map(|doc| {
259− doc.relative_path()
260− .map(|p| p.display().to_string().into())
261− .unwrap_or_else(|| Cow::from(SCRATCH_BUFFER_NAME))
262− });
263−
264− fuzzy_match(input, names, true)
250+ let mut names: Vec<_> = editor
251+ .documents
252+ .values()
253+ .map(|doc| {
254+ let name = doc
255+ .relative_path()
256+ .map(|p| p.display().to_string())
257+ .unwrap_or_else(|| String::from(SCRATCH_BUFFER_NAME));
258+ ((0..), Cow::from(name))
259+ })
260+ .collect();
261+
262+ let matcher = Matcher::default();
263+
264+ let mut matches: Vec<_> = names
265265 .into_iter()
266− .map(|(name, _)| ((0..), name))
267− .collect()
266+ .filter_map(|(_range, name)| {
267+ matcher.fuzzy_match(&name, input).map(|score| (name, score))
268+ })
269+ .collect();
270+
271+ matches.sort_unstable_by_key(|(_file, score)| Reverse(*score));
272+ names = matches.into_iter().map(|(name, _)| ((0..), name)).collect();
273+
274+ names
268275 }
269276
270277 pub fn theme(_editor: &Editor, input: &str) -> Vec<Completion> {
@@ -277,10 +284,26 @@ pub mod completers {
277284 names.sort();
278285 names.dedup();
279286
280− fuzzy_match(input, names, false)
287+ let mut names: Vec<_> = names
281288 .into_iter()
282− .map(|(name, _)| ((0..), name.into()))
283− .collect()
289+ .map(|name| ((0..), Cow::from(name)))
290+ .collect();
291+
292+ let matcher = Matcher::default();
293+
294+ let mut matches: Vec<_> = names
295+ .into_iter()
296+ .filter_map(|(_range, name)| {
297+ matcher.fuzzy_match(&name, input).map(|score| (name, score))
298+ })
299+ .collect();
300+
301+ matches.sort_unstable_by(|(name1, score1), (name2, score2)| {
302+ (Reverse(*score1), name1).cmp(&(Reverse(*score2), name2))
303+ });
304+ names = matches.into_iter().map(|(name, _)| ((0..), name)).collect();
305+
306+ names
284307 }
285308
286309 /// Recursive function to get all keys from this value and add them to vec
@@ -307,22 +330,22 @@ pub mod completers {
307330 keys
308331 });
309332
310− fuzzy_match(input, &*KEYS, false)
333+ let matcher = Matcher::default();
334+
335+ let mut matches: Vec<_> = KEYS
336+ .iter()
337+ .filter_map(|name| matcher.fuzzy_match(name, input).map(|score| (name, score)))
338+ .collect();
339+
340+ matches.sort_unstable_by_key(|(_file, score)| Reverse(*score));
341+ matches
311342 .into_iter()
312343 .map(|(name, _)| ((0..), name.into()))
313344 .collect()
314345 }
315346
316347 pub fn filename(editor: &Editor, input: &str) -> Vec<Completion> {
317− filename_with_git_ignore(editor, input, true)
318− }
319−
320− pub fn filename_with_git_ignore(
321− editor: &Editor,
322− input: &str,
323− git_ignore: bool,
324− ) -> Vec<Completion> {
325− filename_impl(editor, input, git_ignore, |entry| {
348+ filename_impl(editor, input, |entry| {
326349 let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir());
327350
328351 if is_dir {
@@ -334,6 +357,8 @@ pub mod completers {
334357 }
335358
336359 pub fn language(editor: &Editor, input: &str) -> Vec<Completion> {
360+ let matcher = Matcher::default();
361+
337362 let text: String = "text".into();
338363
339364 let language_ids = editor
@@ -342,13 +367,27 @@ pub mod completers {
342367 .map(|config| &config.language_id)
343368 .chain(std::iter::once(&text));
344369
345− fuzzy_match(input, language_ids, false)
370+ let mut matches: Vec<_> = language_ids
371+ .filter_map(|language_id| {
372+ matcher
373+ .fuzzy_match(language_id, input)
374+ .map(|score| (language_id, score))
375+ })
376+ .collect();
377+
378+ matches.sort_unstable_by(|(language1, score1), (language2, score2)| {
379+ (Reverse(*score1), language1).cmp(&(Reverse(*score2), language2))
380+ });
381+
382+ matches
346383 .into_iter()
347− .map(|(name, _)| ((0..), name.to_owned().into()))
384+ .map(|(language, _score)| ((0..), language.clone().into()))
348385 .collect()
349386 }
350387
351388 pub fn lsp_workspace_command(editor: &Editor, input: &str) -> Vec<Completion> {
389+ let matcher = Matcher::default();
390+
352391 let Some(options) = doc!(editor)
353392 .language_servers_with_feature(LanguageServerFeature::WorkspaceCommand)
354393 .find_map(|ls| ls.capabilities().execute_command_provider.as_ref())
@@ -356,22 +395,28 @@ pub mod completers {
356395 return vec![];
357396 };
358397
359− fuzzy_match(input, &options.commands, false)
398+ let mut matches: Vec<_> = options
399+ .commands
400+ .iter()
401+ .filter_map(|command| {
402+ matcher
403+ .fuzzy_match(command, input)
404+ .map(|score| (command, score))
405+ })
406+ .collect();
407+
408+ matches.sort_unstable_by(|(command1, score1), (command2, score2)| {
409+ (Reverse(*score1), command1).cmp(&(Reverse(*score2), command2))
410+ });
411+
412+ matches
360413 .into_iter()
361− .map(|(name, _)| ((0..), name.to_owned().into()))
414+ .map(|(command, _score)| ((0..), command.clone().into()))
362415 .collect()
363416 }
364417
365418 pub fn directory(editor: &Editor, input: &str) -> Vec<Completion> {
366− directory_with_git_ignore(editor, input, true)
367− }
368−
369− pub fn directory_with_git_ignore(
370− editor: &Editor,
371− input: &str,
372− git_ignore: bool,
373− ) -> Vec<Completion> {
374− filename_impl(editor, input, git_ignore, |entry| {
419+ filename_impl(editor, input, |entry| {
375420 let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir());
376421
377422 if is_dir {
@@ -394,12 +439,7 @@ pub mod completers {
394439 }
395440
396441 // TODO: we could return an iter/lazy thing so it can fetch as many as it needs.
397− fn filename_impl<F>(
398− _editor: &Editor,
399− input: &str,
400− git_ignore: bool,
401− filter_fn: F,
402− ) -> Vec<Completion>
442+ fn filename_impl<F>(_editor: &Editor, input: &str, filter_fn: F) -> Vec<Completion>
403443 where
404444 F: Fn(&ignore::DirEntry) -> FileMatch,
405445 {
@@ -439,10 +479,9 @@ pub mod completers {
439479
440480 let end = input.len()..;
441481
442− let files = WalkBuilder::new(&dir)
482+ let mut files: Vec<_> = WalkBuilder::new(&dir)
443483 .hidden(false)
444484 .follow_links(false) // We're scanning over depth 1
445− .git_ignore(git_ignore)
446485 .max_depth(Some(1))
447486 .build()
448487 .filter_map(|file| {
@@ -471,25 +510,43 @@ pub mod completers {
471510 path.push("");
472511 }
473512
474− let path = path.into_os_string().into_string().ok()?;
475− Some(Cow::from(path))
513+ let path = path.to_str()?.to_owned();
514+ Some((end.clone(), Cow::from(path)))
476515 })
477516 }) // TODO: unwrap or skip
478− .filter(|path| !path.is_empty());
517+ .filter(|(_, path)| !path.is_empty()) // TODO
518+ .collect();
479519
480520 // if empty, return a list of dirs and files in current dir
481521 if let Some(file_name) = file_name {
522+ let matcher = Matcher::default();
523+
524+ // inefficient, but we need to calculate the scores, filter out None, then sort.
525+ let mut matches: Vec<_> = files
526+ .into_iter()
527+ .filter_map(|(_range, file)| {
528+ matcher
529+ .fuzzy_match(&file, &file_name)
530+ .map(|score| (file, score))
531+ })
532+ .collect();
533+
482534 let range = (input.len().saturating_sub(file_name.len()))..;
483− fuzzy_match(&file_name, files, true)
535+
536+ matches.sort_unstable_by(|(file1, score1), (file2, score2)| {
537+ (Reverse(*score1), file1).cmp(&(Reverse(*score2), file2))
538+ });
539+
540+ files = matches
484541 .into_iter()
485− .map(|(name, _)| (range.clone(), name))
486− .collect()
542+ .map(|(file, _)| (range.clone(), file))
543+ .collect();
487544
488545 // TODO: complete to longest common match
489546 } else {
490− let mut files: Vec<_> = files.map(|file| (end.clone(), file)).collect();
491547 files.sort_unstable_by(|(_, path1), (_, path2)| path1.cmp(path2));
492− files
493548 }
549+
550+ files
494551 }
495552}
helix-term/src/ui/picker.rs+319−353
@@ -7,12 +7,11 @@ use crate::{
77 ui::{
88 self,
99 document::{render_document, LineDecoration, LinePos, TextRenderer},
10+ fuzzy_match::FuzzyQuery,
1011 EditorView,
1112 },
1213};
1314use futures_util::{future::BoxFuture, FutureExt};
14−use nucleo::pattern::CaseMatching;
15−use nucleo::{Config, Nucleo, Utf32String};
1615use tui::{
1716 buffer::Buffer as Surface,
1817 layout::Constraint,
@@ -20,23 +19,16 @@ use tui::{
2019 widgets::{Block, BorderType, Borders, Cell, Table},
2120};
2221
22+use fuzzy_matcher::skim::SkimMatcherV2 as Matcher;
2323use tui::widgets::Widget;
2424
25−use std::{
26− collections::HashMap,
27− io::Read,
28− path::PathBuf,
29− sync::{
30− atomic::{self, AtomicBool},
31− Arc,
32− },
33−};
25+use std::cmp::{self, Ordering};
26+use std::{collections::HashMap, io::Read, path::PathBuf};
3427
3528use crate::ui::{Prompt, PromptEvent};
3629use helix_core::{
37− char_idx_at_visual_offset, fuzzy::MATCHER, movement::Direction,
38− text_annotations::TextAnnotations, unicode::segmentation::UnicodeSegmentation, Position,
39− Syntax,
30+ char_idx_at_visual_offset, movement::Direction, text_annotations::TextAnnotations,
31+ unicode::segmentation::UnicodeSegmentation, Position, Syntax,
4032};
4133use helix_view::{
4234 editor::Action,
@@ -46,7 +38,6 @@ use helix_view::{
4638 Document, DocumentId, Editor,
4739};
4840
49−pub const ID: &str = "picker";
5041use super::{menu::Item, overlay::Overlay};
5142
5243pub const MIN_AREA_WIDTH_FOR_PREVIEW: u16 = 72;
@@ -60,12 +51,12 @@ pub enum PathOrId {
6051}
6152
6253impl PathOrId {
63− fn get_canonicalized(self) -> Self {
54+ fn get_canonicalized(self) -> std::io::Result<Self> {
6455 use PathOrId::*;
65− match self {
66− Path(path) => Path(helix_core::path::get_canonicalized_path(&path)),
56+ Ok(match self {
57+ Path(path) => Path(helix_core::path::get_canonicalized_path(&path)?),
6758 Id(id) => Id(id),
68− }
59+ })
6960 }
7061}
7162
@@ -112,9 +103,9 @@ impl Preview<'_, '_> {
112103 /// Alternate text to show for the preview.
113104 fn placeholder(&self) -> &str {
114105 match *self {
115− Self::EditorDocument(_) => "<Invalid file location>",
106+ Self::EditorDocument(_) => "<File preview>",
116107 Self::Cached(preview) => match preview {
117− CachedPreview::Document(_) => "<Invalid file location>",
108+ CachedPreview::Document(_) => "<File preview>",
118109 CachedPreview::Binary => "<Binary file>",
119110 CachedPreview::LargeFile => "<File too large to preview>",
120111 CachedPreview::NotFound => "<File not found>",
@@ -123,71 +114,20 @@ impl Preview<'_, '_> {
123114 }
124115}
125116
126−fn item_to_nucleo<T: Item>(item: T, editor_data: &T::Data) -> Option<(T, Utf32String)> {
127− let row = item.format(editor_data);
128− let mut cells = row.cells.iter();
129− let mut text = String::with_capacity(row.cell_text().map(|cell| cell.len()).sum());
130− let cell = cells.next()?;
131− if let Some(cell) = cell.content.lines.first() {
132− for span in &cell.0 {
133− text.push_str(&span.content);
134− }
135− }
136−
137− for cell in cells {
138− text.push(' ');
139− if let Some(cell) = cell.content.lines.first() {
140− for span in &cell.0 {
141− text.push_str(&span.content);
142− }
143− }
144− }
145− Some((item, text.into()))
146−}
147−
148−pub struct Injector<T: Item> {
149− dst: nucleo::Injector<T>,
150− editor_data: Arc<T::Data>,
151− shutown: Arc<AtomicBool>,
152−}
153−
154−impl<T: Item> Clone for Injector<T> {
155− fn clone(&self) -> Self {
156− Injector {
157− dst: self.dst.clone(),
158− editor_data: self.editor_data.clone(),
159− shutown: self.shutown.clone(),
160− }
161− }
162−}
163−
164−pub struct InjectorShutdown;
165−
166−impl<T: Item> Injector<T> {
167− pub fn push(&self, item: T) -> Result<(), InjectorShutdown> {
168− if self.shutown.load(atomic::Ordering::Relaxed) {
169− return Err(InjectorShutdown);
170− }
171−
172− if let Some((item, matcher_text)) = item_to_nucleo(item, &self.editor_data) {
173− self.dst.push(item, |dst| dst[0] = matcher_text);
174− }
175− Ok(())
176− }
177−}
178−
179117pub struct Picker<T: Item> {
180− editor_data: Arc<T::Data>,
181− shutdown: Arc<AtomicBool>,
182− matcher: Nucleo<T>,
118+ options: Vec<T>,
119+ editor_data: T::Data,
120+ // filter: String,
121+ matcher: Box<Matcher>,
122+ matches: Vec<PickerMatch>,
183123
184124 /// Current height of the completions box
185125 completion_height: u16,
186126
187− cursor: u32,
127+ cursor: usize,
128+ // pattern: String,
188129 prompt: Prompt,
189− previous_pattern: String,
190−
130+ previous_pattern: (String, FuzzyQuery),
191131 /// Whether to show the preview panel (default true)
192132 show_preview: bool,
193133 /// Constraints for tabular formatting
@@ -204,59 +144,10 @@ pub struct Picker<T: Item> {
204144}
205145
206146impl<T: Item + 'static> Picker<T> {
207− pub fn stream(editor_data: T::Data) -> (Nucleo<T>, Injector<T>) {
208− let matcher = Nucleo::new(
209− Config::DEFAULT,
210− Arc::new(helix_event::request_redraw),
211− None,
212− 1,
213− );
214− let streamer = Injector {
215− dst: matcher.injector(),
216− editor_data: Arc::new(editor_data),
217− shutown: Arc::new(AtomicBool::new(false)),
218− };
219− (matcher, streamer)
220− }
221−
222147 pub fn new(
223148 options: Vec<T>,
224149 editor_data: T::Data,
225150 callback_fn: impl Fn(&mut Context, &T, Action) + 'static,
226− ) -> Self {
227− let matcher = Nucleo::new(
228− Config::DEFAULT,
229− Arc::new(helix_event::request_redraw),
230− None,
231− 1,
232− );
233− let injector = matcher.injector();
234− for item in options {
235− if let Some((item, matcher_text)) = item_to_nucleo(item, &editor_data) {
236− injector.push(item, |dst| dst[0] = matcher_text);
237− }
238− }
239− Self::with(
240− matcher,
241− Arc::new(editor_data),
242− Arc::new(AtomicBool::new(false)),
243− callback_fn,
244− )
245− }
246−
247− pub fn with_stream(
248− matcher: Nucleo<T>,
249− injector: Injector<T>,
250− callback_fn: impl Fn(&mut Context, &T, Action) + 'static,
251− ) -> Self {
252− Self::with(matcher, injector.editor_data, injector.shutown, callback_fn)
253− }
254−
255− fn with(
256− matcher: Nucleo<T>,
257− editor_data: Arc<T::Data>,
258− shutdown: Arc<AtomicBool>,
259− callback_fn: impl Fn(&mut Context, &T, Action) + 'static,
260151 ) -> Self {
261152 let prompt = Prompt::new(
262153 "".into(),
@@ -265,13 +156,14 @@ impl<T: Item + 'static> Picker<T> {
265156 |_editor: &mut Context, _pattern: &str, _event: PromptEvent| {},
266157 );
267158
268− Self {
269− matcher,
159+ let mut picker = Self {
160+ options,
270161 editor_data,
271− shutdown,
162+ matcher: Box::default(),
163+ matches: Vec::new(),
272164 cursor: 0,
273165 prompt,
274− previous_pattern: String::new(),
166+ previous_pattern: (String::new(), FuzzyQuery::default()),
275167 truncate_start: true,
276168 show_preview: true,
277169 callback_fn: Box::new(callback_fn),
@@ -280,15 +172,24 @@ impl<T: Item + 'static> Picker<T> {
280172 preview_cache: HashMap::new(),
281173 read_buffer: Vec::with_capacity(1024),
282174 file_fn: None,
283− }
284− }
175+ };
285176
286− pub fn injector(&self) -> Injector<T> {
287− Injector {
288− dst: self.matcher.injector(),
289− editor_data: self.editor_data.clone(),
290− shutown: self.shutdown.clone(),
291− }
177+ picker.calculate_column_widths();
178+
179+ // scoring on empty input
180+ // TODO: just reuse score()
181+ picker
182+ .matches
183+ .extend(picker.options.iter().enumerate().map(|(index, option)| {
184+ let text = option.filter_text(&picker.editor_data);
185+ PickerMatch {
186+ index,
187+ score: 0,
188+ len: text.chars().count(),
189+ }
190+ }));
191+
192+ picker
292193 }
293194
294195 pub fn truncate_start(mut self, truncate_start: bool) -> Self {
@@ -301,25 +202,122 @@ impl<T: Item + 'static> Picker<T> {
301202 preview_fn: impl Fn(&Editor, &T) -> Option<FileLocation> + 'static,
302203 ) -> Self {
303204 self.file_fn = Some(Box::new(preview_fn));
304− // assumption: if we have a preview we are matching paths... If this is ever
305− // not true this could be a separate builder function
306− self.matcher.update_config(Config::DEFAULT.match_paths());
307205 self
308206 }
309207
310208 pub fn set_options(&mut self, new_options: Vec<T>) {
311− self.matcher.restart(false);
312− let injector = self.matcher.injector();
313− for item in new_options {
314− if let Some((item, matcher_text)) = item_to_nucleo(item, &self.editor_data) {
315− injector.push(item, |dst| dst[0] = matcher_text);
209+ self.options = new_options;
210+ self.cursor = 0;
211+ self.force_score();
212+ self.calculate_column_widths();
213+ }
214+
215+ /// Calculate the width constraints using the maximum widths of each column
216+ /// for the current options.
217+ fn calculate_column_widths(&mut self) {
218+ let n = self
219+ .options
220+ .first()
221+ .map(|option| option.format(&self.editor_data).cells.len())
222+ .unwrap_or_default();
223+ let max_lens = self.options.iter().fold(vec![0; n], |mut acc, option| {
224+ let row = option.format(&self.editor_data);
225+ // maintain max for each column
226+ for (acc, cell) in acc.iter_mut().zip(row.cells.iter()) {
227+ let width = cell.content.width();
228+ if width > *acc {
229+ *acc = width;
230+ }
316231 }
232+ acc
233+ });
234+ self.widths = max_lens
235+ .into_iter()
236+ .map(|len| Constraint::Length(len as u16))
237+ .collect();
238+ }
239+
240+ pub fn score(&mut self) {
241+ let pattern = self.prompt.line();
242+
243+ if pattern == &self.previous_pattern.0 {
244+ return;
317245 }
246+
247+ let (query, is_refined) = self
248+ .previous_pattern
249+ .1
250+ .refine(pattern, &self.previous_pattern.0);
251+
252+ if pattern.is_empty() {
253+ // Fast path for no pattern.
254+ self.matches.clear();
255+ self.matches
256+ .extend(self.options.iter().enumerate().map(|(index, option)| {
257+ let text = option.filter_text(&self.editor_data);
258+ PickerMatch {
259+ index,
260+ score: 0,
261+ len: text.chars().count(),
262+ }
263+ }));
264+ } else if is_refined {
265+ // optimization: if the pattern is a more specific version of the previous one
266+ // then we can score the filtered set.
267+ self.matches.retain_mut(|pmatch| {
268+ let option = &self.options[pmatch.index];
269+ let text = option.sort_text(&self.editor_data);
270+
271+ match query.fuzzy_match(&text, &self.matcher) {
272+ Some(s) => {
273+ // Update the score
274+ pmatch.score = s;
275+ true
276+ }
277+ None => false,
278+ }
279+ });
280+
281+ self.matches.sort_unstable();
282+ } else {
283+ self.force_score();
284+ }
285+
286+ // reset cursor position
287+ self.cursor = 0;
288+ let pattern = self.prompt.line();
289+ self.previous_pattern.0.clone_from(pattern);
290+ self.previous_pattern.1 = query;
291+ }
292+
293+ pub fn force_score(&mut self) {
294+ let pattern = self.prompt.line();
295+
296+ let query = FuzzyQuery::new(pattern);
297+ self.matches.clear();
298+ self.matches.extend(
299+ self.options
300+ .iter()
301+ .enumerate()
302+ .filter_map(|(index, option)| {
303+ let text = option.filter_text(&self.editor_data);
304+
305+ query
306+ .fuzzy_match(&text, &self.matcher)
307+ .map(|score| PickerMatch {
308+ index,
309+ score,
310+ len: text.chars().count(),
311+ })
312+ }),
313+ );
314+
315+ self.matches.sort_unstable();
318316 }
319317
320318 /// Move the cursor by a number of lines, either down (`Forward`) or up (`Backward`)
321− pub fn move_by(&mut self, amount: u32, direction: Direction) {
322− let len = self.matcher.snapshot().matched_item_count();
319+ pub fn move_by(&mut self, amount: usize, direction: Direction) {
320+ let len = self.matches.len();
323321
324322 if len == 0 {
325323 // No results, can't move.
@@ -338,12 +336,12 @@ impl<T: Item + 'static> Picker<T> {
338336
339337 /// Move the cursor down by exactly one page. After the last page comes the first page.
340338 pub fn page_up(&mut self) {
341− self.move_by(self.completion_height as u32, Direction::Backward);
339+ self.move_by(self.completion_height as usize, Direction::Backward);
342340 }
343341
344342 /// Move the cursor up by exactly one page. After the first page comes the last page.
345343 pub fn page_down(&mut self) {
346− self.move_by(self.completion_height as u32, Direction::Forward);
344+ self.move_by(self.completion_height as usize, Direction::Forward);
347345 }
348346
349347 /// Move the cursor to the first entry
@@ -353,18 +351,13 @@ impl<T: Item + 'static> Picker<T> {
353351
354352 /// Move the cursor to the last entry
355353 pub fn to_end(&mut self) {
356− self.cursor = self
357− .matcher
358− .snapshot()
359− .matched_item_count()
360− .saturating_sub(1);
354+ self.cursor = self.matches.len().saturating_sub(1);
361355 }
362356
363357 pub fn selection(&self) -> Option<&T> {
364− self.matcher
365− .snapshot()
366− .get_matched_item(self.cursor)
367− .map(|item| item.data)
358+ self.matches
359+ .get(self.cursor)
360+ .map(|pmatch| &self.options[pmatch.index])
368361 }
369362
370363 pub fn toggle_preview(&mut self) {
@@ -373,17 +366,8 @@ impl<T: Item + 'static> Picker<T> {
373366
374367 fn prompt_handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult {
375368 if let EventResult::Consumed(_) = self.prompt.handle_event(event, cx) {
376− let pattern = self.prompt.line();
377− // TODO: better track how the pattern has changed
378− if pattern != &self.previous_pattern {
379− self.matcher.pattern.reparse(
380− 0,
381− pattern,
382− CaseMatching::Smart,
383− pattern.starts_with(&self.previous_pattern),
384− );
385− self.previous_pattern = pattern.clone();
386− }
369+ // TODO: recalculate only if pattern changed
370+ self.score();
387371 }
388372 EventResult::Consumed(None)
389373 }
@@ -391,7 +375,7 @@ impl<T: Item + 'static> Picker<T> {
391375 fn current_file(&self, editor: &Editor) -> Option<FileLocation> {
392376 self.selection()
393377 .and_then(|current| (self.file_fn.as_ref()?)(editor, current))
394− .map(|(path_or_id, line)| (path_or_id.get_canonicalized(), line))
378+ .and_then(|(path_or_id, line)| path_or_id.get_canonicalized().ok().zip(Some(line)))
395379 }
396380
397381 /// Get (cached) preview for a given path. If a document corresponding
@@ -427,9 +411,12 @@ impl<T: Item + 'static> Picker<T> {
427411 (size, _) if size > MAX_FILE_SIZE_FOR_PREVIEW => {
428412 CachedPreview::LargeFile
429413 }
430− _ => Document::open(path, None, None, editor.config.clone())
431− .map(|doc| CachedPreview::Document(Box::new(doc)))
432− .unwrap_or(CachedPreview::NotFound),
414+ _ => {
415+ // TODO: enable syntax highlighting; blocked by async rendering
416+ Document::open(path, None, None, editor.config.clone())
417+ .map(|doc| CachedPreview::Document(Box::new(doc)))
418+ .unwrap_or(CachedPreview::NotFound)
419+ }
433420 },
434421 )
435422 .unwrap_or(CachedPreview::NotFound);
@@ -474,13 +461,9 @@ impl<T: Item + 'static> Picker<T> {
474461 log::info!("highlighting picker item failed");
475462 return;
476463 };
477− let picker = match compositor.find::<Overlay<Self>>() {
478− Some(Overlay { content, .. }) => Some(content),
479− None => compositor
480− .find::<Overlay<DynamicPicker<T>>>()
481− .map(|overlay| &mut overlay.content.file_picker),
482− };
483− let Some(picker) = picker
464+ let Some(Overlay {
465+ content: picker, ..
466+ }) = compositor.find::<Overlay<Self>>()
484467 else {
485468 log::info!("picker closed before syntax highlighting finished");
486469 return;
@@ -512,14 +495,6 @@ impl<T: Item + 'static> Picker<T> {
512495 }
513496
514497 fn render_picker(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
515− let status = self.matcher.tick(10);
516− let snapshot = self.matcher.snapshot();
517− if status.changed {
518− self.cursor = self
519− .cursor
520− .min(snapshot.matched_item_count().saturating_sub(1))
521− }
522−
523498 let text_style = cx.editor.theme.get("ui.text");
524499 let selected = cx.editor.theme.get("ui.text.focus");
525500 let highlight_style = cx.editor.theme.get("special").add_modifier(Modifier::BOLD);
@@ -540,15 +515,8 @@ impl<T: Item + 'static> Picker<T> {
540515 // -- Render the input bar:
541516
542517 let area = inner.clip_left(1).with_height(1);
543− // render the prompt first since it will clear its background
544− self.prompt.render(area, surface, cx);
545518
546− let count = format!(
547− "{}{}/{}",
548− if status.running { "(running) " } else { "" },
549− snapshot.matched_item_count(),
550− snapshot.item_count(),
551− );
519+ let count = format!("{}/{}", self.matches.len(), self.options.len());
552520 surface.set_stringn(
553521 (area.x + area.width).saturating_sub(count.len() as u16 + 1),
554522 area.y,
@@ -557,6 +525,8 @@ impl<T: Item + 'static> Picker<T> {
557525 text_style,
558526 );
559527
528+ self.prompt.render(area, surface, cx);
529+
560530 // -- Separator
561531 let sep_style = cx.editor.theme.get("ui.background.separator");
562532 let borders = BorderType::line_symbols(BorderType::Plain);
@@ -569,89 +539,106 @@ impl<T: Item + 'static> Picker<T> {
569539 // -- Render the contents:
570540 // subtract area of prompt from top
571541 let inner = inner.clip_top(2);
572− let rows = inner.height as u32;
573− let offset = self.cursor - (self.cursor % std::cmp::max(1, rows));
542+
543+ let rows = inner.height;
544+ let offset = self.cursor - (self.cursor % std::cmp::max(1, rows as usize));
574545 let cursor = self.cursor.saturating_sub(offset);
575− let end = offset
576− .saturating_add(rows)
577− .min(snapshot.matched_item_count());
578− let mut indices = Vec::new();
579− let mut matcher = MATCHER.lock();
580− matcher.config = Config::DEFAULT;
581− if self.file_fn.is_some() {
582− matcher.config.set_match_paths()
583− }
584546
585− let options = snapshot.matched_items(offset..end).map(|item| {
586− snapshot.pattern().column_pattern(0).indices(
587− item.matcher_columns[0].slice(..),
588− &mut matcher,
589− &mut indices,
590− );
591− indices.sort_unstable();
592− indices.dedup();
593− let mut row = item.data.format(&self.editor_data);
594−
595− let mut grapheme_idx = 0u32;
596− let mut indices = indices.drain(..);
597− let mut next_highlight_idx = indices.next().unwrap_or(u32::MAX);
598− if self.widths.len() < row.cells.len() {
599− self.widths.resize(row.cells.len(), Constraint::Length(0));
600− }
601− let mut widths = self.widths.iter_mut();
602− for cell in &mut row.cells {
603− let Some(Constraint::Length(max_width)) = widths.next() else {
604− unreachable!();
605− };
547+ let options = self
548+ .matches
549+ .iter()
550+ .skip(offset)
551+ .take(rows as usize)
552+ .map(|pmatch| &self.options[pmatch.index])
553+ .map(|option| option.format(&self.editor_data))
554+ .map(|mut row| {
555+ const TEMP_CELL_SEP: &str = " ";
556+
557+ let line = row.cell_text().fold(String::new(), |mut s, frag| {
558+ s.push_str(&frag);
559+ s.push_str(TEMP_CELL_SEP);
560+ s
561+ });
606562
607− // merge index highlights on top of existing hightlights
608− let mut span_list = Vec::new();
609− let mut current_span = String::new();
610− let mut current_style = Style::default();
611− let mut width = 0;
612−
613− let spans: &[Span] = cell.content.lines.first().map_or(&[], |it| it.0.as_slice());
614− for span in spans {
615− // this looks like a bug on first glance, we are iterating
616− // graphemes but treating them as char indices. The reason that
617− // this is correct is that nucleo will only ever consider the first char
618− // of a grapheme (and discard the rest of the grapheme) so the indices
619− // returned by nucleo are essentially grapheme indecies
620− for grapheme in span.content.graphemes(true) {
621− let style = if grapheme_idx == next_highlight_idx {
622− next_highlight_idx = indices.next().unwrap_or(u32::MAX);
623− span.style.patch(highlight_style)
624− } else {
625− span.style
626− };
627− if style != current_style {
628− if !current_span.is_empty() {
629− span_list.push(Span::styled(current_span, current_style))
563+ // Items are filtered by using the text returned by menu::Item::filter_text
564+ // but we do highlighting here using the text in Row and therefore there
565+ // might be inconsistencies. This is the best we can do since only the
566+ // text in Row is displayed to the end user.
567+ let (_score, highlights) = FuzzyQuery::new(self.prompt.line())
568+ .fuzzy_indices(&line, &self.matcher)
569+ .unwrap_or_default();
570+
571+ let highlight_byte_ranges: Vec<_> = line
572+ .char_indices()
573+ .enumerate()
574+ .filter_map(|(char_idx, (byte_offset, ch))| {
575+ highlights
576+ .contains(&char_idx)
577+ .then(|| byte_offset..byte_offset + ch.len_utf8())
578+ })
579+ .collect();
580+
581+ // The starting byte index of the current (iterating) cell
582+ let mut cell_start_byte_offset = 0;
583+ for cell in row.cells.iter_mut() {
584+ let spans = match cell.content.lines.get(0) {
585+ Some(s) => s,
586+ None => {
587+ cell_start_byte_offset += TEMP_CELL_SEP.len();
588+ continue;
589+ }
590+ };
591+
592+ let mut cell_len = 0;
593+
594+ let graphemes_with_style: Vec<_> = spans
595+ .0
596+ .iter()
597+ .flat_map(|span| {
598+ span.content
599+ .grapheme_indices(true)
600+ .zip(std::iter::repeat(span.style))
601+ })
602+ .map(|((grapheme_byte_offset, grapheme), style)| {
603+ cell_len += grapheme.len();
604+ let start = cell_start_byte_offset;
605+
606+ let grapheme_byte_range =
607+ grapheme_byte_offset..grapheme_byte_offset + grapheme.len();
608+
609+ if highlight_byte_ranges.iter().any(|hl_rng| {
610+ hl_rng.start >= start + grapheme_byte_range.start
611+ && hl_rng.end <= start + grapheme_byte_range.end
612+ }) {
613+ (grapheme, style.patch(highlight_style))
614+ } else {
615+ (grapheme, style)
630616 }
631− current_span = String::new();
632− current_style = style;
617+ })
618+ .collect();
619+
620+ let mut span_list: Vec<(String, Style)> = Vec::new();
621+ for (grapheme, style) in graphemes_with_style {
622+ if span_list.last().map(|(_, sty)| sty) == Some(&style) {
623+ let (string, _) = span_list.last_mut().unwrap();
624+ string.push_str(grapheme);
625+ } else {
626+ span_list.push((String::from(grapheme), style))
633627 }
634− current_span.push_str(grapheme);
635− grapheme_idx += 1;
636628 }
637− width += span.width();
638− }
639629
640− span_list.push(Span::styled(current_span, current_style));
641− if width as u16 > *max_width {
642− *max_width = width as u16;
643− }
644− *cell = Cell::from(Spans::from(span_list));
630+ let spans: Vec<Span> = span_list
631+ .into_iter()
632+ .map(|(string, style)| Span::styled(string, style))
633+ .collect();
634+ let spans: Spans = spans.into();
635+ *cell = Cell::from(spans);
645636
646− // spacer
647− if grapheme_idx == next_highlight_idx {
648− next_highlight_idx = indices.next().unwrap_or(u32::MAX);
637+ cell_start_byte_offset += cell_len + TEMP_CELL_SEP.len();
649638 }
650− grapheme_idx += 1;
651− }
652639
653− row
654− });
640+ row
641+ });
655642
656643 let table = Table::new(options)
657644 .style(text_style)
@@ -667,7 +654,7 @@ impl<T: Item + 'static> Picker<T> {
667654 surface,
668655 &mut TableState {
669656 offset: 0,
670− selected: Some(cursor as usize),
657+ selected: Some(cursor),
671658 },
672659 self.truncate_start,
673660 );
@@ -693,14 +680,8 @@ impl<T: Item + 'static> Picker<T> {
693680 if let Some((path, range)) = self.current_file(cx.editor) {
694681 let preview = self.get_preview(path, cx.editor);
695682 let doc = match preview.document() {
696− Some(doc)
697− if range.map_or(true, |(start, end)| {
698− start <= end && end <= doc.text().len_lines()
699− }) =>
700− {
701− doc
702− }
703− _ => {
683+ Some(doc) => doc,
684+ None => {
704685 let alt_text = preview.placeholder();
705686 let x = inner.x + inner.width.saturating_sub(alt_text.len() as u16) / 2;
706687 let y = inner.y + inner.height / 2;
@@ -710,46 +691,31 @@ impl<T: Item + 'static> Picker<T> {
710691 };
711692
712693 let mut offset = ViewPosition::default();
713− if let Some((start_line, end_line)) = range {
714− let height = end_line - start_line;
715− let text = doc.text().slice(..);
716− let start = text.line_to_char(start_line);
717− let middle = text.line_to_char(start_line + height / 2);
718− if height < inner.height as usize {
719− let text_fmt = doc.text_format(inner.width, None);
720− let annotations = TextAnnotations::default();
721− (offset.anchor, offset.vertical_offset) = char_idx_at_visual_offset(
722− text,
723− middle,
724− // align to middle
725− -(inner.height as isize / 2),
726− 0,
727− &text_fmt,
728− &annotations,
729− );
730− if start < offset.anchor {
731− offset.anchor = start;
732− offset.vertical_offset = 0;
733− }
734− } else {
735− offset.anchor = start;
736− }
694+ if let Some(range) = range {
695+ let text_fmt = doc.text_format(inner.width, None);
696+ let annotations = TextAnnotations::default();
697+ (offset.anchor, offset.vertical_offset) = char_idx_at_visual_offset(
698+ doc.text().slice(..),
699+ doc.text().line_to_char(range.0),
700+ // align to middle
701+ -(inner.height as isize / 2),
702+ 0,
703+ &text_fmt,
704+ &annotations,
705+ );
737706 }
738707
739− let syntax_highlights = EditorView::doc_syntax_highlights(
708+ let mut highlights = EditorView::doc_syntax_highlights(
740709 doc,
741710 offset.anchor,
742711 area.height,
743712 &cx.editor.theme,
744713 );
745−
746− let mut overlay_highlights =
747− EditorView::empty_highlight_iter(doc, offset.anchor, area.height);
748714 for spans in EditorView::doc_diagnostics_highlights(doc, &cx.editor.theme) {
749715 if spans.is_empty() {
750716 continue;
751717 }
752− overlay_highlights = Box::new(helix_core::syntax::merge(overlay_highlights, spans));
718+ highlights = Box::new(helix_core::syntax::merge(highlights, spans));
753719 }
754720 let mut decorations: Vec<Box<dyn LineDecoration>> = Vec::new();
755721
@@ -780,8 +746,7 @@ impl<T: Item + 'static> Picker<T> {
780746 offset,
781747 // TODO: compute text annotations asynchronously here (like inlay hints)
782748 &TextAnnotations::default(),
783− syntax_highlights,
784− overlay_highlights,
749+ highlights,
785750 &cx.editor.theme,
786751 &mut decorations,
787752 &mut [],
@@ -790,7 +755,7 @@ impl<T: Item + 'static> Picker<T> {
790755 }
791756}
792757
793−impl<T: Item + 'static + Send + Sync> Component for Picker<T> {
758+impl<T: Item + 'static> Component for Picker<T> {
794759 fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
795760 // +---------+ +---------+
796761 // |prompt | |preview |
@@ -799,8 +764,7 @@ impl<T: Item + 'static + Send + Sync> Component for Picker<T> {
799764 // | | | |
800765 // +---------+ +---------+
801766
802− let render_preview =
803− self.show_preview && self.file_fn.is_some() && area.width > MIN_AREA_WIDTH_FOR_PREVIEW;
767+ let render_preview = self.show_preview && area.width > MIN_AREA_WIDTH_FOR_PREVIEW;
804768
805769 let picker_width = if render_preview {
806770 area.width / 2
@@ -830,28 +794,11 @@ impl<T: Item + 'static + Send + Sync> Component for Picker<T> {
830794 _ => return EventResult::Ignored(None),
831795 };
832796
833− let close_fn = |picker: &mut Self| {
834− // if the picker is very large don't store it as last_picker to avoid
835− // excessive memory consumption
836− let callback: compositor::Callback = if picker.matcher.snapshot().item_count() > 100_000
837− {
838− Box::new(|compositor: &mut Compositor, _ctx| {
839− // remove the layer
840− compositor.pop();
841− })
842− } else {
843− // stop streaming in new items in the background, really we should
844− // be restarting the stream somehow once the picker gets
845− // reopened instead (like for an FS crawl) that would also remove the
846− // need for the special case above but that is pretty tricky
847− picker.shutdown.store(true, atomic::Ordering::Relaxed);
848− Box::new(|compositor: &mut Compositor, _ctx| {
849− // remove the layer
850− compositor.last_picker = compositor.pop();
851− })
852− };
853− EventResult::Consumed(Some(callback))
854− };
797+ let close_fn =
798+ EventResult::Consumed(Some(Box::new(|compositor: &mut Compositor, _ctx| {
799+ // remove the layer
800+ compositor.last_picker = compositor.pop();
801+ })));
855802
856803 // So that idle timeout retriggers
857804 ctx.editor.reset_idle_timer();
@@ -875,7 +822,9 @@ impl<T: Item + 'static + Send + Sync> Component for Picker<T> {
875822 key!(End) => {
876823 self.to_end();
877824 }
878− key!(Esc) | ctrl!('c') => return close_fn(self),
825+ key!(Esc) | ctrl!('c') => {
826+ return close_fn;
827+ }
879828 alt!(Enter) => {
880829 if let Some(option) = self.selection() {
881830 (self.callback_fn)(ctx, option, Action::Load);
@@ -885,19 +834,19 @@ impl<T: Item + 'static + Send + Sync> Component for Picker<T> {
885834 if let Some(option) = self.selection() {
886835 (self.callback_fn)(ctx, option, Action::Replace);
887836 }
888− return close_fn(self);
837+ return close_fn;
889838 }
890839 ctrl!('s') => {
891840 if let Some(option) = self.selection() {
892841 (self.callback_fn)(ctx, option, Action::HorizontalSplit);
893842 }
894− return close_fn(self);
843+ return close_fn;
895844 }
896845 ctrl!('v') => {
897846 if let Some(option) = self.selection() {
898847 (self.callback_fn)(ctx, option, Action::VerticalSplit);
899848 }
900− return close_fn(self);
849+ return close_fn;
901850 }
902851 ctrl!('t') => {
903852 self.toggle_preview();
@@ -925,15 +874,30 @@ impl<T: Item + 'static + Send + Sync> Component for Picker<T> {
925874 self.completion_height = height.saturating_sub(4);
926875 Some((width, height))
927876 }
877+}
928878
929− fn id(&self) -> Option<&'static str> {
930− Some(ID)
879+#[derive(PartialEq, Eq, Debug)]
880+struct PickerMatch {
881+ score: i64,
882+ index: usize,
883+ len: usize,
884+}
885+
886+impl PickerMatch {
887+ fn key(&self) -> impl Ord {
888+ (cmp::Reverse(self.score), self.len, self.index)
931889 }
932890}
933−impl<T: Item> Drop for Picker<T> {
934− fn drop(&mut self) {
935− // ensure we cancel any ongoing background threads streaming into the picker
936− self.shutdown.store(true, atomic::Ordering::Relaxed)
891+
892+impl PartialOrd for PickerMatch {
893+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
894+ Some(self.cmp(other))
895+ }
896+}
897+
898+impl Ord for PickerMatch {
899+ fn cmp(&self, other: &Self) -> Ordering {
900+ self.key().cmp(&other.key())
937901 }
938902}
939903
@@ -946,13 +910,15 @@ pub type DynQueryCallback<T> =
946910
947911/// A picker that updates its contents via a callback whenever the
948912/// query string changes. Useful for live grep, workspace symbols, etc.
949−pub struct DynamicPicker<T: ui::menu::Item + Send + Sync> {
913+pub struct DynamicPicker<T: ui::menu::Item + Send> {
950914 file_picker: Picker<T>,
951915 query_callback: DynQueryCallback<T>,
952916 query: String,
953917}
954918
955−impl<T: ui::menu::Item + Send + Sync> DynamicPicker<T> {
919+impl<T: ui::menu::Item + Send> DynamicPicker<T> {
920+ pub const ID: &'static str = "dynamic-picker";
921+
956922 pub fn new(file_picker: Picker<T>, query_callback: DynQueryCallback<T>) -> Self {
957923 Self {
958924 file_picker,
@@ -962,7 +928,7 @@ impl<T: ui::menu::Item + Send + Sync> DynamicPicker<T> {
962928 }
963929}
964930
965−impl<T: Item + Send + Sync + 'static> Component for DynamicPicker<T> {
931+impl<T: Item + Send + 'static> Component for DynamicPicker<T> {
966932 fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
967933 self.file_picker.render(area, surface, cx);
968934 }
@@ -984,7 +950,7 @@ impl<T: Item + Send + Sync + 'static> Component for DynamicPicker<T> {
984950 let callback = Callback::EditorCompositor(Box::new(move |editor, compositor| {
985951 // Wrapping of pickers in overlay is done outside the picker code,
986952 // so this is fragile and will break if wrapped in some other widget.
987− let picker = match compositor.find_id::<Overlay<DynamicPicker<T>>>(ID) {
953+ let picker = match compositor.find_id::<Overlay<DynamicPicker<T>>>(Self::ID) {
988954 Some(overlay) => &mut overlay.content.file_picker,
989955 None => return,
990956 };
@@ -1005,6 +971,6 @@ impl<T: Item + Send + Sync + 'static> Component for DynamicPicker<T> {
1005971 }
1006972
1007973 fn id(&self) -> Option<&'static str> {
1008− Some(ID)
974+ Some(Self::ID)
1009975 }
1010976}
helix-term/src/ui/popup.rs+7−27
@@ -3,10 +3,7 @@ use crate::{
33 compositor::{Callback, Component, Context, Event, EventResult},
44 ctrl, key,
55};
6−use tui::{
7− buffer::Buffer as Surface,
8− widgets::{Block, Borders, Widget},
9−};
6+use tui::buffer::Buffer as Surface;
107
118use helix_core::Position;
129use helix_view::{
@@ -255,29 +252,13 @@ impl<T: Component> Component for Popup<T> {
255252 let background = cx.editor.theme.get("ui.popup");
256253 surface.clear_with(area, background);
257254
258− let render_borders = cx.editor.popup_border();
259−
260− let inner = if self
261− .contents
262− .type_name()
263− .starts_with("helix_term::ui::menu::Menu")
264− {
265− area
266− } else {
267− area.inner(&self.margin)
268− };
269−
270− let border = usize::from(render_borders);
271− if render_borders {
272− Widget::render(Block::default().borders(Borders::ALL), area, surface);
273− }
274−
255+ let inner = area.inner(&self.margin);
275256 self.contents.render(inner, surface, cx);
276257
277258 // render scrollbar if contents do not fit
278259 if self.has_scrollbar {
279− let win_height = (inner.height as usize).saturating_sub(2 * border);
280− let len = (self.child_size.1 as usize).saturating_sub(2 * border);
260+ let win_height = inner.height as usize;
261+ let len = self.child_size.1 as usize;
281262 let fits = len <= win_height;
282263 let scroll = self.scroll;
283264 let scroll_style = cx.editor.theme.get("ui.menu.scroll");
@@ -293,15 +274,14 @@ impl<T: Component> Component for Popup<T> {
293274
294275 let mut cell;
295276 for i in 0..win_height {
296− cell = &mut surface[(inner.right() - 1, inner.top() + (border + i) as u16)];
277+ cell = &mut surface[(inner.right() - 1, inner.top() + i as u16)];
297278
298− let half_block = if render_borders { "▌" } else { "▐" };
279+ cell.set_symbol("▐"); // right half block
299280
300281 if scroll_line <= i && i < scroll_line + scroll_height {
301282 // Draw scroll thumb
302− cell.set_symbol(half_block);
303283 cell.set_fg(scroll_style.fg.unwrap_or(helix_view::theme::Color::Reset));
304− } else if !render_borders {
284+ } else {
305285 // Draw scroll track
306286 cell.set_fg(scroll_style.bg.unwrap_or(helix_view::theme::Color::Reset));
307287 }
helix-term/tests/integration.rs+1
@@ -20,6 +20,7 @@ mod test {
2020 mod commands;
2121 mod languages;
2222 mod movement;
23+ mod picker;
2324 mod prompt;
2425 mod splits;
2526}
helix-term/tests/test/commands.rs−46
@@ -480,49 +480,3 @@ fn bar() {#(\n|)#\
480480
481481 Ok(())
482482}
483−
484−#[tokio::test(flavor = "multi_thread")]
485−async fn test_join_selections() -> anyhow::Result<()> {
486− // normal join
487− test((
488− platform_line(indoc! {"\
489− #[a|]#bc
490− def
491− "}),
492− "J",
493− platform_line(indoc! {"\
494− #[a|]#bc def
495− "}),
496− ))
497− .await?;
498−
499− // join with empty line
500− test((
501− platform_line(indoc! {"\
502− #[a|]#bc
503−
504− def
505− "}),
506− "JJ",
507− platform_line(indoc! {"\
508− #[a|]#bc def
509− "}),
510− ))
511− .await?;
512−
513− // join with additional space in non-empty line
514− test((
515− platform_line(indoc! {"\
516− #[a|]#bc
517−
518− def
519− "}),
520− "JJ",
521− platform_line(indoc! {"\
522− #[a|]#bc def
523− "}),
524− ))
525− .await?;
526−
527− Ok(())
528−}
helix-term/tests/test/commands/write.rs+3−122
@@ -93,7 +93,7 @@ async fn test_buffer_close_concurrent() -> anyhow::Result<()> {
9393 )
9494 .await?;
9595
96− helpers::assert_file_has_content(file.as_file_mut(), &platform_line(&RANGE.end().to_string()))?;
96+ helpers::assert_file_has_content(file.as_file_mut(), &RANGE.end().to_string())?;
9797
9898 Ok(())
9999}
@@ -209,7 +209,7 @@ async fn test_write_concurrent() -> anyhow::Result<()> {
209209
210210 let mut file_content = String::new();
211211 file.as_file_mut().read_to_string(&mut file_content)?;
212− assert_eq!(platform_line(&RANGE.end().to_string()), file_content);
212+ assert_eq!(RANGE.end().to_string(), file_content);
213213
214214 Ok(())
215215}
@@ -424,132 +424,13 @@ async fn test_write_utf_bom_file() -> anyhow::Result<()> {
424424 Ok(())
425425}
426426
427−#[tokio::test(flavor = "multi_thread")]
428−async fn test_write_insert_final_newline_added_if_missing() -> anyhow::Result<()> {
429− let mut file = tempfile::NamedTempFile::new()?;
430− let mut app = helpers::AppBuilder::new()
431− .with_file(file.path(), None)
432− .with_input_text("#[h|]#ave you tried chamomile tea?")
433− .build()?;
434−
435− test_key_sequence(&mut app, Some(":w<ret>"), None, false).await?;
436−
437− helpers::assert_file_has_content(
438− file.as_file_mut(),
439− &helpers::platform_line("have you tried chamomile tea?\n"),
440− )?;
441−
442− Ok(())
443−}
444−
445−#[tokio::test(flavor = "multi_thread")]
446−async fn test_write_insert_final_newline_unchanged_if_not_missing() -> anyhow::Result<()> {
447− let mut file = tempfile::NamedTempFile::new()?;
448− let mut app = helpers::AppBuilder::new()
449− .with_file(file.path(), None)
450− .with_input_text(&helpers::platform_line("#[t|]#en minutes, please\n"))
451− .build()?;
452−
453− test_key_sequence(&mut app, Some(":w<ret>"), None, false).await?;
454−
455− helpers::assert_file_has_content(
456− file.as_file_mut(),
457− &helpers::platform_line("ten minutes, please\n"),
458− )?;
459−
460− Ok(())
461−}
462−
463−#[tokio::test(flavor = "multi_thread")]
464−async fn test_write_insert_final_newline_unchanged_if_missing_and_false() -> anyhow::Result<()> {
465− let mut file = tempfile::NamedTempFile::new()?;
466− let mut app = helpers::AppBuilder::new()
467− .with_config(Config {
468− editor: helix_view::editor::Config {
469− insert_final_newline: false,
470− ..Default::default()
471− },
472− ..Default::default()
473− })
474− .with_file(file.path(), None)
475− .with_input_text("#[t|]#he quiet rain continued through the night")
476− .build()?;
477−
478− test_key_sequence(&mut app, Some(":w<ret>"), None, false).await?;
479−
480− helpers::assert_file_has_content(
481− file.as_file_mut(),
482− "the quiet rain continued through the night",
483− )?;
484−
485− Ok(())
486−}
487−
488−#[tokio::test(flavor = "multi_thread")]
489−async fn test_write_all_insert_final_newline_add_if_missing_and_modified() -> anyhow::Result<()> {
490− let mut file1 = tempfile::NamedTempFile::new()?;
491− let mut file2 = tempfile::NamedTempFile::new()?;
492− let mut app = helpers::AppBuilder::new()
493− .with_file(file1.path(), None)
494− .with_input_text("#[w|]#e don't serve time travelers here")
495− .build()?;
496−
497− test_key_sequence(
498− &mut app,
499− Some(&format!(
500− ":o {}<ret>ia time traveler walks into a bar<esc>:wa<ret>",
501− file2.path().to_string_lossy()
502− )),
503− None,
504− false,
505− )
506− .await?;
507−
508− helpers::assert_file_has_content(
509− file1.as_file_mut(),
510− &helpers::platform_line("we don't serve time travelers here\n"),
511− )?;
512−
513− helpers::assert_file_has_content(
514− file2.as_file_mut(),
515− &helpers::platform_line("a time traveler walks into a bar\n"),
516− )?;
517−
518− Ok(())
519−}
520−
521−#[tokio::test(flavor = "multi_thread")]
522−async fn test_write_all_insert_final_newline_do_not_add_if_unmodified() -> anyhow::Result<()> {
523− let mut file = tempfile::NamedTempFile::new()?;
524− let mut app = helpers::AppBuilder::new()
525− .with_file(file.path(), None)
526− .build()?;
527−
528− file.write_all(b"i lost on Jeopardy!")?;
529− file.rewind()?;
530−
531− test_key_sequence(&mut app, Some(":wa<ret>"), None, false).await?;
532−
533− helpers::assert_file_has_content(file.as_file_mut(), "i lost on Jeopardy!")?;
534−
535− Ok(())
536−}
537−
538427async fn edit_file_with_content(file_content: &[u8]) -> anyhow::Result<()> {
539428 let mut file = tempfile::NamedTempFile::new()?;
540429
541430 file.as_file_mut().write_all(&file_content)?;
542431
543432 helpers::test_key_sequence(
544− &mut helpers::AppBuilder::new()
545− .with_config(Config {
546− editor: helix_view::editor::Config {
547− insert_final_newline: false,
548− ..Default::default()
549− },
550− ..Default::default()
551− })
552− .build()?,
433+ &mut helpers::AppBuilder::new().build()?,
553434 Some(&format!(":o {}<ret>:x<ret>", file.path().to_string_lossy())),
554435 None,
555436 true,
helix-term/tests/test/helpers.rs+1−9
@@ -320,14 +320,6 @@ impl AppBuilder {
320320 }
321321
322322 pub fn build(self) -> anyhow::Result<Application> {
323− if let Some(path) = &self.args.working_directory {
324− bail!("Changing the working directory to {path:?} is not yet supported for integration tests");
325− }
326−
327− if let Some((path, _)) = self.args.files.first().filter(|p| p.0.is_dir()) {
328− bail!("Having the directory {path:?} in args.files[0] is not yet supported for integration tests");
329− }
330−
331323 let mut app = Application::new(self.args, self.config, self.syn_conf)?;
332324
333325 if let Some((text, selection)) = self.input {
@@ -358,7 +350,7 @@ pub fn assert_file_has_content(file: &mut File, content: &str) -> anyhow::Result
358350
359351 let mut file_content = String::new();
360352 file.read_to_string(&mut file_content)?;
361− assert_eq!(file_content, content);
353+ assert_eq!(content, file_content);
362354
363355 Ok(())
364356}
helix-term/tests/test/movement.rs−39
@@ -513,42 +513,3 @@ async fn select_mode_tree_sitter_prev_function_goes_backwards_to_object() -> any
513513
514514 Ok(())
515515}
516−
517−#[tokio::test(flavor = "multi_thread")]
518−async fn find_char_line_ending() -> anyhow::Result<()> {
519− test((
520− helpers::platform_line(indoc! {
521− "\
522− one
523− #[|t]#wo
524− three"
525− }),
526− "T<ret>gll2f<ret>",
527− helpers::platform_line(indoc! {
528− "\
529− one
530− two#[
531− |]#three"
532− }),
533− ))
534− .await?;
535−
536− test((
537− helpers::platform_line(indoc! {
538− "\
539− #[|o]#ne
540− two
541− three"
542− }),
543− "f<ret>2t<ret>ghT<ret>F<ret>",
544− helpers::platform_line(indoc! {
545− "\
546− one#[|
547− t]#wo
548− three"
549− }),
550− ))
551− .await?;
552−
553− Ok(())
554−}
helix-term/tests/test/picker.rsnew file+80
@@ -0,0 +1,80 @@
1+use std::fs;
2+
3+use helix_core::{path::get_canonicalized_path, Range};
4+use helix_loader::{current_working_dir, set_current_working_dir};
5+use helix_view::{current_ref, editor::Action};
6+use tempfile::{Builder, TempDir};
7+
8+use super::*;
9+
10+#[tokio::test(flavor = "multi_thread")]
11+async fn test_picker_alt_ret() -> anyhow::Result<()> {
12+ // Create two files, open the first and run a global search for a word
13+ // from the second file. Press <alt-ret> to have helix open the second file in the
14+ // new buffer, but not change focus. Then check whether the word is highlighted
15+ // correctly and the view of the first file has not changed.
16+ let tmp_dir = TempDir::new()?;
17+ set_current_working_dir(tmp_dir.path().into())?;
18+
19+ let mut app = AppBuilder::new().build()?;
20+
21+ log::debug!(
22+ "set current working directory to {:?}",
23+ current_working_dir()
24+ );
25+
26+ // Add prefix so helix doesn't hide these files in a picker
27+ let files = [
28+ Builder::new().prefix("1").tempfile_in(&tmp_dir)?,
29+ Builder::new().prefix("2").tempfile_in(&tmp_dir)?,
30+ ];
31+ let paths = files
32+ .iter()
33+ .map(|f| get_canonicalized_path(f.path()).unwrap())
34+ .collect::<Vec<_>>();
35+
36+ fs::write(&paths[0], "1\n2\n3\n4")?;
37+ fs::write(&paths[1], "first\nsecond")?;
38+
39+ log::debug!(
40+ "created and wrote two temporary files: {:?} & {:?}",
41+ paths[0],
42+ paths[1]
43+ );
44+
45+ // Manually open to save the offset, otherwise we won't be able to change the state in the Fn trait
46+ app.editor.open(files[0].path(), Action::Replace)?;
47+ let view_offset = current_ref!(app.editor).0.offset;
48+
49+ test_key_sequences(
50+ &mut app,
51+ vec![
52+ (Some("<space>/"), None),
53+ (Some("second<ret>"), None),
54+ (
55+ Some("<A-ret><esc>"),
56+ Some(&|app| {
57+ let (view, doc) = current_ref!(app.editor);
58+ assert_eq!(doc.path().unwrap(), &paths[0]);
59+ let select_ranges = doc.selection(view.id).ranges();
60+ assert_eq!(select_ranges[0], Range::new(0, 1));
61+ assert_eq!(view.offset, view_offset);
62+ }),
63+ ),
64+ (
65+ Some(":buffer<minus>next<ret>"),
66+ Some(&|app| {
67+ let (view, doc) = current_ref!(app.editor);
68+ assert_eq!(doc.path().unwrap(), &paths[1]);
69+ let select_ranges = doc.selection(view.id).ranges();
70+ assert_eq!(select_ranges.len(), 1);
71+ assert_eq!(select_ranges[0], Range::new(6, 12));
72+ }),
73+ ),
74+ ],
75+ false,
76+ )
77+ .await?;
78+
79+ Ok(())
80+}
helix-term/tests/test/splits.rs+3−3
@@ -62,9 +62,9 @@ async fn test_split_write_quit_all() -> anyhow::Result<()> {
6262 )
6363 .await?;
6464
65− helpers::assert_file_has_content(file1.as_file_mut(), &platform_line("hello1"))?;
66− helpers::assert_file_has_content(file2.as_file_mut(), &platform_line("hello2"))?;
67− helpers::assert_file_has_content(file3.as_file_mut(), &platform_line("hello3"))?;
65+ helpers::assert_file_has_content(file1.as_file_mut(), "hello1")?;
66+ helpers::assert_file_has_content(file2.as_file_mut(), "hello2")?;
67+ helpers::assert_file_has_content(file3.as_file_mut(), "hello3")?;
6868
6969 Ok(())
7070}
helix-tui/Cargo.toml+15−15
@@ -1,28 +1,28 @@
11[package]
22name = "helix-tui"
3−description = """A library to build rich terminal user interfaces or dashboards"""
3+version = "0.6.0"
4+authors = ["Blaž Hrastnik <blaz@mxxn.io>"]
5+description = """
6+A library to build rich terminal user interfaces or dashboards
7+"""
8+edition = "2021"
9+license = "MPL-2.0"
10+categories = ["editor"]
11+repository = "https://github.com/helix-editor/helix"
12+homepage = "https://helix-editor.com"
413include = ["src/**/*", "README.md"]
5−version.workspace = true
6−authors.workspace = true
7−edition.workspace = true
8−license.workspace = true
9−rust-version.workspace = true
10−categories.workspace = true
11−repository.workspace = true
12−homepage.workspace = true
1314
1415[features]
1516default = ["crossterm"]
1617
1718[dependencies]
18−helix-view = { path = "../helix-view", features = ["term"] }
19−helix-core = { path = "../helix-core" }
20−
21−bitflags = "2.4"
19+bitflags = "2.3"
2220cassowary = "0.3"
2321unicode-segmentation = "1.10"
24−crossterm = { version = "0.27", optional = true }
22+crossterm = { version = "0.26", optional = true }
2523termini = "1.0"
2624serde = { version = "1", "optional" = true, features = ["derive"]}
27−once_cell = "1.19"
25+once_cell = "1.18"
2826log = "~0.4"
27+helix-view = { version = "0.6", path = "../helix-view", features = ["term"] }
28+helix-core = { version = "0.6", path = "../helix-core" }
helix-tui/src/backend/crossterm.rs+33−51
@@ -32,21 +32,10 @@ fn vte_version() -> Option<usize> {
3232}
3333
3434/// Describes terminal capabilities like extended underline, truecolor, etc.
35−#[derive(Clone, Debug)]
35+#[derive(Copy, Clone, Debug, Default)]
3636struct Capabilities {
3737 /// Support for undercurled, underdashed, etc.
3838 has_extended_underlines: bool,
39− /// Support for resetting the cursor style back to normal.
40− reset_cursor_command: String,
41−}
42−
43−impl Default for Capabilities {
44− fn default() -> Self {
45− Self {
46− has_extended_underlines: false,
47− reset_cursor_command: "\x1B[0 q".to_string(),
48− }
49− }
5039}
5140
5241impl Capabilities {
@@ -65,10 +54,6 @@ impl Capabilities {
6554 || t.extended_cap("Su").is_some()
6655 || vte_version() >= Some(5102)
6756 || matches!(term_program().as_deref(), Some("WezTerm")),
68− reset_cursor_command: t
69− .utf8_string_cap(termini::StringCapability::CursorNormal)
70− .unwrap_or("\x1B[0 q")
71− .to_string(),
7257 },
7358 }
7459 }
@@ -169,8 +154,7 @@ where
169154
170155 fn restore(&mut self, config: Config) -> io::Result<()> {
171156 // reset cursor shape
172− self.buffer
173− .write_all(self.capabilities.reset_cursor_command.as_bytes())?;
157+ write!(self.buffer, "\x1B[0 q")?;
174158 if config.enable_mouse_capture {
175159 execute!(self.buffer, DisableMouseCapture)?;
176160 }
@@ -217,7 +201,7 @@ where
217201 for (x, y, cell) in content {
218202 // Move the cursor if the previous location was not (x - 1, y)
219203 if !matches!(last_pos, Some(p) if x == p.0 + 1 && y == p.1) {
220− queue!(self.buffer, MoveTo(x, y))?;
204+ map_error(queue!(self.buffer, MoveTo(x, y)))?;
221205 }
222206 last_pos = Some((x, y));
223207 if cell.modifier != modifier {
@@ -230,12 +214,12 @@ where
230214 }
231215 if cell.fg != fg {
232216 let color = CColor::from(cell.fg);
233− queue!(self.buffer, SetForegroundColor(color))?;
217+ map_error(queue!(self.buffer, SetForegroundColor(color)))?;
234218 fg = cell.fg;
235219 }
236220 if cell.bg != bg {
237221 let color = CColor::from(cell.bg);
238− queue!(self.buffer, SetBackgroundColor(color))?;
222+ map_error(queue!(self.buffer, SetBackgroundColor(color)))?;
239223 bg = cell.bg;
240224 }
241225
@@ -243,7 +227,7 @@ where
243227 if self.capabilities.has_extended_underlines {
244228 if cell.underline_color != underline_color {
245229 let color = CColor::from(cell.underline_color);
246− queue!(self.buffer, SetUnderlineColor(color))?;
230+ map_error(queue!(self.buffer, SetUnderlineColor(color)))?;
247231 underline_color = cell.underline_color;
248232 }
249233 } else {
@@ -255,24 +239,24 @@ where
255239
256240 if new_underline_style != underline_style {
257241 let attr = CAttribute::from(new_underline_style);
258− queue!(self.buffer, SetAttribute(attr))?;
242+ map_error(queue!(self.buffer, SetAttribute(attr)))?;
259243 underline_style = new_underline_style;
260244 }
261245
262− queue!(self.buffer, Print(&cell.symbol))?;
246+ map_error(queue!(self.buffer, Print(&cell.symbol)))?;
263247 }
264248
265− queue!(
249+ map_error(queue!(
266250 self.buffer,
267251 SetUnderlineColor(CColor::Reset),
268252 SetForegroundColor(CColor::Reset),
269253 SetBackgroundColor(CColor::Reset),
270254 SetAttribute(CAttribute::Reset)
271− )
255+ ))
272256 }
273257
274258 fn hide_cursor(&mut self) -> io::Result<()> {
275− execute!(self.buffer, Hide)
259+ map_error(execute!(self.buffer, Hide))
276260 }
277261
278262 fn show_cursor(&mut self, kind: CursorKind) -> io::Result<()> {
@@ -282,7 +266,7 @@ where
282266 CursorKind::Underline => SetCursorStyle::SteadyUnderScore,
283267 CursorKind::Hidden => unreachable!(),
284268 };
285− execute!(self.buffer, Show, shape)
269+ map_error(execute!(self.buffer, Show, shape))
286270 }
287271
288272 fn get_cursor(&mut self) -> io::Result<(u16, u16)> {
@@ -291,11 +275,11 @@ where
291275 }
292276
293277 fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> {
294− execute!(self.buffer, MoveTo(x, y))
278+ map_error(execute!(self.buffer, MoveTo(x, y)))
295279 }
296280
297281 fn clear(&mut self) -> io::Result<()> {
298− execute!(self.buffer, Clear(ClearType::All))
282+ map_error(execute!(self.buffer, Clear(ClearType::All)))
299283 }
300284
301285 fn size(&self) -> io::Result<Rect> {
@@ -310,6 +294,10 @@ where
310294 }
311295}
312296
297+fn map_error(error: crossterm::Result<()>) -> io::Result<()> {
298+ error.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))
299+}
300+
313301#[derive(Debug)]
314302struct ModifierDiff {
315303 pub from: Modifier,
@@ -324,54 +312,48 @@ impl ModifierDiff {
324312 //use crossterm::Attribute;
325313 let removed = self.from - self.to;
326314 if removed.contains(Modifier::REVERSED) {
327− queue!(w, SetAttribute(CAttribute::NoReverse))?;
315+ map_error(queue!(w, SetAttribute(CAttribute::NoReverse)))?;
328316 }
329317 if removed.contains(Modifier::BOLD) {
330− queue!(w, SetAttribute(CAttribute::NormalIntensity))?;
318+ map_error(queue!(w, SetAttribute(CAttribute::NormalIntensity)))?;
331319 if self.to.contains(Modifier::DIM) {
332− queue!(w, SetAttribute(CAttribute::Dim))?;
320+ map_error(queue!(w, SetAttribute(CAttribute::Dim)))?;
333321 }
334322 }
335323 if removed.contains(Modifier::ITALIC) {
336− queue!(w, SetAttribute(CAttribute::NoItalic))?;
324+ map_error(queue!(w, SetAttribute(CAttribute::NoItalic)))?;
337325 }
338326 if removed.contains(Modifier::DIM) {
339− queue!(w, SetAttribute(CAttribute::NormalIntensity))?;
327+ map_error(queue!(w, SetAttribute(CAttribute::NormalIntensity)))?;
340328 }
341329 if removed.contains(Modifier::CROSSED_OUT) {
342− queue!(w, SetAttribute(CAttribute::NotCrossedOut))?;
330+ map_error(queue!(w, SetAttribute(CAttribute::NotCrossedOut)))?;
343331 }
344332 if removed.contains(Modifier::SLOW_BLINK) || removed.contains(Modifier::RAPID_BLINK) {
345− queue!(w, SetAttribute(CAttribute::NoBlink))?;
346− }
347− if removed.contains(Modifier::HIDDEN) {
348− queue!(w, SetAttribute(CAttribute::NoHidden))?;
333+ map_error(queue!(w, SetAttribute(CAttribute::NoBlink)))?;
349334 }
350335
351336 let added = self.to - self.from;
352337 if added.contains(Modifier::REVERSED) {
353− queue!(w, SetAttribute(CAttribute::Reverse))?;
338+ map_error(queue!(w, SetAttribute(CAttribute::Reverse)))?;
354339 }
355340 if added.contains(Modifier::BOLD) {
356− queue!(w, SetAttribute(CAttribute::Bold))?;
341+ map_error(queue!(w, SetAttribute(CAttribute::Bold)))?;
357342 }
358343 if added.contains(Modifier::ITALIC) {
359− queue!(w, SetAttribute(CAttribute::Italic))?;
344+ map_error(queue!(w, SetAttribute(CAttribute::Italic)))?;
360345 }
361346 if added.contains(Modifier::DIM) {
362− queue!(w, SetAttribute(CAttribute::Dim))?;
347+ map_error(queue!(w, SetAttribute(CAttribute::Dim)))?;
363348 }
364349 if added.contains(Modifier::CROSSED_OUT) {
365− queue!(w, SetAttribute(CAttribute::CrossedOut))?;
350+ map_error(queue!(w, SetAttribute(CAttribute::CrossedOut)))?;
366351 }
367352 if added.contains(Modifier::SLOW_BLINK) {
368− queue!(w, SetAttribute(CAttribute::SlowBlink))?;
353+ map_error(queue!(w, SetAttribute(CAttribute::SlowBlink)))?;
369354 }
370355 if added.contains(Modifier::RAPID_BLINK) {
371− queue!(w, SetAttribute(CAttribute::RapidBlink))?;
372− }
373− if added.contains(Modifier::HIDDEN) {
374− queue!(w, SetAttribute(CAttribute::Hidden))?;
356+ map_error(queue!(w, SetAttribute(CAttribute::RapidBlink)))?;
375357 }
376358
377359 Ok(())
@@ -425,7 +407,7 @@ impl Command for SetUnderlineColor {
425407 }
426408
427409 #[cfg(windows)]
428− fn execute_winapi(&self) -> io::Result<()> {
410+ fn execute_winapi(&self) -> crossterm::Result<()> {
429411 Err(std::io::Error::new(
430412 std::io::ErrorKind::Other,
431413 "SetUnderlineColor not supported by winapi.",
helix-tui/src/buffer.rs+2−2
@@ -213,7 +213,7 @@ impl Buffer {
213213 && y < self.area.bottom()
214214 }
215215
216− /// Returns the index in the `Vec<Cell>` for the given global (x, y) coordinates.
216+ /// Returns the index in the Vec<Cell> for the given global (x, y) coordinates.
217217 ///
218218 /// Global coordinates are offset by the Buffer's area offset (`x`/`y`).
219219 ///
@@ -242,7 +242,7 @@ impl Buffer {
242242 ((y - self.area.y) as usize) * (self.area.width as usize) + ((x - self.area.x) as usize)
243243 }
244244
245− /// Returns the index in the `Vec<Cell>` for the given global (x, y) coordinates,
245+ /// Returns the index in the Vec<Cell> for the given global (x, y) coordinates,
246246 /// or `None` if the coordinates are outside the buffer's area.
247247 fn index_of_opt(&self, x: u16, y: u16) -> Option<usize> {
248248 if self.in_bounds(x, y) {
helix-tui/src/terminal.rs+14
@@ -65,6 +65,20 @@ where
6565 viewport: Viewport,
6666}
6767
68+impl<B> Drop for Terminal<B>
69+where
70+ B: Backend,
71+{
72+ fn drop(&mut self) {
73+ // Attempt to restore the cursor state
74+ if self.cursor_kind == CursorKind::Hidden {
75+ if let Err(err) = self.show_cursor(CursorKind::Block) {
76+ eprintln!("Failed to show the cursor: {}", err);
77+ }
78+ }
79+ }
80+}
81+
6882impl<B> Terminal<B>
6983where
7084 B: Backend,
helix-vcs/Cargo.toml+10−12
@@ -1,25 +1,23 @@
11[package]
22name = "helix-vcs"
3−version.workspace = true
4−authors.workspace = true
5−edition.workspace = true
6−license.workspace = true
7−rust-version.workspace = true
8−categories.workspace = true
9−repository.workspace = true
10−homepage.workspace = true
3+version = "0.6.0"
4+authors = ["Blaž Hrastnik <blaz@mxxn.io>"]
5+edition = "2021"
6+license = "MPL-2.0"
7+categories = ["editor"]
8+repository = "https://github.com/helix-editor/helix"
9+homepage = "https://helix-editor.com"
1110
1211# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1312
1413[dependencies]
15−helix-core = { path = "../helix-core" }
16−helix-event = { path = "../helix-event" }
14+helix-core = { version = "0.6", path = "../helix-core" }
1715
1816tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "parking_lot", "macros"] }
1917parking_lot = "0.12"
2018arc-swap = { version = "1.6.0" }
2119
22−gix = { version = "0.57.0", default-features = false , optional = true }
20+gix = { version = "0.48.0", default-features = false , optional = true }
2321imara-diff = "0.1.5"
2422anyhow = "1"
2523
@@ -29,4 +27,4 @@ log = "0.4"
2927git = ["gix"]
3028
3129[dev-dependencies]
32−tempfile = "3.8"
30+tempfile = "3.7"
helix-vcs/src/diff.rs+19−6
@@ -2,10 +2,10 @@ use std::ops::Range;
22use std::sync::Arc;
33
44use helix_core::Rope;
5−use helix_event::RenderLockGuard;
65use imara_diff::Algorithm;
76use parking_lot::{Mutex, MutexGuard};
87use tokio::sync::mpsc::{unbounded_channel, UnboundedSender};
8+use tokio::sync::{Notify, OwnedRwLockReadGuard, RwLock};
99use tokio::task::JoinHandle;
1010use tokio::time::Instant;
1111
@@ -14,9 +14,11 @@ use crate::diff::worker::DiffWorker;
1414mod line_cache;
1515mod worker;
1616
17+type RedrawHandle = (Arc<Notify>, Arc<RwLock<()>>);
18+
1719/// A rendering lock passed to the differ the prevents redraws from occurring
1820struct RenderLock {
19− pub lock: RenderLockGuard,
21+ pub lock: OwnedRwLockReadGuard<()>,
2022 pub timeout: Option<Instant>,
2123}
2224
@@ -36,22 +38,28 @@ struct DiffInner {
3638#[derive(Clone, Debug)]
3739pub struct DiffHandle {
3840 channel: UnboundedSender<Event>,
41+ render_lock: Arc<RwLock<()>>,
3942 diff: Arc<Mutex<DiffInner>>,
4043 inverted: bool,
4144}
4245
4346impl DiffHandle {
44− pub fn new(diff_base: Rope, doc: Rope) -> DiffHandle {
45− DiffHandle::new_with_handle(diff_base, doc).0
47+ pub fn new(diff_base: Rope, doc: Rope, redraw_handle: RedrawHandle) -> DiffHandle {
48+ DiffHandle::new_with_handle(diff_base, doc, redraw_handle).0
4649 }
4750
48− fn new_with_handle(diff_base: Rope, doc: Rope) -> (DiffHandle, JoinHandle<()>) {
51+ fn new_with_handle(
52+ diff_base: Rope,
53+ doc: Rope,
54+ redraw_handle: RedrawHandle,
55+ ) -> (DiffHandle, JoinHandle<()>) {
4956 let (sender, receiver) = unbounded_channel();
5057 let diff: Arc<Mutex<DiffInner>> = Arc::default();
5158 let worker = DiffWorker {
5259 channel: receiver,
5360 diff: diff.clone(),
5461 new_hunks: Vec::default(),
62+ redraw_notify: redraw_handle.0,
5563 diff_finished_notify: Arc::default(),
5664 };
5765 let handle = tokio::spawn(worker.run(diff_base, doc));
@@ -59,6 +67,7 @@ impl DiffHandle {
5967 channel: sender,
6068 diff,
6169 inverted: false,
70+ render_lock: redraw_handle.1,
6271 };
6372 (differ, handle)
6473 }
@@ -78,7 +87,11 @@ impl DiffHandle {
7887 /// This function is only intended to be called from within the rendering loop
7988 /// if called from elsewhere it may fail to acquire the render lock and panic
8089 pub fn update_document(&self, doc: Rope, block: bool) -> bool {
81− let lock = helix_event::lock_frame();
90+ // unwrap is ok here because the rendering lock is
91+ // only exclusively locked during redraw.
92+ // This function is only intended to be called
93+ // from the core rendering loop where no redraw can happen in parallel
94+ let lock = self.render_lock.clone().try_read_owned().unwrap();
8295 let timeout = if block {
8396 None
8497 } else {
helix-vcs/src/diff/worker.rs+9−3
@@ -23,6 +23,7 @@ pub(super) struct DiffWorker {
2323 pub channel: UnboundedReceiver<Event>,
2424 pub diff: Arc<Mutex<DiffInner>>,
2525 pub new_hunks: Vec<Hunk>,
26+ pub redraw_notify: Arc<Notify>,
2627 pub diff_finished_notify: Arc<Notify>,
2728}
2829
@@ -31,7 +32,11 @@ impl DiffWorker {
3132 let mut accumulator = EventAccumulator::new();
3233 accumulator.handle_event(event).await;
3334 accumulator
34− .accumulate_debounced_events(&mut self.channel, self.diff_finished_notify.clone())
35+ .accumulate_debounced_events(
36+ &mut self.channel,
37+ self.redraw_notify.clone(),
38+ self.diff_finished_notify.clone(),
39+ )
3540 .await;
3641 (accumulator.doc, accumulator.diff_base)
3742 }
@@ -132,6 +137,7 @@ impl<'a> EventAccumulator {
132137 async fn accumulate_debounced_events(
133138 &mut self,
134139 channel: &mut UnboundedReceiver<Event>,
140+ redraw_notify: Arc<Notify>,
135141 diff_finished_notify: Arc<Notify>,
136142 ) {
137143 let async_debounce = Duration::from_millis(DIFF_DEBOUNCE_TIME_ASYNC);
@@ -158,7 +164,7 @@ impl<'a> EventAccumulator {
158164 None => {
159165 tokio::spawn(async move {
160166 diff_finished_notify.notified().await;
161− helix_event::request_redraw();
167+ redraw_notify.notify_one();
162168 });
163169 }
164170 // diff is performed inside the rendering loop
@@ -184,7 +190,7 @@ impl<'a> EventAccumulator {
184190 // and wait until the diff occurs to trigger an async redraw
185191 log::info!("Diff computation timed out, update of diffs might appear delayed");
186192 diff_finished_notify.notified().await;
187− helix_event::request_redraw()
193+ redraw_notify.notify_one();
188194 });
189195 }
190196 // a blocking diff is performed inside the rendering loop
helix-vcs/src/diff/worker/test.rs+5−1
@@ -5,7 +5,11 @@ use crate::diff::{DiffHandle, Hunk};
55
66impl DiffHandle {
77 fn new_test(diff_base: &str, doc: &str) -> (DiffHandle, JoinHandle<()>) {
8− DiffHandle::new_with_handle(Rope::from_str(diff_base), Rope::from_str(doc))
8+ DiffHandle::new_with_handle(
9+ Rope::from_str(diff_base),
10+ Rope::from_str(doc),
11+ Default::default(),
12+ )
913 }
1014 async fn into_diff(self, handle: JoinHandle<()>) -> Vec<Hunk> {
1115 let diff = self.diff;
helix-vcs/src/git.rs+5−5
@@ -3,7 +3,7 @@ use arc_swap::ArcSwap;
33use std::path::Path;
44use std::sync::Arc;
55
6−use gix::objs::tree::EntryKind;
6+use gix::objs::tree::EntryMode;
77use gix::sec::trust::DefaultForLevel;
88use gix::{Commit, ObjectId, Repository, ThreadSafeRepository};
99
@@ -126,14 +126,14 @@ fn find_file_in_commit(repo: &Repository, commit: &Commit, file: &Path) -> Resul
126126 let rel_path = file.strip_prefix(repo_dir)?;
127127 let tree = commit.tree()?;
128128 let tree_entry = tree
129− .lookup_entry_by_path(rel_path, &mut Vec::new())?
129+ .lookup_entry_by_path(rel_path)?
130130 .context("file is untracked")?;
131− match tree_entry.mode().kind() {
131+ match tree_entry.mode() {
132132 // not a file, everything is new, do not show diff
133− mode @ (EntryKind::Tree | EntryKind::Commit | EntryKind::Link) => {
133+ mode @ (EntryMode::Tree | EntryMode::Commit | EntryMode::Link) => {
134134 bail!("entry at {} is not a file but a {mode:?}", file.display())
135135 }
136136 // found a file
137− EntryKind::Blob | EntryKind::BlobExecutable => Ok(tree_entry.object_id()),
137+ EntryMode::Blob | EntryMode::BlobExecutable => Ok(tree_entry.object_id()),
138138 }
139139}
helix-view/Cargo.toml+18−21
@@ -1,34 +1,31 @@
11[package]
22name = "helix-view"
3+version = "0.6.0"
4+authors = ["Blaž Hrastnik <blaz@mxxn.io>"]
5+edition = "2021"
6+license = "MPL-2.0"
37description = "UI abstractions for use in backends"
4−version.workspace = true
5−authors.workspace = true
6−edition.workspace = true
7−license.workspace = true
8−rust-version.workspace = true
9−categories.workspace = true
10−repository.workspace = true
11−homepage.workspace = true
8+categories = ["editor"]
9+repository = "https://github.com/helix-editor/helix"
10+homepage = "https://helix-editor.com"
1211
1312[features]
1413default = []
1514term = ["crossterm"]
1615
1716[dependencies]
18−helix-core = { path = "../helix-core" }
19−helix-event = { path = "../helix-event" }
20−helix-loader = { path = "../helix-loader" }
21−helix-lsp = { path = "../helix-lsp" }
22−helix-dap = { path = "../helix-dap" }
23−helix-vcs = { path = "../helix-vcs" }
24−
25−bitflags = "2.4"
17+bitflags = "2.3"
2618anyhow = "1"
27−crossterm = { version = "0.27", optional = true }
19+helix-core = { version = "0.6", path = "../helix-core" }
20+helix-loader = { version = "0.6", path = "../helix-loader" }
21+helix-lsp = { version = "0.6", path = "../helix-lsp" }
22+helix-dap = { version = "0.6", path = "../helix-dap" }
23+crossterm = { version = "0.26", optional = true }
24+helix-vcs = { version = "0.6", path = "../helix-vcs" }
2825
2926# Conversion traits
30−once_cell = "1.19"
31−url = "2.5.0"
27+once_cell = "1.18"
28+url = "2"
3229
3330arc-swap = { version = "1.6.0" }
3431
@@ -45,12 +42,12 @@ serde_json = "1.0"
4542toml = "0.7"
4643log = "~0.4"
4744
48−which = "5.0.0"
45+which = "4.4"
4946parking_lot = "0.12.1"
5047
5148
5249[target.'cfg(windows)'.dependencies]
53−clipboard-win = { version = "5.0", features = ["std"] }
50+clipboard-win = { version = "4.5", features = ["std"] }
5451
5552[target.'cfg(unix)'.dependencies]
5653libc = "0.2"
helix-view/src/clipboard.rs+2−7
@@ -73,14 +73,9 @@ pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
7373
7474#[cfg(target_os = "macos")]
7575pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
76− use crate::env::{binary_exists, env_var_is_set};
76+ use crate::env::binary_exists;
7777
78− if env_var_is_set("TMUX") && binary_exists("tmux") {
79− command_provider! {
80− paste => "tmux", "save-buffer", "-";
81− copy => "tmux", "load-buffer", "-w", "-";
82− }
83− } else if binary_exists("pbcopy") && binary_exists("pbpaste") {
78+ if binary_exists("pbcopy") && binary_exists("pbpaste") {
8479 command_provider! {
8580 paste => "pbpaste";
8681 copy => "pbcopy";
helix-view/src/document.rs+40−72
@@ -33,7 +33,7 @@ use helix_core::{
3333 ChangeSet, Diagnostic, LineEnding, Range, Rope, RopeBuilder, Selection, Syntax, Transaction,
3434};
3535
36−use crate::editor::Config;
36+use crate::editor::{Config, RedrawHandle};
3737use crate::{DocumentId, Editor, Theme, View, ViewId};
3838
3939/// 8kB of buffer space for encoding and decoding `Rope`s.
@@ -708,7 +708,7 @@ impl Document {
708708 let mut doc = Self::from(rope, Some((encoding, has_bom)), config);
709709
710710 // set the path and try detecting the language
711− doc.set_path(Some(path));
711+ doc.set_path(Some(path))?;
712712 if let Some(loader) = config_loader {
713713 doc.detect_language(loader);
714714 }
@@ -733,16 +733,16 @@ impl Document {
733733 // We can't use anyhow::Result here since the output of the future has to be
734734 // clonable to be used as shared future. So use a custom error type.
735735 pub fn format(&self) -> Option<BoxFuture<'static, Result<Transaction, FormatterError>>> {
736− if let Some((fmt_cmd, fmt_args)) = self
736+ if let Some(formatter) = self
737737 .language_config()
738− .and_then(|c| c.formatter.as_ref())
739− .and_then(|formatter| Some((which::which(&formatter.command).ok()?, &formatter.args)))
738+ .and_then(|c| c.formatter.clone())
739+ .filter(|formatter| which::which(&formatter.command).is_ok())
740740 {
741741 use std::process::Stdio;
742742 let text = self.text().clone();
743− let mut process = tokio::process::Command::new(&fmt_cmd);
743+ let mut process = tokio::process::Command::new(&formatter.command);
744744 process
745− .args(fmt_args)
745+ .args(&formatter.args)
746746 .stdin(Stdio::piped())
747747 .stdout(Stdio::piped())
748748 .stderr(Stdio::piped());
@@ -751,7 +751,7 @@ impl Document {
751751 let mut process = process
752752 .spawn()
753753 .map_err(|e| FormatterError::SpawningFailed {
754− command: fmt_cmd.to_string_lossy().into(),
754+ command: formatter.command.clone(),
755755 error: e.kind(),
756756 })?;
757757 {
@@ -853,7 +853,7 @@ impl Document {
853853 let text = self.text().clone();
854854
855855 let path = match path {
856− Some(path) => helix_core::path::get_canonicalized_path(&path),
856+ Some(path) => helix_core::path::get_canonicalized_path(&path)?,
857857 None => {
858858 if self.path.is_none() {
859859 bail!("Can't save with no path set!");
@@ -995,6 +995,7 @@ impl Document {
995995 &mut self,
996996 view: &mut View,
997997 provider_registry: &DiffProviderRegistry,
998+ redraw_handle: RedrawHandle,
998999 ) -> Result<(), Error> {
9991000 let encoding = self.encoding;
10001001 let path = self
@@ -1022,7 +1023,7 @@ impl Document {
10221023 self.detect_indent_and_line_ending();
10231024
10241025 match provider_registry.get_diff_base(&path) {
1025− Some(diff_base) => self.set_diff_base(diff_base),
1026+ Some(diff_base) => self.set_diff_base(diff_base, redraw_handle),
10261027 None => self.diff_handle = None,
10271028 }
10281029
@@ -1046,14 +1047,18 @@ impl Document {
10461047 self.encoding
10471048 }
10481049
1049− pub fn set_path(&mut self, path: Option<&Path>) {
1050− let path = path.map(helix_core::path::get_canonicalized_path);
1050+ pub fn set_path(&mut self, path: Option<&Path>) -> Result<(), std::io::Error> {
1051+ let path = path
1052+ .map(helix_core::path::get_canonicalized_path)
1053+ .transpose()?;
10511054
10521055 // if parent doesn't exist we still want to open the document
10531056 // and error out when document is saved
10541057 self.path = path;
10551058
10561059 self.detect_readonly();
1060+
1061+ Ok(())
10571062 }
10581063
10591064 /// Set the programming language for the file and load associated data (e.g. highlighting)
@@ -1206,47 +1211,30 @@ impl Document {
12061211 transaction.changes(),
12071212 );
12081213 if res.is_err() {
1209− log::error!("TS parser failed, disabling TS for the current buffer: {res:?}");
1214+ log::error!("TS parser failed, disabeling TS for the current buffer: {res:?}");
12101215 self.syntax = None;
12111216 }
12121217 }
12131218
12141219 let changes = transaction.changes();
12151220
1216− // map diagnostics over changes too
1217− changes.update_positions(self.diagnostics.iter_mut().map(|diagnostic| {
1218− let assoc = if diagnostic.starts_at_word {
1219− Assoc::BeforeWord
1220− } else {
1221− Assoc::After
1222− };
1223− (&mut diagnostic.range.start, assoc)
1224− }));
1225− changes.update_positions(self.diagnostics.iter_mut().map(|diagnostic| {
1226− let assoc = if diagnostic.ends_at_word {
1227− Assoc::AfterWord
1228− } else {
1229− Assoc::Before
1230− };
1231− (&mut diagnostic.range.end, assoc)
1232− }));
1233− self.diagnostics.retain_mut(|diagnostic| {
1234− if diagnostic.range.start > diagnostic.range.end
1235− || (!diagnostic.zero_width && diagnostic.range.start == diagnostic.range.end)
1236− {
1237− return false;
1238− }
1221+ changes.update_positions(
1222+ self.diagnostics
1223+ .iter_mut()
1224+ .map(|diagnostic| (&mut diagnostic.range.start, Assoc::After)),
1225+ );
1226+ changes.update_positions(
1227+ self.diagnostics
1228+ .iter_mut()
1229+ .map(|diagnostic| (&mut diagnostic.range.end, Assoc::After)),
1230+ );
1231+ // map state.diagnostics over changes::map_pos too
1232+ for diagnostic in &mut self.diagnostics {
12391233 diagnostic.line = self.text.char_to_line(diagnostic.range.start);
1240− true
1241− });
1234+ }
12421235
1243− self.diagnostics.sort_unstable_by_key(|diagnostic| {
1244− (
1245− diagnostic.range,
1246− diagnostic.severity,
1247− diagnostic.language_server_id,
1248− )
1249− });
1236+ self.diagnostics
1237+ .sort_unstable_by_key(|diagnostic| diagnostic.range);
12501238
12511239 // Update the inlay hint annotations' positions, helping ensure they are displayed in the proper place
12521240 let apply_inlay_hint_changes = |annotations: &mut Rc<[InlineAnnotation]>| {
@@ -1599,13 +1587,13 @@ impl Document {
15991587 }
16001588
16011589 /// Intialize/updates the differ for this document with a new base.
1602− pub fn set_diff_base(&mut self, diff_base: Vec<u8>) {
1590+ pub fn set_diff_base(&mut self, diff_base: Vec<u8>, redraw_handle: RedrawHandle) {
16031591 if let Ok((diff_base, ..)) = from_reader(&mut diff_base.as_slice(), Some(self.encoding)) {
16041592 if let Some(differ) = &self.diff_handle {
16051593 differ.update_diff_base(diff_base);
16061594 return;
16071595 }
1608− self.diff_handle = Some(DiffHandle::new(diff_base, self.text.clone()))
1596+ self.diff_handle = Some(DiffHandle::new(diff_base, self.text.clone(), redraw_handle))
16091597 } else {
16101598 self.diff_handle = None;
16111599 }
@@ -1723,33 +1711,13 @@ impl Document {
17231711
17241712 pub fn replace_diagnostics(
17251713 &mut self,
1726− diagnostics: impl IntoIterator<Item = Diagnostic>,
1727− unchanged_sources: &[String],
1714+ mut diagnostics: Vec<Diagnostic>,
17281715 language_server_id: usize,
17291716 ) {
1730− if unchanged_sources.is_empty() {
1731− self.clear_diagnostics(language_server_id);
1732− } else {
1733− self.diagnostics.retain(|d| {
1734− if d.language_server_id != language_server_id {
1735− return true;
1736− }
1737−
1738− if let Some(source) = &d.source {
1739− unchanged_sources.contains(source)
1740− } else {
1741− false
1742− }
1743− });
1744− }
1745− self.diagnostics.extend(diagnostics);
1746− self.diagnostics.sort_unstable_by_key(|diagnostic| {
1747− (
1748− diagnostic.range,
1749− diagnostic.severity,
1750− diagnostic.language_server_id,
1751− )
1752− });
1717+ self.clear_diagnostics(language_server_id);
1718+ self.diagnostics.append(&mut diagnostics);
1719+ self.diagnostics
1720+ .sort_unstable_by_key(|diagnostic| diagnostic.range);
17531721 }
17541722
17551723 pub fn clear_diagnostics(&mut self, language_server_id: usize) {
helix-view/src/editor.rs+71−103
@@ -32,7 +32,7 @@ use std::{
3232use tokio::{
3333 sync::{
3434 mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
35− oneshot,
35+ oneshot, Notify, RwLock,
3636 },
3737 time::{sleep, Duration, Instant, Sleep},
3838};
@@ -42,9 +42,10 @@ use anyhow::{anyhow, bail, Error};
4242pub use helix_core::diagnostic::Severity;
4343use helix_core::{
4444 auto_pairs::AutoPairs,
45− syntax::{self, AutoPairConfig, IndentationHeuristic, SoftWrap},
46− Change, LineEnding, Position, Selection, NATIVE_LINE_ENDING,
45+ syntax::{self, AutoPairConfig, SoftWrap},
46+ Change, LineEnding, NATIVE_LINE_ENDING,
4747};
48+use helix_core::{Position, Selection};
4849use helix_dap as dap;
4950use helix_lsp::lsp;
5051
@@ -243,7 +244,7 @@ pub struct Config {
243244 /// Set a global text_width
244245 pub text_width: usize,
245246 /// Time in milliseconds since last keypress before idle timers trigger.
246− /// Used for autocompletion, set to 0 for instant. Defaults to 250ms.
247+ /// Used for autocompletion, set to 0 for instant. Defaults to 400ms.
247248 #[serde(
248249 serialize_with = "serialize_duration_millis",
249250 deserialize_with = "deserialize_duration_millis"
@@ -286,15 +287,8 @@ pub struct Config {
286287 pub workspace_lsp_roots: Vec<PathBuf>,
287288 /// Which line ending to choose for new documents. Defaults to `native`. i.e. `crlf` on Windows, otherwise `lf`.
288289 pub default_line_ending: LineEndingConfig,
289− /// Whether to automatically insert a trailing line-ending on write if missing. Defaults to `true`.
290− pub insert_final_newline: bool,
291290 /// Enables smart tab
292291 pub smart_tab: Option<SmartTabConfig>,
293− /// Draw border around popups.
294− pub popup_border: PopupBorderConfig,
295− /// Which indent heuristic to use when a new line is inserted
296− #[serde(default)]
297− pub indent_heuristic: IndentationHeuristic,
298292}
299293
300294#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)]
@@ -471,10 +465,10 @@ pub enum StatusLineElement {
471465 /// The LSP activity spinner
472466 Spinner,
473467
474− /// The file basename (the leaf of the open file's path)
468+ /// The base file name, including a dirty flag if it's unsaved
475469 FileBaseName,
476470
477− /// The relative file path
471+ /// The relative file path, including a dirty flag if it's unsaved
478472 FileName,
479473
480474 // The file modification indicator
@@ -731,7 +725,7 @@ pub struct WhitespaceCharacters {
731725impl Default for WhitespaceCharacters {
732726 fn default() -> Self {
733727 Self {
734− space: '·', // U+00B7
728+ space: '·', // U+00B7
735729 nbsp: '⍽', // U+237D
736730 tab: '→', // U+2192
737731 newline: '⏎', // U+23CE
@@ -759,13 +753,12 @@ impl Default for IndentGuidesConfig {
759753}
760754
761755/// Line ending configuration.
762−#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
756+#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
763757#[serde(rename_all = "lowercase")]
764758pub enum LineEndingConfig {
765759 /// The platform's native line ending.
766760 ///
767761 /// `crlf` on Windows, otherwise `lf`.
768− #[default]
769762 Native,
770763 /// Line feed.
771764 LF,
@@ -782,6 +775,12 @@ pub enum LineEndingConfig {
782775 Nel,
783776}
784777
778+impl Default for LineEndingConfig {
779+ fn default() -> Self {
780+ LineEndingConfig::Native
781+ }
782+}
783+
785784impl From<LineEndingConfig> for LineEnding {
786785 fn from(line_ending: LineEndingConfig) -> Self {
787786 match line_ending {
@@ -798,15 +797,6 @@ impl From<LineEndingConfig> for LineEnding {
798797 }
799798}
800799
801−#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
802−#[serde(rename_all = "kebab-case")]
803−pub enum PopupBorderConfig {
804− None,
805− All,
806− Popup,
807− Menu,
808−}
809−
810800impl Default for Config {
811801 fn default() -> Self {
812802 Self {
@@ -827,7 +817,7 @@ impl Default for Config {
827817 auto_completion: true,
828818 auto_format: true,
829819 auto_save: false,
830− idle_timeout: Duration::from_millis(250),
820+ idle_timeout: Duration::from_millis(400),
831821 preview_completion_insert: true,
832822 completion_trigger_len: 2,
833823 auto_info: true,
@@ -852,10 +842,7 @@ impl Default for Config {
852842 completion_replace: false,
853843 workspace_lsp_roots: Vec::new(),
854844 default_line_ending: LineEndingConfig::default(),
855− insert_final_newline: true,
856845 smart_tab: Some(SmartTabConfig::default()),
857− popup_border: PopupBorderConfig::None,
858− indent_heuristic: IndentationHeuristic::default(),
859846 }
860847 }
861848}
@@ -931,13 +918,16 @@ pub struct Editor {
931918 pub auto_pairs: Option<AutoPairs>,
932919
933920 pub idle_timer: Pin<Box<Sleep>>,
934− redraw_timer: Pin<Box<Sleep>>,
935921 last_motion: Option<Motion>,
936922 pub last_completion: Option<CompleteAction>,
937923
938924 pub exit_code: i32,
939925
940926 pub config_events: (UnboundedSender<ConfigEvent>, UnboundedReceiver<ConfigEvent>),
927+ /// Allows asynchronous tasks to control the rendering
928+ /// The `Notify` allows asynchronous tasks to request the editor to perform a redraw
929+ /// The `RwLock` blocks the editor from performing the render until an exclusive lock can be acquired
930+ pub redraw_handle: RedrawHandle,
941931 pub needs_redraw: bool,
942932 /// Cached position of the cursor calculated during rendering.
943933 /// The content of `cursor_cache` is returned by `Editor::cursor` if
@@ -964,6 +954,8 @@ pub struct Editor {
964954
965955pub type Motion = Box<dyn Fn(&mut Editor)>;
966956
957+pub type RedrawHandle = (Arc<Notify>, Arc<RwLock<()>>);
958+
967959#[derive(Debug)]
968960pub enum EditorEvent {
969961 DocumentSaved(DocumentSavedEventResult),
@@ -971,7 +963,6 @@ pub enum EditorEvent {
971963 LanguageServerMessage((usize, Call)),
972964 DebuggerEvent(dap::Payload),
973965 IdleTimer,
974− Redraw,
975966}
976967
977968#[derive(Debug, Clone)]
@@ -1062,29 +1053,19 @@ impl Editor {
10621053 status_msg: None,
10631054 autoinfo: None,
10641055 idle_timer: Box::pin(sleep(conf.idle_timeout)),
1065− redraw_timer: Box::pin(sleep(Duration::MAX)),
10661056 last_motion: None,
10671057 last_completion: None,
10681058 config,
10691059 auto_pairs,
10701060 exit_code: 0,
10711061 config_events: unbounded_channel(),
1062+ redraw_handle: Default::default(),
10721063 needs_redraw: false,
10731064 cursor_cache: Cell::new(None),
10741065 completion_request_handle: None,
10751066 }
10761067 }
10771068
1078− pub fn popup_border(&self) -> bool {
1079− self.config().popup_border == PopupBorderConfig::All
1080− || self.config().popup_border == PopupBorderConfig::Popup
1081− }
1082−
1083− pub fn menu_border(&self) -> bool {
1084− self.config().popup_border == PopupBorderConfig::All
1085− || self.config().popup_border == PopupBorderConfig::Menu
1086− }
1087−
10881069 pub fn apply_motion<F: Fn(&mut Self) + 'static>(&mut self, motion: F) {
10891070 motion(self);
10901071 self.last_motion = Some(Box::new(motion));
@@ -1208,80 +1189,71 @@ impl Editor {
12081189 }
12091190
12101191 /// Refreshes the language server for a given document
1211− pub fn refresh_language_servers(&mut self, doc_id: DocumentId) {
1192+ pub fn refresh_language_servers(&mut self, doc_id: DocumentId) -> Option<()> {
12121193 self.launch_language_servers(doc_id)
12131194 }
12141195
12151196 /// Launch a language server for a given document
1216− fn launch_language_servers(&mut self, doc_id: DocumentId) {
1197+ fn launch_language_servers(&mut self, doc_id: DocumentId) -> Option<()> {
12171198 if !self.config().lsp.enable {
1218− return;
1199+ return None;
12191200 }
12201201 // if doc doesn't have a URL it's a scratch buffer, ignore it
1221− let Some(doc) = self.documents.get_mut(&doc_id) else {
1222− return;
1223− };
1224− let Some(doc_url) = doc.url() else {
1225− return;
1226− };
1202+ let doc = self.documents.get_mut(&doc_id)?;
1203+ let doc_url = doc.url()?;
12271204 let (lang, path) = (doc.language.clone(), doc.path().cloned());
12281205 let config = doc.config.load();
12291206 let root_dirs = &config.workspace_lsp_roots;
12301207
1231− // store only successfully started language servers
1232− let language_servers = lang.as_ref().map_or_else(HashMap::default, |language| {
1208+ // try to find language servers based on the language name
1209+ let language_servers = lang.as_ref().and_then(|language| {
12331210 self.language_servers
12341211 .get(language, path.as_ref(), root_dirs, config.lsp.snippets)
1235− .filter_map(|(lang, client)| match client {
1236− Ok(client) => Some((lang, client)),
1237− Err(err) => {
1238− log::error!(
1239− "Failed to initialize the language servers for `{}` - `{}` {{ {} }}",
1240− language.scope(),
1241− lang,
1242− err
1243− );
1244− None
1245− }
1212+ .map_err(|e| {
1213+ log::error!(
1214+ "Failed to initialize the language servers for `{}` {{ {} }}",
1215+ language.scope(),
1216+ e
1217+ )
12461218 })
1247− .collect::<HashMap<_, _>>()
1219+ .ok()
12481220 });
12491221
1250− if language_servers.is_empty() {
1251− return;
1252− }
1222+ if let Some(language_servers) = language_servers {
1223+ let language_id = doc.language_id().map(ToOwned::to_owned).unwrap_or_default();
1224+
1225+ // only spawn new language servers if the servers aren't the same
12531226
1254− let language_id = doc.language_id().map(ToOwned::to_owned).unwrap_or_default();
1227+ let doc_language_servers_not_in_registry =
1228+ doc.language_servers.iter().filter(|(name, doc_ls)| {
1229+ language_servers
1230+ .get(*name)
1231+ .map_or(true, |ls| ls.id() != doc_ls.id())
1232+ });
12551233
1256− // only spawn new language servers if the servers aren't the same
1257− let doc_language_servers_not_in_registry =
1258− doc.language_servers.iter().filter(|(name, doc_ls)| {
1259− language_servers
1234+ for (_, language_server) in doc_language_servers_not_in_registry {
1235+ tokio::spawn(language_server.text_document_did_close(doc.identifier()));
1236+ }
1237+
1238+ let language_servers_not_in_doc = language_servers.iter().filter(|(name, ls)| {
1239+ doc.language_servers
12601240 .get(*name)
1261− .map_or(true, |ls| ls.id() != doc_ls.id())
1241+ .map_or(true, |doc_ls| ls.id() != doc_ls.id())
12621242 });
12631243
1264− for (_, language_server) in doc_language_servers_not_in_registry {
1265− tokio::spawn(language_server.text_document_did_close(doc.identifier()));
1266− }
1267−
1268− let language_servers_not_in_doc = language_servers.iter().filter(|(name, ls)| {
1269− doc.language_servers
1270− .get(*name)
1271− .map_or(true, |doc_ls| ls.id() != doc_ls.id())
1272− });
1244+ for (_, language_server) in language_servers_not_in_doc {
1245+ // TODO: this now races with on_init code if the init happens too quickly
1246+ tokio::spawn(language_server.text_document_did_open(
1247+ doc_url.clone(),
1248+ doc.version(),
1249+ doc.text(),
1250+ language_id.clone(),
1251+ ));
1252+ }
12731253
1274− for (_, language_server) in language_servers_not_in_doc {
1275− // TODO: this now races with on_init code if the init happens too quickly
1276− tokio::spawn(language_server.text_document_did_open(
1277− doc_url.clone(),
1278− doc.version(),
1279− doc.text(),
1280− language_id.clone(),
1281− ));
1254+ doc.language_servers = language_servers;
12821255 }
1283−
1284− doc.language_servers = language_servers;
1256+ Some(())
12851257 }
12861258
12871259 fn _refresh(&mut self) {
@@ -1464,7 +1436,7 @@ impl Editor {
14641436
14651437 // ??? possible use for integration tests
14661438 pub fn open(&mut self, path: &Path, action: Action) -> Result<DocumentId, Error> {
1467− let path = helix_core::path::get_canonicalized_path(path);
1439+ let path = helix_core::path::get_canonicalized_path(path)?;
14681440 let id = self.document_by_path(&path).map(|doc| doc.id);
14691441
14701442 let id = if let Some(id) = id {
@@ -1478,12 +1450,12 @@ impl Editor {
14781450 )?;
14791451
14801452 if let Some(diff_base) = self.diff_providers.get_diff_base(&path) {
1481− doc.set_diff_base(diff_base);
1453+ doc.set_diff_base(diff_base, self.redraw_handle.clone());
14821454 }
14831455 doc.set_version_control_head(self.diff_providers.get_current_head_name(&path));
14841456
14851457 let id = self.new_document(doc);
1486− self.launch_language_servers(id);
1458+ let _ = self.launch_language_servers(id);
14871459
14881460 id
14891461 };
@@ -1777,20 +1749,16 @@ impl Editor {
17771749 return EditorEvent::DebuggerEvent(event)
17781750 }
17791751
1780− _ = helix_event::redraw_requested() => {
1752+ _ = self.redraw_handle.0.notified() => {
17811753 if !self.needs_redraw{
17821754 self.needs_redraw = true;
17831755 let timeout = Instant::now() + Duration::from_millis(33);
1784− if timeout < self.idle_timer.deadline() && timeout < self.redraw_timer.deadline(){
1785− self.redraw_timer.as_mut().reset(timeout)
1756+ if timeout < self.idle_timer.deadline(){
1757+ self.idle_timer.as_mut().reset(timeout)
17861758 }
17871759 }
17881760 }
17891761
1790− _ = &mut self.redraw_timer => {
1791− self.redraw_timer.as_mut().reset(Instant::now() + Duration::from_secs(86400 * 365 * 30));
1792− return EditorEvent::Redraw
1793− }
17941762 _ = &mut self.idle_timer => {
17951763 return EditorEvent::IdleTimer
17961764 }
helix-view/src/gutter.rs+5−4
@@ -9,7 +9,8 @@ use crate::{
99};
1010
1111fn count_digits(n: usize) -> usize {
12− (usize::checked_ilog10(n).unwrap_or(0) + 1) as usize
12+ // TODO: use checked_log10 when MSRV reaches 1.67
13+ std::iter::successors(Some(n), |&n| (n >= 10).then_some(n / 10)).count()
1314}
1415
1516pub type GutterFn<'doc> = Box<dyn FnMut(usize, bool, bool, &mut String) -> Option<Style> + 'doc>;
@@ -93,9 +94,9 @@ pub fn diff<'doc>(
9394 theme: &Theme,
9495 _is_focused: bool,
9596) -> GutterFn<'doc> {
96− let added = theme.get("diff.plus.gutter");
97− let deleted = theme.get("diff.minus.gutter");
98− let modified = theme.get("diff.delta.gutter");
97+ let added = theme.get("diff.plus");
98+ let deleted = theme.get("diff.minus");
99+ let modified = theme.get("diff.delta");
99100 if let Some(diff_handle) = doc.diff_handle() {
100101 let hunks = diff_handle.load();
101102 let mut hunk_i = 0;
helix-view/src/handlers/dap.rs+3−1
@@ -369,7 +369,9 @@ impl Editor {
369369 {
370370 Ok(process) => process,
371371 Err(err) => {
372− self.set_error(format!("Error starting external terminal: {}", err));
372+ // TODO replace the pretty print {:?} with a regular format {}
373+ // when the MSRV is raised to 1.60.0
374+ self.set_error(format!("Error starting external terminal: {:?}", err));
373375 return true;
374376 }
375377 };
helix-view/src/input.rs+1−65
@@ -43,10 +43,6 @@ pub enum MouseEventKind {
4343 ScrollDown,
4444 /// Scrolled mouse wheel upwards (away from the user).
4545 ScrollUp,
46− /// Scrolled mouse wheel leftwards.
47− ScrollLeft,
48− /// Scrolled mouse wheel rightwards.
49− ScrollRight,
5046}
5147
5248/// Represents a mouse button.
@@ -462,8 +458,6 @@ impl From<crossterm::event::MouseEventKind> for MouseEventKind {
462458 crossterm::event::MouseEventKind::Moved => Self::Moved,
463459 crossterm::event::MouseEventKind::ScrollDown => Self::ScrollDown,
464460 crossterm::event::MouseEventKind::ScrollUp => Self::ScrollUp,
465− crossterm::event::MouseEventKind::ScrollLeft => Self::ScrollLeft,
466− crossterm::event::MouseEventKind::ScrollRight => Self::ScrollRight,
467461 }
468462 }
469463}
@@ -549,7 +543,7 @@ pub fn parse_macro(keys_str: &str) -> anyhow::Result<Vec<KeyEvent>> {
549543 if c == ">" {
550544 keys_res = Err(anyhow!("Unmatched '>'"));
551545 } else if c != "<" {
552− keys.push(if c == "-" { keys::MINUS } else { c });
546+ keys.push(c);
553547 i += end_i;
554548 } else {
555549 match s.find('>').context("'>' expected") {
@@ -813,64 +807,6 @@ mod test {
813807 },
814808 ])
815809 );
816−
817− assert_eq!(
818− parse_macro(":w aa-bb.txt<ret>").ok(),
819− Some(vec![
820− KeyEvent {
821− code: KeyCode::Char(':'),
822− modifiers: KeyModifiers::NONE,
823− },
824− KeyEvent {
825− code: KeyCode::Char('w'),
826− modifiers: KeyModifiers::NONE,
827− },
828− KeyEvent {
829− code: KeyCode::Char(' '),
830− modifiers: KeyModifiers::NONE,
831− },
832− KeyEvent {
833− code: KeyCode::Char('a'),
834− modifiers: KeyModifiers::NONE,
835− },
836− KeyEvent {
837− code: KeyCode::Char('a'),
838− modifiers: KeyModifiers::NONE,
839− },
840− KeyEvent {
841− code: KeyCode::Char('-'),
842− modifiers: KeyModifiers::NONE,
843− },
844− KeyEvent {
845− code: KeyCode::Char('b'),
846− modifiers: KeyModifiers::NONE,
847− },
848− KeyEvent {
849− code: KeyCode::Char('b'),
850− modifiers: KeyModifiers::NONE,
851− },
852− KeyEvent {
853− code: KeyCode::Char('.'),
854− modifiers: KeyModifiers::NONE,
855− },
856− KeyEvent {
857− code: KeyCode::Char('t'),
858− modifiers: KeyModifiers::NONE,
859− },
860− KeyEvent {
861− code: KeyCode::Char('x'),
862− modifiers: KeyModifiers::NONE,
863− },
864− KeyEvent {
865− code: KeyCode::Char('t'),
866− modifiers: KeyModifiers::NONE,
867− },
868− KeyEvent {
869− code: KeyCode::Enter,
870− modifiers: KeyModifiers::NONE,
871− },
872− ])
873− );
874810 }
875811
876812 #[test]
helix-view/src/register.rs+10−12
@@ -29,7 +29,6 @@ pub struct Registers {
2929 /// efficiently prepend new values in `Registers::push`.
3030 inner: HashMap<char, Vec<String>>,
3131 clipboard_provider: Box<dyn ClipboardProvider>,
32− pub last_search_register: char,
3332}
3433
3534impl Default for Registers {
@@ -37,7 +36,6 @@ impl Default for Registers {
3736 Self {
3837 inner: Default::default(),
3938 clipboard_provider: get_clipboard_provider(),
40− last_search_register: '/',
4139 }
4240 }
4341}
@@ -75,8 +73,8 @@ impl Registers {
7573 self.clipboard_provider.as_ref(),
7674 self.inner.get(&name),
7775 match name {
78− '+' => ClipboardType::Clipboard,
79− '*' => ClipboardType::Selection,
76+ '*' => ClipboardType::Clipboard,
77+ '+' => ClipboardType::Selection,
8078 _ => unreachable!(),
8179 },
8280 )),
@@ -95,8 +93,8 @@ impl Registers {
9593 self.clipboard_provider.set_contents(
9694 values.join(NATIVE_LINE_ENDING.as_str()),
9795 match name {
98− '+' => ClipboardType::Clipboard,
99− '*' => ClipboardType::Selection,
96+ '*' => ClipboardType::Clipboard,
97+ '+' => ClipboardType::Selection,
10098 _ => unreachable!(),
10199 },
102100 )?;
@@ -118,8 +116,8 @@ impl Registers {
118116 '#' | '.' | '%' => Err(anyhow::anyhow!("Register {name} does not support pushing")),
119117 '*' | '+' => {
120118 let clipboard_type = match name {
121− '+' => ClipboardType::Clipboard,
122− '*' => ClipboardType::Selection,
119+ '*' => ClipboardType::Clipboard,
120+ '+' => ClipboardType::Selection,
123121 _ => unreachable!(),
124122 };
125123 let contents = self.clipboard_provider.get_contents(clipboard_type)?;
@@ -172,8 +170,8 @@ impl Registers {
172170 ('#', "<selection indices>"),
173171 ('.', "<selection contents>"),
174172 ('%', "<document path>"),
175− ('+', "<system clipboard>"),
176− ('*', "<primary clipboard>"),
173+ ('*', "<system clipboard>"),
174+ ('+', "<primary clipboard>"),
177175 ]
178176 .iter()
179177 .copied(),
@@ -190,8 +188,8 @@ impl Registers {
190188 match name {
191189 '*' | '+' => {
192190 self.clear_clipboard(match name {
193− '+' => ClipboardType::Clipboard,
194− '*' => ClipboardType::Selection,
191+ '*' => ClipboardType::Clipboard,
192+ '+' => ClipboardType::Selection,
195193 _ => unreachable!(),
196194 });
197195 self.inner.remove(&name);
helix-view/src/theme.rs−6
@@ -297,11 +297,6 @@ impl Theme {
297297 self.highlights[index]
298298 }
299299
300− #[inline]
301− pub fn scope(&self, index: usize) -> &str {
302− &self.scopes[index]
303− }
304−
305300 pub fn name(&self) -> &str {
306301 &self.name
307302 }
@@ -364,7 +359,6 @@ impl Default for ThemePalette {
364359 fn default() -> Self {
365360 Self {
366361 palette: hashmap! {
367− "default".to_string() => Color::Reset,
368362 "black".to_string() => Color::Black,
369363 "red".to_string() => Color::Red,
370364 "green".to_string() => Color::Green,
languages.toml+196−433
@@ -3,7 +3,6 @@
33
44[language-server]
55
6−als = { command = "als" }
76awk-language-server = { command = "awk-language-server" }
87bash-language-server = { command = "bash-language-server", args = ["start"] }
98bass = { command = "bass", args = ["--lsp"] }
@@ -16,7 +15,6 @@ clojure-lsp = { command = "clojure-lsp" }
1615cmake-language-server = { command = "cmake-language-server" }
1716crystalline = { command = "crystalline", args = ["--stdio"] }
1817cs = { command = "cs", args = ["launch", "--contrib", "smithy-language-server", "--", "0"] }
19−csharp-ls = { command = "csharp-ls" }
2018cuelsp = { command = "cuelsp" }
2119dart = { command = "dart", args = ["language-server", "--client-id=helix"] }
2220dhall-lsp-server = { command = "dhall-lsp-server" }
@@ -31,7 +29,6 @@ forth-lsp = { command = "forth-lsp" }
3129fortls = { command = "fortls", args = ["--lowercase_intrinsics"] }
3230fsharp-ls = { command = "fsautocomplete", config = { AutomaticWorkspaceInit = true } }
3331gleam = { command = "gleam", args = ["lsp"] }
34−graphql-language-service = { command = "graphql-lsp", args = ["server", "-m", "stream"] }
3532haskell-language-server = { command = "haskell-language-server-wrapper", args = ["--lsp"] }
3633idris2-lsp = { command = "idris2-lsp" }
3734intelephense = { command = "intelephense", args = ["--stdio"] }
@@ -40,7 +37,6 @@ jsonnet-language-server = { command = "jsonnet-language-server", args= ["-t", "-
4037julia = { command = "julia", timeout = 60, args = [ "--startup-file=no", "--history-file=no", "--quiet", "-e", "using LanguageServer; runserver()", ] }
4138kotlin-language-server = { command = "kotlin-language-server" }
4239lean = { command = "lean", args = [ "--server" ] }
43−ltex-ls = { command = "ltex-ls" }
4440markdoc-ls = { command = "markdoc-ls", args = ["--stdio"] }
4541marksman = { command = "marksman", args = ["server"] }
4642metals = { command = "metals", config = { "isHttpEnabled" = true } }
@@ -48,7 +44,6 @@ mint = { command = "mint", args = ["ls"] }
4844nil = { command = "nil" }
4945nimlangserver = { command = "nimlangserver" }
5046nls = { command = "nls" }
51−nu-lsp = { command = "nu", args = [ "--lsp" ] }
5247ocamllsp = { command = "ocamllsp" }
5348ols = { command = "ols", args = [] }
5449omnisharp = { command = "OmniSharp", args = [ "--languageserver" ] }
@@ -59,8 +54,6 @@ perlnavigator = { command = "perlnavigator", args= ["--stdio"] }
5954prisma-language-server = { command = "prisma-language-server", args = ["--stdio"] }
6055purescript-language-server = { command = "purescript-language-server", args = ["--stdio"] }
6156pylsp = { command = "pylsp" }
62−pyright = { command = "pyright-langserver", args = ["--stdio"], config = {} }
63−pylyzer = { command = "pylyzer", args = ["--server"] }
6457qmlls = { command = "qmlls" }
6558r = { command = "R", args = ["--no-echo", "-e", "languageserver::run()"] }
6659racket = { command = "racket", args = ["-l", "racket-langserver"] }
@@ -74,30 +67,24 @@ solc = { command = "solc", args = ["--lsp"] }
7467sourcekit-lsp = { command = "sourcekit-lsp" }
7568svlangserver = { command = "svlangserver", args = [] }
7669swipl = { command = "swipl", args = [ "-g", "use_module(library(lsp_server))", "-g", "lsp_server:main", "-t", "halt", "--", "stdio" ] }
77−tailwindcss-ls = { command = "tailwindcss-language-server", args = ["--stdio"] }
7870taplo = { command = "taplo", args = ["lsp", "stdio"] }
79−templ = { command = "templ", args = ["lsp"] }
8071terraform-ls = { command = "terraform-ls", args = ["serve"] }
8172texlab = { command = "texlab" }
8273vala-language-server = { command = "vala-language-server" }
8374vhdl_ls = { command = "vhdl_ls", args = [] }
8475vlang-language-server = { command = "v-analyzer" }
85−vscode-css-language-server = { command = "vscode-css-language-server", args = ["--stdio"], config = { provideFormatter = true, css = { validate = { enable = true } } } }
76+vscode-css-language-server = { command = "vscode-css-language-server", args = ["--stdio"], config = { "provideFormatter" = true }}
8677vscode-html-language-server = { command = "vscode-html-language-server", args = ["--stdio"], config = { provideFormatter = true } }
87−vscode-json-language-server = { command = "vscode-json-language-server", args = ["--stdio"], config = { provideFormatter = true, json = { validate = { enable = true } } } }
78+vscode-json-language-server = { command = "vscode-json-language-server", args = ["--stdio"], config = { provideFormatter = true } }
8879vuels = { command = "vue-language-server", args = ["--stdio"], config = { typescript = { tsdk = "node_modules/typescript/lib/" } } }
8980wgsl_analyzer = { command = "wgsl_analyzer" }
9081yaml-language-server = { command = "yaml-language-server", args = ["--stdio"] }
9182zls = { command = "zls" }
9283blueprint-compiler = { command = "blueprint-compiler", args = ["lsp"] }
93−typst-lsp = { command = "typst-lsp" }
9484
95−[language-server.ansible-language-server]
96−command = "ansible-language-server"
97−args = ["--stdio"]
9885
9986[language-server.lua-language-server]
100−command = "lua-language-server"
87+command = "lua-language-server"
10188
10289[language-server.lua-language-server.config.Lua.hint]
10390enable = true
@@ -119,12 +106,6 @@ functionTypeParameters = true
119106parameterNames = true
120107rangeVariableTypes = true
121108
122−[language-server.golangci-lint-lsp]
123−command = "golangci-lint-langserver"
124−
125−[language-server.golangci-lint-lsp.config]
126−command = ["golangci-lint", "run", "--out-format", "json", "--issues-exit-code=1"]
127−
128109
129110[language-server.rust-analyzer]
130111command = "rust-analyzer"
@@ -191,7 +172,6 @@ auto-format = true
191172comment-token = "//"
192173language-servers = [ "rust-analyzer" ]
193174indent = { tab-width = 4, unit = " " }
194−persistent-diagnostic-sources = ["rustc", "clippy"]
195175
196176[language.auto-pairs]
197177'(' = ')'
@@ -252,6 +232,7 @@ name = "toml"
252232scope = "source.toml"
253233injection-regex = "toml"
254234file-types = ["toml", "poetry.lock", "Cargo.lock"]
235+roots = []
255236comment-token = "#"
256237language-servers = [ "taplo" ]
257238indent = { tab-width = 2, unit = " " }
@@ -265,6 +246,7 @@ name = "awk"
265246scope = "source.awk"
266247injection-regex = "awk"
267248file-types = ["awk", "gawk", "nawk", "mawk"]
249+roots = []
268250comment-token = "#"
269251language-servers = [ "awk-language-server" ]
270252indent = { tab-width = 2, unit = " " }
@@ -279,6 +261,7 @@ scope = "source.proto"
279261injection-regex = "protobuf"
280262file-types = ["proto"]
281263language-servers = [ "bufls", "pbkit" ]
264+roots = []
282265comment-token = "//"
283266indent = { tab-width = 2, unit = " " }
284267
@@ -307,6 +290,7 @@ scope = "source.fish"
307290injection-regex = "fish"
308291file-types = ["fish"]
309292shebangs = ["fish"]
293+roots = []
310294comment-token = "#"
311295indent = { tab-width = 4, unit = " " }
312296
@@ -320,6 +304,7 @@ scope = "source.mint"
320304injection-regex = "mint"
321305file-types = ["mint"]
322306shebangs = []
307+roots = []
323308comment-token = "//"
324309language-servers = [ "mint" ]
325310indent = { tab-width = 2, unit = " " }
@@ -328,28 +313,8 @@ indent = { tab-width = 2, unit = " " }
328313name = "json"
329314scope = "source.json"
330315injection-regex = "json"
331−file-types = [
332− "json",
333− "jsonc",
334− "arb",
335− "ipynb",
336− "geojson",
337− "gltf",
338− "webmanifest",
339− "flake.lock",
340− ".babelrc",
341− ".bowerrc",
342− ".jscrc",
343− "js.map",
344− "ts.map",
345− "css.map",
346− ".jslintrc",
347− "jsonld",
348− ".vuerc",
349− "composer.lock",
350− ".watchmanconfig",
351− "avsc"
352−]
316+file-types = ["json", "jsonc", "arb", "ipynb", "geojson", "gltf"]
317+roots = []
353318language-servers = [ "vscode-json-language-server" ]
354319auto-format = true
355320indent = { tab-width = 2, unit = " " }
@@ -358,26 +323,12 @@ indent = { tab-width = 2, unit = " " }
358323name = "json"
359324source = { git = "https://github.com/tree-sitter/tree-sitter-json", rev = "73076754005a460947cafe8e03a8cf5fa4fa2938" }
360325
361−
362−[[language]]
363−name = "json5"
364−scope = "source.json5"
365−injection-regex = "json5"
366−file-types = ["json5"]
367−language-servers = []
368−comment-token = "//"
369−indent = { tab-width = 4, unit = " " }
370−# https://json5.org
371−
372−[[grammar]]
373−name = "json5"
374−source = { git = "https://github.com/Joakker/tree-sitter-json5", rev = "c23f7a9b1ee7d45f516496b1e0e4be067264fa0d" }
375−
376326[[language]]
377327name = "c"
378328scope = "source.c"
379329injection-regex = "c"
380330file-types = ["c"] # TODO: ["h"]
331+roots = []
381332comment-token = "//"
382333language-servers = [ "clangd" ]
383334indent = { tab-width = 2, unit = " " }
@@ -413,7 +364,8 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-c", rev = "7175a6dd
413364name = "cpp"
414365scope = "source.cpp"
415366injection-regex = "cpp"
416−file-types = ["cc", "hh", "c++", "cpp", "hpp", "h", "ipp", "tpp", "cxx", "hxx", "ixx", "txx", "ino", "C", "H", "cu", "cuh", "cppm", "h++", "ii", "inl", { suffix = ".hpp.in" }, { suffix = ".h.in" }]
367+file-types = ["cc", "hh", "c++", "cpp", "hpp", "h", "ipp", "tpp", "cxx", "hxx", "ixx", "txx", "ino", "C", "H", "cu", "cuh", "cppm"]
368+roots = []
417369comment-token = "//"
418370language-servers = [ "clangd" ]
419371indent = { tab-width = 2, unit = " " }
@@ -459,7 +411,7 @@ language-servers = [ "crystalline" ]
459411name = "c-sharp"
460412scope = "source.csharp"
461413injection-regex = "c-?sharp"
462−file-types = ["cs", "csx", "cake"]
414+file-types = ["cs"]
463415roots = ["sln", "csproj"]
464416comment-token = "//"
465417indent = { tab-width = 4, unit = "\t" }
@@ -496,7 +448,7 @@ file-types = ["go"]
496448roots = ["go.work", "go.mod"]
497449auto-format = true
498450comment-token = "//"
499−language-servers = [ "gopls", "golangci-lint-lsp" ]
451+language-servers = [ "gopls" ]
500452# TODO: gopls needs utf-8 offsets?
501453indent = { tab-width = 4, unit = "\t" }
502454
@@ -546,6 +498,7 @@ name = "gomod"
546498scope = "source.gomod"
547499injection-regex = "gomod"
548500file-types = ["go.mod"]
501+roots = []
549502auto-format = true
550503comment-token = "//"
551504language-servers = [ "gopls" ]
@@ -560,6 +513,7 @@ name = "gotmpl"
560513scope = "source.gotmpl"
561514injection-regex = "gotmpl"
562515file-types = ["gotmpl"]
516+roots = []
563517comment-token = "//"
564518language-servers = [ "gopls" ]
565519indent = { tab-width = 2, unit = " " }
@@ -573,6 +527,7 @@ name = "gowork"
573527scope = "source.gowork"
574528injection-regex = "gowork"
575529file-types = ["go.work"]
530+roots = []
576531auto-format = true
577532comment-token = "//"
578533language-servers = [ "gopls" ]
@@ -587,8 +542,9 @@ name = "javascript"
587542scope = "source.js"
588543injection-regex = "(js|javascript)"
589544language-id = "javascript"
590−file-types = ["js", "mjs", "cjs", "rules", "es6", "pac", "jakefile"]
545+file-types = ["js", "mjs", "cjs"]
591546shebangs = ["node"]
547+roots = []
592548comment-token = "//"
593549language-servers = [ "typescript-language-server" ]
594550indent = { tab-width = 2, unit = " " }
@@ -615,6 +571,7 @@ scope = "source.jsx"
615571injection-regex = "jsx"
616572language-id = "javascriptreact"
617573file-types = ["jsx"]
574+roots = []
618575comment-token = "//"
619576language-servers = [ "typescript-language-server" ]
620577indent = { tab-width = 2, unit = " " }
@@ -626,7 +583,8 @@ scope = "source.ts"
626583injection-regex = "(ts|typescript)"
627584file-types = ["ts", "mts", "cts"]
628585language-id = "typescript"
629−shebangs = ["deno", "ts-node"]
586+shebangs = []
587+roots = []
630588language-servers = [ "typescript-language-server" ]
631589indent = { tab-width = 2, unit = " " }
632590
@@ -640,6 +598,7 @@ scope = "source.tsx"
640598injection-regex = "(tsx)" # |typescript
641599language-id = "typescriptreact"
642600file-types = ["tsx"]
601+roots = []
643602language-servers = [ "typescript-language-server" ]
644603indent = { tab-width = 2, unit = " " }
645604
@@ -652,6 +611,7 @@ name = "css"
652611scope = "source.css"
653612injection-regex = "css"
654613file-types = ["css", "scss"]
614+roots = []
655615language-servers = [ "vscode-css-language-server" ]
656616auto-format = true
657617indent = { tab-width = 2, unit = " " }
@@ -665,6 +625,7 @@ name = "scss"
665625scope = "source.scss"
666626injection-regex = "scss"
667627file-types = ["scss"]
628+roots = []
668629language-servers = [ "vscode-css-language-server" ]
669630auto-format = true
670631indent = { tab-width = 2, unit = " " }
@@ -677,7 +638,8 @@ source = { git = "https://github.com/serenadeai/tree-sitter-scss", rev = "c478c6
677638name = "html"
678639scope = "text.html.basic"
679640injection-regex = "html"
680−file-types = ["html", "htm", "shtml", "xhtml", "xht", "jsp", "asp", "aspx", "jshtm", "volt", "rhtml"]
641+file-types = ["html"]
642+roots = []
681643language-servers = [ "vscode-html-language-server" ]
682644auto-format = true
683645indent = { tab-width = 2, unit = " " }
@@ -690,9 +652,9 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-html", rev = "29f53
690652name = "python"
691653scope = "source.python"
692654injection-regex = "python"
693−file-types = ["py","pyi","py3","pyw","ptl",".pythonstartup",".pythonrc","SConstruct", "rpy", "cpy", "ipy", "pyt", "SConscript"]
655+file-types = ["py","pyi","py3","pyw","ptl",".pythonstartup",".pythonrc","SConstruct"]
694656shebangs = ["python"]
695−roots = ["pyproject.toml", "setup.py", "poetry.lock", "pyrightconfig.json"]
657+roots = []
696658comment-token = "#"
697659language-servers = [ "pylsp" ]
698660# TODO: pyls needs utf-8 offsets
@@ -700,7 +662,7 @@ indent = { tab-width = 4, unit = " " }
700662
701663[[grammar]]
702664name = "python"
703−source = { git = "https://github.com/tree-sitter/tree-sitter-python", rev = "4bfdd9033a2225cc95032ce77066b7aeca9e2efc" }
665+source = { git = "https://github.com/tree-sitter/tree-sitter-python", rev = "de221eccf9a221f5b85474a553474a69b4b5784d" }
704666
705667[[language]]
706668name = "nickel"
@@ -708,6 +670,7 @@ scope = "source.nickel"
708670injection-regex = "nickel"
709671file-types = ["ncl"]
710672shebangs = []
673+roots = []
711674comment-token = "#"
712675language-servers = [ "nls" ]
713676indent = { tab-width = 2, unit = " " }
@@ -728,6 +691,7 @@ scope = "source.nix"
728691injection-regex = "nix"
729692file-types = ["nix"]
730693shebangs = []
694+roots = []
731695comment-token = "#"
732696language-servers = [ "nil" ]
733697indent = { tab-width = 2, unit = " " }
@@ -740,43 +704,9 @@ source = { git = "https://github.com/nix-community/tree-sitter-nix", rev = "1b69
740704name = "ruby"
741705scope = "source.ruby"
742706injection-regex = "ruby"
743−file-types = [
744− "rb",
745− "rake",
746− "rakefile",
747− "irb",
748− "gemfile",
749− "gemspec",
750− "Rakefile",
751− "Gemfile",
752− "rabl",
753− "jbuilder",
754− "jb",
755− "Podfile",
756− "podspec",
757− "Vagrantfile",
758− "Brewfile",
759− "rjs",
760− "rbi",
761− "Guardfile",
762− "Capfile",
763− "Cheffile",
764− "Hobofile",
765− "Appraisals",
766− "Rantfile",
767− "Berksfile",
768− "Berksfile.lock",
769− "Thorfile",
770− "Puppetfile",
771− "Fastfile",
772− "Appfile",
773− "Deliverfile",
774− "Matchfile",
775− "Scanfile",
776− "Snapfile",
777− "Gymfile"
778−]
707+file-types = ["rb", "rake", "rakefile", "irb", "gemfile", "gemspec", "Rakefile", "Gemfile", "rabl", "jbuilder", "jb", "Podfile", "podspec", "Vagrantfile", "Brewfile"]
779708shebangs = ["ruby"]
709+roots = []
780710comment-token = "#"
781711language-servers = [ "solargraph" ]
782712indent = { tab-width = 2, unit = " " }
@@ -789,48 +719,9 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-ruby", rev = "206c7
789719name = "bash"
790720scope = "source.bash"
791721injection-regex = "(shell|bash|zsh|sh)"
792−file-types = [
793− "sh",
794− "bash",
795− "zsh",
796− ".bash_login",
797− ".bash_logout",
798− ".bash_profile",
799− ".bashrc",
800− ".profile",
801− ".zshenv",
802− "zshenv",
803− ".zlogin",
804− "zlogin",
805− ".zlogout",
806− "zlogout",
807− ".zprofile",
808− "zprofile",
809− ".zshrc",
810− "zshrc",
811− ".zimrc",
812− "APKBUILD",
813− "PKGBUILD",
814− "eclass",
815− "ebuild",
816− "bazelrc",
817− ".bash_aliases",
818− "Renviron",
819− ".Renviron",
820− ".xprofile",
821− ".xsession",
822− ".xsessionrc",
823− "zsh-theme",
824− "ksh",
825− "cshrc",
826− "tcshrc",
827− ".yashrc",
828− ".yash_profile",
829− ".hushlogin",
830− "bashrc_Apple_Terminal",
831− "zshrc_Apple_Terminal"
832−]
722+file-types = ["sh", "bash", "zsh", ".bash_login", ".bash_logout", ".bash_profile", ".bashrc", ".profile", ".zshenv", ".zlogin", ".zlogout", ".zprofile", ".zshrc", ".zimrc", "APKBUILD", "PKGBUILD", "eclass", "ebuild", "bazelrc", ".bash_aliases", "Renviron", ".Renviron"]
833723shebangs = ["sh", "bash", "dash", "zsh"]
724+roots = []
834725comment-token = "#"
835726language-servers = [ "bash-language-server" ]
836727indent = { tab-width = 2, unit = " " }
@@ -843,7 +734,7 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-bash", rev = "275ef
843734name = "php"
844735scope = "source.php"
845736injection-regex = "php"
846−file-types = ["php", "inc", "php4", "php5", "phtml", "ctp"]
737+file-types = ["php", "inc"]
847738shebangs = ["php"]
848739roots = ["composer.json", "index.php"]
849740language-servers = [ "intelephense" ]
@@ -858,6 +749,7 @@ name = "twig"
858749scope = "source.twig"
859750injection-regex = "twig"
860751file-types = ["twig"]
752+roots = []
861753indent = { tab-width = 2, unit = " " }
862754
863755[[grammar]]
@@ -868,7 +760,8 @@ source = { git = "https://github.com/gbprod/tree-sitter-twig", rev = "807b293fec
868760name = "latex"
869761scope = "source.tex"
870762injection-regex = "tex"
871−file-types = ["tex", "sty", "cls", "Rd", "bbx", "cbx"]
763+file-types = ["tex", "sty", "cls", "Rd"]
764+roots = []
872765comment-token = "%"
873766language-servers = [ "texlab" ]
874767indent = { tab-width = 4, unit = "\t" }
@@ -882,6 +775,7 @@ name = "bibtex"
882775scope = "source.bib"
883776injection-regex = "bib"
884777file-types = ["bib"]
778+roots = []
885779comment-token = "%"
886780language-servers = [ "texlab" ]
887781indent = { tab-width = 4, unit = "\t" }
@@ -918,23 +812,11 @@ indent = { tab-width = 2, unit = " " }
918812name = "lean"
919813source = { git = "https://github.com/Julian/tree-sitter-lean", rev = "d98426109258b266e1e92358c5f11716d2e8f638" }
920814
921−
922−[[language]]
923−name = "lpf"
924−comment-token = "#"
925−scope = "source.lpf"
926−file-types = ["lpf"]
927−
928−[[grammar]]
929−name = "lpf"
930−source = { git = "https://gitlab.com/TheZoq2/tree-sitter-lpf", rev = "db7372e60c722ca7f12ab359e57e6bf7611ab126" }
931−
932815[[language]]
933816name = "julia"
934817scope = "source.julia"
935818injection-regex = "julia"
936819file-types = ["jl"]
937−shebangs = ["julia"]
938820roots = ["Manifest.toml", "Project.toml"]
939821comment-token = "#"
940822language-servers = [ "julia" ]
@@ -948,7 +830,7 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-julia", rev = "8fb3
948830name = "java"
949831scope = "source.java"
950832injection-regex = "java"
951−file-types = ["java", "jav"]
833+file-types = ["java"]
952834roots = ["pom.xml", "build.gradle", "build.gradle.kts"]
953835language-servers = [ "jdtls" ]
954836indent = { tab-width = 2, unit = " " }
@@ -957,24 +839,12 @@ indent = { tab-width = 2, unit = " " }
957839name = "java"
958840source = { git = "https://github.com/tree-sitter/tree-sitter-java", rev = "09d650def6cdf7f479f4b78f595e9ef5b58ce31e" }
959841
960−[[language]]
961−name = "smali"
962−scope = "source.smali"
963−injection-regex = "smali"
964−file-types = ["smali"]
965−comment-token = "#"
966−roots = []
967−indent = { tab-width = 4, unit = " " }
968−
969−[[grammar]]
970−name = "smali"
971−source = { git = "https://github.com/amaanq/tree-sitter-smali", rev = "5ae51e15c4d1ac93cba6127caf3d1f0a072c140c" }
972−
973842[[language]]
974843name = "ledger"
975844scope = "source.ledger"
976845injection-regex = "ledger"
977846file-types = ["ldg", "ledger", "journal"]
847+roots = []
978848comment-token = ";"
979849indent = { tab-width = 4, unit = " " }
980850
@@ -987,19 +857,21 @@ name = "beancount"
987857scope = "source.beancount"
988858injection-regex = "beancount"
989859file-types = ["beancount", "bean"]
860+roots = []
990861comment-token = ";"
991862indent = { tab-width = 2, unit = " " }
992863
993864[[grammar]]
994865name = "beancount"
995−source = { git = "https://github.com/polarmutex/tree-sitter-beancount", rev = "f3741a3a68ade59ec894ed84a64673494d2ba8f3" }
866+source = { git = "https://github.com/polarmutex/tree-sitter-beancount", rev = "4cbd1f09cd07c1f1fabf867c2cf354f9da53cc4c" }
996867
997868[[language]]
998869name = "ocaml"
999870scope = "source.ocaml"
1000871injection-regex = "ocaml"
1001872file-types = ["ml"]
1002−shebangs = ["ocaml", "ocamlrun", "ocamlscript"]
873+shebangs = []
874+roots = []
1003875comment-token = "(**)"
1004876language-servers = [ "ocamllsp" ]
1005877indent = { tab-width = 2, unit = " " }
@@ -1009,6 +881,7 @@ indent = { tab-width = 2, unit = " " }
1009881'{' = '}'
1010882'[' = ']'
1011883'"' = '"'
884+'`' = '`'
1012885
1013886[[grammar]]
1014887name = "ocaml"
@@ -1019,6 +892,7 @@ name = "ocaml-interface"
1019892scope = "source.ocaml.interface"
1020893file-types = ["mli"]
1021894shebangs = []
895+roots = []
1022896comment-token = "(**)"
1023897language-servers = [ "ocamllsp" ]
1024898indent = { tab-width = 2, unit = " " }
@@ -1028,6 +902,7 @@ indent = { tab-width = 2, unit = " " }
1028902'{' = '}'
1029903'[' = ']'
1030904'"' = '"'
905+'`' = '`'
1031906
1032907[[grammar]]
1033908name = "ocaml-interface"
@@ -1053,6 +928,7 @@ name = "svelte"
1053928scope = "source.svelte"
1054929injection-regex = "svelte"
1055930file-types = ["svelte"]
931+roots = []
1056932indent = { tab-width = 2, unit = " " }
1057933language-servers = [ "svelteserver" ]
1058934
@@ -1077,9 +953,10 @@ source = { git = "https://github.com/ikatyang/tree-sitter-vue", rev = "91fe27547
1077953name = "yaml"
1078954scope = "source.yaml"
1079955file-types = ["yml", "yaml"]
956+roots = []
1080957comment-token = "#"
1081958indent = { tab-width = 2, unit = " " }
1082−language-servers = [ "yaml-language-server", "ansible-language-server" ]
959+language-servers = [ "yaml-language-server" ]
1083960injection-regex = "yml|yaml"
1084961
1085962[[grammar]]
@@ -1098,12 +975,13 @@ indent = { tab-width = 2, unit = " " }
1098975
1099976[[grammar]]
1100977name = "haskell"
1101−source = { git = "https://github.com/tree-sitter/tree-sitter-haskell", rev = "d7ac98f49e3ed7e17541256fe3881a967d7ffdd3" }
978+source = { git = "https://github.com/tree-sitter/tree-sitter-haskell", rev = "98fc7f59049aeb713ab9b72a8ff25dcaaef81087" }
1102979
1103980[[language]]
1104981name = "haskell-persistent"
1105982scope = "source.persistentmodels"
1106983file-types = ["persistentmodels"]
984+roots = []
1107985comment-token = "--"
1108986indent = { tab-width = 2, unit = " " }
1109987
@@ -1122,10 +1000,7 @@ language-servers = [ "purescript-language-server" ]
11221000indent = { tab-width = 2, unit = " " }
11231001auto-format = true
11241002formatter = { command = "purs-tidy", args = ["format"] }
1125−
1126−[[grammar]]
1127−name = "purescript"
1128−source = { git = "https://github.com/postsolar/tree-sitter-purescript", rev = "5ef5592674ea42de75fc2792972e4ea0b6e3da6c" }
1003+grammar = "haskell"
11291004
11301005[[language]]
11311006name = "zig"
@@ -1169,6 +1044,7 @@ source = { git = "https://github.com/maxxnino/tree-sitter-zig", rev = "0d08703e4
11691044[[language]]
11701045name = "prolog"
11711046scope = "source.prolog"
1047+roots = []
11721048file-types = ["pl", "prolog"]
11731049shebangs = ["swipl"]
11741050comment-token = "%"
@@ -1178,6 +1054,7 @@ language-servers = [ "swipl" ]
11781054name = "tsq"
11791055scope = "source.tsq"
11801056file-types = ["tsq"]
1057+roots = []
11811058comment-token = ";"
11821059injection-regex = "tsq"
11831060indent = { tab-width = 2, unit = " " }
@@ -1190,6 +1067,7 @@ source = { git = "https://github.com/the-mikedavis/tree-sitter-tsq", rev = "48b5
11901067name = "cmake"
11911068scope = "source.cmake"
11921069file-types = ["cmake", "CMakeLists.txt"]
1070+roots = []
11931071comment-token = "#"
11941072indent = { tab-width = 2, unit = " " }
11951073language-servers = [ "cmake-language-server" ]
@@ -1202,9 +1080,9 @@ source = { git = "https://github.com/uyha/tree-sitter-cmake", rev = "6e51463ef30
12021080[[language]]
12031081name = "make"
12041082scope = "source.make"
1205−file-types = ["Makefile", "makefile", "make", "mk", "mak", "GNUmakefile", "OCamlMakefile"]
1206−shebangs = ["make", "gmake"]
1083+file-types = ["Makefile", "makefile", "make", "mk"]
12071084injection-regex = "(make|makefile|Makefile|mk)"
1085+roots = []
12081086comment-token = "#"
12091087indent = { tab-width = 4, unit = "\t" }
12101088
@@ -1216,6 +1094,7 @@ source = { git = "https://github.com/alemuller/tree-sitter-make", rev = "a4b9187
12161094name = "glsl"
12171095scope = "source.glsl"
12181096file-types = ["glsl", "vert", "tesc", "tese", "geom", "frag", "comp" ]
1097+roots = []
12191098comment-token = "//"
12201099indent = { tab-width = 4, unit = " " }
12211100injection-regex = "glsl"
@@ -1227,39 +1106,31 @@ source = { git = "https://github.com/theHamsta/tree-sitter-glsl", rev = "88408ff
12271106[[language]]
12281107name = "perl"
12291108scope = "source.perl"
1230−file-types = ["pl", "pm", "t", "psgi", "raku", "rakumod", "rakutest", "rakudoc", "nqp", "p6", "pl6", "pm6"]
1109+file-types = ["pl", "pm", "t"]
12311110shebangs = ["perl"]
1111+roots = []
12321112comment-token = "#"
12331113language-servers = [ "perlnavigator" ]
12341114indent = { tab-width = 2, unit = " " }
12351115
12361116[[grammar]]
12371117name = "perl"
1238−source = { git = "https://github.com/tree-sitter-perl/tree-sitter-perl", rev = "e99bb5283805db4cb86c964722d709df21b0ac16" }
1239−
1240−[[language]]
1241−name = "pod"
1242−scope = "source.pod"
1243−injection-regex = "pod"
1244−file-types = ["pod"]
1245−
1246−[[grammar]]
1247−name = "pod"
1248−source = { git = "https://github.com/tree-sitter-perl/tree-sitter-pod", rev = "d466b84009a63986834498073ec05d58d727d55f" }
1118+source = { git = "https://github.com/tree-sitter-perl/tree-sitter-perl", rev = "ed21ecbcc128a6688770ebafd3ef68a1c9bc1ea9" }
12491119
12501120[[language]]
12511121name = "racket"
12521122scope = "source.racket"
1123+roots = []
12531124file-types = ["rkt", "rktd", "rktl", "scrbl"]
12541125shebangs = ["racket"]
12551126comment-token = ";"
1256−indent = { tab-width = 2, unit = " " }
12571127language-servers = [ "racket" ]
12581128grammar = "scheme"
12591129
12601130[[language]]
12611131name = "common-lisp"
12621132scope = "source.lisp"
1133+roots = []
12631134file-types = ["lisp", "asd", "cl", "l", "lsp", "ny", "podsl", "sexp"]
12641135shebangs = ["lisp", "sbcl", "ccl", "clisp", "ecl"]
12651136comment-token = ";"
@@ -1276,17 +1147,19 @@ grammar = "scheme"
12761147[[language]]
12771148name = "comment"
12781149scope = "scope.comment"
1150+roots = []
12791151file-types = []
12801152injection-regex = "comment"
12811153
12821154[[grammar]]
12831155name = "comment"
1284−source = { git = "https://github.com/stsewd/tree-sitter-comment", rev = "a37ca370310ac6f89b6e0ebf2b86b2219780494e" }
1156+source = { git = "https://github.com/stsewd/tree-sitter-comment", rev = "5dd3c62f1bbe378b220fe16b317b85247898639e" }
12851157
12861158[[language]]
12871159name = "wgsl"
12881160scope = "source.wgsl"
12891161file-types = ["wgsl"]
1162+roots = []
12901163comment-token = "//"
12911164language-servers = [ "wgsl_analyzer" ]
12921165indent = { tab-width = 4, unit = " " }
@@ -1298,6 +1171,7 @@ source = { git = "https://github.com/szebniok/tree-sitter-wgsl", rev = "272e89ef
12981171[[language]]
12991172name = "llvm"
13001173scope = "source.llvm"
1174+roots = []
13011175file-types = ["ll"]
13021176comment-token = ";"
13031177indent = { tab-width = 2, unit = " " }
@@ -1305,11 +1179,12 @@ injection-regex = "llvm"
13051179
13061180[[grammar]]
13071181name = "llvm"
1308−source = { git = "https://github.com/benwilliamgraham/tree-sitter-llvm", rev = "e9948edc41e9e5869af99dddb2b5ff5cc5581af6" }
1182+source = { git = "https://github.com/benwilliamgraham/tree-sitter-llvm", rev = "3b213925b9c4f42c1acfe2e10bfbb438d9c6834d" }
13091183
13101184[[language]]
13111185name = "llvm-mir"
13121186scope = "source.llvm_mir"
1187+roots = []
13131188file-types = []
13141189comment-token = ";"
13151190indent = { tab-width = 2, unit = " " }
@@ -1325,6 +1200,7 @@ name = "llvm-mir-yaml"
13251200#
13261201# grammar = "yaml"
13271202scope = "source.yaml"
1203+roots = []
13281204file-types = ["mir"]
13291205comment-token = "#"
13301206indent = { tab-width = 2, unit = " " }
@@ -1332,6 +1208,7 @@ indent = { tab-width = 2, unit = " " }
13321208[[language]]
13331209name = "tablegen"
13341210scope = "source.tablegen"
1211+roots = []
13351212file-types = ["td"]
13361213comment-token = "//"
13371214indent = { tab-width = 2, unit = " " }
@@ -1345,25 +1222,26 @@ source = { git = "https://github.com/Flakebi/tree-sitter-tablegen", rev = "568dd
13451222name = "markdown"
13461223scope = "source.md"
13471224injection-regex = "md|markdown"
1348−file-types = ["md", "markdown", "PULLREQ_EDITMSG", "mkd", "mdwn", "mdown", "markdn", "mdtxt", "mdtext", "workbook"]
1225+file-types = ["md", "markdown", "PULLREQ_EDITMSG"]
13491226roots = [".marksman.toml"]
13501227language-servers = [ "marksman" ]
13511228indent = { tab-width = 2, unit = " " }
13521229
13531230[[grammar]]
13541231name = "markdown"
1355−source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "aaf76797aa8ecd9a5e78e0ec3681941de6c945ee", subpath = "tree-sitter-markdown" }
1232+source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "fa6bfd51727e4bef99f7eec5f43947f73d64ea7d", subpath = "tree-sitter-markdown" }
13561233
13571234[[language]]
13581235name = "markdown.inline"
13591236scope = "source.markdown.inline"
13601237injection-regex = "markdown\\.inline"
13611238file-types = []
1239+roots = []
13621240grammar = "markdown_inline"
13631241
13641242[[grammar]]
13651243name = "markdown_inline"
1366−source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "aaf76797aa8ecd9a5e78e0ec3681941de6c945ee", subpath = "tree-sitter-markdown-inline" }
1244+source = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "fa6bfd51727e4bef99f7eec5f43947f73d64ea7d", subpath = "tree-sitter-markdown-inline" }
13671245
13681246[[language]]
13691247name = "dart"
@@ -1409,6 +1287,7 @@ source = { git = "https://github.com/camdencheek/tree-sitter-dockerfile", rev =
14091287[[language]]
14101288name = "git-commit"
14111289scope = "git.commitmsg"
1290+roots = []
14121291file-types = ["COMMIT_EDITMSG"]
14131292comment-token = "#"
14141293indent = { tab-width = 2, unit = " " }
@@ -1422,7 +1301,8 @@ source = { git = "https://github.com/the-mikedavis/tree-sitter-git-commit", rev
14221301[[language]]
14231302name = "diff"
14241303scope = "source.diff"
1425−file-types = ["diff", "patch", "rej"]
1304+roots = []
1305+file-types = ["diff", "patch"]
14261306injection-regex = "diff"
14271307comment-token = "#"
14281308indent = { tab-width = 2, unit = " " }
@@ -1434,6 +1314,7 @@ source = { git = "https://github.com/the-mikedavis/tree-sitter-diff", rev = "fd7
14341314[[language]]
14351315name = "git-rebase"
14361316scope = "source.gitrebase"
1317+roots = []
14371318file-types = ["git-rebase-todo"]
14381319injection-regex = "git-rebase"
14391320comment-token = "#"
@@ -1448,6 +1329,7 @@ name = "regex"
14481329scope = "source.regex"
14491330injection-regex = "regex"
14501331file-types = ["regex", ".Rbuildignore"]
1332+roots = []
14511333
14521334[[grammar]]
14531335name = "regex"
@@ -1456,6 +1338,7 @@ source = { git = "https://github.com/tree-sitter/tree-sitter-regex", rev = "e1cf
14561338[[language]]
14571339name = "git-config"
14581340scope = "source.gitconfig"
1341+roots = []
14591342file-types = [".gitmodules", ".gitconfig", { suffix = ".git/config" }, { suffix = ".config/git/config" }]
14601343injection-regex = "git-config"
14611344comment-token = "#"
@@ -1468,6 +1351,7 @@ source = { git = "https://github.com/the-mikedavis/tree-sitter-git-config", rev
14681351[[language]]
14691352name = "git-attributes"
14701353scope = "source.gitattributes"
1354+roots = []
14711355file-types = [".gitattributes"]
14721356injection-regex = "git-attributes"
14731357comment-token = "#"
@@ -1480,7 +1364,8 @@ source = { git = "https://github.com/mtoohey31/tree-sitter-gitattributes", rev =
14801364[[language]]
14811365name = "git-ignore"
14821366scope = "source.gitignore"
1483−file-types = [".gitignore", ".gitignore_global", ".ignore", ".prettierignore", ".eslintignore", ".npmignore", "CODEOWNERS"]
1367+roots = []
1368+file-types = [".gitignore", ".gitignore_global"]
14841369injection-regex = "git-ignore"
14851370comment-token = "#"
14861371grammar = "gitignore"
@@ -1494,7 +1379,7 @@ name = "graphql"
14941379scope = "source.graphql"
14951380injection-regex = "graphql"
14961381file-types = ["gql", "graphql", "graphqls"]
1497−language-servers = [ "graphql-language-service" ]
1382+roots = []
14981383indent = { tab-width = 2, unit = " " }
14991384
15001385[[grammar]]
@@ -1521,6 +1406,7 @@ name = "iex"
15211406scope = "source.iex"
15221407injection-regex = "iex"
15231408file-types = ["iex"]
1409+roots = []
15241410
15251411[[grammar]]
15261412name = "iex"
@@ -1539,7 +1425,7 @@ indent = { tab-width = 2, unit = " " }
15391425
15401426[[grammar]]
15411427name = "rescript"
1542−source = { git = "https://github.com/jaredramirez/tree-sitter-rescript", rev = "467dcf99f68c47823d7b378779a6b282d7ef9782" }
1428+source = { git = "https://github.com/jaredramirez/tree-sitter-rescript", rev = "65609807c628477f3b94052e7ef895885ac51c3c" }
15431429
15441430[[language]]
15451431name = "erlang"
@@ -1583,6 +1469,7 @@ scope = "source.hcl"
15831469injection-regex = "(hcl|tf|nomad)"
15841470language-id = "terraform"
15851471file-types = ["hcl", "tf", "nomad"]
1472+roots = []
15861473comment-token = "#"
15871474indent = { tab-width = 2, unit = " " }
15881475language-servers = [ "terraform-ls" ]
@@ -1597,6 +1484,7 @@ name = "tfvars"
15971484scope = "source.tfvars"
15981485language-id = "terraform-vars"
15991486file-types = ["tfvars"]
1487+roots = []
16001488comment-token = "#"
16011489indent = { tab-width = 2, unit = " " }
16021490language-servers = [ "terraform-ls" ]
@@ -1608,6 +1496,7 @@ name = "org"
16081496scope = "source.org"
16091497injection-regex = "org"
16101498file-types = ["org"]
1499+roots = []
16111500indent = { tab-width = 2, unit = " " }
16121501
16131502[[grammar]]
@@ -1619,6 +1508,7 @@ name = "solidity"
16191508scope = "source.sol"
16201509injection-regex = "(sol|solidity)"
16211510file-types = ["sol"]
1511+roots = []
16221512comment-token = "//"
16231513indent = { tab-width = 4, unit = " " }
16241514language-servers = [ "solc" ]
@@ -1636,23 +1526,20 @@ roots = ["gleam.toml"]
16361526comment-token = "//"
16371527indent = { tab-width = 2, unit = " " }
16381528language-servers = [ "gleam" ]
1639−auto-format = true
16401529
16411530[[grammar]]
16421531name = "gleam"
1643−source = { git = "https://github.com/gleam-lang/tree-sitter-gleam", rev = "b2afa4fd6bb41a7bf912b034c653c90af7ae5122" }
1532+source = { git = "https://github.com/gleam-lang/tree-sitter-gleam", rev = "ae79782c00656945db69641378e688cdb78d52c1" }
16441533
16451534[[language]]
16461535name = "ron"
16471536scope = "source.ron"
16481537injection-regex = "ron"
16491538file-types = ["ron"]
1539+roots = []
16501540comment-token = "//"
16511541indent = { tab-width = 4, unit = " " }
1652−
1653−[[grammar]]
1654−name = "ron"
1655−source = { git = "https://github.com/zee-editor/tree-sitter-ron", rev = "7762d709a0f7c1f9e269d0125a2e8a7a69006146" }
1542+grammar = "rust"
16561543
16571544[[language]]
16581545name = "robot"
@@ -1660,19 +1547,21 @@ scope = "source.robot"
16601547injection-regex = "robot"
16611548file-types = ["robot", "resource"]
16621549comment-token = "#"
1550+roots = []
16631551indent = { tab-width = 4, unit = " " }
16641552language-servers = [ "robotframework_ls" ]
16651553
16661554[[grammar]]
16671555name = "robot"
1668−source = { git = "https://github.com/Hubro/tree-sitter-robot", rev = "322e4cc65754d2b3fdef4f2f8a71e0762e3d13af" }
1556+source = { git = "https://github.com/Hubro/tree-sitter-robot", rev = "f1142bfaa6acfce95e25d2c6d18d218f4f533927" }
16691557
16701558[[language]]
16711559name = "r"
16721560scope = "source.r"
16731561injection-regex = "(r|R)"
1674−file-types = ["r", "R", ".Rprofile", "Rprofile.site", ".RHistory"]
1562+file-types = ["r", "R", ".Rprofile", "Rprofile.site"]
16751563shebangs = ["r", "R"]
1564+roots = []
16761565comment-token = "#"
16771566indent = { tab-width = 2, unit = " " }
16781567language-servers = [ "r" ]
@@ -1684,9 +1573,9 @@ source = { git = "https://github.com/r-lib/tree-sitter-r", rev = "cc04302e1bff76
16841573[[language]]
16851574name = "rmarkdown"
16861575scope = "source.rmd"
1687−language-id = "rmd"
16881576injection-regex = "(r|R)md"
16891577file-types = ["rmd", "Rmd"]
1578+roots = []
16901579indent = { tab-width = 2, unit = " " }
16911580grammar = "markdown"
16921581language-servers = [ "r" ]
@@ -1710,6 +1599,7 @@ name = "erb"
17101599scope = "text.html.erb"
17111600injection-regex = "erb"
17121601file-types = ["erb"]
1602+roots = []
17131603indent = { tab-width = 2, unit = " " }
17141604grammar = "embedded-template"
17151605
@@ -1718,6 +1608,7 @@ name = "ejs"
17181608scope = "text.html.ejs"
17191609injection-regex = "ejs"
17201610file-types = ["ejs"]
1611+roots = []
17211612indent = { tab-width = 2, unit = " " }
17221613grammar = "embedded-template"
17231614
@@ -1753,14 +1644,15 @@ source = { git = "https://github.com/phoenixframework/tree-sitter-heex", rev = "
17531644[[language]]
17541645name = "sql"
17551646scope = "source.sql"
1756−file-types = ["sql", "dsql"]
1647+file-types = ["sql"]
1648+roots = []
17571649comment-token = "--"
17581650indent = { tab-width = 4, unit = " " }
17591651injection-regex = "sql"
17601652
17611653[[grammar]]
17621654name = "sql"
1763−source = { git = "https://github.com/DerekStride/tree-sitter-sql", rev = "25be0b8f17e9189ad9e1b875869d025c5aec1286" }
1655+source = { git = "https://github.com/DerekStride/tree-sitter-sql", rev = "7cbac0472e5b8f8486ce64ffbcf1982d5cd5fc8d" }
17641656
17651657[[language]]
17661658name = "gdscript"
@@ -1799,9 +1691,9 @@ scope = "source.nu"
17991691injection-regex = "nu"
18001692file-types = ["nu"]
18011693shebangs = ["nu"]
1694+roots = []
18021695comment-token = "#"
18031696indent = { tab-width = 2, unit = " " }
1804−language-servers = [ "nu-lsp" ]
18051697
18061698[[grammar]]
18071699name = "nu"
@@ -1812,6 +1704,7 @@ name = "vala"
18121704scope = "source.vala"
18131705injection-regex = "vala"
18141706file-types = ["vala", "vapi"]
1707+roots = []
18151708comment-token = "//"
18161709indent = { tab-width = 2, unit = " " }
18171710language-servers = [ "vala-language-server" ]
@@ -1825,6 +1718,7 @@ name = "hare"
18251718scope = "source.hare"
18261719injection-regex = "hare"
18271720file-types = ["ha"]
1721+roots = []
18281722comment-token = "//"
18291723indent = { tab-width = 8, unit = "\t" }
18301724
@@ -1837,6 +1731,7 @@ name = "devicetree"
18371731scope = "source.devicetree"
18381732injection-regex = "(dtsi?|devicetree|fdt)"
18391733file-types = ["dts", "dtsi"]
1734+roots = []
18401735comment-token = "//"
18411736indent = { tab-width = 4, unit = "\t" }
18421737
@@ -1849,6 +1744,7 @@ name = "cairo"
18491744scope = "source.cairo"
18501745injection-regex = "cairo"
18511746file-types = ["cairo"]
1747+roots = []
18521748comment-token = "//"
18531749indent = { tab-width = 4, unit = " " }
18541750# auto-format = true
@@ -1860,6 +1756,7 @@ name = "cpon"
18601756scope = "scope.cpon"
18611757injection-regex = "cpon"
18621758file-types = ["cpon", "cp"]
1759+roots = []
18631760auto-format = true
18641761comment-token = "//"
18651762indent = { tab-width = 2, unit = " " }
@@ -1886,7 +1783,8 @@ source = { git = "https://github.com/ap29600/tree-sitter-odin", rev = "b219207e4
18861783name = "meson"
18871784scope = "source.meson"
18881785injection-regex = "meson"
1889−file-types = ["meson.build", "meson_options.txt"]
1786+file-types = ["meson.build"]
1787+roots = []
18901788comment-token = "#"
18911789indent = { tab-width = 2, unit = " " }
18921790
@@ -1898,6 +1796,7 @@ source = { git = "https://github.com/staysail/tree-sitter-meson", rev = "32a83e8
18981796name = "sshclientconfig"
18991797scope = "source.sshclientconfig"
19001798file-types = [{ suffix = ".ssh/config" }, { suffix = "/etc/ssh/ssh_config" }]
1799+roots = []
19011800comment-token = "#"
19021801
19031802[[grammar]]
@@ -1909,7 +1808,7 @@ name = "scheme"
19091808scope = "source.scheme"
19101809injection-regex = "scheme"
19111810file-types = ["ss", "scm"]
1912−shebangs = ["scheme", "guile", "chicken"]
1811+roots = []
19131812comment-token = ";"
19141813indent = { tab-width = 2, unit = " " }
19151814
@@ -1936,6 +1835,7 @@ source = {git = "https://github.com/v-analyzer/v-analyzer", subpath = "tree_sitt
19361835name = "verilog"
19371836scope = "source.verilog"
19381837file-types = ["v", "vh", "sv", "svh"]
1838+roots = []
19391839comment-token = "//"
19401840language-servers = [ "svlangserver" ]
19411841indent = { tab-width = 2, unit = " " }
@@ -1950,6 +1850,7 @@ name = "edoc"
19501850scope = "source.edoc"
19511851file-types = ["edoc", "edoc.in"]
19521852injection-regex = "edoc"
1853+roots = []
19531854indent = { tab-width = 4, unit = " " }
19541855
19551856[[grammar]]
@@ -1961,6 +1862,7 @@ name = "jsdoc"
19611862scope = "source.jsdoc"
19621863injection-regex = "jsdoc"
19631864file-types = ["jsdoc"]
1865+roots = []
19641866indent = { tab-width = 2, unit = " " }
19651867
19661868[[grammar]]
@@ -1972,6 +1874,7 @@ name = "openscad"
19721874scope = "source.openscad"
19731875injection-regex = "openscad"
19741876file-types = ["scad"]
1877+roots = []
19751878comment-token = "//"
19761879language-servers = [ "openscad-lsp" ]
19771880indent = { tab-width = 2, unit = "\t" }
@@ -2012,7 +1915,8 @@ source = { git = "https://github.com/sogaiu/tree-sitter-clojure", rev = "e57c569
20121915name = "starlark"
20131916scope = "source.starlark"
20141917injection-regex = "(starlark|bzl|bazel)"
2015−file-types = ["bzl", "bazel", "BUILD", "star"]
1918+file-types = ["bzl", "bazel", "BUILD"]
1919+roots = []
20161920comment-token = "#"
20171921indent = { tab-width = 4, unit = " " }
20181922grammar = "python"
@@ -2021,6 +1925,7 @@ grammar = "python"
20211925name = "elvish"
20221926scope = "source.elvish"
20231927file-types = ["elv"]
1928+roots = []
20241929comment-token = "#"
20251930indent = { tab-width = 2, unit = " " }
20261931language-servers = [ "elvish" ]
@@ -2036,6 +1941,7 @@ scope = "source.idr"
20361941injection-regex = "idr"
20371942file-types = ["idr"]
20381943shebangs = []
1944+roots = []
20391945comment-token = "--"
20401946indent = { tab-width = 2, unit = " " }
20411947language-servers = [ "idris2-lsp" ]
@@ -2059,18 +1965,20 @@ name = "ungrammar"
20591965scope = "source.ungrammar"
20601966injection-regex = "ungrammar"
20611967file-types = ["ungram", "ungrammar"]
1968+roots = []
20621969comment-token = "//"
20631970indent = { tab-width = 2, unit = " " }
20641971
20651972[[grammar]]
20661973name = "ungrammar"
2067−source = { git = "https://github.com/Philipp-M/tree-sitter-ungrammar", rev = "a7e104629cff5a8b7367187610631e8f5eb7c6ea" }
1974+source = { git = "https://github.com/Philipp-M/tree-sitter-ungrammar", rev = "0113de880a58ea14f2a75802e9b99fcc25003d9c" }
20681975
20691976[[language]]
20701977name = "dot"
20711978scope = "source.dot"
20721979injection-regex = "dot"
20731980file-types = ["dot"]
1981+roots = []
20741982comment-token = "//"
20751983indent = { tab-width = 4, unit = " " }
20761984language-servers = [ "dot-language-server" ]
@@ -2100,19 +2008,21 @@ name = "slint"
21002008scope = "source.slint"
21012009injection-regex = "slint"
21022010file-types = ["slint"]
2011+roots = []
21032012comment-token = "//"
21042013indent = { tab-width = 4, unit = " " }
21052014language-servers = [ "slint-lsp" ]
21062015
21072016[[grammar]]
21082017name = "slint"
2109−source = { git = "https://github.com/jrmoulton/tree-sitter-slint", rev = "00c8a2d3645766f68c0d0460086c0a994e5b0d85" }
2018+source = { git = "https://github.com/jrmoulton/tree-sitter-slint", rev = "0d4dda94f96623302dfc234e06be62a5717f47da" }
21102019
21112020[[language]]
21122021name = "task"
21132022scope = "source.task"
21142023injection-regex = "task"
21152024file-types = ["task"]
2025+roots = []
21162026comment-token = "#"
21172027indent = { tab-width = 2, unit = " " }
21182028
@@ -2125,6 +2035,7 @@ name = "xit"
21252035scope = "source.xit"
21262036injection-regex = "xit"
21272037file-types = ["xit"]
2038+roots = []
21282039indent = { tab-width = 4, unit = " " }
21292040
21302041[[grammar]]
@@ -2142,13 +2053,14 @@ roots = ["edgedb.toml"]
21422053
21432054[[grammar]]
21442055name ="esdl"
2145−source = { git = "https://github.com/greym0uth/tree-sitter-esdl", rev = "df83acc8cacd0cfb139eecee0e718dc32c4f92e2" }
2056+source = { git = "https://github.com/greym0uth/tree-sitter-esdl", rev = "b840c8a8028127e0a7c6e6c45141adade2bd75cf" }
21462057
21472058[[language]]
21482059name = "pascal"
21492060scope = "source.pascal"
21502061injection-regex = "pascal"
21512062file-types = ["pas", "pp", "inc", "lpr", "lfm"]
2063+roots = []
21522064comment-token = "//"
21532065indent = { tab-width = 2, unit = " " }
21542066language-servers = [ "pasls" ]
@@ -2163,6 +2075,7 @@ scope = "source.sml"
21632075injection-regex = "sml"
21642076file-types = ["sml"]
21652077comment-token = "(*"
2078+roots = []
21662079
21672080[[grammar]]
21682081name = "sml"
@@ -2186,17 +2099,19 @@ name = "astro"
21862099scope = "source.astro"
21872100injection-regex = "astro"
21882101file-types = ["astro"]
2102+roots = []
21892103indent = { tab-width = 2, unit = " " }
21902104
21912105[[grammar]]
21922106name = "astro"
2193−source = { git = "https://github.com/virchau13/tree-sitter-astro", rev = "947e93089e60c66e681eba22283f4037841451e7" }
2107+source = { git = "https://github.com/virchau13/tree-sitter-astro", rev = "5f5c3e73c45967df9aa42f861fad2d77cd4e0900" }
21942108
21952109[[language]]
21962110name = "bass"
21972111scope = "source.bass"
21982112injection-regex = "bass"
21992113file-types = ["bass"]
2114+roots = []
22002115comment-token = ";"
22012116indent = { tab-width = 2, unit = " " }
22022117language-servers = [ "bass" ]
@@ -2210,6 +2125,7 @@ name = "wat"
22102125scope = "source.wat"
22112126comment-token = ";;"
22122127file-types = ["wat"]
2128+roots = []
22132129
22142130[[grammar]]
22152131name = "wat"
@@ -2220,6 +2136,7 @@ name = "wast"
22202136scope = "source.wast"
22212137comment-token = ";;"
22222138file-types = ["wast"]
2139+roots = []
22232140
22242141[[grammar]]
22252142name = "wast"
@@ -2229,6 +2146,7 @@ source = { git = "https://github.com/wasm-lsp/tree-sitter-wasm", rev = "2ca28a9f
22292146name = "d"
22302147scope = "source.d"
22312148file-types = [ "d", "dd" ]
2149+roots = []
22322150comment-token = "//"
22332151injection-regex = "d"
22342152indent = { tab-width = 4, unit = " "}
@@ -2237,12 +2155,13 @@ formatter = { command = "dfmt" }
22372155
22382156[[grammar]]
22392157name = "d"
2240−source = { git = "https://github.com/gdamore/tree-sitter-d", rev = "5566f8ce8fc24186fad06170bbb3c8d97c935d74" }
2158+source = { git = "https://github.com/gdamore/tree-sitter-d", rev="601c4a1e8310fb2f3c43fa8a923d0d27497f3c04" }
22412159
22422160[[language]]
22432161name = "vhs"
22442162scope = "source.vhs"
22452163file-types = ["tape"]
2164+roots = []
22462165comment-token = "#"
22472166indent = { tab-width = 2, unit = " " }
22482167grammar = "vhs"
@@ -2255,76 +2174,21 @@ source = { git = "https://github.com/charmbracelet/tree-sitter-vhs", rev = "c6d8
22552174name = "kdl"
22562175scope = "source.kdl"
22572176file-types = ["kdl"]
2177+roots = []
22582178comment-token = "//"
22592179injection-regex = "kdl"
22602180
22612181[[grammar]]
22622182name = "kdl"
2263−source = { git = "https://github.com/amaanq/tree-sitter-kdl", rev = "3ca569b9f9af43593c24f9e7a21f02f43a13bb88" }
2183+source = { git = "https://github.com/Unoqwy/tree-sitter-kdl", rev = "e1cd292c6d15df6610484e1d4b5c987ecad52373" }
22642184
22652185[[language]]
22662186name = "xml"
22672187scope = "source.xml"
22682188injection-regex = "xml"
2269−file-types = [
2270− "xml",
2271− "mobileconfig",
2272− "plist",
2273− "xib",
2274− "storyboard",
2275− "svg",
2276− "xsd",
2277− "gml",
2278− "xaml",
2279− "gir",
2280− "rss",
2281− "atom",
2282− "opml",
2283− "policy",
2284− "ascx",
2285− "axml",
2286− "axaml",
2287− "bpmn",
2288− "cpt",
2289− "csl",
2290− "csproj.user",
2291− "dita",
2292− "ditamap",
2293− "dtml",
2294− "fxml",
2295− "iml",
2296− "isml",
2297− "jmx",
2298− "launch",
2299− "menu",
2300− "mxml",
2301− "nuspec",
2302− "pt",
2303− "publishsettings",
2304− "pubxml",
2305− "pubxml.user",
2306− "rbxlx",
2307− "rbxmx",
2308− "rng",
2309− "shproj",
2310− "tld",
2311− "tmx",
2312− "vbproj.user",
2313− "vcxproj",
2314− "vcxproj.filters",
2315− "wsdl",
2316− "wxi",
2317− "wxs",
2318− "xbl",
2319− "xlf",
2320− "xliff",
2321− "xpdl",
2322− "xul",
2323− "xoml",
2324− "musicxml",
2325− "glif"
2326−]
2189+file-types = ["xml", "mobileconfig", "plist", "xib", "storyboard", "svg", "xsd", "gml", "xaml", "gir"]
23272190indent = { tab-width = 2, unit = " " }
2191+roots = []
23282192
23292193[language.auto-pairs]
23302194'(' = ')'
@@ -2345,6 +2209,7 @@ scope = "source.dtd"
23452209injection-regex = "dtd"
23462210file-types = ["dtd", "ent"]
23472211indent = {tab-width = 2, unit = " "}
2212+roots = []
23482213
23492214[language.auto-pairs]
23502215'(' = ')'
@@ -2362,6 +2227,7 @@ name = "wit"
23622227scope = "source.wit"
23632228injection-regex = "wit"
23642229file-types = ["wit"]
2230+roots = []
23652231comment-token = "//"
23662232indent = { tab-width = 2, unit = " " }
23672233
@@ -2380,10 +2246,11 @@ source = { git = "https://github.com/hh9527/tree-sitter-wit", rev = "c917790ab9a
23802246[[language]]
23812247name = "env"
23822248scope = "source.env"
2383−file-types = [".env", ".env.local", ".env.development", ".env.production", ".env.dist", ".envrc", ".envrc.local", ".envrc.private"]
2249+file-types = [".env", ".env.local", ".env.development", ".env.production", ".env.dist", ".envrc"]
23842250injection-regex = "env"
23852251comment-token = "#"
23862252indent = { tab-width = 4, unit = "\t" }
2253+roots = []
23872254grammar = "bash"
23882255
23892256[[language]]
@@ -2407,15 +2274,12 @@ file-types = [
24072274 "container",
24082275 "volume",
24092276 "kube",
2410− "network",
2411− ".editorconfig",
2412− "properties",
2413− "cfg",
2414− "directory"
2277+ "network"
24152278]
24162279injection-regex = "ini"
24172280comment-token = "#"
24182281indent = { tab-width = 4, unit = "\t" }
2282+roots = []
24192283
24202284[[grammar]]
24212285name = "ini"
@@ -2425,6 +2289,7 @@ source = { git = "https://github.com/justinmk/tree-sitter-ini", rev = "4d247fb87
24252289name = "bicep"
24262290scope = "source.bicep"
24272291file-types = ["bicep"]
2292+roots = []
24282293auto-format = true
24292294comment-token = "//"
24302295indent = { tab-width = 2, unit = " "}
@@ -2438,6 +2303,7 @@ source = { git = "https://github.com/the-mikedavis/tree-sitter-bicep", rev = "d8
24382303name = "qml"
24392304scope = "source.qml"
24402305file-types = ["qml"]
2306+roots = []
24412307language-servers = [ "qmlls" ]
24422308indent = { tab-width = 4, unit = " " }
24432309grammar = "qmljs"
@@ -2451,6 +2317,7 @@ name = "mermaid"
24512317scope = "source.mermaid"
24522318injection-regex = "mermaid"
24532319file-types = ["mermaid"]
2320+roots = []
24542321comment-token = "%%"
24552322indent = { tab-width = 4, unit = " " }
24562323
@@ -2464,11 +2331,12 @@ scope = "source.m"
24642331file-types = ["m"]
24652332comment-token = "%"
24662333shebangs = ["octave-cli", "matlab"]
2334+roots = []
24672335indent = { tab-width = 2, unit = " " }
24682336
24692337[[grammar]]
24702338name = "matlab"
2471−source = { git = "https://github.com/acristoffers/tree-sitter-matlab", rev = "6071891a8c39600203eba20513666cf93b4d650a" }
2339+source = { git = "https://github.com/acristoffers/tree-sitter-matlab", rev = "676117eafa64afedc8380a921a77cd9f2244bc6b" }
24722340
24732341[[language]]
24742342name = "ponylang"
@@ -2488,6 +2356,7 @@ name = "dhall"
24882356scope = "source.dhall"
24892357injection-regex = "dhall"
24902358file-types = ["dhall"]
2359+roots = []
24912360comment-token = "--"
24922361indent = { tab-width = 2, unit = " " }
24932362language-servers = [ "dhall-lsp-server" ]
@@ -2502,6 +2371,7 @@ name = "sage"
25022371scope = "source.sage"
25032372file-types = ["sage"]
25042373injection-regex = "sage"
2374+roots = []
25052375comment-token = "#"
25062376indent = { tab-width = 4, unit = " " }
25072377grammar = "python"
@@ -2512,6 +2382,7 @@ scope = "source.msbuild"
25122382injection-regex = "msbuild"
25132383file-types = ["proj", "vbproj", "csproj", "fsproj", "targets", "props"]
25142384indent = { tab-width = 2, unit = " " }
2385+roots = []
25152386grammar = "xml"
25162387
25172388[language.auto-pairs]
@@ -2527,6 +2398,7 @@ name = "pem"
25272398scope = "source.pem"
25282399file-types = ["pem", "cert", "crt"]
25292400injection-regex = "pem"
2401+roots = []
25302402grammar = "pem"
25312403
25322404[[grammar]]
@@ -2537,6 +2409,7 @@ source = { git = "https://github.com/mtoohey31/tree-sitter-pem", rev = "be67a433
25372409name = "passwd"
25382410scope = "source.passwd"
25392411file-types = ["passwd"]
2412+roots = []
25402413
25412414[[grammar]]
25422415name = "passwd"
@@ -2546,6 +2419,7 @@ source = { git = "https://github.com/ath3/tree-sitter-passwd", rev = "20239395ea
25462419name = "hosts"
25472420scope = "source.hosts"
25482421file-types = ["hosts"]
2422+roots = []
25492423comment-token = "#"
25502424
25512425[[grammar]]
@@ -2557,18 +2431,20 @@ name = "uxntal"
25572431scope = "source.tal"
25582432injection-regex = "tal"
25592433file-types = ["tal"]
2434+roots = []
25602435auto-format = false
25612436comment-token = "("
25622437
25632438[[grammar]]
25642439name = "uxntal"
2565−source = { git = "https://github.com/Jummit/tree-sitter-uxntal", rev = "d68406066648cd6db4c6a2f11ec305af02079884" }
2440+source = { git = "https://github.com/Jummit/tree-sitter-uxntal", rev = "9297e95ef74380b0ad84c4fd98f91e9f6e4319e6" }
25662441
25672442[[language]]
25682443name = "yuck"
25692444scope = "source.yuck"
25702445injection-regex = "yuck"
25712446file-types = ["yuck"]
2447+roots = []
25722448comment-token = ";"
25732449indent = { tab-width = 2, unit = " " }
25742450
@@ -2581,6 +2457,7 @@ name = "prql"
25812457scope = "source.prql"
25822458injection-regex = "prql"
25832459file-types = ["prql"]
2460+roots = []
25842461comment-token = "#"
25852462indent = { tab-width = 4, unit = " " }
25862463
@@ -2592,6 +2469,7 @@ source = { git = "https://github.com/PRQL/tree-sitter-prql", rev = "09e158cd3650
25922469name = "po"
25932470scope = "source.po"
25942471file-types = ["po", "pot"]
2472+roots = []
25952473comment-token = "#"
25962474
25972475[[grammar]]
@@ -2601,8 +2479,9 @@ source = { git = "https://github.com/erasin/tree-sitter-po", rev = "417cee9abb20
26012479[[language]]
26022480name = "nasm"
26032481scope = "source.nasm"
2604−file-types = ["asm", "S", "nasm"]
2482+file-types = ["asm", "s", "S", "nasm"]
26052483injection-regex = "n?asm"
2484+roots = []
26062485comment-token = ";"
26072486indent = { tab-width = 8, unit = " " }
26082487
@@ -2610,23 +2489,12 @@ indent = { tab-width = 8, unit = " " }
26102489name = "nasm"
26112490source = { git = "https://github.com/naclsn/tree-sitter-nasm", rev = "a0db15db6fcfb1bf2cc8702500e55e558825c48b" }
26122491
2613−[[language]]
2614−name = "gas"
2615−scope = "source.gas"
2616−file-types = ["s"]
2617−injection-regex = "gas"
2618−comment-token = "#"
2619−indent = { tab-width = 8, unit = " " }
2620−
2621−[[grammar]]
2622−name = "gas"
2623−source = { git = "https://github.com/sirius94/tree-sitter-gas", rev = "60f443646b20edee3b7bf18f3a4fb91dc214259a" }
2624−
26252492[[language]]
26262493name = "rst"
26272494scope = "source.rst"
26282495comment-token = ".."
26292496file-types = ["rst"]
2497+roots = []
26302498
26312499[[grammar]]
26322500name = "rst"
@@ -2637,6 +2505,7 @@ name = "capnp"
26372505scope = "source.capnp"
26382506injection-regex = "capnp"
26392507file-types = ["capnp"]
2508+roots = []
26402509comment-token = "#"
26412510indent = { tab-width = 2, unit = " " }
26422511
@@ -2662,6 +2531,7 @@ source = { git = "https://github.com/indoorvivants/tree-sitter-smithy", rev = "c
26622531name = "vhdl"
26632532scope = "source.vhdl"
26642533file-types = ["vhd", "vhdl"]
2534+roots = []
26652535comment-token = "--"
26662536language-servers = [ "vhdl_ls" ]
26672537indent = { tab-width = 2, unit = " " }
@@ -2673,6 +2543,7 @@ source = { git = "https://github.com/teburd/tree-sitter-vhdl", rev = "c57313adee
26732543
26742544[[language]]
26752545name = "rego"
2546+roots = []
26762547scope = "source.rego"
26772548injection-regex = "rego"
26782549file-types = ["rego"]
@@ -2683,7 +2554,7 @@ grammar = "rego"
26832554
26842555[[grammar]]
26852556name = "rego"
2686−source = { git = "https://github.com/FallenAngel97/tree-sitter-rego", rev = "9ac75e71b2d791e0aadeef68098319d86a2a14cf" }
2557+source = { git = "https://github.com/FallenAngel97/tree-sitter-rego", rev = "b2667c975f07b33be3ceb83bea5cfbad88095866" }
26872558
26882559[[language]]
26892560name = "nim"
@@ -2691,6 +2562,7 @@ scope = "source.nim"
26912562injection-regex = "nim"
26922563file-types = ["nim", "nims", "nimble"]
26932564shebangs = []
2565+roots = []
26942566comment-token = "#"
26952567indent = { tab-width = 2, unit = " " }
26962568language-servers = [ "nimlangserver" ]
@@ -2714,13 +2586,13 @@ file-types = [ "cabal" ]
27142586roots = ["cabal.project", "Setup.hs"]
27152587indent = { tab-width = 2, unit = " " }
27162588comment-token = "--"
2717−language-servers = [ "haskell-language-server" ]
27182589
27192590[[language]]
27202591name = "hurl"
27212592scope = "source.hurl"
27222593injection-regex = "hurl"
27232594file-types = ["hurl"]
2595+roots = []
27242596comment-token = "#"
27252597indent = { tab-width = 2, unit = " " }
27262598
@@ -2731,6 +2603,7 @@ source = { git = "https://github.com/pfeiferj/tree-sitter-hurl", rev = "264c4206
27312603[[language]]
27322604name = "markdoc"
27332605scope = "text.markdoc"
2606+roots = []
27342607file-types = ["mdoc"]
27352608language-servers = [ "markdoc-ls" ]
27362609
@@ -2743,6 +2616,7 @@ name = "opencl"
27432616scope = "source.cl"
27442617injection-regex = "(cl|opencl)"
27452618file-types = ["cl"]
2619+roots = []
27462620comment-token = "//"
27472621language-servers = [ "clangd" ]
27482622
@@ -2755,6 +2629,7 @@ name = "just"
27552629scope = "source.just"
27562630file-types = ["justfile", "Justfile", ".justfile", ".Justfile"]
27572631injection-regex = "just"
2632+roots = []
27582633comment-token = "#"
27592634indent = { tab-width = 4, unit = "\t" }
27602635
@@ -2762,52 +2637,40 @@ indent = { tab-width = 4, unit = "\t" }
27622637name = "just"
27632638source = { git = "https://github.com/IndianBoy42/tree-sitter-just", rev = "8af0aab79854aaf25b620a52c39485849922f766" }
27642639
2765−[[language]]
2766−name = "gn"
2767−scope = "source.gn"
2768−injection-regex = "gn"
2769−file-types = ["gn", "gni"]
2770−roots = []
2771−comment-token = "#"
2772−indent = { tab-width = 2, unit = " " }
2773−formatter = { command = "gn", args = ["format", "--stdin"] }
2774−
2775−[[grammar]]
2776−name = "gn"
2777−source = { git = "https://github.com/willcassella/tree-sitter-gn", rev = "e18d6e36a79b20dafb58f19d407bd38b0e60260e" }
2778−
27792640[[language]]
27802641name = "blueprint"
27812642scope = "source.blueprint"
27822643injection-regex = "blueprint"
27832644file-types = ["blp"]
2645+roots = []
27842646comment-token = "//"
27852647language-servers = [ "blueprint-compiler" ]
27862648indent = { tab-width = 4, unit = " " }
27872649
27882650[[grammar]]
27892651name = "blueprint"
2790−source = { git = "https://gitlab.com/gabmus/tree-sitter-blueprint", rev = "863cea9f83ad5637300478e0559262f1e791684b" }
2652+source = { git = "https://gitlab.com/gabmus/tree-sitter-blueprint", rev = "7f1a5df44861291d6951b6b2146a9fef4c226e14" }
27912653
27922654[[language]]
27932655name = "forth"
27942656scope = "source.forth"
27952657injection-regex = "forth"
27962658file-types = ["fs", "forth", "fth", "4th"]
2659+roots = []
27972660comment-token = "\\"
27982661language-servers = [ "forth-lsp" ]
27992662indent = { tab-width = 3, unit = " " }
28002663
28012664[[grammar]]
28022665name = "forth"
2803−source = { git = "https://github.com/alexanderbrevig/tree-sitter-forth", rev = "90189238385cf636b9ee99ce548b9e5b5e569d48" }
2666+source = { git = "https://github.com/alexanderbrevig/tree-sitter-forth", rev = "304ed77beb113e37af38b20ff14e3c37bf350d10" }
28042667
28052668[[language]]
28062669name = "fsharp"
28072670scope = "source.fs"
28082671roots = ["sln", "fsproj"]
28092672injection-regex = "fsharp"
2810−file-types = ["fs", "fsx", "fsi", "fsscript"]
2673+file-types = ["fs", "fsx"]
28112674comment-token = "//"
28122675indent = { tab-width = 4, unit = " " }
28132676auto-format = true
@@ -2815,13 +2678,14 @@ language-servers = ["fsharp-ls"]
28152678
28162679[[grammar]]
28172680name = "fsharp"
2818−source = { git = "https://github.com/kaashyapan/tree-sitter-fsharp", rev = "18da392fd9bd5e79f357abcce13f61f3a15e3951" }
2681+source = { git = "https://github.com/kaashyapan/tree-sitter-fsharp", rev = "1b5a315e003024db6181744f1d25b8f525732665" }
28192682
28202683[[language]]
28212684name = "t32"
28222685scope = "source.t32"
28232686injection-regex = "t32"
28242687file-types = ["cmm", "t32"]
2688+roots = []
28252689comment-token = ";"
28262690indent = { tab-width = 2, unit = " " }
28272691
@@ -2834,34 +2698,16 @@ name = "webc"
28342698scope = "text.html.webc"
28352699injection-regex = "webc"
28362700file-types = ["webc"]
2701+roots = []
28372702indent = { tab-width = 2, unit = " " }
28382703grammar = "html"
28392704
2840−[[language]]
2841−name = "typst"
2842−scope = "source.typst"
2843−injection-regex = "typst"
2844−file-types = ["typst", "typ"]
2845−comment-token = "//"
2846−language-servers = ["typst-lsp"]
2847−indent = { tab-width = 2, unit = " " }
2848−
2849−[language.auto-pairs]
2850−'(' = ')'
2851−'{' = '}'
2852−'[' = ']'
2853−'$' = '$'
2854−'"' = '"'
2855−
2856−[[grammar]]
2857−name = "typst"
2858−source = { git = "https://github.com/uben0/tree-sitter-typst", rev = "e35aa22395fdde82bbc4b5700c324ce346dfc9e5" }
2859−
28602705[[language]]
28612706name = "nunjucks"
28622707scope = "text.html.nunjucks"
28632708injection-regex = "nunjucks"
28642709file-types = ["njk"]
2710+roots = []
28652711indent = { tab-width = 2, unit = " " }
28662712grammar = "jinja2"
28672713
@@ -2870,6 +2716,7 @@ name = "jinja"
28702716scope = "text.html.jinja"
28712717injection-regex = "jinja"
28722718file-types = ["jinja", "jinja2", "j2"]
2719+roots = []
28732720indent = { tab-width = 2, unit = " " }
28742721grammar = "jinja2"
28752722
@@ -2886,6 +2733,7 @@ name = "wren"
28862733scope = "source.wren"
28872734injection-regex = "wren"
28882735file-types = ["wren"]
2736+roots = []
28892737indent = { tab-width = 2, unit = " "}
28902738
28912739[[language]]
@@ -2894,6 +2742,7 @@ scope = "source.unison"
28942742injection-regex = "unison"
28952743file-types = ["u"]
28962744shebangs = []
2745+roots = []
28972746auto-format = false
28982747comment-token = "--"
28992748indent = { tab-width = 4, unit = " " }
@@ -2913,96 +2762,10 @@ source = { git = "https://github.com/kylegoetz/tree-sitter-unison", rev = "98c4e
29132762name = "todotxt"
29142763scope = "text.todotxt"
29152764file-types = [{ suffix = ".todo.txt" }, "todotxt"]
2765+roots = []
29162766formatter = { command = "sort" }
29172767auto-format = true
29182768
29192769[[grammar]]
29202770name = "todotxt"
29212771source = { git = "https://github.com/arnarg/tree-sitter-todotxt", rev = "0207f6a4ab6aeafc4b091914d31d8235049a2578" }
2922−
2923−[[language]]
2924−name = "strace"
2925−scope = "source.strace"
2926−file-types = ["strace"]
2927−
2928−[[grammar]]
2929−name = "strace"
2930−source = { git = "https://github.com/sigmaSd/tree-sitter-strace", rev = "2b18fdf9a01e7ec292cc6006724942c81beb7fd5" }
2931−
2932−[[language]]
2933−name = "gemini"
2934−scope = "source.gmi"
2935−file-types = ["gmi"]
2936−
2937−[[grammar]]
2938−name = "gemini"
2939−source = { git = "https://git.sr.ht/~nbsp/tree-sitter-gemini", rev = "3cc5e4bdf572d5df4277fc2e54d6299bd59a54b3" }
2940−
2941−[[language]]
2942−name = "agda"
2943−scope = "source.agda"
2944−injection-regex = "agda"
2945−file-types = ["agda"]
2946−roots = []
2947−comment-token = "--"
2948−# language-servers = [ "als" ]
2949−# the agda language server is of questionable functionality.
2950−auto-format = false
2951−indent = { tab-width = 2, unit = " " }
2952−
2953−[language.auto-pairs]
2954−'"' = '"'
2955−"'" = "'"
2956−'{' = '}'
2957−'(' = ')'
2958−'[' = ']'
2959−
2960−# [language.debugger]
2961−# ?? can this be used for proof assistant support? explore
2962−
2963−[[grammar]]
2964−name = "agda"
2965−source = { git = "https://github.com/tree-sitter/tree-sitter-agda", rev = "c21c3a0f996363ed17b8ac99d827fe5a4821f217" }
2966−
2967−[[language]]
2968−name = "templ"
2969−scope = "source.templ"
2970−file-types = ["templ"]
2971−roots = ["go.work", "go.mod"]
2972−comment-token = "//"
2973−indent = { tab-width = 2, unit = " " }
2974−language-servers = [ "templ" ]
2975−
2976−[[grammar]]
2977−name = "templ"
2978−source = { git = "https://github.com/vrischmann/tree-sitter-templ", rev = "ea56ac0655243490a4929a988f4eaa91dfccc995" }
2979−
2980−[[language]]
2981−name = "dbml"
2982−scope = "source.dbml"
2983−injection-regex = "dbml"
2984−file-types = ["dbml"]
2985−comment-token = ";"
2986−indent = { tab-width = 2, unit = " " }
2987−
2988−[[grammar]]
2989−name = "dbml"
2990−source = { git = "https://github.com/dynamotn/tree-sitter-dbml", rev = "2e2fa5640268c33c3d3f27f7e676f631a9c68fd9" }
2991−
2992−[[language]]
2993−name = "log"
2994−scope = "source.log"
2995−file-types = ["log"]
2996−
2997−[[grammar]]
2998−name = "log"
2999−source = { git = "https://github.com/Tudyx/tree-sitter-log", rev = "62cfe307e942af3417171243b599cc7deac5eab9" }
3000−
3001−[[language]]
3002−name = "janet"
3003−scope = "source.janet"
3004−injection-regex = "janet"
3005−file-types = ["janet"]
3006−comment-token = "#"
3007−indent = { tab-width = 2, unit = " " }
3008−grammar = "clojure"
logo.svg+1−1
@@ -1 +1 @@
1−<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;" viewBox="663.38 37.57 575.35 903.75"><g transform="matrix(1,0,0,1,-31352.7,-1817.25)"><g transform="matrix(1,0,0,1,31062.7,-20.8972)"><g transform="matrix(1,0,0,1,-130.173,0.00185558)"><path style="fill:#706bc8;" d="M1083.58,1875.72L1635.06,2194.12C1649.8,2202.63 1658.88,2218.37 1658.88,2235.39C1658.88,2264.98 1658.88,2311.74 1658.88,2341.33C1658.88,2349.84 1656.61,2358.03 1652.5,2365.16C1652.5,2365.16 1214.7,2112.4 1107.2,2050.33C1092.58,2041.89 1083.58,2026.29 1083.58,2009.41C1083.58,1963.5 1083.58,1875.72 1083.58,1875.72Z"></path></g><g transform="matrix(1,0,0,1,-130.173,0.00185558)"><path style="fill:#55c5e4;" d="M1635.26,2604.84C1649.88,2613.28 1658.88,2628.87 1658.88,2645.75C1658.88,2691.67 1658.88,2779.44 1658.88,2779.44L1107.41,2461.05C1092.66,2452.53 1083.58,2436.8 1083.58,2419.78C1083.58,2390.19 1083.58,2343.42 1083.58,2313.84C1083.58,2305.32 1085.85,2297.13 1089.96,2290.01C1089.96,2290.01 1527.76,2542.77 1635.26,2604.84Z"></path></g><g transform="matrix(1,0,0,1,216.062,984.098)"><path style="fill:#84ddea;" d="M790.407,1432.56C785.214,1435.55 780.717,1439.9 777.509,1445.46C767.862,1462.16 773.473,1483.76 790.004,1493.59L789.998,1493.59L761.173,1476.95C746.427,1468.44 737.344,1452.71 737.344,1435.68C737.344,1406.09 737.344,1359.33 737.344,1329.74C737.344,1312.71 746.427,1296.98 761.173,1288.47L1259.59,1000.74L1259.83,1000.6C1264.92,997.617 1269.33,993.314 1272.48,987.844C1282.13,971.136 1276.52,949.544 1259.99,939.707L1260,939.707L1288.82,956.349C1303.57,964.862 1312.65,980.595 1312.65,997.622C1312.65,1027.21 1312.65,1073.97 1312.65,1103.56C1312.65,1120.59 1303.57,1136.32 1288.82,1144.83L1259.19,1161.94L1259.59,1161.68L790.407,1432.56Z"></path></g><g transform="matrix(1,0,0,1,216.062,984.098)"><path style="fill:#997bc8;" d="M790.407,1686.24C785.214,1689.23 780.717,1693.58 777.509,1699.13C767.862,1715.84 773.473,1737.43 790.004,1747.27L789.998,1747.27L761.173,1730.63C746.427,1722.12 737.344,1706.38 737.344,1689.36C737.344,1659.77 737.344,1613.01 737.344,1583.42C737.344,1566.39 746.427,1550.66 761.173,1542.15L1259.59,1254.42L1259.83,1254.28C1264.92,1251.29 1269.33,1246.99 1272.48,1241.52C1282.13,1224.81 1276.52,1203.22 1259.99,1193.38L1260,1193.38L1288.82,1210.03C1303.57,1218.54 1312.65,1234.27 1312.65,1251.3C1312.65,1280.89 1312.65,1327.65 1312.65,1357.24C1312.65,1374.26 1303.57,1390 1288.82,1398.51L1259.19,1415.61L1259.59,1415.36L790.407,1686.24Z"></path></g></g></g></svg>
1+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;" viewBox="663.38 37.57 575.35 903.75"> <g transform="matrix(1,0,0,1,-31352.7,-1817.25)"> <g transform="matrix(1,0,0,1,31062.7,-20.8972)"> <g transform="matrix(1,0,0,1,-130.173,0.00185558)"> <path d="M1083.58,1875.72L1635.06,2194.12C1649.8,2202.63 1658.88,2218.37 1658.88,2235.39C1658.88,2264.98 1658.88,2311.74 1658.88,2341.33C1658.88,2349.84 1656.61,2358.03 1652.5,2365.16C1652.5,2365.16 1214.7,2112.4 1107.2,2050.33C1092.58,2041.89 1083.58,2026.29 1083.58,2009.41C1083.58,1963.5 1083.58,1875.72 1083.58,1875.72Z" style="fill:#706bc8;"></path> </g> <g transform="matrix(1,0,0,1,-130.173,0.00185558)"> <path d="M1635.26,2604.84C1649.88,2613.28 1658.88,2628.87 1658.88,2645.75C1658.88,2691.67 1658.88,2779.44 1658.88,2779.44L1107.41,2461.05C1092.66,2452.53 1083.58,2436.8 1083.58,2419.78C1083.58,2390.19 1083.58,2343.42 1083.58,2313.84C1083.58,2305.32 1085.85,2297.13 1089.96,2290.01C1089.96,2290.01 1527.76,2542.77 1635.26,2604.84Z" style="fill:#55c5e4;"></path> </g> <g transform="matrix(1,0,0,1,216.062,984.098)"> <path d="M790.407,1432.56C785.214,1435.55 780.717,1439.9 777.509,1445.46C767.862,1462.16 773.473,1483.76 790.004,1493.59L789.998,1493.59L761.173,1476.95C746.427,1468.44 737.344,1452.71 737.344,1435.68C737.344,1406.09 737.344,1359.33 737.344,1329.74C737.344,1312.71 746.427,1296.98 761.173,1288.47L1259.59,1000.74L1259.83,1000.6C1264.92,997.617 1269.33,993.314 1272.48,987.844C1282.13,971.136 1276.52,949.544 1259.99,939.707L1260,939.707L1288.82,956.349C1303.57,964.862 1312.65,980.595 1312.65,997.622C1312.65,1027.21 1312.65,1073.97 1312.65,1103.56C1312.65,1120.59 1303.57,1136.32 1288.82,1144.83L1259.19,1161.94L1259.59,1161.68L790.407,1432.56Z" style="fill:#84ddea;"></path> </g> <g transform="matrix(1,0,0,1,216.062,984.098)"> <path d="M790.407,1686.24C785.214,1689.23 780.717,1693.58 777.509,1699.13C767.862,1715.84 773.473,1737.43 790.004,1747.27L789.998,1747.27L761.173,1730.63C746.427,1722.12 737.344,1706.38 737.344,1689.36C737.344,1659.77 737.344,1613.01 737.344,1583.42C737.344,1566.39 746.427,1550.66 761.173,1542.15L1259.59,1254.42L1259.83,1254.28C1264.92,1251.29 1269.33,1246.99 1272.48,1241.52C1282.13,1224.81 1276.52,1203.22 1259.99,1193.38L1260,1193.38L1288.82,1210.03C1303.57,1218.54 1312.65,1234.27 1312.65,1251.3C1312.65,1280.89 1312.65,1327.65 1312.65,1357.24C1312.65,1374.26 1303.57,1390 1288.82,1398.51L1259.19,1415.61L1259.59,1415.36L790.407,1686.24Z" style="fill:#997bc8;"></path></g></g></g> </svg>
runtime/queries/_typescript/highlights.scm+3−5
@@ -39,11 +39,11 @@
3939 (identifier) @variable.parameter))
4040
4141; (p?: t)
42−; (p?: t = 1) // Invalid but still possible to highlight.
42+; (p?: t = 1) // Invalid but still posible to hihglight.
4343(optional_parameter
4444 (identifier) @variable.parameter)
4545
46−; (...p?: t) // Invalid but still possible to highlight.
46+; (...p?: t) // Invalid but still posible to hihglight.
4747(optional_parameter
4848 (rest_pattern
4949 (identifier) @variable.parameter))
@@ -59,7 +59,7 @@
5959 (pair_pattern
6060 value: (identifier) @variable.parameter)))
6161
62−; ([ p ]?: t[]) // Invalid but still possible to highlight.
62+; ([ p ]?: t[]) // Invalid but still posible to hihglight.
6363(optional_parameter
6464 (array_pattern
6565 (identifier) @variable.parameter))
@@ -107,8 +107,6 @@
107107; Types
108108; -----
109109
110−(type_parameter
111− name: (type_identifier) @type.parameter)
112110(type_identifier) @type
113111(predefined_type) @type.builtin
114112
runtime/queries/_typescript/locals.scm−17
@@ -1,18 +1,6 @@
1−; Scopes
2−;-------
3−
4−[
5− (type_alias_declaration)
6− (class_declaration)
7− (interface_declaration)
8−] @local.scope
9−
101; Definitions
112;------------
123
13−(type_parameter
14− name: (type_identifier) @local.definition)
15−
164; Javascript and Typescript Treesitter grammars deviate when defining the
175; tree structure for parameters, so we need to address them in each specific
186; language instead of ecma.
@@ -26,8 +14,3 @@
2614; (i?: t = 1) // Invalid but still posible to hihglight.
2715(optional_parameter
2816 (identifier) @local.definition)
29−
30−; References
31−;-----------
32−
33−(type_identifier) @local.reference
runtime/queries/agda/highlights.scmdeleted−124
@@ -1,124 +0,0 @@
1−;; Punctuation
2−[ "." ";" ":"] @punctuation.delimiter
3−[ "(" ")" "{" "}" ] @punctuation.bracket
4−
5−;; Constants
6−(integer) @constant.numeric.integer
7−; (float) @constant.numeric.float
8−(literal) @string
9−
10−;; Pragmas and comments
11−(comment) @comment
12−(pragma) @attribute
13−(macro) @function.macro
14−
15−;; Imports
16−(module_name) @namespace
17−(import_directive (id) @namespace)
18−[(module) (import) (open)] @keyword.control.import
19−
20−;; Types
21−(typed_binding (expr) @type)
22−(record (expr) @type)
23−(data (expr) @type)
24−(signature (expr) @type)
25−(function (rhs (expr) @type))
26−; todo: these are too general. ideally, any nested (atom)
27−; https://github.com/tree-sitter/tree-sitter/issues/880
28−
29−;; Variables
30−(untyped_binding (atom) @variable)
31−(typed_binding (atom) @variable)
32−(field_name) @variable.other.member
33−
34−;; Functions
35−(function_name) @function
36−;(function (lhs
37−; . (atom) @function
38−; (atom) @variable.parameter))
39−; todo: currently fails to parse, upstream tree-sitter bug
40−
41−;; Data
42−[(data_name) (record_name)] @constructor
43−((atom) @constant.builtin.boolean
44− (#any-of? @constant.builtin.boolean "true" "false" "True" "False"))
45−
46−"Set" @type.builtin
47−
48−; postulate
49−; type_signature
50−; pattern
51−; id
52−; bid
53−; typed_binding
54−; primitive
55−; private
56−; record_signature
57−; record_assignments
58−; field_assignment
59−; module_assignment
60−; renaming
61−; import_directive
62−; lambda
63−; let
64−; instance
65−; generalize
66−; record
67−; fields
68−; syntax
69−; hole_name
70−; data_signature
71−
72−;; Keywords
73−[
74− "where"
75− "data"
76− "rewrite"
77− "postulate"
78− "public"
79− "private"
80− "tactic"
81− "Prop"
82− "quote"
83− "renaming"
84− "in"
85− "hiding"
86− "constructor"
87− "abstract"
88− "let"
89− "field"
90− "mutual"
91− "infix"
92− "infixl"
93− "infixr"
94− "record"
95− "overlap"
96− "instance"
97− "do"
98−] @keyword
99−
100−[
101− "="
102−] @operator
103−
104−; = | -> : ? \ .. ... λ ∀ →
105−; (_LAMBDA) (_FORALL) (_ARROW)
106−; "coinductive"
107−; "eta-equality"
108−; "field"
109−; "inductive"
110−; "interleaved"
111−; "macro"
112−; "no-eta-equality"
113−; "pattern"
114−; "primitive"
115−; "quoteTerm"
116−; "rewrite"
117−; "syntax"
118−; "unquote"
119−; "unquoteDecl"
120−; "unquoteDef"
121−; "using"
122−; "variable"
123−; "with"
124−
runtime/queries/bash/indents.scm−1
@@ -2,7 +2,6 @@
22 (function_definition)
33 (if_statement)
44 (for_statement)
5− (while_statement)
65 (case_statement)
76 (pipeline)
87] @indent
runtime/queries/blueprint/highlights.scm−5
@@ -15,11 +15,6 @@
1515(decorator) @attribute
1616
1717(property_definition (property_name) @variable.other.member)
18−(property_definition
19− (property_binding
20− "bind" @keyword
21− (property_name) @variable.other.member
22− ["no-sync-create" "bidirectional" "inverted"]* @keyword))
2318
2419(object) @type
2520
runtime/queries/c/indents.scm+1−18
@@ -5,6 +5,7 @@
55 (enumerator_list)
66 (parameter_list)
77 (init_declarator)
8+ (case_statement)
89 (expression_statement)
910] @indent
1011
@@ -12,7 +13,6 @@
1213 "case"
1314 "}"
1415 "]"
15− ")"
1616] @outdent
1717
1818(if_statement
@@ -32,20 +32,3 @@
3232 (_) @indent
3333 (#not-kind-eq? @indent "compound_statement")
3434 (#set! "scope" "all"))
35−
36−(parameter_list
37− . (parameter_declaration) @anchor
38− (#set! "scope" "tail")) @align
39−(argument_list
40− . (_) @anchor
41− (#set! "scope" "tail")) @align
42−; These are a bit opinionated since some people just indent binary/ternary expressions spanning multiple lines.
43−; Since they are only triggered when a newline is inserted into an already complete binary/ternary expression,
44−; this should happen rarely, so it is not a big deal either way.
45−; Additionally, adding these queries has the advantage of preventing such continuation lines from being used
46−; as the baseline when the `hybrid` indent heuristic is used (which is desirable since their indentation is so inconsistent).
47−(binary_expression
48− (#set! "scope" "tail")) @anchor @align
49−(conditional_expression
50− "?" @anchor
51− (#set! "scope" "tail")) @align
runtime/queries/comment/highlights.scm+8−8
@@ -7,31 +7,31 @@
77
88; Hint level tags
99((tag (name) @hint)
10− (#match? @hint "^(HINT|MARK|PASSED|STUB|MOCK)$"))
10+ (#match? @hint "^(HINT|MARK)$"))
1111
1212("text" @hint
13− (#match? @hint "^(HINT|MARK|PASSED|STUB|MOCK)$"))
13+ (#match? @hint "^(HINT|MARK)$"))
1414
1515; Info level tags
1616((tag (name) @info)
17− (#match? @info "^(INFO|NOTE|TODO|PERF|OPTIMIZE|PERFORMANCE|QUESTION|ASK)$"))
17+ (#match? @info "^(INFO|NOTE|TODO)$"))
1818
1919("text" @info
20− (#match? @info "^(INFO|NOTE|TODO|PERF|OPTIMIZE|PERFORMANCE|QUESTION|ASK)$"))
20+ (#match? @info "^(INFO|NOTE|TODO)$"))
2121
2222; Warning level tags
2323((tag (name) @warning)
24− (#match? @warning "^(HACK|WARN|WARNING|TEST|TEMP)$"))
24+ (#match? @warning "^(HACK|WARN|WARNING)$"))
2525
2626("text" @warning
27− (#match? @warning "^(HACK|WARN|WARNING|TEST|TEMP)$"))
27+ (#match? @warning "^(HACK|WARN|WARNING)$"))
2828
2929; Error level tags
3030((tag (name) @error)
31− (#match? @error "^(BUG|FIXME|ISSUE|XXX|FIX|SAFETY|FIXIT|FAILED|DEBUG)$"))
31+ (#match? @error "^(BUG|FIXME|ISSUE|XXX)$"))
3232
3333("text" @error
34− (#match? @error "^(BUG|FIXME|ISSUE|XXX|FIX|SAFETY|FIXIT|FAILED|DEBUG)$"))
34+ (#match? @error "^(BUG|FIXME|ISSUE|XXX)$"))
3535
3636(tag
3737 (name) @ui.text
runtime/queries/common-lisp/indents.scmdeleted−1
@@ -1 +0,0 @@
1−; inherits: scheme
runtime/queries/dart/highlights.scm+1−3
@@ -200,7 +200,6 @@
200200 "async"
201201 "async*"
202202 "await"
203− "base"
204203 "class"
205204 "covariant"
206205 "deferred"
@@ -220,7 +219,6 @@
220219 "operator"
221220 "part"
222221 "required"
223− "sealed"
224222 "set"
225223 "show"
226224 "static"
@@ -232,7 +230,7 @@
232230
233231; when used as an identifier:
234232((identifier) @variable.builtin
235− (#match? @variable.builtin "^(abstract|as|base|covariant|deferred|dynamic|export|external|factory|Function|get|implements|import|interface|library|operator|mixin|part|sealed|set|static|typedef)$"))
233+ (#match? @variable.builtin "^(abstract|as|covariant|deferred|dynamic|export|external|factory|Function|get|implements|import|interface|library|operator|mixin|part|set|static|typedef)$"))
236234
237235; Error
238236(ERROR) @error
runtime/queries/dbml/highlights.scmdeleted−44
@@ -1,44 +0,0 @@
1−
2−; comments highlighting
3−(comment) @comment
4−
5−; keyword highlighting
6−(keyword_def) @keyword
7−(keyword_enum) @keyword
8−(keyword_ref) @keyword
9−
10−; identify blocks and definitions
11−(definition) @function
12−
13−; for identifiers
14−(identifier) @variable
15−(type) @keyword
16−
17−; Highlight special types for database/data types
18−("Project" ) @type
19−("Table" ) @type
20−("TableGroup" ) @type
21−("database_type" ) @variable
22−
23−; string and number constants
24−("'''") @constant.character.escape
25−(string) @string
26−(number) @constant.numeric
27−
28−; brackets
29−[
30− "("
31− ")"
32− "{"
33− "}"
34− "["
35− "]"
36−] @punctuation.bracket
37−
38−; brackets
39−[
40− ":"
41− "."
42− ","
43−] @punctuation.delimiter
44−
runtime/queries/fsharp/locals.scmdeleted−25
@@ -1,25 +0,0 @@
1−; Scopes
2−;-------
3−
4−[
5− (ce_expression)
6− (module_defn)
7− (for_expression)
8− (do_expression)
9− (fun_expression)
10− (function_expression)
11− (try_expression)
12− (match_expression)
13− (elif_expression)
14− (if_expression)
15−] @local.scope
16−
17−; Definitions
18−;------------
19−
20−(function_or_value_defn) @local.definition
21−
22−; References
23−;-----------
24−
25−(identifier) @local.reference
runtime/queries/gas/highlights.scmdeleted−21
@@ -1,21 +0,0 @@
1−(comment) @comment
2−(number) @constant.numeric
3−(directive_name) @keyword.directive
4−(symbol) @variable
5−(label) @function
6−(label)
7−(instruction_prefix) @keyword
8−(instruction_name) @function.special
9−(register) @constant.builtin
10−(string) @string
11−(char) @constant.character
12−(type) @type
13−(constant "$" @constant)
14−(operand_modifier) @attribute
15−
16−(expression
17− ["-" "+" "*" "/" "="] @operator)
18−
19−["(" ")"] @punctuation.bracket
20−
21−["," ":"] @punctuation.delimiter
runtime/queries/gas/injections.scmdeleted−2
@@ -1,2 +0,0 @@
1−((comment) @injection.content
2− (#set! injection.language "comment"))
runtime/queries/gas/textobjects.scmdeleted−2
@@ -1,2 +0,0 @@
1−(comment) @comment.inside
2−(comment)+ @comment.around
runtime/queries/gemini/highlights.scmdeleted−26
@@ -1,26 +0,0 @@
1−(link) @punctuation.bracket
2−(link
3− label: (text) @markup.link.label)
4−(link
5− uri: (uri) @markup.link.url)
6−
7−[
8− (start_pre)
9− (pre)
10− (end_pre)
11−] @markup.raw.block
12−(start_pre
13− alt: (text) @label)
14−
15−(heading1
16− (text) @markup.heading.1) @markup.heading.marker
17−(heading2
18− (text) @markup.heading.2) @markup.heading.marker
19−(heading3
20− (text) @markup.heading.3) @markup.heading.marker
21−
22−(ulist
23− (indicator) @markup.list.unnumbered)
24−(quote
25− (indicator) @markup.quote
26− (text) @markup.italic)
runtime/queries/gleam/highlights.scm+5−16
@@ -21,8 +21,6 @@
2121
2222; Functions
2323(unqualified_import (identifier) @function)
24−(unqualified_import "type" (type_identifier) @type)
25−(unqualified_import (type_identifier) @constructor)
2624(function
2725 name: (identifier) @function)
2826(external_function
@@ -45,13 +43,6 @@
4543(tuple_access
4644 index: (integer) @variable.other.member)
4745
48−; Attributes
49−(attribute
50− "@" @attribute
51− name: (identifier) @attribute)
52−
53−(attribute_value (identifier) @constant)
54−
5546; Type names
5647(remote_type_identifier) @type
5748(type_identifier) @type
@@ -69,6 +60,10 @@
6960(identifier) @variable
7061(discard) @comment.unused
7162
63+; Operators
64+(binary_expression
65+ operator: _ @operator)
66+
7267; Keywords
7368[
7469 (visibility_modifier) ; "pub"
@@ -77,7 +72,6 @@
7772 "assert"
7873 "case"
7974 "const"
80− ; DEPRECATED: 'external' was removed in v0.30.
8175 "external"
8276 "fn"
8377 "if"
@@ -85,16 +79,11 @@
8579 "let"
8680 "panic"
8781 "todo"
82+ "try"
8883 "type"
8984 "use"
9085] @keyword
9186
92−; Operators
93−(binary_expression
94− operator: _ @operator)
95−(boolean_negation "!" @operator)
96−(integer_negation "-" @operator)
97−
9887; Punctuation
9988[
10089 "("
runtime/queries/gn/highlights.scmdeleted−42
@@ -1,42 +0,0 @@
1−; Copyright (C) 2021 Will Cassella (github@willcassella.com)
2−;
3−; Licensed under the Apache License, Version 2.0 (the "License");
4−; you may not use this file except in compliance with the License.
5−; You may obtain a copy of the License at
6−;
7−; http://www.apache.org/licenses/LICENSE-2.0
8−;
9−; Unless required by applicable law or agreed to in writing, software
10−; distributed under the License is distributed on an "AS IS" BASIS,
11−; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12−; See the License for the specific language governing permissions and
13−; limitations under the License.
14−
15−(identifier) @variable.builtin
16−
17−(scope_access field: (_) @variable.other.member)
18−
19−(call target: (_) @function)
20−
21−[ "if" "else" ] @keyword.control.conditional
22−
23−[
24− (assign_op)
25− (arithmetic_binary_op)
26− (comparison_binary_op)
27− (equivalence_binary_op)
28− (logical_and_binary_op)
29− (logical_or_binary_op)
30− (negation_unary_op)
31−] @operator
32−
33−[ "(" ")" "[" "]" "{" "}" ] @punctuation.bracket
34−[ "." "," ] @punctuation.delimiter
35−
36−(string) @string
37−(string_escape) @constant.character.escape
38−(string_expansion [ "$" "${" "}" ] @constant.character.escape)
39−[ (integer) (hex) ] @constant.numeric
40−(boolean) @constant.builtin.boolean
41−
42−(comment) @comment
runtime/queries/gn/injections.scmdeleted−15
@@ -1,15 +0,0 @@
1−; Copyright (C) 2021 Will Cassella (github@willcassella.com)
2−;
3−; Licensed under the Apache License, Version 2.0 (the "License");
4−; you may not use this file except in compliance with the License.
5−; You may obtain a copy of the License at
6−;
7−; http://www.apache.org/licenses/LICENSE-2.0
8−;
9−; Unless required by applicable law or agreed to in writing, software
10−; distributed under the License is distributed on an "AS IS" BASIS,
11−; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12−; See the License for the specific language governing permissions and
13−; limitations under the License.
14−
15−((comment) @injection.content (#set! injection.language "comment"))
runtime/queries/gn/locals.scmdeleted−16
@@ -1,16 +0,0 @@
1−; Copyright (C) 2021 Will Cassella (github@willcassella.com)
2−;
3−; Licensed under the Apache License, Version 2.0 (the "License");
4−; you may not use this file except in compliance with the License.
5−; You may obtain a copy of the License at
6−;
7−; http://www.apache.org/licenses/LICENSE-2.0
8−;
9−; Unless required by applicable law or agreed to in writing, software
10−; distributed under the License is distributed on an "AS IS" BASIS,
11−; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12−; See the License for the specific language governing permissions and
13−; limitations under the License.
14−
15−(source_file) @local.scope
16−(assignment target: (identifier) @local.definition)
runtime/queries/go/highlights.scm+5−13
@@ -11,18 +11,6 @@
1111 function: (selector_expression
1212 field: (field_identifier) @function.method))
1313
14−
15−; Types
16−
17−(type_parameter_list
18− (parameter_declaration
19− name: (identifier) @type.parameter))
20−
21−((type_identifier) @type.builtin
22− (match? @type.builtin "^(any|bool|byte|comparable|complex128|complex64|error|float32|float64|int|int16|int32|int64|int8|rune|string|uint|uint16|uint32|uint64|uint8|uintptr)$"))
23−
24−(type_identifier) @type
25−
2614; Function definitions
2715
2816(function_declaration
@@ -36,16 +24,20 @@
3624
3725; Identifiers
3826
27+((identifier) @constant (match? @constant "^[A-Z][A-Z\\d_]+$"))
3928(const_spec
4029 name: (identifier) @constant)
4130
4231(parameter_declaration (identifier) @variable.parameter)
4332(variadic_parameter_declaration (identifier) @variable.parameter)
4433
34+((type_identifier) @type.builtin
35+ (match? @type.builtin "^(any|bool|byte|comparable|complex128|complex64|error|float32|float64|int|int16|int32|int64|int8|rune|string|uint|uint16|uint32|uint64|uint8|uintptr)$"))
36+
37+(type_identifier) @type
4538(type_spec
4639 name: (type_identifier) @constructor)
4740(field_identifier) @variable.other.member
48−(keyed_element (literal_element (identifier) @variable.other.member))
4941(identifier) @variable
5042(package_identifier) @namespace
5143
runtime/queries/go/locals.scm+2−10
@@ -1,17 +1,9 @@
11; Scopes
22
3−[
4− (function_declaration)
5− (type_declaration)
6− (block)
7−] @local.scope
3+(block) @local.scope
84
95; Definitions
106
11−(type_parameter_list
12− (parameter_declaration
13− name: (identifier) @local.definition))
14−
157(parameter_declaration (identifier) @local.definition)
168(variadic_parameter_declaration (identifier) @local.definition)
179
@@ -35,4 +27,4 @@
3527
3628(identifier) @local.reference
3729(field_identifier) @local.reference
38−(type_identifier) @local.reference
30+
runtime/queries/haskell/highlights.scm+11−24
@@ -33,11 +33,6 @@
3333;; ----------------------------------------------------------------------------
3434;; Keywords, operators, includes
3535
36−[
37− "forall"
38− "∀"
39−] @keyword.control.repeat
40−
4136(pragma) @constant.macro
4237
4338[
@@ -73,7 +68,10 @@
7368 "@"
7469] @operator
7570
76−(module) @namespace
71+(qualified_module (module) @constructor)
72+(qualified_type (module) @namespace)
73+(qualified_variable (module) @namespace)
74+(import (module) @namespace)
7775
7876[
7977 (where)
@@ -94,6 +92,8 @@
9492 "do"
9593 "mdo"
9694 "rec"
95+ "forall"
96+ "∀"
9797 "infix"
9898 "infixl"
9999 "infixr"
@@ -104,35 +104,22 @@
104104;; Functions and variables
105105
106106(signature name: (variable) @type)
107−(function
108− name: (variable) @function
109− patterns: (patterns))
110−((signature (fun)) . (function (variable) @function))
111−((signature (context (fun))) . (function (variable) @function))
112−((signature (forall (context (fun)))) . (function (variable) @function))
107+(function name: (variable) @function)
108+
109+(variable) @variable
110+"_" @variable.builtin
113111
114112(exp_infix (variable) @operator) ; consider infix functions as operators
115113
116−(exp_infix (exp_name) @function)
117−(exp_apply . (exp_name (variable) @function))
118−(exp_apply . (exp_name (qualified_variable (variable) @function)))
114+("@" @namespace) ; "as" pattern operator, e.g. x@Constructor
119115
120−(variable) @variable
121−(pat_wildcard) @variable
122116
123117;; ----------------------------------------------------------------------------
124118;; Types
125119
126120(type) @type
127−(type_variable) @type.parameter
128121
129122(constructor) @constructor
130123
131124; True or False
132125((constructor) @_bool (#match? @_bool "(True|False)")) @constant.builtin.boolean
133−
134−;; ----------------------------------------------------------------------------
135−;; Quasi-quotes
136−
137−(quoter) @function
138−; Highlighting of quasiquote_body is handled by injections.scm
runtime/queries/janet/highlights.scmdeleted−1
@@ -1 +0,0 @@
1−; inherits: clojure
runtime/queries/json5/highlights.scmdeleted−11
@@ -1,11 +0,0 @@
1−(string) @string
2−
3−(identifier) @constant
4−
5−(number) @constant.numeric
6−
7−(null) @constant.builtin
8−
9−[(true) (false)] @constant.builtin.boolean
10−
11−(comment) @comment
runtime/queries/kdl/highlights.scm+4−4
@@ -1,12 +1,12 @@
1+(comment) @comment
12(single_line_comment) @comment
2−(multi_line_comment) @comment
33
44(node
5− (identifier) @variable)
6−
5+ name: (identifier) @function)
76(prop (identifier) @attribute)
7+(type) @type
88
9−(type (_) @type) @punctuation.bracket
9+(bare_identifier) @variable.other.member
1010
1111(keyword) @keyword
1212
runtime/queries/kdl/indents.scmdeleted−3
@@ -1,3 +0,0 @@
1−(node_children) @indent
2−
3− "}" @outdent
runtime/queries/kdl/textobjects.scmdeleted−27
@@ -1,27 +0,0 @@
1−(type (_) @test.inside) @test.around
2−
3−(node
4− children: (node_children)? @class.inside) @class.around
5−
6−(node
7− children: (node_children)? @function.inside) @function.around
8−
9−(node (identifier) @function.movement)
10−
11−[
12− (single_line_comment)
13− (multi_line_comment)
14−] @comment.inside
15−
16−[
17− (single_line_comment)+
18− (multi_line_comment)+
19−] @comment.around
20−
21−[
22− (prop)
23− (value)
24−] @parameter.inside
25−
26−(value (type) ? (_) @parameter.inside @parameter.movement . ) @parameter.around
27−
runtime/queries/kotlin/highlights.scm+1−4
@@ -244,10 +244,7 @@
244244 . (identifier)) @namespace
245245
246246((type_identifier) @type.builtin
247− (#match? @type.builtin "^(Byte|Short|Int|Long|UByte|UShort|UInt|ULong|Float|Double|Boolean|Char|String|Array|ByteArray|ShortArray|IntArray|LongArray|UByteArray|UShortArray|UIntArray|ULongArray|FloatArray|DoubleArray|BooleanArray|CharArray|Map|Set|List|EmptyMap|EmptySet|EmptyList|MutableMap|MutableSet|MutableList)$"))
248−
249−(type_parameter
250− (type_identifier) @type.parameter)
247+ (#match? @function.builtin "^(Byte|Short|Int|Long|UByte|UShort|UInt|ULong|Float|Double|Boolean|Char|String|Array|ByteArray|ShortArray|IntArray|LongArray|UByteArray|UShortArray|UIntArray|ULongArray|FloatArray|DoubleArray|BooleanArray|CharArray|Map|Set|List|EmptyMap|EmptySet|EmptyList|MutableMap|MutableSet|MutableList)$"))
251248
252249(type_identifier) @type
253250
runtime/queries/kotlin/locals.scmdeleted−15
@@ -1,15 +0,0 @@
1−; Scopes
2−
3−[
4− (class_declaration)
5− (function_declaration)
6−] @local.scope
7−
8−; Definitions
9−
10−(type_parameter
11− (type_identifier) @local.definition)
12−
13−; References
14−
15−(type_identifier) @local.reference
runtime/queries/log/highlights.scmdeleted−10
@@ -1,10 +0,0 @@
1−(trace) @comment
2−(debug) @hint
3−(info) @info
4−(warn) @warning
5−(error) @error
6−(year_month_day) @keyword
7−(time) @constant
8−(string_literal) @string
9−(number) @constant.numeric
10−(constant) @constant.builtin
runtime/queries/lpf/highlights.scmdeleted−19
@@ -1,19 +0,0 @@
1−[
2− "SYSCONFIG"
3− "BLOCK"
4− "LOCATE"
5− "COMP"
6− "FREQUENCY"
7− "PORT"
8− "IOBUF"
9−] @keyword
10−
11−["SITE"] @keyword.storage
12−
13−["="] @operator
14−
15−((number) @constant.numeric)
16−
17−((string) @string)
18−((line_comment) @comment)
19−
runtime/queries/markdown.inline/injections.scm+1−4
@@ -1,7 +1,4 @@
11
2−((html_tag) @injection.content
3− (#set! injection.language "html")
4− (#set! injection.include-unnamed-children)
5− (#set! injection.combined))
2+((html_tag) @injection.content (#set! injection.language "html") (#set! injection.include-unnamed-children))
63
74((latex_block) @injection.content (#set! injection.language "latex") (#set! injection.include-unnamed-children))
runtime/queries/nix/injections.scm−14
@@ -5,20 +5,6 @@
55((((comment) @injection.language) .
66 (indented_string_expression (string_fragment) @injection.content))
77 (#set! injection.combined))
8−((binding
9− (comment) @injection.language
10− expression: (indented_string_expression (string_fragment) @injection.content))
11− (#set! injection.combined))
12−
13−; Common attribute keys corresponding to Python scripts,
14−; such as those for NixOS VM tests in nixpkgs/nixos/tests.
15−((binding
16− attrpath: (attrpath (identifier) @_path)
17− expression: (indented_string_expression
18− (string_fragment) @injection.content))
19− (#match? @_path "(^|\\.)testScript$")
20− (#set! injection.language "python")
21− (#set! injection.combined))
228
239; Common attribute keys corresponding to scripts,
2410; such as those of stdenv.mkDerivation.
runtime/queries/ocaml/highlights.scm−2
@@ -8,8 +8,6 @@
88
99[(class_name) (class_type_name) (type_constructor)] @type
1010
11−(type_variable) @type.parameter
12−
1311[(constructor_name) (tag)] @constructor
1412
1513; Functions
runtime/queries/perl/highlights.scm+2
@@ -41,6 +41,8 @@
4141(eof_marker) @keyword.directive
4242(data_section) @comment
4343
44+(pod) @comment.block.documentation
45+
4446(number) @constant.numeric
4547(version) @constant
4648
runtime/queries/perl/indents.scmdeleted−29
@@ -1,29 +0,0 @@
1−[
2− (block)
3− (conditional_statement)
4− (loop_statement)
5− (cstyle_for_statement)
6− (for_statement)
7− (elsif)
8− (array_element_expression)
9− (hash_element_expression)
10− (coderef_call_expression)
11− (anonymous_slice_expression)
12− (slice_expression)
13− (keyval_expression)
14− (anonymous_array_expression)
15− (anonymous_hash_expression)
16− (stub_expression)
17− (func0op_call_expression)
18− (func1op_call_expression)
19− (map_grep_expression)
20− (function_call_expression)
21− (method_call_expression)
22− (attribute)
23−] @indent
24−
25−[
26− "}"
27− "]"
28− ")"
29−] @outdent
runtime/queries/perl/injections.scm−2
@@ -1,4 +1,2 @@
11((comment) @injection.content
22 (#set! injection.language "comment"))
3−((pod) @injection.content
4− (#set! injection.language "pod"))
runtime/queries/perl/textobjects.scmdeleted−14
@@ -1,14 +0,0 @@
1−(subroutine_declaration_statement
2− body: (_) @function.inside) @function.around
3−(anonymous_subroutine_expression
4− body: (_) @function.inside) @function.around
5−
6−(package_statement) @class.around
7−(package_statement
8− (block) @class.inside)
9−
10−(list_expression
11− (_) @parameter.inside)
12−
13−(comment) @comment.around
14−(pod) @comment.around
runtime/queries/pod/highlights.scmdeleted−61
@@ -1,61 +0,0 @@
1−[(pod_directive)
2− (head_directive)
3− (over_directive)
4− (item_directive)
5− (back_directive)
6− (encoding_directive)
7− (cut_directive)] @tag
8−
9−(head_paragraph
10− (head_directive) @directive
11− (#eq? @directive "=head1")
12− (content) @markup.heading.1)
13−(head_paragraph
14− (head_directive) @directive
15− (#eq? @directive "=head2")
16− (content) @markup.heading.2)
17−(head_paragraph
18− (head_directive) @directive
19− (#eq? @directive "=head3")
20− (content) @markup.heading.3)
21−(head_paragraph
22− (head_directive) @directive
23− (#eq? @directive "=head4")
24− (content) @markup.heading.4)
25−(head_paragraph
26− (head_directive) @directive
27− (#eq? @directive "=head5")
28− (content) @markup.heading.5)
29−(head_paragraph
30− (head_directive) @directive
31− (#eq? @directive "=head6")
32− (content) @markup.heading.6)
33−
34−(over_paragraph (content) @constant.numeric.integer)
35−(item_paragraph (content) @markup.list)
36−(encoding_paragraph (content) @string)
37−
38−(verbatim_paragraph (content) @markup.raw)
39−
40−(interior_sequence) @tag
41−
42−(interior_sequence
43− (sequence_letter) @letter
44− (#eq? @letter "B")
45− (content) @markup.bold)
46−(interior_sequence
47− (sequence_letter) @letter
48− (#eq? @letter "C")
49− (content) @markup.raw)
50−(interior_sequence
51− (sequence_letter) @letter
52− (#eq? @letter "F")
53− (content) @markup.italic)
54−(interior_sequence
55− (sequence_letter) @letter
56− (#eq? @letter "I")
57− (content) @markup.italic)
58−(interior_sequence
59− (sequence_letter) @letter
60− (#eq? @letter "L")
61− (content) @markup.link.url)
runtime/queries/purescript/highlights.scm+1−164
@@ -1,164 +1 @@
1−; ----------------------------------------------------------------------------
2−; Record fields would need to come before literal strings in order to be captured correctly
3−
4− (record_accessor
5− field: [ (variable)
6− (string)
7− (triple_quote_string)
8− ] @variable.other.member)
9−
10− (exp_record_access
11− field: [ (variable)
12− (string)
13− (triple_quote_string)
14− ] @variable.other.member)
15−
16−
17−; ----------------------------------------------------------------------------
18−; Literals and comments
19−
20− (integer) @constant.numeric.integer
21− (exp_negation) @constant.numeric.integer
22− (exp_literal (number)) @constant.numeric.float
23− (char) @constant.character
24− [
25− (string)
26− (triple_quote_string)
27− ] @string
28−
29− (comment) @comment
30−
31−
32−; ----------------------------------------------------------------------------
33−; Punctuation
34−
35− [
36− "("
37− ")"
38− "{"
39− "}"
40− "["
41− "]"
42− ] @punctuation.bracket
43−
44− [
45− (comma)
46− ";"
47− ] @punctuation.delimiter
48−
49−
50−; ----------------------------------------------------------------------------
51−; Keywords, operators, includes
52−
53− ; This needs to come before the other "else" in
54− ; order to be highlighted correctly
55− (class_instance "else" @keyword)
56−
57− [
58− "if"
59− "then"
60− "else"
61− "case"
62− "of"
63− ] @keyword.control.conditional
64−
65− [
66− "import"
67− "module"
68− ] @keyword.control.import
69−
70− [
71− (operator)
72− (constructor_operator)
73− (type_operator)
74− (qualified_module) ; grabs the `.` (dot), ex: import System.IO
75− (all_names)
76−
77− ; `_` wildcards in if-then-else and case-of expressions,
78− ; as well as record updates and operator sections
79− (wildcard)
80− "="
81− "|"
82− "::"
83− "∷"
84− "=>"
85− "⇒"
86− "<="
87− "⇐"
88− "->"
89− "→"
90− "<-"
91− "←"
92− "\\"
93− "`"
94− "@"
95− ] @operator
96−
97− (qualified_module (module) @constructor)
98− (module) @namespace
99− (qualified_type (module) @namespace)
100− (qualified_variable (module) @namespace)
101− (import (module) @namespace)
102−
103− [
104− (where)
105− "let"
106− "in"
107− "class"
108− "instance"
109− "derive"
110− "foreign"
111− "data"
112− "newtype"
113− "type"
114− "as"
115− "hiding"
116− "do"
117− "ado"
118− "forall"
119− "∀"
120− "infix"
121− "infixl"
122− "infixr"
123− ] @keyword
124−
125− (type_role_declaration
126− "role" @keyword
127− role: (type_role) @keyword)
128−
129− (hole) @label
130−
131−; ----------------------------------------------------------------------------
132−; Functions and variables
133−
134− (row_field (field_name) @variable.other.member)
135− (record_field (field_name) @variable.other.member)
136− (record_field (field_pun) @variable.other.member)
137−
138− (signature name: (variable) @type)
139− (function name: (variable) @function)
140− (class_instance (instance_name) @function)
141− (derive_declaration (instance_name) @function)
142−
143− ; true or false
144− ((variable) @constant.builtin.boolean
145− (#match? @constant.builtin.boolean "^(true|false)$"))
146−
147− ; The former one works for `tree-sitter highlight` but not in Helix/Kakoune.
148− ; The latter two work in Helix (but not Kakoune) and are a good compromise between not highlighting anything at all
149− ; as an operator and leaving it to the child nodes, and highlighting everything as an operator.
150− (exp_ticked (_) @operator)
151− (exp_ticked (exp_name (variable) @operator))
152− (exp_ticked (exp_name (qualified_variable (variable) @operator)))
153−
154− (variable) @variable
155−
156− ("@" @namespace) ; "as" pattern operator, e.g. x@Constructor
157−
158−; ----------------------------------------------------------------------------
159−; Types
160−
161− (type) @type
162−
163− (constructor) @constructor
164−
1+; inherits: haskell
runtime/queries/purescript/injections.scm+1−2
@@ -1,2 +1 @@
1−((comment) @injection.content
2− (#set! injection.language "comment"))
1+; inherits: haskell
runtime/queries/purescript/locals.scm+1−4
@@ -1,4 +1 @@
1−(signature name: (variable)) @local.definition
2−(function name: (variable)) @local.definition
3−(pat_name (variable)) @local.definition
4−(exp_name (variable)) @local.reference
1+; inherits: haskell
runtime/queries/purescript/textobjects.scmdeleted−13
@@ -1,13 +0,0 @@
1−(comment) @comment.inside
2−
3−[
4− (data)
5− (type)
6− (newtype)
7−] @class.around
8−
9−((signature)? (function rhs:(_) @function.inside)) @function.around
10−(exp_lambda) @function.around
11−
12−(data (type_variable) @parameter.inside)
13−(patterns (_) @parameter.inside)
runtime/queries/python/highlights.scm−6
@@ -134,17 +134,14 @@
134134 "//="
135135 "/="
136136 "&"
137− "&="
138137 "%"
139138 "%="
140139 "^"
141− "^="
142140 "+"
143141 "->"
144142 "+="
145143 "<"
146144 "<<"
147− "<<="
148145 "<="
149146 "<>"
150147 "="
@@ -153,11 +150,8 @@
153150 ">"
154151 ">="
155152 ">>"
156− ">>="
157153 "|"
158− "|="
159154 "~"
160− "@="
161155] @operator
162156
163157[
runtime/queries/python/indents.scm−9
@@ -73,12 +73,3 @@
7373(else_clause
7474 "else" @outdent)
7575
76−(parameters
77− .
78− (identifier) @anchor
79− (#set! "scope" "tail")) @align
80−(argument_list
81− .
82− (_) @anchor
83− (#set! "scope" "tail")) @align
84−
runtime/queries/racket/indents.scmdeleted−1
@@ -1 +0,0 @@
1−; inherits: scheme
runtime/queries/robot/highlights.scm+13−51
@@ -1,59 +1,21 @@
1−[
2− (comment)
3− (extra_text)
4−] @comment
5−
6−[
7− (section_header)
8− (setting_statement)
9− (keyword_setting)
10− (test_case_setting)
11−] @keyword
12−
13−(variable_definition (variable_name) @variable)
14−(keyword_definition (name) @function)
15−(test_case_definition (name) @function)
16−
17−(keyword_invocation (keyword) @function)
1+(comment) @comment
182(ellipses) @punctuation.delimiter
193
20−(text_chunk) @string
21−(inline_python_expression) @string.special
22−[
23− (scalar_variable)
24− (list_variable)
25− (dictionary_variable)
26−] @variable
4+(section_header) @keyword
5+(extra_text) @comment
276
28−; Control structures
7+(setting_statement) @keyword
298
30−"RETURN" @keyword.control.return
9+(variable_definition (variable_name) @variable)
3110
32−[
33− "FOR"
34− "IN"
35− "IN RANGE"
36− "IN ENUMERATE"
37− "IN ZIP"
38− (break_statement)
39− (continue_statement)
40−] @keyword.control.repeat
41−(for_statement "END" @keyword.control.repeat)
11+(keyword_definition (name) @function)
12+(keyword_definition (body (keyword_setting) @keyword))
4213
43−"WHILE" @keyword.control.repeat
44−(while_statement "END" @keyword.control.repeat)
14+(test_case_definition (name) @property)
4515
46−[
47− "IF"
48− "ELSE IF"
49−] @keyword.control.conditional
50−(if_statement "END" @keyword.control.conditional)
51−(if_statement (else_statement "ELSE" @keyword.control.conditional))
16+(keyword_invocation (keyword) @function)
5217
53−[
54− "TRY"
55− "EXCEPT"
56− "FINALLY"
57−] @keyword.control.exception
58−(try_statement "END" @keyword.control.exception)
59−(try_statement (else_statement "ELSE" @keyword.control.exception))
18+(argument (text_chunk) @string)
19+(argument (scalar_variable) @string.special)
20+(argument (list_variable) @string.special)
21+(argument (dictionary_variable) @string.special)
runtime/queries/ron/highlights.scm+1−43
@@ -1,43 +1 @@
1−; Literals
2−;------------
3−
4−(string) @string
5−(boolean) @constant.builtin.boolean
6−(integer) @constant.numeric.integer
7−(float) @constant.numeric.float
8−(char) @constant.character
9−
10−; Structs
11−;------------
12−
13−(enum_variant) @type.enum.variant
14−(struct_entry (_) @variable.other.member ":")
15−(struct_name (identifier)) @type
16−
17−
18−
19−
20−; Comments
21−;------------
22−
23−(line_comment) @comment.line
24−(block_comment) @comment.block
25−
26−
27−; Punctuation
28−;------------
29−
30−"," @punctuation.delimiter
31−":" @punctuation.delimiter
32−
33−"(" @punctuation.bracket
34−")" @punctuation.bracket
35−"[" @punctuation.bracket
36−"]" @punctuation.bracket
37−"{" @punctuation.bracket
38−"}" @punctuation.bracket
39−
40−
41−; Special
42−;------------
43−(escape_sequence) @constant.character.escape
1+; inherits: rust
runtime/queries/ron/indents.scm+1−12
@@ -1,12 +1 @@
1−[
2− (array)
3− (map)
4− (tuple)
5− (struct)
6−] @indent
7−
8−[
9− "}"
10− "]"
11− ")"
12−] @outdent
1+; inherits: rust
runtime/queries/ron/injections.scm+1−2
@@ -1,2 +1 @@
1−([(line_comment) (block_comment)] @injection.content
2− (#set! injection.language "comment"))
1+; inherits: rust
runtime/queries/rust/highlights.scm−7
@@ -9,13 +9,6 @@
99; Types
1010; -------
1111
12−(type_parameters
13− (type_identifier) @type.parameter)
14−(constrained_type_parameter
15− left: (type_identifier) @type.parameter)
16−(optional_type_parameter
17− name: (type_identifier) @type.parameter)
18−
1912; ---
2013; Primitives
2114; ---
runtime/queries/rust/indents.scm+2−69
@@ -14,11 +14,9 @@
1414 (call_expression)
1515 (binary_expression)
1616 (field_expression)
17− (await_expression)
1817 (tuple_expression)
1918 (array_expression)
2019 (where_clause)
21− (type_cast_expression)
2220
2321 (token_tree)
2422 (macro_definition)
@@ -50,16 +48,10 @@
5048 (#set! "scope" "all")
5149)
5250(let_declaration
53− "let" @expr-start
54− value: (_) @indent
55− alternative: (_)? @indent
56− (#not-same-line? @indent @expr-start)
57− (#set! "scope" "all")
58−)
59−(let_condition
6051 .
6152 (_) @expr-start
6253 value: (_) @indent
54+ alternative: (_)? @indent
6355 (#not-same-line? @indent @expr-start)
6456 (#set! "scope" "all")
6557)
@@ -77,22 +69,6 @@
7769 (#not-same-line? @indent @expr-start)
7870 (#set! "scope" "all")
7971)
80−(field_pattern
81− .
82− (_) @expr-start
83− pattern: (_) @indent
84− (#not-same-line? @indent @expr-start)
85− (#set! "scope" "all")
86−)
87−; Indent type aliases that span multiple lines, similar to
88−; regular assignment expressions
89−(type_item
90− .
91− (_) @expr-start
92− type: (_) @indent
93− (#not-same-line? @indent @expr-start)
94− (#set! "scope" "all")
95−)
9672
9773; Some field expressions where the left part is a multiline expression are not
9874; indented by cargo fmt.
@@ -101,48 +77,5 @@
10177(field_expression
10278 value: (_) @val
10379 "." @outdent
104− ; Check whether the first line ends with `(`, `{` or `[` (up to whitespace).
105− (#match? @val "(\\A[^\\n\\r]+(\\(|\\{|\\[)[\\t ]*(\\n|\\r))")
106−)
107−; Same as above, but with an additional `call_expression`. This is required since otherwise
108−; the arguments of the function call won't be outdented.
109−(call_expression
110− function: (field_expression
111− value: (_) @val
112− "." @outdent
113− (#match? @val "(\\A[^\\n\\r]+(\\(|\\{|\\[)[\\t ]*(\\n|\\r))")
114− )
115− arguments: (_) @outdent
116−)
117−
118−
119−; Indent if guards in patterns.
120−; Since the tree-sitter grammar doesn't create a node for the if expression,
121−; it's not possible to do this correctly in all cases. Indenting the tail of the
122−; whole pattern whenever it contains an `if` only fails if the `if` appears after
123−; the second line of the pattern (which should only rarely be the case)
124−(match_pattern
125− .
126− (_) @expr-start
127− "if" @pattern-guard
128− (#not-same-line? @expr-start @pattern-guard)
129−) @indent
130−
131−; Align closure parameters if they span more than one line
132−(closure_parameters
133− "|"
134− .
135− (_) @anchor
136− (_) @expr-end
137− .
138− (#not-same-line? @anchor @expr-end)
139−) @align
140−
141−(for_expression
142− "in" @in
143− .
144− (_) @indent
145− (#not-same-line? @in @indent)
146− (#set! "scope" "all")
80+ (#match? @val "(\\A[^\\n\\r]+\\([\\t ]*(\\n|\\r).*)|(\\A[^\\n\\r]*\\{[\\t ]*(\\n|\\r))")
14781)
148−
runtime/queries/rust/injections.scm−6
@@ -1,12 +1,6 @@
11([(line_comment) (block_comment)] @injection.content
22 (#set! injection.language "comment"))
33
4−((macro_invocation
5− macro: (identifier) @_html (#eq? @_html "html")
6− (token_tree) @injection.content)
7− (#set! injection.language "html")
8− (#set! injection.include-children))
9−
104((macro_invocation
115 (token_tree) @injection.content)
126 (#set! injection.language "rust")
runtime/queries/rust/locals.scm+1−14
@@ -2,12 +2,6 @@
22
33[
44 (function_item)
5− (struct_item)
6− (enum_item)
7− (union_item)
8− (type_item)
9− (trait_item)
10− (impl_item)
115 (closure_expression)
126 (block)
137] @local.scope
@@ -17,15 +11,8 @@
1711(parameter
1812 (identifier) @local.definition)
1913
20−(type_parameters
21− (type_identifier) @local.definition)
22−(constrained_type_parameter
23− left: (type_identifier) @local.definition)
24−(optional_type_parameter
25− name: (type_identifier) @local.definition)
26−
2714(closure_parameters (identifier) @local.definition)
2815
2916; References
3017(identifier) @local.reference
31−(type_identifier) @local.reference
18+
runtime/queries/rust/textobjects.scm+1−4
@@ -1,8 +1,5 @@
11(function_item
2− body: (_) @function.inside) @function.around
3−
4−(closure_expression
5− body: (_) @function.inside) @function.around
2+ body: (_) @function.inside) @function.around(closure_expression body: (_) @function.inside) @function.around
63
74(struct_item
85 body: (_) @class.inside) @class.around
runtime/queries/scheme/highlights.scm−5
@@ -97,8 +97,3 @@
9797
9898["(" ")" "[" "]" "{" "}"] @punctuation.bracket
9999
100−(quote "'") @operator
101−(unquote_splicing ",@") @operator
102−(unquote ",") @operator
103−(quasiquote "`") @operator
104−
runtime/queries/scheme/indents.scmdeleted−43
@@ -1,43 +0,0 @@
1−; This roughly follows the description at: https://github.com/ds26gte/scmindent#how-subforms-are-indented
2−
3−; Exclude literals in the first patterns, since different rules apply for them.
4−; Similarly, exclude certain keywords (detected by a regular expression).
5−; If a list has 2 elements on the first line, it is aligned to the second element.
6−(list . (_) @first . (_) @anchor
7− (#same-line? @first @anchor)
8− (#set! "scope" "tail")
9− (#not-kind-eq? @first "boolean") (#not-kind-eq? @first "character") (#not-kind-eq? @first "string") (#not-kind-eq? @first "number")
10− (#not-match? @first "def.*|let.*|set!")) @align
11−; If the first element in a list is also a list and on a line by itself, the outer list is aligned to it
12−(list . (list) @anchor .
13− (#set! "scope" "tail")
14− (#not-kind-eq? @first "boolean") (#not-kind-eq? @first "character") (#not-kind-eq? @first "string") (#not-kind-eq? @first "number")) @align
15−(list . (list) @anchor . (_) @second
16− (#not-same-line? @anchor @second)
17− (#set! "scope" "tail")
18− (#not-kind-eq? @first "boolean") (#not-kind-eq? @first "character") (#not-kind-eq? @first "string") (#not-kind-eq? @first "number")
19− (#not-match? @first "def.*|let.*|set!")) @align
20−; If the first element in a list is not a list and on a line by itself, the outer list is aligned to
21−; it plus 1 additional space. This cannot currently be modelled exactly by our indent queries,
22−; but the following is equivalent, assuming that:
23−; - the indent width is 2 (the default for scheme)
24−; - There is no space between the opening parenthesis of the list and the first element
25−(list . (_) @first .
26− (#not-kind-eq? @first "boolean") (#not-kind-eq? @first "character") (#not-kind-eq? @first "string") (#not-kind-eq? @first "number")
27− (#not-match? @first "def.*|let.*|set!")) @indent
28−(list . (_) @first . (_) @second
29− (#not-same-line? @first @second)
30− (#not-kind-eq? @first "boolean") (#not-kind-eq? @first "character") (#not-kind-eq? @first "string") (#not-kind-eq? @first "number")
31− (#not-match? @first "def.*|let.*|set!")) @indent
32−
33−; If the first element in a list is a literal, align the list to it
34−(list . [(boolean) (character) (string) (number)] @anchor
35− (#set! "scope" "tail")) @align
36−
37−; If the first element is among a set of predefined keywords, align the list to this element
38−; plus 1 space (using the same workaround as above for now). This is a simplification since actually
39−; the second line of the list should be indented by 2 spaces more in some cases. Supporting this would
40−; be possible but require significantly more patterns.
41−(list . (symbol) @first
42− (#match? @first "def.*|let.*|set!")) @indent
43−
runtime/queries/slint/highlights.scm+72−118
@@ -1,153 +1,105 @@
11
2−(identifier) @variable
3−[
4− (type_identifier)
5− (units)
6−]@type
2+(user_type_identifier) @type
73
8−(array_literal
9− (identifier) @type)
4+(var_identifier) @variable
105
11−(function_identifier) @function
12−[
13− (image_macro)
14− (children_macro)
15− (radial_grad_macro)
16− (linear_grad_macro)
17−] @function.macro
6+(state_identifier) @variable.other.member
187
19−(call_expression
20− function: (identifier) @function)
21−(call_expression
22− function: (field_expression
23− field: (identifier) @function))
8+(var_identifier
9+ (post_identifier) @variable)
2410
25−(vis) @keyword.control.import
11+(function_identifier) @function
2612
27−(transition_statement state: (identifier) @variable.other.member)
28−(state_expression state: (identifier) @variable.other.member)
29−(struct_block_definition field: (identifier) @variable.other.member)
30−(assign_property (identifier) @attribute)
13+(reference_identifier) @keyword.storage.modifier.ref
14+(visibility_modifier) @keyword.storage.modifier
3115
3216(comment) @comment
3317
34−(string_literal) @string
35−(int_literal) @constant.numeric.integer
36−(float_literal) @constant.numeric.float
37−
38−[
39− "in"
40− "in-out"
41− "for"
42−] @keyword.control.repeat
43−
44−[
45− "import"
46− "export"
47− "from"
48−] @keyword.control.import
49−
50−[
51− "if"
52− "else"
53− "when"
54−] @keyword.control.conditional
55−
56−[
57− "struct"
58− "property"
59−] @keyword.storage.type
60−
61−[
62− "global"
63−] @keyword.storage.modifier
64−
18+(string) @string
19+(int_number) @constant.numeric
20+(unit_type) @type.builtin
6521
6622[
67− "root"
68− "parent"
69− "duration"
70− "easing"
71−] @variable.builtin
72−
73−
74−[
75− "callback"
76− "animate"
77− "states"
78− "out"
79− "transitions"
80− "component"
81− "inherits"
23+"struct"
24+"property"
25+"callback"
26+"import"
27+"from"
28+"root"
29+"parent"
30+"this"
31+"for"
32+"in"
33+"if"
34+"else if"
35+"else"
36+"animate"
37+"states"
38+"when"
39+"in"
40+"out"
41+"transitions"
42+"global"
8243] @keyword
8344
8445[
85− "black"
86− "transparent"
87− "blue"
88− "ease"
89− "ease_in"
90− "ease-in"
91− "ease_in_out"
92− "ease-in-out"
93− "ease_out"
94− "ease-out"
95− "end"
96− "green"
97− "red"
98− "start"
99− "yellow"
100− "white"
101− "gray"
46+ "black"
47+ "transparent"
48+ "blue"
49+ "ease"
50+ "ease_in"
51+ "ease-in"
52+ "ease_in_out"
53+ "ease-in-out"
54+ "ease_out"
55+ "ease-out"
56+ "end"
57+ "green"
58+ "red"
59+ "red"
60+ "start"
61+ "yellow"
62+ "true"
63+ "false"
10264 ] @constant.builtin
10365
104−[
105− "true"
106− "false"
107−] @constant.builtin.boolean
108−
10966"@" @keyword
11067
11168; ; Punctuation
11269[
11370 ","
11471 "."
115− ";"
116− ":"
11772] @punctuation.delimiter
11873
11974; ; Brackets
12075[
121− "("
122− ")"
123− "["
124− "]"
125− "{"
126− "}"
76+"("
77+")"
78+"["
79+"]"
80+"{"
81+"}"
12782] @punctuation.bracket
12883
129−(define_property ["<" ">"] @punctuation.bracket)
130−
13184[
132− "angle"
133− "bool"
134− "brush"
135− "color"
136− "duration"
137− "easing"
138− "float"
139− "image"
140− "int"
141− "length"
142− "percent"
143− "physical-length"
144− "physical_length"
145− "string"
85+"angle"
86+"bool"
87+"brush"
88+; "color" // This causes problems
89+"duration"
90+"easing"
91+"float"
92+"image"
93+"int"
94+"length"
95+"percent"
96+"physical-length"
97+"physical_length"
98+"string"
14699] @type.builtin
147100
148101[
149102 ":="
150− "<=>"
151103 "!"
152104 "-"
153105 "+"
@@ -166,6 +118,8 @@
166118 "*="
167119 "/="
168120 "?"
169− "=>" ] @operator
121+
122+ "=>"
123+ ] @operator
170124
171125(ternary_expression [":" "?"] @keyword.control.conditional)
runtime/queries/slint/indents.scm+5−6
@@ -1,12 +1,11 @@
11[
2− (comp_body)
3− (state_statement)
4− (transition_statement)
5− (handler_body)
6− (consequence_body)
7− (global_single)
2+ (field_declaration_list_body)
3+ (list_definition_body)
4+ (struct_field_declaration_list_body)
85] @indent
96
107[
118 "}"
9+ "]"
10+ ")"
1211] @outdent
runtime/queries/slint/injections.scmdeleted−2
@@ -1,2 +0,0 @@
1−((comment) @injection.content
2− (#set! injection.language "comment"))
runtime/queries/slint/locals.scm+1−1
@@ -1,3 +1,3 @@
11; locals.scm
22
3−(component_item) @local.scope
3+(component_definition) @local.scope
runtime/queries/smali/folds.scmdeleted−12
@@ -1,12 +0,0 @@
1−[
2− (annotation_directive)
3− (array_data_directive)
4− (field_definition)
5− (method_definition)
6− (packed_switch_directive)
7− (param_directive)
8− (parameter_directive)
9− (sparse_switch_directive)
10− (subannotation_directive)
11− (list)
12−] @fold
runtime/queries/smali/highlights.scmdeleted−216
@@ -1,216 +0,0 @@
1−; Types
2−
3−(class_identifier
4− (identifier) @type)
5−
6−(primitive_type) @type.builtin
7−
8−((class_identifier
9− . (identifier) @_first @type.builtin
10− (identifier) @type.builtin)
11− (#match? @_first "^(android|dalvik|java|kotlinx)$"))
12−
13−((class_identifier
14− . (identifier) @_first @type.builtin
15− . (identifier) @_second @type.builtin
16− (identifier) @type.builtin)
17− (#eq? @_first "com")
18− (#match? @_second "^(android|google)$"))
19−
20−; Methods
21−
22−(method_definition
23− (method_signature (method_identifier) @function.method))
24−
25−(expression
26− (opcode) @_invoke
27− (body
28− (full_method_signature
29− (method_signature (method_identifier) @function.method)))
30− (#match? @_invoke "^invoke"))
31−
32−(expression
33− (opcode) @_field_access
34− (body
35− (field_identifier) @variable.other.member)
36− (#match? @_field_access "^[is](get|put)-"))
37−
38−(method_handle
39− (full_method_signature
40− (method_signature (method_identifier) @function.method)))
41−
42−(custom_invoke
43− . (identifier) @function.method
44− (method_signature (method_identifier) @function.method))
45−
46−(annotation_value
47− (body
48− (method_signature (method_identifier) @function.method)))
49−
50−(annotation_value
51− (body
52− (full_method_signature
53− (method_signature (method_identifier) @function.method))))
54−
55−(field_definition
56− (body
57− (method_signature (method_identifier) @function.method)))
58−
59−(field_definition
60− (body
61− (full_method_signature
62− (method_signature (method_identifier) @function.method))))
63−
64−((method_identifier) @constructor
65− (#match? @constructor "^(<init>|<clinit>)$"))
66−
67−"constructor" @constructor
68−
69−; Fields
70−
71−[
72− (field_identifier)
73− (annotation_key)
74−] @variable.other.member
75−
76−((field_identifier) @constant
77− (#match? @constant "^[%u_]*$"))
78−
79−; Variables
80−
81−(variable) @variable.builtin
82−
83−(local_directive
84− (identifier) @variable)
85−
86−; Parameters
87−
88−(parameter) @variable.parameter
89−(param_identifier) @variable.parameter
90−
91−; Labels
92−
93−[
94− (label)
95− (jmp_label)
96−] @label
97−
98−; Operators
99−
100−; (opcode) @keyword.operator
101−
102−((opcode) @keyword.control.return
103− (#match? @keyword.control.return "^return"))
104−
105−((opcode) @keyword.control.conditional
106− (#match? @keyword.control.conditional "^if"))
107−
108−((opcode) @keyword.control.conditional
109− (#match? @keyword.control.conditional "^cmp"))
110−
111−((opcode) @keyword.control.exception
112− (#match? @keyword.control.exception "^throw"))
113−
114−[
115− "="
116− ".."
117−] @operator
118−
119−; Keywords
120−
121−[
122− ".class"
123− ".super"
124− ".implements"
125− ".field"
126− ".end field"
127− ".annotation"
128− ".end annotation"
129− ".subannotation"
130− ".end subannotation"
131− ".param"
132− ".end param"
133− ".parameter"
134− ".end parameter"
135− ".local"
136− ".end local"
137− ".restart local"
138− ".registers"
139− ".packed-switch"
140− ".end packed-switch"
141− ".sparse-switch"
142− ".end sparse-switch"
143− ".array-data"
144− ".end array-data"
145− ".enum"
146− (prologue_directive)
147− (epilogue_directive)
148−] @keyword
149−
150−[
151− ".source"
152−] @keyword.directive
153−
154−[
155− ".method"
156− ".end method"
157−] @keyword.function
158−
159−[
160− ".catch"
161− ".catchall"
162−] @keyword.control.exception
163−
164−; Literals
165−
166−(string) @string
167−(source_directive (string "\"" _ @string.special.url "\""))
168−(escape_sequence) @constant.character.escape
169−
170−(character) @constant.character
171−
172−"L" @punctuation
173−
174−(line_directive (number) @comment) @comment
175−(".locals" (number) @comment) @comment
176−
177−(number) @constant.numeric.integer
178−
179−[
180− (float)
181− (NaN)
182− (Infinity)
183−] @constant.numeric.float
184−
185−(boolean) @constant.builtin.boolean
186−
187−(null) @constant.builtin
188−
189−; Misc
190−
191−(annotation_visibility) @keyword.storage.modifier
192−
193−(access_modifier) @keyword.storage.type
194−
195−(array_type
196− "[" @punctuation.special)
197−
198−["{" "}"] @punctuation.bracket
199−
200−["(" ")"] @punctuation.bracket
201−
202−[
203− "->"
204− ","
205− ":"
206− ";"
207− "@"
208− "/"
209−] @punctuation.delimiter
210−
211−; Comments
212−
213−(comment) @comment
214−
215−(class_definition
216− (comment) @comment.block.documentation)
runtime/queries/smali/indents.scmdeleted−31
@@ -1,31 +0,0 @@
1−[
2− (annotation_directive)
3− (array_data_directive)
4− (field_definition)
5− (method_definition)
6− (packed_switch_directive)
7− (param_directive)
8− (parameter_directive)
9− (sparse_switch_directive)
10− (subannotation_directive)
11− (list)
12− "\{"
13−] @indent
14−
15−[
16− ".end annotation"
17− ".end array-data"
18− ".end field"
19− ".end method"
20− ".end packed-switch"
21− ".end param"
22− ".end parameter"
23− ".end sparse-switch"
24− ".end subannotation"
25− "\}"
26−] @outdent
27−
28−[
29− (ERROR)
30− (comment)
31−] @indent.always
runtime/queries/smali/injections.scmdeleted−2
@@ -1,2 +0,0 @@
1−((comment) @injection.content
2− (#set! injection.language "comment"))
runtime/queries/smali/locals.scmdeleted−42
@@ -1,42 +0,0 @@
1−[
2− (class_directive)
3− (expression)
4− (annotation_directive)
5− (array_data_directive)
6− (method_definition)
7− (packed_switch_directive)
8− (sparse_switch_directive)
9− (subannotation_directive)
10−] @local.scope
11−
12−[
13− (identifier)
14− (class_identifier)
15− (label)
16− (jmp_label)
17−] @local.reference
18−
19−(enum_reference
20− (field_identifier) @local.definition)
21−
22−((field_definition
23− (access_modifiers) @_mod
24− (field_identifier) @local.definition)
25− (#eq? @_mod "enum"))
26−
27−(field_definition
28− (field_identifier) @local.definition
29− (field_type) @local.definition)
30−
31−(annotation_key) @local.definition
32−
33−(method_definition
34− (method_signature (method_identifier) @local.definition))
35−
36−(param_identifier) @local.definition
37−
38−(annotation_directive
39− (class_identifier) @local.definition)
40−
41−(class_directive
42− (class_identifier) @local.definition)
runtime/queries/sql/highlights.scm+231−317
@@ -1,169 +1,134 @@
1−(invocation
2− (object_reference
3− name: (identifier) @function.method))
41
52[
6− (keyword_gist)
73 (keyword_btree)
84 (keyword_hash)
5+ (keyword_gist)
96 (keyword_spgist)
107 (keyword_gin)
118 (keyword_brin)
12− (keyword_array)
13−] @function.builtin
149
15−(object_reference
16− name: (identifier) @variable.other.member)
10+ (cast)
11+ (group_concat)
12+ (invocation)
13+] @function.builtin
14+
15+(table_reference
16+ name: (identifier) @namespace)
1717
1818(relation
19− alias: (identifier) @variable.parameter)
20−
19+ table_alias: (identifier) @variable.parameter)
20+
2121(field
2222 name: (identifier) @variable.other.member)
23+
24+(field
25+ table_alias: (identifier) @variable.parameter
26+ name: (identifier) @variable.other.member)
2327
24−(term
25− alias: (identifier) @variable.parameter)
26−
27−(term
28− value: (cast
29− name: (keyword_cast) @function.builtin
30− parameter: [(literal)]?))
28+(comment) @comment
3129
32−(literal) @string
33−(comment) @comment.line
34−(marginalia) @comment.block
30+[
31+ "("
32+ ")"
33+] @punctuation.bracket
3534
36−((literal) @constant.numeric.integer
37− (#match? @constant.numeric.integer "^-?\\d+$"))
35+[
36+ ";"
37+ ","
38+ "."
39+] @punctuation.delimiter
3840
39−((literal) @constant.numeric.float
40− (#match? @constant.numeric.float "^-?\\d*\\.\\d*$"))
41+(binary_expression
42+ operator: _ @operator)
4143
42−(parameter) @variable.parameter
44+(unary_expression
45+ operator: _ @operator)
4346
44−[
45− (keyword_true)
46− (keyword_false)
47−] @constant.builtin.boolean
47+(all_fields) @special
4848
4949[
50− (keyword_asc)
51− (keyword_desc)
52− (keyword_terminated)
53− (keyword_escaped)
54− (keyword_unsigned)
55− (keyword_nulls)
56− (keyword_last)
57− (keyword_delimited)
58− (keyword_replication)
59− (keyword_auto_increment)
60− (keyword_default)
61− (keyword_collate)
62− (keyword_concurrently)
63− (keyword_engine)
64− (keyword_always)
65− (keyword_generated)
66− (keyword_preceding)
67− (keyword_following)
68− (keyword_first)
69− (keyword_current_timestamp)
70− (keyword_immutable)
71− (keyword_atomic)
72− (keyword_parallel)
73− (keyword_leakproof)
74− (keyword_safe)
75− (keyword_cost)
76− (keyword_strict)
77−] @attribute
50+ (keyword_null)
51+ (keyword_true)
52+ (keyword_false)
53+] @constant.builtin
7854
79−[
80− (keyword_materialized)
81− (keyword_recursive)
82− (keyword_temp)
83− (keyword_temporary)
84− (keyword_unlogged)
85− (keyword_external)
86− (keyword_parquet)
87− (keyword_csv)
88− (keyword_rcfile)
89− (keyword_textfile)
90− (keyword_orc)
91− (keyword_avro)
92− (keyword_jsonfile)
93− (keyword_sequencefile)
94− (keyword_volatile)
95−] @keyword.storage.type
55+((literal) @constant.numeric
56+ (#match? @constant.numeric "^-?\\d*\\.?\\d*$"))
9657
97−[
98− (keyword_case)
99− (keyword_when)
100− (keyword_then)
101− (keyword_else)
102−] @keyword.control.conditional
58+(literal) @string
10359
10460[
10561 (keyword_select)
106− (keyword_from)
107− (keyword_where)
108− (keyword_index)
109− (keyword_join)
110− (keyword_primary)
11162 (keyword_delete)
112− (keyword_create)
11363 (keyword_insert)
114− (keyword_merge)
115− (keyword_distinct)
11664 (keyword_replace)
11765 (keyword_update)
11866 (keyword_into)
11967 (keyword_overwrite)
120− (keyword_matched)
12168 (keyword_values)
122− (keyword_value)
123− (keyword_attribute)
12469 (keyword_set)
70+ (keyword_from)
12571 (keyword_left)
12672 (keyword_right)
127− (keyword_outer)
12873 (keyword_inner)
12974 (keyword_full)
75+ (keyword_outer)
76+ (keyword_cross)
77+ (keyword_join)
78+ (keyword_lateral)
79+ (keyword_on)
80+ (keyword_not)
13081 (keyword_order)
131− (keyword_partition)
13282 (keyword_group)
133− (keyword_with)
134− (keyword_without)
135− (keyword_as)
83+ (keyword_partition)
84+ (keyword_by)
13685 (keyword_having)
86+ (keyword_desc)
87+ (keyword_asc)
13788 (keyword_limit)
13889 (keyword_offset)
90+ (keyword_primary)
91+ (keyword_create)
92+ (keyword_alter)
93+ (keyword_change)
94+ (keyword_analyze)
95+ (keyword_modify)
96+ (keyword_drop)
97+ (keyword_add)
13998 (keyword_table)
14099 (keyword_tables)
100+ (keyword_view)
101+ (keyword_materialized)
102+ (keyword_column)
141103 (keyword_key)
142− (keyword_references)
143− (keyword_foreign)
104+ (keyword_as)
105+ (keyword_distinct)
144106 (keyword_constraint)
145− (keyword_force)
146− (keyword_use)
147− (keyword_for)
148− (keyword_if)
149− (keyword_exists)
107+ ; (keyword_cast)
108+ ; (keyword_group_concat)
109+ (keyword_separator)
150110 (keyword_max)
151111 (keyword_min)
152112 (keyword_avg)
153− (keyword_column)
154− (keyword_columns)
155− (keyword_cross)
156− (keyword_lateral)
157− (keyword_natural)
158− (keyword_alter)
159− (keyword_drop)
160− (keyword_add)
161− (keyword_view)
162113 (keyword_end)
163− (keyword_is)
114+ (keyword_force)
115+ (keyword_ignore)
164116 (keyword_using)
165− (keyword_between)
166− (keyword_window)
117+ (keyword_use)
118+ (keyword_index)
119+ (keyword_for)
120+ (keyword_if)
121+ (keyword_exists)
122+ (keyword_auto_increment)
123+ (keyword_generated)
124+ (keyword_always)
125+ (keyword_collate)
126+ (keyword_character)
127+ (keyword_engine)
128+ (keyword_default)
129+ (keyword_cascade)
130+ (keyword_restrict)
131+ (keyword_with)
167132 (keyword_no)
168133 (keyword_data)
169134 (keyword_type)
@@ -171,259 +136,208 @@
171136 (keyword_to)
172137 (keyword_schema)
173138 (keyword_owner)
174− (keyword_authorization)
139+ (keyword_temp)
140+ (keyword_temporary)
141+ (keyword_unlogged)
142+ (keyword_union)
175143 (keyword_all)
176144 (keyword_any)
177145 (keyword_some)
146+ (keyword_except)
147+ (keyword_intersect)
178148 (keyword_returning)
179149 (keyword_begin)
180150 (keyword_commit)
181151 (keyword_rollback)
182152 (keyword_transaction)
183− (keyword_only)
184− (keyword_like)
185− (keyword_similar)
186153 (keyword_over)
187− (keyword_change)
188− (keyword_modify)
154+ (keyword_nulls)
155+ (keyword_first)
189156 (keyword_after)
190− (keyword_before)
157+ (keyword_last)
158+ (keyword_window)
191159 (keyword_range)
192160 (keyword_rows)
193161 (keyword_groups)
162+ (keyword_between)
163+ (keyword_unbounded)
164+ (keyword_preceding)
165+ (keyword_following)
194166 (keyword_exclude)
195167 (keyword_current)
168+ (keyword_row)
196169 (keyword_ties)
197170 (keyword_others)
171+ (keyword_only)
172+ (keyword_unique)
173+ (keyword_foreign)
174+ (keyword_references)
175+ (keyword_concurrently)
176+ ; (keyword_btree)
177+ ; (keyword_hash)
178+ ; (keyword_gist)
179+ ; (keyword_spgist)
180+ ; (keyword_gin)
181+ ; (keyword_brin)
182+ (keyword_like)
183+ (keyword_similar)
198184 (keyword_preserve)
185+ (keyword_unsigned)
199186 (keyword_zerofill)
200− (keyword_format)
201− (keyword_fields)
202− (keyword_row)
203− (keyword_sort)
204− (keyword_compute)
205− (keyword_comment)
206− (keyword_location)
207− (keyword_cached)
208− (keyword_uncached)
209− (keyword_lines)
210− (keyword_stored)
211− (keyword_virtual)
212− (keyword_partitioned)
213− (keyword_analyze)
214− (keyword_explain)
215− (keyword_verbose)
216− (keyword_truncate)
217− (keyword_rewrite)
218− (keyword_optimize)
219− (keyword_vacuum)
220− (keyword_cache)
221− (keyword_language)
222− (keyword_sql)
223− (keyword_called)
224187 (keyword_conflict)
225− (keyword_declare)
226− (keyword_filter)
188+ (keyword_do)
189+ (keyword_nothing)
190+ (keyword_high_priority)
191+ (keyword_low_priority)
192+ (keyword_delayed)
193+ (keyword_recursive)
194+ (keyword_cascaded)
195+ (keyword_local)
196+ (keyword_current_timestamp)
197+ (keyword_check)
198+ (keyword_option)
199+ (keyword_vacuum)
200+ (keyword_wait)
201+ (keyword_nowait)
202+
203+ (keyword_trigger)
227204 (keyword_function)
228− (keyword_input)
229− (keyword_name)
230− (keyword_oid)
231− (keyword_oids)
232− (keyword_options)
233− (keyword_plpgsql)
234− (keyword_precision)
235− (keyword_regclass)
236− (keyword_regnamespace)
237− (keyword_regproc)
238− (keyword_regtype)
239− (keyword_restricted)
240− (keyword_return)
241205 (keyword_returns)
242− (keyword_separator)
206+ (keyword_return)
243207 (keyword_setof)
208+ (keyword_atomic)
209+ (keyword_declare)
210+ ; (keyword_language)
211+ (keyword_sql)
212+ (keyword_plpgsql)
213+ (keyword_immutable)
244214 (keyword_stable)
215+ (keyword_volatile)
216+ (keyword_leakproof)
217+ (keyword_parallel)
218+ (keyword_safe)
219+ (keyword_unsafe)
220+ (keyword_restricted)
221+ (keyword_called)
222+ (keyword_returns)
223+ (keyword_input)
224+ (keyword_strict)
225+ (keyword_cost)
226+ (keyword_rows)
245227 (keyword_support)
228+
229+ (keyword_external)
230+ (keyword_stored)
231+ (keyword_cached)
232+ (keyword_uncached)
233+ (keyword_replication)
246234 (keyword_tblproperties)
247− (keyword_trigger)
248− (keyword_unsafe)
249− (keyword_admin)
250− (keyword_connection)
251− (keyword_cycle)
252− (keyword_database)
253− (keyword_encrypted)
254− (keyword_increment)
255− (keyword_logged)
256− (keyword_none)
257− (keyword_owned)
258− (keyword_password)
259− (keyword_reset)
260− (keyword_role)
261− (keyword_sequence)
262− (keyword_start)
263− (keyword_restart)
264− (keyword_tablespace)
265− (keyword_until)
266− (keyword_user)
267− (keyword_valid)
268− (keyword_action)
269− (keyword_definer)
270− (keyword_invoker)
271− (keyword_security)
272− (keyword_extension)
273− (keyword_version)
274− (keyword_out)
275− (keyword_inout)
276− (keyword_variadic)
277− (keyword_session)
278− (keyword_isolation)
279− (keyword_level)
280− (keyword_serializable)
281− (keyword_repeatable)
282− (keyword_read)
283− (keyword_write)
284− (keyword_committed)
285− (keyword_uncommitted)
286− (keyword_deferrable)
287− (keyword_names)
288− (keyword_zone)
289− (keyword_immediate)
290− (keyword_deferred)
291− (keyword_constraints)
292− (keyword_snapshot)
293− (keyword_characteristics)
294− (keyword_off)
295− (keyword_follows)
296− (keyword_precedes)
297− (keyword_each)
298− (keyword_instead)
299− (keyword_of)
300− (keyword_initially)
301− (keyword_old)
302− (keyword_new)
303− (keyword_referencing)
304− (keyword_statement)
305− (keyword_execute)
306− (keyword_procedure)
235+ (keyword_options)
236+ (keyword_compute)
237+ (keyword_stats)
238+ (keyword_statistics)
239+ (keyword_optimize)
240+ (keyword_rewrite)
241+ (keyword_bin_pack)
242+ (keyword_incremental)
243+ (keyword_location)
244+ (keyword_partitioned)
245+ (keyword_comment)
246+ (keyword_sort)
247+ (keyword_format)
248+ (keyword_delimited)
249+ (keyword_fields)
250+ (keyword_terminated)
251+ (keyword_escaped)
252+ (keyword_lines)
253+ (keyword_cache)
254+ (keyword_metadata)
255+ (keyword_noscan)
256+
257+ (keyword_parquet)
258+ (keyword_rcfile)
259+ (keyword_csv)
260+ (keyword_textfile)
261+ (keyword_avro)
262+ (keyword_sequencefile)
263+ (keyword_orc)
264+ (keyword_avro)
265+ (keyword_jsonfile)
266+
267+ (keyword_precision)
268+ (keyword_inet)
307269] @keyword
308270
309271[
310− (keyword_restrict)
311− (keyword_unbounded)
312− (keyword_unique)
313− (keyword_cascade)
314− (keyword_delayed)
315− (keyword_high_priority)
316− (keyword_low_priority)
317− (keyword_ignore)
318− (keyword_nothing)
319− (keyword_check)
320− (keyword_option)
321− (keyword_local)
322− (keyword_cascaded)
323− (keyword_wait)
324− (keyword_nowait)
325− (keyword_metadata)
326− (keyword_incremental)
327− (keyword_bin_pack)
328− (keyword_noscan)
329− (keyword_stats)
330− (keyword_statistics)
331− (keyword_maxvalue)
332− (keyword_minvalue)
333−] @keyword
272+ (keyword_case)
273+ (keyword_when)
274+ (keyword_then)
275+ (keyword_else)
276+ (keyword_where)
277+] @keyword.control.conditional
278+
279+[
280+ (keyword_in)
281+ (keyword_and)
282+ (keyword_or)
283+ (keyword_is)
284+] @keyword.operator
334285
335286[
336− (keyword_int)
337− (keyword_null)
338287 (keyword_boolean)
288+ (bit)
339289 (keyword_binary)
340− (keyword_varbinary)
341− (keyword_image)
342− (keyword_bit)
343− (keyword_inet)
344− (keyword_character)
290+
345291 (keyword_smallserial)
346292 (keyword_serial)
347293 (keyword_bigserial)
348− (keyword_smallint)
349− (keyword_mediumint)
350− (keyword_bigint)
351− (keyword_tinyint)
352− (keyword_decimal)
353− (keyword_float)
354− (keyword_double)
355− (keyword_numeric)
294+
295+ (tinyint)
296+ (smallint)
297+ (mediumint)
298+ (int)
299+ (bigint)
300+ (decimal)
301+ (numeric)
356302 (keyword_real)
357303 (double)
304+ (float)
305+
358306 (keyword_money)
359− (keyword_smallmoney)
360− (keyword_char)
361− (keyword_nchar)
362− (keyword_varchar)
363− (keyword_nvarchar)
364− (keyword_varying)
365− (keyword_text)
307+
308+ (char)
309+ (varchar)
310+ (numeric)
366311 (keyword_string)
312+ (keyword_text)
313+
367314 (keyword_uuid)
315+
368316 (keyword_json)
369317 (keyword_jsonb)
370318 (keyword_xml)
319+
371320 (keyword_bytea)
372− (keyword_enum)
321+ (keyword_inet)
322+
323+ (enum)
324+
373325 (keyword_date)
374326 (keyword_datetime)
375− (keyword_time)
376− (keyword_datetime2)
377− (keyword_datetimeoffset)
378− (keyword_smalldatetime)
379327 (keyword_timestamp)
380328 (keyword_timestamptz)
329+
330+ (keyword_interval)
331+
381332 (keyword_geometry)
382333 (keyword_geography)
383334 (keyword_box2d)
384335 (keyword_box3d)
385− (keyword_interval)
386−] @type.builtin
387336
388−[
389− (keyword_in)
390− (keyword_and)
391− (keyword_or)
392− (keyword_not)
393− (keyword_by)
394− (keyword_on)
395− (keyword_do)
396− (keyword_union)
397− (keyword_except)
398− (keyword_intersect)
399−] @keyword.operator
400−
401−[
402− "+"
403− "-"
404− "*"
405− "/"
406− "%"
407− "^"
408− ":="
409− "="
410− "<"
411− "<="
412− "!="
413− ">="
414− ">"
415− "<>"
416− (op_other)
417− (op_unary_other)
418−] @operator
419−
420−[
421− "("
422− ")"
423−] @punctuation.bracket
424−
425−[
426− ";"
427− ","
428− "."
429−] @punctuation.delimiter
337+ (keyword_oid)
338+ (keyword_name)
339+ (keyword_regclass)
340+ (keyword_regnamespace)
341+ (keyword_regproc)
342+ (keyword_regtype)
343+] @type.builtin
runtime/queries/strace/highlights.scmdeleted−8
@@ -1,8 +0,0 @@
1−(syscall) @function
2−(integer) @constant.numeric
3−(pointer) @constant.numeric
4−(value) @label
5−(string) @string
6−(comment) @comment
7−(errorName) @error
8−(errorDescription) @error
runtime/queries/templ/highlights.scmdeleted−99
@@ -1,99 +0,0 @@
1−(package_identifier) @namespace
2−
3−(parameter_declaration (identifier) @variable.parameter)
4−(variadic_parameter_declaration (identifier) @variable.parameter)
5−
6−(function_declaration
7− name: (identifier) @function)
8−
9−(type_spec name: (type_identifier) @type)
10−(type_identifier) @type
11−(field_identifier) @variable.other.member
12−(identifier) @variable
13−
14−; Function calls
15−
16−(call_expression
17− function: (identifier) @function)
18−
19−(call_expression
20− function: (selector_expression
21− field: (field_identifier) @function))
22−
23−;
24−; These are Templ specific
25−;
26−
27−(component_declaration
28− name: (component_identifier) @function)
29−
30−(tag_start) @tag
31−(tag_end) @tag
32−(self_closing_tag) @tag
33−(style_element) @tag
34−
35−(attribute
36− name: (attribute_name) @attribute)
37−(attribute
38− value: (quoted_attribute_value) @string)
39−
40−(element_text) @string.special
41−(style_element_text) @string.special
42−
43−(css_property
44− name: (css_property_name) @attribute)
45−
46−(expression) @function.method
47−(dynamic_class_attribute_value) @function.method
48−
49−(component_import
50− name: (component_identifier) @function)
51−
52−(component_render) @function
53−
54−[
55− "@"
56−] @operator
57−
58−[
59− "func"
60− "var"
61− "const"
62− "templ"
63− "css"
64− "type"
65− "struct"
66− "range"
67− "script"
68−] @keyword.storage.type
69−
70−[
71− "return"
72−] @keyword.control.return
73−
74−[
75− "import"
76− "package"
77−] @keyword.control.import
78−
79−[
80− "else"
81− "case"
82− "switch"
83− "if"
84− "default"
85−] @keyword.control.conditional
86−
87−"for" @keyword.control.repeat
88−
89−[
90− (interpreted_string_literal)
91− (raw_string_literal)
92− (rune_literal)
93−] @string
94−
95−; Comments
96−
97−(comment) @comment
98−
99−(element_comment) @comment
runtime/queries/templ/injections.scmdeleted−4
@@ -1,4 +0,0 @@
1−((script_block_text) @injection.content (#set! injection.language "javascript"))
2−((script_element_text) @injection.content (#set! injection.language "javascript"))
3−
4−((style_element_text) @injection.content (#set! injection.language "css"))
runtime/queries/typst/highlights.scmdeleted−77
@@ -1,77 +0,0 @@
1−(call
2− item: (ident) @function)
3−(call
4− item: (field field: (ident) @function.method))
5−(tagged field: (ident) @tag)
6−(field field: (ident) @tag)
7−(comment) @comment
8−
9−; CONTROL
10−(let "let" @keyword.storage.type)
11−(branch ["if" "else"] @keyword.control.conditional)
12−(while "while" @keyword.control.repeat)
13−(for ["for" "in"] @keyword.control.repeat)
14−(import "import" @keyword.control.import)
15−(as "as" @keyword.operator)
16−(include "include" @keyword.control.import)
17−(show "show" @keyword.control)
18−(set "set" @keyword.control)
19−(return "return" @keyword.control)
20−(flow ["break" "continue"] @keyword.control)
21−
22−; OPERATOR
23−(in ["in" "not"] @keyword.operator)
24−(and "and" @keyword.operator)
25−(or "or" @keyword.operator)
26−(not "not" @keyword.operator)
27−(sign ["+" "-"] @operator)
28−(add "+" @operator)
29−(sub "-" @operator)
30−(mul "*" @operator)
31−(div "/" @operator)
32−(cmp ["==" "<=" ">=" "!=" "<" ">"] @operator)
33−(fraction "/" @operator)
34−(fac "!" @operator)
35−(attach ["^" "_"] @operator)
36−(wildcard) @operator
37−
38−; VALUE
39−(raw_blck "```" @operator) @markup.raw.block
40−(raw_span "`" @operator) @markup.raw.block
41−(raw_blck lang: (ident) @tag)
42−(label) @tag
43−(ref) @tag
44−(number) @constant.numeric
45−(string) @string
46−(content ["[" "]"] @operator)
47−(bool) @constant.builtin.boolean
48−(builtin) @constant.builtin
49−(none) @constant.builtin
50−(auto) @constant.builtin
51−(ident) @variable
52−(call
53− item: (builtin) @function.builtin)
54−
55−; MARKUP
56−(item "-" @markup.list)
57−(term ["/" ":"] @markup.list)
58−(heading ["=" "==" "===" "====" "====="] @markup.heading.marker) @markup.heading
59−(url) @tag
60−(emph) @markup.italic
61−(strong) @markup.bold
62−(symbol) @constant.character
63−(shorthand) @constant.builtin
64−(quote) @markup.quote
65−(align) @operator
66−(letter) @constant.character
67−(linebreak) @constant.builtin
68−
69−(math "$" @operator)
70−"#" @operator
71−"end" @operator
72−
73−(escape) @constant.character.escape
74−["(" ")" "{" "}"] @punctuation.bracket
75−["," ";" ".." ":" "sep"] @punctuation.delimiter
76−"assign" @punctuation
77−(field "." @punctuation)
runtime/queries/typst/injections.scmdeleted−6
@@ -1,6 +0,0 @@
1−(raw_blck
2− (blob) @injection.shebang @injection.content)
3−
4−(raw_blck
5− lang: (ident) @injection.language
6− (blob) @injection.content)
runtime/queries/unison/highlights.scm+6−21
@@ -10,18 +10,14 @@
1010[
1111 (kw_forall)
1212 (unique_kw)
13− (structural_kw)
1413 (type_kw)
1514 (kw_equals)
1615 (do)
17− (ability)
18− (where)
1916] @keyword
2017
2118(kw_let) @keyword.function
2219(type_kw) @keyword.storage.type
2320(unique) @keyword.storage.modifier
24−(structural) @keyword.storage.modifier
2521("use") @keyword.control.import
2622
2723
@@ -35,7 +31,6 @@
3531 (arrow_symbol)
3632 (">")
3733 (or)
38− (and)
3934 (bang)
4035] @operator
4136
@@ -52,22 +47,13 @@
5247
5348;; Types
5449(record_field name: (wordy_id) @variable.other.member type: (wordy_id) @type)
55−(type_constructor (type_name (wordy_id) @constructor))
56−(ability_declaration type_name: (wordy_id) @type type_arg: (wordy_id) @variable.parameter)
57−(effect (wordy_id) @special) ;; NOTE: an effect is just like a type, but in signature we special case it
58−
59−;; Namespaces
60−(path) @namespace
61−(namespace) @namespace
62−
63−;; Terms
64−(type_signature term_name: (path)? @variable term_name: (wordy_id) @variable)
65−(type_signature (wordy_id) @type)
66−(type_signature (delayed (wordy_id)) @type)
67−
68−(term_definition param: (wordy_id) @variable.parameter)
50+[
51+ (type_name)
52+ (type_signature)
53+ (effect)
54+] @type
6955
70−(function_application function_name: (path)? function_name: (wordy_id) @function)
56+(term_definition) @variable
7157
7258;; Punctuation
7359[
@@ -84,4 +70,3 @@
8470 "]"
8571] @punctuation.bracket
8672
87−(test_watch_expression (wordy_id) @keyword.directive)
runtime/queries/yaml/injections.scm−52
@@ -1,54 +1,2 @@
11((comment) @injection.content
22 (#set! injection.language "comment"))
3−
4−; The remaining code in this file incorporates work covered by the following
5−; copyright and permission notice:
6−;
7−; Copyright 2023 the nvim-treesitter authors
8−;
9−; Licensed under the Apache License, Version 2.0 (the "License");
10−; you may not use this file except in compliance with the License.
11−; You may obtain a copy of the License at
12−;
13−; http://www.apache.org/licenses/LICENSE-2.0
14−;
15−; Unless required by applicable law or agreed to in writing, software
16−; distributed under the License is distributed on an "AS IS" BASIS,
17−; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18−; See the License for the specific language governing permissions and
19−; limitations under the License.
20−
21−; Modified for Helix from https://github.com/nvim-treesitter/nvim-treesitter/blob/master/queries/yaml/injections.scm
22−
23−;; Github actions ("run") / Gitlab CI ("scripts")
24−(block_mapping_pair
25− key: (flow_node) @_run (#match? @_run "^(run|script|before_script|after_script)$")
26− value: (flow_node
27− (plain_scalar
28− (string_scalar) @injection.content)
29− (#set! injection.language "bash")))
30−
31−(block_mapping_pair
32− key: (flow_node) @_run (#match? @_run "^(run|script|before_script|after_script)$")
33− value: (block_node
34− (block_scalar) @injection.content
35− (#set! injection.language "bash")))
36−
37−(block_mapping_pair
38− key: (flow_node) @_run (#match? @_run "^(run|script|before_script|after_script)$")
39− value: (block_node
40− (block_sequence
41− (block_sequence_item
42− (flow_node
43− (plain_scalar
44− (string_scalar) @injection.content))
45− (#set! injection.language "bash")))))
46−
47−(block_mapping_pair
48− key: (flow_node) @_run (#match? @_run "^(run|script|before_script|after_script)$")
49− value: (block_node
50− (block_sequence
51− (block_sequence_item
52− (block_node
53− (block_scalar) @injection.content
54− (#set! injection.language "bash"))))))
runtime/queries/yuck/highlights.scm+1−1
@@ -101,7 +101,7 @@
101101(list
102102 (symbol) @tag)
103103
104−; Other stuff that has not been caught by the previous queries yet
104+; Other stuff that has not been catched by the previous queries yet
105105
106106(ident) @variable
107107(index) @variable
runtime/themes/README.md−8
@@ -6,12 +6,4 @@ If you submit a theme, please include a comment at the top with your name and em
66# Author : Name <email@my.domain>
77```
88
9−If you are submitting a theme that is already published somewhere, then please
10−add the corresponding license file for it under `licenses/` with the following
11−name `theme_name.license` and add a comment at the top of the theme file:
12−
13−```toml
14−# License: <License specification>
15−```
16−
179We have a preview page for themes on our [wiki](https://github.com/helix-editor/helix/wiki/Themes)!
runtime/themes/autumn.toml+65−62
@@ -7,79 +7,81 @@
77# Jens Getreu ported and optimised the color theme for the Helix editor.
88# Author: Jens Getreu <getreu at web.de>
99
10−"attribute" = "my_turquoise1"
11−"comment" = { fg = "my_gray5" }
12−"constant.character.escape" = "my_turquoise1"
13−"constant" = "my_white3"
14−"constant.numeric" = "my_turquoise1"
15−"constructor" = "my_yellow1"
16−"debug" = "my_yellow2"
17−"diagnostic.error" = { underline = { style = "curl", color = "my_red" } }
18−"diagnostic.hint" = { underline = { style = "line", color = "my_gray5" }, bg = "my_black"}
19−"diagnostic.info" = { underline = { style = "line" } }
20−"diagnostic" = { underline = { style = "line", color = "my_gray5" }, bg = "my_black"}
21−"diagnostic.warning" = { underline = { style = "curl", color = "my_yellow2" } }
22−"diff.delta" = "my_gray5"
23−"diff.minus" = "my_red"
24−"diff.plus" = "my_green"
25−"error" = "my_red"
26−"function" = "my_yellow1"
27−"hint" = "my_gray6"
28−"info" = "my_yellow2"
29−"keyword" = "my_red"
30−"label" = "my_red"
31−"markup.bold" = { modifiers = ["bold"] }
32−"markup.heading" = "my_yellow1"
33−"markup.italic" = { modifiers = ["italic"] }
34−"markup.link.text" = "my_white2"
35−"markup.link.url" = "my_turquoise2"
36−"markup.list" = "my_white2"
37−"markup.quote" = "my_brown"
38−"markup.raw" = "my_green"
39−"markup.strikethrough" = { modifiers = ["crossed_out"] }
40−"namespace" = "my_white3"
41−"operator" = "my_white1"
42−"special" = "my_yellow1"
43−"string" = "my_green"
44−"type" = { fg = "my_white3", modifiers = ["italic"] }
4510"ui.background" = { bg = "my_gray0" }
46−"ui.cursor" = { bg = "my_white4", fg = "my_black" }
47−"ui.cursorline" = { bg = "my_gray3" }
48−"ui.cursorline.primary" = { bg = "my_black" }
49−"ui.cursorline.secondary" = { bg = "my_black" }
50−"ui.cursor.match" = { fg = "my_white1", modifiers = ["bold"], underline = { style = "double_line", color = "my_white1" }, bg = "my_black"}
51−"ui.cursor.primary" = { fg = "my_white1", modifiers = ["reversed"] }
52−"ui.debug" = { fg = "my_yellow1", bg = "my_gray0" }
53−"ui.gutter" = { bg = "my_gray0" }
54−"ui.help" = { fg = "my_gray7", bg = "my_gray2" }
55−"ui.highlight.frameline" = { bg = "#8b6904" }
56−"ui.linenr" = { fg = "my_gray3", bg = "my_gray0" }
57−"ui.linenr.selected" = { fg = "my_gray7", bg = "my_gray0"}
58−"ui.menu" = { fg = "my_white1", bg = "my_gray2" }
11+"ui.menu" = { fg = "my_white", bg = "my_gray2" }
5912"ui.menu.selected" = { fg = "my_gray2", bg = "my_gray6" }
13+"ui.linenr" = { fg = "my_gray3", bg = "my_gray0" }
6014"ui.popup" = { bg = "my_gray2" }
15+"ui.window" = { fg = "my_gray3", bg = "my_gray2" }
16+"ui.linenr.selected" = { fg = "my_gray7", bg = "my_gray0"}
6117"ui.selection" = { bg = "my_gray3" }
18+"comment" = { fg = "my_gray5", modifiers = ["italic"] }
19+"ui.cursorline" = { bg = "my_gray3" }
6220"ui.statusline" = { fg = "my_gray7", bg = "my_gray2" }
6321"ui.statusline.inactive" = { fg = 'my_gray5', bg = 'my_gray2' }
6422"ui.statusline.insert" = {fg = "my_black", bg = "my_gray6", modifiers = ["bold"]}
6523"ui.statusline.normal" = {fg = "my_gray7", bg = "my_gray2"}
6624"ui.statusline.select" = {fg = "my_gray7", bg = "my_black", modifiers = ["bold"]}
67−"ui.text.focus" = "my_white1"
68−"ui.text" = "my_white1"
25+"ui.cursor" = { bg = "my_white4", fg = "my_black" }
26+"ui.cursor.primary" = { fg = "my_white", modifiers = ["reversed"] }
27+"ui.cursor.match" = { fg = "my_white", modifiers = ["bold"], underline = { style = "double_line", color = "my_white" }, bg = "my_black"}
28+"ui.cursorline.primary" = { bg = "my_black" }
29+"ui.cursorline.secondary" = { bg = "my_black" }
30+"ui.highlight.frameline" = { bg = "#8b6904" }
31+"ui.debug" = { fg = "my_yellow1", bg = "my_gray0" }
32+"ui.text" = "my_white"
33+"operator" = "my_white"
34+"ui.text.focus" = "my_white"
35+"variable" = "my_white3"
36+"constant.numeric" = "my_turquoise"
37+"constant" = "my_white3"
38+"attribute" = "my_turquoise"
39+"type" = { fg = "my_white3", modifiers = ["italic"] }
40+"string" = "my_green"
41+"variable.other.member" = "my_brown"
42+"constant.character.escape" = "my_turquoise"
43+"function" = "my_yellow1"
44+"constructor" = "my_yellow1"
45+"special" = "my_yellow1"
46+"keyword" = "my_red"
47+"label" = "my_red"
48+"namespace" = "my_white3"
49+"ui.help" = { fg = "my_gray7", bg = "my_gray2" }
50+"ui.virtual.wrap" = "my_gray4"
51+"ui.virtual.whitespace" = { fg = "my_gray6" }
52+"ui.virtual.ruler" = { bg = "my_gray1" }
6953"ui.virtual.inlay-hint" = { fg = "my_gray4", bg="my_black", modifiers = ["normal"] }
7054"ui.virtual.inlay-hint.parameter" = { fg = "my_gray4", modifiers = ["normal"] }
7155"ui.virtual.inlay-hint.type" = { fg = "my_gray4", modifiers = ["italic"] }
72−"ui.virtual.ruler" = { bg = "my_gray1" }
73−"ui.virtual.whitespace" = { fg = "my_gray6" }
74−"ui.virtual.wrap" = "my_gray4"
75−"ui.window" = { fg = "my_gray3", bg = "my_gray2" }
76−"variable" = "my_white3"
77−"variable.other.member" = "my_brown"
56+
57+"markup.heading" = "my_yellow1"
58+"markup.list" = "my_white2"
59+"markup.bold" = { modifiers = ["bold"] }
60+"markup.italic" = { modifiers = ["italic"] }
61+"markup.strikethrough" = { modifiers = ["crossed_out"] }
62+"markup.link.url" = "my_turquoise2"
63+"markup.link.text" = "my_white2"
64+"markup.quote" = "my_brown"
65+"markup.raw" = "my_green"
66+
67+"diff.plus" = "my_green"
68+"diff.delta" = "my_gray5"
69+"diff.minus" = "my_red"
70+
71+"diagnostic" = { underline = { style = "line", color = "my_gray5" }, bg = "my_black"}
72+"diagnostic.hint" = { underline = { style = "line", color = "my_gray5" }, bg = "my_black"}
73+"diagnostic.info" = { underline = { style = "line" } }
74+"diagnostic.warning" = { underline = { style = "curl", color = "my_yellow2" } }
75+"diagnostic.error" = { underline = { style = "curl", color = "my_red" } }
76+"ui.gutter" = { bg = "my_gray0" }
77+"hint" = "my_gray6"
78+"debug" = "my_yellow2"
79+"info" = "my_yellow2"
7880"warning" = "my_yellow2"
81+"error" = "my_red"
7982
8083[palette]
8184my_black = "#212121" # Cursorline
82−my_brown = "#cfba8b" # Member variables, Quotes
8385my_gray0 = "#232323" # Default Background
8486my_gray1 = "#2b2b2b" # Ruler
8587my_gray2 = "#323232" # Lighter Background (Used for status bars, line number and folding marks)
@@ -89,13 +91,14 @@ my_gray5 = "#646f69" # Comments, Invisibles, Line Highlighting
8991my_gray6 = "#a8a8a8" # Dark Foreground (Used for status bars)
9092my_gray7 = "#c8c8c8" # Light Foreground
9193my_gray8 = "#e8e8e8" # Light Background
92−my_green = "#99be70" # Strings, Inherited Class, Markup Code, Diff Inserted
93−my_red = "#F05E48" # Keywords, Storage, Selector, Diff Changed
94−my_turquoise1 = "#86c1b9" # Support, Regular Expressions, Escape Characters
95−my_turquoise2 = "#72a59e" # URL
96−my_white1 = "#F3F2CC" # Default Foreground, Caret, Delimiters, Operators
94+my_white = "#F3F2CC" # Default Foreground, Caret, Delimiters, Operators
9795my_white2 = "#F3F2CC" # Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted
9896my_white3 = "#F3F2CC" # Classes, Markup Bold, Search Text Background
9997my_white4 = "#7e7d6a" # Cursor match
98+my_turquoise = "#86c1b9" # Support, Regular Expressions, Escape Characters
99+my_turquoise2 = "#72a59e" # URL
100+my_green = "#99be70" # Strings, Inherited Class, Markup Code, Diff Inserted
101+my_brown = "#cfba8b" # Member variables, Quotes
100102my_yellow1 = "#FAD566" # Functions, Methods, Attribute IDs, Headings
101103my_yellow2 = "#ffff9f" # Debug, Info
104+my_red = "#F05E48" # Keywords, Storage, Selector, Diff Changed
runtime/themes/autumn_night.toml+6−6
@@ -11,7 +11,6 @@ inherits = "autumn"
1111
1212[palette]
1313my_black = "#111111" # Cursorline
14−my_brown = "#cfba8b" # Member variables, Quotes
1514my_gray0 = "#090909" # Default Background
1615my_gray1 = "#0e0e0e" # Ruler
1716my_gray2 = "#1a1a1a" # Lighter Background (Used for status bars, line number and folding marks)
@@ -21,13 +20,14 @@ my_gray5 = "#626C66" # Comments, Invisibles, Line Highlighting
2120my_gray6 = "#aaaaaa" # Dark Foreground (Used for status bars)
2221my_gray7 = "#c4c4c4" # Light Foreground
2322my_gray8 = "#e8e8e8" # Light Background
24−my_green = "#99be70" # Strings, Inherited Class, Markup Code, Diff Inserted
25−my_red = "#F05E48" # Keywords, Storage, Selector, Diff Changed
26−my_turquoise1 = "#86c1b9" # Support, Regular Expressions, Escape Characters
27−my_turquoise2 = "#72a59e" # URL
28−my_white1 = "#F3F2CC" # Default Foreground, Caret, Delimiters, Operators
23+my_white = "#F3F2CC" # Default Foreground, Caret, Delimiters, Operators
2924my_white2 = "#F3F2CC" # Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted
3025my_white3 = "#F3F2CC" # Classes, Markup Bold, Search Text Background
3126my_white4 = "#7e7d6a" # Secondary cursors
27+my_turquoise = "#86c1b9" # Support, Regular Expressions, Escape Characters
28+my_turquoise2 = "#72a59e" # URL
29+my_green = "#99be70" # Strings, Inherited Class, Markup Code, Diff Inserted
30+my_brown = "#cfba8b" # Member variables, Quotes
3231my_yellow1 = "#FAD566" # Functions, Methods, Attribute IDs, Headings
3332my_yellow2 = "#ffff9f" # Debug, Info
33+my_red = "#F05E48" # Keywords, Storage, Selector, Diff Changed
runtime/themes/catppuccin_frappe.toml−2
@@ -34,5 +34,3 @@ crust = "#232634"
3434# derived colors by blending existing palette colors
3535cursorline = "#3b3f52"
3636secondary_cursor = "#b8a5a6"
37−secondary_cursor_normal = "#9193be"
38−secondary_cursor_insert = "#83a275"
runtime/themes/catppuccin_latte.toml−2
@@ -34,5 +34,3 @@ crust = "#dce0e8"
3434# derived colors by blending existing palette colors
3535cursorline = "#e9ebf1"
3636secondary_cursor = "#e2a99e"
37−secondary_cursor_normal = "#98a7fb"
38−secondary_cursor_insert = "#75b868"
runtime/themes/catppuccin_macchiato.toml−2
@@ -34,5 +34,3 @@ crust = "#181926"
3434# derived colors by blending existing palette colors
3535cursorline = "#303347"
3636secondary_cursor = "#b6a5a7"
37−secondary_cursor_normal = "#8b90bf"
38−secondary_cursor_insert = "#7fa47a"
runtime/themes/catppuccin_mocha.toml−11
@@ -83,7 +83,6 @@
8383
8484"ui.text" = "text"
8585"ui.text.focus" = { fg = "text", bg = "surface0", modifiers = ["bold"] }
86−"ui.text.inactive" = { fg = "overlay1" }
8786
8887"ui.virtual" = "overlay0"
8988"ui.virtual.ruler" = { bg = "surface0" }
@@ -96,14 +95,6 @@
9695"ui.cursor.primary" = { fg = "base", bg = "rosewater" }
9796"ui.cursor.match" = { fg = "peach", modifiers = ["bold"] }
9897
99−"ui.cursor.primary.normal" = { fg = "base", bg = "lavender" }
100−"ui.cursor.primary.insert" = { fg = "base", bg = "green" }
101−"ui.cursor.primary.select" = { fg = "base", bg = "flamingo" }
102−
103−"ui.cursor.normal" = { fg = "base", bg = "secondary_cursor_normal" }
104−"ui.cursor.insert" = { fg = "base", bg = "secondary_cursor_insert" }
105−"ui.cursor.select" = { fg = "base", bg = "secondary_cursor" }
106−
10798"ui.cursorline.primary" = { bg = "cursorline" }
10899
109100"ui.highlight" = { bg = "surface1", modifiers = ["bold"] }
@@ -155,5 +146,3 @@ crust = "#11111b"
155146# derived colors by blending existing palette colors
156147cursorline = "#2a2b3c"
157148secondary_cursor = "#b5a6a8"
158−secondary_cursor_normal = "#878ec0"
159−secondary_cursor_insert = "#7da87e"
runtime/themes/cyan_light.tomldeleted−154
@@ -1,154 +0,0 @@
1−# An approximation/port of the Cyan Light Theme from Jetbrains
2−#
3−# Original Color Scheme here https://plugins.jetbrains.com/plugin/12102-cyan-light-theme
4−
5−"attribute" = "blue"
6−"type" = "shade07"
7−"type.enum.variant" = "purple"
8−"constructor" = "shade07"
9−
10−"constant" = "darker_blue"
11−"constant.builtin.boolean" = "blue"
12−"constant.character" = "blue"
13−"constant.character.escape" = "dark_red"
14−"constant.numeric" = "blue"
15−
16−"string" = "green"
17−"string.regexp" = "blue"
18−"string.special" = { fg = "dark_red", modifiers = ["underlined"] }
19−
20−"comment" = "comment_gray"
21−
22−"variable" = "green_blue"
23−"variable.builtin" = { fg = "darker_blue" }
24−"variable.parameter" = "purple"
25−"variable.other.member" = "purple"
26−
27−"label" = { fg = "darker_blue", modifiers = ["underlined"] }
28−"punctuation" = "shade06"
29−
30−"keyword" = "darker_blue"
31−"keyword.control.exception" = "darker_blue"
32−
33−"operator" = "shade06"
34−
35−"function" = "shade07"
36−"function.macro" = "yellow"
37−"function.builtin" = { fg = "shade07", modifiers = ["italic"] }
38−"function.special" = "dark_red"
39−"function.method" = "dark_yellow"
40−
41−"tag" = "darker_blue"
42−"special" = "shade06"
43−"namespace" = "darker_blue"
44−
45−"markup.bold" = { fg = "shade06", modifiers = ["bold"] }
46−"markup.italic" = { fg = "shade06", modifiers = ["italic"] }
47−"markup.strikethrough" = { fg = "shade06", modifiers = ["crossed_out"] }
48−"markup.heading" = { fg = "purple" }
49−"markup.list" = "darker_blue"
50−"markup.list.numbered" = "darker_blue"
51−"markup.list.unnumbered" = "darker_blue"
52−"markup.link.url" = "shade06"
53−"markup.link.text" = { fg = "dark_blue", modifiers = ['underlined'] }
54−"markup.link.label" = "dark_blue"
55−"markup.quote" = "green"
56−"markup.raw" = "green"
57−"markup.raw.inline" = "green"
58−"markup.raw.block" = "green"
59−
60−"diff.plus" = "green"
61−"diff.plus.gutter" = "gutter_green"
62−"diff.minus" = "red"
63−"diff.minus.gutter" = "gutter_red"
64−"diff.delta" = "blue"
65−"diff.delta.gutter" = "gutter_blue"
66−
67−# ui specific
68−"ui.background" = { bg = "shade00" }
69−"ui.cursor" = { bg = "shade02" }
70−"ui.cursor.primary" = { bg = "cursor_blue" }
71−"ui.cursor.match" = { fg = "shade00", bg = "shade04" }
72−"ui.cursor.primary.select" = { bg = "light_purple" }
73−"ui.cursor.primary.insert" = { bg = "light_green" }
74−
75−"ui.selection" = { bg = "lighter_blue" }
76−"ui.selection.primary" = { bg = "lighter_blue" }
77−
78−"ui.highlight" = { bg = "faint_blue" }
79−"ui.cursorline.primary" = { bg = "faint_blue" }
80−
81−"ui.linenr" = { fg = "shade03" }
82−"ui.linenr.selected" = { fg = "shade04", bg = "faint_blue", modifiers = [
83− "bold",
84−] }
85−
86−"ui.statusline" = { fg = "shade06", bg = "shade02" }
87−"ui.statusline.inactive" = { fg = "shade04", bg = "shade01" }
88−"ui.statusline.normal" = { fg = "shade00", bg = "blue" }
89−"ui.statusline.insert" = { fg = "shade00", bg = "green" }
90−"ui.statusline.select" = { fg = "shade00", bg = "purple" }
91−
92−"ui.popup" = { bg = "shade01", fg = "shade04" }
93−"ui.window" = { bg = "shade00", fg = "shade04" }
94−"ui.help" = { fg = "shade06", bg = "shade01" }
95−"ui.text" = "shade05"
96−"ui.text.focus" = { fg = "shade07", bg = "light_blue" }
97−"ui.virtual" = "shade03"
98−"ui.virtual.ruler" = { bg = "shade04" }
99−"ui.menu" = { fg = "shade05", bg = "shade01" }
100−"ui.menu.selected" = { fg = "shade07", bg = "light_blue" }
101−
102−"hint" = "shade04"
103−"info" = "light_blue"
104−"warning" = "orange"
105−"error" = "red"
106−"diagnostic" = { modifiers = [] }
107−"diagnostic.hint" = { underline = { color = "shade04", style = "line" } }
108−"diagnostic.info" = { underline = { color = "light_blue", style = "line" } }
109−"diagnostic.warning" = { underline = { color = "orange", style = "curl" } }
110−"diagnostic.error" = { underline = { color = "red", style = "curl" } }
111−
112−[palette]
113−shade00 = "#f2f3f7"
114−shade01 = "#dadde8"
115−shade02 = "#c1c6d9"
116−shade03 = "#a9b0ca"
117−shade04 = "#525c85"
118−shade05 = "#434b6c"
119−shade06 = "#343a54"
120−shade07 = "#25293c"
121−
122−background = "#f2f3f7"
123−foreground = "#25293c"
124−
125−comment_gray = "#808080"
126−
127−gutter_blue = "#C3D6E8"
128−faint_blue = "#E8Eef1"
129−lighter_blue = "#d0eaff"
130−light_blue = "#99ccff"
131−cursor_blue = "#80bfff"
132−blue = "#0073E6"
133−dark_blue = "#185b93"
134−darker_blue = "#000080"
135−
136−
137−purple = "#660E7A"
138−light_purple = "#ED9CFF"
139−
140−gutter_green = "#C9DEC1"
141−green = "#00733B"
142−light_green = "#5DCE87"
143−green_blue = "#458383"
144−
145−
146−yellow = "#808000"
147−dark_yellow = "#7A7A43"
148−
149−light_orange = "#f9c881"
150−orange = "#F49810"
151−
152−gutter_red = "#EBBCBC"
153−red = "#d90016"
154−dark_red = "#7F0000"
runtime/themes/darcula-solid.toml+4−1
@@ -4,8 +4,9 @@ inherits = "darcula"
44
55"ui.background.separator" = { bg = "grey01" }
66"ui.menu.scroll" = { fg = "grey02", bg = "grey00" }
7−"ui.popup" = { fg = "grey05", bg = "grey00" }
7+"ui.popup" = { fg = "grey03", bg = "grey02" }
88"ui.window" = { bg = "grey00" }
9+"ui.selection" = { bg = "blue" }
910"ui.cursorline.secondary" = { bg = "grey03" }
1011
1112[palette]
@@ -14,3 +15,5 @@ grey01 = "#1f1f1f"
1415grey02 = "#323232"
1516grey03 = "#555555"
1617grey04 = "#a8a8a8"
18+
19+blue = "#104158"
runtime/themes/darcula.toml+4−10
@@ -8,14 +8,13 @@
88"ui.gutter" = { bg = "grey01" }
99"ui.popup" = { fg = "grey05", bg = "grey00" }
1010"ui.window" = { bg = "grey01" }
11−"ui.selection" = { bg = "grey02" }
12−"ui.selection.primary" = { bg = "blue" }
11+"ui.selection" = { bg = "grey03" }
1312"ui.statusline" = { fg = "grey04", bg = "grey02" }
1413"ui.statusline.insert" = { bg = "white", fg = "grey01" }
1514"ui.statusline.select" = { bg = "orange", fg = "grey01" }
1615"ui.help" = { fg = "grey04", bg = "grey01" }
1716"ui.cursor" = { fg = "grey04", modifiers = ["reversed"] }
18−"ui.cursor.primary" = { fg = "grey02", bg = "grey05" }
17+"ui.cursor.primary" = { fg = "grey05", modifiers = ["reversed"] }
1918"ui.cursor.match" = { fg = "white", modifiers = ["underlined"] }
2019"ui.cursorline.primary" = { bg = "grey02" }
2120"ui.cursorline.secondary" = { bg = "grey02" }
@@ -35,11 +34,7 @@
3534"constant.numeric" = "lightblue"
3635"constant.character.escape" = "white"
3736"attribute" = "yellow"
38−"type" = "white"
39−"type.builtin" = "orange"
40−"type.parameter" = { fg = "white", modifiers = ["bold"] }
41−"type.enum" = "white"
42−"type.enum.variant" = "orange"
37+"type" = "orange"
4338"string" = "darkgreen"
4439"function" = "yellow"
4540"function.macro" = "green"
@@ -66,7 +61,7 @@
6661"markup.link.url" = { fg = "lightblue", modifiers = ["underlined"] }
6762"markup.link.text" = "white"
6863"markup.quote" = "darkgreen"
69−"markup.raw" = "purple"
64+"markup.raw" = "white"
7065
7166"diff.plus" = "green"
7267"diff.delta" = "grey"
@@ -102,4 +97,3 @@ green = "#32cd32"
10297grey = "#808080"
10398darkgreen = "#629755"
10499lightblue = "#6897bb"
105−blue = "#104158"
runtime/themes/dracula.toml−2
@@ -90,7 +90,6 @@
9090"ui.virtual.whitespace" = { fg = "current_line" }
9191"ui.virtual.wrap" = { fg = "current_line" }
9292"ui.virtual.ruler" = { bg = "black" }
93−"ui.virtual.indent-guide" = { fg = "indent" }
9493"ui.virtual.inlay-hint" = { fg = "cyan" }
9594"ui.virtual.inlay-hint.parameter" = { fg = "cyan", modifiers = ["italic", "dim"] }
9695"ui.virtual.inlay-hint.type" = { fg = "cyan", modifiers = ["italic", "dim"] }
@@ -124,7 +123,6 @@ black = "#191A21"
124123grey = "#666771"
125124comment = "#6272A4"
126125current_line = "#44475a"
127−indent = "#56596a"
128126selection = "#363848"
129127red = "#ff5555"
130128orange = "#ffb86c"
runtime/themes/everblush.toml−1
@@ -68,7 +68,6 @@
6868"ui.virtual.whitespace" = { fg = "comment" }
6969"ui.virtual.wrap" = { fg = "comment" }
7070"ui.virtual.indent-guide" = { fg = "comment" }
71−"ui.virtual.inlay-hint" = { fg = "comment" }
7271"ui.window" = { fg = "black" }
7372
7473"error" = { fg = "red" }
runtime/themes/gruber-darker.tomldeleted−114
@@ -1,114 +0,0 @@
1−# Author : Mehedi Hasan <mehedi.r137@gmail.com>
2−# Based on : https://github.com/rexim/gruber-darker-theme
3−
4−"attribute" = "fg0"
5−"keyword" = { fg = "yellow0", modifiers = ["bold"] }
6−"keyword.directive" = "quartz"
7−"namespace" = "quartz"
8−"punctuation" = "fg0"
9−"punctuation.delimiter" = "fg0"
10−"operator" = "fg0"
11−"special" = { fg = "yellow0", modifiers = ["bold"] }
12−"variable" = "fg0"
13−"variable.builtin" = { fg = "yellow0", modifiers = ["bold"] }
14−"variable.parameter" = "fg0"
15−"type" = "quartz"
16−"type.builtin" = "yellow0"
17−"constructor" = { fg = "quartz" }
18−"function" = "niagara0"
19−"function.builtin" = "yellow0"
20−"tag" = "niagara0"
21−"comment" = { fg = "brown0" }
22−"constant.character" = { fg = "green0" }
23−"constant.character.escape" = { fg = "yellow0" }
24−"constant.builtin" = { fg = "yellow0", modifiers = ["bold"] }
25−"string" = "green0"
26−"constant.numeric" = "wisteria"
27−"label" = "fg0"
28−"module" = "aqua1"
29−
30−"diff.plus" = "green1"
31−"diff.delta" = "orange1"
32−"diff.minus" = "red0"
33−
34−"warning" = { fg = "orange1", modifiers = ["bold"] }
35−"error" = { fg = "red0", modifiers = ["bold"] }
36−"info" = { fg = "aqua1", modifiers = ["bold"] }
37−"hint" = { fg = "blue0", modifiers = ["bold"] }
38−
39−"ui.background" = { bg = "bg0" }
40−"ui.linenr" = { fg = "bg4" }
41−"ui.linenr.selected" = { fg = "yellow0" }
42−"ui.cursorline" = { bg = "bg1" }
43−
44−"ui.statusline" = { fg = "fg0", bg = "bg1" }
45−"ui.statusline.normal" = { fg = "bg1", bg = "yellow0", modifiers = ["bold"] }
46−"ui.statusline.insert" = { fg = "bg1", bg = "blue0", modifiers = ["bold"] }
47−"ui.statusline.select" = { fg = "bg1", bg = "wisteria", modifiers = ["bold"] }
48−"ui.statusline.inactive" = { fg = "fg3", bg = "bg1" }
49−
50−"ui.bufferline" = { fg = "fg3", bg = "bg6" }
51−"ui.bufferline.active" = { fg = "fg0", bg = "bg7" }
52−
53−"ui.popup" = { bg = "bg6" }
54−"ui.window" = { fg = "bg1" }
55−"ui.help" = { bg = "bg1", fg = "fg0" }
56−"ui.text" = { fg = "fg0" }
57−"ui.text.focus" = { bg = "bg5", modifiers = ["bold"] }
58−"ui.selection" = { bg = "bg2" }
59−"ui.selection.primary" = { bg = "bg5" }
60−"ui.cursor.primary" = { bg = "fg0", fg = "niagara1" }
61−"ui.cursor.match" = { bg = "yellow1" }
62−"ui.menu" = { fg = "fg0", bg = "bg6" }
63−"ui.menu.selected" = { fg = "fg0", bg = "bg5", modifiers = ["bold"] }
64−
65−"ui.virtual.whitespace" = "bg8"
66−"ui.virtual.indent-guide" = "bg8"
67−"ui.virtual.ruler" = { bg = "bg1" }
68−"ui.virtual.inlay-hint" = { fg = "bg7" }
69−"ui.virtual.wrap" = { fg = "bg2" }
70−
71−"diagnostic.warning" = { underline = { color = "orange1", style = "dashed" } }
72−"diagnostic.error" = { underline = { color = "red3", style = "dashed" } }
73−"diagnostic.info" = { underline = { color = "aqua1", style = "dashed" } }
74−"diagnostic.hint" = { underline = { color = "blue0", style = "dashed" } }
75−
76−"markup.heading" = { fg = "aqua1", modifiers = ["bold"] }
77−"markup.bold" = { modifiers = ["bold"] }
78−"markup.italic" = { modifiers = ["italic"] }
79−"markup.strikethrough" = { modifiers = ["crossed_out"] }
80−"markup.link.url" = { fg = "green1", modifiers = ["underlined"] }
81−"markup.link.text" = "red3"
82−"markup.raw" = { fg = "fg0", bg = "bg8", modifiers = ["bold"] }
83−
84−[palette]
85−fg0 = "#e4e4ef"
86−fg1 = "#f4f4ff"
87−fg2 = "#f5f5f5"
88−fg3 = "#a89984"
89−bg0 = "#181818"
90−bg1 = "#282828"
91−bg2 = "#453d41"
92−bg4 = "#52494e"
93−bg5 = "#404040"
94−bg6 = "#232323"
95−bg7 = "#3f3f3f"
96−bg8 = "#2c2c2c"
97−red0 = "#f43841"
98−red1 = "#ff4f58"
99−red2 = "#2B0A0B"
100−red3 = "#fb4934"
101−green0 = "#73c936"
102−green1 = "#b8bb26"
103−yellow0 = "#ffdd33"
104−yellow1 = "#655814"
105−blue0 = "#5292c8"
106−orange0 = "#d65d0e"
107−orange1 = "#fe8019"
108−brown0 = "#cc8c3c"
109−quartz = "#95a99f"
110−niagara0 = "#96a6c8"
111−niagara1 = "#303540"
112−wisteria = "#9e95c7"
113−aqua1 = "#8ec07c"
114−
runtime/themes/horizon-dark.tomldeleted−80
@@ -1,80 +0,0 @@
1−# Syntax
2−string = "orange"
3−constant = "purple"
4−"constant.numeric" = "orange"
5−"constant.builtin" = "orange"
6−variable = "red"
7−comment = "light-gray"
8−special = "purple"
9−"punctuation.bracket" = "purple"
10−keyword = "purple"
11−function = "blue"
12−label = "orange"
13−type = "orange"
14−namespace = "orange"
15−
16−# User Interface
17−"ui.background" = { bg = "bg", fg = "gray" }
18−"ui.background.separator" = "light-gray"
19−"ui.text" = "white"
20−"ui.text.focus" = "green"
21−"ui.text.inactive" = "selection"
22−"ui.text.info" = "orange"
23−"ui.cursor" = { modifiers = ["reversed"] }
24−"ui.cursor.primary" = { modifiers = ["reversed"] }
25−"ui.cursor.match" = { bg = "selection" }
26−"ui.gutter" = "gray"
27−"ui.gutter.selected" = "light-gray"
28−"ui.selection" = { bg = "selection" }
29−"ui.virtual.indent-guide" = { fg = "gray"}
30−"ui.virtual.whitespace" = { fg = "light-gray"}
31−"ui.statusline" = { bg = "dark-bg", fg = "light-gray" }
32−"ui.popup" = { bg = "dark-bg", fg = "orange" }
33−"ui.help" = { bg = "dark-bg", fg = "orange" }
34−"ui.menu" = { bg = "dark-bg", fg = "light-gray" }
35−"ui.menu.selected" = { bg = "selection", fg = "orange" }
36−"ui.window" = "selection"
37−"ui.bufferline" = { bg = "dark-bg", fg = "light-gray" }
38−"ui.bufferline.active" = { bg = "dark-bg", fg = "orange" }
39−
40−# Diagnostics
41−"diagnostic" = { underline = { style = "curl" } }
42−"diagnostic.hint" = { underline = { color = "green", style = "curl" } }
43−"diagnostic.info" = { underline = { color = "blue", style = "curl" } }
44−"diagnostics.error" = { underline = { color = "red", style = "curl"} }
45−"diagnostics.warning" = { underline = { color = "orange", style = "curl"} }
46−
47−warning = { fg = "orange", modifiers = ["bold"] }
48−error = { fg = "red", modifiers = ["bold"] }
49−info = { fg = "blue", modifiers = ["bold"] }
50−hint = { fg = "green", modifiers = ["bold"] }
51−
52−# Markup
53−"markup.heading" = "pink"
54−"markup.list" = "light-gray"
55−"markup.list.checked" = "green"
56−"markup.list.unchecked" = "light-gray"
57−"markup.bold" = { modifiers = ["bold"] }
58−"markup.italic" = { modifiers = ["italic"] }
59−"markup.strikethrough" = { modifiers = ["crossed_out"] }
60−"markup.link" = "blue"
61−"markup.quote" = "orange"
62−"markup.raw" = "orange"
63−
64−"diff.plus" = "green"
65−"diff.minus" = "red"
66−"diff.delta" = "orange"
67−
68−[palette]
69−white = "#D5D8DA"
70−gray = "#2E303E"
71−light-gray = "#6C6F93"
72−bg = "#1C1E26"
73−dark-bg = "#16161C"
74−pink = "#EE64AE"
75−selection = "#353747"
76−green = "#27D796"
77−orange = "#FAB795"
78−purple = "#B877DB"
79−red = "#E95678"
80−blue = "#25B2BC"
runtime/themes/jellybeans.toml+1−1
@@ -22,7 +22,7 @@
2222
2323"constant.builtin.boolean" = "yellow"
2424"constant.character" = "yellow"
25−"constant.character.escape" = "red_error"
25+"constant.characted.escape" = "red_error"
2626"constant.numeric" = "dark_orange"
2727"string" = "dark_green"
2828"string.regexp" = "light_purple"
runtime/themes/licenses/everforest.LICENSEdeleted−21
@@ -1,21 +0,0 @@
1−MIT License
2−
3−Copyright (c) 2019 sainnhe
4−
5−Permission is hereby granted, free of charge, to any person obtaining a copy
6−of this software and associated documentation files (the "Software"), to deal
7−in the Software without restriction, including without limitation the rights
8−to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9−copies of the Software, and to permit persons to whom the Software is
10−furnished to do so, subject to the following conditions:
11−
12−The above copyright notice and this permission notice shall be included in all
13−copies or substantial portions of the Software.
14−
15−THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16−IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17−FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18−AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19−LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20−OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21−SOFTWARE.
runtime/themes/licenses/modus_vivendi.LICENSEdeleted−5
@@ -1,5 +0,0 @@
1−Copyright (C) 2020-2023 Free Software Foundation, Inc.
2−
3−Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with the Front-Cover Texts being “A GNU Manual,” and with the Back-Cover Texts as in (a) below. A copy of the license is included in the section entitled “GNU Free Documentation License.”
4−
5−(a) The FSF’s Back-Cover Text is: “You have the freedom to copy and modify this GNU manual.”
runtime/themes/licenses/modus_vivendi_deuteranopia.LICENSEdeleted−5
@@ -1,5 +0,0 @@
1−Copyright (C) 2020-2023 Free Software Foundation, Inc.
2−
3−Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with the Front-Cover Texts being “A GNU Manual,” and with the Back-Cover Texts as in (a) below. A copy of the license is included in the section entitled “GNU Free Documentation License.”
4−
5−(a) The FSF’s Back-Cover Text is: “You have the freedom to copy and modify this GNU manual.”
runtime/themes/licenses/modus_vivendi_tinted.LICENSEdeleted−5
@@ -1,5 +0,0 @@
1−Copyright (C) 2020-2023 Free Software Foundation, Inc.
2−
3−Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with the Front-Cover Texts being “A GNU Manual,” and with the Back-Cover Texts as in (a) below. A copy of the license is included in the section entitled “GNU Free Documentation License.”
4−
5−(a) The FSF’s Back-Cover Text is: “You have the freedom to copy and modify this GNU manual.”
runtime/themes/licenses/modus_vivendi_tritanopia.LICENSEdeleted−5
@@ -1,5 +0,0 @@
1−Copyright (C) 2020-2023 Free Software Foundation, Inc.
2−
3−Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with the Front-Cover Texts being “A GNU Manual,” and with the Back-Cover Texts as in (a) below. A copy of the license is included in the section entitled “GNU Free Documentation License.”
4−
5−(a) The FSF’s Back-Cover Text is: “You have the freedom to copy and modify this GNU manual.”
runtime/themes/licenses/poimandres.LICENSEdeleted−21
@@ -1,21 +0,0 @@
1−MIT License
2−
3−Copyright (c) 2023 drcmda
4−
5−Permission is hereby granted, free of charge, to any person obtaining a copy
6−of this software and associated documentation files (the "Software"), to deal
7−in the Software without restriction, including without limitation the rights
8−to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9−copies of the Software, and to permit persons to whom the Software is
10−furnished to do so, subject to the following conditions:
11−
12−The above copyright notice and this permission notice shall be included in all
13−copies or substantial portions of the Software.
14−
15−THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16−IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17−FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18−AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19−LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20−OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21−SOFTWARE.
runtime/themes/licenses/serika-syntax.LICENSEdeleted−21
@@ -1,21 +0,0 @@
1−MIT License
2−
3−Copyright (c) 2018 arturoalviar
4−
5−Permission is hereby granted, free of charge, to any person obtaining a copy
6−of this software and associated documentation files (the "Software"), to deal
7−in the Software without restriction, including without limitation the rights
8−to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9−copies of the Software, and to permit persons to whom the Software is
10−furnished to do so, subject to the following conditions:
11−
12−The above copyright notice and this permission notice shall be included in all
13−copies or substantial portions of the Software.
14−
15−THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16−IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17−FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18−AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19−LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20−OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21−SOFTWARE.
runtime/themes/licenses/sonokai.LICENSEdeleted−21
@@ -1,21 +0,0 @@
1−MIT License
2−
3−Copyright (c) 2020 sainnhe
4−
5−Permission is hereby granted, free of charge, to any person obtaining a copy
6−of this software and associated documentation files (the "Software"), to deal
7−in the Software without restriction, including without limitation the rights
8−to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9−copies of the Software, and to permit persons to whom the Software is
10−furnished to do so, subject to the following conditions:
11−
12−The above copyright notice and this permission notice shall be included in all
13−copies or substantial portions of the Software.
14−
15−THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16−IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17−FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18−AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19−LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20−OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21−SOFTWARE.
runtime/themes/licenses/starlight.LICENSEdeleted−24
@@ -1,24 +0,0 @@
1−This is free and unencumbered software released into the public domain.
2−
3−Anyone is free to copy, modify, publish, use, compile, sell, or
4−distribute this software, either in source code form or as a compiled
5−binary, for any purpose, commercial or non-commercial, and by any
6−means.
7−
8−In jurisdictions that recognize copyright laws, the author or authors
9−of this software dedicate any and all copyright interest in the
10−software to the public domain. We make this dedication for the benefit
11−of the public at large and to the detriment of our heirs and
12−successors. We intend this dedication to be an overt act of
13−relinquishment in perpetuity of all present and future rights to this
14−software under copyright law.
15−
16−THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17−EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18−MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19−IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20−OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21−ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22−OTHER DEALINGS IN THE SOFTWARE.
23−
24−For more information, please refer to <https://unlicense.org>
runtime/themes/material_darker.tomldeleted−20
@@ -1,20 +0,0 @@
1−# Material Theme <https://material-theme.com/> for Helix Editor
2−
3−inherits = "material_deep_ocean"
4−
5−[palette]
6−bg = "#212121"
7−text = "#b0bec5"
8−
9−gray = "#616161"
10−error = "#ff5370"
11−
12−disabled = "#474747"
13−
14−accent = "#ff9800"
15−
16−highlight = "#3f3f3f"
17−
18−comment = "#616161"
19−
20−selection = "#404040"
runtime/themes/material_deep_ocean.tomldeleted−123
@@ -1,123 +0,0 @@
1−# Material Theme <https://material-theme.com/> for Helix Editor
2−
3−# Syntax Highlighting
4−
5−"type" = "purple"
6−
7−"constructor" = "blue"
8−
9−"constant" = "yellow"
10−
11−"string" = "green"
12−"string.regexp" = "yellow"
13−"string.special" = "blue"
14−
15−"comment" = { fg = "comment" }
16−
17−"variable" = "text"
18−"variable.parameter" = { fg = "orange" }
19−"variable.builtin" = "yellow"
20−
21−"label" = "orange"
22−
23−"punctuation" = "cyan"
24−
25−"keyword" = "purple"
26−"keyword.storage" = "cyan"
27−
28−"operator" = "cyan"
29−
30−"function" = "blue"
31−"function.macro" = "cyan"
32−
33−"tag" = "red"
34−"attribute" = "purple"
35−
36−"namespace" = { fg = "yellow" }
37−
38−"special" = "cyan"
39−
40−"markup.heading.marker" = { fg = "cyan", modifiers = ["bold"] }
41−"markup.heading.1" = "cyan"
42−"markup.heading.2" = "red"
43−"markup.heading.3" = "green"
44−"markup.heading.4" = "yellow"
45−"markup.heading.5" = "blue"
46−"markup.heading.6" = "orange"
47−"markup.list" = "purple"
48−"markup.bold" = { modifiers = ["bold"] }
49−"markup.italic" = { modifiers = ["italic"] }
50−"markup.strikethrough" = { modifiers = ["crossed_out"] }
51−"markup.link.url" = { fg = "green", modifiers = ["underlined"] }
52−"markup.link.text" = "blue"
53−"markup.raw" = "text"
54−
55−"diff.plus" = "green"
56−"diff.minus" = "red"
57−"diff.delta" = "blue"
58−
59−# User Interface
60−
61−"ui.background" = { bg = "bg", fg = "text" }
62−"ui.text" = { fg = "text" }
63−
64−"ui.statusline" = { bg = "bg", fg = "text" }
65−"ui.statusline.inactive" = { bg = "bg", fg = "disabled" }
66−"ui.statusline.normal" = { bg = "accent", fg = "text" }
67−"ui.statusline.insert" = { bg = "green", fg = "text" }
68−"ui.statusline.select" = { bg = "purple", fg = "text" }
69−
70−
71−"ui.selection" = { bg = "selection" }
72−
73−"ui.linenr" = { fg = "line-number" }
74−"ui.linenr.selected" = { fg = "accent" }
75−
76−"ui.cursor" = { bg = "highlight", fg = "white" }
77−
78−"ui.cursor.primary" = { bg = "white", fg = "gray" }
79−"ui.cursorline.primary" = { bg = "white" }
80−
81−"ui.virtual" = { fg = "gray" }
82−"ui.virtual.ruler" = { bg = "highlight" }
83−"ui.virtual.indent-guide" = { fg = "gray" }
84−
85−"ui.highlight" = { bg = "highlight" }
86−
87−"ui.menu" = { bg = "highlight", fg = "text" }
88−
89−"ui.help" = { bg = "highlight", fg = "text" }
90−
91−"ui.popup" = { bg = "highlight", fg = "text" }
92−
93−warning = "yellow"
94−error = "error"
95−info = "blue"
96−hint = "purple"
97−
98−[palette]
99−bg = "#0f111a"
100−text = "#a6accd"
101−
102−white = "#eeffff"
103−green = "#c3e88d"
104−yellow = "#ffcb6b"
105−blue = "#82aaff"
106−red = "#f07178"
107−purple = "#c792ea"
108−orange = "#f78c6c"
109−cyan = "#89ddff"
110−gray = "#717cb4"
111−error = "#ff5370"
112−
113−disabled = "#464b5d"
114−
115−accent = "#84ffff"
116−
117−highlight = "#1f2233"
118−
119−comment = "#464b5d"
120−
121−selection = "#1f2233"
122−
123−line-number = "#3b3f51"
runtime/themes/material_oceanic.tomldeleted−21
@@ -1,21 +0,0 @@
1−# Material Theme <https://material-theme.com/> for Helix Editor
2−
3−inherits = "material_deep_ocean"
4−
5−[palette]
6−bg = "#25363b"
7−text = "#b0bec5"
8−
9−gray = "#546e7a"
10−
11−disabled = "#415967"
12−
13−accent = "#009688"
14−
15−highlight = "#425b67"
16−
17−comment = "#546e7a"
18−
19−selection = "#395b65"
20−
21−line-number = "#355058"
runtime/themes/material_palenight.tomldeleted−19
@@ -1,19 +0,0 @@
1−# Material Theme <https://material-theme.com/> for Helix Editor
2−
3−inherits = "material_deep_ocean"
4−
5−[palette]
6−bg = "#292d3e"
7−text = "#a6accd"
8−
9−disabled = "#515772"
10−
11−accent = "#ab47bc"
12−
13−highlight = "#444267"
14−
15−comment = "#676e95"
16−
17−selection = "#444267"
18−
19−line-number = "#3a3f58"
runtime/themes/modus_operandi.tomldeleted−194
@@ -1,194 +0,0 @@
1−# Author: Alexis Mousset <contact@amousset.me>
2−# Adapted from https://protesilaos.com/emacs/modus-themes, by Protesilaos Stavrou
3−# Version 4.3.0
4−#
5−
6−# Syntax highlighting
7−# -------------------
8−"type" = "cyan-cooler"
9−"constructor" = "cyan-cooler"
10−
11−"constant" = "blue-cooler"
12−"constant.character.escape" = "magenta"
13−
14−"string" = "blue-warmer"
15−"string.regexp" = "magenta-faint"
16−"string.special" = "blue-faint" # used for colors in CSS
17−
18−"comment" = "fg-dim"
19−
20−"variable.parameter" = "cyan"
21−"variable.builtin" = "magenta-cooler"
22−"label" = "fg-dim" # used for language in markdown code blocks
23−"keyword" = "magenta-cooler"
24−"keyword.directive" = "red-cooler"
25−"function" = "magenta"
26−"function.macro" = "magenta-warmer"
27−
28−punctuation = "fg-dim"
29−"tag" = "magenta"
30−"attribute" = "cyan-cooler"
31−"namespace" = "blue-cooler"
32−"special" = "red-cooler"
33−
34−"markup.heading.marker" = "fg-dim"
35−"markup.heading.1" = { fg = "fg-main", modifiers = ["bold"] }
36−"markup.heading.2" = { fg = "yellow-faint", modifiers = ["bold"] }
37−"markup.heading.3" = { fg = "fg-alt", modifiers = ["bold"] }
38−"markup.heading.4" = { fg = "magenta", modifiers = ["bold"] }
39−"markup.heading.5" = { fg = "green-faint", modifiers = ["bold"] }
40−"markup.heading.6" = { fg = "red-faint", modifiers = ["bold"] }
41−"markup.list" = "fg-dim"
42−"markup.list.checked" = { fg = "yellow-warmer" }
43−"markup.list.unchecked" = { fg = "yellow-warmer" }
44−"markup.bold" = { modifiers = ["bold"] }
45−"markup.italic" = { modifiers = ["italic"] }
46−"markup.strikethrough" = { modifiers = ["crossed_out"] }
47−"markup.link.url" = { fg = "cyan" }
48−"markup.link.text" = { fg = "blue-warmer", modifiers = ["underlined"] }
49−"markup.raw.block" = { bg = "bg-dim" }
50−"markup.raw.inline" = { fg = "green-cooler" }
51−
52−"diff.plus" = { fg = "fg-added", bg = "bg-added" }
53−"diff.plus.gutter" = "green-intense"
54−"diff.minus" = { fg = "fg-removed", bg = "bg-removed" }
55−"diff.minus.gutter" = "red-intense"
56−"diff.delta" = { fg = "fg-changed", bg = "bg-changed" }
57−"diff.delta.gutter" = "yellow-intense"
58−
59−# User Interface
60−# --------------
61−
62−"ui.background" = { bg = "bg-main" }
63−
64−"ui.linenr" = { fg = "fg-dim", bg = "bg-dim" }
65−"ui.linenr.selected" = { fg = "fg-main", bg = "bg-active" }
66−
67−"ui.statusline" = { fg = "fg-mode-line-active", bg = "bg-mode-line-active" }
68−"ui.statusline.inactive" = { fg = "fg-mode-line-inactive", bg = "bg-mode-line-inactive" }
69−"ui.statusline.normal" = { fg = "blue-warmer" }
70−"ui.statusline.insert" = { fg = "green-warmer" }
71−"ui.statusline.select" = { fg = "magenta-warmer" }
72−
73−"ui.popup" = { fg = "fg-main", bg = "bg-dim" }
74−"ui.window" = { fg = "fg-dim" }
75−"ui.help" = { fg = "fg-main", bg = "bg-dim" }
76−"ui.gutter" = { bg = "bg-dim" }
77−"ui.text" = "fg-main"
78−"ui.text.focus" = { fg = "fg-main", bg = "bg-completion", modifiers = ["bold"] }
79−"ui.text.inactive" = { fg = "fg-dim" }
80−"ui.virtual" = "bg-active"
81−"ui.virtual.ruler" = { bg = "bg-dim" }
82−"ui.virtual.inlay-hint" = { fg = "fg-dim", modifiers = ["italic"] }
83−
84−"ui.selection" = { fg = "fg-main", bg = "bg-inactive" }
85−"ui.selection.primary" = { fg = "fg-main", bg = "bg-active" }
86−
87−"ui.cursor" = { fg = "bg-main", bg = "fg-main" }
88−"ui.cursor.primary" = { fg = "bg-main", bg = "fg-dim" }
89−"ui.cursor.match" = { bg = "bg-paren-match" }
90−"ui.cursorline.primary" = { bg = "bg-hl-line" }
91−
92−"ui.highlight" = { bg = "bg-hl-line" }
93−
94−"ui.menu" = { fg = "fg-main", bg = "bg-dim" }
95−"ui.menu.selected" = { fg = "fg-main", bg = "bg-completion", modifiers = ["bold"] }
96−"ui.menu.scroll" = { fg = "fg-dim", bg = "bg-cyan-intense" }
97−
98−"diagnostic.error" = { underline = { color = "red-intense", style = "curl" } }
99−"diagnostic.warning" = { underline = { color = "yellow-intense", style = "curl" } }
100−"diagnostic.info" = { underline = { color = "cyan-intense", style = "curl" } }
101−"diagnostic.hint" = { underline = { color = "blue-intense", style = "curl" } }
102−
103−error = "red"
104−warning = "yellow-warmer"
105−info = "cyan-cooler"
106−hint = "blue-cooler"
107−
108−[palette]
109−# Basic values
110−bg-main = "#ffffff"
111−bg-dim = "#f2f2f2"
112−fg-main = "#000000"
113−fg-dim = "#595959"
114−fg-alt = "#193668"
115−bg-active = "#c4c4c4"
116−bg-inactive = "#e0e0e0"
117−
118−# Common accent foregrounds
119−red = "#a60000"
120−red-warmer = "#972500"
121−red-cooler = "#a0132f"
122−red-faint = "#7f0000"
123−red-intense = "#d00000"
124−green = "#006800"
125−green-warmer = "#316500"
126−green-cooler = "#00663f"
127−green-faint = "#2a5045"
128−green-intense = "#008900"
129−yellow = "#6f5500"
130−yellow-warmer = "#884900"
131−yellow-cooler = "#7a4f2f"
132−yellow-faint = "#624416"
133−yellow-intense = "#808000"
134−blue = "#0031a9"
135−blue-warmer = "#354fcf"
136−blue-cooler = "#0000b0"
137−blue-faint = "#003497"
138−blue-intense = "#0000ff"
139−magenta = "#721045"
140−magenta-warmer = "#8f0075"
141−magenta-cooler = "#531ab6"
142−magenta-faint = "#7c318f"
143−magenta-intense = "#dd22dd"
144−cyan = "#005e8b"
145−cyan-warmer = "#3f578f"
146−cyan-cooler = "#005f5f"
147−cyan-faint = "#005077"
148−cyan-intense = "#008899"
149−
150−# Common accent backgrounds
151−bg-red-intense = "#ff8f88"
152−bg-green-intense = "#8adf80"
153−bg-yellow-intense = "#f3d000"
154−bg-blue-intense = "#bfc9ff"
155−bg-magenta-intense = "#dfa0f0"
156−bg-cyan-intense = "#a4d5f9"
157−
158−bg-red-subtle = "#ffcfbf"
159−bg-green-subtle = "#b3fabf"
160−bg-yellow-subtle = "#fff576"
161−bg-blue-subtle = "#ccdfff"
162−bg-magenta-subtle = "#ffddff"
163−bg-cyan-subtle = "#bfefff"
164−
165−bg-red-nuanced = "#fff1f0"
166−bg-green-nuanced = "#ecf7ed"
167−bg-yellow-nuanced = "#fff3da"
168−bg-blue-nuanced = "#f3f3ff"
169−bg-magenta-nuanced = "#fdf0ff"
170−bg-cyan-nuanced = "#ebf6fa"
171−
172−# Special purpose
173−bg-completion = "#c0deff"
174−bg-hl-line = "#dae5ec"
175−
176−bg-mode-line-active = "#c8c8c8"
177−fg-mode-line-active = "#000000"
178−bg-mode-line-inactive = "#e6e6e6"
179−fg-mode-line-inactive = "#585858"
180−
181−modeline-err = "#7f0000"
182−modeline-warning = "#5f0070"
183−modeline-info = "#002580"
184−
185−# Diffs
186−bg-added = "#c1f2d1"
187−fg-added = "#005000"
188−bg-changed = "#ffdfa9"
189−fg-changed = "#553d00"
190−bg-removed = "#ffd8d5"
191−fg-removed = "#8f1313"
192−
193−# Paren match
194−bg-paren-match = "#5fcfff"
runtime/themes/modus_operandi_deuteranopia.tomldeleted−46
@@ -1,46 +0,0 @@
1−# Author: Alexis Mousset <contact@amousset.me>
2−# modus_operandi.toml variant
3−#
4−# This variant is optimized for users with red-green color deficiency (deuteranopia)
5−
6−inherits = "modus_operandi"
7−
8−"constant.character.escape" = "magenta"
9−"comment" = "yellow-cooler"
10−"function" = "magenta"
11−"tag" = "magenta"
12−
13−"ui.cursor" = { fg = "bg-main", bg = "blue-intense" }
14−"ui.cursor.primary.normal" = { fg = "bg-main", bg = "blue-intense" }
15−
16−"diagnostic.error" = { underline = { color = "yellow-intense", style = "curl" } }
17−"diagnostic.warning" = { underline = { color = "magenta-faint", style = "curl" } }
18−"diagnostic.info" = { underline = { color = "cyan", style = "curl" } }
19−"diagnostic.hint" = { underline = { color = "blue", style = "curl" } }
20−
21−error = "yellow-intense"
22−warning = "magenta-faint"
23−info = "cyan"
24−hint = "blue"
25−
26−[palette]
27−
28−yellow = "#695500"
29−yellow-warmer = "#973300"
30−yellow-cooler = "#77492f"
31−
32−bg-mode-line-active = "#d0d6ff"
33−fg-mode-line-active = "#0f0f0f"
34−border-mode-line-active = "#4f4f74"
35−
36−modeline-err = "#603a00"
37−modeline-warning = "#454500"
38−modeline-info = "#023d92"
39−
40−# Diffs
41−bg-added = "#d5d7ff"
42−fg-added = "#303099"
43−bg-changed = "#eecfdf"
44−fg-changed = "#6f1343"
45−bg-removed = "#f4f099"
46−fg-removed = "#553d00"
runtime/themes/modus_operandi_tinted.tomldeleted−45
@@ -1,45 +0,0 @@
1−# Author: Alexis Mousset <contact@amousset.me>
2−# modus_operandi.toml variant
3−
4−inherits = "modus_operandi"
5−
6−"comment" = "red-faint"
7−
8−"ui.cursor.primary" = { fg = "bg-main", bg = "red" }
9−
10−[palette]
11−# Basic values
12−bg-main = "#fbf7f0"
13−bg-dim = "#efe9dd"
14−bg-active = "#c9b9b0"
15−bg-inactive = "#dfd5cf"
16−border = "#9f9690"
17−
18−# Common accent backgrounds
19−bg-red-nuanced = "#ffe8f0"
20−bg-green-nuanced = "#e0f5e0"
21−bg-yellow-nuanced = "#f9ead0"
22−bg-blue-nuanced = "#ebebff"
23−bg-magenta-nuanced = "#f6e7ff"
24−bg-cyan-nuanced = "#e1f3fc"
25−
26−# Special purpose
27−bg-completion = "#f0c1cf"
28−bg-hl-line = "#f1d5d0"
29−bg-region = "#c2bcb5"
30−
31−bg-mode-line-active = "#cab9b2"
32−border-mode-line-active = "#545454"
33−bg-mode-line-inactive = "#dfd9cf"
34−border-mode-line-inactive = "#a59a94"
35−
36−bg-tab-bar = "#e0d4ce"
37−bg-tab-current = "#fbf7f0"
38−bg-tab-other = "#c8b8b2"
39−
40−# Diffs
41−bg-added = "#c3ebc1"
42−bg-removed = "#f4d0cf"
43−
44−# Paren match
45−bg-paren-match = "#7fdfcf"
runtime/themes/modus_operandi_tritanopia.tomldeleted−73
@@ -1,73 +0,0 @@
1−# Author: Alexis Mousset <contact@amousset.me>
2−# modus_operandi.toml variant
3−#
4−# This variant is optimized for users with blue-yellow color deficiency (tritanopia)
5−
6−inherits = "modus_operandi"
7−
8−"type" = "blue-warmer"
9−"constructor" = "blue-warmer"
10−"constant" = "green-cooler"
11−"constant.character.escape" = "red-cooler"
12−"string" = "cyan"
13−"comment" = "red-faint"
14−"variable.parameter" = "cyan-cooler"
15−"keyword" = "red-cooler"
16−"keyword.directive" = "red-warmer"
17−"function" = "cyan-warmer"
18−"function.macro" = "magenta"
19−"tag" = "red-cooler"
20−
21−"markup.heading.2" = { fg = "red-faint", modifiers = ["bold"] }
22−"markup.heading.3" = { fg = "cyan-faint", modifiers = ["bold"] }
23−"markup.heading.6" = { fg = "magenta-faint", modifiers = ["bold"] }
24−"markup.link.url" = { fg = "cyan-cooler" }
25−"markup.link.text" = { fg = "cyan", modifiers = ["underlined"] }
26−
27−"ui.cursor" = { fg = "bg-main", bg = "red-intense" }
28−"ui.cursor.primary.normal" = { fg = "bg-main", bg = "red-intense" }
29−
30−"diagnostic.error" = { underline = { color = "red-warmer", style = "curl" } }
31−"diagnostic.warning" = { underline = { color = "magenta", style = "curl" } }
32−"diagnostic.info" = { underline = { color = "cyan", style = "curl" } }
33−"diagnostic.hint" = { underline = { color = "blue", style = "curl" } }
34−
35−error = "red-warmer"
36−warning = "magenta"
37−info = "cyan"
38−hint = "blue"
39−
40−[palette]
41−
42−# Common accent foregrounds
43−red-warmer = "#b21100"
44−red-faint = "#702000"
45−yellow = "#695500"
46−yellow-warmer = "#973300"
47−yellow-cooler = "#77492f"
48−magenta-intense = "#cd22bd"
49−cyan-faint = "#004f5f"
50−
51−# Special purpose
52−bg-completion = "#afdfef"
53−bg-hover = "#ffafbc"
54−bg-hover-secondary = "#9fdfff"
55−bg-hl-line = "#dfeaec"
56−
57−bg-char-0 = "#ff908f"
58−bg-char-1 = "#bfbfff"
59−bg-char-2 = "#5fcfdf"
60−
61−bg-mode-line-active = "#afe0f2"
62−fg-mode-line-active = "#0f0f0f"
63−border-mode-line-active = "#2f4f44"
64−
65−modeline-err = "#8f0000"
66−modeline-warning = "#6f306f"
67−modeline-info = "#00445f"
68−
69−# Diffs
70−bg-added = "#b5e7ff"
71−fg-added = "#005079"
72−bg-changed = "#eecfdf"
73−fg-changed = "#6f1343"
runtime/themes/modus_vivendi.tomldeleted−242
@@ -1,242 +0,0 @@
1−# Author: Matous Dzivjak <matousdzivjak@gmail.com>
2−# Adapted from https://protesilaos.com/emacs/modus-themes, by Protesilaos Stavrou
3−# Source: https://github.com/protesilaos/modus-themes/blob/main/modus-vivendi-theme.el
4−# Version 4.3.0
5−
6−# Syntax highlighting
7−# -------------------
8−"type" = "cyan-cooler"
9−"constructor" = "cyan-cooler"
10−
11−"constant" = "blue-cooler"
12−"constant.character.escape" = "magenta"
13−
14−"string" = "blue-warmer"
15−"string.regexp" = "magenta-faint"
16−"string.special" = "blue-faint" # used for colors in CSS
17−
18−"comment" = "fg-dim"
19−
20−"variable.parameter" = "cyan"
21−"variable.builtin" = "magenta-cooler"
22−"label" = "fg-dim" # used for language in markdown code blocks
23−"keyword" = "magenta-cooler"
24−"keyword.directive" = "red-cooler"
25−"function" = "magenta"
26−"function.macro" = "magenta-warmer"
27−
28−punctuation = "fg-dim"
29−"tag" = "magenta"
30−"attribute" = "cyan-cooler"
31−"namespace" = "blue-cooler"
32−"special" = "red-cooler"
33−
34−"markup.heading.marker" = "fg-dim"
35−"markup.heading.1" = { fg = "fg-main", modifiers = ["bold"] }
36−"markup.heading.2" = { fg = "yellow-faint", modifiers = ["bold"] }
37−"markup.heading.3" = { fg = "fg-alt", modifiers = ["bold"] }
38−"markup.heading.4" = { fg = "magenta", modifiers = ["bold"] }
39−"markup.heading.5" = { fg = "green-faint", modifiers = ["bold"] }
40−"markup.heading.6" = { fg = "red-faint", modifiers = ["bold"] }
41−"markup.list" = "fg-dim"
42−"markup.list.checked" = { fg = "yellow-warmer" }
43−"markup.list.unchecked" = { fg = "yellow-warmer" }
44−"markup.bold" = { modifiers = ["bold"] }
45−"markup.italic" = { modifiers = ["italic"] }
46−"markup.strikethrough" = { modifiers = ["crossed_out"] }
47−"markup.link.url" = { fg = "cyan" }
48−"markup.link.text" = { fg = "blue-warmer", modifiers = ["underlined"] }
49−"markup.raw.block" = { bg = "bg-dim" }
50−"markup.raw.inline" = { fg = "green-cooler" }
51−
52−"diff.plus" = { fg = "fg-added", bg = "bg-added" }
53−"diff.plus.gutter" = "green-intense"
54−"diff.minus" = { fg = "fg-removed", bg = "bg-removed" }
55−"diff.minus.gutter" = "red-intense"
56−"diff.delta" = { fg = "fg-changed", bg = "bg-changed" }
57−"diff.delta.gutter" = "yellow-intense"
58−
59−# User Interface
60−# --------------
61−
62−"ui.background" = { bg = "bg-main" }
63−
64−"ui.linenr" = { fg = "fg-dim", bg = "bg-dim" }
65−"ui.linenr.selected" = { fg = "fg-main", bg = "bg-active" }
66−
67−"ui.statusline" = { fg = "fg-mode-line-active", bg = "bg-mode-line-active" }
68−"ui.statusline.inactive" = { fg = "fg-mode-line-inactive", bg = "bg-mode-line-inactive" }
69−"ui.statusline.normal" = { fg = "blue-warmer" }
70−"ui.statusline.insert" = { fg = "green-warmer" }
71−"ui.statusline.select" = { fg = "magenta-warmer" }
72−
73−"ui.bufferline" = { bg = "bg-tab-bar" }
74−"ui.bufferline.active" = { bg = "bg-tab-current", fg = "fg-mode-line-active" }
75−
76−"ui.popup" = { fg = "fg-main", bg = "bg-dim" }
77−"ui.window" = { fg = "fg-dim" }
78−"ui.help" = { fg = "fg-main", bg = "bg-dim" }
79−"ui.gutter" = { bg = "bg-dim" }
80−"ui.text" = "fg-main"
81−"ui.text.focus" = { fg = "fg-main", bg = "bg-completion", modifiers = ["bold"] }
82−"ui.text.inactive" = { fg = "fg-dim" }
83−"ui.virtual" = "bg-active"
84−"ui.virtual.ruler" = { bg = "bg-dim" }
85−"ui.virtual.inlay-hint" = { fg = "fg-dim", modifiers = ["italic"] }
86−
87−"ui.selection" = { fg = "fg-main", bg = "bg-inactive" }
88−"ui.selection.primary" = { fg = "fg-main", bg = "bg-active" }
89−
90−"ui.cursor" = { fg = "bg-main", bg = "fg-main" }
91−"ui.cursor.primary" = { fg = "bg-main", bg = "fg-dim" }
92−"ui.cursor.match" = { bg = "bg-paren-match" }
93−"ui.cursorline.primary" = { bg = "bg-hl-line" }
94−
95−"ui.highlight" = { bg = "bg-hl-line" }
96−
97−"ui.menu" = { fg = "fg-main", bg = "bg-dim" }
98−"ui.menu.selected" = { fg = "fg-main", bg = "bg-completion", modifiers = ["bold"] }
99−"ui.menu.scroll" = { fg = "fg-dim", bg = "bg-cyan-intense" }
100−
101−"diagnostic.error" = { underline = { color = "red-intense", style = "curl" } }
102−"diagnostic.warning" = { underline = { color = "yellow-intense", style = "curl" } }
103−"diagnostic.info" = { underline = { color = "cyan-intense", style = "curl" } }
104−"diagnostic.hint" = { underline = { color = "blue-intense", style = "curl" } }
105−
106−error = "red"
107−warning = "yellow-warmer"
108−info = "cyan-cooler"
109−hint = "blue-cooler"
110−
111−[palette]
112−# Basic values
113−bg-main = "#000000"
114−bg-dim = "#1e1e1e"
115−fg-main = "#ffffff"
116−fg-dim = "#989898"
117−fg-alt = "#c6daff"
118−bg-active = "#535353"
119−bg-inactive = "#303030"
120−
121−# Common accent foregrounds
122−red = "#ff5f59"
123−red-warmer = "#ff6b55"
124−red-cooler = "#ff7f9f"
125−red-faint = "#ff9580"
126−red-intense = "#ff5f5f"
127−green = "#44bc44"
128−green-warmer = "#70b900"
129−green-cooler = "#00c06f"
130−green-faint = "#88ca9f"
131−green-intense = "#44df44"
132−yellow = "#d0bc00"
133−yellow-warmer = "#fec43f"
134−yellow-cooler = "#dfaf7a"
135−yellow-faint = "#d2b580"
136−yellow-intense = "#efef00"
137−blue = "#2fafff"
138−blue-warmer = "#79a8ff"
139−blue-cooler = "#00bcff"
140−blue-faint = "#82b0ec"
141−blue-intense = "#338fff"
142−magenta = "#feacd0"
143−magenta-warmer = "#f78fe7"
144−magenta-cooler = "#b6a0ff"
145−magenta-faint = "#caa6df"
146−magenta-intense = "#ff66ff"
147−cyan = "#00d3d0"
148−cyan-warmer = "#4ae2f0"
149−cyan-cooler = "#6ae4b9"
150−cyan-faint = "#9ac8e0"
151−cyan-intense = "#00eff0"
152−
153−# Uncommon accent foregrounds
154−rust = "#db7b5f"
155−gold = "#c0965b"
156−olive = "#9cbd6f"
157−slate = "#76afbf"
158−indigo = "#9099d9"
159−maroon = "#cf7fa7"
160−pink = "#d09dc0"
161−
162−# Common accent backgrounds
163−bg-red-intense = "#9d1f1f"
164−bg-green-intense = "#2f822f"
165−bg-yellow-intense = "#7a6100"
166−bg-blue-intense = "#1640b0"
167−bg-magenta-intense = "#7030af"
168−bg-cyan-intense = "#2266ae"
169−
170−bg-red-subtle = "#620f2a"
171−bg-green-subtle = "#00422a"
172−bg-yellow-subtle = "#4a4000"
173−bg-blue-subtle = "#242679"
174−bg-magenta-subtle = "#552f5f"
175−bg-cyan-subtle = "#004065"
176−
177−bg-red-nuanced = "#2c0614"
178−bg-green-nuanced = "#001904"
179−bg-yellow-nuanced = "#221000"
180−bg-blue-nuanced = "#0f0e39"
181−bg-magenta-nuanced = "#230631"
182−bg-cyan-nuanced = "#041529"
183−
184−# Uncommon accent backgrounds
185−bg-ochre = "#442c2f"
186−bg-lavender = "#38325c"
187−bg-sage = "#0f3d30"
188−
189−# Special purpose
190−bg-completion = "#2f447f"
191−bg-hover = "#45605e"
192−bg-hover-secondary = "#654a39"
193−bg-hl-line = "#2f3849"
194−bg-region = "#5a5a5a"
195−fg-region = "#ffffff"
196−
197−bg-char-0 = "#0050af"
198−bg-char-1 = "#7f1f7f"
199−bg-char-2 = "#625a00"
200−
201−bg-mode-line-active = "#505050"
202−fg-mode-line-active = "#ffffff"
203−border-mode-line-active = "#959595"
204−bg-mode-line-inactive = "#2d2d2d"
205−fg-mode-line-inactive = "#969696"
206−border-mode-line-inactive = "#606060"
207−
208−modeline-err = "#ffa9bf"
209−modeline-warning = "#dfcf43"
210−modeline-info = "#9fefff"
211−
212−bg-tab-bar = "#313131"
213−bg-tab-current = "#000000"
214−bg-tab-other = "#545454"
215−
216−# Diffs
217−bg-added = "#00381f"
218−bg-added-faint = "#002910"
219−bg-added-refine = "#034f2f"
220−bg-added-fringe = "#237f3f"
221−fg-added = "#a0e0a0"
222−fg-added-intense = "#80e080"
223−
224−bg-changed = "#363300"
225−bg-changed-faint = "#2a1f00"
226−bg-changed-refine = "#4a4a00"
227−bg-changed-fringe = "#8a7a00"
228−fg-changed = "#efef80"
229−fg-changed-intense = "#c0b05f"
230−
231−bg-removed = "#4f1119"
232−bg-removed-faint = "#380a0f"
233−bg-removed-refine = "#781a1f"
234−bg-removed-fringe = "#b81a1f"
235−fg-removed = "#ffbfbf"
236−fg-removed-intense = "#ff9095"
237−
238−bg-diff-context = "#1a1a1a"
239−
240−# Paren match
241−bg-paren-match = "#2f7f9f"
242−tg-paren-expression = "#453040"
runtime/themes/modus_vivendi_deuteranopia.tomldeleted−158
@@ -1,158 +0,0 @@
1−# Author: Matous Dzivjak <matousdzivjak@gmail.com>
2−# Adapted from https://protesilaos.com/emacs/modus-themes, by Protesilaos Stavrou
3−# Source: https://github.com/protesilaos/modus-themes/blob/main/modus-vivendi-deuteranopia-theme.el
4−# Version 4.3.0
5−
6−inherits = "modus_vivendi"
7−
8−"constant.character.escape" = "magenta"
9−"comment" = "yellow-cooler"
10−"function" = "magenta"
11−"tag" = "magenta"
12−
13−"ui.cursor" = { fg = "bg-main", bg = "blue-intense" }
14−"ui.cursor.primary.normal" = { fg = "bg-main", bg = "blue-intense" }
15−
16−"diagnostic.error" = { underline = { color = "yellow-intense", style = "curl" } }
17−"diagnostic.warning" = { underline = { color = "magenta-faint", style = "curl" } }
18−"diagnostic.info" = { underline = { color = "cyan", style = "curl" } }
19−"diagnostic.hint" = { underline = { color = "blue", style = "curl" } }
20−
21−error = "yellow-intense"
22−warning = "magenta-faint"
23−info = "cyan"
24−hint = "blue"
25−
26−[palette]
27−# Basic values
28−bg-main = "#000000"
29−bg-dim = "#1e1e1e"
30−fg-main = "#ffffff"
31−fg-dim = "#989898"
32−fg-alt = "#c6daff"
33−bg-active = "#535353"
34−bg-inactive = "#303030"
35−border = "#646464"
36−
37−# Common accent foregrounds
38−red = "#ff5f59"
39−red-warmer = "#ff6b55"
40−red-cooler = "#ff7f9f"
41−red-faint = "#ff9580"
42−red-intense = "#ff5f5f"
43−green = "#44bc44"
44−green-warmer = "#70b900"
45−green-cooler = "#00c06f"
46−green-faint = "#88ca9f"
47−green-intense = "#44df44"
48−yellow = "#cabf00"
49−yellow-warmer = "#ffa00f"
50−yellow-cooler = "#d8af7a"
51−yellow-faint = "#d2b580"
52−yellow-intense = "#efef00"
53−blue = "#2fafff"
54−blue-warmer = "#79a8ff"
55−blue-cooler = "#00bcff"
56−blue-faint = "#82b0ec"
57−blue-intense = "#338fff"
58−magenta = "#feacd0"
59−magenta-warmer = "#f78fe7"
60−magenta-cooler = "#b6a0ff"
61−magenta-faint = "#caa6df"
62−magenta-intense = "#ff66ff"
63−cyan = "#00d3d0"
64−cyan-warmer = "#4ae2f0"
65−cyan-cooler = "#6ae4b9"
66−cyan-faint = "#9ac8e0"
67−cyan-intense = "#00eff0"
68−
69−# Uncommon accent foregrounds
70−rust = "#db7b5f"
71−gold = "#c0965b"
72−olive = "#9cbd6f"
73−slate = "#76afbf"
74−indigo = "#9099d9"
75−maroon = "#cf7fa7"
76−pink = "#d09dc0"
77−
78−# Common accent backgrounds
79−bg-red-intense = "#9d1f1f"
80−bg-green-intense = "#2f822f"
81−bg-yellow-intense = "#7a6100"
82−bg-blue-intense = "#1640b0"
83−bg-magenta-intense = "#7030af"
84−bg-cyan-intense = "#2266ae"
85−
86−bg-red-subtle = "#620f2a"
87−bg-green-subtle = "#00422a"
88−bg-yellow-subtle = "#4a4000"
89−bg-blue-subtle = "#242679"
90−bg-magenta-subtle = "#552f5f"
91−bg-cyan-subtle = "#004065"
92−
93−bg-red-nuanced = "#2c0614"
94−bg-green-nuanced = "#001904"
95−bg-yellow-nuanced = "#221000"
96−bg-blue-nuanced = "#0f0e39"
97−bg-magenta-nuanced = "#230631"
98−bg-cyan-nuanced = "#041529"
99−
100−# Uncommon accent backgrounds
101−bg-ochre = "#442c2f"
102−bg-lavender = "#38325c"
103−bg-sage = "#0f3d30"
104−
105−# Special purpose
106−bg-completion = "#2f447f"
107−bg-hover = "#45605e"
108−bg-hover-secondary = "#654a39"
109−bg-hl-line = "#2f3849"
110−bg-region = "#5a5a5a"
111−fg-region = "#ffffff"
112−
113−bg-char-0 = "#0050af"
114−bg-char-1 = "#7f1f7f"
115−bg-char-2 = "#625a00"
116−
117−bg-mode-line-active = "#2a2a6a"
118−fg-mode-line-active = "#f0f0f0"
119−border-mode-line-active = "#8080a7"
120−bg-mode-line-inactive = "#2d2d2d"
121−fg-mode-line-inactive = "#969696"
122−border-mode-line-inactive = "#606060"
123−
124−modeline-err = "#e5bf00"
125−modeline-warning = "#c0cf35"
126−modeline-info = "#abeadf"
127−
128−bg-tab-bar = "#313131"
129−bg-tab-current = "#000000"
130−bg-tab-other = "#545454"
131−
132−# Diffs
133−bg-added = "#003066"
134−bg-added-faint = "#001a4f"
135−bg-added-refine = "#0f4a77"
136−bg-added-fringe = "#006fff"
137−fg-added = "#c4d5ff"
138−fg-added-intense = "#8080ff"
139−
140−bg-changed = "#2f123f"
141−bg-changed-faint = "#1f022f"
142−bg-changed-refine = "#3f325f"
143−bg-changed-fringe = "#7f55a0"
144−fg-changed = "#e3cfff"
145−fg-changed-intense = "#cf9fe2"
146−
147−bg-removed = "#3d3d00"
148−bg-removed-faint = "#281f00"
149−bg-removed-refine = "#555500"
150−bg-removed-fringe = "#d0c03f"
151−fg-removed = "#d4d48f"
152−fg-removed-intense = "#d0b05f"
153−
154−bg-diff-context = "#1a1a1a"
155−
156−# Paren match
157−bg-paren-match = "#2f7f9f"
158−bg-paren-expression = "#453040"
runtime/themes/modus_vivendi_tinted.tomldeleted−144

This diff is too big to show here.

runtime/themes/modus_vivendi_tritanopia.tomldeleted−186

This diff is too big to show here.

runtime/themes/molokai.toml+1−1

This diff is too big to show here.

runtime/themes/monokai.toml−5

This diff is too big to show here.

runtime/themes/naysayer.toml+2−2

This diff is too big to show here.

runtime/themes/nightfox.toml+2−2

This diff is too big to show here.

runtime/themes/noctis.toml+26−26

This diff is too big to show here.

runtime/themes/nord-night.tomldeleted−23

This diff is too big to show here.

runtime/themes/nord.toml+13−23

This diff is too big to show here.

runtime/themes/onedark.toml−1

This diff is too big to show here.

runtime/themes/papercolor-dark.toml+116−67

This diff is too big to show here.

runtime/themes/papercolor-light.toml+103−194

This diff is too big to show here.

runtime/themes/poimandres.tomldeleted−113

This diff is too big to show here.

runtime/themes/poimandres_storm.tomldeleted−19

This diff is too big to show here.

runtime/themes/rose_pine.toml+29−31

This diff is too big to show here.

runtime/themes/starlight.tomldeleted−113

This diff is too big to show here.

runtime/themes/zenburn.toml+1−1

This diff is too big to show here.

runtime/tutor+3−157

This diff is too big to show here.

rust-toolchain.toml+2−2

This diff is too big to show here.

xtask/Cargo.toml+6−12

This diff is too big to show here.