Merge branch 'helix-editor:master' into pull-diagnostics

pull/11315/head
SofusA 4 months ago committed by GitHub
commit 4e85776813
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

141
Cargo.lock generated

@ -166,7 +166,7 @@ dependencies = [
"android-tzdata",
"iana-time-zone",
"num-traits",
"windows-targets 0.52.0",
"windows-targets 0.52.6",
]
[[package]]
@ -263,17 +263,18 @@ dependencies = [
[[package]]
name = "crossterm"
version = "0.27.0"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
dependencies = [
"bitflags 2.6.0",
"crossterm_winapi",
"filedescriptor",
"futures-core",
"libc",
"mio 0.8.11",
"mio",
"parking_lot",
"rustix",
"signal-hook",
"signal-hook-mio",
"winapi",
@ -356,9 +357,9 @@ dependencies = [
[[package]]
name = "dunce"
version = "1.0.4"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
[[package]]
name = "either"
@ -1405,7 +1406,7 @@ dependencies = [
name = "helix-lsp-types"
version = "0.95.1"
dependencies = [
"bitflags 1.3.2",
"bitflags 2.6.0",
"serde",
"serde_json",
"serde_repr",
@ -1428,7 +1429,7 @@ dependencies = [
"rustix",
"tempfile",
"which",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@ -1699,7 +1700,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
dependencies = [
"cfg-if",
"windows-targets 0.52.0",
"windows-targets 0.48.0",
]
[[package]]
@ -1766,18 +1767,6 @@ dependencies = [
"adler",
]
[[package]]
name = "mio"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys 0.48.0",
]
[[package]]
name = "mio"
version = "1.0.1"
@ -1786,6 +1775,7 @@ checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4"
dependencies = [
"hermit-abi 0.3.9",
"libc",
"log",
"wasi",
"windows-sys 0.52.0",
]
@ -2034,9 +2024,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.10.5"
version = "1.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
dependencies = [
"aho-corasick",
"memchr",
@ -2152,9 +2142,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.121"
version = "1.0.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609"
checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da"
dependencies = [
"itoa",
"memchr",
@ -2164,9 +2154,9 @@ dependencies = [
[[package]]
name = "serde_repr"
version = "0.1.12"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab"
checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
dependencies = [
"proc-macro2",
"quote",
@ -2206,12 +2196,12 @@ dependencies = [
[[package]]
name = "signal-hook-mio"
version = "0.2.3"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
dependencies = [
"libc",
"mio 0.8.11",
"mio",
"signal-hook",
]
@ -2323,12 +2313,13 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.10.1"
version = "3.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53"
dependencies = [
"cfg-if",
"fastrand",
"once_cell",
"rustix",
"windows-sys 0.52.0",
]
@ -2448,7 +2439,7 @@ dependencies = [
"backtrace",
"bytes",
"libc",
"mio 1.0.1",
"mio",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
@ -2481,9 +2472,9 @@ dependencies = [
[[package]]
name = "toml"
version = "0.8.16"
version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81967dd0dd2c1ab0bc3468bd7caecc32b8a4aa47d0c8c695d8c2b2108168d62c"
checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
dependencies = [
"serde",
"serde_spanned",
@ -2493,18 +2484,18 @@ dependencies = [
[[package]]
name = "toml_datetime"
version = "0.6.7"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8fb9f64314842840f1d940ac544da178732128f1c78c21772e876579e0da1db"
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.22.17"
version = "0.22.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d9f8729f5aea9562aac1cc0441f5d6de3cff1ee0c5d67293eeca5eb36ee7c16"
checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d"
dependencies = [
"indexmap",
"serde",
@ -2673,9 +2664,9 @@ checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
[[package]]
name = "which"
version = "6.0.1"
version = "6.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8211e4f58a2b2805adfbefbc07bab82958fc91e3836339b1ab7ae32465dce0d7"
checksum = "3d9c5ed668ee1f17edb3b627225343d210006a90bb1e3745ce1f30b1fb115075"
dependencies = [
"either",
"home",
@ -2747,7 +2738,16 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.0",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
@ -2782,17 +2782,18 @@ dependencies = [
[[package]]
name = "windows-targets"
version = "0.52.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm 0.52.0",
"windows_aarch64_msvc 0.52.0",
"windows_i686_gnu 0.52.0",
"windows_i686_msvc 0.52.0",
"windows_x86_64_gnu 0.52.0",
"windows_x86_64_gnullvm 0.52.0",
"windows_x86_64_msvc 0.52.0",
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
@ -2809,9 +2810,9 @@ checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
@ -2827,9 +2828,9 @@ checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
@ -2845,9 +2846,15 @@ checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_gnu"
version = "0.52.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
@ -2863,9 +2870,9 @@ checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_i686_msvc"
version = "0.52.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
@ -2881,9 +2888,9 @@ checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
@ -2899,9 +2906,9 @@ checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
@ -2917,15 +2924,15 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.6.5"
version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8"
checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
dependencies = [
"memchr",
]

@ -1,6 +1,6 @@
| Language | Syntax Highlighting | Treesitter Textobjects | Auto Indent | Default LSP |
| --- | --- | --- | --- | --- |
| ada | ✓ | ✓ | | `ada_language_server`, `ada_language_server` |
| ada | ✓ | ✓ | | `ada_language_server` |
| adl | ✓ | ✓ | ✓ | |
| agda | ✓ | | | |
| astro | ✓ | | | |
@ -58,6 +58,7 @@
| gas | ✓ | ✓ | | |
| gdscript | ✓ | ✓ | ✓ | |
| gemini | ✓ | | | |
| gherkin | ✓ | | | |
| git-attributes | ✓ | | | |
| git-commit | ✓ | ✓ | | |
| git-config | ✓ | | | |
@ -97,6 +98,7 @@
| javascript | ✓ | ✓ | ✓ | `typescript-language-server` |
| jinja | ✓ | | | |
| jjdescription | ✓ | | | |
| jq | ✓ | ✓ | | `jq-lsp` |
| jsdoc | ✓ | | | |
| json | ✓ | ✓ | ✓ | `vscode-json-language-server` |
| json5 | ✓ | | | |
@ -125,7 +127,7 @@
| markdown.inline | ✓ | | | |
| matlab | ✓ | ✓ | ✓ | |
| mermaid | ✓ | | | |
| meson | ✓ | | ✓ | |
| meson | ✓ | | ✓ | `mesonlsp` |
| mint | | | | `mint` |
| mojo | ✓ | ✓ | ✓ | `mojo-lsp-server` |
| move | ✓ | | | |
@ -133,7 +135,7 @@
| nasm | ✓ | ✓ | | |
| nickel | ✓ | | ✓ | `nls` |
| nim | ✓ | ✓ | ✓ | `nimlangserver` |
| nix | ✓ | ✓ | | `nil` |
| nix | ✓ | ✓ | | `nil`, `nixd` |
| nu | ✓ | | | `nu` |
| nunjucks | ✓ | | | |
| ocaml | ✓ | | ✓ | `ocamllsp` |
@ -199,12 +201,14 @@
| tcl | ✓ | | ✓ | |
| templ | ✓ | | | `templ` |
| tfvars | ✓ | | ✓ | `terraform-ls` |
| thrift | ✓ | | | |
| todotxt | ✓ | | | |
| toml | ✓ | ✓ | | `taplo` |
| tsq | ✓ | | | |
| tsx | ✓ | ✓ | ✓ | `typescript-language-server` |
| twig | ✓ | | | |
| typescript | ✓ | ✓ | ✓ | `typescript-language-server` |
| typespec | ✓ | ✓ | ✓ | `tsp-server` |
| typst | ✓ | | | `tinymist`, `typst-lsp` |
| ungrammar | ✓ | | | |
| unison | ✓ | | ✓ | |

@ -14,6 +14,10 @@ Note that:
## Pre-built binaries
Download pre-built binaries from the [GitHub Releases page](https://github.com/helix-editor/helix/releases).
Add the `hx` binary to your system's `$PATH` to use it from the command line, and copy the `runtime` directory into the config directory (for example `~/.config/helix/runtime` on Linux/macOS).
The runtime location can be overriden via the HELIX_RUNTIME environment variable.
The tarball contents include an `hx` binary and a `runtime` directory.
To set up Helix:
1. Add the `hx` binary to your system's `$PATH` to allow it to be used from the command line.
2. Copy the `runtime` directory to a location that `hx` searches for runtime files. A typical location on Linux/macOS is `~/.config/helix/runtime`.
To see the runtime directories that `hx` searches, run `hx --health`. If necessary, you can override the default runtime location by setting the `HELIX_RUNTIME` environment variable.

@ -320,10 +320,14 @@ Displays documentation for item under cursor. Remapping currently not supported.
Displays documentation for the selected completion item. Remapping currently not supported.
| Key | Description |
| ---- | ----------- |
| `Shift-Tab`, `Ctrl-p`, `Up` | Previous entry |
| `Tab`, `Ctrl-n`, `Down` | Next entry |
| Key | Description |
| ---- | ----------- |
| `Shift-Tab`, `Ctrl-p`, `Up` | Previous entry |
| `Tab`, `Ctrl-n`, `Down` | Next entry |
| `Enter` | Close menu and accept completion |
| `Ctrl-c` | Close menu and reject completion |
Any other keypresses result in the completion being accepted.
##### Signature-help Popup

@ -75,5 +75,20 @@ Ctrl, Shift and Alt modifiers are encoded respectively with the prefixes
Keys can be disabled by binding them to the `no_op` command.
A list of commands is available in the [Keymap](https://docs.helix-editor.com/keymap.html) documentation
and in the source code at [`helix-term/src/commands.rs`](https://github.com/helix-editor/helix/blob/master/helix-term/src/commands.rs) at the invocation of `static_commands!` macro and the `TypableCommandList`.
## Commands
There are three kinds of commands that can be used in keymaps:
* Static commands: commands like `move_char_right` which are usually bound to
keys and used for movement and editing. A list of static commands is
available in the [Keymap](./keymap.html) documentation and in the source code
in [`helix-term/src/commands.rs`](https://github.com/helix-editor/helix/blob/master/helix-term/src/commands.rs)
at the invocation of `static_commands!` macro and the `TypableCommandList`.
* Typable commands: commands that can be executed from command mode (`:`), for
example `:write!`. See the [Commands](./commands.html) documentation for a
list of available typeable commands.
* Macros: sequences of keys that are executed in order. These keybindings
start with `@` and then list any number of keys to be executed. For example
`@miw` can be used to select the surrounding word. For now, macro keybindings
are not allowed in keybinding sequences due to limitations in the way that
command sequences are executed.

@ -197,13 +197,31 @@ pub fn move_prev_long_word_end(slice: RopeSlice, range: Range, count: usize) ->
word_move(slice, range, count, WordMotionTarget::PrevLongWordEnd)
}
pub fn move_next_sub_word_start(slice: RopeSlice, range: Range, count: usize) -> Range {
word_move(slice, range, count, WordMotionTarget::NextSubWordStart)
}
pub fn move_next_sub_word_end(slice: RopeSlice, range: Range, count: usize) -> Range {
word_move(slice, range, count, WordMotionTarget::NextSubWordEnd)
}
pub fn move_prev_sub_word_start(slice: RopeSlice, range: Range, count: usize) -> Range {
word_move(slice, range, count, WordMotionTarget::PrevSubWordStart)
}
pub fn move_prev_sub_word_end(slice: RopeSlice, range: Range, count: usize) -> Range {
word_move(slice, range, count, WordMotionTarget::PrevSubWordEnd)
}
fn word_move(slice: RopeSlice, range: Range, count: usize, target: WordMotionTarget) -> Range {
let is_prev = matches!(
target,
WordMotionTarget::PrevWordStart
| WordMotionTarget::PrevLongWordStart
| WordMotionTarget::PrevSubWordStart
| WordMotionTarget::PrevWordEnd
| WordMotionTarget::PrevLongWordEnd
| WordMotionTarget::PrevSubWordEnd
);
// Special-case early-out.
@ -383,6 +401,12 @@ pub enum WordMotionTarget {
NextLongWordEnd,
PrevLongWordStart,
PrevLongWordEnd,
// A sub word is similar to a regular word, except it is also delimited by
// underscores and transitions from lowercase to uppercase.
NextSubWordStart,
NextSubWordEnd,
PrevSubWordStart,
PrevSubWordEnd,
}
pub trait CharHelpers {
@ -398,8 +422,10 @@ impl CharHelpers for Chars<'_> {
target,
WordMotionTarget::PrevWordStart
| WordMotionTarget::PrevLongWordStart
| WordMotionTarget::PrevSubWordStart
| WordMotionTarget::PrevWordEnd
| WordMotionTarget::PrevLongWordEnd
| WordMotionTarget::PrevSubWordEnd
);
// Reverse the iterator if needed for the motion direction.
@ -476,6 +502,25 @@ fn is_long_word_boundary(a: char, b: char) -> bool {
}
}
fn is_sub_word_boundary(a: char, b: char, dir: Direction) -> bool {
match (categorize_char(a), categorize_char(b)) {
(CharCategory::Word, CharCategory::Word) => {
if (a == '_') != (b == '_') {
return true;
}
// Subword boundaries are directional: in 'fooBar', there is a
// boundary between 'o' and 'B', but not between 'B' and 'a'.
match dir {
Direction::Forward => a.is_lowercase() && b.is_uppercase(),
Direction::Backward => a.is_uppercase() && b.is_lowercase(),
}
}
(a, b) if a != b => true,
_ => false,
}
}
fn reached_target(target: WordMotionTarget, prev_ch: char, next_ch: char) -> bool {
match target {
WordMotionTarget::NextWordStart | WordMotionTarget::PrevWordEnd => {
@ -494,6 +539,22 @@ fn reached_target(target: WordMotionTarget, prev_ch: char, next_ch: char) -> boo
is_long_word_boundary(prev_ch, next_ch)
&& (!prev_ch.is_whitespace() || char_is_line_ending(next_ch))
}
WordMotionTarget::NextSubWordStart => {
is_sub_word_boundary(prev_ch, next_ch, Direction::Forward)
&& (char_is_line_ending(next_ch) || !(next_ch.is_whitespace() || next_ch == '_'))
}
WordMotionTarget::PrevSubWordEnd => {
is_sub_word_boundary(prev_ch, next_ch, Direction::Backward)
&& (char_is_line_ending(next_ch) || !(next_ch.is_whitespace() || next_ch == '_'))
}
WordMotionTarget::NextSubWordEnd => {
is_sub_word_boundary(prev_ch, next_ch, Direction::Forward)
&& (!(prev_ch.is_whitespace() || prev_ch == '_') || char_is_line_ending(next_ch))
}
WordMotionTarget::PrevSubWordStart => {
is_sub_word_boundary(prev_ch, next_ch, Direction::Backward)
&& (!(prev_ch.is_whitespace() || prev_ch == '_') || char_is_line_ending(next_ch))
}
}
}
@ -1012,6 +1073,178 @@ mod test {
}
}
#[test]
fn test_behaviour_when_moving_to_start_of_next_sub_words() {
let tests = [
(
"NextSubwordStart",
vec![
(1, Range::new(0, 0), Range::new(0, 4)),
(1, Range::new(4, 4), Range::new(4, 11)),
],
),
(
"next_subword_start",
vec![
(1, Range::new(0, 0), Range::new(0, 5)),
(1, Range::new(4, 4), Range::new(5, 13)),
],
),
(
"Next_Subword_Start",
vec![
(1, Range::new(0, 0), Range::new(0, 5)),
(1, Range::new(4, 4), Range::new(5, 13)),
],
),
(
"NEXT_SUBWORD_START",
vec![
(1, Range::new(0, 0), Range::new(0, 5)),
(1, Range::new(4, 4), Range::new(5, 13)),
],
),
(
"next subword start",
vec![
(1, Range::new(0, 0), Range::new(0, 5)),
(1, Range::new(4, 4), Range::new(5, 13)),
],
),
(
"Next Subword Start",
vec![
(1, Range::new(0, 0), Range::new(0, 5)),
(1, Range::new(4, 4), Range::new(5, 13)),
],
),
(
"NEXT SUBWORD START",
vec![
(1, Range::new(0, 0), Range::new(0, 5)),
(1, Range::new(4, 4), Range::new(5, 13)),
],
),
(
"next__subword__start",
vec![
(1, Range::new(0, 0), Range::new(0, 6)),
(1, Range::new(4, 4), Range::new(4, 6)),
(1, Range::new(5, 5), Range::new(6, 15)),
],
),
(
"Next__Subword__Start",
vec![
(1, Range::new(0, 0), Range::new(0, 6)),
(1, Range::new(4, 4), Range::new(4, 6)),
(1, Range::new(5, 5), Range::new(6, 15)),
],
),
(
"NEXT__SUBWORD__START",
vec![
(1, Range::new(0, 0), Range::new(0, 6)),
(1, Range::new(4, 4), Range::new(4, 6)),
(1, Range::new(5, 5), Range::new(6, 15)),
],
),
];
for (sample, scenario) in tests {
for (count, begin, expected_end) in scenario.into_iter() {
let range = move_next_sub_word_start(Rope::from(sample).slice(..), begin, count);
assert_eq!(range, expected_end, "Case failed: [{}]", sample);
}
}
}
#[test]
fn test_behaviour_when_moving_to_end_of_next_sub_words() {
let tests = [
(
"NextSubwordEnd",
vec![
(1, Range::new(0, 0), Range::new(0, 4)),
(1, Range::new(4, 4), Range::new(4, 11)),
],
),
(
"next subword end",
vec![
(1, Range::new(0, 0), Range::new(0, 4)),
(1, Range::new(4, 4), Range::new(4, 12)),
],
),
(
"Next Subword End",
vec![
(1, Range::new(0, 0), Range::new(0, 4)),
(1, Range::new(4, 4), Range::new(4, 12)),
],
),
(
"NEXT SUBWORD END",
vec![
(1, Range::new(0, 0), Range::new(0, 4)),
(1, Range::new(4, 4), Range::new(4, 12)),
],
),
(
"next_subword_end",
vec![
(1, Range::new(0, 0), Range::new(0, 4)),
(1, Range::new(4, 4), Range::new(4, 12)),
],
),
(
"Next_Subword_End",
vec![
(1, Range::new(0, 0), Range::new(0, 4)),
(1, Range::new(4, 4), Range::new(4, 12)),
],
),
(
"NEXT_SUBWORD_END",
vec![
(1, Range::new(0, 0), Range::new(0, 4)),
(1, Range::new(4, 4), Range::new(4, 12)),
],
),
(
"next__subword__end",
vec![
(1, Range::new(0, 0), Range::new(0, 4)),
(1, Range::new(4, 4), Range::new(4, 13)),
(1, Range::new(5, 5), Range::new(5, 13)),
],
),
(
"Next__Subword__End",
vec![
(1, Range::new(0, 0), Range::new(0, 4)),
(1, Range::new(4, 4), Range::new(4, 13)),
(1, Range::new(5, 5), Range::new(5, 13)),
],
),
(
"NEXT__SUBWORD__END",
vec![
(1, Range::new(0, 0), Range::new(0, 4)),
(1, Range::new(4, 4), Range::new(4, 13)),
(1, Range::new(5, 5), Range::new(5, 13)),
],
),
];
for (sample, scenario) in tests {
for (count, begin, expected_end) in scenario.into_iter() {
let range = move_next_sub_word_end(Rope::from(sample).slice(..), begin, count);
assert_eq!(range, expected_end, "Case failed: [{}]", sample);
}
}
}
#[test]
fn test_behaviour_when_moving_to_start_of_next_long_words() {
let tests = [
@ -1181,6 +1414,92 @@ mod test {
}
}
#[test]
fn test_behaviour_when_moving_to_start_of_previous_sub_words() {
let tests = [
(
"PrevSubwordEnd",
vec![
(1, Range::new(13, 13), Range::new(14, 11)),
(1, Range::new(11, 11), Range::new(11, 4)),
],
),
(
"prev subword end",
vec![
(1, Range::new(15, 15), Range::new(16, 13)),
(1, Range::new(12, 12), Range::new(13, 5)),
],
),
(
"Prev Subword End",
vec![
(1, Range::new(15, 15), Range::new(16, 13)),
(1, Range::new(12, 12), Range::new(13, 5)),
],
),
(
"PREV SUBWORD END",
vec![
(1, Range::new(15, 15), Range::new(16, 13)),
(1, Range::new(12, 12), Range::new(13, 5)),
],
),
(
"prev_subword_end",
vec![
(1, Range::new(15, 15), Range::new(16, 13)),
(1, Range::new(12, 12), Range::new(13, 5)),
],
),
(
"Prev_Subword_End",
vec![
(1, Range::new(15, 15), Range::new(16, 13)),
(1, Range::new(12, 12), Range::new(13, 5)),
],
),
(
"PREV_SUBWORD_END",
vec![
(1, Range::new(15, 15), Range::new(16, 13)),
(1, Range::new(12, 12), Range::new(13, 5)),
],
),
(
"prev__subword__end",
vec![
(1, Range::new(17, 17), Range::new(18, 15)),
(1, Range::new(13, 13), Range::new(14, 6)),
(1, Range::new(14, 14), Range::new(15, 6)),
],
),
(
"Prev__Subword__End",
vec![
(1, Range::new(17, 17), Range::new(18, 15)),
(1, Range::new(13, 13), Range::new(14, 6)),
(1, Range::new(14, 14), Range::new(15, 6)),
],
),
(
"PREV__SUBWORD__END",
vec![
(1, Range::new(17, 17), Range::new(18, 15)),
(1, Range::new(13, 13), Range::new(14, 6)),
(1, Range::new(14, 14), Range::new(15, 6)),
],
),
];
for (sample, scenario) in tests {
for (count, begin, expected_end) in scenario.into_iter() {
let range = move_prev_sub_word_start(Rope::from(sample).slice(..), begin, count);
assert_eq!(range, expected_end, "Case failed: [{}]", sample);
}
}
}
#[test]
fn test_behaviour_when_moving_to_start_of_previous_long_words() {
let tests = [
@ -1444,6 +1763,92 @@ mod test {
}
}
#[test]
fn test_behaviour_when_moving_to_end_of_previous_sub_words() {
let tests = [
(
"PrevSubwordEnd",
vec![
(1, Range::new(13, 13), Range::new(14, 11)),
(1, Range::new(11, 11), Range::new(11, 4)),
],
),
(
"prev subword end",
vec![
(1, Range::new(15, 15), Range::new(16, 12)),
(1, Range::new(12, 12), Range::new(12, 4)),
],
),
(
"Prev Subword End",
vec![
(1, Range::new(15, 15), Range::new(16, 12)),
(1, Range::new(12, 12), Range::new(12, 4)),
],
),
(
"PREV SUBWORD END",
vec![
(1, Range::new(15, 15), Range::new(16, 12)),
(1, Range::new(12, 12), Range::new(12, 4)),
],
),
(
"prev_subword_end",
vec![
(1, Range::new(15, 15), Range::new(16, 12)),
(1, Range::new(12, 12), Range::new(12, 4)),
],
),
(
"Prev_Subword_End",
vec![
(1, Range::new(15, 15), Range::new(16, 12)),
(1, Range::new(12, 12), Range::new(12, 4)),
],
),
(
"PREV_SUBWORD_END",
vec![
(1, Range::new(15, 15), Range::new(16, 12)),
(1, Range::new(12, 12), Range::new(12, 4)),
],
),
(
"prev__subword__end",
vec![
(1, Range::new(17, 17), Range::new(18, 13)),
(1, Range::new(13, 13), Range::new(13, 4)),
(1, Range::new(14, 14), Range::new(15, 13)),
],
),
(
"Prev__Subword__End",
vec![
(1, Range::new(17, 17), Range::new(18, 13)),
(1, Range::new(13, 13), Range::new(13, 4)),
(1, Range::new(14, 14), Range::new(15, 13)),
],
),
(
"PREV__SUBWORD__END",
vec![
(1, Range::new(17, 17), Range::new(18, 13)),
(1, Range::new(13, 13), Range::new(13, 4)),
(1, Range::new(14, 14), Range::new(15, 13)),
],
),
];
for (sample, scenario) in tests {
for (count, begin, expected_end) in scenario.into_iter() {
let range = move_prev_sub_word_end(Rope::from(sample).slice(..), begin, count);
assert_eq!(range, expected_end, "Case failed: [{}]", sample);
}
}
}
#[test]
fn test_behaviour_when_moving_to_end_of_next_long_words() {
let tests = [

@ -184,16 +184,16 @@ impl Range {
let positions_to_map = match self.anchor.cmp(&self.head) {
Ordering::Equal => [
(&mut self.anchor, Assoc::After),
(&mut self.head, Assoc::After),
(&mut self.anchor, Assoc::AfterSticky),
(&mut self.head, Assoc::AfterSticky),
],
Ordering::Less => [
(&mut self.anchor, Assoc::After),
(&mut self.head, Assoc::Before),
(&mut self.anchor, Assoc::AfterSticky),
(&mut self.head, Assoc::BeforeSticky),
],
Ordering::Greater => [
(&mut self.head, Assoc::After),
(&mut self.anchor, Assoc::Before),
(&mut self.head, Assoc::AfterSticky),
(&mut self.anchor, Assoc::BeforeSticky),
],
};
changes.update_positions(positions_to_map.into_iter());
@ -482,16 +482,16 @@ impl Selection {
range.old_visual_position = None;
match range.anchor.cmp(&range.head) {
Ordering::Equal => [
(&mut range.anchor, Assoc::After),
(&mut range.head, Assoc::After),
(&mut range.anchor, Assoc::AfterSticky),
(&mut range.head, Assoc::AfterSticky),
],
Ordering::Less => [
(&mut range.anchor, Assoc::After),
(&mut range.head, Assoc::Before),
(&mut range.anchor, Assoc::AfterSticky),
(&mut range.head, Assoc::BeforeSticky),
],
Ordering::Greater => [
(&mut range.head, Assoc::After),
(&mut range.anchor, Assoc::Before),
(&mut range.head, Assoc::AfterSticky),
(&mut range.anchor, Assoc::BeforeSticky),
],
}
});

@ -29,6 +29,12 @@ pub enum Assoc {
/// Acts like `Before` if a word character is inserted
/// before the position, otherwise acts like `After`
BeforeWord,
/// Acts like `Before` but if the position is within an exact replacement
/// (exact size) the offset to the start of the replacement is kept
BeforeSticky,
/// Acts like `After` but if the position is within an exact replacement
/// (exact size) the offset to the start of the replacement is kept
AfterSticky,
}
impl Assoc {
@ -40,13 +46,17 @@ impl Assoc {
fn insert_offset(self, s: &str) -> usize {
let chars = s.chars().count();
match self {
Assoc::After => chars,
Assoc::After | Assoc::AfterSticky => chars,
Assoc::AfterWord => s.chars().take_while(|&c| char_is_word(c)).count(),
// return position before inserted text
Assoc::Before => 0,
Assoc::Before | Assoc::BeforeSticky => 0,
Assoc::BeforeWord => chars - s.chars().rev().take_while(|&c| char_is_word(c)).count(),
}
}
pub fn sticky(self) -> bool {
matches!(self, Assoc::BeforeSticky | Assoc::AfterSticky)
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
@ -456,8 +466,14 @@ impl ChangeSet {
if pos == old_pos && assoc.stay_at_gaps() {
new_pos
} else {
// place to end of insert
new_pos + assoc.insert_offset(s)
let ins = assoc.insert_offset(s);
// if the deleted and inserted text have the exact same size
// keep the relative offset into the new text
if *len == ins && assoc.sticky() {
new_pos + (pos - old_pos)
} else {
new_pos + assoc.insert_offset(s)
}
}
}),
i

@ -30,8 +30,8 @@ log = "0.4"
# cloning/compiling tree-sitter grammars
cc = { version = "1" }
threadpool = { version = "1.0" }
tempfile = "3.10.1"
dunce = "1.0.4"
tempfile = "3.11.0"
dunce = "1.0.5"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
libloading = "0.8"

@ -225,13 +225,16 @@ pub fn merge_toml_values(left: toml::Value, right: toml::Value, merge_depth: usi
/// Used as a ceiling dir for LSP root resolution, the filepicker and potentially as a future filewatching root
///
/// This function starts searching the FS upward from the CWD
/// and returns the first directory that contains either `.git` or `.helix`.
/// and returns the first directory that contains either `.git`, `.svn` or `.helix`.
/// If no workspace was found returns (CWD, true).
/// Otherwise (workspace, false) is returned
pub fn find_workspace() -> (PathBuf, bool) {
let current_dir = current_working_dir();
for ancestor in current_dir.ancestors() {
if ancestor.join(".git").exists() || ancestor.join(".helix").exists() {
if ancestor.join(".git").exists()
|| ancestor.join(".svn").exists()
|| ancestor.join(".helix").exists()
{
return (ancestor.to_owned(), false);
}
}

@ -21,9 +21,9 @@ keywords = ["language", "server", "lsp", "vscode", "lsif"]
license = "MIT"
[dependencies]
bitflags = "1.0.1"
bitflags = "2.6.0"
serde = { version = "1.0.34", features = ["derive"] }
serde_json = "1.0.50"
serde_json = "1.0.122"
serde_repr = "0.1"
url = {version = "2.0.0", features = ["serde"]}

@ -2495,6 +2495,7 @@ pub struct RelativePattern {
pub type Pattern = String;
bitflags! {
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
pub struct WatchKind: u8 {
/// Interested in create events.
const Create = 1;

@ -20,10 +20,10 @@ regex-cursor = "0.1.4"
bitflags = "2.6"
[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.52", features = ["Win32_Security", "Win32_Security_Authorization", "Win32_System_Threading"] }
windows-sys = { version = "0.59", features = ["Win32_Foundation", "Win32_Security", "Win32_Security_Authorization", "Win32_Storage_FileSystem", "Win32_System_Threading"] }
[target.'cfg(unix)'.dependencies]
rustix = { version = "0.38", features = ["fs"] }
[dev-dependencies]
tempfile = "3.10"
tempfile = "3.11"

@ -85,7 +85,7 @@ mod imp {
#[cfg(windows)]
mod imp {
use windows_sys::Win32::Foundation::{CloseHandle, LocalFree, ERROR_SUCCESS, HANDLE, PSID};
use windows_sys::Win32::Foundation::{CloseHandle, LocalFree, ERROR_SUCCESS, HANDLE};
use windows_sys::Win32::Security::Authorization::{
GetNamedSecurityInfoW, SetNamedSecurityInfoW, SE_FILE_OBJECT,
};
@ -95,7 +95,7 @@ mod imp {
SecurityImpersonation, ACCESS_ALLOWED_CALLBACK_ACE, ACL, ACL_SIZE_INFORMATION,
DACL_SECURITY_INFORMATION, GENERIC_MAPPING, GROUP_SECURITY_INFORMATION, INHERITED_ACE,
LABEL_SECURITY_INFORMATION, OBJECT_SECURITY_INFORMATION, OWNER_SECURITY_INFORMATION,
PRIVILEGE_SET, PROTECTED_DACL_SECURITY_INFORMATION, PSECURITY_DESCRIPTOR,
PRIVILEGE_SET, PROTECTED_DACL_SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, PSID,
SID_IDENTIFIER_AUTHORITY, TOKEN_DUPLICATE, TOKEN_QUERY,
};
use windows_sys::Win32::Storage::FileSystem::{
@ -419,7 +419,7 @@ mod imp {
pub fn hardlink_count(p: &Path) -> std::io::Result<u64> {
let file = std::fs::File::open(p)?;
let handle = file.as_raw_handle() as isize;
let handle = file.as_raw_handle();
let mut info: BY_HANDLE_FILE_INFORMATION = unsafe { std::mem::zeroed() };
if unsafe { GetFileInformationByHandle(handle, &mut info) } == 0 {

@ -37,7 +37,7 @@ once_cell = "1.19"
tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] }
tui = { path = "../helix-tui", package = "helix-tui", default-features = false, features = ["crossterm"] }
crossterm = { version = "0.27", features = ["event-stream"] }
crossterm = { version = "0.28", features = ["event-stream"] }
signal-hook = "0.3"
tokio-stream = "0.1"
futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false }
@ -77,7 +77,7 @@ signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }
libc = "0.2.155"
[target.'cfg(target_os = "macos")'.dependencies]
crossterm = { version = "0.27", features = ["event-stream", "use-dev-tty"] }
crossterm = { version = "0.28", features = ["event-stream", "use-dev-tty", "libc"] }
[build-dependencies]
helix-loader = { path = "../helix-loader" }
@ -85,5 +85,5 @@ helix-loader = { path = "../helix-loader" }
[dev-dependencies]
smallvec = "1.13"
indoc = "2.0.5"
tempfile = "3.10.1"
tempfile = "3.11.0"
same-file = "1.0.1"

@ -176,9 +176,16 @@ where
use helix_view::{align_view, Align};
/// A MappableCommand is either a static command like "jump_view_up" or a Typable command like
/// :format. It causes a side-effect on the state (usually by creating and applying a transaction).
/// Both of these types of commands can be mapped with keybindings in the config.toml.
/// MappableCommands are commands that can be bound to keys, executable in
/// normal, insert or select mode.
///
/// There are three kinds:
///
/// * Static: commands usually bound to keys and used for editing, movement,
/// etc., for example `move_char_left`.
/// * Typable: commands executable from command mode, prefixed with a `:`,
/// for example `:write!`.
/// * Macro: a sequence of keys to execute, for example `@miw`.
#[derive(Clone)]
pub enum MappableCommand {
Typable {
@ -191,6 +198,10 @@ pub enum MappableCommand {
fun: fn(cx: &mut Context),
doc: &'static str,
},
Macro {
name: String,
keys: Vec<KeyEvent>,
},
}
macro_rules! static_commands {
@ -227,6 +238,23 @@ impl MappableCommand {
}
}
Self::Static { fun, .. } => (fun)(cx),
Self::Macro { keys, .. } => {
// Protect against recursive macros.
if cx.editor.macro_replaying.contains(&'@') {
cx.editor.set_error(
"Cannot execute macro because the [@] register is already playing a macro",
);
return;
}
cx.editor.macro_replaying.push('@');
let keys = keys.clone();
cx.callback.push(Box::new(move |compositor, cx| {
for key in keys.into_iter() {
compositor.handle_event(&compositor::Event::Key(key), cx);
}
cx.editor.macro_replaying.pop();
}));
}
}
}
@ -234,6 +262,7 @@ impl MappableCommand {
match &self {
Self::Typable { name, .. } => name,
Self::Static { name, .. } => name,
Self::Macro { name, .. } => name,
}
}
@ -241,6 +270,7 @@ impl MappableCommand {
match &self {
Self::Typable { doc, .. } => doc,
Self::Static { doc, .. } => doc,
Self::Macro { name, .. } => name,
}
}
@ -269,6 +299,10 @@ impl MappableCommand {
move_prev_long_word_start, "Move to start of previous long word",
move_next_long_word_end, "Move to end of next long word",
move_prev_long_word_end, "Move to end of previous long word",
move_next_sub_word_start, "Move to start of next sub word",
move_prev_sub_word_start, "Move to start of previous sub word",
move_next_sub_word_end, "Move to end of next sub word",
move_prev_sub_word_end, "Move to end of previous sub word",
move_parent_node_end, "Move to end of the parent node",
move_parent_node_start, "Move to beginning of the parent node",
extend_next_word_start, "Extend to start of next word",
@ -279,6 +313,10 @@ impl MappableCommand {
extend_prev_long_word_start, "Extend to start of previous long word",
extend_next_long_word_end, "Extend to end of next long word",
extend_prev_long_word_end, "Extend to end of prev long word",
extend_next_sub_word_start, "Extend to start of next sub word",
extend_prev_sub_word_start, "Extend to start of previous sub word",
extend_next_sub_word_end, "Extend to end of next sub word",
extend_prev_sub_word_end, "Extend to end of prev sub word",
extend_parent_node_end, "Extend to end of the parent node",
extend_parent_node_start, "Extend to beginning of the parent node",
find_till_char, "Move till next occurrence of char",
@ -543,6 +581,11 @@ impl fmt::Debug for MappableCommand {
.field(name)
.field(args)
.finish(),
MappableCommand::Macro { name, keys, .. } => f
.debug_tuple("MappableCommand")
.field(name)
.field(keys)
.finish(),
}
}
}
@ -573,6 +616,11 @@ impl std::str::FromStr for MappableCommand {
args,
})
.ok_or_else(|| anyhow!("No TypableCommand named '{}'", s))
} else if let Some(suffix) = s.strip_prefix('@') {
helix_view::input::parse_macro(suffix).map(|keys| Self::Macro {
name: s.to_string(),
keys,
})
} else {
MappableCommand::STATIC_COMMAND_LIST
.iter()
@ -1126,6 +1174,22 @@ fn move_next_long_word_end(cx: &mut Context) {
move_word_impl(cx, movement::move_next_long_word_end)
}
fn move_next_sub_word_start(cx: &mut Context) {
move_word_impl(cx, movement::move_next_sub_word_start)
}
fn move_prev_sub_word_start(cx: &mut Context) {
move_word_impl(cx, movement::move_prev_sub_word_start)
}
fn move_prev_sub_word_end(cx: &mut Context) {
move_word_impl(cx, movement::move_prev_sub_word_end)
}
fn move_next_sub_word_end(cx: &mut Context) {
move_word_impl(cx, movement::move_next_sub_word_end)
}
fn goto_para_impl<F>(cx: &mut Context, move_fn: F)
where
F: Fn(RopeSlice, Range, usize, Movement) -> Range + 'static,
@ -1362,6 +1426,22 @@ fn extend_next_long_word_end(cx: &mut Context) {
extend_word_impl(cx, movement::move_next_long_word_end)
}
fn extend_next_sub_word_start(cx: &mut Context) {
extend_word_impl(cx, movement::move_next_sub_word_start)
}
fn extend_prev_sub_word_start(cx: &mut Context) {
extend_word_impl(cx, movement::move_prev_sub_word_start)
}
fn extend_prev_sub_word_end(cx: &mut Context) {
extend_word_impl(cx, movement::move_prev_sub_word_end)
}
fn extend_next_sub_word_end(cx: &mut Context) {
extend_word_impl(cx, movement::move_next_sub_word_end)
}
/// Separate branch to find_char designed only for `<ret>` char.
//
// This is necessary because the one document can have different line endings inside. And we
@ -3145,6 +3225,9 @@ pub fn command_palette(cx: &mut Context) {
ui::PickerColumn::new("name", |item, _| match item {
MappableCommand::Typable { name, .. } => format!(":{name}").into(),
MappableCommand::Static { name, .. } => (*name).into(),
MappableCommand::Macro { .. } => {
unreachable!("macros aren't included in the command palette")
}
}),
ui::PickerColumn::new(
"bindings",

@ -2300,7 +2300,7 @@ fn run_shell_command(
move |editor: &mut Editor, compositor: &mut Compositor| {
if !output.is_empty() {
let contents = ui::Markdown::new(
format!("```sh\n{}\n```", output),
format!("```sh\n{}\n```", output.trim_end()),
editor.syn_loader.clone(),
);
let popup = Popup::new("shell", contents).position(Some(

@ -177,6 +177,19 @@ impl<'de> serde::de::Visitor<'de> for KeyTrieVisitor {
.map_err(serde::de::Error::custom)?,
)
}
// Prevent macro keybindings from being used in command sequences.
// This is meant to be a temporary restriction pending a larger
// refactor of how command sequences are executed.
if commands
.iter()
.any(|cmd| matches!(cmd, MappableCommand::Macro { .. }))
{
return Err(serde::de::Error::custom(
"macro keybindings may not be used in command sequences",
));
}
Ok(KeyTrie::Sequence(commands))
}
@ -199,6 +212,7 @@ impl KeyTrie {
// recursively visit all nodes in keymap
fn map_node(cmd_map: &mut ReverseKeymap, node: &KeyTrie, keys: &mut Vec<KeyEvent>) {
match node {
KeyTrie::MappableCommand(MappableCommand::Macro { .. }) => {}
KeyTrie::MappableCommand(cmd) => {
let name = cmd.name();
if name != "no_op" {

@ -58,11 +58,16 @@ impl PickerQuery {
() => {
let key = field.take().unwrap_or(primary_field);
// Trims one space from the end, enabling leading and trailing
// spaces in search patterns, while also retaining spaces as separators
// between column filters.
let pat = text.strip_suffix(' ').unwrap_or(&text);
if let Some(pattern) = fields.get_mut(key) {
pattern.push(' ');
pattern.push_str(text.trim());
pattern.push_str(pat);
} else {
fields.insert(key.clone(), text.trim().to_string());
fields.insert(key.clone(), pat.to_string());
}
text.clear();
};

@ -21,7 +21,7 @@ helix-core = { path = "../helix-core" }
bitflags = "2.6"
cassowary = "0.3"
unicode-segmentation = "1.11"
crossterm = { version = "0.27", optional = true }
crossterm = { version = "0.28", optional = true }
termini = "1.0"
serde = { version = "1", "optional" = true, features = ["derive"]}
once_cell = "1.19"

@ -8,8 +8,8 @@ use crossterm::{
},
execute, queue,
style::{
Attribute as CAttribute, Color as CColor, Print, SetAttribute, SetBackgroundColor,
SetForegroundColor,
Attribute as CAttribute, Color as CColor, Colors, Print, SetAttribute, SetBackgroundColor,
SetColors, SetForegroundColor,
},
terminal::{self, Clear, ClearType},
Command,
@ -260,14 +260,12 @@ where
diff.queue(&mut self.buffer)?;
modifier = cell.modifier;
}
if cell.fg != fg {
let color = CColor::from(cell.fg);
queue!(self.buffer, SetForegroundColor(color))?;
if cell.fg != fg || cell.bg != bg {
queue!(
self.buffer,
SetColors(Colors::new(cell.fg.into(), cell.bg.into()))
)?;
fg = cell.fg;
}
if cell.bg != bg {
let color = CColor::from(cell.bg);
queue!(self.buffer, SetBackgroundColor(color))?;
bg = cell.bg;
}

@ -29,4 +29,4 @@ log = "0.4"
git = ["gix"]
[dev-dependencies]
tempfile = "3.10"
tempfile = "3.11"

@ -5,7 +5,7 @@ use std::sync::Arc;
use helix_core::Rope;
use helix_event::RenderLockGuard;
use imara_diff::Algorithm;
use parking_lot::{Mutex, MutexGuard};
use parking_lot::{RwLock, RwLockReadGuard};
use tokio::sync::mpsc::{unbounded_channel, UnboundedSender};
use tokio::task::JoinHandle;
use tokio::time::Instant;
@ -37,7 +37,7 @@ struct DiffInner {
#[derive(Clone, Debug)]
pub struct DiffHandle {
channel: UnboundedSender<Event>,
diff: Arc<Mutex<DiffInner>>,
diff: Arc<RwLock<DiffInner>>,
inverted: bool,
}
@ -48,7 +48,7 @@ impl DiffHandle {
fn new_with_handle(diff_base: Rope, doc: Rope) -> (DiffHandle, JoinHandle<()>) {
let (sender, receiver) = unbounded_channel();
let diff: Arc<Mutex<DiffInner>> = Arc::default();
let diff: Arc<RwLock<DiffInner>> = Arc::default();
let worker = DiffWorker {
channel: receiver,
diff: diff.clone(),
@ -70,7 +70,7 @@ impl DiffHandle {
pub fn load(&self) -> Diff {
Diff {
diff: self.diff.lock(),
diff: self.diff.read(),
inverted: self.inverted,
}
}
@ -164,7 +164,7 @@ impl Hunk {
/// non-overlapping order
#[derive(Debug)]
pub struct Diff<'a> {
diff: MutexGuard<'a, DiffInner>,
diff: RwLockReadGuard<'a, DiffInner>,
inverted: bool,
}

@ -4,7 +4,7 @@ use std::sync::Arc;
use helix_core::{Rope, RopeSlice};
use imara_diff::intern::InternedInput;
use parking_lot::Mutex;
use parking_lot::RwLock;
use tokio::sync::mpsc::UnboundedReceiver;
use tokio::sync::Notify;
use tokio::time::{timeout, timeout_at, Duration};
@ -21,7 +21,7 @@ mod test;
pub(super) struct DiffWorker {
pub channel: UnboundedReceiver<Event>,
pub diff: Arc<Mutex<DiffInner>>,
pub diff: Arc<RwLock<DiffInner>>,
pub new_hunks: Vec<Hunk>,
pub diff_finished_notify: Arc<Notify>,
}
@ -73,7 +73,7 @@ impl DiffWorker {
/// `self.new_hunks` is always empty after this function runs.
/// To improve performance this function tries to reuse the allocation of the old diff previously stored in `self.line_diffs`
fn apply_hunks(&mut self, diff_base: Rope, doc: Rope) {
let mut diff = self.diff.lock();
let mut diff = self.diff.write();
diff.diff_base = diff_base;
diff.doc = doc;
swap(&mut diff.hunks, &mut self.new_hunks);

@ -12,7 +12,7 @@ impl DiffHandle {
// dropping the channel terminates the task
drop(self.channel);
handle.await.unwrap();
let diff = diff.lock();
let diff = diff.read();
Vec::clone(&diff.hunks)
}
}

@ -26,9 +26,9 @@ helix-vcs = { path = "../helix-vcs" }
bitflags = "2.6"
anyhow = "1"
crossterm = { version = "0.27", optional = true }
crossterm = { version = "0.28", optional = true }
tempfile = "3.9"
tempfile = "3.11"
# Conversion traits
once_cell = "1.19"

@ -44,6 +44,7 @@ haskell-language-server = { command = "haskell-language-server-wrapper", args =
idris2-lsp = { command = "idris2-lsp" }
intelephense = { command = "intelephense", args = ["--stdio"] }
jdtls = { command = "jdtls" }
jq-lsp = { command = "jq-lsp" }
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()", ] }
koka = { command = "koka", args = ["--language-server", "--lsstdio"] }
@ -54,11 +55,13 @@ markdoc-ls = { command = "markdoc-ls", args = ["--stdio"] }
markdown-oxide = { command = "markdown-oxide" }
marksman = { command = "marksman", args = ["server"] }
metals = { command = "metals", config = { "isHttpEnabled" = true, metals = { inlayHints = { typeParameters = {enable = true} , hintsInPatternMatch = {enable = true} } } } }
mesonlsp = { command = "mesonlsp", args = ["--lsp"] }
mint = { command = "mint", args = ["ls"] }
mojo-lsp = { command = "mojo-lsp-server" }
nil = { command = "nil" }
nimlangserver = { command = "nimlangserver" }
nimlsp = { command = "nimlsp" }
nixd = { command = "nixd" }
nls = { command = "nls" }
nu-lsp = { command = "nu", args = [ "--lsp" ] }
ocamllsp = { command = "ocamllsp" }
@ -93,6 +96,7 @@ taplo = { command = "taplo", args = ["lsp", "stdio"] }
templ = { command = "templ", args = ["lsp"] }
terraform-ls = { command = "terraform-ls", args = ["serve"] }
texlab = { command = "texlab" }
typespec = { command = "tsp-server", args = ["--stdio"] }
vala-language-server = { command = "vala-language-server" }
vhdl_ls = { command = "vhdl_ls", args = [] }
vlang-language-server = { command = "v-analyzer" }
@ -766,6 +770,23 @@ indent = { tab-width = 2, unit = " " }
name = "typescript"
source = { git = "https://github.com/tree-sitter/tree-sitter-typescript", rev = "b1bf4825d9eaa0f3bdeb1e52f099533328acfbdf", subpath = "typescript" }
[[language]]
name = "typespec"
scope = "source.typespec"
injection-regex = "(tsp|typespec)"
language-id = "typespec"
file-types = ["tsp"]
roots = ["tspconfig.yaml"]
auto-format = true
comment-token = "//"
block-comment-tokens = { start = "/*", end = "*/" }
language-servers = ["typespec"]
indent = { tab-width = 2, unit = " " }
[[grammar]]
name = "typespec"
source = { git = "https://github.com/happenslol/tree-sitter-typespec", rev = "0ee05546d73d8eb64635ed8125de6f35c77759fe" }
[[language]]
name = "tsx"
scope = "source.tsx"
@ -866,7 +887,7 @@ injection-regex = "nix"
file-types = ["nix"]
shebangs = []
comment-token = "#"
language-servers = [ "nil" ]
language-servers = [ "nil", "nixd" ]
indent = { tab-width = 2, unit = " " }
[[grammar]]
@ -948,6 +969,8 @@ file-types = [
"tcshrc",
"bashrc_Apple_Terminal",
"zshrc_Apple_Terminal",
{ glob = "i3/config" },
{ glob = "sway/config" },
{ glob = "tmux.conf" },
{ glob = ".bash_history" },
{ glob = ".bash_login" },
@ -1855,7 +1878,7 @@ auto-format = true
[[grammar]]
name = "gleam"
source = { git = "https://github.com/gleam-lang/tree-sitter-gleam", rev = "bcf9c45b56cbe46e9dac5eee0aee75df270000ac" }
source = { git = "https://github.com/gleam-lang/tree-sitter-gleam", rev = "426e67087fd62be5f4533581b5916b2cf010fb5b" }
[[language]]
name = "ron"
@ -2143,6 +2166,7 @@ injection-regex = "meson"
file-types = [{ glob = "meson.build" }, { glob = "meson.options" }, { glob = "meson_options.txt" }]
comment-token = "#"
indent = { tab-width = 2, unit = " " }
language-servers = ["mesonlsp"]
[[grammar]]
name = "meson"
@ -3082,7 +3106,7 @@ indent = { tab-width = 4, unit = " " }
[[grammar]]
name = "just"
source = { git = "https://github.com/IndianBoy42/tree-sitter-just", rev = "379fbe36d1e441bc9414ea050ad0c85c9d6935ea" }
source = { git = "https://github.com/poliorcetics/tree-sitter-just", rev = "f58a8fd869035ac4653081401e6c2030251240ab" }
[[language]]
name = "gn"
@ -3139,7 +3163,7 @@ language-servers = ["fsharp-ls"]
[[grammar]]
name = "fsharp"
source = { git = "https://github.com/kaashyapan/tree-sitter-fsharp", rev = "18da392fd9bd5e79f357abcce13f61f3a15e3951" }
source = { git = "https://github.com/ionide/tree-sitter-fsharp", rev = "996ea9982bd4e490029f84682016b6793940113b" }
[[language]]
name = "t32"
@ -3216,6 +3240,19 @@ text-width = 72
name = "jjdescription"
source = { git = "https://github.com/kareigu/tree-sitter-jjdescription", rev = "2ddec6cad07b366aee276a608e1daa2c29d3caf2" }
[[language]]
name = "jq"
scope = "source.jq"
injection-regex = "jq"
file-types = ["jq"]
comment-token = "#"
language-servers = ["jq-lsp"]
indent = { tab-width = 2, unit = " " }
[[grammar]]
name = "jq"
source = { git = "https://github.com/flurie/tree-sitter-jq", rev = "13990f530e8e6709b7978503da9bc8701d366791" }
[[grammar]]
name = "wren"
source = { git = "https://git.sr.ht/~jummit/tree-sitter-wren", rev = "6748694be32f11e7ec6b5faeb1b48ca6156d4e06" }
@ -3726,3 +3763,26 @@ grammar = "typescript"
"{" = "}"
"(" = ")"
'"' = '"'
[[language]]
name = "gherkin"
scope = "source.feature"
file-types = ["feature"]
comment-token = "#"
indent = { tab-width = 2, unit = " " }
[[grammar]]
name = "gherkin"
source = { git = "https://github.com/SamyAB/tree-sitter-gherkin", rev = "43873ee8de16476635b48d52c46f5b6407cb5c09" }
[[language]]
name = "thrift"
scope = "source.thrift"
file-types = ["thrift"]
comment-token = "//"
block-comment-tokens = { start = "/*", end = "*/" }
indent = { tab-width = 2, unit = " " }
[[grammar]]
name = "thrift"
source = { git = "https://github.com/tree-sitter-grammars/tree-sitter-thrift" , rev = "68fd0d80943a828d9e6f49c58a74be1e9ca142cf" }

@ -1,16 +1,176 @@
;; ----------------------------------------------------------------------------
;; Literals and comments
[
(line_comment)
(block_comment)
(block_comment_content)
] @comment
(line_comment) @comment.line
(block_comment) @comment.block
(xml_doc) @comment.block.documentation
(const
[
(_) @constant
(unit) @constant.builtin
])
(primary_constr_args (_) @variable.parameter)
((identifier_pattern (long_identifier (identifier) @special))
(#match? @special "^\_.*"))
((long_identifier
(identifier)+
.
(identifier) @variable.other.member))
;; ----------------------------------------------------------------------------
;; Punctuation
(wildcard_pattern) @string.special
(type_name type_name: (_) @type)
[
(type)
(atomic_type)
] @type
(member_signature
.
(identifier) @function.method
(curried_spec
(arguments_spec
"*"* @operator
(argument_spec
(argument_name_spec
"?"? @special
name: (_) @variable.parameter)))))
(union_type_case) @constant
(rules
(rule
pattern: (_) @constant
block: (_)))
(identifier_pattern
.
(_) @constant
.
(_) @variable)
(fsi_directive_decl . (string) @namespace)
(import_decl . (_) @namespace)
(named_module
name: (_) @namespace)
(namespace
name: (_) @namespace)
(module_defn
.
(_) @namespace)
(ce_expression
.
(_) @function.macro)
(field_initializer
field: (_) @variable.other.member)
(record_fields
(record_field
.
(identifier) @variable.other.member))
(dot_expression
base: (_) @namespace
field: (_) @variable.other.member)
(value_declaration_left . (_) @variable)
(function_declaration_left
. (_) @function
[
(argument_patterns)
(argument_patterns (long_identifier (identifier)))
] @variable.parameter)
(member_defn
(method_or_prop_defn
[
(property_or_ident) @function
(property_or_ident
instance: (identifier) @variable.builtin
method: (identifier) @function.method)
]
args: (_)* @variable.parameter))
(application_expression
.
[
(long_identifier_or_op [
(long_identifier (identifier)* (identifier) @function)
(identifier) @function
])
(typed_expression . (long_identifier_or_op (long_identifier (identifier)* . (identifier) @function.call)))
(dot_expression base: (_) @variable.other.member field: (_) @function)
] @function)
((infix_expression
.
(_)
.
(infix_op) @operator
.
(_) @function
)
(#eq? @operator "|>")
)
((infix_expression
.
(_) @function
.
(infix_op) @operator
.
(_)
)
(#eq? @operator "<|")
)
[
(xint)
(int)
(int16)
(uint16)
(int32)
(uint32)
(int64)
(uint64)
(nativeint)
(unativeint)
] @constant.numeric.integer
[
(ieee32)
(ieee64)
(float)
(decimal)
] @constant.numeric.float
(bool) @constant.builtin.boolean
([
(string)
(triple_quoted_string)
(verbatim_string)
(char)
] @string)
(compiler_directive_decl) @keyword.directive
(attribute) @attribute
[
"("
")"
@ -20,31 +180,40 @@
"]"
"[|"
"|]"
"{|"
"|}"
"[<"
">]"
] @punctuation.bracket
(format_string_eval
[
"{"
"}"
] @punctuation.special)
[
","
","
";"
] @punctuation.delimiter
[
"|"
"|"
"="
">"
"<"
"-"
"~"
"->"
"<-"
"&&"
"||"
":>"
":?>"
(infix_op)
(prefix_op)
(symbolic_op)
] @operator
(attribute) @attribute
[
"if"
"then"
@ -53,22 +222,29 @@
"when"
"match"
"match!"
] @keyword.control.conditional
[
"and"
"or"
"&&"
"||"
"then"
] @keyword.control.conditional
"not"
"upcast"
"downcast"
] @keyword.operator
[
"return"
"return!"
"yield"
"yield!"
] @keyword.control.return
[
"for"
"while"
] @keyword.control.return
"downto"
"to"
] @keyword.control.repeat
[
@ -82,115 +258,93 @@
"delegate"
"static"
"inline"
"internal"
"mutable"
"override"
"private"
"public"
"rec"
"global"
(access_modifier)
] @keyword.storage.modifier
[
"enum"
"let"
"let!"
"use"
"use!"
"member"
"module"
"namespace"
] @keyword.function
[
"enum"
"type"
] @keyword.storage
"inherit"
"interface"
] @keyword.storage.type
(try_expression
[
"try"
"with"
"finally"
] @keyword.control.exception)
((identifier) @keyword.control.exception
(#any-of? @keyword.control.exception "failwith" "failwithf" "raise" "reraise"))
[
"as"
"assert"
"begin"
"end"
"done"
"default"
"in"
"do"
"do!"
"done"
"downcast"
"downto"
"end"
"event"
"field"
"finally"
"fun"
"function"
"get"
"global"
"inherit"
"interface"
"set"
"lazy"
"new"
"not"
"null"
"of"
"param"
"property"
"set"
"struct"
"try"
"upcast"
"use"
"use!"
"val"
"module"
"namespace"
"with"
"yield"
"yield!"
] @keyword
[
"true"
"false"
"unit"
] @constant.builtin
[
(type)
(const)
] @constant
[
(union_type_case)
(rules (rule (identifier_pattern)))
] @type.enum
(fsi_directive_decl (string) @namespace)
[
(import_decl (long_identifier))
(named_module (long_identifier))
(namespace (long_identifier))
(named_module
name: (long_identifier) )
(namespace
name: (long_identifier) )
] @namespace
"null"
] @constant.builtin
(match_expression "with" @keyword.control.conditional)
(dot_expression
base: (long_identifier_or_op) @variable.other.member
field: (long_identifier_or_op) @function)
((type
(long_identifier (identifier) @type.builtin))
(#any-of? @type.builtin "bool" "byte" "sbyte" "int16" "uint16" "int" "uint" "int64" "uint64" "nativeint" "unativeint" "decimal" "float" "double" "float32" "single" "char" "string" "unit"))
[
;;(value_declaration_left (identifier_pattern) )
(function_declaration_left (identifier) )
(call_expression (long_identifier_or_op (long_identifier)))
;;(application_expression (long_identifier_or_op (long_identifier)))
] @function
(preproc_if
[
"#if" @keyword.directive
"#endif" @keyword.directive
]
condition: (_)? @keyword.directive)
[
(string)
(triple_quoted_string)
] @string
(preproc_else
"#else" @keyword.directive)
[
(int)
(int16)
(int32)
(int64)
(float)
(decimal)
] @constant.numeric
((long_identifier
(identifier)+ @namespace
.
(identifier)))
(long_identifier_or_op
(op_identifier) @operator)
((identifier) @namespace
(#any-of? @namespace "Array" "Async" "Directory" "File" "List" "Option" "Path" "Map" "Set" "Lazy" "Seq" "Task" "String" "Result" ))

@ -0,0 +1,8 @@
([
(line_comment)
(block_comment_content)
] @injection.content
(#set! injection.language "comment"))
((xml_doc (xml_doc_content) @injection.content)
(#set! injection.language "xml"))

@ -1,25 +1,32 @@
; Scopes
;-------
(identifier) @local.reference
[
(ce_expression)
(module_defn)
(for_expression)
(do_expression)
(fun_expression)
(function_expression)
(try_expression)
(match_expression)
(elif_expression)
(if_expression)
(namespace)
(named_module)
(function_or_value_defn)
] @local.scope
; Definitions
;------------
(function_or_value_defn) @local.definition
(value_declaration_left
.
[
(_ (identifier) @local.definition)
(_ (_ (identifier) @local.definition))
(_ (_ (_ (identifier) @local.definition)))
(_ (_ (_ (_ (identifier) @local.definition))))
(_ (_ (_ (_ (_ (identifier) @local.definition)))))
(_ (_ (_ (_ (_ (_ (identifier) @local.definition))))))
])
; References
;-----------
(identifier) @local.reference
(function_declaration_left
.
((_) @local.definition)
((argument_patterns
[
(_ (identifier) @local.definition)
(_ (_ (identifier) @local.definition))
(_ (_ (_ (identifier) @local.definition)))
(_ (_ (_ (_ (identifier) @local.definition))))
(_ (_ (_ (_ (_ (identifier) @local.definition)))))
(_ (_ (_ (_ (_ (_ (identifier) @local.definition))))))
])
))

@ -0,0 +1,17 @@
[
(feature_keyword)
(rule_keyword)
(background_keyword)
(scenario_keyword)
(given_keyword)
(when_keyword)
(then_keyword)
(and_keyword)
(but_keyword)
(asterisk_keyword)
] @keyword
(tag) @function
(doc_string) @string
(data_table) @special
(comment) @comment

@ -1,13 +1,39 @@
(tag_name) @tag
(erroneous_end_tag_name) @tag.error
(erroneous_end_tag_name) @error
(doctype) @constant
(attribute_name) @attribute
(comment) @comment
[
"\""
(attribute_value)
] @string
((attribute
(attribute_name) @_attr
(quoted_attribute_value (attribute_value) @markup.link.url))
(#any-of? @_attr "href" "src"))
((element
(start_tag
(tag_name) @_tag)
(text) @markup.link.label)
(#eq? @_tag "a"))
(attribute [(attribute_value) (quoted_attribute_value)] @string)
((element
(start_tag
(tag_name) @_tag)
(text) @markup.bold)
(#any-of? @_tag "strong" "b"))
((element
(start_tag
(tag_name) @_tag)
(text) @markup.italic)
(#any-of? @_tag "em" "i"))
((element
(start_tag
(tag_name) @_tag)
(text) @markup.strikethrough)
(#any-of? @_tag "s" "del"))
[
"<"

@ -0,0 +1,160 @@
;; From nvim-treesitter, contributed by @ObserverOfTime et al.
; Variables
(variable) @variable
((variable) @constant.builtin
(#eq? @constant.builtin "$ENV"))
((variable) @constant.builtin
(#eq? @constant.builtin "$__loc__"))
; Properties
(index
(identifier) @variable.other.member)
; Labels
(query
label: (variable) @label)
(query
break_statement: (variable) @label)
; Literals
(number) @constant.numeric
(string) @string
[
"true"
"false"
] @constant.builtin.boolean
"null" @type.builtin
; Interpolation
[
"\\("
")"
] @special
; Format
(format) @attribute
; Functions
(funcdef
(identifier) @function)
(funcdefargs
(identifier) @variable.parameter)
[
"reduce"
"foreach"
] @function.builtin
((funcname) @function
.
"(")
; jq -n 'builtins | map(split("/")[0]) | unique | .[]'
((funcname) @function.builtin
(#any-of? @function.builtin
"IN" "INDEX" "JOIN" "abs" "acos" "acosh" "add" "all" "any" "arrays" "ascii_downcase"
"ascii_upcase" "asin" "asinh" "atan" "atan2" "atanh" "booleans" "bsearch" "builtins" "capture"
"cbrt" "ceil" "combinations" "contains" "copysign" "cos" "cosh" "debug" "del" "delpaths" "drem"
"empty" "endswith" "env" "erf" "erfc" "error" "exp" "exp10" "exp2" "explode" "expm1" "fabs"
"fdim" "finites" "first" "flatten" "floor" "fma" "fmax" "fmin" "fmod" "format" "frexp"
"from_entries" "fromdate" "fromdateiso8601" "fromjson" "fromstream" "gamma" "get_jq_origin"
"get_prog_origin" "get_search_list" "getpath" "gmtime" "group_by" "gsub" "halt" "halt_error"
"has" "hypot" "implode" "in" "index" "indices" "infinite" "input" "input_filename"
"input_line_number" "inputs" "inside" "isempty" "isfinite" "isinfinite" "isnan" "isnormal"
"iterables" "j0" "j1" "jn" "join" "keys" "keys_unsorted" "last" "ldexp" "length" "lgamma"
"lgamma_r" "limit" "localtime" "log" "log10" "log1p" "log2" "logb" "ltrimstr" "map" "map_values"
"match" "max" "max_by" "min" "min_by" "mktime" "modf" "modulemeta" "nan" "nearbyint" "nextafter"
"nexttoward" "normals" "not" "now" "nth" "nulls" "numbers" "objects" "path" "paths" "pick" "pow"
"pow10" "range" "recurse" "remainder" "repeat" "reverse" "rindex" "rint" "round" "rtrimstr"
"scalars" "scalb" "scalbln" "scan" "select" "setpath" "significand" "sin" "sinh" "sort"
"sort_by" "split" "splits" "sqrt" "startswith" "stderr" "strflocaltime" "strftime" "strings"
"strptime" "sub" "tan" "tanh" "test" "tgamma" "to_entries" "todate" "todateiso8601" "tojson"
"tonumber" "tostream" "tostring" "transpose" "trunc" "truncate_stream" "type" "unique"
"unique_by" "until" "utf8bytelength" "values" "walk" "while" "with_entries" "y0" "y1" "yn"))
; Keywords
[
"def"
"as"
"label"
"module"
"break"
] @keyword
[
"import"
"include"
] @keyword.control.import
[
"if"
"then"
"elif"
"else"
"end"
] @keyword.control.conditional
[
"try"
"catch"
] @keyword.control.exception
[
"or"
"and"
] @keyword.operator
; Operators
[
"."
"=="
"!="
">"
">="
"<="
"<"
"="
"+"
"-"
"*"
"/"
"%"
"+="
"-="
"*="
"/="
"%="
"//="
"|"
"?"
"//"
"?//"
(recurse) ; ".."
] @operator
; Punctuation
[
";"
","
":"
] @punctuation.delimiter
[
"["
"]"
"{"
"}"
"("
")"
] @punctuation.bracket
; Comments
(comment) @comment.line

@ -0,0 +1,25 @@
;; From nvim-treesitter, contributed by @ObserverOfTime et al.
((comment) @injection.content
(#set! injection.language "comment"))
; test(val)
(query
((funcname) @_function
(#any-of? @_function "test" "match" "capture" "scan" "split" "splits" "sub" "gsub"))
(args
.
(query
(string) @injection.content
(#set! injection.language "regex"))))
; test(regex; flags)
(query
((funcname) @_function
(#any-of? @_function "test" "match" "capture" "scan" "split" "splits" "sub" "gsub"))
(args
.
(args
(query
(string) @injection.content
(#set! injection.language "regex")))))

@ -0,0 +1,12 @@
;; From nvim-treesitter, contributed by @ObserverOfTime et al.
(funcdef
(identifier) @local.definition)
(funcdefargs
(identifier) @local.definition)
(funcname) @local.reference
(index
(identifier) @local.reference)

@ -0,0 +1,8 @@
(comment) @comment.inside
(comment)+ @comment.around
(funcdef
(query) @function.inside) @function.around
(objectkeyval
(_) @entry.inside) @entry.around

@ -1,5 +1,3 @@
; From <https://github.com/IndianBoy42/tree-sitter-just/blob/6c2f018ab1d90946c0ce029bb2f7d57f56895dff/queries-flavored/helix/folds.scm>
; Define collapse points
([

@ -1,5 +1,3 @@
; From <https://github.com/IndianBoy42/tree-sitter-just/blob/6c2f018ab1d90946c0ce029bb2f7d57f56895dff/queries-flavored/helix/highlights.scm>
; This file specifies how matched syntax patterns should be highlighted
[
@ -26,35 +24,57 @@
(identifier) @variable)
(alias
left: (identifier) @variable)
name: (identifier) @variable)
(assignment
left: (identifier) @variable)
name: (identifier) @variable)
; Functions
(shell_variable_name) @variable
(recipe_header
name: (identifier) @function)
; Functions
(dependency
(recipe
name: (identifier) @function)
(dependency_expression
name: (identifier) @function)
(recipe_dependency
name: (identifier) @function.call)
(function_call
name: (identifier) @function)
name: (identifier) @function.builtin)
; Parameters
(parameter
(recipe_parameter
name: (identifier) @variable.parameter)
; Namespaces
(module
(mod
name: (identifier) @namespace)
; Paths
(mod
(path) @string.special.path)
(import
(path) @string.special.path)
; Shebangs
(shebang_line) @keyword.directive
(shebang_line
(shebang_shell) @string.special)
(shell_expanded_string
[
(expansion_short_start)
(expansion_long_start)
(expansion_long_middle)
(expansion_long_end)
] @punctuation.special)
; Operators
[
@ -95,55 +115,31 @@
; Literals
(boolean) @constant.builtin.boolean
; Booleans are not allowed anywhere except in settings
(setting
(boolean) @constant.builtin.boolean)
[
(string)
(external_command)
] @string
(escape_sequence) @constant.character.escape
[
(escape_sequence)
(escape_variable_end)
] @constant.character.escape
; Comments
(comment) @comment.line
(shebang) @keyword.directive
; highlight known settings (filtering does not always work)
; highlight known settings
(setting
left: (identifier) @keyword
(#any-of? @keyword
"allow-duplicate-recipes"
"dotenv-filename"
"dotenv-load"
"dotenv-path"
"export"
"fallback"
"ignore-comments"
"positional-arguments"
"shell"
"tempdi"
"windows-powershell"
"windows-shell"))
; highlight known attributes (filtering does not always work)
name: (_) @keyword.function)
; highlight known attributes
(attribute
(identifier) @attribute
(#any-of? @attribute
"private"
"allow-duplicate-recipes"
"dotenv-filename"
"dotenv-load"
"dotenv-path"
"export"
"fallback"
"ignore-comments"
"positional-arguments"
"shell"
"tempdi"
"windows-powershell"
"windows-shell"))
name: (identifier) @attribute)
; Numbers are part of the syntax tree, even if disallowed
(numeric_error) @error

@ -1,5 +1,3 @@
; From <https://github.com/IndianBoy42/tree-sitter-just/blob/6c2f018ab1d90946c0ce029bb2f7d57f56895dff/queries-flavored/helix/indents.scm>
;
; This query specifies how to auto-indent logical blocks.
;
; Better documentation with diagrams is in https://docs.helix-editor.com/guides/indent.html

@ -1,5 +1,3 @@
; From <https://github.com/IndianBoy42/tree-sitter-just/blob/6c2f018ab1d90946c0ce029bb2f7d57f56895dff/queries-flavored/helix/injections.scm>
;
; Specify nested languages that live within a `justfile`
; ================ Always applicable ================
@ -8,7 +6,7 @@
(#set! injection.language "comment"))
; Highlight the RHS of `=~` as regex
((regex_literal
((regex
(_) @injection.content)
(#set! injection.language "regex"))
@ -21,7 +19,7 @@
(#set! injection.include-children)) @injection.content
(external_command
(command_body) @injection.content
(content) @injection.content
(#set! injection.language "bash"))
; ================ Global language specified ================
@ -43,7 +41,7 @@
; they default to bash. Limitations...
; See https://github.com/tree-sitter/tree-sitter/issues/880 for more on that.
(source_file
(file
(setting "shell" ":=" "[" (string) @_langstr
(#match? @_langstr ".*(powershell|pwsh|cmd).*")
(#set! injection.language "powershell"))
@ -57,10 +55,10 @@
(expression
(value
(external_command
(command_body) @injection.content))))
(content) @injection.content))))
])
(source_file
(file
(setting "shell" ":=" "[" (string) @injection.language
(#not-match? @injection.language ".*(powershell|pwsh|cmd).*"))
[
@ -73,12 +71,12 @@
(expression
(value
(external_command
(command_body) @injection.content))))
(content) @injection.content))))
])
; ================ Recipe language specified - Helix only ================
; Set highlighting for recipes that specify a language using builtin shebang matching
(recipe_body
(shebang) @injection.shebang
(shebang_line) @injection.shebang
(#set! injection.include-children)) @injection.content

@ -1,5 +1,3 @@
; From <https://github.com/IndianBoy42/tree-sitter-just/blob/6c2f018ab1d90946c0ce029bb2f7d57f56895dff/queries-flavored/helix/locals.scm>
;
; This file tells us about the scope of variables so e.g. local
; variables override global functions with the same name
@ -10,32 +8,29 @@
; Definitions
(alias
left: (identifier) @local.definition)
name: (identifier) @local.definition)
(assignment
left: (identifier) @local.definition)
name: (identifier) @local.definition)
(module
(mod
name: (identifier) @local.definition)
(parameter
(recipe_parameter
name: (identifier) @local.definition)
(recipe_header
(recipe
name: (identifier) @local.definition)
; References
(alias
right: (identifier) @local.reference)
(function_call
name: (identifier) @local.reference)
(dependency
(function_call
name: (identifier) @local.reference)
(dependency_expression
(recipe_dependency
name: (identifier) @local.reference)
(value

@ -1,18 +1,19 @@
; From <https://github.com/IndianBoy42/tree-sitter-just/blob/6c2f018ab1d90946c0ce029bb2f7d57f56895dff/queries-flavored/helix/textobjects.scm>
;
; Specify how to navigate around logical blocks in code
(assert_parameters
((_) @parameter.inside . ","? @parameter.around)) @parameter.around
(recipe
(recipe_body) @function.inside) @function.around
(parameters
(recipe_parameters
((_) @parameter.inside . ","? @parameter.around)) @parameter.around
(dependency_expression
(recipe_dependency
(_) @parameter.inside) @parameter.around
(function_call
arguments: (sequence
(expression) @parameter.inside) @parameter.around) @function.around
(function_parameters
((_) @parameter.inside . ","? @parameter.around)) @parameter.around) @function.around
(comment) @comment.around

@ -0,0 +1,12 @@
[
(annotation_definition)
(enum_definition)
(exception_definition)
(function_definition)
(senum_definition)
(service_definition)
(struct_definition)
(union_definition)
(comment)
] @fold

@ -0,0 +1,211 @@
; Variables
((identifier) @variable)
; Includes
[
"include"
"cpp_include"
] @keyword
; Function
(function_definition
(identifier) @function)
; Fields
(field (identifier) @variable.other.member)
; Parameters
(function_definition
(parameters
(parameter (identifier) @variable.parameter)))
(throws
(parameters
(parameter (identifier) @keyword.control.exception)))
; Types
(typedef_identifier) @type
(struct_definition
"struct" (identifier) @type)
(union_definition
"union" (identifier) @type)
(exception_definition
"exception" (identifier) @type)
(service_definition
"service" (identifier) @type)
(interaction_definition
"interaction" (identifier) @type)
(type
type: (identifier) @type)
(definition_type
type: (identifier) @type)
; Constants
(const_definition (identifier) @constant)
(enum_definition "enum"
. (identifier) @type
"{" (identifier) @constant "}")
; Builtin Types
(primitive) @type.builtin
[
"list"
"map"
"set"
"sink"
"stream"
"void"
] @type.builtin
; Namespace
(namespace_declaration
(namespace_scope) @tag
[(namespace) @namespace (_ (identifier) @namespace)])
; Attributes
(annotation_definition
(annotation_identifier (identifier) @attribute))
(fb_annotation_definition
"@" @attribute (annotation_identifier (identifier) @attribute)
(identifier)? @attribute)
(namespace_uri (string) @attribute)
; Operators
[
"="
"&"
] @operator
; Exceptions
[
"throws"
] @keyword.control.exception
; Keywords
[
"enum"
"exception"
"extends"
"interaction"
"namespace"
"senum"
"service"
"struct"
"typedef"
"union"
"uri"
] @keyword
; Deprecated Keywords
[
"cocoa_prefix"
"cpp_namespace"
"csharp_namespace"
"delphi_namespace"
"java_package"
"perl_package"
"php_namespace"
"py_module"
"ruby_namespace"
"smalltalk_category"
"smalltalk_prefix"
"xsd_all"
"xsd_attrs"
"xsd_namespace"
"xsd_nillable"
"xsd_optional"
] @keyword
; Extended Kewords
[
"package"
"performs"
] @keyword
[
"async"
"oneway"
] @keyword
; Qualifiers
[
"client"
"const"
"idempotent"
"optional"
"permanent"
"readonly"
"required"
"safe"
"server"
"stateful"
"transient"
] @type.directive
; Literals
(string) @string
(escape_sequence) @constant.character.escape
(namespace_uri
(string) @string.special)
(number) @constant.numeric.integer
(double) @constant.numeric.float
(boolean) @constant.builtin.boolean
; Typedefs
(typedef_identifier) @type.definition
; Punctuation
[
"*"
] @punctuation.special
["{" "}"] @punctuation.bracket
["(" ")"] @punctuation.bracket
["[" "]"] @punctuation.bracket
["<" ">"] @punctuation.bracket
[
"."
","
";"
":"
] @punctuation.delimiter
; Comments
(comment) @comment

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

@ -0,0 +1,51 @@
; Scopes
[
(document)
(definition)
] @local.scope
; References
(identifier) @local.reference
; Definitions
(annotation_identifier) @local.definition
; (const_definition (identifier) @definition.constant)
; (enum_definition "enum"
; . (identifier) @definition.enum
; "{" (identifier) @definition.constant "}")
; (senum_definition "senum"
; . (identifier) @definition.enum)
; (field (identifier) @definition.field)
; (function_definition (identifier) @definition.function)
; (namespace_declaration
; "namespace" (namespace_scope)
; . (_) @definition.namespace
; (namespace_uri)?)
; (parameter (identifier) @definition.parameter)
; (struct_definition
; "struct" . (identifier) @definition.type)
; (union_definition
; "union" . (identifier) @definition.type)
; (exception_definition
; "exception" . (identifier) @definition.type)
; (service_definition
; "service" . (identifier) @definition.type)
; (interaction_definition
; "interaction" . (identifier) @definition.type)
; (typedef_identifier) @definition.type

@ -0,0 +1,177 @@
; Keywords
[
"is"
"extends"
"valueof"
] @keyword.operator
[
"namespace"
"scalar"
"interface"
"alias"
] @keyword
[
"model"
"enum"
"union"
] @keyword.storage.type
[
"op"
"fn"
"dec"
] @keyword.function
"extern" @keyword.storage.modifier
[
"import"
"using"
] @keyword.control.import
[
"("
")"
"{"
"}"
"<"
">"
"["
"]"
] @punctuation.bracket
[
","
";"
"."
":"
] @punctuation.delimiter
[
"|"
"&"
"="
"..."
] @operator
"?" @punctuation.special
; Imports
(import_statement
(quoted_string_literal) @string.special.path)
; Namespaces
(using_statement
module: (identifier_or_member_expression) @namespace)
(namespace_statement
name: (identifier_or_member_expression) @namespace)
; Comments
[
(single_line_comment)
] @comment.line
[
(multi_line_comment)
] @comment.block
; Decorators
(decorator
"@" @attribute
name: (identifier_or_member_expression) @attribute)
(augment_decorator_statement
name: (identifier_or_member_expression) @attribute)
(decorator
(decorator_arguments) @variable.parameter)
; Scalars
(scalar_statement
name: (identifier) @type)
; Models
(model_statement
name: (identifier) @type)
(model_property
name: (identifier) @variable.other.member)
; Operations
(operation_statement
name: (identifier) @function.method)
(operation_arguments
(model_property
name: (identifier) @variable.parameter))
(template_parameter
name: (identifier) @type.parameter)
(function_parameter
name: (identifier) @variable.parameter)
; Interfaces
(interface_statement
name: (identifier) @type)
(interface_statement
(interface_body
(interface_member
(identifier) @function.method)))
; Enums
(enum_statement
name: (identifier) @type.enum)
(enum_member
name: (identifier) @constant)
; Unions
(union_statement
name: (identifier) @type)
(union_variant
name: (identifier) @type.enum.variant)
; Aliases
(alias_statement
name: (identifier) @type)
; Built-in types
[
(quoted_string_literal)
(triple_quoted_string_literal)
] @string
(escape_sequence) @constant.character.escape
(boolean_literal) @constant.builtin.boolean
[
(decimal_literal)
(hex_integer_literal)
(binary_integer_literal)
] @constant.numeric.integer
(builtin_type) @type.builtin
; Identifiers
(identifier_or_member_expression) @type

@ -0,0 +1,18 @@
[
(model_expression)
(tuple_expression)
(namespace_body)
(interface_body)
(union_body)
(enum_body)
(template_arguments)
(template_parameters)
(operation_arguments)
] @indent.begin
[
"}"
")"
">"
"]"
] @indent.end

@ -0,0 +1,5 @@
([
(single_line_comment)
(multi_line_comment)
] @injection.content
(#set! injection.language "comment"))

@ -0,0 +1,51 @@
; Classes
(enum_statement
(enum_body) @class.inside) @class.around
(model_statement
(model_expression) @class.inside) @class.around
(union_statement
(union_body) @class.inside) @class.around
; Interfaces
(interface_statement
(interface_body
(interface_member) @function.around) @class.inside) @class.around
; Comments
[
(single_line_comment)
(multi_line_comment)
] @comment.inside
[
(single_line_comment)
(multi_line_comment)
]+ @comment.around
; Functions
[
(decorator)
(decorator_declaration_statement)
(function_declaration_statement)
(operation_statement)
] @function.around
(function_parameter_list
(function_parameter)? @parameter.inside)* @function.inside
(decorator_arguments
(expression_list
(_) @parameter.inside)*) @function.inside
(operation_arguments
(model_property)? @parameter.inside)* @function.inside
(template_parameters
(template_parameter_list
(template_parameter) @parameter.inside)) @function.inside

@ -3,4 +3,8 @@
(function_body_declaration
(function_identifier
(function_identifier
(simple_identifier) @function.inside)))) @function.around
(simple_identifier) @function.inside)))) @function.around
(comment) @comment.inside
(comment)+ @comment.around

@ -1,7 +1,7 @@
# Author: David Else <12832280+David-Else@users.noreply.github.com>
# SYNTAX
"attribute" = "fn_declaration"
"attribute" = "variable"
"comment" = "dark_green"
"constant" = "constant"
"constant.builtin" = "blue2"
@ -39,10 +39,10 @@
# MARKUP
"markup.heading" = { fg = "blue2", modifiers = ["bold"] }
"markup.list" = "blue3"
"markup.bold" = { fg = "blue2", modifiers = ["bold"] }
"markup.bold" = { modifiers = ["bold"] }
"markup.italic" = { modifiers = ["italic"] }
"markup.strikethrough" = { modifiers = ["crossed_out"] }
"markup.link.url" = { modifiers = ["underlined"] }
"markup.link.url" = { underline.style= "line" }
"markup.link.text" = "orange"
"markup.quote" = "dark_green"
"markup.raw" = "orange"
@ -57,7 +57,7 @@
# TODO: Alternate bg colour for `ui.cursor.match` and `ui.selection`.
"ui.cursor" = { fg = "cursor", modifiers = ["reversed"] }
"ui.cursor.primary" = { fg = "cursor", modifiers = ["reversed"] }
"ui.cursor.match" = { bg = "#3a3d41", modifiers = ["underlined"] }
"ui.cursor.match" = { bg = "#3a3d41", underline.style = "line" }
"ui.selection" = { bg = "#3a3d41" }
"ui.selection.primary" = { bg = "dark_blue" }
"ui.linenr" = { fg = "dark_gray" }
@ -80,6 +80,8 @@
"ui.highlight.frameline" = { bg = "#4b4b18" }
"ui.debug.active" = { fg = "#ffcc00" }
"ui.debug.breakpoint" = { fg = "#e51400" }
"ui.picker.header.column" = { underline.style = "line" }
"ui.picker.header.column.active" = { fg ="white", underline.style = "line" }
"warning" = { fg = "gold2" }
"error" = { fg = "red" }
"info" = { fg = "light_blue" }

@ -0,0 +1,128 @@
# Author : Chromo-residuum-opec <development.0extl@simplelogin.com>
"attribute" = { fg = "green" }
"boolean" = { fg = "purple" }
"character" = { fg = "purple" }
"comment" = { fg = "comment_fg" }
"conditional" = { fg = "blue" }
"constant" = { fg = "purple" }
"constructor" = { fg = "blue" }
"diagnostic.deprecated" = { modifiers = ["crossed_out"] }
"diagnostic.error" = { underline = { style = "curl", color = "red" } }
"diagnostic.hint" = { underline = { style = "curl", color = "comment_fg" } }
"diagnostic.info" = { underline = { style = "curl", color = "cyan" } }
"diagnostic.unnecessary" = { modifiers = ["dim"] }
"diagnostic.warning" = { underline = { style = "curl", color = "orange" } }
"diff.delta" = { fg = "blue" }
"diff.delta.gutter" = { fg = "cyan", bg = "linenr_bg" }
"diff.minus" = { fg = "red" }
"diff.minus.gutter" = { fg = "red", bg = "linenr_bg" }
"diff.plus" = { fg = "green" }
"diff.plus.gutter" = { fg = "green", bg = "linenr_bg" }
"error" = { fg = "red" }
"exception" = { fg = "blue" }
"field" = { fg = "background_fg" }
"float" = { fg = "purple" }
"function" = { fg = "pale" }
"function.macro" = { fg = "green" }
"hint" = { fg = "comment_fg" }
"identifier" = { fg = "blue" }
"info" = { fg = "cyan" }
"keyword" = { fg = "blue" }
"keyword.directive" = { fg = "green" }
"keyword.import" = { fg = "pale" }
"label" = { fg = "green" }
"markup.bold" = { modifiers = ["bold"] }
"markup.heading" = { fg = "blue", modifiers = ["bold"] }
"markup.italic" = { modifiers = ["italic"] }
"markup.link" = { fg = "blue", underline = { style = "line" } }
"markup.link.label" = { fg = "cyan" }
"markup.link.text" = { fg = "cyan" }
"markup.link.url" = { underline = { style = "line" } }
"markup.list" = { fg = "orange", modifiers = ["bold"] }
"markup.raw" = { fg = "cyan" }
"markup.raw.inline" = { bg = "black", fg = "blue" }
"markup.strikethrough" = { modifiers = ["crossed_out"] }
"method" = { fg = "pale" }
"namespace" = { fg = "blue" }
"number" = { fg = "purple" }
"operator" = { fg = "blue" }
"parameter" = { fg = "background_fg" }
"property" = { fg = "background_fg" }
"punctuation.bracket" = { fg = "background_fg" }
"punctuation.delimiter" = { fg = "background_fg" }
"punctuation.special" = { fg = "green" }
"repeat" = { fg = "blue" }
"special" = { fg = "green" }
"string" = { fg = "cyan" }
"string.escape" = { fg = "green" }
"string.special" = { fg = "green" }
"tag" = { fg = "blue" }
"tag.attribute" = { fg = "purple" }
"text" = { fg = "background_fg" }
"type" = { fg = "blue" }
"ui.background" = { fg = "background_fg", bg = "background_bg" }
"ui.background.separator" = { fg = "comment_fg" }
"ui.bufferline.active" = { fg = "pale" }
"ui.cursor.match" = { fg = "background_fg", bg = "matchparen_bg" }
"ui.cursor.normal" = { bg = "gray" }
"ui.cursor.primary" = { modifiers = ["reversed"] }
"ui.cursor.select" = { bg = "gray" }
"ui.gutter" = { fg = "linenr_fg", bg = "linenr_bg" }
"ui.help" = { fg = "background_fg", bg = "cursorlinenr_bg" }
"ui.linenr" = { fg = "linenr_fg", bg = "linenr_bg" }
"ui.menu" = { fg = "background_fg", bg = "cursorlinenr_bg" }
"ui.menu.border" = { fg = "comment_fg" }
"ui.menu.selected" = { fg = "menusel_fg", bg = "menusel_bg" }
"ui.popup" = { fg = "background_fg", bg = "cursorlinenr_bg" }
"ui.popup.info" = { fg = "blue" }
"ui.selection" = { bg = "sel_bg" }
"ui.statusline" = { bg = "statusline_bg", fg = "statusline_fg" }
"ui.statusline.insert" = { fg = "black", bg = "blue" }
"ui.statusline.select" = { fg = "black", bg = "green" }
"ui.text.focus" = { fg = "orange" }
"ui.virtual" = { fg = "linenr_fg" }
"ui.virtual.indent-guide" = { fg = "linenr_fg" }
"ui.virtual.jump-label" = { fg = "orange", modifiers = ["bold"] }
"ui.virtual.ruler" = { bg = "linenr_bg" }
"ui.virtual.whitespace" = { fg = "sel_bg" }
"ui.window" = { fg = "comment_fg", modifiers = ["bold"] }
"variable" = { fg = "background_fg" }
"variable.builtin" = { fg = "blue" }
"warning" = { fg = "orange" }
[palette]
orange = "#e2a578"
pale = "#a4aecc"
purple = "#a093c8"
black = "#1e2132"
gray = "#6b7089"
red = "#e27878"
light-red = "#e98989"
green = "#b5bf82"
light-green = "#c0ca8e"
yellow = "#e2a478"
light-yellow = "#e9b189"
blue = "#85a0c7"
light-blue = "#91acd1"
magenta = "#a093c7"
light-magenta = "#ada0d3"
cyan = "#89b9c2"
light-cyan = "#95c4ce"
white = "#c6c8d1"
light-gray = "#d2d4de"
background_bg = "#161822"
background_fg = "#c7c9d1"
comment_fg = "#6c7189"
cursorlinenr_bg = "#3d425c"
linenr_bg = "#1f2233"
linenr_fg = "#454d73"
matchparen_bg = "#3f455f"
menusel_bg = "#5c638a"
menusel_fg = "#f0f1f5"
sel_bg = "#282d43"
statusline_bg = "#0f1117"
statusline_fg = "#828597"

@ -0,0 +1,39 @@
# Author : Chromo-residuum-opec <development.0extl@simplelogin.com>
inherits = "iceberg-dark"
"ui.menu.selected" = { fg = "background_fg", bg = "menusel_bg" }
[palette]
orange = "#c67439"
pale = "#505695"
purple = "#785ab5"
black = "#dcdfe7"
gray = "#8389a3"
red = "#cd517a"
light-red = "#cc3768"
green = "#668f3d"
light-green = "#598030"
yellow = "#c57339"
light-yellow = "#b6662d"
blue = "#2e539e"
light-blue = "#22478e"
magenta = "#7759b4"
light-magenta = "#6845ad"
cyan = "#3f84a6"
light-cyan = "#327698"
white = "#33374c"
light-gray = "#262a3f"
background_bg = "#e9e9ed"
background_fg = "#33374d"
comment_fg = "#8489a4"
cursorlinenr_bg = "#cccfe0"
linenr_bg = "#dddfe9"
linenr_fg = "#a0a5c0"
matchparen_bg = "#bec0ca"
menusel_bg = "#a9afd1"
sel_bg = "#cacdd8"
statusline_bg = "#cad0de"
statusline_fg = "#757da3"

@ -1,9 +1,9 @@
use crate::helpers;
use crate::path;
use crate::DynError;
use helix_term::commands::TYPABLE_COMMAND_LIST;
use helix_term::health::TsFeature;
use std::collections::HashSet;
use std::fs;
pub const TYPABLE_COMMANDS_MD_OUTPUT: &str = "typable-cmd.md";
@ -95,14 +95,25 @@ pub fn lang_features() -> Result<String, DynError> {
.to_owned(),
);
}
row.push(
lc.language_servers
.iter()
.filter_map(|ls| config.language_server.get(&ls.name))
.map(|s| md_mono(&s.command.clone()))
.collect::<Vec<_>>()
.join(", "),
);
let mut seen_commands = HashSet::new();
let mut commands = String::new();
for ls_config in lc
.language_servers
.iter()
.filter_map(|ls| config.language_server.get(&ls.name))
{
let command = &ls_config.command;
if !seen_commands.insert(command) {
continue;
}
if !commands.is_empty() {
commands.push_str(", ");
}
commands.push_str(&md_mono(command));
}
row.push(commands);
md.push_str(&md_table_row(&row));
row.clear();

Loading…
Cancel
Save