Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Kalle Carlbark 2025-01-14 20:55:31 +01:00
commit a0ca976c99
36 changed files with 1591 additions and 1158 deletions

View file

@ -61,17 +61,17 @@ jobs:
build: [x86_64-linux, x86_64-macos, x86_64-windows] #, x86_64-win-gnu, win32-msvc
include:
- build: x86_64-linux
os: ubuntu-latest
os: ubuntu-22.04
rust: stable
target: x86_64-unknown-linux-gnu
cross: false
- build: aarch64-linux
os: ubuntu-latest
os: ubuntu-22.04
rust: stable
target: aarch64-unknown-linux-gnu
cross: true
# - build: riscv64-linux
# os: ubuntu-latest
# os: ubuntu-22.04
# rust: stable
# target: riscv64gc-unknown-linux-gnu
# cross: true

View file

@ -24,6 +24,10 @@ Packaging:
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))

123
Cargo.lock generated
View file

@ -101,9 +101,9 @@ dependencies = [
[[package]]
name = "bitflags"
version = "2.6.0"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be"
[[package]]
name = "bstr"
@ -136,9 +136,9 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
[[package]]
name = "cc"
version = "1.2.6"
version = "1.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333"
checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b"
dependencies = [
"shlex",
]
@ -530,7 +530,7 @@ dependencies = [
"gix-worktree",
"once_cell",
"smallvec",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -543,7 +543,7 @@ dependencies = [
"gix-date",
"gix-utils",
"itoa",
"thiserror 2.0.9",
"thiserror 2.0.11",
"winnow",
]
@ -560,7 +560,7 @@ dependencies = [
"gix-trace",
"kstring",
"smallvec",
"thiserror 2.0.9",
"thiserror 2.0.11",
"unicode-bom",
]
@ -570,7 +570,7 @@ version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d48b897b4bbc881aea994b4a5bbb340a04979d7be9089791304e04a9fbc66b53"
dependencies = [
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -579,7 +579,7 @@ version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6ffbeb3a5c0b8b84c3fe4133a6f8c82fa962f4caefe8d0762eced025d3eb4f7"
dependencies = [
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -605,7 +605,7 @@ dependencies = [
"gix-features",
"gix-hash",
"memmap2",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -624,7 +624,7 @@ dependencies = [
"memchr",
"once_cell",
"smallvec",
"thiserror 2.0.9",
"thiserror 2.0.11",
"unicode-bom",
"winnow",
]
@ -639,7 +639,7 @@ dependencies = [
"bstr",
"gix-path",
"libc",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -651,7 +651,7 @@ dependencies = [
"bstr",
"itoa",
"jiff",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -672,7 +672,7 @@ dependencies = [
"gix-traverse",
"gix-worktree",
"imara-diff",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -692,7 +692,7 @@ dependencies = [
"gix-trace",
"gix-utils",
"gix-worktree",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -708,7 +708,7 @@ dependencies = [
"gix-path",
"gix-ref",
"gix-sec",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -726,7 +726,7 @@ dependencies = [
"once_cell",
"prodash",
"sha1_smol",
"thiserror 2.0.9",
"thiserror 2.0.11",
"walkdir",
]
@ -748,7 +748,7 @@ dependencies = [
"gix-trace",
"gix-utils",
"smallvec",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -781,7 +781,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b5eccc17194ed0e67d49285e4853307e4147e95407f91c1c3e4a13ba9f4e4ce"
dependencies = [
"faster-hex",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -833,7 +833,7 @@ dependencies = [
"memmap2",
"rustix",
"smallvec",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -864,7 +864,7 @@ dependencies = [
"gix-validate",
"itoa",
"smallvec",
"thiserror 2.0.9",
"thiserror 2.0.11",
"winnow",
]
@ -886,7 +886,7 @@ dependencies = [
"gix-quote",
"parking_lot",
"tempfile",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -904,7 +904,7 @@ dependencies = [
"gix-path",
"memmap2",
"smallvec",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -916,7 +916,7 @@ dependencies = [
"bstr",
"faster-hex",
"gix-trace",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -928,7 +928,7 @@ dependencies = [
"bstr",
"faster-hex",
"gix-trace",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -941,7 +941,7 @@ dependencies = [
"gix-trace",
"home",
"once_cell",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -956,7 +956,7 @@ dependencies = [
"gix-config-value",
"gix-glob",
"gix-path",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -974,7 +974,7 @@ dependencies = [
"gix-transport",
"gix-utils",
"maybe-async",
"thiserror 2.0.9",
"thiserror 2.0.11",
"winnow",
]
@ -986,7 +986,7 @@ checksum = "64a1e282216ec2ab2816cd57e6ed88f8009e634aec47562883c05ac8a7009a63"
dependencies = [
"bstr",
"gix-utils",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -1006,7 +1006,7 @@ dependencies = [
"gix-utils",
"gix-validate",
"memmap2",
"thiserror 2.0.9",
"thiserror 2.0.11",
"winnow",
]
@ -1021,7 +1021,7 @@ dependencies = [
"gix-revision",
"gix-validate",
"smallvec",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -1036,7 +1036,7 @@ dependencies = [
"gix-hash",
"gix-object",
"gix-revwalk",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -1051,7 +1051,7 @@ dependencies = [
"gix-hashtable",
"gix-object",
"smallvec",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -1075,7 +1075,7 @@ dependencies = [
"bstr",
"gix-hash",
"gix-lock",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -1098,7 +1098,7 @@ dependencies = [
"gix-pathspec",
"gix-worktree",
"portable-atomic",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -1113,7 +1113,7 @@ dependencies = [
"gix-pathspec",
"gix-refspec",
"gix-url",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -1149,7 +1149,7 @@ dependencies = [
"gix-quote",
"gix-sec",
"gix-url",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -1166,7 +1166,7 @@ dependencies = [
"gix-object",
"gix-revwalk",
"smallvec",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -1179,7 +1179,7 @@ dependencies = [
"gix-features",
"gix-path",
"percent-encoding",
"thiserror 2.0.9",
"thiserror 2.0.11",
"url",
]
@ -1201,7 +1201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd520d09f9f585b34b32aba1d0b36ada89ab7fefb54a8ca3fe37fc482a750937"
dependencies = [
"bstr",
"thiserror 2.0.9",
"thiserror 2.0.11",
]
[[package]]
@ -1335,7 +1335,7 @@ dependencies = [
"log",
"serde",
"serde_json",
"thiserror 2.0.9",
"thiserror 2.0.11",
"tokio",
]
@ -1391,7 +1391,7 @@ dependencies = [
"serde",
"serde_json",
"slotmap",
"thiserror 2.0.9",
"thiserror 2.0.11",
"tokio",
"tokio-stream",
]
@ -1466,7 +1466,7 @@ dependencies = [
"smallvec",
"tempfile",
"termini",
"thiserror 2.0.9",
"thiserror 2.0.11",
"tokio",
"tokio-stream",
"toml",
@ -1536,7 +1536,7 @@ dependencies = [
"slotmap",
"smartstring",
"tempfile",
"thiserror 2.0.9",
"thiserror 2.0.11",
"tokio",
"tokio-stream",
"toml",
@ -1999,9 +1999,9 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "open"
version = "5.3.1"
version = "5.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ecd52f0b8d15c40ce4820aa251ed5de032e5d91fab27f7db2f40d42a8bdf69c"
checksum = "e2483562e62ea94312f3576a7aca397306df7990b8d89033e18766744377ef95"
dependencies = [
"is-wsl",
"libc",
@ -2216,9 +2216,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "rustix"
version = "0.38.42"
version = "0.38.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6"
dependencies = [
"bitflags",
"errno",
@ -2270,9 +2270,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.134"
version = "1.0.135"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d"
checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9"
dependencies = [
"itoa",
"memchr",
@ -2454,12 +2454,13 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.14.0"
version = "3.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
dependencies = [
"cfg-if",
"fastrand",
"getrandom",
"once_cell",
"rustix",
"windows-sys 0.59.0",
@ -2496,11 +2497,11 @@ dependencies = [
[[package]]
name = "thiserror"
version = "2.0.9"
version = "2.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc"
checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
dependencies = [
"thiserror-impl 2.0.9",
"thiserror-impl 2.0.11",
]
[[package]]
@ -2516,9 +2517,9 @@ dependencies = [
[[package]]
name = "thiserror-impl"
version = "2.0.9"
version = "2.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4"
checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2"
dependencies = [
"proc-macro2",
"quote",
@ -2561,9 +2562,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.42.0"
version = "1.43.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551"
checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e"
dependencies = [
"backtrace",
"bytes",
@ -2579,9 +2580,9 @@ dependencies = [
[[package]]
name = "tokio-macros"
version = "2.4.0"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
dependencies = [
"proc-macro2",
"quote",

View file

@ -42,6 +42,8 @@ tree-sitter = { version = "0.22" }
nucleo = "0.5.0"
slotmap = "1.0.7"
thiserror = "2.0"
tempfile = "3.15.0"
bitflags = "2.7"
[workspace.package]
version = "25.1.0"

View file

@ -145,7 +145,8 @@ The following statusline elements can be configured:
| Key | Description | Default |
| --- | ----------- | ------- |
| `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` |
| `display-inlay-hints` | Display inlay hints[^2] | `false` |
| `display-color-swatches` | Shows color swatches next to colors | `true` |

View file

@ -23,6 +23,7 @@
| circom | ✓ | | | `circom-lsp` |
| clojure | ✓ | | | `clojure-lsp` |
| cmake | ✓ | ✓ | ✓ | `cmake-language-server` |
| codeql | ✓ | ✓ | | `codeql` |
| comment | ✓ | | | |
| common-lisp | ✓ | | ✓ | `cl-lsp` |
| cpon | ✓ | | ✓ | |
@ -80,6 +81,7 @@
| gowork | ✓ | | | `gopls` |
| gpr | ✓ | | | `ada_language_server` |
| graphql | ✓ | ✓ | | `graphql-lsp` |
| gren | ✓ | ✓ | | |
| groovy | ✓ | | | |
| gts | ✓ | ✓ | ✓ | `typescript-language-server`, `vscode-eslint-language-server`, `ember-language-server` |
| hare | ✓ | | | |

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

@ -6,14 +6,6 @@ const MAJOR: &str = env!("CARGO_PKG_VERSION_MAJOR");
const MINOR: &str = env!("CARGO_PKG_VERSION_MINOR");
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() {
let git_hash = Command::new("git")
.args(["rev-parse", "HEAD"])
@ -23,7 +15,17 @@ fn main() {
.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 {
Some(git_hash) => format!("{} ({})", calver, &git_hash[..8]).into(),
None => calver.into(),

View file

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

View file

@ -26,7 +26,7 @@ globset = "0.4.15"
log = "0.4"
serde = { version = "1.0", features = ["derive"] }
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"
parking_lot = "0.12.3"
arc-swap = "1"

View file

@ -17,7 +17,7 @@ etcetera = "0.8"
ropey = { version = "1.6.1", default-features = false }
which = "7.0"
regex-cursor = "0.1.4"
bitflags = "2.6"
bitflags.workspace = true
once_cell = "1.19"
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"] }
[dev-dependencies]
tempfile = "3.14"
tempfile.workspace = true

View file

@ -59,7 +59,7 @@ content_inspector = "0.2.4"
thiserror.workspace = true
# opening URLs
open = "5.3.1"
open = "5.3.2"
url = "2.5.4"
# config
@ -85,5 +85,5 @@ helix-loader = { path = "../helix-loader" }
[dev-dependencies]
smallvec = "1.13"
indoc = "2.0.5"
tempfile = "3.14.0"
tempfile.workspace = true
same-file = "1.0.1"

View file

@ -30,9 +30,7 @@ use helix_core::{
object, pos_at_coords,
regex::{self, Regex},
search::{self, CharMatcher},
selection,
shellwords::{self, Args},
surround,
selection, shellwords, surround,
syntax::{BlockCommentToken, LanguageServerFeature},
text_annotations::{Overlay, TextAnnotations},
textobject,
@ -209,7 +207,7 @@ use helix_view::{align_view, Align};
pub enum MappableCommand {
Typable {
name: String,
args: String,
args: Vec<String>,
doc: String,
},
Static {
@ -244,17 +242,15 @@ impl MappableCommand {
pub fn execute(&self, cx: &mut Context) {
match &self {
Self::Typable { name, args, doc: _ } => {
let args: Vec<Cow<str>> = args.iter().map(Cow::from).collect();
if let Some(command) = typed::TYPABLE_COMMAND_MAP.get(name.as_str()) {
let mut cx = compositor::Context {
editor: cx.editor,
jobs: cx.jobs,
scroll: None,
};
if let Err(err) =
(command.fun)(&mut cx, Args::from(args), PromptEvent::Validate)
{
cx.editor.set_error(format!("{err}"));
if let Err(e) = (command.fun)(&mut cx, &args[..], PromptEvent::Validate) {
cx.editor.set_error(format!("{}", e));
}
}
}
@ -628,15 +624,21 @@ impl std::str::FromStr for MappableCommand {
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Some(suffix) = s.strip_prefix(':') {
let (name, args) = suffix.split_once(' ').unwrap_or((suffix, ""));
let mut typable_command = suffix.split(' ').map(|arg| arg.trim());
let name = typable_command
.next()
.ok_or_else(|| anyhow!("Expected typable command name"))?;
let args = typable_command
.map(|s| s.to_owned())
.collect::<Vec<String>>();
typed::TYPABLE_COMMAND_MAP
.get(name)
.map(|cmd| MappableCommand::Typable {
name: cmd.name.to_owned(),
doc: format!(":{} {:?}", cmd.name, args),
args: args.to_string(),
args,
})
.ok_or_else(|| anyhow!("No TypableCommand named '{}'", name))
.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(),
@ -3101,12 +3103,11 @@ fn buffer_picker(cx: &mut Context) {
})
.with_preview(|editor, meta| {
let doc = &editor.documents.get(&meta.id)?;
let &view_id = doc.selections().keys().next()?;
let line = doc
.selection(view_id)
.primary()
.cursor_line(doc.text().slice(..));
Some((meta.id.into(), Some((line, line))))
let lines = doc.selections().values().next().map(|selection| {
let cursor_line = selection.primary().cursor_line(doc.text().slice(..));
(cursor_line, cursor_line)
});
Some((meta.id.into(), lines))
});
cx.push_layer(Box::new(overlaid(picker)));
}
@ -3311,7 +3312,7 @@ pub fn command_palette(cx: &mut Context) {
.iter()
.map(|cmd| MappableCommand::Typable {
name: cmd.name.to_owned(),
args: String::new(),
args: Vec::new(),
doc: cmd.doc.to_owned(),
}),
);
@ -3532,6 +3533,7 @@ fn open(cx: &mut Context, open: Open) {
let text = doc.text().slice(..);
let contents = doc.text();
let selection = doc.selection(view.id);
let mut offs = 0;
let mut ranges = SmallVec::with_capacity(selection.len());
@ -3608,7 +3610,7 @@ fn open(cx: &mut Context, open: Open) {
let text = text.repeat(count);
// 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
.map(|token| token.len() + 1) // `+ 1` for the extra space added
.unwrap_or_default();
@ -3621,6 +3623,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,
@ -4385,19 +4390,13 @@ fn yank_joined_impl(editor: &mut Editor, separator: &str, register: char) {
let (view, doc) = current!(editor);
let text = doc.text().slice(..);
let separator = if separator.is_empty() {
doc.line_ending.as_str()
} else {
separator
};
let selection = doc.selection(view.id);
let selections = selection.len();
let joined = selection
.fragments(text)
.fold(String::new(), |mut acc, fragment| {
if !acc.is_empty() {
acc.push_str(&shellwords::unescape(separator));
acc.push_str(separator);
}
acc.push_str(&fragment);
acc
@ -4844,7 +4843,7 @@ fn join_selections_impl(cx: &mut Context, select_space: bool) {
changes.reserve(lines.len());
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);
let first_line = slice.slice(first_line_idx..);
let mut current_comment_token = comment_tokens

View file

@ -109,7 +109,6 @@ fn dap_callback<T, F>(
jobs.callback(callback);
}
// TODO: transition to `shellwords::Args` instead of `Option<Vec<Cow>>>`
pub fn dap_start_impl(
cx: &mut compositor::Context,
name: Option<&str>,
@ -313,7 +312,6 @@ pub fn dap_restart(cx: &mut Context) {
);
}
// TODO: transition to `shellwords::Args` instead of `Vec<String>`
fn debug_parameter_prompt(
completions: Vec<DebugConfigCompletion>,
config_name: String,

File diff suppressed because it is too large Load diff

View file

@ -597,14 +597,18 @@ mod tests {
let expectation = KeyTrie::Node(KeyTrieNode::new(
"",
hashmap! {
key => KeyTrie::Sequence(vec![
key => KeyTrie::Sequence(vec!{
MappableCommand::select_all,
MappableCommand::Typable {
name: "pipe".to_string(),
args: String::from("sed -E 's/\\s+$//g'"),
doc: String::new(),
args: vec!{
"sed".to_string(),
"-E".to_string(),
"'s/\\s+$//g'".to_string()
},
doc: "".to_string(),
},
])
})
},
vec![key],
));

View file

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

View file

@ -184,6 +184,127 @@ async fn test_open_above() -> anyhow::Result<()> {
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.
#[tokio::test(flavor = "multi_thread")]
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-core = { path = "../helix-core" }
bitflags = "2.6"
bitflags.workspace = true
cassowary = "0.3"
unicode-segmentation = "1.12"
crossterm = { version = "0.28", optional = true }

View file

@ -29,4 +29,4 @@ log = "0.4"
git = ["gix"]
[dev-dependencies]
tempfile = "3.14"
tempfile.workspace = true

View file

@ -9,6 +9,7 @@ rust-version.workspace = true
categories.workspace = true
repository.workspace = true
homepage.workspace = true
temp.worspace = true
[features]
default = []
@ -24,13 +25,13 @@ helix-lsp = { path = "../helix-lsp" }
helix-dap = { path = "../helix-dap" }
helix-vcs = { path = "../helix-vcs" }
bitflags = "2.6"
bitflags.workspace = true
anyhow = "1"
crossterm = { version = "0.28", optional = true }
tempfile = "3.14"
same-file = "1.0.1"
filetime = "0.2"
tempfile = "3.14"
# Conversion traits
once_cell = "1.20"

View file

@ -980,7 +980,13 @@ impl Document {
{
use std::process::Stdio;
let text = self.text().clone();
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
.args(fmt_args)
.stdin(Stdio::piped())

View file

@ -21,6 +21,7 @@ cl-lsp = { command = "cl-lsp", args = [ "stdio" ] }
clangd = { command = "clangd" }
clojure-lsp = { command = "clojure-lsp" }
cmake-language-server = { command = "cmake-language-server" }
codeql = { command = "codeql", args = ["execute", "language-server", "--check-errors=ON_CHANGE"] }
crystalline = { command = "crystalline", args = ["--stdio"] }
cs = { command = "cs", args = ["launch", "--contrib", "smithy-language-server", "--", "0"] }
csharp-ls = { command = "csharp-ls" }
@ -487,6 +488,8 @@ name = "jsonc"
scope = "source.json"
injection-regex = "jsonc"
file-types = ["jsonc", { glob = "tsconfig.json" }]
comment-token = "//"
block-comment-tokens = { start = "/*", end = "*/" }
grammar = "json"
language-servers = [ "vscode-json-language-server" ]
auto-format = true
@ -1292,7 +1295,7 @@ formatter = { command = "dune", args = ["format-dune-file"] }
name = "lua"
injection-regex = "lua"
scope = "source.lua"
file-types = ["lua"]
file-types = ["lua", "rockspec"]
shebangs = ["lua", "luajit"]
roots = [".luarc.json", ".luacheckrc", ".stylua.toml", "selene.toml", ".git"]
comment-token = "--"
@ -1347,7 +1350,7 @@ source = { git = "https://github.com/ikatyang/tree-sitter-vue", rev = "91fe27547
[[language]]
name = "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 = "#"
indent = { tab-width = 2, unit = " " }
language-servers = [ "yaml-language-server", "ansible-language-server" ]
@ -2897,7 +2900,7 @@ indent = { tab-width = 2, unit = " " }
[[grammar]]
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]]
name = "ponylang"
@ -4033,3 +4036,32 @@ 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

@ -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

@ -16,8 +16,31 @@
(#match? @variable.builtin "^(arguments|module|console|window|document)$")
(#is-not? local))
((identifier) @function.builtin
(#eq? @function.builtin "require")
(call_expression
(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))
; 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
(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 ()
(comment) @comment

View file

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

View file

@ -63,6 +63,14 @@
(#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
(#any-of?
@ -311,6 +319,8 @@
((identifier) @type
(#match? @type "^[A-Z]"))
(never_type "!" @type)
; -------
; Functions
; -------
@ -453,6 +463,7 @@
; 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
(type_identifier) @type

View file

@ -24,7 +24,7 @@
"operator" = "text"
"punctuation" = "text"
"punctuation.delimiter" = "text"
"special" = "text"
"special" = "light_blue"
"string" = "orange"
"string.regexp" = "gold"
"tag" = "blue2"
@ -72,9 +72,10 @@
"ui.bufferline.background" = { bg = "background" }
"ui.text" = { fg = "text" }
"ui.text.focus" = { fg = "white" }
"ui.text.directory" = { fg = "blue3" }
"ui.text.directory" = { fg = "blue2" }
"ui.text.inactive" = { fg = "dark_gray" }
"ui.virtual.whitespace" = { fg = "#3e3e3d" }
"ui.virtual.wrap" = { fg = "#3e3e3d" }
"ui.virtual.ruler" = { bg = "borders" }
"ui.virtual.indent-guide" = { fg = "dark_gray4" }
"ui.virtual.inlay-hint" = { fg = "dark_gray5"}