Compare commits

...

98 Commits

Author SHA1 Message Date
Michael Davis
e7ac2fcdec Add changelog notes for 25.01.1 (#12560) 2025-01-19 14:50:39 -06:00
Christoph Heiss
7cc93eb1c5 feat: add MERGE_MSG file glob for git-commit (#12589) 2025-01-18 12:50:03 -06:00
Michael Davis
2c09a35ccf Re-enable Hare by default (#11507) 2025-01-18 09:48:51 -06:00
Frans Skarman
954c97f2b5 Bump Spade grammar (#12583) 2025-01-18 09:43:45 -06:00
Nikita Revenco
076d8bd173 fix: surprising behaviour when changing line above a comment (#12575)
Co-authored-by: Nikita Revenco <154856872+NikitaRevenco@users.noreply.github.com>
2025-01-17 15:29:39 -06:00
Michael Davis
343397391f Remove unused variant from FormatterError
This seems to be a relic from the change which added external formatting
commands - initially it worked by writing the file in place and
reloading it. Now this error type is not possible and can be removed.
2025-01-17 11:00:37 -05:00
Michael Davis
69068770c8 Add extra logging for external formatters and formatting errors
This should help debug formatting failures when using external
formatters in the future. Previously we didn't log anything when an
external formatter failed despite having a custom error type for it.
2025-01-17 11:00:34 -05:00
Michael Davis
4c41c5250c Eliminate an unnecessary clone in insert_newline 2025-01-17 10:23:36 -05:00
Michael Davis
ffdfb59033 Fix slicing panic in path completion variable expansion (#12556) 2025-01-16 18:10:30 -06:00
janos-r
d4ee22b483 Generate a .deb file (#12453) 2025-01-16 17:37:53 -06:00
Valentin B.
29dda1403f chore(solidity): update to newest grammar and fix queries (#12457) 2025-01-16 09:11:18 -06:00
Michael Davis
19f7bc9ecb book: Add missing TOC entries to editor config page 2025-01-16 08:14:09 -05:00
Michael Davis
3318953bf6 minor: Use more exact allocations in insert_newline
This is partially a style commit:

* Pull more bindings out the `change_by_selection` closure like the
  line-ending string and the comment tokens used for continuation.
* Prefer `Editor::config` to `Document`'s config.

The rest is changes to places where `insert_newline` may allocate.

The first is to move `new_text` out of the `change_by_selection`
closure, reusing it between iterations. This is not necessarily always
an improvement as we need to clone the text for the return type of the
closure. `SmartString`'s `From<String>` implementation reuses the
allocation when the string is too long to inline and drops it if it is
short enough to inline though which can be wasteful. `From<&String>`
clones the string's allocation only when it is too long to be inlined,
so we save on allocations for any `new_text` short enough to be inlined.

The rest is changes to `new_text.reserve_exact`. Previously calls to
this function in this block mixed up character and byte indexing by
treating the length of the line-ending as 1. `reserve_exact` takes a
number of bytes to reserve and that may be 2 when `line_ending` is a
CRLF. A call to `reserve_exact` is also added to the branch used when
continuing line comments.
2025-01-15 10:57:03 -05:00
Michael Davis
4bd17e542e Fix offset tracking in insert_newline
#12177 changed `insert_newline`'s behavior to trim any trailing
whitespace on a line which came before a cursor. `insert_newline` would
previously never delete text. Even the whitespace stripping behavior in
#4854 worked by inserting text - a line ending at the beginning of the
line. `global_offs`, a variable that tracks the number of characters
inserted between iterations over the existing selection ranges, was not
updated to also account for text deleted by the trimming behavior,
causing cursors to be offset by the amount of trailing space deleted
and causing panics in some cases.

To fix this we need to subtract the number of trimmed whitespace
characters from `global_offs`. `global_offs` must become an `isize`
(was a `usize`) because it may become negative in cases where a lot of
trailing whitespace is trimmed. Integration tests have been added for
each of these cases.

Fixes #12461
Fixes #12495
Fixes #12539
2025-01-15 10:36:29 -05:00
Michael Davis
99d33c741a Add '///' to Dart comment-token configuration
Fixes #12537
2025-01-15 08:33:33 -05:00
David Else
ca19496eed Improve dark_plus theme: Change special, ui.text.directory and ui.virtual.wrap (#12530) 2025-01-14 12:55:01 -06:00
Robin Heggelund Hansen
f69659c5be Add support for the Gren programming language (#12525) 2025-01-14 08:26:56 -06:00
Michael Davis
27bb2447db Use a workspace dependency for bitflags 2025-01-13 18:26:31 -05:00
dependabot[bot]
3d772afc8b build(deps): bump the rust-dependencies group with 6 updates
Bumps the rust-dependencies group with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [thiserror](https://github.com/dtolnay/thiserror) | `2.0.9` | `2.0.11` |
| [bitflags](https://github.com/bitflags/bitflags) | `2.6.0` | `2.7.0` |
| [serde_json](https://github.com/serde-rs/json) | `1.0.134` | `1.0.135` |
| [tokio](https://github.com/tokio-rs/tokio) | `1.42.0` | `1.43.0` |
| [rustix](https://github.com/bytecodealliance/rustix) | `0.38.42` | `0.38.43` |
| [cc](https://github.com/rust-lang/cc-rs) | `1.2.7` | `1.2.9` |


Updates `thiserror` from 2.0.9 to 2.0.11
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](https://github.com/dtolnay/thiserror/compare/2.0.9...2.0.11)

Updates `bitflags` from 2.6.0 to 2.7.0
- [Release notes](https://github.com/bitflags/bitflags/releases)
- [Changelog](https://github.com/bitflags/bitflags/blob/main/CHANGELOG.md)
- [Commits](https://github.com/bitflags/bitflags/compare/2.6.0...2.7.0)

Updates `serde_json` from 1.0.134 to 1.0.135
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.134...v1.0.135)

Updates `tokio` from 1.42.0 to 1.43.0
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.42.0...tokio-1.43.0)

Updates `rustix` from 0.38.42 to 0.38.43
- [Release notes](https://github.com/bytecodealliance/rustix/releases)
- [Changelog](https://github.com/bytecodealliance/rustix/blob/main/CHANGELOG.md)
- [Commits](https://github.com/bytecodealliance/rustix/compare/v0.38.42...v0.38.43)

Updates `cc` from 1.2.7 to 1.2.9
- [Release notes](https://github.com/rust-lang/cc-rs/releases)
- [Changelog](https://github.com/rust-lang/cc-rs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/cc-rs/compare/cc-v1.2.7...cc-v1.2.9)

---
updated-dependencies:
- dependency-name: thiserror
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rust-dependencies
- dependency-name: bitflags
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: rust-dependencies
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rust-dependencies
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: rust-dependencies
- dependency-name: rustix
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rust-dependencies
- dependency-name: cc
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rust-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-13 23:09:54 +00:00
TornaxO7
60bff8feee Fix open_{below, above} behaviour with multiple cursors (#12465) 2025-01-13 08:14:30 -06:00
Taylor C. Richberger
134aebf8cc add rockspec to lua file types (#12516) 2025-01-13 07:45:38 -06:00
Álan Crístoffer
367ccc1c64 Fix a bug in matlab indentation and updates the grammar commit hash to latest (#12518) 2025-01-13 07:43:02 -06:00
Nikita Revenco
e01775a667 fix: unable to detect Color completion item hex code for some LSPs (#12501)
Co-authored-by: Nikita Revenco <154856872+NikitaRevenco@users.noreply.github.com>
2025-01-12 09:40:19 -06:00
Michael Davis
0f2ce303c5 Add directory name to :cd errors
For example `:cd README.md` would say "Not a directory" but would not
print the directory name. Now the error message includes some context
about the operation and requested directory.
2025-01-11 20:39:44 -05:00
meator
b05971f178 Add .clang-tidy highlighting (#12498) 2025-01-11 15:12:46 -06:00
Nikita Revenco
a539199666 feat(highlights): add more built-in functions for ecma, rust and haskell (#12488)
Co-authored-by: Nikita Revenco <154856872+NikitaRevenco@users.noreply.github.com>
2025-01-11 14:59:03 -06:00
Kirawi
e440e54e79 pin to ubuntu-22.04 for releases (#12464) 2025-01-11 10:52:13 -06:00
Nikita Revenco
8f5f818c88 fix(highlights): recognize ! as the never type (#12485)
Co-authored-by: Nikita Revenco <154856872+NikitaRevenco@users.noreply.github.com>
2025-01-11 10:49:39 -06:00
Michael Davis
b26903cd13 Add comment tokens for JSONC
Fixes #12491
2025-01-11 08:42:17 -05:00
Evan Richter
9721144e03 language support: CodeQL (#12470) 2025-01-10 09:03:04 -06:00
Rob Gonnella
a83c23bb03 Run formatter from Document directory (#12315)
Co-authored-by: Rob Gonnella <rob.gonnella@papayapay.com>
2025-01-08 12:36:40 -06:00
rhogenson
931dd9c1dc Fix a typo in join_selections (#12452)
Co-authored-by: Rose Hogenson <rosehogenson@posteo.net>
2025-01-08 08:42:41 -06:00
Michael Davis
917174e546 Fix blank buffer picker preview on doc with no views
Reproduction:

* `hx`
* Open any file in a split (`<space>f` and choose anything with `<C-v>`)
* Close the split with `<C-w>q`
* Open up the buffer picker and look the file you opened previously

Previously the preview was empty in this case because the Document's
`selections` hashmap was empty and we returned early, giving `None`
instead of a FileLocation. Instead when the Document is not currently
open in any view we can show the document but with no range highlighted.
2025-01-07 15:11:15 -05:00
Michael Davis
a0bd39d40e book: Document editor.lsp.display-progress-messages config option
Connects #5535
2025-01-07 09:17:59 -05:00
dependabot[bot]
e698b20245 build(deps): bump the rust-dependencies group with 3 updates (#12437) 2025-01-06 19:34:21 -05:00
Michael Davis
5616f1d66d changelog: Add missing breaking change for display-messages config 2025-01-06 14:18:26 -05:00
Michael Davis
217818681e Revert "refactor(shellwords)!: change arg handling strategy (#11149)"
This reverts commit 64b38d1a28.
2025-01-06 12:39:53 -05:00
Michael Davis
03f35af9c1 Format '--version' calendar version as 'YY.0M'
We use calendar versioning which isn't supported by Cargo, so we need
to add an extra leading zero to the month for releases between January
and September to match our usual 'YY.0M' formatting.

Closes #12414
2025-01-06 10:34:25 -05:00
uncenter
6c9619d094 Improve markdown heading highlights (#12417) 2025-01-05 16:35:09 -06:00
uncenter
e856dde738 Use @attribute scope for JSX attributes (#12416) 2025-01-05 16:33:08 -06:00
RoloEdits
f80ae997f2 perf: cache Documents relative path (#12385) 2025-01-05 16:29:16 -06:00
RoloEdits
64b38d1a28 refactor(shellwords)!: change arg handling strategy (#11149) 2025-01-05 12:18:30 -06:00
Seigo Mori
377e36908a Add cursorline color to iceberg theme (#12404) 2025-01-05 10:58:31 -06:00
Nikita Revenco
fa4aa0fb42 docs: catppuccin themes should not be directly edited here (#12400)
Co-authored-by: uncenter <47499684+uncenter@users.noreply.github.com>
2025-01-05 10:55:28 -06:00
Nikita Revenco
2b8f8df1af feat: correct Swift highlights (#12409)
- Adds injections for the `comment` language
- Correct highlight of the `nil` value. Same highlight as `null` in javascript, java and others
- Recognize `<` and `>` as punctuation, used in generics (same color as the syntax used in other languages)
- `protocol` function methods are recognized
- When accessing object properties, like `hello.world`, the `world` is properly recognized as being a member
- Recognize the `\` as an operator
2025-01-05 10:54:45 -06:00
Nikita Revenco
eed052e86b feat: highlight : as a delimiter in Rust (#12408) 2025-01-05 10:51:33 -06:00
Erasin Wang
0654a1f058 Update onelight theme (#12399) 2025-01-05 10:27:38 -06:00
RoloEdits
353176082e doc: generate lang-support.md for teal (#12402) 2025-01-05 01:11:10 +09:00
André L. Alvares
b47b946c47 Fix Teal LSP name. (#12395) 2025-01-04 11:49:44 +09:00
Will Faught
827deba74c Change Cwd to Cmd (#12396) 2025-01-03 20:23:21 -05:00
Michael Davis
dabfb6ceea Add changelog notes for 25.01 (#12347) 2025-01-03 13:50:51 -06:00
Niza Toshpulatov
9dcc1f06b0 Add dim modifier to diagnostic.unnecessary in catppuccin_mocha.toml (#12391) 2025-01-03 08:13:44 -06:00
David Crespo
eaa7c8e9f6 docs: fix typo in usage.md (#12390) 2025-01-03 08:11:37 -06:00
Michael Davis
4817bfa003 minor: fix syntax tree pretty print test
This case needs to be adjusted for the escaping added in 38e8382b
2025-01-02 15:44:04 -05:00
Michael Davis
e0bccd2c58 tsq: Tune highlights to more closely match 24.07 release
The changes in #12148 were a bit radical - this restores some
customizations we had like using "label" for captures and not
highlighting the '#' or '?'/'!' parts differently. Also the highlighting
for predicates we do (not) support has been restored.
2025-01-02 15:37:18 -05:00
Michael Davis
38e8382b01 Escape double quotes for anonymous nodes in :tree-sitter-subtree
If the anonymous node contained a double quote it would throw off the
highlighting.
2025-01-02 15:33:48 -05:00
Darshan Kumawat
c9cc14728f Update hyprland langugauge file type. (#12384) 2025-01-02 08:39:02 -06:00
Sebastian Dörner
b1759f998d Migrate to an improved proto grammar (#12225) 2024-12-31 13:41:53 -06:00
Samuel Selleck
4a59f68a0d LSP Client: Accept floats with trailing zeros as valid JSONRPC IDs (#12376) 2024-12-31 12:45:47 -06:00
dependabot[bot]
2b4a77b9bf build(deps): bump the rust-dependencies group with 2 updates (#12371)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-31 09:12:48 -06:00
Egor Afanasin
41763b4851 Sunset theme: add ui.text.directory (#12372) 2024-12-31 09:11:33 -06:00
Matthew Taylor
bbeb99dc40 fix: Bump vento grammar revision (#12368) 2024-12-30 14:58:16 -06:00
Jean Abou Samra
9cc056e755 fix (hx --health): Don't print headers in white (#12355) 2024-12-29 10:38:28 -06:00
Karim Abou Zeid
6d07ae4f07 add uv shebang for python (#12360) 2024-12-28 20:44:26 -06:00
Michael Davis
073efe48f9 minor: Setup default keymap directly in xtask docgen
Instantiating EditorView is a lot of machinery which is unnecessary:
the default keymap is exposed through the `default` function in the
keymap module.
2024-12-28 21:42:09 -05:00
Michael Davis
127567df8e docs: Fix dead links to tree-sitter docs
tree-sitter now uses mdbook for their docs and the switch adds a chapter
number to each section, so each link to the website needs an update.
2024-12-28 09:05:48 -05:00
{{david|odenwald}}
4b288e4de7 languages: add block comment tokens for jinja and nunjucks (#12348)
Co-authored-by: David Odenwald <daod@solute.de>
2024-12-28 07:44:41 -06:00
RoloEdits
19c91dfb80 fix: string literals with format args not in format! (#12354) 2024-12-28 07:44:16 -06:00
uncenter
a5a7cff311 Improve tsq/tree-sitter-query language support (#12148) 2024-12-27 08:57:53 -06:00
0rphee
7b9b9329b9 Make git revision available for nix flake builds (#12331) 2024-12-25 11:26:53 -06:00
Michael Davis
c262fe41ab Consistently replace line-endings in paste/replace commands
Previously we replaced line-endings in pasted text to the document
line-ending for some values in paste commands. We missed the `repeat`
values in paste though and didn't do any replacement in the replace
command.

Along with this change I've refactored the replace command to avoid
intermediary collections. We previously eagerly collected the values
from the input register as a `Vec<String>` but we can avoid both of
those conversions and only allocate for the conversion to a `Tendril`.
We can also switch from `str::repeat` to a manual implementation to
avoid the intermediary conversion to a String - this avoids an extra
allocation in the common case (i.e. no count).

Fixes #12329
2024-12-25 11:38:44 -05:00
dependabot[bot]
a074129f9c build(deps): bump the rust-dependencies group with 7 updates (#12327)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
2024-12-25 10:05:50 -06:00
Bryce Berger
eda96cc285 Add diff injections for jjdescription tree-sitter (#12305) 2024-12-25 09:35:34 -06:00
DiegoDev
c63616b421 docs: Mention sudo in macports installation snippet (#12336) 2024-12-25 09:23:56 -06:00
Nikita Revenco
faf0eee3c9 feat: Highlight = and ; in .proto files (#12339) 2024-12-25 09:06:14 -06:00
Clay
a2b241eb08 chore: update tree-sitter-heex to version 0.7.0 (#12334) 2024-12-25 10:31:57 +09:00
Nikita Revenco
0fd4a4aae2 feat: Nginx support (#12309)
Co-authored-by: Denis Gruzdev <codingjerk@gmail.com>
2024-12-24 13:22:29 -06:00
Pedro Fedricci
9e77c44b38 feat(themes): add ui.text.directory to nightfox (#12328) 2024-12-23 20:26:16 -06:00
Michael Davis
ea17b9edb7 release docs: Fix git push command for the release tag
Git can be configured to push tags with `push.followTags` but this is
not the default. Pushing the tag explicitly with `git push <remote>
<tag>` is generally considered safer anyways since it only attempts to
push the desired tag.
2024-12-22 09:48:32 -05:00
Michael Davis
4f63a46e14 minor: Remove redundant condition in shell pipe trimming
`output.ends_with('\n')` implies `!output.is_empty()`

Connects #11183
2024-12-22 09:42:37 -05:00
Nikita Revenco
ac4c017165 feat: autohelp for delete, replace and add surrounds (#12262) 2024-12-22 08:17:44 -06:00
Maurice Hieronymus
b946b21b01 fix: Respect workspace-lsp-roots on doc opening (#12223)
When a new language server is started, find_lsp_workspace is called
with LanguageConfiguration::workspace_lsp_roots as the root_dirs.

This behavior is different when a new document is opened.
find_lsp_workspace is called with editor::Config::workspace_lsp_roots
which is never set.

This leads to a bug where workspace-lsp-roots is not respected when
opening a new document. This commit fixes this bug.
2024-12-22 08:08:41 -06:00
Nikita Revenco
ba6e6dc3dd Colors for items in the completion menu (#12299) 2024-12-20 10:16:15 -06:00
cornishon
a91263d604 Odin textobjects (#12302)
Co-authored-by: Adam Zadrożny <zadroznyadam@protonmail.com>
2024-12-20 09:59:28 -06:00
Ian Hobson
06d0f33c94 Add Koto language support (#12307) 2024-12-20 09:56:13 -06:00
Eduardo Rittner Coelho
eaff0c3cd6 Document diagnostic severity levels (#12306) 2024-12-20 09:47:06 -06:00
uncenter
1e9412269a Sync Catppuccin theme changes (#12304) 2024-12-20 09:43:45 -06:00
Nikita Revenco
355e381626 feat: use ui.text.directory for path completion item if its a folder (#12295) 2024-12-19 14:36:54 -06:00
Tobias Hunger
cbc06d1f15 chore: Update slint tree-sitter grammar to version 1.9 (#12297) 2024-12-19 10:16:12 -06:00
Eduardo Rittner Coelho
9e4da4b950 Show parser availability in --health [LANG] (#12228) 2024-12-18 11:21:58 -06:00
Christian Schneider
13e5a2ee5a Outdent array literals for php [] (#12286)
Co-authored-by: Christian Schneider <schneider@search.ch>
2024-12-18 08:52:20 -06:00
David Else
0134bb7063 Update dark_plus theme for inactive text and improve jump label (#12289) 2024-12-18 08:32:41 -06:00
Peter Ingram
ec65cc4913 Adds colored directories to everforest themes (#12287)
Co-authored-by: Peter Ingram <p.ingram@mrx.technology>
2024-12-18 08:31:40 -06:00
Nikita Revenco
91a5d407da Allow theming directory prompt completions (#12205) 2024-12-17 21:13:42 -06:00
Michael Davis
6eb186eb7b helix-lsp-types: use bitflags::bitflags rather than extern crate
This seems to be a historical artifact in `lsp_types` - we can use a
regular `use` statement to pull in the `bitflags!` macro rather than
an external crate definition. This fixes rust-analyzer's ability to find
the macro at least on rust-analyzer 2024-02-26.
2024-12-17 15:42:36 -05:00
Michael Davis
1980bd5992 helix-lsp-types: Prefer crate::Url to url::Url
This is a cosmetic change to replace all direct `use`s of the `url::Url`
type in the `helix-lsp-types` crate with `use crate::Url;`. The types
are the same type currently: this refactor will make a future
replacement of the Url type less noisy.

Connects https://github.com/helix-editor/helix/pull/11889
2024-12-17 15:42:28 -05:00
Tim Sampson
cc3b77b584 dockerfile: bump tree-sitter grammar to gain support for heredocs (#12230) 2024-12-17 13:26:49 -06:00
Christian Schneider
fcded6ce1e Trim trailing colons from paths to allow copy/pasting git grep -n output (#9963)
Co-authored-by: Christian Schneider <schneider@search.ch>
2024-12-17 13:02:06 -06:00
114 changed files with 2643 additions and 591 deletions

View File

@@ -61,17 +61,17 @@ jobs:
build: [x86_64-linux, x86_64-macos, x86_64-windows] #, x86_64-win-gnu, win32-msvc build: [x86_64-linux, x86_64-macos, x86_64-windows] #, x86_64-win-gnu, win32-msvc
include: include:
- build: x86_64-linux - build: x86_64-linux
os: ubuntu-latest os: ubuntu-22.04
rust: stable rust: stable
target: x86_64-unknown-linux-gnu target: x86_64-unknown-linux-gnu
cross: false cross: false
- build: aarch64-linux - build: aarch64-linux
os: ubuntu-latest os: ubuntu-22.04
rust: stable rust: stable
target: aarch64-unknown-linux-gnu target: aarch64-unknown-linux-gnu
cross: true cross: true
# - build: riscv64-linux # - build: riscv64-linux
# os: ubuntu-latest # os: ubuntu-22.04
# rust: stable # rust: stable
# target: riscv64gc-unknown-linux-gnu # target: riscv64gc-unknown-linux-gnu
# cross: true # cross: true
@@ -147,16 +147,8 @@ jobs:
if: "!matrix.skip_tests" if: "!matrix.skip_tests"
run: ${{ env.CARGO }} test --release --locked --target ${{ matrix.target }} --workspace run: ${{ env.CARGO }} test --release --locked --target ${{ matrix.target }} --workspace
- name: Set profile.release.strip = true
shell: bash
run: |
cat >> .cargo/config.toml <<EOF
[profile.release]
strip = true
EOF
- name: Build release binary - name: Build release binary
run: ${{ env.CARGO }} build --release --locked --target ${{ matrix.target }} run: ${{ env.CARGO }} build --profile opt --locked --target ${{ matrix.target }}
- name: Build AppImage - name: Build AppImage
shell: bash shell: bash
@@ -183,7 +175,7 @@ jobs:
mkdir -p "$APP.AppDir"/usr/{bin,lib/helix} mkdir -p "$APP.AppDir"/usr/{bin,lib/helix}
cp "target/${{ matrix.target }}/release/hx" "$APP.AppDir/usr/bin/hx" cp "target/${{ matrix.target }}/opt/hx" "$APP.AppDir/usr/bin/hx"
rm -rf runtime/grammars/sources rm -rf runtime/grammars/sources
cp -r runtime "$APP.AppDir/usr/lib/helix/runtime" cp -r runtime "$APP.AppDir/usr/lib/helix/runtime"
@@ -206,14 +198,25 @@ jobs:
mv "$APP-$VERSION-$ARCH.AppImage" \ mv "$APP-$VERSION-$ARCH.AppImage" \
"$APP-$VERSION-$ARCH.AppImage.zsync" dist "$APP-$VERSION-$ARCH.AppImage.zsync" dist
- name: Build Deb
shell: bash
if: matrix.build == 'x86_64-linux'
run: |
cargo install cargo-deb
mkdir -p target/release
cp target/${{ matrix.target }}/opt/hx target/release/
cargo deb --no-build
mkdir -p dist
mv target/debian/*.deb dist/
- name: Build archive - name: Build archive
shell: bash shell: bash
run: | run: |
mkdir -p dist mkdir -p dist
if [ "${{ matrix.os }}" = "windows-2019" ]; then if [ "${{ matrix.os }}" = "windows-2019" ]; then
cp "target/${{ matrix.target }}/release/hx.exe" "dist/" cp "target/${{ matrix.target }}/opt/hx.exe" "dist/"
else else
cp "target/${{ matrix.target }}/release/hx" "dist/" cp "target/${{ matrix.target }}/opt/hx" "dist/"
fi fi
if [ -d runtime/grammars/sources ]; then if [ -d runtime/grammars/sources ]; then
rm -rf runtime/grammars/sources rm -rf runtime/grammars/sources
@@ -241,6 +244,7 @@ jobs:
set -ex set -ex
source="$(pwd)" source="$(pwd)"
tag=${GITHUB_REF_NAME//\//}
mkdir -p runtime/grammars/sources mkdir -p runtime/grammars/sources
tar xJf grammars/grammars.tar.xz -C runtime/grammars/sources tar xJf grammars/grammars.tar.xz -C runtime/grammars/sources
rm -rf grammars rm -rf grammars
@@ -254,7 +258,7 @@ jobs:
if [[ $platform =~ "windows" ]]; then if [[ $platform =~ "windows" ]]; then
exe=".exe" exe=".exe"
fi fi
pkgname=helix-$GITHUB_REF_NAME-$platform pkgname=helix-$tag-$platform
mkdir -p $pkgname mkdir -p $pkgname
cp $source/LICENSE $source/README.md $pkgname cp $source/LICENSE $source/README.md $pkgname
mkdir $pkgname/contrib mkdir $pkgname/contrib
@@ -265,6 +269,7 @@ jobs:
if [[ "$platform" = "x86_64-linux" ]]; then if [[ "$platform" = "x86_64-linux" ]]; then
mv bins-$platform/helix-*.AppImage* dist/ mv bins-$platform/helix-*.AppImage* dist/
mv bins-$platform/*.deb dist/
fi fi
if [ "$exe" = "" ]; then if [ "$exe" = "" ]; then
@@ -274,7 +279,7 @@ jobs:
fi fi
done done
tar cJf dist/helix-$GITHUB_REF_NAME-source.tar.xz -C $source . tar cJf dist/helix-$tag-source.tar.xz -C $source .
mv dist $source/ mv dist $source/
- name: Upload binaries to release - name: Upload binaries to release

View File

@@ -1,3 +1,302 @@
<!--
# YY.0M (YYYY-0M-0D)
Breaking changes:
Features:
Commands:
Usability improvements:
Fixes:
Themes:
New languages:
Updated languages and queries:
Packaging:
-->
# 25.01.1 (2025-01-19)
25.01.1 is a patch release focusing on fixing bugs and panics from changes in 25.01.
Usability improvements:
* Run external formatters from the document's directory ([#12315](https://github.com/helix-editor/helix/pull/12315))
Fixes:
* Fix blank buffer picker preview on doc with no views ([917174e](https://github.com/helix-editor/helix/commit/917174e))
* Fix `join_selections` behavior on tabs ([#12452](https://github.com/helix-editor/helix/pull/12452))
* Fix recognition for color LSP completion hex codes for some language servers ([#12501](https://github.com/helix-editor/helix/pull/12501))
* Fix offsets to selections updated by `open_below`/`open_above` (`o`/`O`) in multi-cursor scenarios ([#12465](https://github.com/helix-editor/helix/pull/12465))
* Fix offsets to selections updated by `insert_newline` when trimming whitespace in multi-cursor scenarios ([4bd17e5](https://github.com/helix-editor/helix/commit/4bd17e5))
* Fix panic in path completion from resolving variables like `${HOME:-$HOME}` ([#12556](https://github.com/helix-editor/helix/pull/12556))
* Prevent line comment continuation when using `change_selection` (`c`) on a line above a comment ([#12575](https://github.com/helix-editor/helix/pull/12575))
Themes:
* Update `onelight` ([#12399](https://github.com/helix-editor/helix/pull/12399))
* Add cursorline color to iceberg themes ([#12404](https://github.com/helix-editor/helix/pull/12404))
* Update `special`, `ui.text.directory` and `ui.virtual.wrap` in `dark_plus` ([#12530](https://github.com/helix-editor/helix/pull/12530))
New languages:
* CodeQL ([#12470](https://github.com/helix-editor/helix/pull/12470))
* Gren ([#12525](https://github.com/helix-editor/helix/pull/12525))
Updated languages and queries:
* Fix Teal LSP name ([#12395](https://github.com/helix-editor/helix/pull/12395))
* Highlight `:` in Rust as a delimiter ([#12408](https://github.com/helix-editor/helix/pull/12408))
* Update Swift highlights ([#12409](https://github.com/helix-editor/helix/pull/12409))
* Highlight JSX attributes as `@attribute` ([#12416](https://github.com/helix-editor/helix/pull/12416))
* Improve markdown heading highlights ([#12417](https://github.com/helix-editor/helix/pull/12417))
* Add comment tokens configuration for JSONC ([b26903c](https://github.com/helix-editor/helix/commit/b26903c))
* Highlight the never type `!` as a type in Rust ([#12485](https://github.com/helix-editor/helix/pull/12485))
* Expand builtin function highlights for ECMA languages, Rust and Haskell ([#12488](https://github.com/helix-editor/helix/pull/12488))
* Recognize `.clang-tidy` as YAML ([#12498](https://github.com/helix-editor/helix/pull/12498))
* Update MATLAB grammar and indent queries ([#12518](https://github.com/helix-editor/helix/pull/12518))
* Recognize `rockspec` as Lua ([#12516](https://github.com/helix-editor/helix/pull/12516))
* Add `///` to Dart comment tokens configuration ([99d33c7](https://github.com/helix-editor/helix/commit/99d33c7))
* Update Solidity grammar and queries ([#12457](https://github.com/helix-editor/helix/pull/12457))
* Update Spade grammar and queries ([#12583](https://github.com/helix-editor/helix/pull/12583))
* Re-enable Hare fetching and building by default ([#11507](https://github.com/helix-editor/helix/pull/11507))
Packaging:
* `--version` now prints a leading zero for single-digit months, for example `25.01` (03f35af)
* Pin the Ubuntu GitHub Actions runners used for releases to `ubuntu-22.04` ([#12464](https://github.com/helix-editor/helix/pull/12464))
* Produce a Debian package (`.deb` file) in the release GitHub Actions workflow ([#12453](https://github.com/helix-editor/helix/pull/12453))
# 25.01 (2025-01-03)
As always, a big thank you to all of the contributors! This release saw changes from 171 contributors.
Breaking changes:
* The `editor.lsp.display-messages` key now controls messages sent with the LSP `window/showMessage` notification rather than progress messages. If you want to enable progress messages you should now enable the `editor.lsp.display-progress-messages` key instead. ([#5535](https://github.com/helix-editor/helix/pull/5535))
Features:
* Big refactor for `Picker`s ([#9647](https://github.com/helix-editor/helix/pull/9647), [#11209](https://github.com/helix-editor/helix/pull/11209), [#11216](https://github.com/helix-editor/helix/pull/11216), [#11211](https://github.com/helix-editor/helix/pull/11211), [#11343](https://github.com/helix-editor/helix/pull/11343), [#11406](https://github.com/helix-editor/helix/pull/11406))
* Use a table layout and allow filtering by column
* Reimplement `global_search` to allow changing the query dynamically
* Add an alternative "inline" display for LSP diagnostics ([#6417](https://github.com/helix-editor/helix/pull/6417), [#11815](https://github.com/helix-editor/helix/pull/11815))
* Support defining keybindings as macros ([#4709](https://github.com/helix-editor/helix/pull/4709))
* Continue line comments in `o`/`O` and on `<ret>` in insert mode ([#10996](https://github.com/helix-editor/helix/pull/10996), [#12213](https://github.com/helix-editor/helix/pull/12213), [#12215](https://github.com/helix-editor/helix/pull/12215))
* Allow configuring and switching clipboard providers at runtime ([#10839](https://github.com/helix-editor/helix/pull/10839), [b855cd0](https://github.com/helix-editor/helix/commit/b855cd0), [467fad5](https://github.com/helix-editor/helix/commit/467fad5), [191b0f0](https://github.com/helix-editor/helix/commit/191b0f0))
* Add support for path completion ([#2608](https://github.com/helix-editor/helix/pull/2608))
* Support bindings with the Super (Cmd/Win/Meta) modifier ([#6592](https://github.com/helix-editor/helix/pull/6592))
* Support rendering and jumping between tabstops in snippet completions ([#9801](https://github.com/helix-editor/helix/pull/9801))
* Allow theming directory completions ([#12205](https://github.com/helix-editor/helix/pull/12205), [#12295](https://github.com/helix-editor/helix/pull/12295))
Commands:
* Add commands to move within snake_case or camelCase words ([#8147](https://github.com/helix-editor/helix/pull/8147))
* Add `search_selection_detect_word_boundaries` ([#12126](https://github.com/helix-editor/helix/pull/12126))
* This command takes the `*` key in normal and select mode, replacing `search_selection` which was moved to `A-*`.
Usability improvements:
* Add `:edit` and `:e` aliases for `:open` ([#11186](https://github.com/helix-editor/helix/pull/11186), [#11196](https://github.com/helix-editor/helix/pull/11196))
* Trim trailing newline from pipe command outputs when the input doesn't have a trailing newline ([#11183](https://github.com/helix-editor/helix/pull/11183), [4f63a46](https://github.com/helix-editor/helix/commit/4f63a46))
* Add `:mv` alias for `:move` ([#11256](https://github.com/helix-editor/helix/pull/11256))
* Return document display name instead of absolute path from the `%` special register ([#11275](https://github.com/helix-editor/helix/pull/11275))
* Track view position on a per-view instead of per-document basis ([#10559](https://github.com/helix-editor/helix/pull/10559))
* Improve scrolloff calculation to leave a gap in the middle ([#11323](https://github.com/helix-editor/helix/pull/11323))
* Show a popup for stderr printed by failed `:sh` commands ([#11239](https://github.com/helix-editor/helix/pull/11239))
* Add statusline errors when nothing is selected with `s`, `K`, `A-K` ([#11370](https://github.com/helix-editor/helix/pull/11370))
* Add `.svn` as a workspace root marker ([#11429](https://github.com/helix-editor/helix/pull/11429))
* Trim the end of `:sh` outputs ([#11161](https://github.com/helix-editor/helix/pull/11161))
* Show LSP `window/showMessage` messages in the statusline ([#5535](https://github.com/helix-editor/helix/pull/5535))
* Support finding workspace directories via `.jj` directories ([#11685](https://github.com/helix-editor/helix/pull/11685))
* Join single-line comments with `join_selections` (`J`) ([#11742](https://github.com/helix-editor/helix/pull/11742))
* Show anonymous syntax tree nodes in `:tree-sitter-subtree` ([#11663](https://github.com/helix-editor/helix/pull/11663), [38e8382](https://github.com/helix-editor/helix/commit/38e8382))
* Save an undo checkpoint before paste in insert mode ([#8121](https://github.com/helix-editor/helix/pull/8121))
* Only break on ASCII spaces in `:reflow` ([#12048](https://github.com/helix-editor/helix/pull/12048))
* Add a `default-yank-register` config option ([#11430](https://github.com/helix-editor/helix/pull/11430))
* Show a statusline error for `:format` when a formatter is not available ([#12183](https://github.com/helix-editor/helix/pull/12183))
* Change to the home directory with `:cd` with no arguments ([#12042](https://github.com/helix-editor/helix/pull/12042))
* Change default comment token to `#` for unrecognized files ([#12080](https://github.com/helix-editor/helix/pull/12080), [#12266](https://github.com/helix-editor/helix/pull/12266), [bae6a58](https://github.com/helix-editor/helix/commit/bae6a58))
* Trim all trailing whitespace on `insert_newline` ([#12177](https://github.com/helix-editor/helix/pull/12177))
* Change to the prior directory with `:cd -` ([#12194](https://github.com/helix-editor/helix/pull/12194))
* Allow parsing `-` (with no modifiers) as a keybinding ([#12191](https://github.com/helix-editor/helix/pull/12191))
* Improve opening statusline and error messages when opening duplicate files or directories ([#12199](https://github.com/helix-editor/helix/pull/12199))
* Trim trailing colons in paths passed on the argv ([#9963](https://github.com/helix-editor/helix/pull/9963))
* Show tree-sitter parser availability in `hx --health <lang>` ([#12228](https://github.com/helix-editor/helix/pull/12228))
* Show a preview block for colors in the LSP completion menu ([#12299](https://github.com/helix-editor/helix/pull/12299))
* Add infobox help for `surround_add`, `surround_replace` and `surround_delete` ([#12262](https://github.com/helix-editor/helix/pull/12262))
Fixes:
* Respect document indentation settings in `format_selections` (`=`) ([#11169](https://github.com/helix-editor/helix/pull/11169))
* Avoid switching the current document to normal mode during an LSP `workspace/applyEdit` operation ([#11176](https://github.com/helix-editor/helix/pull/11176))
* Fix off-by-one in LSP `find_completion_range` ([#11266](https://github.com/helix-editor/helix/pull/11266))
* Prefer file-system mtime to local system time for detecting external modifications ([#11142](https://github.com/helix-editor/helix/pull/11142), [#11352](https://github.com/helix-editor/helix/pull/11352), [#11358](https://github.com/helix-editor/helix/pull/11358), [#11361](https://github.com/helix-editor/helix/pull/11361))
* Fix writing of hardlinks ([#11340](https://github.com/helix-editor/helix/pull/11340))
* Prevent language servers from being automatically restarted when stopped with `:lsp-stop` ([#11321](https://github.com/helix-editor/helix/pull/11321))
* Stable-sort LSP text edits ([#11357](https://github.com/helix-editor/helix/pull/11357))
* Fix determination of current language layer in documents with nested language injections ([#11365](https://github.com/helix-editor/helix/pull/11365))
* Fix a panic from `:move`ing a file to a new extension which starts a language server ([#11387](https://github.com/helix-editor/helix/pull/11387))
* Fix a panic from duplicating the diff gutter ([#11092](https://github.com/helix-editor/helix/pull/11092))
* Keep cursor position when exactly replacing text ([#5930](https://github.com/helix-editor/helix/pull/5930))
* Fix a panic from `jump_backward` on a newly opened split ([#11508](https://github.com/helix-editor/helix/pull/11508))
* Fix a panic from language servers sending an unknown diagnostic severity ([#11569](https://github.com/helix-editor/helix/pull/11569))
* Fix a panic when drawing at the edge of the screen ([#11737](https://github.com/helix-editor/helix/pull/11737))
* Fix git repo detection on symlinks ([#11732](https://github.com/helix-editor/helix/pull/11732))
* Fix a panic from a language server sending an out-of-range active signature index in `textDocument/signatureHelp` ([#11825](https://github.com/helix-editor/helix/pull/11825))
* Fix a panic from using `C-k` in a prompt ending in a multi-byte character ([#12237](https://github.com/helix-editor/helix/pull/12237))
* Expand tildes in paths passed to `:read` ([#12271](https://github.com/helix-editor/helix/pull/12271))
* Respect per-language `workspace-lsp-roots` configuration when opening new documents ([#12223](https://github.com/helix-editor/helix/pull/12223))
* Consistently replace line-endings in paste/replace commands ([c262fe4](https://github.com/helix-editor/helix/commit/c262fe4))
* Fix formatting in error statusline messages when inspecting variables in DAP ([#12354](https://github.com/helix-editor/helix/pull/12354))
* Fix invisible printing of headers in `--health` output on light terminals ([#12355](https://github.com/helix-editor/helix/pull/12355))
* Accept integers serialized as floats in the JSONRPC `id` field ([#12376](https://github.com/helix-editor/helix/pull/12376))
Themes:
* Bring `kanagawa` colors better in line with neovim version ([#11187](https://github.com/helix-editor/helix/pull/11187), [#11270](https://github.com/helix-editor/helix/pull/11270))
* Add `ao` ([#11063](https://github.com/helix-editor/helix/pull/11063))
* Update `dark_plus` ([#11415](https://github.com/helix-editor/helix/pull/11415))
* Add `iceberg-light` and `iceberg-dark` ([#10674](https://github.com/helix-editor/helix/pull/10674))
* Update everforest themes ([#11459](https://github.com/helix-editor/helix/pull/11459))
* Update gruvbox themes ([#11477](https://github.com/helix-editor/helix/pull/11477))
* Change primary selection cursor color for `naysayer` ([#11617](https://github.com/helix-editor/helix/pull/11617))
* Style picker column names in `horizon-dark` ([#11649](https://github.com/helix-editor/helix/pull/11649))
* Style picker column names in Darcula themes ([#11649](https://github.com/helix-editor/helix/pull/11649))
* Update diagnostics colors in `snazzy` ([#11731](https://github.com/helix-editor/helix/pull/11731))
* Update bogster themes ([#11353](https://github.com/helix-editor/helix/pull/11353))
* Highlight `keyword.storage` in `onedark` ([#11802](https://github.com/helix-editor/helix/pull/11802))
* Add `ui.virtual.jump-label` to `serika-dark` ([#11911](https://github.com/helix-editor/helix/pull/11911))
* Add `adwaita-light` ([#10869](https://github.com/helix-editor/helix/pull/10869))
* Add seoul256 themes ([#11466](https://github.com/helix-editor/helix/pull/11466))
* Add yo themes ([#11703](https://github.com/helix-editor/helix/pull/11703))
* Add `eiffel` ([#11679](https://github.com/helix-editor/helix/pull/11679))
* Add `carbonfox` ([#11558](https://github.com/helix-editor/helix/pull/11558))
* Set tags color in monokai themes ([#11917](https://github.com/helix-editor/helix/pull/11917))
* Improve readability of spacebones picker selection ([#12064](https://github.com/helix-editor/helix/pull/12064))
* Update modus themes ([#11949](https://github.com/helix-editor/helix/pull/11949))
* Use bold for statusline mode indicator in `onedarker` ([#11958](https://github.com/helix-editor/helix/pull/11958))
* Update hex themes, add a new hex theme ([#10849](https://github.com/helix-editor/helix/pull/10849))
* Add `sunset` ([#12093](https://github.com/helix-editor/helix/pull/12093))
* Add bufferline highlighting for flexoki themes ([#12146](https://github.com/helix-editor/helix/pull/12146))
* Add colors for (un)checked list items to catppuccin themes ([#12167](https://github.com/helix-editor/helix/pull/12167))
* Update `voxed` ([#9328](https://github.com/helix-editor/helix/pull/9328))
* Add `vintage` ([#9361](https://github.com/helix-editor/helix/pull/9361))
* Add directory style to everforest themes ([#12287](https://github.com/helix-editor/helix/pull/12287))
* Add inactive text and update jump label highlights in `dark_plus` ([#12289](https://github.com/helix-editor/helix/pull/12289))
* Sync changes with catppuccin themes ([#12304](https://github.com/helix-editor/helix/pull/12304))
* Add `ui.text.directory` to `nightfox` ([#12328](https://github.com/helix-editor/helix/pull/12328))
* Add `ui.text.directory` to `sunset` ([#12328](https://github.com/helix-editor/helix/pull/12328))
* Add `diagnostic.unnecessary` to Catppuccin themes ([#12391](https://github.com/helix-editor/helix/pull/12391))
New languages:
* `jjdescription` ([#11271](https://github.com/helix-editor/helix/pull/11271), [#11857](https://github.com/helix-editor/helix/pull/11857), [#12305](https://github.com/helix-editor/helix/pull/12305))
* i3wm and Sway configs ([#11424](https://github.com/helix-editor/helix/pull/11424))
* TypeSpec ([#11412](https://github.com/helix-editor/helix/pull/11412))
* jq ([#11393](https://github.com/helix-editor/helix/pull/11393))
* Thrift ([#11367](https://github.com/helix-editor/helix/pull/11367))
* Gherkin ([#11083](https://github.com/helix-editor/helix/pull/11083))
* Circom ([#11676](https://github.com/helix-editor/helix/pull/11676))
* Dune ([#11829](https://github.com/helix-editor/helix/pull/11829))
* Snakemake ([#11858](https://github.com/helix-editor/helix/pull/11858), [#11936](https://github.com/helix-editor/helix/pull/11936))
* Cylc ([#11830](https://github.com/helix-editor/helix/pull/11830))
* textproto ([#11874](https://github.com/helix-editor/helix/pull/11874))
* Spade ([#11448](https://github.com/helix-editor/helix/pull/11448), [#12276](https://github.com/helix-editor/helix/pull/12276))
* NestedText ([#11987](https://github.com/helix-editor/helix/pull/11987))
* Quint ([#11898](https://github.com/helix-editor/helix/pull/11898))
* Amber-lang ([#12021](https://github.com/helix-editor/helix/pull/12021))
* Vento ([#12147](https://github.com/helix-editor/helix/pull/12147))
* Teal ([#12081](https://github.com/helix-editor/helix/pull/12081))
* Koto ([#12307](https://github.com/helix-editor/helix/pull/12307))
* NGINX ([#12309](https://github.com/helix-editor/helix/pull/12309))
Updated languages and queries:
* Add comment injections for Hare ([#11173](https://github.com/helix-editor/helix/pull/11173))
* Improve highlights for `blade.php` files ([#11138](https://github.com/helix-editor/helix/pull/11138))
* Update tree-sitter-slint ([#11224](https://github.com/helix-editor/helix/pull/11224), [#11757](https://github.com/helix-editor/helix/pull/11757), [#12297](https://github.com/helix-editor/helix/pull/12297))
* Recognize `just` files as Just ([#11286](https://github.com/helix-editor/helix/pull/11286))
* Recognize `mdx` as Markdown ([#11122](https://github.com/helix-editor/helix/pull/11122))
* Update Just grammar and queries ([#11306](https://github.com/helix-editor/helix/pull/11306))
* Recognize `tclsh` as TCL ([#11236](https://github.com/helix-editor/helix/pull/11236))
* Update Godot grammar and queries ([#11235](https://github.com/helix-editor/helix/pull/11235))
* Update Gleam grammar and queries ([#11427](https://github.com/helix-editor/helix/pull/11427))
* Add `mesonlsp` for Meson ([#11416](https://github.com/helix-editor/helix/pull/11416))
* Update HTML highlights ([#11400](https://github.com/helix-editor/helix/pull/11400))
* Add comment textobjects for Verilog ([#11388](https://github.com/helix-editor/helix/pull/11388))
* Switch tree-sitter-just grammar ([#11380](https://github.com/helix-editor/helix/pull/11380), [#11606](https://github.com/helix-editor/helix/pull/11606), [#12141](https://github.com/helix-editor/helix/pull/12141))
* Update tree-sitter-fsharp ([#11061](https://github.com/helix-editor/helix/pull/11061))
* Add `nixd` for Nix ([#10767](https://github.com/helix-editor/helix/pull/10767))
* Highlight types and enum members from the Rust prelude ([#8535](https://github.com/helix-editor/helix/pull/8535))
* Improve textobjects for HCL, Nix ([#11513](https://github.com/helix-editor/helix/pull/11513))
* Add textobjects queries for docker-compose, dockerfile, env, git-config, hcl, hocon, prisma, SQL and YAML ([#11513](https://github.com/helix-editor/helix/pull/11513))
* Recognize cshtml files as HTML ([#11540](https://github.com/helix-editor/helix/pull/11540))
* Set a memory limit for the Lean language server ([#11683](https://github.com/helix-editor/helix/pull/11683))
* Add configurations for jedi and ruff language servers ([#11630](https://github.com/helix-editor/helix/pull/11630))
* Update Vue highlights ([#11706](https://github.com/helix-editor/helix/pull/11706))
* Switch tree-sitter-hcl grammar ([#11749](https://github.com/helix-editor/helix/pull/11749))
* Fix `odinfmt` formatter configuration ([#11759](https://github.com/helix-editor/helix/pull/11759))
* Recognize `rbs` files as Ruby ([#11786](https://github.com/helix-editor/helix/pull/11786))
* Update tree-sitter-nickel ([#11771](https://github.com/helix-editor/helix/pull/11771))
* Recognize `ldtk` and `ldtkl` files as JSON ([#11793](https://github.com/helix-editor/helix/pull/11793))
* Fix highlights for builtin functions in Fish ([#11792](https://github.com/helix-editor/helix/pull/11792))
* Add `superhtml` for HTML ([#11609](https://github.com/helix-editor/helix/pull/11609))
* Add a configuration for the Vale language server ([#11636](https://github.com/helix-editor/helix/pull/11636))
* Add Erlang Language Platform (`elp`) for Erlang ([#11499](https://github.com/helix-editor/helix/pull/11499))
* Update Odin highlights ([#11804](https://github.com/helix-editor/helix/pull/11804))
* Remove auto-pairs for single quotes in SML ([#11838](https://github.com/helix-editor/helix/pull/11838))
* Add `glsl_analyzer` for GLSL ([#11891](https://github.com/helix-editor/helix/pull/11891))
* Recognize `.prettierrc` as YAML ([#11997](https://github.com/helix-editor/helix/pull/11997))
* Fix `swift-format` formatter configuration ([#12052](https://github.com/helix-editor/helix/pull/12052))
* Add `package.json` and `tsconfig.json` as JS/TS workspace roots ([#10652](https://github.com/helix-editor/helix/pull/10652))
* Add "INVARIANT" to comment error highlights ([#12094](https://github.com/helix-editor/helix/pull/12094))
* Update Rescript grammar and queries ([#11165](https://github.com/helix-editor/helix/pull/11165))
* Update tree-sitter-nasm ([#11795](https://github.com/helix-editor/helix/pull/11795))
* Update LLVM grammars ([#11851](https://github.com/helix-editor/helix/pull/11851))
* Update Perl and Pod grammars ([#11848](https://github.com/helix-editor/helix/pull/11848))
* Add Nim injections in Nix ([#11837](https://github.com/helix-editor/helix/pull/11837))
* Recognize `livemd` as Markdown ([#12034](https://github.com/helix-editor/helix/pull/12034))
* Update Unison grammar and queries ([#12039](https://github.com/helix-editor/helix/pull/12039))
* Turn off Swift auto-format by default ([#12071](https://github.com/helix-editor/helix/pull/12071))
* Recognize `.swift-format` as JSON ([#12071](https://github.com/helix-editor/helix/pull/12071))
* Recognize `.clangd` and `.clang-format` as YAML ([#12032](https://github.com/helix-editor/helix/pull/12032))
* Recognize `ssh_config.d/*.conf` as sshclientconfig ([#11947](https://github.com/helix-editor/helix/pull/11947))
* Update comment token configs for Zig ([#12049](https://github.com/helix-editor/helix/pull/12049))
* Update tree-sitter-bicep ([#11525](https://github.com/helix-editor/helix/pull/11525))
* Add `hyperls` for Hyperlang ([#11056](https://github.com/helix-editor/helix/pull/11056))
* Add highlight queries for Solidity ([#12102](https://github.com/helix-editor/helix/pull/12102))
* Recognize `WORKSPACE.bzlmod` as Starlark ([#12103](https://github.com/helix-editor/helix/pull/12103))
* Update Ada grammar and queries ([#12131](https://github.com/helix-editor/helix/pull/12131))
* Restrict Hocon file-types glob patterns ([#12156](https://github.com/helix-editor/helix/pull/12156))
* Update Mojo language server to Magic ([#12195](https://github.com/helix-editor/helix/pull/12195))
* Switch tree-sitter-v grammar ([#12236](https://github.com/helix-editor/helix/pull/12236))
* Add "COMPLIANCE" to comment error highlights ([#12094](https://github.com/helix-editor/helix/pull/12094))
* Add a language server configuration for `ltex-ls-plus` ([#12251](https://github.com/helix-editor/helix/pull/12251))
* Update tree-sitter-dockerfile ([#12230](https://github.com/helix-editor/helix/pull/12230))
* Add `]` to PHP outdents ([#12286](https://github.com/helix-editor/helix/pull/12286))
* Add textobjects for Odin ([#12302](https://github.com/helix-editor/helix/pull/12302))
* Update tree-sitter-heex and queries ([#12334](https://github.com/helix-editor/helix/pull/12334))
* Update protobuf highlights ([#12339](https://github.com/helix-editor/helix/pull/12339))
* Switch tree-sitter-query (TSQ) grammar ([#12148](https://github.com/helix-editor/helix/pull/12148), [e0bccd2](https://github.com/helix-editor/helix/commit/e0bccd2))
* Add block comment configurations for jinja and nunjucks ([#12348](https://github.com/helix-editor/helix/pull/12348))
* Add `uv` shebang for python ([#12360](https://github.com/helix-editor/helix/pull/12360))
* Update tree-sitter-vento ([#12368](https://github.com/helix-editor/helix/pull/12368))
* Switch Protobuf tree-sitter grammar ([#12225](https://github.com/helix-editor/helix/pull/12225))
* Recognize `hypr/*.conf` as Hyprland ([#12384](https://github.com/helix-editor/helix/pull/12384))
Packaging:
* Add completions for Nushell ([#11262](https://github.com/helix-editor/helix/pull/11262), [#11346](https://github.com/helix-editor/helix/pull/11346))
* Fix completion of flags in Bash completions ([#11246](https://github.com/helix-editor/helix/pull/11246))
* Include shell completions in Nix outputs ([#11518](https://github.com/helix-editor/helix/pull/11518))
# 24.07 (2024-07-14) # 24.07 (2024-07-14)
Thanks to all of the contributors! This release has changes from 160 contributors. Thanks to all of the contributors! This release has changes from 160 contributors.

305
Cargo.lock generated
View File

@@ -68,9 +68,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.94" version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
[[package]] [[package]]
name = "arc-swap" name = "arc-swap"
@@ -101,9 +101,9 @@ dependencies = [
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.6.0" version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be"
[[package]] [[package]]
name = "bstr" name = "bstr"
@@ -136,9 +136,9 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.4" version = "1.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b"
dependencies = [ dependencies = [
"shlex", "shlex",
] ]
@@ -319,6 +319,12 @@ dependencies = [
"encoding_rs", "encoding_rs",
] ]
[[package]]
name = "env_home"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe"
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.1" version = "1.0.1"
@@ -479,9 +485,9 @@ checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
[[package]] [[package]]
name = "gix" name = "gix"
version = "0.68.0" version = "0.69.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b04c66359b5e17f92395abc433861df0edf48f39f3f590818d1d7217327dd6a1" checksum = "8d0eebdaecdcf405d5433a36f85e4f058cf4de48ee2604388be0dbccbaad353e"
dependencies = [ dependencies = [
"gix-actor", "gix-actor",
"gix-attributes", "gix-attributes",
@@ -506,11 +512,13 @@ dependencies = [
"gix-pack", "gix-pack",
"gix-path", "gix-path",
"gix-pathspec", "gix-pathspec",
"gix-protocol",
"gix-ref", "gix-ref",
"gix-refspec", "gix-refspec",
"gix-revision", "gix-revision",
"gix-revwalk", "gix-revwalk",
"gix-sec", "gix-sec",
"gix-shallow",
"gix-status", "gix-status",
"gix-submodule", "gix-submodule",
"gix-tempfile", "gix-tempfile",
@@ -522,7 +530,7 @@ dependencies = [
"gix-worktree", "gix-worktree",
"once_cell", "once_cell",
"smallvec", "smallvec",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
@@ -535,7 +543,7 @@ dependencies = [
"gix-date", "gix-date",
"gix-utils", "gix-utils",
"itoa", "itoa",
"thiserror 2.0.7", "thiserror 2.0.11",
"winnow", "winnow",
] ]
@@ -552,7 +560,7 @@ dependencies = [
"gix-trace", "gix-trace",
"kstring", "kstring",
"smallvec", "smallvec",
"thiserror 2.0.7", "thiserror 2.0.11",
"unicode-bom", "unicode-bom",
] ]
@@ -562,7 +570,7 @@ version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d48b897b4bbc881aea994b4a5bbb340a04979d7be9089791304e04a9fbc66b53" checksum = "d48b897b4bbc881aea994b4a5bbb340a04979d7be9089791304e04a9fbc66b53"
dependencies = [ dependencies = [
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
@@ -571,14 +579,14 @@ version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6ffbeb3a5c0b8b84c3fe4133a6f8c82fa962f4caefe8d0762eced025d3eb4f7" checksum = "c6ffbeb3a5c0b8b84c3fe4133a6f8c82fa962f4caefe8d0762eced025d3eb4f7"
dependencies = [ dependencies = [
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
name = "gix-command" name = "gix-command"
version = "0.3.11" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d7d6b8f3a64453fd7e8191eb80b351eb7ac0839b40a1237cd2c137d5079fe53" checksum = "9405c0a56e17f8365a46870cd2c7db71323ecc8bda04b50cb746ea37bd091e90"
dependencies = [ dependencies = [
"bstr", "bstr",
"gix-path", "gix-path",
@@ -597,7 +605,7 @@ dependencies = [
"gix-features", "gix-features",
"gix-hash", "gix-hash",
"memmap2", "memmap2",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
@@ -616,7 +624,7 @@ dependencies = [
"memchr", "memchr",
"once_cell", "once_cell",
"smallvec", "smallvec",
"thiserror 2.0.7", "thiserror 2.0.11",
"unicode-bom", "unicode-bom",
"winnow", "winnow",
] ]
@@ -631,26 +639,26 @@ dependencies = [
"bstr", "bstr",
"gix-path", "gix-path",
"libc", "libc",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
name = "gix-date" name = "gix-date"
version = "0.9.2" version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "691142b1a34d18e8ed6e6114bc1a2736516c5ad60ef3aa9bd1b694886e3ca92d" checksum = "c57c477b645ee248b173bb1176b52dd528872f12c50375801a58aaf5ae91113f"
dependencies = [ dependencies = [
"bstr", "bstr",
"itoa", "itoa",
"jiff", "jiff",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
name = "gix-diff" name = "gix-diff"
version = "0.48.0" version = "0.49.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a327be31a392144b60ab0b1c863362c32a1c8f7effdfa2141d5d5b6b916ef3bf" checksum = "a8e92566eccbca205a0a0f96ffb0327c061e85bc5c95abbcddfe177498aa04f6"
dependencies = [ dependencies = [
"bstr", "bstr",
"gix-command", "gix-command",
@@ -664,14 +672,14 @@ dependencies = [
"gix-traverse", "gix-traverse",
"gix-worktree", "gix-worktree",
"imara-diff", "imara-diff",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
name = "gix-dir" name = "gix-dir"
version = "0.10.0" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acd6a0618958f9cce78a32724f8e06c4f4a57ca7080f645736d53676dc9b4db9" checksum = "fba2ffbcf4bd34438e8a8367ccbc94870549903d1f193a14f47eb6b0967e1293"
dependencies = [ dependencies = [
"bstr", "bstr",
"gix-discover", "gix-discover",
@@ -684,7 +692,7 @@ dependencies = [
"gix-trace", "gix-trace",
"gix-utils", "gix-utils",
"gix-worktree", "gix-worktree",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
@@ -700,7 +708,7 @@ dependencies = [
"gix-path", "gix-path",
"gix-ref", "gix-ref",
"gix-sec", "gix-sec",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
@@ -718,15 +726,15 @@ dependencies = [
"once_cell", "once_cell",
"prodash", "prodash",
"sha1_smol", "sha1_smol",
"thiserror 2.0.7", "thiserror 2.0.11",
"walkdir", "walkdir",
] ]
[[package]] [[package]]
name = "gix-filter" name = "gix-filter"
version = "0.15.0" version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5108cc58d58b27df10ac4de7f31b2eb96d588a33e5eba23739b865f5d8db7995" checksum = "3d0ecdee5667f840ba20c7fe56d63f8e1dc1e6b3bfd296151fe5ef07c874790a"
dependencies = [ dependencies = [
"bstr", "bstr",
"encoding_rs", "encoding_rs",
@@ -740,14 +748,14 @@ dependencies = [
"gix-trace", "gix-trace",
"gix-utils", "gix-utils",
"smallvec", "smallvec",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
name = "gix-fs" name = "gix-fs"
version = "0.12.0" version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34740384d8d763975858fa2c176b68652a6fcc09f616e24e3ce967b0d370e4d8" checksum = "3b3d4fac505a621f97e5ce2c69fdc425742af00c0920363ca4074f0eb48b1db9"
dependencies = [ dependencies = [
"fastrand", "fastrand",
"gix-features", "gix-features",
@@ -773,7 +781,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b5eccc17194ed0e67d49285e4853307e4147e95407f91c1c3e4a13ba9f4e4ce" checksum = "0b5eccc17194ed0e67d49285e4853307e4147e95407f91c1c3e4a13ba9f4e4ce"
dependencies = [ dependencies = [
"faster-hex", "faster-hex",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
@@ -825,7 +833,7 @@ dependencies = [
"memmap2", "memmap2",
"rustix", "rustix",
"smallvec", "smallvec",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
@@ -841,9 +849,9 @@ dependencies = [
[[package]] [[package]]
name = "gix-object" name = "gix-object"
version = "0.46.0" version = "0.46.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65d93e2bbfa83a307e47f45e45de7b6c04d7375a8bd5907b215f4bf45237d879" checksum = "e42d58010183ef033f31088479b4eb92b44fe341b35b62d39eb8b185573d77ea"
dependencies = [ dependencies = [
"bstr", "bstr",
"gix-actor", "gix-actor",
@@ -851,19 +859,20 @@ dependencies = [
"gix-features", "gix-features",
"gix-hash", "gix-hash",
"gix-hashtable", "gix-hashtable",
"gix-path",
"gix-utils", "gix-utils",
"gix-validate", "gix-validate",
"itoa", "itoa",
"smallvec", "smallvec",
"thiserror 2.0.7", "thiserror 2.0.11",
"winnow", "winnow",
] ]
[[package]] [[package]]
name = "gix-odb" name = "gix-odb"
version = "0.65.0" version = "0.66.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93bed6e1b577c25a6bb8e6ecbf4df525f29a671ddf5f2221821a56a8dbeec4e3" checksum = "cb780eceb3372ee204469478de02eaa34f6ba98247df0186337e0333de97d0ae"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"gix-date", "gix-date",
@@ -877,14 +886,14 @@ dependencies = [
"gix-quote", "gix-quote",
"parking_lot", "parking_lot",
"tempfile", "tempfile",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
name = "gix-pack" name = "gix-pack"
version = "0.55.0" version = "0.56.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b91fec04d359544fecbb8e85117ec746fbaa9046ebafcefb58cb74f20dc76d4" checksum = "4158928929be29cae7ab97afc8e820a932071a7f39d8ba388eed2380c12c566c"
dependencies = [ dependencies = [
"clru", "clru",
"gix-chunk", "gix-chunk",
@@ -895,7 +904,19 @@ dependencies = [
"gix-path", "gix-path",
"memmap2", "memmap2",
"smallvec", "smallvec",
"thiserror 2.0.7", "thiserror 2.0.11",
]
[[package]]
name = "gix-packetline"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "911aeea8b2dabeed2f775af9906152a1f0109787074daf9e64224e3892dde453"
dependencies = [
"bstr",
"faster-hex",
"gix-trace",
"thiserror 2.0.11",
] ]
[[package]] [[package]]
@@ -907,7 +928,7 @@ dependencies = [
"bstr", "bstr",
"faster-hex", "faster-hex",
"gix-trace", "gix-trace",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
@@ -920,7 +941,7 @@ dependencies = [
"gix-trace", "gix-trace",
"home", "home",
"once_cell", "once_cell",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
@@ -935,7 +956,26 @@ dependencies = [
"gix-config-value", "gix-config-value",
"gix-glob", "gix-glob",
"gix-path", "gix-path",
"thiserror 2.0.7", "thiserror 2.0.11",
]
[[package]]
name = "gix-protocol"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c84642e8b6fed7035ce9cc449593019c55b0ec1af7a5dce1ab8a0636eaaeb067"
dependencies = [
"bstr",
"gix-date",
"gix-features",
"gix-hash",
"gix-ref",
"gix-shallow",
"gix-transport",
"gix-utils",
"maybe-async",
"thiserror 2.0.11",
"winnow",
] ]
[[package]] [[package]]
@@ -946,14 +986,14 @@ checksum = "64a1e282216ec2ab2816cd57e6ed88f8009e634aec47562883c05ac8a7009a63"
dependencies = [ dependencies = [
"bstr", "bstr",
"gix-utils", "gix-utils",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
name = "gix-ref" name = "gix-ref"
version = "0.49.0" version = "0.49.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1eae462723686272a58f49501015ef7c0d67c3e042c20049d8dd9c7eff92efde" checksum = "a91b61776c839d0f1b7114901179afb0947aa7f4d30793ca1c56d335dfef485f"
dependencies = [ dependencies = [
"gix-actor", "gix-actor",
"gix-features", "gix-features",
@@ -966,7 +1006,7 @@ dependencies = [
"gix-utils", "gix-utils",
"gix-validate", "gix-validate",
"memmap2", "memmap2",
"thiserror 2.0.7", "thiserror 2.0.11",
"winnow", "winnow",
] ]
@@ -981,14 +1021,14 @@ dependencies = [
"gix-revision", "gix-revision",
"gix-validate", "gix-validate",
"smallvec", "smallvec",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
name = "gix-revision" name = "gix-revision"
version = "0.31.0" version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44488e0380847967bc3e3cacd8b22652e02ea1eb58afb60edd91847695cd2d8d" checksum = "61e1ddc474405a68d2ce8485705dd72fe6ce959f2f5fe718601ead5da2c8f9e7"
dependencies = [ dependencies = [
"bstr", "bstr",
"gix-commitgraph", "gix-commitgraph",
@@ -996,7 +1036,7 @@ dependencies = [
"gix-hash", "gix-hash",
"gix-object", "gix-object",
"gix-revwalk", "gix-revwalk",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
@@ -1011,7 +1051,7 @@ dependencies = [
"gix-hashtable", "gix-hashtable",
"gix-object", "gix-object",
"smallvec", "smallvec",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
@@ -1027,10 +1067,22 @@ dependencies = [
] ]
[[package]] [[package]]
name = "gix-status" name = "gix-shallow"
version = "0.15.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "201396192ee4c4dd9e8a84fed4b0d2b33d639fca815fb99b0f653dfeddf38585" checksum = "88d2673242e87492cb6ff671f0c01f689061ca306c4020f137197f3abc84ce01"
dependencies = [
"bstr",
"gix-hash",
"gix-lock",
"thiserror 2.0.11",
]
[[package]]
name = "gix-status"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1665770e277608bd6b0eaf86adbf6cb3ffc6fb97749e7bc6f9318ac5f37564df"
dependencies = [ dependencies = [
"bstr", "bstr",
"filetime", "filetime",
@@ -1046,7 +1098,7 @@ dependencies = [
"gix-pathspec", "gix-pathspec",
"gix-worktree", "gix-worktree",
"portable-atomic", "portable-atomic",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
@@ -1061,7 +1113,7 @@ dependencies = [
"gix-pathspec", "gix-pathspec",
"gix-refspec", "gix-refspec",
"gix-url", "gix-url",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
@@ -1085,10 +1137,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04bdde120c29f1fc23a24d3e115aeeea3d60d8e65bab92cc5f9d90d9302eb952" checksum = "04bdde120c29f1fc23a24d3e115aeeea3d60d8e65bab92cc5f9d90d9302eb952"
[[package]] [[package]]
name = "gix-traverse" name = "gix-transport"
version = "0.43.0" version = "0.44.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ff2ec9f779680f795363db1c563168b32b8d6728ec58564c628e85c92d29faf" checksum = "dd04d91e507a8713cfa2318d5a85d75b36e53a40379cc7eb7634ce400ecacbaf"
dependencies = [
"bstr",
"gix-command",
"gix-features",
"gix-packetline",
"gix-quote",
"gix-sec",
"gix-url",
"thiserror 2.0.11",
]
[[package]]
name = "gix-traverse"
version = "0.43.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ed47d648619e23e93f971d2bba0d10c1100e54ef95d2981d609907a8cabac89"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"gix-commitgraph", "gix-commitgraph",
@@ -1098,19 +1166,20 @@ dependencies = [
"gix-object", "gix-object",
"gix-revwalk", "gix-revwalk",
"smallvec", "smallvec",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
name = "gix-url" name = "gix-url"
version = "0.28.1" version = "0.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e09f97db3618fb8e473d7d97e77296b50aaee0ddcd6a867f07443e3e87391099" checksum = "d096fb733ba6bd3f5403dba8bd72bdd8809fe2b347b57844040b8f49c93492d9"
dependencies = [ dependencies = [
"bstr", "bstr",
"gix-features", "gix-features",
"gix-path", "gix-path",
"thiserror 2.0.7", "percent-encoding",
"thiserror 2.0.11",
"url", "url",
] ]
@@ -1132,7 +1201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd520d09f9f585b34b32aba1d0b36ada89ab7fefb54a8ca3fe37fc482a750937" checksum = "cd520d09f9f585b34b32aba1d0b36ada89ab7fefb54a8ca3fe37fc482a750937"
dependencies = [ dependencies = [
"bstr", "bstr",
"thiserror 2.0.7", "thiserror 2.0.11",
] ]
[[package]] [[package]]
@@ -1216,7 +1285,7 @@ dependencies = [
[[package]] [[package]]
name = "helix-core" name = "helix-core"
version = "24.7.0" version = "25.1.1"
dependencies = [ dependencies = [
"ahash", "ahash",
"anyhow", "anyhow",
@@ -1257,7 +1326,7 @@ dependencies = [
[[package]] [[package]]
name = "helix-dap" name = "helix-dap"
version = "24.7.0" version = "25.1.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"fern", "fern",
@@ -1266,13 +1335,13 @@ dependencies = [
"log", "log",
"serde", "serde",
"serde_json", "serde_json",
"thiserror 2.0.7", "thiserror 2.0.11",
"tokio", "tokio",
] ]
[[package]] [[package]]
name = "helix-event" name = "helix-event"
version = "24.7.0" version = "25.1.1"
dependencies = [ dependencies = [
"ahash", "ahash",
"anyhow", "anyhow",
@@ -1286,7 +1355,7 @@ dependencies = [
[[package]] [[package]]
name = "helix-loader" name = "helix-loader"
version = "24.7.0" version = "25.1.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cc", "cc",
@@ -1305,7 +1374,7 @@ dependencies = [
[[package]] [[package]]
name = "helix-lsp" name = "helix-lsp"
version = "24.7.0" version = "25.1.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"arc-swap", "arc-swap",
@@ -1322,7 +1391,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"slotmap", "slotmap",
"thiserror 2.0.7", "thiserror 2.0.11",
"tokio", "tokio",
"tokio-stream", "tokio-stream",
] ]
@@ -1340,11 +1409,11 @@ dependencies = [
[[package]] [[package]]
name = "helix-parsec" name = "helix-parsec"
version = "24.7.0" version = "25.1.1"
[[package]] [[package]]
name = "helix-stdx" name = "helix-stdx"
version = "24.7.0" version = "25.1.1"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"dunce", "dunce",
@@ -1361,7 +1430,7 @@ dependencies = [
[[package]] [[package]]
name = "helix-term" name = "helix-term"
version = "24.7.0" version = "25.1.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"arc-swap", "arc-swap",
@@ -1397,7 +1466,7 @@ dependencies = [
"smallvec", "smallvec",
"tempfile", "tempfile",
"termini", "termini",
"thiserror 2.0.7", "thiserror 2.0.11",
"tokio", "tokio",
"tokio-stream", "tokio-stream",
"toml", "toml",
@@ -1406,7 +1475,7 @@ dependencies = [
[[package]] [[package]]
name = "helix-tui" name = "helix-tui"
version = "24.7.0" version = "25.1.1"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cassowary", "cassowary",
@@ -1422,7 +1491,7 @@ dependencies = [
[[package]] [[package]]
name = "helix-vcs" name = "helix-vcs"
version = "24.7.0" version = "25.1.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"arc-swap", "arc-swap",
@@ -1438,7 +1507,7 @@ dependencies = [
[[package]] [[package]]
name = "helix-view" name = "helix-view"
version = "24.7.0" version = "25.1.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"arc-swap", "arc-swap",
@@ -1464,7 +1533,7 @@ dependencies = [
"serde_json", "serde_json",
"slotmap", "slotmap",
"tempfile", "tempfile",
"thiserror 2.0.7", "thiserror 2.0.11",
"tokio", "tokio",
"tokio-stream", "tokio-stream",
"toml", "toml",
@@ -1760,9 +1829,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.168" version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]] [[package]]
name = "libloading" name = "libloading"
@@ -1813,6 +1882,17 @@ version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "maybe-async"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.4" version = "2.7.4"
@@ -1916,9 +1996,9 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]] [[package]]
name = "open" name = "open"
version = "5.3.1" version = "5.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ecd52f0b8d15c40ce4820aa251ed5de032e5d91fab27f7db2f40d42a8bdf69c" checksum = "e2483562e62ea94312f3576a7aca397306df7990b8d89033e18766744377ef95"
dependencies = [ dependencies = [
"is-wsl", "is-wsl",
"libc", "libc",
@@ -2133,9 +2213,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.42" version = "0.38.43"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"errno", "errno",
@@ -2167,18 +2247,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.216" version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.216" version = "1.0.217"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -2187,9 +2267,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.133" version = "1.0.135"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9"
dependencies = [ dependencies = [
"itoa", "itoa",
"memchr", "memchr",
@@ -2370,12 +2450,13 @@ dependencies = [
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.14.0" version = "3.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"fastrand", "fastrand",
"getrandom",
"once_cell", "once_cell",
"rustix", "rustix",
"windows-sys 0.59.0", "windows-sys 0.59.0",
@@ -2412,11 +2493,11 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "2.0.7" version = "2.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93605438cbd668185516ab499d589afb7ee1859ea3d5fc8f6b0755e1c7443767" checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
dependencies = [ dependencies = [
"thiserror-impl 2.0.7", "thiserror-impl 2.0.11",
] ]
[[package]] [[package]]
@@ -2432,9 +2513,9 @@ dependencies = [
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "2.0.7" version = "2.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1d8749b4531af2117677a5fcd12b1348a3fe2b81e36e61ffeac5c4aa3273e36" checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -2477,9 +2558,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.42.0" version = "1.43.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes", "bytes",
@@ -2495,9 +2576,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio-macros" name = "tokio-macros"
version = "2.4.0" version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -2716,12 +2797,12 @@ checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
[[package]] [[package]]
name = "which" name = "which"
version = "7.0.0" version = "7.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9cad3279ade7346b96e38731a641d7343dd6a53d55083dd54eadfa5a1b38c6b" checksum = "fb4a9e33648339dc1642b0e36e21b3385e6148e289226f657c809dee59df5028"
dependencies = [ dependencies = [
"either", "either",
"home", "env_home",
"rustix", "rustix",
"winsafe", "winsafe",
] ]
@@ -2943,7 +3024,7 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
[[package]] [[package]]
name = "xtask" name = "xtask"
version = "24.7.0" version = "25.1.1"
dependencies = [ dependencies = [
"helix-core", "helix-core",
"helix-loader", "helix-loader",

View File

@@ -22,13 +22,12 @@ default-members = [
[profile.release] [profile.release]
lto = "thin" lto = "thin"
# debug = true
[profile.opt] [profile.opt]
inherits = "release" inherits = "release"
lto = "fat" lto = "fat"
codegen-units = 1 codegen-units = 1
# strip = "debuginfo" # TODO: or strip = true strip = true
opt-level = 3 opt-level = 3
[profile.integration] [profile.integration]
@@ -42,9 +41,11 @@ tree-sitter = { version = "0.22" }
nucleo = "0.5.0" nucleo = "0.5.0"
slotmap = "1.0.7" slotmap = "1.0.7"
thiserror = "2.0" thiserror = "2.0"
tempfile = "3.15.0"
bitflags = "2.7"
[workspace.package] [workspace.package]
version = "24.7.0" version = "25.1.1"
edition = "2021" edition = "2021"
authors = ["Blaž Hrastnik <blaz@mxxn.io>"] authors = ["Blaž Hrastnik <blaz@mxxn.io>"]
categories = ["editor"] categories = ["editor"]

View File

@@ -7,6 +7,7 @@
- [Note to packagers](#note-to-packagers) - [Note to packagers](#note-to-packagers)
- [Validating the installation](#validating-the-installation) - [Validating the installation](#validating-the-installation)
- [Configure the desktop shortcut](#configure-the-desktop-shortcut) - [Configure the desktop shortcut](#configure-the-desktop-shortcut)
- [Building the Debian package](#building-the-debian-package)
Requirements: Requirements:
@@ -162,3 +163,39 @@ file. For example, to use `kitty`:
sed -i "s|Exec=hx %F|Exec=kitty hx %F|g" ~/.local/share/applications/Helix.desktop sed -i "s|Exec=hx %F|Exec=kitty hx %F|g" ~/.local/share/applications/Helix.desktop
sed -i "s|Terminal=true|Terminal=false|g" ~/.local/share/applications/Helix.desktop sed -i "s|Terminal=true|Terminal=false|g" ~/.local/share/applications/Helix.desktop
``` ```
### Building the Debian package
If the `.deb` file provided on the release page uses a `libc` version higher
than that used by your Debian, Ubuntu, or Mint system, you can build the package
from source to match your system's dependencies.
Install `cargo-deb`, the tool used for building the `.deb` file:
```sh
cargo install cargo-deb
```
After cloning and entering the Helix repository as previously described,
use the following command to build the release binary and package it into a `.deb` file in a single step.
```sh
cargo deb -- --locked
```
> 💡 This locks you into the `--release` profile. But you can also build helix in any way you like.
> As long as you leave a `target/release/hx` file, it will get packaged with `cargo deb --no-build`
> 💡 Don't worry about the repeated
> ```
> warning: Failed to find dependency specification
> ```
> warnings. Cargo deb just reports which packaged files it didn't derive dependencies for. But
> so far the dependency deriving seams very good, even if some of the grammar files are skipped.
You can find the resulted `.deb` in `target/debian/`. It should contain everything it needs, including the
- completions for bash, fish, zsh
- .desktop file
- icon (though desktop environments might use their own since the name of the package is correctly `helix`)
- launcher to the binary with the runtime

View File

@@ -1,11 +1,13 @@
## Editor ## Editor
- [`[editor]` Section](#editor-section) - [`[editor]` Section](#editor-section)
- [`[editor.clipboard-provider]` Section](#editorclipboard-provider-section)
- [`[editor.statusline]` Section](#editorstatusline-section) - [`[editor.statusline]` Section](#editorstatusline-section)
- [`[editor.lsp]` Section](#editorlsp-section) - [`[editor.lsp]` Section](#editorlsp-section)
- [`[editor.cursor-shape]` Section](#editorcursor-shape-section) - [`[editor.cursor-shape]` Section](#editorcursor-shape-section)
- [`[editor.file-picker]` Section](#editorfile-picker-section) - [`[editor.file-picker]` Section](#editorfile-picker-section)
- [`[editor.auto-pairs]` Section](#editorauto-pairs-section) - [`[editor.auto-pairs]` Section](#editorauto-pairs-section)
- [`[editor.auto-save]` Section](#editorauto-save-section)
- [`[editor.search]` Section](#editorsearch-section) - [`[editor.search]` Section](#editorsearch-section)
- [`[editor.whitespace]` Section](#editorwhitespace-section) - [`[editor.whitespace]` Section](#editorwhitespace-section)
- [`[editor.indent-guides]` Section](#editorindent-guides-section) - [`[editor.indent-guides]` Section](#editorindent-guides-section)
@@ -143,7 +145,8 @@ The following statusline elements can be configured:
| Key | Description | Default | | Key | Description | Default |
| --- | ----------- | ------- | | --- | ----------- | ------- |
| `enable` | Enables LSP integration. Setting to false will completely disable language servers regardless of language settings.| `true` | | `enable` | Enables LSP integration. Setting to false will completely disable language servers regardless of language settings.| `true` |
| `display-messages` | Display LSP progress messages below statusline[^1] | `false` | | `display-messages` | Display LSP `window/showMessage` messages below statusline[^1] | `true` |
| `display-progress-messages` | Display LSP progress messages below statusline[^1] | `false` |
| `auto-signature-help` | Enable automatic popup of signature help (parameter hints) | `true` | | `auto-signature-help` | Enable automatic popup of signature help (parameter hints) | `true` |
| `display-inlay-hints` | Display inlay hints[^2] | `false` | | `display-inlay-hints` | Display inlay hints[^2] | `false` |
| `display-signature-help-docs` | Display docs under signature help popup | `true` | | `display-signature-help-docs` | Display docs under signature help popup | `true` |
@@ -442,6 +445,8 @@ fn main() {
| `max-wrap` | Equivalent of the `editor.soft-wrap.max-wrap` option for diagnostics. | `20` | | `max-wrap` | Equivalent of the `editor.soft-wrap.max-wrap` option for diagnostics. | `20` |
| `max-diagnostics` | Maximum number of diagnostics to render inline for a given line | `10` | | `max-diagnostics` | Maximum number of diagnostics to render inline for a given line | `10` |
The allowed values for `cursor-line` and `other-lines` are: `error`, `warning`, `info`, `hint`.
The (first) diagnostic with the highest severity that is not shown inline is rendered at the end of the line (as long as its severity is higher than the `end-of-line-diagnostics` config option): The (first) diagnostic with the highest severity that is not shown inline is rendered at the end of the line (as long as its severity is higher than the `end-of-line-diagnostics` config option):
``` ```

View File

@@ -23,6 +23,7 @@
| circom | ✓ | | | `circom-lsp` | | circom | ✓ | | | `circom-lsp` |
| clojure | ✓ | | | `clojure-lsp` | | clojure | ✓ | | | `clojure-lsp` |
| cmake | ✓ | ✓ | ✓ | `cmake-language-server` | | cmake | ✓ | ✓ | ✓ | `cmake-language-server` |
| codeql | ✓ | ✓ | | `codeql` |
| comment | ✓ | | | | | comment | ✓ | | | |
| common-lisp | ✓ | | ✓ | `cl-lsp` | | common-lisp | ✓ | | ✓ | `cl-lsp` |
| cpon | ✓ | | ✓ | | | cpon | ✓ | | ✓ | |
@@ -80,6 +81,7 @@
| gowork | ✓ | | | `gopls` | | gowork | ✓ | | | `gopls` |
| gpr | ✓ | | | `ada_language_server` | | gpr | ✓ | | | `ada_language_server` |
| graphql | ✓ | ✓ | | `graphql-lsp` | | graphql | ✓ | ✓ | | `graphql-lsp` |
| gren | ✓ | ✓ | | |
| groovy | ✓ | | | | | groovy | ✓ | | | |
| gts | ✓ | ✓ | ✓ | `typescript-language-server`, `vscode-eslint-language-server`, `ember-language-server` | | gts | ✓ | ✓ | ✓ | `typescript-language-server`, `vscode-eslint-language-server`, `ember-language-server` |
| hare | ✓ | | | | | hare | ✓ | | | |
@@ -115,6 +117,7 @@
| kdl | ✓ | ✓ | ✓ | | | kdl | ✓ | ✓ | ✓ | |
| koka | ✓ | | ✓ | `koka` | | koka | ✓ | | ✓ | `koka` |
| kotlin | ✓ | | | `kotlin-language-server` | | kotlin | ✓ | | | `kotlin-language-server` |
| koto | ✓ | ✓ | ✓ | `koto-ls` |
| latex | ✓ | ✓ | | `texlab` | | latex | ✓ | ✓ | | `texlab` |
| ld | ✓ | | ✓ | | | ld | ✓ | | ✓ | |
| ldif | ✓ | | | | | ldif | ✓ | | | |
@@ -139,6 +142,7 @@
| msbuild | ✓ | | ✓ | | | msbuild | ✓ | | ✓ | |
| nasm | ✓ | ✓ | | | | nasm | ✓ | ✓ | | |
| nestedtext | ✓ | ✓ | ✓ | | | nestedtext | ✓ | ✓ | ✓ | |
| nginx | ✓ | | | |
| nickel | ✓ | | ✓ | `nls` | | nickel | ✓ | | ✓ | `nls` |
| nim | ✓ | ✓ | ✓ | `nimlangserver` | | nim | ✓ | ✓ | ✓ | `nimlangserver` |
| nix | ✓ | ✓ | | `nil`, `nixd` | | nix | ✓ | ✓ | | `nil`, `nixd` |
@@ -146,7 +150,7 @@
| nunjucks | ✓ | | | | | nunjucks | ✓ | | | |
| ocaml | ✓ | | ✓ | `ocamllsp` | | ocaml | ✓ | | ✓ | `ocamllsp` |
| ocaml-interface | ✓ | | | `ocamllsp` | | ocaml-interface | ✓ | | | `ocamllsp` |
| odin | ✓ | | ✓ | `ols` | | odin | ✓ | | ✓ | `ols` |
| ohm | ✓ | ✓ | ✓ | | | ohm | ✓ | ✓ | ✓ | |
| opencl | ✓ | ✓ | ✓ | `clangd` | | opencl | ✓ | ✓ | ✓ | `clangd` |
| openscad | ✓ | | | `openscad-lsp` | | openscad | ✓ | | | `openscad-lsp` |
@@ -208,14 +212,14 @@
| tact | ✓ | ✓ | ✓ | | | tact | ✓ | ✓ | ✓ | |
| task | ✓ | | | | | task | ✓ | | | |
| tcl | ✓ | | ✓ | | | tcl | ✓ | | ✓ | |
| teal | ✓ | | | | | teal | ✓ | | | `teal-language-server` |
| templ | ✓ | | | `templ` | | templ | ✓ | | | `templ` |
| textproto | ✓ | ✓ | ✓ | | | textproto | ✓ | ✓ | ✓ | |
| tfvars | ✓ | | ✓ | `terraform-ls` | | tfvars | ✓ | | ✓ | `terraform-ls` |
| thrift | ✓ | | | | | thrift | ✓ | | | |
| todotxt | ✓ | | | | | todotxt | ✓ | | | |
| toml | ✓ | ✓ | | `taplo` | | toml | ✓ | ✓ | | `taplo` |
| tsq | ✓ | | | | | tsq | ✓ | | | `ts_query_ls` |
| tsx | ✓ | ✓ | ✓ | `typescript-language-server` | | tsx | ✓ | ✓ | ✓ | `typescript-language-server` |
| twig | ✓ | | | | | twig | ✓ | | | |
| typescript | ✓ | ✓ | ✓ | `typescript-language-server` | | typescript | ✓ | ✓ | ✓ | `typescript-language-server` |

View File

@@ -34,7 +34,7 @@ below.
2. Create a new directory for the language with the path 2. Create a new directory for the language with the path
`runtime/queries/<name>/`. `runtime/queries/<name>/`.
3. Refer to the 3. Refer to the
[tree-sitter website](https://tree-sitter.github.io/tree-sitter/syntax-highlighting#queries) [tree-sitter website](https://tree-sitter.github.io/tree-sitter/3-syntax-highlighting.html#highlights)
for more information on writing queries. for more information on writing queries.
4. A list of highlight captures can be found [on the themes page](https://docs.helix-editor.com/themes.html#scopes). 4. A list of highlight captures can be found [on the themes page](https://docs.helix-editor.com/themes.html#scopes).

View File

@@ -57,4 +57,4 @@ second argument (a string).
- `#any-of?` (standard): - `#any-of?` (standard):
The first argument (a capture) must be one of the other arguments (strings). The first argument (a capture) must be one of the other arguments (strings).
[upstream-docs]: http://tree-sitter.github.io/tree-sitter/syntax-highlighting#language-injection [upstream-docs]: https://tree-sitter.github.io/tree-sitter/3-syntax-highlighting.html#language-injection

View File

@@ -44,6 +44,6 @@ in its `textobjects.scm` file, function navigation should also work automaticall
`function.movement` should be defined only if the node captured by `function.around` `function.movement` should be defined only if the node captured by `function.around`
doesn't make sense in a navigation context. doesn't make sense in a navigation context.
[tree-sitter-queries]: https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax [tree-sitter-queries]: https://tree-sitter.github.io/tree-sitter/using-parsers/queries/1-syntax.html
[tree-sitter-captures]: https://tree-sitter.github.io/tree-sitter/using-parsers#capturing-nodes [tree-sitter-captures]: https://tree-sitter.github.io/tree-sitter/using-parsers/queries/2-operators.html#capturing-nodes
[textobject-examples]: https://github.com/search?q=repo%3Ahelix-editor%2Fhelix+path%3A%2A%2A/textobjects.scm&type=Code&ref=advsearch&l=&l= [textobject-examples]: https://github.com/search?q=repo%3Ahelix-editor%2Fhelix+path%3A%2A%2A/textobjects.scm&type=Code&ref=advsearch&l=&l=

View File

@@ -60,7 +60,7 @@ These configuration keys are available:
| `shebangs` | The interpreters from the shebang line, for example `["sh", "bash"]` | | `shebangs` | The interpreters from the shebang line, for example `["sh", "bash"]` |
| `roots` | A set of marker files to look for when trying to find the workspace root. For example `Cargo.lock`, `yarn.lock` | | `roots` | A set of marker files to look for when trying to find the workspace root. For example `Cargo.lock`, `yarn.lock` |
| `auto-format` | Whether to autoformat this language when saving | | `auto-format` | Whether to autoformat this language when saving |
| `diagnostic-severity` | Minimal severity of diagnostic for it to be displayed. (Allowed values: `Error`, `Warning`, `Info`, `Hint`) | | `diagnostic-severity` | Minimal severity of diagnostic for it to be displayed. (Allowed values: `error`, `warning`, `info`, `hint`) |
| `comment-tokens` | The tokens to use as a comment token, either a single token `"//"` or an array `["//", "///", "//!"]` (the first token will be used for commenting). Also configurable as `comment-token` for backwards compatibility| | `comment-tokens` | The tokens to use as a comment token, either a single token `"//"` or an array `["//", "///", "//!"]` (the first token will be used for commenting). Also configurable as `comment-token` for backwards compatibility|
| `block-comment-tokens`| The start and end tokens for a multiline comment either an array or single table of `{ start = "/*", end = "*/"}`. The first set of tokens will be used for commenting, any pairs in the array can be uncommented | | `block-comment-tokens`| The start and end tokens for a multiline comment either an array or single table of `{ start = "/*", end = "*/"}`. The first set of tokens will be used for commenting, any pairs in the array can be uncommented |
| `indent` | The indent to use. Has sub keys `unit` (the text inserted into the document when indenting; usually set to N spaces or `"\t"` for tabs) and `tab-width` (the number of spaces rendered for a tab) | | `indent` | The indent to use. Has sub keys `unit` (the text inserted into the document when indenting; usually set to N spaces or `"\t"` for tabs) and `tab-width` (the number of spaces rendered for a tab) |
@@ -241,4 +241,4 @@ use-grammars = { except = [ "yaml", "json" ] }
When omitted, all grammars are fetched and built. When omitted, all grammars are fetched and built.
[treesitter-language-injection]: https://tree-sitter.github.io/tree-sitter/syntax-highlighting#language-injection [treesitter-language-injection]: https://tree-sitter.github.io/tree-sitter/3-syntax-highlighting.html#language-injection

View File

@@ -1,7 +1,8 @@
## Package managers ## Package managers
- [Linux](#linux) - [Linux](#linux)
- [Ubuntu](#ubuntu) - [Ubuntu/Debian](#ubuntudebian)
- [Ubuntu (PPA)](#ubuntu-ppa)
- [Fedora/RHEL](#fedorarhel) - [Fedora/RHEL](#fedorarhel)
- [Arch Linux extra](#arch-linux-extra) - [Arch Linux extra](#arch-linux-extra)
- [NixOS](#nixos) - [NixOS](#nixos)
@@ -23,7 +24,14 @@
The following third party repositories are available: The following third party repositories are available:
### Ubuntu ### Ubuntu/Debian
Install the Debian package from the release page.
If you are running a system older than Ubuntu 22.04, Mint 21, or Debian 12, you can build the `.deb` file locally
[from source](./building-from-source.md#building-the-debian-package).
### Ubuntu (PPA)
Add the `PPA` for Helix: Add the `PPA` for Helix:
@@ -121,7 +129,7 @@ brew install helix
### MacPorts ### MacPorts
```sh ```sh
port install helix sudo port install helix
``` ```
## Windows ## Windows

View File

@@ -136,7 +136,7 @@ The following is a list of scopes available to use for styling:
#### Syntax highlighting #### Syntax highlighting
These keys match [tree-sitter scopes](https://tree-sitter.github.io/tree-sitter/syntax-highlighting#theme). These keys match [tree-sitter scopes](https://tree-sitter.github.io/tree-sitter/3-syntax-highlighting.html#highlights).
When determining styling for a highlight, the longest matching theme key will be used. For example, if the highlight is `function.builtin.static`, the key `function.builtin` will be used instead of `function`. When determining styling for a highlight, the longest matching theme key will be used. For example, if the highlight is `function.builtin.static`, the key `function.builtin` will be used instead of `function`.
@@ -305,6 +305,7 @@ These scopes are used for theming the editor interface:
| `ui.text.focus` | The currently selected line in the picker | | `ui.text.focus` | The currently selected line in the picker |
| `ui.text.inactive` | Same as `ui.text` but when the text is inactive (e.g. suggestions) | | `ui.text.inactive` | Same as `ui.text` but when the text is inactive (e.g. suggestions) |
| `ui.text.info` | The key: command text in `ui.popup.info` boxes | | `ui.text.info` | The key: command text in `ui.popup.info` boxes |
| `ui.text.directory` | Directory names in prompt completion |
| `ui.virtual.ruler` | Ruler columns (see the [`editor.rulers` config][editor-section]) | | `ui.virtual.ruler` | Ruler columns (see the [`editor.rulers` config][editor-section]) |
| `ui.virtual.whitespace` | Visible whitespace characters | | `ui.virtual.whitespace` | Visible whitespace characters |
| `ui.virtual.indent-guide` | Vertical indent width guides | | `ui.virtual.indent-guide` | Vertical indent width guides |
@@ -335,5 +336,6 @@ These scopes are used for theming the editor interface:
| `diagnostic.error` | Diagnostics error (editing area) | | `diagnostic.error` | Diagnostics error (editing area) |
| `diagnostic.unnecessary` | Diagnostics with unnecessary tag (editing area) | | `diagnostic.unnecessary` | Diagnostics with unnecessary tag (editing area) |
| `diagnostic.deprecated` | Diagnostics with deprecated tag (editing area) | | `diagnostic.deprecated` | Diagnostics with deprecated tag (editing area) |
| `tabstop` | Snippet placeholder |
[editor-section]: ./configuration.md#editor-section [editor-section]: ./configuration.md#editor-section

View File

@@ -25,7 +25,7 @@ Inspired by [Kakoune](http://kakoune.org/), Helix follows the `selection → act
## Multiple selections ## Multiple selections
Also inspired by Kakoune, multiple selections are a core mode of interaction in Helix. For example, the standard way of replacing multiple instance of a word is to first select all instances (so there is one selection per instance) and then use the change action (`c`) to edit them all at the same time. Also inspired by Kakoune, multiple selections are a core mode of interaction in Helix. For example, the standard way of replacing multiple instances of a word is to first select all instances (so there is one selection per instance) and then use the change action (`c`) to edit them all at the same time.
## Motions ## Motions

View File

@@ -47,6 +47,12 @@
<content_rating type="oars-1.1" /> <content_rating type="oars-1.1" />
<releases> <releases>
<release version="25.01.1" date="2025-01-19">
<url>https://github.com/helix-editor/helix/releases/tag/25.01.1</url>
</release>
<release version="25.01" date="2025-01-03">
<url>https://helix-editor.com/news/release-25-01-highlights/</url>
</release>
<release version="24.07" date="2024-07-14"> <release version="24.07" date="2024-07-14">
<url>https://github.com/helix-editor/helix/releases/tag/24.07</url> <url>https://github.com/helix-editor/helix/releases/tag/24.07</url>
</release> </release>

3
contrib/hx_launcher.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/usr/bin/env sh
HELIX_RUNTIME=/usr/lib/helix/runtime exec /usr/lib/helix/hx "$@"

View File

@@ -16,7 +16,7 @@ being published.
* 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) * 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)
* Tag and push * Tag and push
* Switch to master and pull * Switch to master and pull
* `git tag -s -m "<tag>" -a <tag> && git push` (note the `-s` which signs the tag) * `git tag -s -m "<tag>" -a <tag> && git push origin <tag>` (note the `-s` which signs the tag)
* Wait for the Release CI to finish * Wait for the Release CI to finish
* It will automatically turn the git tag into a GitHub release when it uploads artifacts * It will automatically turn the git tag into a GitHub release when it uploads artifacts
* Edit the new release * Edit the new release

View File

@@ -138,6 +138,8 @@
cp contrib/helix.png $out/share/icons/hicolor/256x256/apps cp contrib/helix.png $out/share/icons/hicolor/256x256/apps
installShellCompletion contrib/completion/hx.{bash,fish,zsh} installShellCompletion contrib/completion/hx.{bash,fish,zsh}
''; '';
# set git revision for nix flake builds, see 'git_hash' in helix-loader/build.rs
HELIX_NIX_BUILD_REV = self.rev or self.dirtyRev or null;
}); });
helix = makeOverridableHelix self.packages.${system}.helix-unwrapped {}; helix = makeOverridableHelix self.packages.${system}.helix-unwrapped {};
default = self.packages.${system}.helix; default = self.packages.${system}.helix;

View File

@@ -36,7 +36,7 @@ tree-sitter.workspace = true
once_cell = "1.20" once_cell = "1.20"
arc-swap = "1" arc-swap = "1"
regex = "1" regex = "1"
bitflags = "2.6" bitflags.workspace = true
ahash = "0.8.11" ahash = "0.8.11"
hashbrown = { version = "0.14.5", features = ["raw"] } hashbrown = { version = "0.14.5", features = ["raw"] }
dunce = "1.0" dunce = "1.0"

View File

@@ -2666,12 +2666,20 @@ fn node_is_visible(node: &Node) -> bool {
node.is_missing() || (node.is_named() && node.language().node_kind_is_visible(node.kind_id())) node.is_missing() || (node.is_named() && node.language().node_kind_is_visible(node.kind_id()))
} }
fn format_anonymous_node_kind(kind: &str) -> Cow<str> {
if kind.contains('"') {
Cow::Owned(kind.replace('"', "\\\""))
} else {
Cow::Borrowed(kind)
}
}
pub fn pretty_print_tree<W: fmt::Write>(fmt: &mut W, node: Node) -> fmt::Result { pub fn pretty_print_tree<W: fmt::Write>(fmt: &mut W, node: Node) -> fmt::Result {
if node.child_count() == 0 { if node.child_count() == 0 {
if node_is_visible(&node) { if node_is_visible(&node) {
write!(fmt, "({})", node.kind()) write!(fmt, "({})", node.kind())
} else { } else {
write!(fmt, "\"{}\"", node.kind()) write!(fmt, "\"{}\"", format_anonymous_node_kind(node.kind()))
} }
} else { } else {
pretty_print_tree_impl(fmt, &mut node.walk(), 0) pretty_print_tree_impl(fmt, &mut node.walk(), 0)
@@ -2696,7 +2704,7 @@ fn pretty_print_tree_impl<W: fmt::Write>(
write!(fmt, "({}", node.kind())?; write!(fmt, "({}", node.kind())?;
} else { } else {
write!(fmt, " \"{}\"", node.kind())?; write!(fmt, " \"{}\"", format_anonymous_node_kind(node.kind()))?;
} }
// Handle children. // Handle children.
@@ -2973,8 +2981,8 @@ mod test {
" (macro_invocation\n", " (macro_invocation\n",
" macro: (identifier) \"!\"\n", " macro: (identifier) \"!\"\n",
" (token_tree \"(\"\n", " (token_tree \"(\"\n",
" (string_literal \"\"\"\n", " (string_literal \"\\\"\"\n",
" (string_content) \"\"\") \")\")) \";\") \"}\"))", " (string_content) \"\\\"\") \")\")) \";\") \"}\"))",
), ),
0, 0,
source.len(), source.len(),

View File

@@ -30,7 +30,7 @@ log = "0.4"
# cloning/compiling tree-sitter grammars # cloning/compiling tree-sitter grammars
cc = { version = "1" } cc = { version = "1" }
threadpool = { version = "1.0" } threadpool = { version = "1.0" }
tempfile = "3.14.0" tempfile.workspace = true
dunce = "1.0.5" dunce = "1.0.5"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies] [target.'cfg(not(target_arch = "wasm32"))'.dependencies]

View File

@@ -6,23 +6,26 @@ const MAJOR: &str = env!("CARGO_PKG_VERSION_MAJOR");
const MINOR: &str = env!("CARGO_PKG_VERSION_MINOR"); const MINOR: &str = env!("CARGO_PKG_VERSION_MINOR");
const PATCH: &str = env!("CARGO_PKG_VERSION_PATCH"); const PATCH: &str = env!("CARGO_PKG_VERSION_PATCH");
fn get_calver() -> String {
if PATCH == "0" {
format!("{MAJOR}.{MINOR}")
} else {
format!("{MAJOR}.{MINOR}.{PATCH}")
}
}
fn main() { fn main() {
let git_hash = Command::new("git") let git_hash = Command::new("git")
.args(["rev-parse", "HEAD"]) .args(["rev-parse", "HEAD"])
.output() .output()
.ok() .ok()
.filter(|output| output.status.success()) .filter(|output| output.status.success())
.and_then(|x| String::from_utf8(x.stdout).ok()); .and_then(|x| String::from_utf8(x.stdout).ok())
.or_else(|| option_env!("HELIX_NIX_BUILD_REV").map(|s| s.to_string()));
let calver = get_calver(); let minor = if MINOR.len() == 1 {
// Print single-digit months in '0M' format
format!("0{MINOR}")
} else {
MINOR.to_string()
};
let calver = if PATCH == "0" {
format!("{MAJOR}.{minor}")
} else {
format!("{MAJOR}.{minor}.{PATCH}")
};
let version: Cow<_> = match &git_hash { let version: Cow<_> = match &git_hash {
Some(git_hash) => format!("{} ({})", calver, &git_hash[..8]).into(), Some(git_hash) => format!("{} ({})", calver, &git_hash[..8]).into(),
None => calver.into(), None => calver.into(),

View File

@@ -21,9 +21,9 @@ keywords = ["language", "server", "lsp", "vscode", "lsif"]
license = "MIT" license = "MIT"
[dependencies] [dependencies]
bitflags = "2.6.0" bitflags.workspace = true
serde = { version = "1.0.216", features = ["derive"] } serde = { version = "1.0.217", features = ["derive"] }
serde_json = "1.0.133" serde_json = "1.0.135"
serde_repr = "0.1" serde_repr = "0.1"
url = {version = "2.5.4", features = ["serde"]} url = {version = "2.5.4", features = ["serde"]}

View File

@@ -1,10 +1,9 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
use url::Url;
use crate::{ use crate::{
DynamicRegistrationClientCapabilities, PartialResultParams, Range, SymbolKind, SymbolTag, DynamicRegistrationClientCapabilities, PartialResultParams, Range, SymbolKind, SymbolTag,
TextDocumentPositionParams, WorkDoneProgressOptions, WorkDoneProgressParams, TextDocumentPositionParams, Url, WorkDoneProgressOptions, WorkDoneProgressParams,
}; };
pub type CallHierarchyClientCapabilities = DynamicRegistrationClientCapabilities; pub type CallHierarchyClientCapabilities = DynamicRegistrationClientCapabilities;

View File

@@ -1,11 +1,10 @@
use std::collections::HashMap; use std::collections::HashMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use url::Url;
use crate::{ use crate::{
Diagnostic, PartialResultParams, StaticRegistrationOptions, TextDocumentIdentifier, Diagnostic, PartialResultParams, StaticRegistrationOptions, TextDocumentIdentifier,
TextDocumentRegistrationOptions, WorkDoneProgressOptions, WorkDoneProgressParams, TextDocumentRegistrationOptions, Url, WorkDoneProgressOptions, WorkDoneProgressParams,
}; };
/// Client capabilities specific to diagnostic pull requests. /// Client capabilities specific to diagnostic pull requests.

View File

@@ -1,10 +1,9 @@
use crate::{ use crate::{
PartialResultParams, Range, TextDocumentIdentifier, WorkDoneProgressOptions, PartialResultParams, Range, TextDocumentIdentifier, Url, WorkDoneProgressOptions,
WorkDoneProgressParams, WorkDoneProgressParams,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
use url::Url;
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]

View File

@@ -16,8 +16,8 @@ able to parse any URI, such as `urn:isbn:0451450523`.
*/ */
#![allow(non_upper_case_globals)] #![allow(non_upper_case_globals)]
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#[macro_use]
extern crate bitflags; use bitflags::bitflags;
use std::{collections::HashMap, fmt::Debug}; use std::{collections::HashMap, fmt::Debug};

View File

@@ -4,9 +4,7 @@ use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
use url::Url; use crate::{Range, Url};
use crate::Range;
#[derive(Eq, PartialEq, Clone, Copy, Deserialize, Serialize)] #[derive(Eq, PartialEq, Clone, Copy, Deserialize, Serialize)]
#[serde(transparent)] #[serde(transparent)]

View File

@@ -1,8 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use url::Url;
use crate::{ use crate::{
FullDocumentDiagnosticReport, PartialResultParams, UnchangedDocumentDiagnosticReport, FullDocumentDiagnosticReport, PartialResultParams, UnchangedDocumentDiagnosticReport, Url,
WorkDoneProgressParams, WorkDoneProgressParams,
}; };

View File

@@ -1,7 +1,6 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use url::Url;
use crate::OneOf; use crate::{OneOf, Url};
#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]

View File

@@ -26,7 +26,7 @@ globset = "0.4.15"
log = "0.4" log = "0.4"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
tokio = { version = "1.42", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] } tokio = { version = "1.43", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] }
tokio-stream = "0.1.17" tokio-stream = "0.1.17"
parking_lot = "0.12.3" parking_lot = "0.12.3"
arc-swap = "1" arc-swap = "1"

View File

@@ -104,10 +104,37 @@ impl std::error::Error for Error {}
#[serde(untagged)] #[serde(untagged)]
pub enum Id { pub enum Id {
Null, Null,
Num(u64), Num(#[serde(deserialize_with = "deserialize_jsonrpc_id_num")] u64),
Str(String), Str(String),
} }
fn deserialize_jsonrpc_id_num<'de, D>(deserializer: D) -> Result<u64, D::Error>
where
D: serde::Deserializer<'de>,
{
let num = serde_json::Number::deserialize(deserializer)?;
if let Some(val) = num.as_u64() {
return Ok(val);
};
// Accept floats as long as they represent positive whole numbers.
// The JSONRPC spec says "Numbers SHOULD NOT contain fractional parts" so we should try to
// accept them if possible. The JavaScript type system lumps integers and floats together so
// some languages may serialize integer IDs as floats with a zeroed fractional part.
// See <https://github.com/helix-editor/helix/issues/12367>.
if let Some(val) = num
.as_f64()
.filter(|f| f.is_sign_positive() && f.fract() == 0.0)
{
return Ok(val as u64);
}
Err(de::Error::custom(
"number must be integer or float representing a whole number in valid u64 range",
))
}
impl std::fmt::Display for Id { impl std::fmt::Display for Id {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
@@ -375,6 +402,22 @@ fn serialize_skip_none_params() {
assert_eq!(serialized, r#"{"jsonrpc":"2.0","method":"exit"}"#); assert_eq!(serialized, r#"{"jsonrpc":"2.0","method":"exit"}"#);
} }
#[test]
fn id_deserialize() {
use serde_json;
let id = r#"8"#;
let deserialized: Id = serde_json::from_str(id).unwrap();
assert_eq!(deserialized, Id::Num(8));
let id = r#"4.0"#;
let deserialized: Id = serde_json::from_str(id).unwrap();
assert_eq!(deserialized, Id::Num(4));
let id = r#"0.01"#;
assert!(serde_json::from_str::<Id>(id).is_err());
}
#[test] #[test]
fn success_output_deserialize() { fn success_output_deserialize() {
use serde_json; use serde_json;

View File

@@ -701,7 +701,11 @@ impl Registry {
} }
if let Some((_, client)) = clients.iter().enumerate().find(|(i, client)| { if let Some((_, client)) = clients.iter().enumerate().find(|(i, client)| {
client.try_add_doc(&language_config.roots, root_dirs, doc_path, *i == 0) let manual_roots = language_config
.workspace_lsp_roots
.as_deref()
.unwrap_or(root_dirs);
client.try_add_doc(&language_config.roots, manual_roots, doc_path, *i == 0)
}) { }) {
return Some((name.to_owned(), Ok(client.clone()))); return Some((name.to_owned(), Ok(client.clone())));
} }

View File

@@ -17,7 +17,7 @@ etcetera = "0.8"
ropey = { version = "1.6.1", default-features = false } ropey = { version = "1.6.1", default-features = false }
which = "7.0" which = "7.0"
regex-cursor = "0.1.4" regex-cursor = "0.1.4"
bitflags = "2.6" bitflags.workspace = true
once_cell = "1.19" once_cell = "1.19"
regex-automata = "0.4.9" regex-automata = "0.4.9"
@@ -28,4 +28,4 @@ windows-sys = { version = "0.59", features = ["Win32_Foundation", "Win32_Securit
rustix = { version = "0.38", features = ["fs"] } rustix = { version = "0.38", features = ["fs"] }
[dev-dependencies] [dev-dependencies]
tempfile = "3.14" tempfile.workspace = true

View File

@@ -103,6 +103,12 @@ fn expand_impl(src: &OsStr, mut resolve: impl FnMut(&OsStr) -> Option<OsString>)
let mat = captures.get_match().unwrap(); let mat = captures.get_match().unwrap();
let pattern_id = mat.pattern().as_usize(); let pattern_id = mat.pattern().as_usize();
let mut range = mat.range(); let mut range = mat.range();
// A pattern may match multiple times on a single variable, for example `${HOME:-$HOME}`:
// `${HOME:-` matches and also the default value (`$HOME`). Skip past any variables which
// have already been expanded.
if range.start < pos {
continue;
}
let var = &bytes[captures.get_group(1).unwrap().range()]; let var = &bytes[captures.get_group(1).unwrap().range()];
let default = if pattern_id != 5 { let default = if pattern_id != 5 {
let Some(bracket_pos) = find_brace_end(&bytes[range.end..]) else { let Some(bracket_pos) = find_brace_end(&bytes[range.end..]) else {
@@ -203,6 +209,7 @@ mod tests {
assert_env_expand!(env, "bar/$FOO/baz", "bar/foo/baz"); assert_env_expand!(env, "bar/$FOO/baz", "bar/foo/baz");
assert_env_expand!(env, "bar/${FOO}/baz", "bar/foo/baz"); assert_env_expand!(env, "bar/${FOO}/baz", "bar/foo/baz");
assert_env_expand!(env, "baz/${BAR:-bar}/foo", "baz/bar/foo"); assert_env_expand!(env, "baz/${BAR:-bar}/foo", "baz/bar/foo");
assert_env_expand!(env, "baz/${FOO:-$FOO}/foo", "baz/foo/foo");
assert_env_expand!(env, "baz/${BAR:=bar}/foo", "baz/bar/foo"); assert_env_expand!(env, "baz/${BAR:=bar}/foo", "baz/bar/foo");
assert_env_expand!(env, "baz/${BAR-bar}/foo", "baz/bar/foo"); assert_env_expand!(env, "baz/${BAR-bar}/foo", "baz/bar/foo");
assert_env_expand!(env, "baz/${BAR=bar}/foo", "baz/bar/foo"); assert_env_expand!(env, "baz/${BAR=bar}/foo", "baz/bar/foo");

View File

@@ -33,7 +33,9 @@ where
} }
/// Expands tilde `~` into users home directory if available, otherwise returns the path /// Expands tilde `~` into users home directory if available, otherwise returns the path
/// unchanged. The tilde will only be expanded when present as the first component of the path /// unchanged.
///
/// The tilde will only be expanded when present as the first component of the path
/// and only slash follows it. /// and only slash follows it.
pub fn expand_tilde<'a, P>(path: P) -> Cow<'a, Path> pub fn expand_tilde<'a, P>(path: P) -> Cow<'a, Path>
where where
@@ -54,11 +56,11 @@ where
} }
/// Normalize a path without resolving symlinks. /// Normalize a path without resolving symlinks.
// Strategy: start from the first component and move up. Cannonicalize previous path, // Strategy: start from the first component and move up. Canonicalize previous path,
// join component, canonicalize new path, strip prefix and join to the final result. // join component, canonicalize new path, strip prefix and join to the final result.
pub fn normalize(path: impl AsRef<Path>) -> PathBuf { pub fn normalize(path: impl AsRef<Path>) -> PathBuf {
let mut components = path.as_ref().components().peekable(); let mut components = path.as_ref().components().peekable();
let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() { let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().copied() {
components.next(); components.next();
PathBuf::from(c.as_os_str()) PathBuf::from(c.as_os_str())
} else { } else {
@@ -209,7 +211,7 @@ fn path_component_regex(windows: bool) -> String {
// TODO: support backslash path escape on windows (when using git bash for example) // TODO: support backslash path escape on windows (when using git bash for example)
let space_escape = if windows { r"[\^`]\s" } else { r"[\\]\s" }; let space_escape = if windows { r"[\^`]\s" } else { r"[\\]\s" };
// partially baesd on what's allowed in an url but with some care to avoid // partially baesd on what's allowed in an url but with some care to avoid
// false positivies (like any kind of brackets or quotes) // false positives (like any kind of brackets or quotes)
r"[\w@.\-+#$%?!,;~&]|".to_owned() + space_escape r"[\w@.\-+#$%?!,;~&]|".to_owned() + space_escape
} }

View File

@@ -12,6 +12,24 @@ categories.workspace = true
repository.workspace = true repository.workspace = true
homepage.workspace = true homepage.workspace = true
[package.metadata.deb]
# generate a .deb in target/debian/ with the command: cargo deb --no-build
name = "helix"
assets = [
{ source = "target/release/hx", dest = "/usr/lib/helix/", mode = "755" },
{ source = "../contrib/hx_launcher.sh", dest = "/usr/bin/hx", mode = "755" },
{ source = "../runtime/*", dest = "/usr/lib/helix/runtime/", mode = "644" },
{ source = "../runtime/grammars/*", dest = "/usr/lib/helix/runtime/grammars/", mode = "644" }, # to avoid sources/
{ source = "../runtime/queries/**/*", dest = "/usr/lib/helix/runtime/queries/", mode = "644" },
{ source = "../runtime/themes/**/*", dest = "/usr/lib/helix/runtime/themes/", mode = "644" },
{ source = "../README.md", dest = "/usr/share/doc/helix/", mode = "644" },
{ source = "../contrib/completion/hx.bash", dest = "/usr/share/bash-completion/completions/hx", mode = "644" },
{ source = "../contrib/completion/hx.fish", dest = "/usr/share/fish/vendor_completions.d/hx.fish", mode = "644" },
{ source = "../contrib/completion/hx.zsh", dest = "/usr/share/zsh/vendor-completions/_hx", mode = "644" },
{ source = "../contrib/Helix.desktop", dest = "/usr/share/applications/Helix.desktop", mode = "644" },
{ source = "../contrib/helix.png", dest = "/usr/share/icons/hicolor/256x256/apps/helix.png", mode = "644" },
]
[features] [features]
default = ["git"] default = ["git"]
unicode-lines = ["helix-core/unicode-lines", "helix-view/unicode-lines"] unicode-lines = ["helix-core/unicode-lines", "helix-view/unicode-lines"]
@@ -59,7 +77,7 @@ content_inspector = "0.2.4"
thiserror.workspace = true thiserror.workspace = true
# opening URLs # opening URLs
open = "5.3.1" open = "5.3.2"
url = "2.5.4" url = "2.5.4"
# config # config
@@ -74,7 +92,7 @@ grep-searcher = "0.1.14"
[target.'cfg(not(windows))'.dependencies] # https://github.com/vorner/signal-hook/issues/100 [target.'cfg(not(windows))'.dependencies] # https://github.com/vorner/signal-hook/issues/100
signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] } signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }
libc = "0.2.168" libc = "0.2.169"
[target.'cfg(target_os = "macos")'.dependencies] [target.'cfg(target_os = "macos")'.dependencies]
crossterm = { version = "0.28", features = ["event-stream", "use-dev-tty", "libc"] } crossterm = { version = "0.28", features = ["event-stream", "use-dev-tty", "libc"] }
@@ -85,5 +103,5 @@ helix-loader = { path = "../helix-loader" }
[dev-dependencies] [dev-dependencies]
smallvec = "1.13" smallvec = "1.13"
indoc = "2.0.5" indoc = "2.0.5"
tempfile = "3.14.0" tempfile.workspace = true
same-file = "1.0.1" same-file = "1.0.1"

View File

@@ -129,7 +129,7 @@ pub(crate) fn parse_file(s: &str) -> (PathBuf, Position) {
/// ///
/// Does not validate if file.rs is a file or directory. /// Does not validate if file.rs is a file or directory.
fn split_path_row_col(s: &str) -> Option<(PathBuf, Position)> { fn split_path_row_col(s: &str) -> Option<(PathBuf, Position)> {
let mut s = s.rsplitn(3, ':'); let mut s = s.trim_end_matches(':').rsplitn(3, ':');
let col: usize = s.next()?.parse().ok()?; let col: usize = s.next()?.parse().ok()?;
let row: usize = s.next()?.parse().ok()?; let row: usize = s.next()?.parse().ok()?;
let path = s.next()?.into(); let path = s.next()?.into();
@@ -141,7 +141,7 @@ fn split_path_row_col(s: &str) -> Option<(PathBuf, Position)> {
/// ///
/// Does not validate if file.rs is a file or directory. /// Does not validate if file.rs is a file or directory.
fn split_path_row(s: &str) -> Option<(PathBuf, Position)> { fn split_path_row(s: &str) -> Option<(PathBuf, Position)> {
let (path, row) = s.rsplit_once(':')?; let (path, row) = s.trim_end_matches(':').rsplit_once(':')?;
let row: usize = row.parse().ok()?; let row: usize = row.parse().ok()?;
let path = path.into(); let path = path.into();
let pos = Position::new(row.saturating_sub(1), 0); let pos = Position::new(row.saturating_sub(1), 0);

View File

@@ -2183,7 +2183,7 @@ fn searcher(cx: &mut Context, direction: Direction) {
completions completions
.iter() .iter()
.filter(|comp| comp.starts_with(input)) .filter(|comp| comp.starts_with(input))
.map(|comp| (0.., std::borrow::Cow::Owned(comp.clone()))) .map(|comp| (0.., comp.clone().into()))
.collect() .collect()
}, },
move |cx, regex, event| { move |cx, regex, event| {
@@ -2792,7 +2792,7 @@ fn delete_selection_impl(cx: &mut Context, op: Operation, yank: YankAction) {
} }
Operation::Change => { Operation::Change => {
if only_whole_lines { if only_whole_lines {
open_above(cx); open(cx, Open::Above, CommentContinuation::Disabled);
} else { } else {
enter_insert_mode(cx); enter_insert_mode(cx);
} }
@@ -3044,12 +3044,11 @@ fn buffer_picker(cx: &mut Context) {
}) })
.with_preview(|editor, meta| { .with_preview(|editor, meta| {
let doc = &editor.documents.get(&meta.id)?; let doc = &editor.documents.get(&meta.id)?;
let &view_id = doc.selections().keys().next()?; let lines = doc.selections().values().next().map(|selection| {
let line = doc let cursor_line = selection.primary().cursor_line(doc.text().slice(..));
.selection(view_id) (cursor_line, cursor_line)
.primary() });
.cursor_line(doc.text().slice(..)); Some((meta.id.into(), lines))
Some((meta.id.into(), Some((line, line))))
}); });
cx.push_layer(Box::new(overlaid(picker))); cx.push_layer(Box::new(overlaid(picker)));
} }
@@ -3439,14 +3438,19 @@ async fn make_format_callback(
let doc = doc_mut!(editor, &doc_id); let doc = doc_mut!(editor, &doc_id);
let view = view_mut!(editor, view_id); let view = view_mut!(editor, view_id);
if let Ok(format) = format { match format {
if doc.version() == doc_version { Ok(format) => {
doc.apply(&format, view.id); if doc.version() == doc_version {
doc.append_changes_to_history(view); doc.apply(&format, view.id);
doc.detect_indent_and_line_ending(); doc.append_changes_to_history(view);
view.ensure_cursor_in_view(doc, scrolloff); doc.detect_indent_and_line_ending();
} else { view.ensure_cursor_in_view(doc, scrolloff);
log::info!("discarded formatting changes because the document changed"); } else {
log::info!("discarded formatting changes because the document changed");
}
}
Err(err) => {
log::info!("failed to format '{}': {err}", doc.display_name());
} }
} }
@@ -3467,17 +3471,33 @@ pub enum Open {
Above, Above,
} }
fn open(cx: &mut Context, open: Open) { #[derive(PartialEq)]
pub enum CommentContinuation {
Enabled,
Disabled,
}
fn open(cx: &mut Context, open: Open, comment_continuation: CommentContinuation) {
let count = cx.count(); let count = cx.count();
enter_insert_mode(cx); enter_insert_mode(cx);
let config = cx.editor.config();
let (view, doc) = current!(cx.editor); let (view, doc) = current!(cx.editor);
let text = doc.text().slice(..); let text = doc.text().slice(..);
let contents = doc.text(); let contents = doc.text();
let selection = doc.selection(view.id); let selection = doc.selection(view.id);
let mut offs = 0;
let mut ranges = SmallVec::with_capacity(selection.len()); let mut ranges = SmallVec::with_capacity(selection.len());
let continue_comment_tokens =
if comment_continuation == CommentContinuation::Enabled && config.continue_comments {
doc.language_config()
.and_then(|config| config.comment_tokens.as_ref())
} else {
None
};
let mut transaction = Transaction::change_by_selection(contents, selection, |range| { let mut transaction = Transaction::change_by_selection(contents, selection, |range| {
// the line number, where the cursor is currently // the line number, where the cursor is currently
let curr_line_num = text.char_to_line(match open { let curr_line_num = text.char_to_line(match open {
@@ -3493,13 +3513,8 @@ fn open(cx: &mut Context, open: Open) {
let above_next_new_line_num = next_new_line_num.saturating_sub(1); let above_next_new_line_num = next_new_line_num.saturating_sub(1);
let continue_comment_token = if doc.config.load().continue_comments { let continue_comment_token = continue_comment_tokens
doc.language_config() .and_then(|tokens| comment::get_comment_token(text, tokens, curr_line_num));
.and_then(|config| config.comment_tokens.as_ref())
.and_then(|tokens| comment::get_comment_token(text, tokens, curr_line_num))
} else {
None
};
// Index to insert newlines after, as well as the char width // Index to insert newlines after, as well as the char width
// to use to compensate for those inserted newlines. // to use to compensate for those inserted newlines.
@@ -3518,7 +3533,7 @@ fn open(cx: &mut Context, open: Open) {
_ => indent::indent_for_newline( _ => indent::indent_for_newline(
doc.language_config(), doc.language_config(),
doc.syntax(), doc.syntax(),
&doc.config.load().indent_heuristic, &config.indent_heuristic,
&doc.indent_style, &doc.indent_style,
doc.tab_width(), doc.tab_width(),
text, text,
@@ -3551,7 +3566,7 @@ fn open(cx: &mut Context, open: Open) {
let text = text.repeat(count); let text = text.repeat(count);
// calculate new selection ranges // calculate new selection ranges
let pos = above_next_line_end_index + above_next_line_end_width; let pos = offs + above_next_line_end_index + above_next_line_end_width;
let comment_len = continue_comment_token let comment_len = continue_comment_token
.map(|token| token.len() + 1) // `+ 1` for the extra space added .map(|token| token.len() + 1) // `+ 1` for the extra space added
.unwrap_or_default(); .unwrap_or_default();
@@ -3564,6 +3579,9 @@ fn open(cx: &mut Context, open: Open) {
)); ));
} }
// update the offset for the next range
offs += text.chars().count();
( (
above_next_line_end_index, above_next_line_end_index,
above_next_line_end_index, above_next_line_end_index,
@@ -3578,12 +3596,12 @@ fn open(cx: &mut Context, open: Open) {
// o inserts a new line after each line with a selection // o inserts a new line after each line with a selection
fn open_below(cx: &mut Context) { fn open_below(cx: &mut Context) {
open(cx, Open::Below) open(cx, Open::Below, CommentContinuation::Enabled)
} }
// O inserts a new line before each line with a selection // O inserts a new line before each line with a selection
fn open_above(cx: &mut Context) { fn open_above(cx: &mut Context) {
open(cx, Open::Above) open(cx, Open::Above, CommentContinuation::Enabled)
} }
fn normal_mode(cx: &mut Context) { fn normal_mode(cx: &mut Context) {
@@ -3977,17 +3995,29 @@ pub mod insert {
} }
pub fn insert_newline(cx: &mut Context) { pub fn insert_newline(cx: &mut Context) {
let config = cx.editor.config();
let (view, doc) = current_ref!(cx.editor); let (view, doc) = current_ref!(cx.editor);
let text = doc.text().slice(..); let text = doc.text().slice(..);
let line_ending = doc.line_ending.as_str();
let contents = doc.text(); let contents = doc.text();
let selection = doc.selection(view.id).clone(); let selection = doc.selection(view.id);
let mut ranges = SmallVec::with_capacity(selection.len()); let mut ranges = SmallVec::with_capacity(selection.len());
// TODO: this is annoying, but we need to do it to properly calculate pos after edits // TODO: this is annoying, but we need to do it to properly calculate pos after edits
let mut global_offs = 0; let mut global_offs = 0;
let mut new_text = String::new();
let mut transaction = Transaction::change_by_selection(contents, &selection, |range| { let continue_comment_tokens = if config.continue_comments {
doc.language_config()
.and_then(|config| config.comment_tokens.as_ref())
} else {
None
};
let mut transaction = Transaction::change_by_selection(contents, selection, |range| {
// Tracks the number of trailing whitespace characters deleted by this selection.
let mut chars_deleted = 0;
let pos = range.cursor(text); let pos = range.cursor(text);
let prev = if pos == 0 { let prev = if pos == 0 {
@@ -4000,15 +4030,8 @@ pub mod insert {
let current_line = text.char_to_line(pos); let current_line = text.char_to_line(pos);
let line_start = text.line_to_char(current_line); let line_start = text.line_to_char(current_line);
let mut new_text = String::new(); let continue_comment_token = continue_comment_tokens
.and_then(|tokens| comment::get_comment_token(text, tokens, current_line));
let continue_comment_token = if doc.config.load().continue_comments {
doc.language_config()
.and_then(|config| config.comment_tokens.as_ref())
.and_then(|tokens| comment::get_comment_token(text, tokens, current_line))
} else {
None
};
let (from, to, local_offs) = if let Some(idx) = let (from, to, local_offs) = if let Some(idx) =
text.slice(line_start..pos).last_non_whitespace_char() text.slice(line_start..pos).last_non_whitespace_char()
@@ -4021,7 +4044,7 @@ pub mod insert {
_ => indent::indent_for_newline( _ => indent::indent_for_newline(
doc.language_config(), doc.language_config(),
doc.syntax(), doc.syntax(),
&doc.config.load().indent_heuristic, &config.indent_heuristic,
&doc.indent_style, &doc.indent_style,
doc.tab_width(), doc.tab_width(),
text, text,
@@ -4040,7 +4063,8 @@ pub mod insert {
.map_or(false, |pair| pair.open == prev && pair.close == curr); .map_or(false, |pair| pair.open == prev && pair.close == curr);
let local_offs = if let Some(token) = continue_comment_token { let local_offs = if let Some(token) = continue_comment_token {
new_text.push_str(doc.line_ending.as_str()); new_text.reserve_exact(line_ending.len() + indent.len() + token.len() + 1);
new_text.push_str(line_ending);
new_text.push_str(&indent); new_text.push_str(&indent);
new_text.push_str(token); new_text.push_str(token);
new_text.push(' '); new_text.push(' ');
@@ -4048,37 +4072,39 @@ pub mod insert {
} else if on_auto_pair { } else if on_auto_pair {
// line where the cursor will be // line where the cursor will be
let inner_indent = indent.clone() + doc.indent_style.as_str(); let inner_indent = indent.clone() + doc.indent_style.as_str();
new_text.reserve_exact(2 + indent.len() + inner_indent.len()); new_text
new_text.push_str(doc.line_ending.as_str()); .reserve_exact(line_ending.len() * 2 + indent.len() + inner_indent.len());
new_text.push_str(line_ending);
new_text.push_str(&inner_indent); new_text.push_str(&inner_indent);
// line where the matching pair will be // line where the matching pair will be
let local_offs = new_text.chars().count(); let local_offs = new_text.chars().count();
new_text.push_str(doc.line_ending.as_str()); new_text.push_str(line_ending);
new_text.push_str(&indent); new_text.push_str(&indent);
local_offs local_offs
} else { } else {
new_text.reserve_exact(1 + indent.len()); new_text.reserve_exact(line_ending.len() + indent.len());
new_text.push_str(doc.line_ending.as_str()); new_text.push_str(line_ending);
new_text.push_str(&indent); new_text.push_str(&indent);
new_text.chars().count() new_text.chars().count()
}; };
// Note that `first_trailing_whitespace_char` is at least `pos` so this unsigned
// subtraction cannot underflow.
chars_deleted = pos - first_trailing_whitespace_char;
( (
first_trailing_whitespace_char, first_trailing_whitespace_char,
pos, pos,
// Note that `first_trailing_whitespace_char` is at least `pos` so the local_offs as isize - chars_deleted as isize,
// unsigned subtraction (`pos - first_trailing_whitespace_char`) cannot
// underflow.
local_offs as isize - (pos - first_trailing_whitespace_char) as isize,
) )
} else { } else {
// If the current line is all whitespace, insert a line ending at the beginning of // If the current line is all whitespace, insert a line ending at the beginning of
// the current line. This makes the current line empty and the new line contain the // the current line. This makes the current line empty and the new line contain the
// indentation of the old line. // indentation of the old line.
new_text.push_str(doc.line_ending.as_str()); new_text.push_str(line_ending);
(line_start, line_start, new_text.chars().count() as isize) (line_start, line_start, new_text.chars().count() as isize)
}; };
@@ -4086,14 +4112,14 @@ pub mod insert {
let new_range = if range.cursor(text) > range.anchor { let new_range = if range.cursor(text) > range.anchor {
// when appending, extend the range by local_offs // when appending, extend the range by local_offs
Range::new( Range::new(
range.anchor + global_offs, (range.anchor as isize + global_offs) as usize,
(range.head as isize + local_offs) as usize + global_offs, (range.head as isize + local_offs + global_offs) as usize,
) )
} else { } else {
// when inserting, slide the range by local_offs // when inserting, slide the range by local_offs
Range::new( Range::new(
(range.anchor as isize + local_offs) as usize + global_offs, (range.anchor as isize + local_offs + global_offs) as usize,
(range.head as isize + local_offs) as usize + global_offs, (range.head as isize + local_offs + global_offs) as usize,
) )
}; };
@@ -4101,9 +4127,11 @@ pub mod insert {
// range.replace(|range| range.is_empty(), head); -> fn extend if cond true, new head pos // range.replace(|range| range.is_empty(), head); -> fn extend if cond true, new head pos
// can be used with cx.mode to do replace or extend on most changes // can be used with cx.mode to do replace or extend on most changes
ranges.push(new_range); ranges.push(new_range);
global_offs += new_text.chars().count(); global_offs += new_text.chars().count() as isize - chars_deleted as isize;
let tendril = Tendril::from(&new_text);
new_text.clear();
(from, to, Some(new_text.into())) (from, to, Some(tendril))
}); });
transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index())); transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index()));
@@ -4401,6 +4429,8 @@ enum Paste {
Cursor, Cursor,
} }
static LINE_ENDING_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"\r\n|\r|\n").unwrap());
fn paste_impl( fn paste_impl(
values: &[String], values: &[String],
doc: &mut Document, doc: &mut Document,
@@ -4417,26 +4447,26 @@ fn paste_impl(
doc.append_changes_to_history(view); doc.append_changes_to_history(view);
} }
let repeat = std::iter::repeat(
// `values` is asserted to have at least one entry above.
values
.last()
.map(|value| Tendril::from(value.repeat(count)))
.unwrap(),
);
// if any of values ends with a line ending, it's linewise paste // if any of values ends with a line ending, it's linewise paste
let linewise = values let linewise = values
.iter() .iter()
.any(|value| get_line_ending_of_str(value).is_some()); .any(|value| get_line_ending_of_str(value).is_some());
// Only compiled once. let map_value = |value| {
static REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"\r\n|\r|\n").unwrap()); let value = LINE_ENDING_REGEX.replace_all(value, doc.line_ending.as_str());
let mut values = values let mut out = Tendril::from(value.as_ref());
.iter() for _ in 1..count {
.map(|value| REGEX.replace_all(value, doc.line_ending.as_str())) out.push_str(&value);
.map(|value| Tendril::from(value.as_ref().repeat(count))) }
.chain(repeat); out
};
let repeat = std::iter::repeat(
// `values` is asserted to have at least one entry above.
map_value(values.last().unwrap()),
);
let mut values = values.iter().map(|value| map_value(value)).chain(repeat);
let text = doc.text(); let text = doc.text();
let selection = doc.selection(view.id); let selection = doc.selection(view.id);
@@ -4533,19 +4563,24 @@ fn replace_with_yanked_impl(editor: &mut Editor, register: char, count: usize) {
else { else {
return; return;
}; };
let values: Vec<_> = values.map(|value| value.to_string()).collect();
let scrolloff = editor.config().scrolloff; let scrolloff = editor.config().scrolloff;
let (view, doc) = current_ref!(editor);
let (view, doc) = current!(editor); let map_value = |value: &Cow<str>| {
let repeat = std::iter::repeat( let value = LINE_ENDING_REGEX.replace_all(value, doc.line_ending.as_str());
values let mut out = Tendril::from(value.as_ref());
.last() for _ in 1..count {
.map(|value| Tendril::from(&value.repeat(count))) out.push_str(&value);
.unwrap(), }
); out
let mut values = values };
.iter() let mut values_rev = values.rev().peekable();
.map(|value| Tendril::from(&value.repeat(count))) // `values` is asserted to have at least one entry above.
let last = values_rev.peek().unwrap();
let repeat = std::iter::repeat(map_value(last));
let mut values = values_rev
.rev()
.map(|value| map_value(&value))
.chain(repeat); .chain(repeat);
let selection = doc.selection(view.id); let selection = doc.selection(view.id);
let transaction = Transaction::change_by_selection(doc.text(), selection, |range| { let transaction = Transaction::change_by_selection(doc.text(), selection, |range| {
@@ -4555,7 +4590,9 @@ fn replace_with_yanked_impl(editor: &mut Editor, register: char, count: usize) {
(range.from(), range.to(), None) (range.from(), range.to(), None)
} }
}); });
drop(values);
let (view, doc) = current!(editor);
doc.apply(&transaction, view.id); doc.apply(&transaction, view.id);
doc.append_changes_to_history(view); doc.append_changes_to_history(view);
view.ensure_cursor_in_view(doc, scrolloff); view.ensure_cursor_in_view(doc, scrolloff);
@@ -4772,7 +4809,7 @@ fn join_selections_impl(cx: &mut Context, select_space: bool) {
changes.reserve(lines.len()); changes.reserve(lines.len());
let first_line_idx = slice.line_to_char(start); let first_line_idx = slice.line_to_char(start);
let first_line_idx = skip_while(slice, first_line_idx, |ch| matches!(ch, ' ' | 't')) let first_line_idx = skip_while(slice, first_line_idx, |ch| matches!(ch, ' ' | '\t'))
.unwrap_or(first_line_idx); .unwrap_or(first_line_idx);
let first_line = slice.slice(first_line_idx..); let first_line = slice.slice(first_line_idx..);
let mut current_comment_token = comment_tokens let mut current_comment_token = comment_tokens
@@ -5711,8 +5748,17 @@ fn select_textobject(cx: &mut Context, objtype: textobject::TextObject) {
cx.editor.autoinfo = Some(Info::new(title, &help_text)); cx.editor.autoinfo = Some(Info::new(title, &help_text));
} }
static SURROUND_HELP_TEXT: [(&str, &str); 5] = [
("( or )", "Parentheses"),
("{ or }", "Curly braces"),
("< or >", "Angled brackets"),
("[ or ]", "Square brackets"),
(" ", "... or any character"),
];
fn surround_add(cx: &mut Context) { fn surround_add(cx: &mut Context) {
cx.on_next_key(move |cx, event| { cx.on_next_key(move |cx, event| {
cx.editor.autoinfo = None;
let (view, doc) = current!(cx.editor); let (view, doc) = current!(cx.editor);
// surround_len is the number of new characters being added. // surround_len is the number of new characters being added.
let (open, close, surround_len) = match event.char() { let (open, close, surround_len) = match event.char() {
@@ -5753,7 +5799,9 @@ fn surround_add(cx: &mut Context) {
.with_selection(Selection::new(ranges, selection.primary_index())); .with_selection(Selection::new(ranges, selection.primary_index()));
doc.apply(&transaction, view.id); doc.apply(&transaction, view.id);
exit_select_mode(cx); exit_select_mode(cx);
}) });
cx.editor.autoinfo = Some(Info::new("Surround selections with", &SURROUND_HELP_TEXT));
} }
fn surround_replace(cx: &mut Context) { fn surround_replace(cx: &mut Context) {
@@ -5785,6 +5833,7 @@ fn surround_replace(cx: &mut Context) {
); );
cx.on_next_key(move |cx, event| { cx.on_next_key(move |cx, event| {
cx.editor.autoinfo = None;
let (view, doc) = current!(cx.editor); let (view, doc) = current!(cx.editor);
let to = match event.char() { let to = match event.char() {
Some(to) => to, Some(to) => to,
@@ -5812,12 +5861,20 @@ fn surround_replace(cx: &mut Context) {
doc.apply(&transaction, view.id); doc.apply(&transaction, view.id);
exit_select_mode(cx); exit_select_mode(cx);
}); });
})
cx.editor.autoinfo = Some(Info::new("Replace with a pair of", &SURROUND_HELP_TEXT));
});
cx.editor.autoinfo = Some(Info::new(
"Replace surrounding pair of",
&SURROUND_HELP_TEXT,
));
} }
fn surround_delete(cx: &mut Context) { fn surround_delete(cx: &mut Context) {
let count = cx.count(); let count = cx.count();
cx.on_next_key(move |cx, event| { cx.on_next_key(move |cx, event| {
cx.editor.autoinfo = None;
let surround_ch = match event.char() { let surround_ch = match event.char() {
Some('m') => None, // m selects the closest surround pair Some('m') => None, // m selects the closest surround pair
Some(ch) => Some(ch), Some(ch) => Some(ch),
@@ -5840,7 +5897,9 @@ fn surround_delete(cx: &mut Context) {
Transaction::change(doc.text(), change_pos.into_iter().map(|p| (p, p + 1, None))); Transaction::change(doc.text(), change_pos.into_iter().map(|p| (p, p + 1, None)));
doc.apply(&transaction, view.id); doc.apply(&transaction, view.id);
exit_select_mode(cx); exit_select_mode(cx);
}) });
cx.editor.autoinfo = Some(Info::new("Delete surrounding pair of", &SURROUND_HELP_TEXT));
} }
#[derive(Eq, PartialEq)] #[derive(Eq, PartialEq)]
@@ -6007,7 +6066,7 @@ fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) {
let input = range.slice(text); let input = range.slice(text);
match shell_impl(shell, cmd, pipe.then(|| input.into())) { match shell_impl(shell, cmd, pipe.then(|| input.into())) {
Ok(mut output) => { Ok(mut output) => {
if !input.ends_with("\n") && !output.is_empty() && output.ends_with('\n') { if !input.ends_with("\n") && output.ends_with('\n') {
output.pop(); output.pop();
if output.ends_with('\r') { if output.ends_with('\r') {
output.pop(); output.pop();

View File

@@ -518,15 +518,16 @@ pub fn dap_variables(cx: &mut Context) {
Some(thread_frame) => thread_frame, Some(thread_frame) => thread_frame,
None => { None => {
cx.editor cx.editor
.set_error("Failed to get stack frame for thread: {thread_id}"); .set_error(format!("Failed to get stack frame for thread: {thread_id}"));
return; return;
} }
}; };
let stack_frame = match thread_frame.get(frame) { let stack_frame = match thread_frame.get(frame) {
Some(stack_frame) => stack_frame, Some(stack_frame) => stack_frame,
None => { None => {
cx.editor cx.editor.set_error(format!(
.set_error("Failed to get stack frame for thread {thread_id} and frame {frame}."); "Failed to get stack frame for thread {thread_id} and frame {frame}."
));
return; return;
} }
}; };

View File

@@ -187,9 +187,7 @@ fn buffer_gather_paths_impl(editor: &mut Editor, args: &[Cow<str>]) -> Vec<Docum
for arg in args { for arg in args {
let doc_id = editor.documents().find_map(|doc| { let doc_id = editor.documents().find_map(|doc| {
let arg_path = Some(Path::new(arg.as_ref())); let arg_path = Some(Path::new(arg.as_ref()));
if doc.path().map(|p| p.as_path()) == arg_path if doc.path().map(|p| p.as_path()) == arg_path || doc.relative_path() == arg_path {
|| doc.relative_path().as_deref() == arg_path
{
Some(doc.id()) Some(doc.id())
} else { } else {
None None
@@ -651,11 +649,12 @@ fn force_write_quit(
/// error, otherwise returns `Ok(())`. If the current document is unmodified, /// error, otherwise returns `Ok(())`. If the current document is unmodified,
/// and there are modified documents, switches focus to one of them. /// and there are modified documents, switches focus to one of them.
pub(super) fn buffers_remaining_impl(editor: &mut Editor) -> anyhow::Result<()> { pub(super) fn buffers_remaining_impl(editor: &mut Editor) -> anyhow::Result<()> {
let (modified_ids, modified_names): (Vec<_>, Vec<_>) = editor let modified_ids: Vec<_> = editor
.documents() .documents()
.filter(|doc| doc.is_modified()) .filter(|doc| doc.is_modified())
.map(|doc| (doc.id(), doc.display_name())) .map(|doc| doc.id())
.unzip(); .collect();
if let Some(first) = modified_ids.first() { if let Some(first) = modified_ids.first() {
let current = doc!(editor); let current = doc!(editor);
// If the current document is unmodified, and there are modified // If the current document is unmodified, and there are modified
@@ -663,6 +662,12 @@ pub(super) fn buffers_remaining_impl(editor: &mut Editor) -> anyhow::Result<()>
if !modified_ids.contains(&current.id()) { if !modified_ids.contains(&current.id()) {
editor.switch(*first, Action::Replace); editor.switch(*first, Action::Replace);
} }
let modified_names: Vec<_> = modified_ids
.iter()
.map(|doc_id| doc!(editor, doc_id).display_name())
.collect();
bail!( bail!(
"{} unsaved buffer{} remaining: {:?}", "{} unsaved buffer{} remaining: {:?}",
modified_names.len(), modified_names.len(),
@@ -1093,14 +1098,19 @@ fn change_current_directory(
let dir = match args.first().map(AsRef::as_ref) { let dir = match args.first().map(AsRef::as_ref) {
Some("-") => cx Some("-") => cx
.editor .editor
.last_cwd .get_last_cwd()
.clone() .map(|path| Cow::Owned(path.to_path_buf()))
.ok_or(anyhow!("No previous working directory"))?, .ok_or_else(|| anyhow!("No previous working directory"))?,
Some(input_path) => helix_stdx::path::expand_tilde(Path::new(input_path)).to_path_buf(), Some(path) => helix_stdx::path::expand_tilde(Path::new(path)),
None => home_dir()?, None => Cow::Owned(home_dir()?),
}; };
cx.editor.last_cwd = helix_stdx::env::set_current_working_dir(dir)?; cx.editor.set_cwd(&dir).map_err(|err| {
anyhow!(
"Could not change working directory to '{}': {err}",
dir.display()
)
})?;
cx.editor.set_status(format!( cx.editor.set_status(format!(
"Current working directory is now {}", "Current working directory is now {}",
@@ -3198,8 +3208,8 @@ pub(super) fn command_mode(cx: &mut Context) {
{ {
completer(editor, word) completer(editor, word)
.into_iter() .into_iter()
.map(|(range, file)| { .map(|(range, mut file)| {
let file = shellwords::escape(file); file.content = shellwords::escape(file.content);
// offset ranges to input // offset ranges to input
let offset = input.len() - word_len; let offset = input.len() - word_len;

View File

@@ -1,6 +1,6 @@
use crate::config::{Config, ConfigLoadError}; use crate::config::{Config, ConfigLoadError};
use crossterm::{ use crossterm::{
style::{Color, Print, Stylize}, style::{Color, StyledContent, Stylize},
tty::IsTty, tty::IsTty,
}; };
use helix_core::config::{default_lang_config, user_lang_config}; use helix_core::config::{default_lang_config, user_lang_config};
@@ -164,25 +164,20 @@ pub fn languages_all() -> std::io::Result<()> {
let column_width = terminal_cols as usize / headings.len(); let column_width = terminal_cols as usize / headings.len();
let is_terminal = std::io::stdout().is_tty(); let is_terminal = std::io::stdout().is_tty();
let column = |item: &str, color: Color| { let fit = |s: &str| -> StyledContent<String> {
let mut data = format!( format!(
"{:width$}", "{:column_width$}",
item.get(..column_width - 2) s.get(..column_width - 2)
.map(|s| format!("{}", s)) .map(|s| format!("{}", s))
.unwrap_or_else(|| item.to_string()), .unwrap_or_else(|| s.to_string())
width = column_width, )
); .stylize()
if is_terminal {
data = data.stylize().with(color).to_string();
}
// We can't directly use println!() because of
// https://github.com/crossterm-rs/crossterm/issues/589
let _ = crossterm::execute!(std::io::stdout(), Print(data));
}; };
let color = |s: StyledContent<String>, c: Color| if is_terminal { s.with(c) } else { s };
let bold = |s: StyledContent<String>| if is_terminal { s.bold() } else { s };
for heading in headings { for heading in headings {
column(heading, Color::White); write!(stdout, "{}", bold(fit(heading)))?;
} }
writeln!(stdout)?; writeln!(stdout)?;
@@ -192,14 +187,14 @@ pub fn languages_all() -> std::io::Result<()> {
let check_binary = |cmd: Option<&str>| match cmd { let check_binary = |cmd: Option<&str>| match cmd {
Some(cmd) => match helix_stdx::env::which(cmd) { Some(cmd) => match helix_stdx::env::which(cmd) {
Ok(_) => column(&format!("{}", cmd), Color::Green), Ok(_) => color(fit(&format!("{}", cmd)), Color::Green),
Err(_) => column(&format!("{}", cmd), Color::Red), Err(_) => color(fit(&format!("{}", cmd)), Color::Red),
}, },
None => column("None", Color::Yellow), None => color(fit("None"), Color::Yellow),
}; };
for lang in &syn_loader_conf.language { for lang in &syn_loader_conf.language {
column(&lang.language_id, Color::Reset); write!(stdout, "{}", fit(&lang.language_id))?;
let mut cmds = lang.language_servers.iter().filter_map(|ls| { let mut cmds = lang.language_servers.iter().filter_map(|ls| {
syn_loader_conf syn_loader_conf
@@ -207,28 +202,28 @@ pub fn languages_all() -> std::io::Result<()> {
.get(&ls.name) .get(&ls.name)
.map(|config| config.command.as_str()) .map(|config| config.command.as_str())
}); });
check_binary(cmds.next()); write!(stdout, "{}", check_binary(cmds.next()))?;
let dap = lang.debugger.as_ref().map(|dap| dap.command.as_str()); let dap = lang.debugger.as_ref().map(|dap| dap.command.as_str());
check_binary(dap); write!(stdout, "{}", check_binary(dap))?;
let formatter = lang let formatter = lang
.formatter .formatter
.as_ref() .as_ref()
.map(|formatter| formatter.command.as_str()); .map(|formatter| formatter.command.as_str());
check_binary(formatter); write!(stdout, "{}", check_binary(formatter))?;
for ts_feat in TsFeature::all() { for ts_feat in TsFeature::all() {
match load_runtime_file(&lang.language_id, ts_feat.runtime_filename()).is_ok() { match load_runtime_file(&lang.language_id, ts_feat.runtime_filename()).is_ok() {
true => column("", Color::Green), true => write!(stdout, "{}", color(fit(""), Color::Green))?,
false => column("", Color::Red), false => write!(stdout, "{}", color(fit(""), Color::Red))?,
} }
} }
writeln!(stdout)?; writeln!(stdout)?;
for cmd in cmds { for cmd in cmds {
column("", Color::Reset); write!(stdout, "{}", fit(""))?;
check_binary(Some(cmd)); check_binary(Some(cmd));
writeln!(stdout)?; writeln!(stdout)?;
} }
@@ -307,6 +302,8 @@ pub fn language(lang_str: String) -> std::io::Result<()> {
.map(|formatter| formatter.command.to_string()), .map(|formatter| formatter.command.to_string()),
)?; )?;
probe_parser(lang.grammar.as_ref().unwrap_or(&lang.language_id))?;
for ts_feat in TsFeature::all() { for ts_feat in TsFeature::all() {
probe_treesitter_feature(&lang_str, *ts_feat)? probe_treesitter_feature(&lang_str, *ts_feat)?
} }
@@ -314,6 +311,18 @@ pub fn language(lang_str: String) -> std::io::Result<()> {
Ok(()) Ok(())
} }
fn probe_parser(grammar_name: &str) -> std::io::Result<()> {
let stdout = std::io::stdout();
let mut stdout = stdout.lock();
write!(stdout, "Tree-sitter parser: ")?;
match helix_loader::grammar::get_language(grammar_name) {
Ok(_) => writeln!(stdout, "{}", "".green()),
Err(_) => writeln!(stdout, "{}", "None".yellow()),
}
}
/// Display diagnostics about multiple LSPs and DAPs. /// Display diagnostics about multiple LSPs and DAPs.
fn probe_protocols<'a, I: Iterator<Item = &'a str> + 'a>( fn probe_protocols<'a, I: Iterator<Item = &'a str> + 'a>(
protocol_name: &str, protocol_name: &str,

View File

@@ -9,10 +9,13 @@ use helix_view::{
document::SavePoint, document::SavePoint,
editor::CompleteAction, editor::CompleteAction,
handlers::lsp::SignatureHelpInvoked, handlers::lsp::SignatureHelpInvoked,
theme::{Modifier, Style}, theme::{Color, Modifier, Style},
ViewId, ViewId,
}; };
use tui::{buffer::Buffer as Surface, text::Span}; use tui::{
buffer::Buffer as Surface,
text::{Span, Spans},
};
use std::{borrow::Cow, sync::Arc}; use std::{borrow::Cow, sync::Arc};
@@ -28,7 +31,7 @@ use crate::ui::{menu, Markdown, Menu, Popup, PromptEvent};
use helix_lsp::{lsp, util, OffsetEncoding}; use helix_lsp::{lsp, util, OffsetEncoding};
impl menu::Item for CompletionItem { impl menu::Item for CompletionItem {
type Data = (); type Data = Style;
fn sort_text(&self, data: &Self::Data) -> Cow<str> { fn sort_text(&self, data: &Self::Data) -> Cow<str> {
self.filter_text(data) self.filter_text(data)
} }
@@ -46,7 +49,7 @@ impl menu::Item for CompletionItem {
} }
} }
fn format(&self, _data: &Self::Data) -> menu::Row { fn format(&self, dir_style: &Self::Data) -> menu::Row {
let deprecated = match self { let deprecated = match self {
CompletionItem::Lsp(LspCompletionItem { item, .. }) => { CompletionItem::Lsp(LspCompletionItem { item, .. }) => {
item.deprecated.unwrap_or_default() item.deprecated.unwrap_or_default()
@@ -64,51 +67,72 @@ impl menu::Item for CompletionItem {
let kind = match self { let kind = match self {
CompletionItem::Lsp(LspCompletionItem { item, .. }) => match item.kind { CompletionItem::Lsp(LspCompletionItem { item, .. }) => match item.kind {
Some(lsp::CompletionItemKind::TEXT) => "text", Some(lsp::CompletionItemKind::TEXT) => "text".into(),
Some(lsp::CompletionItemKind::METHOD) => "method", Some(lsp::CompletionItemKind::METHOD) => "method".into(),
Some(lsp::CompletionItemKind::FUNCTION) => "function", Some(lsp::CompletionItemKind::FUNCTION) => "function".into(),
Some(lsp::CompletionItemKind::CONSTRUCTOR) => "constructor", Some(lsp::CompletionItemKind::CONSTRUCTOR) => "constructor".into(),
Some(lsp::CompletionItemKind::FIELD) => "field", Some(lsp::CompletionItemKind::FIELD) => "field".into(),
Some(lsp::CompletionItemKind::VARIABLE) => "variable", Some(lsp::CompletionItemKind::VARIABLE) => "variable".into(),
Some(lsp::CompletionItemKind::CLASS) => "class", Some(lsp::CompletionItemKind::CLASS) => "class".into(),
Some(lsp::CompletionItemKind::INTERFACE) => "interface", Some(lsp::CompletionItemKind::INTERFACE) => "interface".into(),
Some(lsp::CompletionItemKind::MODULE) => "module", Some(lsp::CompletionItemKind::MODULE) => "module".into(),
Some(lsp::CompletionItemKind::PROPERTY) => "property", Some(lsp::CompletionItemKind::PROPERTY) => "property".into(),
Some(lsp::CompletionItemKind::UNIT) => "unit", Some(lsp::CompletionItemKind::UNIT) => "unit".into(),
Some(lsp::CompletionItemKind::VALUE) => "value", Some(lsp::CompletionItemKind::VALUE) => "value".into(),
Some(lsp::CompletionItemKind::ENUM) => "enum", Some(lsp::CompletionItemKind::ENUM) => "enum".into(),
Some(lsp::CompletionItemKind::KEYWORD) => "keyword", Some(lsp::CompletionItemKind::KEYWORD) => "keyword".into(),
Some(lsp::CompletionItemKind::SNIPPET) => "snippet", Some(lsp::CompletionItemKind::SNIPPET) => "snippet".into(),
Some(lsp::CompletionItemKind::COLOR) => "color", Some(lsp::CompletionItemKind::COLOR) => item
Some(lsp::CompletionItemKind::FILE) => "file", .documentation
Some(lsp::CompletionItemKind::REFERENCE) => "reference", .as_ref()
Some(lsp::CompletionItemKind::FOLDER) => "folder", .and_then(|docs| {
Some(lsp::CompletionItemKind::ENUM_MEMBER) => "enum_member", let text = match docs {
Some(lsp::CompletionItemKind::CONSTANT) => "constant", lsp::Documentation::String(text) => text,
Some(lsp::CompletionItemKind::STRUCT) => "struct", lsp::Documentation::MarkupContent(lsp::MarkupContent {
Some(lsp::CompletionItemKind::EVENT) => "event", value, ..
Some(lsp::CompletionItemKind::OPERATOR) => "operator", }) => value,
Some(lsp::CompletionItemKind::TYPE_PARAMETER) => "type_param", };
// Language servers which send Color completion items tend to include a 6
// digit hex code at the end for the color. The extra 1 digit is for the '#'
text.get(text.len().checked_sub(7)?..)
})
.and_then(Color::from_hex)
.map_or("color".into(), |color| {
Spans::from(vec![
Span::raw("color "),
Span::styled("", Style::default().fg(color)),
])
}),
Some(lsp::CompletionItemKind::FILE) => "file".into(),
Some(lsp::CompletionItemKind::REFERENCE) => "reference".into(),
Some(lsp::CompletionItemKind::FOLDER) => "folder".into(),
Some(lsp::CompletionItemKind::ENUM_MEMBER) => "enum_member".into(),
Some(lsp::CompletionItemKind::CONSTANT) => "constant".into(),
Some(lsp::CompletionItemKind::STRUCT) => "struct".into(),
Some(lsp::CompletionItemKind::EVENT) => "event".into(),
Some(lsp::CompletionItemKind::OPERATOR) => "operator".into(),
Some(lsp::CompletionItemKind::TYPE_PARAMETER) => "type_param".into(),
Some(kind) => { Some(kind) => {
log::error!("Received unknown completion item kind: {:?}", kind); log::error!("Received unknown completion item kind: {:?}", kind);
"" "".into()
} }
None => "", None => "".into(),
}, },
CompletionItem::Other(core::CompletionItem { kind, .. }) => kind, CompletionItem::Other(core::CompletionItem { kind, .. }) => kind.as_ref().into(),
}; };
menu::Row::new([ let label = Span::styled(
menu::Cell::from(Span::styled( label,
label, if deprecated {
if deprecated { Style::default().add_modifier(Modifier::CROSSED_OUT)
Style::default().add_modifier(Modifier::CROSSED_OUT) } else if kind.0[0].content == "folder" {
} else { *dir_style
Style::default() } else {
}, Style::default()
)), },
menu::Cell::from(kind), );
])
menu::Row::new([menu::Cell::from(label), menu::Cell::from(kind)])
} }
} }
@@ -135,8 +159,10 @@ impl Completion {
// Sort completion items according to their preselect status (given by the LSP server) // Sort completion items according to their preselect status (given by the LSP server)
items.sort_by_key(|item| !item.preselect()); items.sort_by_key(|item| !item.preselect());
let dir_style = editor.theme.get("ui.text.directory");
// Then create the menu // Then create the menu
let menu = Menu::new(items, (), move |editor: &mut Editor, item, event| { let menu = Menu::new(items, dir_style, move |editor: &mut Editor, item, event| {
let (view, doc) = current!(editor); let (view, doc) = current!(editor);
macro_rules! language_server { macro_rules! language_server {

View File

@@ -57,12 +57,6 @@ pub enum InsertEvent {
RequestCompletion, RequestCompletion,
} }
impl Default for EditorView {
fn default() -> Self {
Self::new(Keymaps::default())
}
}
impl EditorView { impl EditorView {
pub fn new(keymaps: Keymaps) -> Self { pub fn new(keymaps: Keymaps) -> Self {
Self { Self {

View File

@@ -32,6 +32,17 @@ use helix_view::Editor;
use std::{error::Error, path::PathBuf}; use std::{error::Error, path::PathBuf};
struct Utf8PathBuf {
path: String,
is_dir: bool,
}
impl AsRef<str> for Utf8PathBuf {
fn as_ref(&self) -> &str {
&self.path
}
}
pub fn prompt( pub fn prompt(
cx: &mut crate::commands::Context, cx: &mut crate::commands::Context,
prompt: std::borrow::Cow<'static, str>, prompt: std::borrow::Cow<'static, str>,
@@ -266,6 +277,7 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi
} }
pub mod completers { pub mod completers {
use super::Utf8PathBuf;
use crate::ui::prompt::Completion; use crate::ui::prompt::Completion;
use helix_core::fuzzy::fuzzy_match; use helix_core::fuzzy::fuzzy_match;
use helix_core::syntax::LanguageServerFeature; use helix_core::syntax::LanguageServerFeature;
@@ -274,6 +286,7 @@ pub mod completers {
use helix_view::{editor::Config, Editor}; use helix_view::{editor::Config, Editor};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::borrow::Cow; use std::borrow::Cow;
use tui::text::Span;
pub type Completer = fn(&Editor, &str) -> Vec<Completion>; pub type Completer = fn(&Editor, &str) -> Vec<Completion>;
@@ -290,7 +303,7 @@ pub mod completers {
fuzzy_match(input, names, true) fuzzy_match(input, names, true)
.into_iter() .into_iter()
.map(|(name, _)| ((0..), name)) .map(|(name, _)| ((0..), name.into()))
.collect() .collect()
} }
@@ -336,7 +349,7 @@ pub mod completers {
fuzzy_match(input, &*KEYS, false) fuzzy_match(input, &*KEYS, false)
.into_iter() .into_iter()
.map(|(name, _)| ((0..), name.into())) .map(|(name, _)| ((0..), Span::raw(name)))
.collect() .collect()
} }
@@ -424,7 +437,7 @@ pub mod completers {
// TODO: we could return an iter/lazy thing so it can fetch as many as it needs. // TODO: we could return an iter/lazy thing so it can fetch as many as it needs.
fn filename_impl<F>( fn filename_impl<F>(
_editor: &Editor, editor: &Editor,
input: &str, input: &str,
git_ignore: bool, git_ignore: bool,
filter_fn: F, filter_fn: F,
@@ -482,7 +495,7 @@ pub mod completers {
return None; return None;
} }
//let is_dir = entry.file_type().map_or(false, |entry| entry.is_dir()); let is_dir = entry.file_type().is_some_and(|entry| entry.is_dir());
let path = entry.path(); let path = entry.path();
let mut path = if is_tilde { let mut path = if is_tilde {
@@ -501,23 +514,35 @@ pub mod completers {
} }
let path = path.into_os_string().into_string().ok()?; let path = path.into_os_string().into_string().ok()?;
Some(Cow::from(path)) Some(Utf8PathBuf { path, is_dir })
}) })
}) // TODO: unwrap or skip }) // TODO: unwrap or skip
.filter(|path| !path.is_empty()); .filter(|path| !path.path.is_empty());
let directory_color = editor.theme.get("ui.text.directory");
let style_from_file = |file: Utf8PathBuf| {
if file.is_dir {
Span::styled(file.path, directory_color)
} else {
Span::raw(file.path)
}
};
// if empty, return a list of dirs and files in current dir // if empty, return a list of dirs and files in current dir
if let Some(file_name) = file_name { if let Some(file_name) = file_name {
let range = (input.len().saturating_sub(file_name.len()))..; let range = (input.len().saturating_sub(file_name.len()))..;
fuzzy_match(&file_name, files, true) fuzzy_match(&file_name, files, true)
.into_iter() .into_iter()
.map(|(name, _)| (range.clone(), name)) .map(|(name, _)| (range.clone(), style_from_file(name)))
.collect() .collect()
// TODO: complete to longest common match // TODO: complete to longest common match
} else { } else {
let mut files: Vec<_> = files.map(|file| (end.clone(), file)).collect(); let mut files: Vec<_> = files
files.sort_unstable_by(|(_, path1), (_, path2)| path1.cmp(path2)); .map(|file| (end.clone(), style_from_file(file)))
.collect();
files.sort_unstable_by(|(_, path1), (_, path2)| path1.content.cmp(&path2.content));
files files
} }
} }

View File

@@ -8,6 +8,7 @@ use helix_view::keyboard::KeyCode;
use std::sync::Arc; use std::sync::Arc;
use std::{borrow::Cow, ops::RangeFrom}; use std::{borrow::Cow, ops::RangeFrom};
use tui::buffer::Buffer as Surface; use tui::buffer::Buffer as Surface;
use tui::text::Span;
use tui::widgets::{Block, Widget}; use tui::widgets::{Block, Widget};
use helix_core::{ use helix_core::{
@@ -19,7 +20,8 @@ use helix_view::{
}; };
type PromptCharHandler = Box<dyn Fn(&mut Prompt, char, &Context)>; type PromptCharHandler = Box<dyn Fn(&mut Prompt, char, &Context)>;
pub type Completion = (RangeFrom<usize>, Cow<'static, str>);
pub type Completion = (RangeFrom<usize>, Span<'static>);
type CompletionFn = Box<dyn FnMut(&Editor, &str) -> Vec<Completion>>; type CompletionFn = Box<dyn FnMut(&Editor, &str) -> Vec<Completion>>;
type CallbackFn = Box<dyn FnMut(&mut Context, &str, PromptEvent)>; type CallbackFn = Box<dyn FnMut(&mut Context, &str, PromptEvent)>;
pub type DocFn = Box<dyn Fn(&str) -> Option<Cow<str>>>; pub type DocFn = Box<dyn Fn(&str) -> Option<Cow<str>>>;
@@ -374,7 +376,7 @@ impl Prompt {
let (range, item) = &self.completion[index]; let (range, item) = &self.completion[index];
self.line.replace_range(range.clone(), item); self.line.replace_range(range.clone(), &item.content);
self.move_end(); self.move_end();
} }
@@ -399,7 +401,7 @@ impl Prompt {
let max_len = self let max_len = self
.completion .completion
.iter() .iter()
.map(|(_, completion)| completion.len() as u16) .map(|(_, completion)| completion.content.len() as u16)
.max() .max()
.unwrap_or(BASE_WIDTH) .unwrap_or(BASE_WIDTH)
.max(BASE_WIDTH); .max(BASE_WIDTH);
@@ -438,18 +440,22 @@ impl Prompt {
for (i, (_range, completion)) in for (i, (_range, completion)) in
self.completion.iter().enumerate().skip(offset).take(items) self.completion.iter().enumerate().skip(offset).take(items)
{ {
let color = if Some(i) == self.selection { let is_selected = Some(i) == self.selection;
selected_color // TODO: just invert bg
let completion_item_style = if is_selected {
selected_color
} else { } else {
completion_color completion_color.patch(completion.style)
}; };
surface.set_stringn( surface.set_stringn(
area.x + col * (1 + col_width), area.x + col * (1 + col_width),
area.y + row, area.y + row,
completion, &completion.content,
col_width.saturating_sub(1) as usize, col_width.saturating_sub(1) as usize,
color, completion_item_style,
); );
row += 1; row += 1;
if row > area.height - 1 { if row > area.height - 1 {
row = 0; row = 0;

View File

@@ -665,6 +665,14 @@ async fn test_join_selections_comment() -> anyhow::Result<()> {
)) ))
.await?; .await?;
test((
"#[|\t// Join comments
\t// with indent]#",
":lang go<ret>J",
"#[|\t// Join comments with indent]#",
))
.await?;
Ok(()) Ok(())
} }

View File

@@ -1,5 +1,125 @@
use super::*; use super::*;
#[tokio::test(flavor = "multi_thread")]
async fn change_line_above_comment() -> anyhow::Result<()> {
// <https://github.com/helix-editor/helix/issues/12570>
test((
indoc! {"\
#[fn main() {}
|]#// a comment
"},
":lang rust<ret>c",
indoc! {"\
#[
|]#// a comment
"},
))
.await?;
Ok(())
}
#[tokio::test(flavor = "multi_thread")]
async fn insert_newline_many_selections() -> anyhow::Result<()> {
test((
indoc! {"\
#(|o)#ne
#(|t)#wo
#[|t]#hree
"},
"i<ret>",
indoc! {"\
\n#(|o)#ne
#(|t)#wo
#[|t]#hree
"},
))
.await?;
// In this case the global offset that adjusts selections for inserted and deleted text
// should become negative because more text is deleted than is inserted.
test((
indoc! {"\
#[|🏴‍☠️]# #(|🏴)# #(|🏴)#
#(|🏴)# #(|🏴)# #(|🏴)#
"},
"i<ret>",
indoc! {"\
\n#[|🏴‍☠️]#
#(|🏴)#
#(|🏴)#
#(|🏴)#
#(|🏴)#
#(|🏴)#
"},
))
.await?;
// <https://github.com/helix-editor/helix/issues/12495>
test((
indoc! {"\
id #(|1)#,Item #(|1)#,cost #(|1)#,location #(|1)#
id #(|2)#,Item #(|2)#,cost #(|2)#,location #(|2)#
id #(|1)##(|0)#,Item #(|1)##(|0)#,cost #(|1)##(|0)#,location #(|1)##[|0]#"},
"i<ret>",
indoc! {"\
id
#(|1)#,Item
#(|1)#,cost
#(|1)#,location
#(|1)#
id
#(|2)#,Item
#(|2)#,cost
#(|2)#,location
#(|2)#
id
#(|1)#
#(|0)#,Item
#(|1)#
#(|0)#,cost
#(|1)#
#(|0)#,location
#(|1)#
#[|0]#"},
))
.await?;
// <https://github.com/helix-editor/helix/issues/12461>
test((
indoc! {"\
real R #(||)# real R @ real R
#(||)# real R + ureal R i #(||)# real R - ureal R i
#(||)# real R + i #(||)# real R - i #(||)# real R infnan i
#(||)# + ureal R i #(||)# - ureal R i
#(||)# infnan i #(||)# + i #[||]# - i"},
"i<ret>",
indoc! {"\
real R
#(||)# real R @ real R
#(||)# real R + ureal R i
#(||)# real R - ureal R i
#(||)# real R + i
#(||)# real R - i
#(||)# real R infnan i
#(||)# + ureal R i
#(||)# - ureal R i
#(||)# infnan i
#(||)# + i
#[||]# - i"},
))
.await?;
Ok(())
}
#[tokio::test(flavor = "multi_thread")] #[tokio::test(flavor = "multi_thread")]
async fn insert_newline_trim_trailing_whitespace() -> anyhow::Result<()> { async fn insert_newline_trim_trailing_whitespace() -> anyhow::Result<()> {
// Trailing whitespace is trimmed. // Trailing whitespace is trimmed.
@@ -117,6 +237,33 @@ async fn insert_newline_continue_line_comment() -> anyhow::Result<()> {
)) ))
.await?; .await?;
// Comment continuation should work on multiple selections.
// <https://github.com/helix-editor/helix/issues/12539>
test((
indoc! {"\
///·Docs#[|·]#
pub·struct·A;
///·Docs#(|·)#
pub·struct·B;
"}
.replace('·', " "),
":lang rust<ret>i<ret><ret>",
indoc! {"\
///·Docs
///
///·#[|·]#
pub·struct·A;
///·Docs
///
///·#(|·)#
pub·struct·B;
"}
.replace('·', " "),
))
.await?;
Ok(()) Ok(())
} }
@@ -184,6 +331,127 @@ async fn test_open_above() -> anyhow::Result<()> {
Ok(()) Ok(())
} }
#[tokio::test(flavor = "multi_thread")]
async fn test_open_above_with_multiple_cursors() -> anyhow::Result<()> {
// the primary cursor is also in the top line
test((
indoc! {"#[H|]#elix
#(i|)#s
#(c|)#ool"},
"O",
indoc! {
"#[\n|]#
Helix
#(\n|)#
is
#(\n|)#
cool
"
},
))
.await?;
// now with some additional indentation
test((
indoc! {"····#[H|]#elix
····#(i|)#s
····#(c|)#ool"}
.replace("·", " "),
":indent-style 4<ret>O",
indoc! {
"····#[\n|]#
····Helix
····#(\n|)#
····is
····#(\n|)#
····cool
"
}
.replace("·", " "),
))
.await?;
// the first line is within a comment, the second not.
// However, if we open above, the first newly added line should start within a comment
// while the other should be a normal line
test((
indoc! {"fn main() {
// #[VIP|]# comment
l#(e|)#t yes = false;
}"},
":lang rust<ret>O",
indoc! {"fn main() {
// #[\n|]#
// VIP comment
#(\n|)#
let yes = false;
}"},
))
.await?;
Ok(())
}
#[tokio::test(flavor = "multi_thread")]
async fn test_open_below_with_multiple_cursors() -> anyhow::Result<()> {
// the primary cursor is also in the top line
test((
indoc! {"#[H|]#elix
#(i|)#s
#(c|)#ool"},
"o",
indoc! {"Helix
#[\n|]#
is
#(\n|)#
cool
#(\n|)#
"
},
))
.await?;
// now with some additional indentation
test((
indoc! {"····#[H|]#elix
····#(i|)#s
····#(c|)#ool"}
.replace("·", " "),
":indent-style 4<ret>o",
indoc! {
"····Helix
····#[\n|]#
····is
····#(\n|)#
····cool
····#(\n|)#
"
}
.replace("·", " "),
))
.await?;
// the first line is within a comment, the second not.
// However, if we open below, the first newly added line should start within a comment
// while the other should be a normal line
test((
indoc! {"fn main() {
// #[VIP|]# comment
l#(e|)#t yes = false;
}"},
":lang rust<ret>o",
indoc! {"fn main() {
// VIP comment
// #[\n|]#
let yes = false;
#(\n|)#
}"},
))
.await?;
Ok(())
}
/// NOTE: To make the `open_above` comment-aware, we're setting the language for each test to rust. /// NOTE: To make the `open_above` comment-aware, we're setting the language for each test to rust.
#[tokio::test(flavor = "multi_thread")] #[tokio::test(flavor = "multi_thread")]
async fn test_open_above_with_comments() -> anyhow::Result<()> { async fn test_open_above_with_comments() -> anyhow::Result<()> {

View File

@@ -18,7 +18,7 @@ default = ["crossterm"]
helix-view = { path = "../helix-view", features = ["term"] } helix-view = { path = "../helix-view", features = ["term"] }
helix-core = { path = "../helix-core" } helix-core = { path = "../helix-core" }
bitflags = "2.6" bitflags.workspace = true
cassowary = "0.3" cassowary = "0.3"
unicode-segmentation = "1.12" unicode-segmentation = "1.12"
crossterm = { version = "0.28", optional = true } crossterm = { version = "0.28", optional = true }

View File

@@ -19,7 +19,7 @@ tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "p
parking_lot = "0.12" parking_lot = "0.12"
arc-swap = { version = "1.7.1" } arc-swap = { version = "1.7.1" }
gix = { version = "0.68.0", features = ["attributes", "status"], default-features = false, optional = true } gix = { version = "0.69.1", features = ["attributes", "status"], default-features = false, optional = true }
imara-diff = "0.1.7" imara-diff = "0.1.7"
anyhow = "1" anyhow = "1"
@@ -29,4 +29,4 @@ log = "0.4"
git = ["gix"] git = ["gix"]
[dev-dependencies] [dev-dependencies]
tempfile = "3.14" tempfile.workspace = true

View File

@@ -144,6 +144,7 @@ fn status(repo: &Repository, f: impl Fn(Result<FileChange>) -> bool) -> Result<(
copies: None, copies: None,
percentage: Some(0.5), percentage: Some(0.5),
limit: 1000, limit: 1000,
..Default::default()
})); }));
// No filtering based on path // No filtering based on path

View File

@@ -24,11 +24,11 @@ helix-lsp = { path = "../helix-lsp" }
helix-dap = { path = "../helix-dap" } helix-dap = { path = "../helix-dap" }
helix-vcs = { path = "../helix-vcs" } helix-vcs = { path = "../helix-vcs" }
bitflags = "2.6" bitflags.workspace = true
anyhow = "1" anyhow = "1"
crossterm = { version = "0.28", optional = true } crossterm = { version = "0.28", optional = true }
tempfile = "3.14" tempfile.workspace = true
# Conversion traits # Conversion traits
once_cell = "1.20" once_cell = "1.20"

View File

@@ -13,6 +13,7 @@ use helix_core::text_annotations::{InlineAnnotation, Overlay};
use helix_lsp::util::lsp_pos_to_pos; use helix_lsp::util::lsp_pos_to_pos;
use helix_stdx::faccess::{copy_metadata, readonly}; use helix_stdx::faccess::{copy_metadata, readonly};
use helix_vcs::{DiffHandle, DiffProviderRegistry}; use helix_vcs::{DiffHandle, DiffProviderRegistry};
use once_cell::sync::OnceCell;
use thiserror; use thiserror;
use ::parking_lot::Mutex; use ::parking_lot::Mutex;
@@ -148,6 +149,7 @@ pub struct Document {
pub inlay_hints_oudated: bool, pub inlay_hints_oudated: bool,
path: Option<PathBuf>, path: Option<PathBuf>,
relative_path: OnceCell<Option<PathBuf>>,
encoding: &'static encoding::Encoding, encoding: &'static encoding::Encoding,
has_bom: bool, has_bom: bool,
@@ -300,6 +302,14 @@ impl fmt::Debug for DocumentInlayHintsId {
} }
} }
impl Editor {
pub(crate) fn clear_doc_relative_paths(&mut self) {
for doc in self.documents_mut() {
doc.relative_path.take();
}
}
}
enum Encoder { enum Encoder {
Utf16Be, Utf16Be,
Utf16Le, Utf16Le,
@@ -659,6 +669,7 @@ impl Document {
id: DocumentId::default(), id: DocumentId::default(),
active_snippet: None, active_snippet: None,
path: None, path: None,
relative_path: OnceCell::new(),
encoding, encoding,
has_bom, has_bom,
text, text,
@@ -761,9 +772,20 @@ impl Document {
)) ))
}) })
{ {
log::debug!(
"formatting '{}' with command '{}', args {fmt_args:?}",
self.display_name(),
fmt_cmd.display(),
);
use std::process::Stdio; use std::process::Stdio;
let text = self.text().clone(); let text = self.text().clone();
let mut process = tokio::process::Command::new(&fmt_cmd); let mut process = tokio::process::Command::new(&fmt_cmd);
if let Some(doc_dir) = self.path.as_ref().and_then(|path| path.parent()) {
process.current_dir(doc_dir);
}
process process
.args(fmt_args) .args(fmt_args)
.stdin(Stdio::piped()) .stdin(Stdio::piped())
@@ -1172,6 +1194,10 @@ impl Document {
pub fn set_path(&mut self, path: Option<&Path>) { pub fn set_path(&mut self, path: Option<&Path>) {
let path = path.map(helix_stdx::path::canonicalize); let path = path.map(helix_stdx::path::canonicalize);
// `take` to remove any prior relative path that may have existed.
// This will get set in `relative_path()`.
self.relative_path.take();
// if parent doesn't exist we still want to open the document // if parent doesn't exist we still want to open the document
// and error out when document is saved // and error out when document is saved
self.path = path; self.path = path;
@@ -1867,16 +1893,19 @@ impl Document {
self.view_data_mut(view_id).view_position = new_offset; self.view_data_mut(view_id).view_position = new_offset;
} }
pub fn relative_path(&self) -> Option<Cow<Path>> { pub fn relative_path(&self) -> Option<&Path> {
self.path self.relative_path
.get_or_init(|| {
self.path
.as_ref()
.map(|path| helix_stdx::path::get_relative_path(path).to_path_buf())
})
.as_deref() .as_deref()
.map(helix_stdx::path::get_relative_path)
} }
pub fn display_name(&self) -> Cow<'static, str> { pub fn display_name(&self) -> Cow<'_, str> {
self.relative_path() self.relative_path()
.map(|path| path.to_string_lossy().to_string().into()) .map_or_else(|| SCRATCH_BUFFER_NAME.into(), |path| path.to_string_lossy())
.unwrap_or_else(|| SCRATCH_BUFFER_NAME.into())
} }
// transact(Fn) ? // transact(Fn) ?
@@ -2169,7 +2198,6 @@ pub enum FormatterError {
BrokenStdin, BrokenStdin,
WaitForOutputFailed, WaitForOutputFailed,
InvalidUtf8Output, InvalidUtf8Output,
DiskReloadError(String),
NonZeroExitStatus(Option<String>), NonZeroExitStatus(Option<String>),
} }
@@ -2184,7 +2212,6 @@ impl Display for FormatterError {
Self::BrokenStdin => write!(f, "Could not write to formatter stdin"), Self::BrokenStdin => write!(f, "Could not write to formatter stdin"),
Self::WaitForOutputFailed => write!(f, "Waiting for formatter output failed"), Self::WaitForOutputFailed => write!(f, "Waiting for formatter output failed"),
Self::InvalidUtf8Output => write!(f, "Invalid UTF-8 formatter output"), Self::InvalidUtf8Output => write!(f, "Invalid UTF-8 formatter output"),
Self::DiskReloadError(error) => write!(f, "Error reloading file from disk: {}", error),
Self::NonZeroExitStatus(Some(output)) => write!(f, "Formatter error: {}", output), Self::NonZeroExitStatus(Some(output)) => write!(f, "Formatter error: {}", output),
Self::NonZeroExitStatus(None) => { Self::NonZeroExitStatus(None) => {
write!(f, "Formatter exited with non zero exit status") write!(f, "Formatter exited with non zero exit status")

View File

@@ -1079,7 +1079,7 @@ pub struct Editor {
redraw_timer: Pin<Box<Sleep>>, redraw_timer: Pin<Box<Sleep>>,
last_motion: Option<Motion>, last_motion: Option<Motion>,
pub last_completion: Option<CompleteAction>, pub last_completion: Option<CompleteAction>,
pub last_cwd: Option<PathBuf>, last_cwd: Option<PathBuf>,
pub exit_code: i32, pub exit_code: i32,
@@ -2209,6 +2209,16 @@ impl Editor {
current_view.id current_view.id
} }
} }
pub fn set_cwd(&mut self, path: &Path) -> std::io::Result<()> {
self.last_cwd = helix_stdx::env::set_current_working_dir(path)?;
self.clear_doc_relative_paths();
Ok(())
}
pub fn get_last_cwd(&mut self) -> Option<&Path> {
self.last_cwd.as_deref()
}
} }
fn try_restore_indent(doc: &mut Document, view: &mut View) { fn try_restore_indent(doc: &mut Document, view: &mut View) {

View File

@@ -263,6 +263,31 @@ pub enum Color {
Indexed(u8), Indexed(u8),
} }
impl Color {
/// Creates a `Color` from a hex string
///
/// # Examples
///
/// ```rust
/// use helix_view::theme::Color;
///
/// let color1 = Color::from_hex("#c0ffee").unwrap();
/// let color2 = Color::Rgb(192, 255, 238);
///
/// assert_eq!(color1, color2);
/// ```
pub fn from_hex(hex: &str) -> Option<Self> {
if !(hex.starts_with('#') && hex.len() == 7) {
return None;
}
match [1..=2, 3..=4, 5..=6].map(|i| hex.get(i).and_then(|c| u8::from_str_radix(c, 16).ok()))
{
[Some(r), Some(g), Some(b)] => Some(Self::Rgb(r, g, b)),
_ => None,
}
}
}
#[cfg(feature = "term")] #[cfg(feature = "term")]
impl From<Color> for crossterm::style::Color { impl From<Color> for crossterm::style::Color {
fn from(color: Color) -> Self { fn from(color: Color) -> Self {

View File

@@ -1,7 +1,7 @@
# Language support configuration. # Language support configuration.
# See the languages documentation: https://docs.helix-editor.com/master/languages.html # See the languages documentation: https://docs.helix-editor.com/master/languages.html
use-grammars = { except = [ "hare", "wren", "gemini" ] } use-grammars = { except = [ "wren", "gemini" ] }
[language-server] [language-server]
@@ -21,6 +21,7 @@ cl-lsp = { command = "cl-lsp", args = [ "stdio" ] }
clangd = { command = "clangd" } clangd = { command = "clangd" }
clojure-lsp = { command = "clojure-lsp" } clojure-lsp = { command = "clojure-lsp" }
cmake-language-server = { command = "cmake-language-server" } cmake-language-server = { command = "cmake-language-server" }
codeql = { command = "codeql", args = ["execute", "language-server", "--check-errors=ON_CHANGE"] }
crystalline = { command = "crystalline", args = ["--stdio"] } crystalline = { command = "crystalline", args = ["--stdio"] }
cs = { command = "cs", args = ["launch", "--contrib", "smithy-language-server", "--", "0"] } cs = { command = "cs", args = ["launch", "--contrib", "smithy-language-server", "--", "0"] }
csharp-ls = { command = "csharp-ls" } csharp-ls = { command = "csharp-ls" }
@@ -53,6 +54,7 @@ jq-lsp = { command = "jq-lsp" }
jsonnet-language-server = { command = "jsonnet-language-server", args= ["-t", "--lint"] } jsonnet-language-server = { command = "jsonnet-language-server", args= ["-t", "--lint"] }
julia = { command = "julia", timeout = 60, args = [ "--startup-file=no", "--history-file=no", "--quiet", "-e", "using LanguageServer; runserver()", ] } julia = { command = "julia", timeout = 60, args = [ "--startup-file=no", "--history-file=no", "--quiet", "-e", "using LanguageServer; runserver()", ] }
koka = { command = "koka", args = ["--language-server", "--lsstdio"] } koka = { command = "koka", args = ["--language-server", "--lsstdio"] }
koto-ls = { command = "koto-ls" }
kotlin-language-server = { command = "kotlin-language-server" } kotlin-language-server = { command = "kotlin-language-server" }
lean = { command = "lean", args = [ "--server", "--memory=1024" ] } lean = { command = "lean", args = [ "--server", "--memory=1024" ] }
ltex-ls = { command = "ltex-ls" } ltex-ls = { command = "ltex-ls" }
@@ -121,6 +123,7 @@ zls = { command = "zls" }
blueprint-compiler = { command = "blueprint-compiler", args = ["lsp"] } blueprint-compiler = { command = "blueprint-compiler", args = ["lsp"] }
typst-lsp = { command = "typst-lsp" } typst-lsp = { command = "typst-lsp" }
tinymist = { command = "tinymist" } tinymist = { command = "tinymist" }
ts_query_ls = { command = "ts_query_ls" }
pkgbuild-language-server = { command = "pkgbuild-language-server" } pkgbuild-language-server = { command = "pkgbuild-language-server" }
helm_ls = { command = "helm_ls", args = ["serve"] } helm_ls = { command = "helm_ls", args = ["serve"] }
ember-language-server = { command = "ember-language-server", args = ["--stdio"] } ember-language-server = { command = "ember-language-server", args = ["--stdio"] }
@@ -338,16 +341,17 @@ source = { git = "https://github.com/Beaglefoot/tree-sitter-awk", rev = "a799bc5
[[language]] [[language]]
name = "protobuf" name = "protobuf"
scope = "source.proto" scope = "source.proto"
injection-regex = "protobuf" injection-regex = "proto"
file-types = ["proto"] file-types = ["proto"]
language-servers = [ "bufls", "pbkit" ] language-servers = [ "bufls", "pbkit" ]
comment-token = "//" comment-token = "//"
block-comment-tokens = { start = "/*", end = "*/" } block-comment-tokens = { start = "/*", end = "*/" }
indent = { tab-width = 2, unit = " " } indent = { tab-width = 2, unit = " " }
grammar = "proto"
[[grammar]] [[grammar]]
name = "protobuf" name = "proto"
source = { git = "https://github.com/yusdacra/tree-sitter-protobuf", rev = "19c211a01434d9f03efff99f85e19f967591b175"} source = { git = "https://github.com/sdoerner/tree-sitter-proto", rev = "778ab6ed18a7fcf82c83805a87d63376c51e80bc"}
[[language]] [[language]]
name = "textproto" name = "textproto"
@@ -484,6 +488,8 @@ name = "jsonc"
scope = "source.json" scope = "source.json"
injection-regex = "jsonc" injection-regex = "jsonc"
file-types = ["jsonc", { glob = "tsconfig.json" }] file-types = ["jsonc", { glob = "tsconfig.json" }]
comment-token = "//"
block-comment-tokens = { start = "/*", end = "*/" }
grammar = "json" grammar = "json"
language-servers = [ "vscode-json-language-server" ] language-servers = [ "vscode-json-language-server" ]
auto-format = true auto-format = true
@@ -880,7 +886,7 @@ name = "python"
scope = "source.python" scope = "source.python"
injection-regex = "py(thon)?" injection-regex = "py(thon)?"
file-types = ["py", "pyi", "py3", "pyw", "ptl", "rpy", "cpy", "ipy", "pyt", { glob = ".python_history" }, { glob = ".pythonstartup" }, { glob = ".pythonrc" }, { glob = "SConstruct" }, { glob = "SConscript" }] file-types = ["py", "pyi", "py3", "pyw", "ptl", "rpy", "cpy", "ipy", "pyt", { glob = ".python_history" }, { glob = ".pythonstartup" }, { glob = ".pythonrc" }, { glob = "SConstruct" }, { glob = "SConscript" }]
shebangs = ["python"] shebangs = ["python", "uv"]
roots = ["pyproject.toml", "setup.py", "poetry.lock", "pyrightconfig.json"] roots = ["pyproject.toml", "setup.py", "poetry.lock", "pyrightconfig.json"]
comment-token = "#" comment-token = "#"
language-servers = ["ruff", "jedi", "pylsp"] language-servers = ["ruff", "jedi", "pylsp"]
@@ -1289,7 +1295,7 @@ formatter = { command = "dune", args = ["format-dune-file"] }
name = "lua" name = "lua"
injection-regex = "lua" injection-regex = "lua"
scope = "source.lua" scope = "source.lua"
file-types = ["lua"] file-types = ["lua", "rockspec"]
shebangs = ["lua", "luajit"] shebangs = ["lua", "luajit"]
roots = [".luarc.json", ".luacheckrc", ".stylua.toml", "selene.toml", ".git"] roots = [".luarc.json", ".luacheckrc", ".stylua.toml", "selene.toml", ".git"]
comment-token = "--" comment-token = "--"
@@ -1313,7 +1319,7 @@ file-types = ["tl"]
comment-tokens = "--" comment-tokens = "--"
block-comment-tokens = { start = "--[[", end = "--]]" } block-comment-tokens = { start = "--[[", end = "--]]" }
roots = [ "tlconfig.lua" ] roots = [ "tlconfig.lua" ]
language-servers = [ "teal-lsp" ] language-servers = [ "teal-language-server" ]
[[language]] [[language]]
name = "svelte" name = "svelte"
@@ -1344,7 +1350,7 @@ source = { git = "https://github.com/ikatyang/tree-sitter-vue", rev = "91fe27547
[[language]] [[language]]
name = "yaml" name = "yaml"
scope = "source.yaml" scope = "source.yaml"
file-types = ["yml", "yaml", { glob = ".prettierrc" }, { glob = ".clangd" }, { glob = ".clang-format" }] file-types = ["yml", "yaml", { glob = ".prettierrc" }, { glob = ".clangd" }, { glob = ".clang-format" }, { glob = ".clang-tidy" }]
comment-token = "#" comment-token = "#"
indent = { tab-width = 2, unit = " " } indent = { tab-width = 2, unit = " " }
language-servers = [ "yaml-language-server", "ansible-language-server" ] language-servers = [ "yaml-language-server", "ansible-language-server" ]
@@ -1457,14 +1463,21 @@ language-servers = [ "swipl" ]
[[language]] [[language]]
name = "tsq" name = "tsq"
scope = "source.tsq" scope = "source.tsq"
file-types = ["tsq"] file-types = [{ glob = "queries/*.scm" }, { glob = "injections.scm" }, { glob = "highlights.scm" }, { glob = "indents.scm" }, { glob = "textobjects.scm" }, { glob = "locals.scm" }, { glob = "tags.scm" }]
comment-token = ";" comment-token = ";"
injection-regex = "tsq" injection-regex = "tsq"
language-servers = ["ts_query_ls"]
grammar = "query"
indent = { tab-width = 2, unit = " " } indent = { tab-width = 2, unit = " " }
[language.auto-pairs]
'(' = ')'
'[' = ']'
'"' = '"'
[[grammar]] [[grammar]]
name = "tsq" name = "query"
source = { git = "https://github.com/the-mikedavis/tree-sitter-tsq", rev = "48b5e9f82ae0a4727201626f33a17f69f8e0ff86" } source = { git = "https://github.com/tree-sitter-grammars/tree-sitter-query", rev = "a6674e279b14958625d7a530cabe06119c7a1532" }
[[language]] [[language]]
name = "cmake" name = "cmake"
@@ -1658,7 +1671,7 @@ scope = "source.dart"
file-types = ["dart"] file-types = ["dart"]
roots = ["pubspec.yaml"] roots = ["pubspec.yaml"]
auto-format = true auto-format = true
comment-token = "//" comment-tokens = ["//", "///"]
block-comment-tokens = { start = "/*", end = "*/" } block-comment-tokens = { start = "/*", end = "*/" }
language-servers = [ "dart" ] language-servers = [ "dart" ]
indent = { tab-width = 2, unit = " " } indent = { tab-width = 2, unit = " " }
@@ -1706,7 +1719,7 @@ language-servers = [ "docker-langserver" ]
[[grammar]] [[grammar]]
name = "dockerfile" name = "dockerfile"
source = { git = "https://github.com/camdencheek/tree-sitter-dockerfile", rev = "8ee3a0f7587b2bd8c45c8cb7d28bd414604aec62" } source = { git = "https://github.com/camdencheek/tree-sitter-dockerfile", rev = "087daa20438a6cc01fa5e6fe6906d77c869d19fe" }
[[language]] [[language]]
name = "docker-compose" name = "docker-compose"
@@ -1721,7 +1734,7 @@ grammar = "yaml"
[[language]] [[language]]
name = "git-commit" name = "git-commit"
scope = "git.commitmsg" scope = "git.commitmsg"
file-types = [{ glob = "COMMIT_EDITMSG" }] file-types = [{ glob = "COMMIT_EDITMSG" }, { glob = "MERGE_MSG" }]
comment-token = "#" comment-token = "#"
indent = { tab-width = 2, unit = " " } indent = { tab-width = 2, unit = " " }
rulers = [51, 73] rulers = [51, 73]
@@ -1938,7 +1951,7 @@ language-servers = [ "solc" ]
[[grammar]] [[grammar]]
name = "solidity" name = "solidity"
source = { git = "https://github.com/JoranHonig/tree-sitter-solidity", rev = "08338dcee32603383fcef08f36321900bb7a354b" } source = { git = "https://github.com/JoranHonig/tree-sitter-solidity", rev = "f7f5251a3f5b1d04f0799b3571b12918af177fc8" }
[[language]] [[language]]
name = "gleam" name = "gleam"
@@ -2068,7 +2081,7 @@ language-servers = [ "elixir-ls" ]
[[grammar]] [[grammar]]
name = "heex" name = "heex"
source = { git = "https://github.com/phoenixframework/tree-sitter-heex", rev = "2e1348c3cf2c9323e87c2744796cf3f3868aa82a" } source = { git = "https://github.com/phoenixframework/tree-sitter-heex", rev = "f6b83f305a755cd49cf5f6a66b2b789be93dc7b9" }
[[language]] [[language]]
name = "sql" name = "sql"
@@ -2471,7 +2484,7 @@ language-servers = [ "slint-lsp" ]
[[grammar]] [[grammar]]
name = "slint" name = "slint"
source = { git = "https://github.com/slint-ui/tree-sitter-slint", rev = "34ccfd58d3baee7636f62d9326f32092264e8407" } source = { git = "https://github.com/slint-ui/tree-sitter-slint", rev = "f11da7e62051ba8b9d4faa299c26de8aeedfc1cd" }
[[language]] [[language]]
name = "task" name = "task"
@@ -2887,7 +2900,7 @@ indent = { tab-width = 2, unit = " " }
[[grammar]] [[grammar]]
name = "matlab" name = "matlab"
source = { git = "https://github.com/acristoffers/tree-sitter-matlab", rev = "6071891a8c39600203eba20513666cf93b4d650a" } source = { git = "https://github.com/acristoffers/tree-sitter-matlab", rev = "b0a0198b182574cd3ca0447264c83331901b9338" }
[[language]] [[language]]
name = "ponylang" name = "ponylang"
@@ -3294,6 +3307,7 @@ injection-regex = "nunjucks"
file-types = ["njk"] file-types = ["njk"]
indent = { tab-width = 2, unit = " " } indent = { tab-width = 2, unit = " " }
grammar = "jinja2" grammar = "jinja2"
block-comment-tokens = { start = "{#", end = "#}" }
[[language]] [[language]]
name = "jinja" name = "jinja"
@@ -3302,6 +3316,7 @@ injection-regex = "jinja"
file-types = ["jinja", "jinja2", "j2"] file-types = ["jinja", "jinja2", "j2"]
indent = { tab-width = 2, unit = " " } indent = { tab-width = 2, unit = " " }
grammar = "jinja2" grammar = "jinja2"
block-comment-tokens = { start = "{#", end = "#}" }
[[grammar]] [[grammar]]
name = "jinja2" name = "jinja2"
@@ -3318,7 +3333,7 @@ text-width = 72
[[grammar]] [[grammar]]
name = "jjdescription" name = "jjdescription"
source = { git = "https://github.com/kareigu/tree-sitter-jjdescription", rev = "23dd3dd18ee29bdd761642511aa314215801afd8" } source = { git = "https://github.com/kareigu/tree-sitter-jjdescription", rev = "d09205b52b5a0165b588a793e366c1116468d86f" }
[[language]] [[language]]
name = "jq" name = "jq"
@@ -3598,7 +3613,7 @@ source = { git = "https://github.com/mtoohey31/tree-sitter-ld", rev = "0e9695ae0
name = "hyprlang" name = "hyprlang"
scope = "source.hyprlang" scope = "source.hyprlang"
roots = ["hyprland.conf"] roots = ["hyprland.conf"]
file-types = [ { glob = "hyprland.conf" }, { glob = "hyprpaper.conf" }, { glob = "hypridle.conf" }, { glob = "hyprlock.conf" } ] file-types = [ { glob = "hypr/*.conf" }]
comment-token = "#" comment-token = "#"
grammar = "hyprlang" grammar = "hyprlang"
language-servers = ["hyprls"] language-servers = ["hyprls"]
@@ -3952,7 +3967,7 @@ indent = { tab-width = 4, unit = " " }
[[grammar]] [[grammar]]
name = "spade" name = "spade"
source = { git = "https://gitlab.com/spade-lang/tree-sitter-spade", rev = "4d5b141017c61fe7e168e0a5c5721ee62b0d9572" } source = { git = "https://gitlab.com/spade-lang/tree-sitter-spade", rev = "78bf09a88fc1d396f66b69879f908fc6bd2e6934" }
[[language]] [[language]]
name = "amber" name = "amber"
@@ -3965,6 +3980,20 @@ indent = { tab-width = 4, unit = " " }
name = "amber" name = "amber"
source = { git = "https://github.com/amber-lang/tree-sitter-amber", rev = "c6df3ec2ec243ed76550c525e7ac3d9a10c6c814" } source = { git = "https://github.com/amber-lang/tree-sitter-amber", rev = "c6df3ec2ec243ed76550c525e7ac3d9a10c6c814" }
[[language]]
name = "koto"
scope = "source.koto"
injection-regex = "koto"
file-types = ["koto"]
comment-token = "#"
block-comment-tokens = ["#-", "-#"]
indent = { tab-width = 2, unit = " " }
language-servers = ["koto-ls"]
[[grammar]]
name = "koto"
source = { git = "https://github.com/koto-lang/tree-sitter-koto", rev = "b420f7922d0d74905fd0d771e5b83be9ee8a8a9a" }
[[language]] [[language]]
name = "gpr" name = "gpr"
scope = "source.gpr" scope = "source.gpr"
@@ -3988,4 +4017,51 @@ indent = { tab-width = 4, unit = " " }
[[grammar]] [[grammar]]
name = "vento" name = "vento"
source = { git = "https://github.com/ventojs/tree-sitter-vento", rev = "3321077d7446c1b3b017c294fd56ce028ed817fe" } source = { git = "https://github.com/ventojs/tree-sitter-vento", rev = "3b32474bc29584ea214e4e84b47102408263fe0e" }
[[language]]
name = "nginx"
scope = "source.nginx"
injection-regex = "nginx"
file-types = [
{ glob = "sites-available/*.conf" },
{ glob = "sites-enabled/*.conf" },
{ glob = "nginx.conf" },
{ glob = "conf.d/*.conf" }
]
roots = ["nginx.conf"]
comment-token = "#"
indent = { tab-width = 4, unit = " " }
[[grammar]]
name = "nginx"
source = { git = "https://gitlab.com/joncoole/tree-sitter-nginx", rev = "b4b61db443602b69410ab469c122c01b1e685aa0" }
[[language]]
name = "codeql"
scope = "source.ql"
file-types = ["ql", "qll"]
comment-token = "//"
block-comment-tokens = { start = "/*", end = "*/" }
indent = { tab-width = 2, unit = " " }
injection-regex = "codeql"
grammar = "ql"
language-servers = ["codeql"]
[[grammar]]
name = "ql"
source = { git = "https://github.com/tree-sitter/tree-sitter-ql", rev = "1fd627a4e8bff8c24c11987474bd33112bead857" }
[[language]]
name = "gren"
scope = "source.gren"
injection-regex = "gren"
file-types = ["gren"]
roots = ["gren.json"]
comment-tokens = "--"
block-comment-tokens = { start = "{-", end = "-}" }
indent = { tab-width = 4, unit = " " }
[[grammar]]
name = "gren"
source = { git = "https://github.com/MaeBrooks/tree-sitter-gren", rev = "76554f4f2339f5a24eed19c58f2079b51c694152" }

View File

@@ -25,7 +25,7 @@
; Attributes ; Attributes
; ---------- ; ----------
(jsx_attribute (property_identifier) @variable.other.member) (jsx_attribute (property_identifier) @attribute)
; Punctuation ; Punctuation
; ----------- ; -----------

View File

@@ -1,9 +1,3 @@
;; highlight queries.
;; See the syntax at https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries
;; See also https://github.com/nvim-treesitter/nvim-treesitter/blob/master/CONTRIBUTING.md#parser-configurations
;; for a list of recommended @ tags, though not all of them have matching
;; highlights in neovim.
[ [
"abort" "abort"
"abs" "abs"

View File

@@ -1,6 +1,3 @@
;; Better highlighting by referencing to the definition, for variable references.
;; See https://tree-sitter.github.io/tree-sitter/syntax-highlighting#local-variables
(compilation) @local.scope (compilation) @local.scope
(package_declaration) @local.scope (package_declaration) @local.scope
(package_body) @local.scope (package_body) @local.scope

View File

@@ -1,7 +1,5 @@
; tree-sitter-awk v0.5.1 ; tree-sitter-awk v0.5.1
; https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries
; Order matters ; Order matters
[ [

View File

@@ -0,0 +1,104 @@
[
"and"
"any"
"as"
"asc"
"avg"
"by"
"class"
"concat"
"count"
"desc"
"else"
"exists"
"extends"
"forall"
"forex"
"from"
"if"
"implements"
"implies"
"import"
"in"
"instanceof"
"max"
"min"
"module"
"newtype"
"not"
"or"
"order"
"rank"
"select"
"strictconcat"
"strictcount"
"strictsum"
"sum"
"then"
"where"
(false)
(predicate)
(result)
(specialId)
(super)
(this)
(true)
] @keyword
[
"boolean"
"float"
"int"
"date"
"string"
] @type.builtin
(annotName) @attribute
[
"<"
"<="
"="
">"
">="
"-"
"!="
"/"
"*"
"%"
"+"
"::"
] @operator
[
"("
")"
"{"
"}"
"["
"]"
] @punctuation.bracket
[
","
"|"
] @punctuation.delimiter
(className) @type
(varName) @variable
(integer) @constant.numeric.integer
(float) @constant.numeric.float
(string) @string
(aritylessPredicateExpr (literalId) @function)
(predicateName) @function
[
(line_comment)
(block_comment)
(qldoc)
] @comment

View File

@@ -0,0 +1,16 @@
(qldoc) @comment.around
(block_comment) @comment.around
(line_comment) @comment.inside
(line_comment)+ @comment.around
(classlessPredicate
((varDecl) @parameter.inside . ","?) @parameter.around
(body "{" (_)* @function.inside "}")) @function.around
(memberPredicate
((varDecl) @parameter.inside . ","?) @parameter.around
(body "{" (_)* @function.inside "}")) @function.around
(dataclass
("{" (_)* @class.inside "}")?) @class.around
(datatype) @class.around
(datatypeBranch) @class.around

View File

@@ -19,6 +19,8 @@
"SHELL" "SHELL"
"MAINTAINER" "MAINTAINER"
"CROSS_BUILD" "CROSS_BUILD"
(heredoc_marker)
(heredoc_end)
] @keyword ] @keyword
[ [
@@ -35,7 +37,12 @@
(image_digest (image_digest
"@" @punctuation.special)) "@" @punctuation.special))
(double_quoted_string) @string [
(double_quoted_string)
(single_quoted_string)
(json_string)
(heredoc_line)
] @string
(expansion (expansion
[ [

View File

@@ -16,8 +16,31 @@
(#match? @variable.builtin "^(arguments|module|console|window|document)$") (#match? @variable.builtin "^(arguments|module|console|window|document)$")
(#is-not? local)) (#is-not? local))
((identifier) @function.builtin (call_expression
(#eq? @function.builtin "require") (identifier) @function.builtin
(#any-of? @function.builtin
"eval"
"fetch"
"isFinite"
"isNaN"
"parseFloat"
"parseInt"
"decodeURI"
"decodeURIComponent"
"encodeURI"
"encodeURIComponent"
"require"
"alert"
"prompt"
"btoa"
"atob"
"confirm"
"structuredClone"
"setTimeout"
"clearTimeout"
"setInterval"
"clearInterval"
"queueMicrotask")
(#is-not? local)) (#is-not? local))
; Function and method definitions ; Function and method definitions

View File

@@ -0,0 +1,81 @@
; Keywords
[
"if"
"then"
"else"
"let"
"in"
] @keyword.control
(when) @keyword.control
(is) @keyword.control
(colon) @keyword.operator
(backslash) @keyword
(as) @keyword
(port) @keyword
(exposing) @keyword
(alias) @keyword
(infix) @keyword
(arrow) @keyword.operator
(dot) @keyword.operator
(type_annotation(lower_case_identifier) @function)
(port_annotation(lower_case_identifier) @function)
(file (value_declaration (function_declaration_left(lower_case_identifier) @function)))
(field name: (lower_case_identifier) @attribute)
(field_access_expr(lower_case_identifier) @attribute)
(operator_identifier) @keyword.operator
(eq) @keyword.operator.assignment
[
"("
")"
"["
"]"
"{"
"}"
] @punctuation.bracket
"|" @keyword
"," @punctuation.delimiter
[
"|>"
] @keyword
(import) @keyword.control.import
(module) @keyword.other
(number_constant_expr) @constant.numeric
(type) @type
(type_declaration(upper_case_identifier) @type)
(type_ref) @type
(type_alias_declaration name: (upper_case_identifier) @type)
(union_pattern constructor: (upper_case_qid (upper_case_identifier) @label (dot) (upper_case_identifier) @variable.other.member))
(union_pattern constructor: (upper_case_qid (upper_case_identifier) @variable.other.member))
(union_variant(upper_case_identifier) @variable.other.member)
(value_expr name: (value_qid (upper_case_identifier) @label))
(value_expr (upper_case_qid (upper_case_identifier) @label (dot) (upper_case_identifier) @variable.other.member))
(value_expr(upper_case_qid(upper_case_identifier)) @variable.other.member)
; comments
(line_comment) @comment
(block_comment) @comment
; strings
(string_escape) @constant.character.escape
(open_quote) @string
(close_quote) @string
(regular_string_part) @string
(open_char) @constant.character
(close_char) @constant.character

View File

@@ -0,0 +1,14 @@
(value_declaration) @local.scope
(type_alias_declaration) @local.scope
(type_declaration) @local.scope
(type_annotation) @local.scope
(port_annotation) @local.scope
(infix_declaration) @local.scope
(let_in_expr) @local.scope
(function_declaration_left (lower_pattern (lower_case_identifier)) @local.definition)
(function_declaration_left (lower_case_identifier) @local.definition)
(value_expr(value_qid(upper_case_identifier)) @local.reference)
(value_expr(value_qid(lower_case_identifier)) @local.reference)
(type_ref (upper_case_qid) @local.reference)

View File

@@ -0,0 +1,19 @@
(value_declaration (function_declaration_left (lower_case_identifier) @name)) @definition.function
(function_call_expr (value_expr (value_qid) @name)) @reference.function
(exposed_value (lower_case_identifier) @name) @reference.function
(type_annotation ((lower_case_identifier) @name) (colon)) @reference.function
(type_declaration ((upper_case_identifier) @name) ) @definition.type
(type_ref (upper_case_qid (upper_case_identifier) @name)) @reference.type
(exposed_type (upper_case_identifier) @name) @reference.type
(type_declaration (union_variant (upper_case_identifier) @name)) @definition.union
(value_expr (upper_case_qid (upper_case_identifier) @name)) @reference.union
(module_declaration
(upper_case_qid (upper_case_identifier)) @name
) @definition.module

View File

@@ -0,0 +1,56 @@
(line_comment) @comment.inside
(line_comment)+ @comment.around
(block_comment) @comment.inside
(block_comment)+ @comment.around
((type_annotation)?
(value_declaration
(function_declaration_left (lower_case_identifier))
(eq)
(_) @function.inside
)
) @function.around
(parenthesized_expr
(anonymous_function_expr
(
(arrow)
(_) @function.inside
)
)
) @function.around
(value_declaration
(function_declaration_left
(lower_pattern
(lower_case_identifier) @parameter.inside @parameter.around
)
)
)
(value_declaration
(function_declaration_left
(pattern) @parameter.inside @parameter.around
)
)
(value_declaration
(function_declaration_left
(record_pattern
(lower_pattern
(lower_case_identifier) @parameter.inside
)
) @parameter.around
)
)
(parenthesized_expr
(anonymous_function_expr
(
(backslash)
(pattern) @parameter.inside
(arrow)
)
)
)

View File

@@ -7,6 +7,255 @@
(char) @constant.character (char) @constant.character
(string) @string (string) @string
(exp_apply
(exp_name
(variable) @function.builtin
(#any-of? @function.builtin
; built in functions from the Haskell prelude (https://hackage.haskell.org/package/base-4.21.0.0/docs/Prelude.html)
; basic data types
"not"
"maybe"
"either"
; tuples
"fst"
"snd"
"curry"
"uncurry"
; Ord
"compare"
"min"
"max"
; Enum
"succ"
"pred"
"toEnum"
"fromEnum"
"enumFrom"
"enumFromThen"
"enumFromThenTo"
; Num
"negate"
"abs"
"signum"
"fromInteger"
; Real
"toRational"
; Integral
"quot"
"rem"
"div"
"mod"
"quotRem"
"divMod"
"toInteger"
; Fractional
"recip"
"fromRational"
; Floating
"exp"
"log"
"sqrt"
"logBase"
"sin"
"cos"
"tan"
"asin"
"acos"
"atan"
"sinh"
"cosh"
"tanh"
"asinh"
"acosh"
"atanh"
; RealFrac
"properFraction"
"truncate"
"round"
"ceiling"
"floor"
; RealFloat
"floatRadix"
"floatDigits"
"floatRange"
"decodeFloat"
"encodeFloat"
"exponent"
"significand"
"scaleFloat"
"isNaN"
"isInfinite"
"isDenormalized"
"isNegativeZero"
"isIEEE"
"atan2"
; Numeric functions
"subtract"
"even"
"odd"
"gcd"
"lcm"
"fromIntegral"
"realToFrac"
; Monoid
"mempty"
"mconcat"
"mappend"
; Functor
"fmap"
; Applicative
"liftA2"
"pure"
; Monad
"return"
; MonadFail
"fail"
"mapM_"
"sequence_"
; Foldable
"foldMap"
"foldr"
"foldl"
"foldl'"
"foldr1"
"foldl1"
"elem"
"maximum"
"minimum"
"sum"
"product"
; Traversable
"traverse"
"sequenceA"
"mapM"
"sequence"
; miscellaneous
"id"
"const"
"flip"
"until"
"asTypeOf"
"error"
"errorWithoutStackTrace"
"undefined"
; List
"map"
"filter"
"head"
"last"
"tail"
"init"
"null"
"length"
"reverse"
; Foldable
"and"
"or"
"any"
"all"
"concat"
"concatMap"
; Building lists
"scanl"
"scanl1"
"scanr"
"scanr1"
; Infinite lists
"iterate"
"repeat"
"replicate"
"cycle"
; Sublists
"take"
"drop"
"takeWhile"
"dropWhile"
"span"
"break"
"splitAt"
; Searching lists
"notElem"
"lookup"
; zipping and unzipping
"zip"
"zip3"
"zipWith"
"zipWith3"
"unzip"
"unzip3"
; String
"lines"
"words"
"unlines"
"unwords"
; Converting to String
"show"
"showList"
"shows"
"showChar"
"showString"
"showParen"
; Converting from String
"readsPrec"
"readList"
"reads"
"readParen"
"read"
"lex"
; Input and output
"putChar"
"putStr"
"putStrLn"
"print"
"getChar"
"getLine"
"getContents"
"interact"
; Files
"readFile"
"writeFile"
"appendFile"
"readIO"
"readLn"
; Exception handling
"ioError"
"userError")
)
)
(con_unit) @constant.builtin ; unit, as in () (con_unit) @constant.builtin ; unit, as in ()
(comment) @comment (comment) @comment

View File

@@ -0,0 +1,3 @@
(((scissors_inner) @injection.content)
(#set! injection.include-children)
(#set! injection.language "diff"))

View File

@@ -0,0 +1,9 @@
[
(assign)
(comment)
(function)
(list)
(map)
(tuple)
(string)
] @fold

View File

@@ -0,0 +1,152 @@
[
"="
"+"
"-"
"*"
"/"
"%"
"+="
"-="
"*="
"/="
"%="
"=="
"!="
"<"
">"
"<="
">="
".."
"..="
"->"
(null_check)
] @operator
[
"let"
] @keyword
[
"and"
"not"
"or"
] @keyword.operator
[
"return"
"yield"
] @keyword.control.return
[
"if"
"then"
"else"
"else if"
"match"
"switch"
] @keyword.control.conditional
[
(break)
(continue)
"for"
"in"
"loop"
"until"
"while"
] @keyword.control.repeat
[
"throw"
"try"
"catch"
"finally"
] @keyword.control.exception
[
"export"
"from"
"import"
"as"
] @keyword.control.import
(string (interpolation ("{") @punctuation.special))
(string (interpolation ("}") @punctuation.special))
[
"("
")"
"["
"]"
"{"
"}"
"|"
] @punctuation.bracket
[
";"
":"
","
] @punctuation.delimiter
(import_module
(identifier) @module)
(import_item
(identifier) @module)
(export
(identifier) @module)
(call
function: (identifier) @function.method)
(chain
lookup: (identifier) @variable.other.member)
[
(true)
(false)
] @constant.builtin.boolean
(comment) @comment
(debug) @keyword
(string) @string
(fill_char) @punctuation.delimiter
(alignment) @operator
(escape) @constant.character.escape
(null) @constant.builtin
(number) @constant.numeric
(meta) @keyword.directive
(meta
name: (identifier) @variable.other.member)
(entry_inline
key: (identifier) @variable.other.member)
(entry_block
key: (identifier) @variable.other.member)
(self) @variable.builtin
(variable
type: (identifier) @type)
(arg
(_ (identifier) @variable.parameter))
(ellipsis) @variable.parameter
(function
output_type: (identifier) @type)
(identifier) @variable

View File

@@ -0,0 +1,61 @@
[
(list)
(map)
(tuple)
] @indent
[
(for)
(else_if)
(else)
(match)
(switch)
(until)
(while)
] @indent @extend
(assign
"=" @indent @extend
!rhs
)
(assign
"=" @indent @extend
rhs: (_) @anchor
(#not-same-line? @indent @anchor)
)
(if
condition: (_) @indent @extend
!then
)
(if
condition: (_) @indent @extend
then: (_) @anchor
(#not-same-line? @indent @anchor)
)
(function
(args) @indent @extend
!body
)
(function
(args) @indent @extend
body: (_) @anchor
(#not-same-line? @indent @anchor)
)
(match_arm
"then" @indent @extend
!then
)
(match_arm
"then" @indent @extend
then: (_) @anchor
(#not-same-line? @indent @anchor)
)
[
"}"
"]"
")"
] @outdent

View File

@@ -0,0 +1,2 @@
((comment) @injection.content
(#set! injection.language "comment"))

View File

@@ -0,0 +1,30 @@
; Scopes
(module (_) @local.scope)
(function
body: (_) @local.scope)
; Definitions
(assign
lhs: (identifier) @local.definition)
(variable
(identifier) @local.definition)
(arg
(identifier) @local.definition)
(arg
(variable (identifier)) @local.definition)
(import_item
(identifier) @local.definition)
(entry_block
(identifier) @local.definition)
(entry_inline
(identifier) @local.definition)
; References
(identifier) @local.reference

View File

@@ -0,0 +1,38 @@
(comment) @comment.inside
(comment)+ @comment.around
(function
body: (_) @function.inside) @function.around
(args
((arg) @parameter.inside . ","? @parameter.around) @parameter.around)
(call_args
((call_arg) @parameter.inside . ","? @parameter.around) @parameter.around)
(chain
call: (tuple
((element) @parameter.inside . ","? @parameter.around) @parameter.around))
(map
((entry_inline) @entry.inside . ","? @entry.around) @entry.around)
(map_block
((entry_block) @entry.inside) @entry.around)
(list
((element) @entry.inside . ","? @entry.around) @entry.around)
(tuple
(_) @entry.around)
(assign
(meta (test))
(function body: (_) @test.inside)
) @test.around
(entry_block
key: (meta (test))
value: (function body: (_) @test.inside)
) @test.around

View File

@@ -2,12 +2,12 @@
(setext_heading (paragraph) @markup.heading.1 (setext_h1_underline) @markup.heading.marker) (setext_heading (paragraph) @markup.heading.1 (setext_h1_underline) @markup.heading.marker)
(setext_heading (paragraph) @markup.heading.2 (setext_h2_underline) @markup.heading.marker) (setext_heading (paragraph) @markup.heading.2 (setext_h2_underline) @markup.heading.marker)
(atx_heading (atx_h1_marker) @markup.heading.marker (inline) @markup.heading.1) (atx_heading (atx_h1_marker) @markup.heading.marker) @markup.heading.1
(atx_heading (atx_h2_marker) @markup.heading.marker (inline) @markup.heading.2) (atx_heading (atx_h2_marker) @markup.heading.marker) @markup.heading.2
(atx_heading (atx_h3_marker) @markup.heading.marker (inline) @markup.heading.3) (atx_heading (atx_h3_marker) @markup.heading.marker) @markup.heading.3
(atx_heading (atx_h4_marker) @markup.heading.marker (inline) @markup.heading.4) (atx_heading (atx_h4_marker) @markup.heading.marker) @markup.heading.4
(atx_heading (atx_h5_marker) @markup.heading.marker (inline) @markup.heading.5) (atx_heading (atx_h5_marker) @markup.heading.marker) @markup.heading.5
(atx_heading (atx_h6_marker) @markup.heading.marker (inline) @markup.heading.6) (atx_heading (atx_h6_marker) @markup.heading.marker) @markup.heading.6
[ [
(indented_code_block) (indented_code_block)

View File

@@ -1,4 +1,5 @@
[ [
(arguments_statement)
(if_statement) (if_statement)
(for_statement) (for_statement)
(while_statement) (while_statement)

View File

@@ -0,0 +1,45 @@
(comment) @comment
(block_directive
(directive) @type)
[
"{"
"}"
"("
")"
"["
"]"
] @punctuation.bracket
(simple_directive
(directive) @function)
[
";"
] @punctuation.delimiter
((generic) @keyword
(#any-of? @keyword
"on"
"off"
"any"
"auto"))
(modifier) @operator
(generic) @variable
(string) @string
(number) @constant.numeric
(metric) @constant.numeric
(variable) @variable.parameter
(regex) @string
(modifier) @keyword.operator
(lua_block_directive
"access_by_lua_block" @function)

View File

@@ -0,0 +1,9 @@
((lua_code) @injection.content
(#set! injection.language "lua")
(#set! injection.combined))
((regex) @injection.content
(#set! injection.language "regex"))
((comment) @injection.content
(#set! injection.language "comment"))

View File

@@ -0,0 +1,22 @@
(procedure_declaration (identifier) (procedure (block) @function.inside)) @function.around
(procedure_declaration (identifier) (procedure (uninitialized) @function.inside)) @function.around
(overloaded_procedure_declaration (identifier) @function.inside) @function.around
(procedure_type (parameters (parameter (identifier) @parameter.inside) @parameter.around))
(procedure (parameters (parameter (identifier) @parameter.inside) @parameter.around))
((procedure_declaration
(attributes (attribute "@" "(" (identifier) @attr_name ")"))
(identifier) (procedure (block) @test.inside)) @test.around
(#match? @attr_name "test"))
(comment) @comment.inside
(comment)+ @comment.around
(block_comment) @comment.inside
(block_comment)+ @comment.around
(struct_declaration (identifier) "::") @class.around
(enum_declaration (identifier) "::") @class.around
(union_declaration (identifier) "::") @class.around
(bit_field_declaration (identifier) "::") @class.around
(const_declaration (identifier) "::" [(array_type) (distinct_type) (bit_set_type) (pointer_type)]) @class.around

View File

@@ -14,4 +14,5 @@
[ [
"}" "}"
")" ")"
"]"
] @outdent ] @outdent

View File

@@ -1,5 +1,6 @@
[ [
"syntax" "syntax"
"edition"
"package" "package"
"option" "option"
"import" "import"
@@ -7,44 +8,45 @@
"rpc" "rpc"
"returns" "returns"
"message" "message"
"map"
"enum" "enum"
"oneof" "oneof"
"repeated" "repeated"
"optional"
"required"
"reserved" "reserved"
"to" "to"
"stream" "stream"
"extend" "extend"
"optional"
] @keyword ] @keyword
[ [
(keyType) (key_type)
(type) (type)
(message_or_enum_type)
] @type.builtin ] @type.builtin
[ [
(mapName) (enum_name)
(enumName) (message_name)
(messageName) (service_name)
(extendName) (rpc_name)
(serviceName)
(rpcName)
] @type ] @type
[ [
(fieldName) (field_name)
(optionName) (option_name)
] @variable.other.member ] @variable.other.member
(enumVariantName) @type.enum.variant (enum_variant_name) @type.enum.variant
(fullIdent) @namespace (full_ident) @namespace
(intLit) @constant.numeric.integer (int_lit) @constant.numeric.integer
(floatLit) @constant.numeric.float (float_lit) @constant.numeric.float
(boolLit) @constant.builtin.boolean (bool) @constant.builtin.boolean
(strLit) @string (string) @string
(constant) @constant (block_lit) @constant
(comment) @comment (comment) @comment
@@ -55,4 +57,8 @@
"]" "]"
"{" "{"
"}" "}"
] @punctuation.bracket ] @punctuation.bracket
"=" @operator
";" @punctuation.delimiter

View File

@@ -1,10 +1,10 @@
[ [
(messageBody) (message_body)
(enumBody) (enum_body)
(oneofBody) (oneof_body)
(serviceBody) (service_body)
(rpcBody) (rpc_body)
(msgLit) (block_lit)
] @indent ] @indent
"}" @outdent "}" @outdent

View File

@@ -1,9 +1,9 @@
(message (messageBody) @class.inside) @class.around (message (message_body) @class.inside) @class.around
(enum (enumBody) @class.inside) @class.around (enum (enum_body) @class.inside) @class.around
(service (serviceBody) @class.inside) @class.around (service (service_body) @class.inside) @class.around
(rpc (enumMessageType) @parameter.inside) @function.inside (rpc (message_or_enum_type) @parameter.inside) @function.inside
(rpc (enumMessageType) @parameter.around) @function.around (rpc (message_or_enum_type) @parameter.around) @function.around
(comment) @comment.inside (comment) @comment.inside
(comment)+ @comment.around (comment)+ @comment.around

View File

@@ -63,6 +63,14 @@
(#any-of? @type.enum.variant.builtin "Some" "None" "Ok" "Err")) (#any-of? @type.enum.variant.builtin "Some" "None" "Ok" "Err"))
(call_expression
(identifier) @function.builtin
(#any-of? @function.builtin
"drop"
"size_of"
"size_of_val"
"align_of"
"align_of_val"))
((type_identifier) @type.builtin ((type_identifier) @type.builtin
(#any-of? (#any-of?
@@ -113,6 +121,7 @@
"." "."
";" ";"
"," ","
":"
] @punctuation.delimiter ] @punctuation.delimiter
[ [
@@ -310,6 +319,8 @@
((identifier) @type ((identifier) @type
(#match? @type "^[A-Z]")) (#match? @type "^[A-Z]"))
(never_type "!" @type)
; ------- ; -------
; Functions ; Functions
; ------- ; -------
@@ -452,6 +463,7 @@
; Remaining Identifiers ; Remaining Identifiers
; ------- ; -------
; We do not style ? as an operator on purpose as it allows styling ? differently, as many highlighters do. @operator.special might have been a better scope, but @special is already documented so the change would break themes (including the intent of the default theme)
"?" @special "?" @special
(type_identifier) @type (type_identifier) @type

View File

@@ -2,10 +2,8 @@
(pragma_directive) @keyword.directive (pragma_directive) @keyword.directive
(solidity_version_comparison_operator _ @keyword.directive) (solidity_version_comparison_operator _ @keyword.directive)
; Literals ; Literals
; -------- ; --------
[ [
(string) (string)
(hex_string_literal) (hex_string_literal)
@@ -27,10 +25,8 @@
(comment) @comment (comment) @comment
; Definitions and references ; Definitions and references
; ----------- ; -----------
(type_name) @type (type_name) @type
[ [
@@ -38,7 +34,8 @@
(number_unit) (number_unit)
] @type.builtin ] @type.builtin
(user_defined_type (identifier) @type) (user_defined_type (_) @type)
(user_defined_type_definition name: (identifier) @type)
(type_alias (identifier) @type) (type_alias (identifier) @type)
; Color payable in payable address conversion as type and not as keyword ; Color payable in payable address conversion as type and not as keyword
@@ -47,24 +44,15 @@
(type_name "(" @punctuation.bracket "=>" @punctuation.delimiter ")" @punctuation.bracket) (type_name "(" @punctuation.bracket "=>" @punctuation.delimiter ")" @punctuation.bracket)
; Definitions ; Definitions
(struct_declaration (struct_declaration name: (identifier) @type)
name: (identifier) @type) (enum_declaration name: (identifier) @type)
(enum_declaration (contract_declaration name: (identifier) @type)
name: (identifier) @type) (library_declaration name: (identifier) @type)
(contract_declaration (interface_declaration name: (identifier) @type)
name: (identifier) @type) (event_definition name: (identifier) @type)
(library_declaration (error_declaration name: (identifier) @type)
name: (identifier) @type) (function_definition name: (identifier) @function)
(interface_declaration (modifier_definition name: (identifier) @function)
name: (identifier) @type)
(event_definition
name: (identifier) @type)
(function_definition
name: (identifier) @function)
(modifier_definition
name: (identifier) @function)
(yul_evm_builtin) @function.builtin (yul_evm_builtin) @function.builtin
; Use constructor coloring for special functions ; Use constructor coloring for special functions
@@ -75,14 +63,16 @@
(struct_member name: (identifier) @variable.other.member) (struct_member name: (identifier) @variable.other.member)
(enum_value) @constant (enum_value) @constant
; SCREAMING_SNAKE_CASE identifier are constants
((identifier) @constant (#match? @constant "^[A-Z][A-Z_]+$"))
; Invocations ; Invocations
(emit_statement . (identifier) @type) (emit_statement name: (expression (identifier) @type))
(revert_statement error: (identifier) @type) (revert_statement error: (expression (identifier) @type))
(modifier_invocation (identifier) @function) (modifier_invocation . (_) @function)
(call_expression . (member_expression property: (identifier) @function.method)) (call_expression . (_(member_expression property: (_) @function.method)))
(call_expression . (identifier) @function) (call_expression . (expression (identifier) @function))
; Function parameters ; Function parameters
(call_struct_argument name: (identifier) @field) (call_struct_argument name: (identifier) @field)
@@ -90,15 +80,20 @@
(parameter name: (identifier) @variable.parameter) (parameter name: (identifier) @variable.parameter)
; Yul functions ; Yul functions
(yul_function_call function: (yul_identifier) @function) (yul_function_call function: (_) @function)
(yul_function_definition . (yul_identifier) @function (yul_identifier) @variable.parameter) (yul_function_definition
("function" (yul_identifier) @function "(" (
(yul_identifier) @variable.parameter ("," (yul_identifier) @variable.parameter)*
)
)
)
; Structs and members ; Structs and members
(member_expression property: (identifier) @variable.other.member) (member_expression property: (identifier) @variable.other.member)
(struct_expression type: ((identifier) @type .)) (struct_expression type: ((expression (identifier)) @type .))
(struct_field_assignment name: (identifier) @variable.other.member) (struct_field_assignment name: (identifier) @variable.other.member)
; Tokens ; Tokens
; ------- ; -------
@@ -113,9 +108,9 @@
"struct" "struct"
"enum" "enum"
"event" "event"
"type"
"assembly" "assembly"
"emit" "emit"
"public" "public"
"internal" "internal"
"private" "private"
@@ -123,7 +118,6 @@
"pure" "pure"
"view" "view"
"payable" "payable"
"modifier" "modifier"
"var" "var"
"let" "let"
@@ -137,6 +131,8 @@
"storage" "storage"
"calldata" "calldata"
"constant" "constant"
"transient"
(immutable)
] @keyword.storage.modifier ] @keyword.storage.modifier
[ [
@@ -175,7 +171,6 @@
(event_parameter "indexed" @keyword) (event_parameter "indexed" @keyword)
; Punctuation ; Punctuation
[ [
"(" "("
")" ")"
@@ -185,7 +180,6 @@
"}" "}"
] @punctuation.bracket ] @punctuation.bracket
[ [
"." "."
"," ","
@@ -194,14 +188,11 @@
"=>" "=>"
] @punctuation.delimiter ] @punctuation.delimiter
; Operators ; Operators
[ [
"&&" "&&"
"||" "||"
">>" ">>"
">>>"
"<<" "<<"
"&" "&"
"^" "^"
@@ -216,15 +207,12 @@
"<=" "<="
"==" "=="
"!=" "!="
"!=="
">=" ">="
">" ">"
"!" "!"
"~" "~"
"-" "-"
"+" "+"
"delete"
"new"
"++" "++"
"--" "--"
"+=" "+="
@@ -244,10 +232,9 @@
"new" "new"
] @keyword.operator ] @keyword.operator
; TODO: move to top when order swapped
; identifiers ; identifiers
; ----------- ; -----------
((identifier) @variable.builtin ((identifier) @variable.builtin (#any-of? @variable.builtin "this" "msg" "block" "tx"))
(#match? @variable.builtin "^(this|msg|block|tx)$"))
(identifier) @variable (identifier) @variable
(yul_identifier) @variable (yul_identifier) @variable

View File

@@ -1,9 +1,9 @@
(function_definition) @local.scope (function_definition) @local.scope
(constructor_definition) @local.scope
(block_statement) @local.scope (block_statement) @local.scope
(function_definition (parameter name: (identifier) @local.definition)) (function_definition (parameter name: (identifier) @local.definition))
(constructor_definition (parameter name: (identifier) @local.definition))
(variable_declaration name: (identifier) @local.definition)
; still have to support tuple assignments (identifier) @local.reference
(assignment_expression left: (identifier) @local.definition)
(identifier) @local.reference

View File

@@ -17,7 +17,7 @@
((parameter) @parameter.inside . ","? @parameter.around) @parameter.around) ((parameter) @parameter.inside . ","? @parameter.around) @parameter.around)
(return_type_definition (return_type_definition
((parameter) @parameter.inside . ","? @parameter.around) @parameter.around) ((parameter) @entry.inside . ","? @entry.around) @entry.around)
(modifier_definition (modifier_definition
((parameter) @parameter.inside . ","? @parameter.around) @parameter.around) ((parameter) @parameter.inside . ","? @parameter.around) @parameter.around)
@@ -29,13 +29,13 @@
((error_parameter) @parameter.inside . ","? @parameter.around) @parameter.around) ((error_parameter) @parameter.inside . ","? @parameter.around) @parameter.around)
(call_argument (call_argument
((call_struct_argument) @parameter.inside . ","? @parameter.around) @parameter.around) ((call_struct_argument) @entry.inside . ","? @entry.around) @entry.around)
(call_expression (call_expression
((call_argument) @parameter.inside . ","? @parameter.around) @parameter.around) ((call_argument) @parameter.inside . ","? @parameter.around) @parameter.around)
(variable_declaration_tuple (variable_declaration_tuple
((variable_declaration) @parameter.inside . ","? @parameter.around) @parameter.around) ((variable_declaration) @entry.inside . ","? @entry.around) @entry.around)
(emit_statement (emit_statement
((call_argument) @parameter.inside . ","? @parameter.around) @parameter.around) ((call_argument) @parameter.inside . ","? @parameter.around) @parameter.around)
@@ -52,3 +52,4 @@
(comment) @comment.inside (comment) @comment.inside
(comment)+ @comment.around (comment)+ @comment.around

View File

@@ -56,13 +56,11 @@
] @keyword.import ] @keyword.import
[ [
"$if" "gen"
"$else"
"$config"
] @keyword.directive ] @keyword.directive
((comptime_if ["{" "}"] @keyword.directive)) ((gen_if_expression ["if" "else"] @keyword.directive))
((comptime_else ["{" "}"] @keyword.directive)) ((naked_gen_if_expression ["if" "else"] @keyword.directive))
((attribute) ["#" "[" "]"] @punctuation.delimiter) ((attribute) ["#" "[" "]"] @punctuation.delimiter)

View File

@@ -4,7 +4,7 @@
["\\(" ")"] @punctuation.special) ["\\(" ")"] @punctuation.special)
["." ";" ":" "," ] @punctuation.delimiter ["." ";" ":" "," ] @punctuation.delimiter
["(" ")" "[" "]" "{" "}"] @punctuation.bracket ["(" ")" "[" "]" "{" "}" "<" ">"] @punctuation.bracket
; Identifiers ; Identifiers
(attribute) @variable (attribute) @variable
@@ -24,6 +24,7 @@
] @keyword ] @keyword
(function_declaration (simple_identifier) @function.method) (function_declaration (simple_identifier) @function.method)
(protocol_function_declaration (simple_identifier) @function.method)
(init_declaration ["init" @constructor]) (init_declaration ["init" @constructor])
(deinit_declaration ["deinit" @constructor]) (deinit_declaration ["deinit" @constructor])
@@ -91,6 +92,9 @@
(#match? @type "^[A-Z]")) (#match? @type "^[A-Z]"))
(call_expression (simple_identifier) @keyword (#eq? @keyword "defer")) ; defer { ... } (call_expression (simple_identifier) @keyword (#eq? @keyword "defer")) ; defer { ... }
(navigation_suffix
(simple_identifier) @variable.other.member)
(try_operator) @operator (try_operator) @operator
(try_operator ["try" @keyword]) (try_operator ["try" @keyword])
@@ -147,7 +151,7 @@
(integer_literal) @constant.numeric.integer (integer_literal) @constant.numeric.integer
(real_literal) @constant.numeric.float (real_literal) @constant.numeric.float
(boolean_literal) @constant.builtin.boolean (boolean_literal) @constant.builtin.boolean
"nil" @variable.builtin "nil" @constant.builtin
"?" @type "?" @type
(type_annotation "!" @type) (type_annotation "!" @type)
@@ -160,6 +164,7 @@
"?" "?"
"+" "+"
"-" "-"
"\\"
"*" "*"
"/" "/"
"%" "%"

View File

@@ -4,3 +4,7 @@
((regex_literal) @injection.content ((regex_literal) @injection.content
(#set! injection.language "regex")) (#set! injection.language "regex"))
((comment) @injection.content
(#set! injection.language "comment")
(#set! injection.include-children))

View File

@@ -1,5 +1,3 @@
; See: https://tree-sitter.github.io/tree-sitter/syntax-highlighting#local-variables
; Scopes @local.scope ; Scopes @local.scope
; ------------------------- ; -------------------------

View File

@@ -0,0 +1,6 @@
[
(named_node)
(predicate)
(grouping)
(list)
] @fold

View File

@@ -1,50 +1,50 @@
; mark the string passed #match? as a regex ((program
(((predicate_name) @function .
(capture) (comment)*
(string) @string.regexp) .
(#eq? @function "#match?")) (comment) @keyword.import)
(#match? @keyword.import "^;+ *inherits *:"))
; highlight inheritance comments ((parameters
(((comment) @keyword.directive) (identifier) @constant.numeric)
(#match? @keyword.directive "^; +inherits *:")) (#match? @constant.numeric "^[-+]?[0-9]+(.[0-9]+)?$"))
[ "_" @constant
"("
")"
"["
"]"
] @punctuation.bracket
":" @punctuation.delimiter ":" @punctuation.delimiter
"!" @operator
[ [
(one_or_more) "["
(zero_or_one) "]"
(zero_or_more) "("
] @operator ")"
] @punctuation.bracket
[ "." @operator
(wildcard_node)
(anchor)
] @constant.builtin
[ (quantifier) @operator
(anonymous_leaf)
(string)
] @string
(comment) @comment (comment) @comment
(field_name) @variable.other.member (negated_field
"!" @operator
(identifier) @variable.other.member)
(field_definition
name: (identifier) @variable.other.member)
(named_node
name: (identifier) @tag)
((predicate
"#" @function.builtin
name: (identifier) @function.builtin @_name
type: (predicate_type) @function.builtin)
(#any-of? @_name "eq" "match" "any-of" "not-any-of" "is" "is-not" "not-same-line" "not-kind-eq" "set" "select-adjacent" "strip"))
(predicate name: (identifier) @error)
(capture) @label (capture) @label
((predicate_name) @function
(#any-of? @function "#eq?" "#match?" "#any-of?" "#not-any-of?" "#is?" "#is-not?" "#not-same-line?" "#not-kind-eq?" "#set!" "#select-adjacent!" "#strip!"))
(predicate_name) @error
(escape_sequence) @constant.character.escape (escape_sequence) @constant.character.escape
(node_name) @tag (string) @string
(variable) @variable

View File

@@ -1,8 +1,10 @@
((comment) @injection.content ((comment) @injection.content
(#set! injection.language "comment")) (#set! injection.language "comment"))
((predicate ((predicate
(predicate_name) @_predicate name: (identifier) @_name
(string) @injection.content) parameters:
(#eq? @_predicate "#match?") (parameters
(#set! injection.language "regex")) (string (string_content) @injection.content)))
(#any-of? @_name "match" "not-match")
(#set! injection.language "regex"))

View File

@@ -1,3 +1,4 @@
# NOTE: For contributors looking to modify the theme, please submit a pull request at https://github.com/catppuccin/helix instead of updating this file. Changes are frequently synchronized from the catppuccin/helix theme repository.
# Syntax highlighting # Syntax highlighting
# ------------------- # -------------------
"attribute" = "yellow" "attribute" = "yellow"
@@ -21,7 +22,7 @@
"variable" = "text" "variable" = "text"
"variable.parameter" = { fg = "maroon", modifiers = ["italic"] } "variable.parameter" = { fg = "maroon", modifiers = ["italic"] }
"variable.builtin" = "red" "variable.builtin" = "red"
"variable.other.member" = "teal" "variable.other.member" = "blue"
"label" = "sapphire" # used for lifetimes "label" = "sapphire" # used for lifetimes
@@ -50,10 +51,10 @@
"markup.heading.5" = "pink" "markup.heading.5" = "pink"
"markup.heading.6" = "teal" "markup.heading.6" = "teal"
"markup.list" = "mauve" "markup.list" = "mauve"
"markup.bold" = { modifiers = ["bold"] }
"markup.italic" = { modifiers = ["italic"] }
"markup.list.unchecked" = "overlay2" "markup.list.unchecked" = "overlay2"
"markup.list.checked" = "green" "markup.list.checked" = "green"
"markup.bold" = { modifiers = ["bold"] }
"markup.italic" = { modifiers = ["italic"] }
"markup.link.url" = { fg = "blue", modifiers = ["italic", "underlined"] } "markup.link.url" = { fg = "blue", modifiers = ["italic", "underlined"] }
"markup.link.text" = "blue" "markup.link.text" = "blue"
"markup.raw" = "flamingo" "markup.raw" = "flamingo"
@@ -86,6 +87,7 @@
"ui.text" = "text" "ui.text" = "text"
"ui.text.focus" = { fg = "text", bg = "surface0", modifiers = ["bold"] } "ui.text.focus" = { fg = "text", bg = "surface0", modifiers = ["bold"] }
"ui.text.inactive" = { fg = "overlay1" } "ui.text.inactive" = { fg = "overlay1" }
"ui.text.directory" = { fg = "blue" }
"ui.virtual" = "overlay0" "ui.virtual" = "overlay0"
"ui.virtual.ruler" = { bg = "surface0" } "ui.virtual.ruler" = { bg = "surface0" }
@@ -114,6 +116,7 @@
"ui.menu" = { fg = "overlay2", bg = "surface0" } "ui.menu" = { fg = "overlay2", bg = "surface0" }
"ui.menu.selected" = { fg = "text", bg = "surface1", modifiers = ["bold"] } "ui.menu.selected" = { fg = "text", bg = "surface1", modifiers = ["bold"] }
"diagnostic.unnecessary" = { modifiers = ["dim"] }
"diagnostic.error" = { underline = { color = "red", style = "curl" } } "diagnostic.error" = { underline = { color = "red", style = "curl" } }
"diagnostic.warning" = { underline = { color = "yellow", style = "curl" } } "diagnostic.warning" = { underline = { color = "yellow", style = "curl" } }
"diagnostic.info" = { underline = { color = "sky", style = "curl" } } "diagnostic.info" = { underline = { color = "sky", style = "curl" } }

View File

@@ -24,7 +24,7 @@
"operator" = "text" "operator" = "text"
"punctuation" = "text" "punctuation" = "text"
"punctuation.delimiter" = "text" "punctuation.delimiter" = "text"
"special" = "text" "special" = "light_blue"
"string" = "orange" "string" = "orange"
"string.regexp" = "gold" "string.regexp" = "gold"
"tag" = "blue2" "tag" = "blue2"
@@ -72,11 +72,14 @@
"ui.bufferline.background" = { bg = "background" } "ui.bufferline.background" = { bg = "background" }
"ui.text" = { fg = "text" } "ui.text" = { fg = "text" }
"ui.text.focus" = { fg = "white" } "ui.text.focus" = { fg = "white" }
"ui.text.directory" = { fg = "blue2" }
"ui.text.inactive" = { fg = "dark_gray" }
"ui.virtual.whitespace" = { fg = "#3e3e3d" } "ui.virtual.whitespace" = { fg = "#3e3e3d" }
"ui.virtual.wrap" = { fg = "#3e3e3d" }
"ui.virtual.ruler" = { bg = "borders" } "ui.virtual.ruler" = { bg = "borders" }
"ui.virtual.indent-guide" = { fg = "dark_gray4" } "ui.virtual.indent-guide" = { fg = "dark_gray4" }
"ui.virtual.inlay-hint" = { fg = "dark_gray5"} "ui.virtual.inlay-hint" = { fg = "dark_gray5"}
"ui.virtual.jump-label" = { fg = "dark_gray", modifiers = ["bold"] } "ui.virtual.jump-label" = { fg = "yellow", modifiers = ["bold"] }
"ui.highlight.frameline" = { bg = "#4b4b18" } "ui.highlight.frameline" = { bg = "#4b4b18" }
"ui.debug.active" = { fg = "#ffcc00" } "ui.debug.active" = { fg = "#ffcc00" }
"ui.debug.breakpoint" = { fg = "#e51400" } "ui.debug.breakpoint" = { fg = "#e51400" }

View File

@@ -118,6 +118,7 @@
"ui.statusline.select" = { fg = "black", bg = "cyan", modifiers = ["bold"] } "ui.statusline.select" = { fg = "black", bg = "cyan", modifiers = ["bold"] }
"ui.text" = { fg = "foreground" } "ui.text" = { fg = "foreground" }
"ui.text.focus" = { fg = "cyan" } "ui.text.focus" = { fg = "cyan" }
"ui.text.directory" = { fg = "cyan" }
"ui.virtual.indent-guide" = { fg = "indent" } "ui.virtual.indent-guide" = { fg = "indent" }
"ui.virtual.inlay-hint" = { fg = "cyan" } "ui.virtual.inlay-hint" = { fg = "cyan" }
"ui.virtual.inlay-hint.parameter" = { fg = "cyan", modifiers = ["italic", "dim"] } "ui.virtual.inlay-hint.parameter" = { fg = "cyan", modifiers = ["italic", "dim"] }

View File

@@ -42,6 +42,7 @@
"ui.statusline.select" = { fg = "background_dark", bg = "purple" } "ui.statusline.select" = { fg = "background_dark", bg = "purple" }
"ui.text" = { fg = "foreground" } "ui.text" = { fg = "foreground" }
"ui.text.focus" = { fg = "cyan" } "ui.text.focus" = { fg = "cyan" }
"ui.text.directory" = { fg = "cyan" }
"ui.window" = { fg = "foreground" } "ui.window" = { fg = "foreground" }
"ui.virtual.jump-label" = { fg = "pink", modifiers = ["bold"] } "ui.virtual.jump-label" = { fg = "pink", modifiers = ["bold"] }
"ui.virtual.ruler" = { bg = "background_dark" } "ui.virtual.ruler" = { bg = "background_dark" }

Some files were not shown because too many files have changed in this diff Show More