helix
helix copied to clipboard
Syntax Highlighting related panic: IncludedRangesError(1)
Summary
When adding a '-symbol to a specific line of a specific nix-file, the predefined language-server for nix files (rnix-lsp) seems to provide information which results in an error in the tree_sitter parser which is unwrapped and hence panics.
https://github.com/helix-editor/helix/blob/03612174ee4cef23217b5adf415ced4a851b4a44/helix-core/src/syntax.rs#L988
Reproduction Steps
I tried this:
hx flake.nix- go to line 32
- add
'after the=-symbol of that line - crash
flake.nix
{
inputs = {
utils.url = "github:numtide/flake-utils";
devshell.url = "github:numtide/devshell";
fenix.url = "github:nix-community/fenix";
fenix.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = { self, nixpkgs, utils, devshell, fenix, ... }@inputs:
utils.lib.eachSystem [ "aarch64-linux" "i686-linux" "x86_64-linux" ]
(system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [ devshell.overlay ];
};
rust-toolchain = with fenix.packages.${system};
combine [ stable.rustc stable.cargo stable.clippy stable.rustfmt ];
in rec {
devShells.default = (pkgs.devshell.mkShell {
imports = [
# "${devshell}/extra/language/rust.nix"
"${devshell}/extra/git/hooks.nix"
];
name = "apex-rs-vanilla-dev-shell";
packages = with pkgs; [
rust-toolchain
rust-analyzer
cargo-outdated
cargo-udeps
];
devshell.startup.bindgen-hook.text = "source ${pkgs.rustPlatform.bindgenHook}/nix-support/setup-hook && populateBindgenEnv";
git.hooks = {
enable = true;
pre-commit.text = "nix flake check";
};
commands = [
{
package = "git-cliff";
help = "Changelog generator";
}
{
package = "treefmt";
help = "Format project tree with recommended formatter";
category = "formatter";
}
{
name = "udeps";
command = "cargo-udeps udeps";
category = "formatter";
help = "Find unused dependencies in Cargo.toml";
}
{
name = "outdated";
command = "cargo-outdated outdated";
category = "formatter";
help = "Find out-of-date dependencies";
}
{
name = "build";
command = "cd $PRJ_ROOT && cargo build";
help = "Build project";
category = "build";
}
{
name = "build release";
command = "cd $PRJ_ROOT && cargo build --release";
help = "Build project in release mode";
category = "build";
}
{
name = "clippy";
command = "cd $PRJ_ROOT && cargo clippy";
help = "Build project";
category = "build";
}
{
name = "clippy release";
command = "cd $PRJ_ROOT && cargo clippy --release";
help = "Build project in release mode";
category = "build";
}
{
name = "watch";
command = "cd $PRJ_ROOT && cargo watch -x clippy";
help = "Watch project and continuesly clippy";
category = "build";
}
{
name = "watch release";
command = "cd $PRJ_ROOT && cargo watch -x clippy --release";
help = "Watch project and continuesly clippy in release mode";
category = "build";
}
];
});
checks = {
nixpkgs-fmt = pkgs.runCommand "nixpkgs-fmt" {
nativeBuildInputs = [ pkgs.nixpkgs-fmt ];
} "nixpkgs-fmt --check ${./.}; touch $out";
cargo-fmt = pkgs.runCommand "cargo-fmt" {
nativeBuildInputs = [ rust-toolchain ];
} "cd ${./.}; cargo fmt --check; touch $out";
};
});
}
I expected this to happen:
No crash
Instead, this happened:
Crash
Helix log
~/.cache/helix/helix.log
2022-09-12T15:24:49.391 helix_lsp::transport [ERROR] err: <- StreamClosed
2022-09-12T15:24:49.391 helix_lsp::transport [ERROR] err: <- StreamClosed
console output
❯ RUST_BACKTRACE=full hx flake.nix
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: IncludedRangesError(1)', helix-core/src/syntax.rs:988:50
stack backtrace:
0: 0x55e7021044d4 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h9c2a9d2774d81873
1: 0x55e701927cac - core::fmt::write::hba4337c43d992f49
2: 0x55e7020fdeb5 - std::io::Write::write_fmt::heb73de6e02cfabed
3: 0x55e70210637e - std::panicking::default_hook::{{closure}}::hc9a76eed0b18f82b
4: 0x55e7021060ad - std::panicking::default_hook::h2e88d02087fae196
5: 0x55e702106a0b - std::panicking::rust_panic_with_hook::habfdcc2e90f9fd4c
6: 0x55e702106834 - std::panicking::begin_panic_handler::{{closure}}::he054b2a83a51d2cd
7: 0x55e702104a04 - std::sys_common::backtrace::__rust_end_short_backtrace::ha48b94ab49b30915
8: 0x55e70210659d - rust_begin_unwind
9: 0x55e70189ed93 - core::panicking::panic_fmt::h366d3a309ae17c94
10: 0x55e70189ee83 - core::result::unwrap_failed::hddd78f4658ac7d0f
11: 0x55e7019efecf - helix_core::syntax::LanguageLayer::parse::h48fdfccc00f93624
12: 0x55e7019c9375 - std::thread::local::LocalKey<T>::with::h3872ba0248f25375
13: 0x55e7019efb32 - helix_core::syntax::Syntax::update::hfabc70c9a1af51f1
14: 0x55e701ee80ca - helix_view::document::Document::apply_impl::h5831f29c9957f896
15: 0x55e701ee91b7 - helix_view::document::Document::apply::h597bd3f2f8ff332e
16: 0x55e701ce541e - helix_term::commands::insert::insert_char::h7a8fb8b8401f39f5
17: 0x55e701c4e3e0 - helix_term::ui::editor::EditorView::insert_mode::hb6771a242a86bcbf
18: 0x55e701c501b0 - <helix_term::ui::editor::EditorView as helix_term::compositor::Component>::handle_event::h0fee62f981b2f994
19: 0x55e701cc9566 - helix_term::compositor::Compositor::handle_event::h6f24a639f104cd8a
20: 0x55e701c45706 - helix_term::application::Application::handle_terminal_events::hd4a6e6651951166f
21: 0x55e701f8517f - helix_term::application::Application::event_loop_until_idle::{{closure}}::h44cf1aa2267c2b1c
22: 0x55e701fa31b5 - <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll::h2bcdc355d267fb0f
23: 0x55e701f80342 - std::thread::local::LocalKey<T>::with::he3043768d7283740
24: 0x55e701f6e868 - tokio::park::thread::CachedParkThread::block_on::h8a087f435dd2194f
25: 0x55e701fc9568 - tokio::runtime::scheduler::multi_thread::MultiThread::block_on::he8e9a60150382027
26: 0x55e701f9f87e - tokio::runtime::Runtime::block_on::hd015e4e225788d29
27: 0x55e701f64445 - hx::main::hb7285d874580d790
28: 0x55e701f67733 - std::sys_common::backtrace::__rust_begin_short_backtrace::h9aa95b3790b5aa07
29: 0x55e701f7fced - std::rt::lang_start::{{closure}}::h5d2638673ea5bf71
30: 0x55e7020f874b - std::rt::lang_start_internal::h9c06694362b5b80c
31: 0x55e701f64552 - main
32: 0x7f1b832e724e - __libc_start_call_main
33: 0x7f1b832e7309 - __libc_start_main@@GLIBC_2.34
34: 0x55e7018d67b5 - _start
35: 0x0 - <unknown>
Platform
Linux (NixOS)
Terminal Emulator
alacritty
Helix Version
helix 22.08.1 (0361217)
Unable to reproduce.
Linux 5.15.60-1-MANJARO @ 21.3.7 Kitty 0.25.2 helix 22.08.1 (23027a45) rnix-lsp 0.2.5-1
Which rnix-lsp are you on?
Seems to trigger if the start of the range is past the end of the range or if ranges overlap:
for (i, range) in ranges.iter().enumerate() {
if range.start_byte < prev_end_byte || range.end_byte < range.start_byte {
return Err(IncludedRangesError(i));
}
prev_end_byte = range.end_byte;
}
I also can't replicate: which = sign on this line? https://github.com/helix-editor/helix/blob/03612174ee4cef23217b5adf415ced4a851b4a44/flake.nix#L31 Do you have auto-pairs disabled?
I don't think it has anything to do with the LSP, this is a tree-sitter parsing issue.
There's a flake.nix linked in the initial post, it's collapsible so easy to miss. I could reproduce the crash with it (on mobile right now so can't get the hx --version).
I tested that file with 32ggf=a' and I simply just get the normal diagnostic error message. Do you have another set of keys you use to trigger the error?
@AlexanderBrevig I am on rnix-lsp 0.2.5.
Do you have another set of keys you use to trigger the error?
At least for me there are no keys required at all. I tested adding the ' with another language selected. It works, but when I reopened the file afterwards helix would just straight up crash.
@archseer
Do you have auto-pairs disabled?
I do not have auto-pairs disabled. I'll provide my config here:
~/.config/helix/config.toml
theme = "autumn"
[editor]
idle-timeout = 0
[editor.cursor-shape]
insert = "bar"
normal = "block"
select = "block"
[keys]
[keys.insert]
down = "move_line_down"
left = "move_char_left"
right = "move_char_right"
up = "move_line_up"
[keys.normal.space]
n = ":new"
u = ":format"
~/.config/helix/languages.toml
[[language]]
name = "latex"
[language.language-server]
command = "ltex-ls"
[[language]]
name = "nix"
[language.formatter]
command = "/nix/store/8i4cph1j35jx722snpd2dbj9s8w60amr-nixfmt-0.5.0/bin/nixfmt"
[[language]]
comment-token = "#"
file-types = ["COMMIT_EDITMSG"]
name = "git-commit"
roots = []
scope = "git.commitmsg"
[language.indent]
tab-width = 2
unit = " "
[language.language-server]
command = "ltex-ls"
[[language]]
file-types = ["md"]
name = "markdown"
roots = []
scope = "source.markdown"
[language.language-server]
command = "ltex-ls"
Other than these settings, default from 0361217 are used
@AlexanderBrevig
Here is a flake.nix which just straight up crashes helix.
flake.nix
{
inputs = {
utils.url = "github:numtide/flake-utils";
devshell.url = "github:numtide/devshell";
fenix.url = "github:nix-community/fenix";
fenix.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = { self, nixpkgs, utils, devshell, fenix, ... }@inputs:
utils.lib.eachSystem [ "aarch64-linux" "i686-linux" "x86_64-linux" ]
(system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [ devshell.overlay ];
};
rust-toolchain = with fenix.packages.${system};
combine [ stable.rustc stable.cargo stable.clippy stable.rustfmt ];
in rec {
devShells.default = (pkgs.devshell.mkShell {
imports = [
# "${devshell}/extra/language/rust.nix"
"${devshell}/extra/git/hooks.nix"
];
name = "apex-rs-vanilla-dev-shell";
packages = with pkgs; [
rust-toolchain
rust-analyzer
cargo-outdated
cargo-udeps
];
devshell.startup.bindgen-hook.text = ''
source ${pkgs.rustPlatform.bindgenHook}/nix-support/setup-hook
populateBindgenEnv
'';
git.hooks = {
enable = true;
pre-commit.text = "nix flake check";
};
commands = [
{
package = "git-cliff";
help = "Changelog generator";
}
{
package = "treefmt";
help = "Format project tree with recommended formatter";
category = "formatter";
}
{
name = "udeps";
command = "cargo-udeps udeps";
category = "formatter";
help = "Find unused dependencies in Cargo.toml";
}
{
name = "outdated";
command = "cargo-outdated outdated";
category = "formatter";
help = "Find out-of-date dependencies";
}
{
name = "build";
command = "cd $PRJ_ROOT && cargo build";
help = "Build project";
category = "build";
}
{
name = "build release";
command = "cd $PRJ_ROOT && cargo build --release";
help = "Build project in release mode";
category = "build";
}
{
name = "clippy";
command = "cd $PRJ_ROOT && cargo clippy";
help = "Build project";
category = "build";
}
{
name = "clippy release";
command = "cd $PRJ_ROOT && cargo clippy --release";
help = "Build project in release mode";
category = "build";
}
{
name = "watch";
command = "cd $PRJ_ROOT && cargo watch -x clippy";
help = "Watch project and continuesly clippy";
category = "build";
}
{
name = "watch release";
command = "cd $PRJ_ROOT && cargo watch -x clippy --release";
help = "Watch project and continuesly clippy in release mode";
category = "build";
}
];
});
checks = {
nixpkgs-fmt = pkgs.runCommand "nixpkgs-fmt" {
nativeBuildInputs = [ pkgs.nixpkgs-fmt ];
} "nixpkgs-fmt --check ${./.}; touch $out";
cargo-fmt = pkgs.runCommand "cargo-fmt" {
nativeBuildInputs = [ rust-toolchain ];
} "cd ${./.}; cargo fmt --check; touch $out";
};
});
}
{
inputs = {
utils.url = "github:numtide/flake-utils";
devshell.url = "github:numtide/devshell";
fenix.url = "github:nix-community/fenix";
fenix.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = { self, nixpkgs, utils, devshell, fenix, ... }@inputs:
utils.lib.eachSystem [ "aarch64-linux" "i686-linux" "x86_64-linux" ]
(system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [ devshell.overlay ];
};
rust-toolchain = with fenix.packages.${system};
combine [ stable.rustc stable.cargo stable.clippy stable.rustfmt ];
in rec {
devShells.default = (pkgs.devshell.mkShell {
imports = [
# "${devshell}/extra/language/rust.nix"
"${devshell}/extra/git/hooks.nix"
];
name = "apex-rs-vanilla-dev-shell";
packages = with pkgs; [
rust-toolchain
rust-analyzer
cargo-outdated
cargo-udeps
];
devshell.startup.bindgen-hook.text = ''
source ${pkgs.rustPlatform.bindgenHook}/nix-support/setup-hook
populateBindgenEnv
'';
git.hooks = {
enable = true;
pre-commit.text = "nix flake check";
};
commands = [
{
package = "git-cliff";
help = "Changelog generator";
}
{
package = "treefmt";
help = "Format project tree with recommended formatter";
category = "formatter";
}
{
name = "udeps";
command = "cargo-udeps udeps";
category = "formatter";
help = "Find unused dependencies in Cargo.toml";
}
{
name = "outdated";
command = "cargo-outdated outdated";
category = "formatter";
help = "Find out-of-date dependencies";
}
{
name = "build";
command = "cd $PRJ_ROOT && cargo build";
help = "Build project";
category = "build";
}
{
name = "build release";
command = "cd $PRJ_ROOT && cargo build --release";
help = "Build project in release mode";
category = "build";
}
{
name = "clippy";
command = "cd $PRJ_ROOT && cargo clippy";
help = "Build project";
category = "build";
}
{
name = "clippy release";
command = "cd $PRJ_ROOT && cargo clippy --release";
help = "Build project in release mode";
category = "build";
}
{
name = "watch";
command = "cd $PRJ_ROOT && cargo watch -x clippy";
help = "Watch project and continuesly clippy";
category = "build";
}
{
name = "watch release";
command = "cd $PRJ_ROOT && cargo watch -x clippy --release";
help = "Watch project and continuesly clippy in release mode";
category = "build";
}
];
});
checks = {
nixpkgs-fmt = pkgs.runCommand "nixpkgs-fmt" {
nativeBuildInputs = [ pkgs.nixpkgs-fmt ];
} "nixpkgs-fmt --check ${./.}; touch $out";
cargo-fmt = pkgs.runCommand "cargo-fmt" {
nativeBuildInputs = [ rust-toolchain ];
} "cd ${./.}; cargo fmt --check; touch $out";
};
});
}
With #3826 of course the output of the program changes to:
Program output
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: InvalidRanges', helix-core/src/syntax.rs:618:14
stack backtrace:
0: 0x55a65d770ed4 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h9c2a9d2774d81873
1: 0x55a65cf94ccc - core::fmt::write::hba4337c43d992f49
2: 0x55a65d76a8b5 - std::io::Write::write_fmt::heb73de6e02cfabed
3: 0x55a65d772d7e - std::panicking::default_hook::{{closure}}::hc9a76eed0b18f82b
4: 0x55a65d772aad - std::panicking::default_hook::h2e88d02087fae196
5: 0x55a65d773325 - std::panicking::rust_panic_with_hook::habfdcc2e90f9fd4c
6: 0x55a65d773234 - std::panicking::begin_panic_handler::{{closure}}::he054b2a83a51d2cd
7: 0x55a65d771404 - std::sys_common::backtrace::__rust_end_short_backtrace::ha48b94ab49b30915
8: 0x55a65d772f9d - rust_begin_unwind
9: 0x55a65cf0bd93 - core::panicking::panic_fmt::h366d3a309ae17c94
10: 0x55a65cf0be83 - core::result::unwrap_failed::hddd78f4658ac7d0f
11: 0x55a65d05c372 - helix_core::syntax::Syntax::new::h3e77386699b9bd03
12: 0x55a65d553450 - helix_view::document::Document::set_language::h4013a5d56dd28867
13: 0x55a65d551e8e - helix_view::document::Document::open::hc8eeb61a7d9ec6b4
14: 0x55a65d51c8e1 - helix_view::editor::Editor::open::h60cbbb87afa07f7b
15: 0x55a65d2af6f9 - helix_term::application::Application::new::h626015731ae4f831
16: 0x55a65d610201 - <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll::h5f3b37062c32a82c
17: 0x55a65d5ecb42 - std::thread::local::LocalKey<T>::with::hb5d8ea16e9cadeef
18: 0x55a65d5db2c8 - tokio::park::thread::CachedParkThread::block_on::h59b4805dfbf7bc54
19: 0x55a65d635ed8 - tokio::runtime::scheduler::multi_thread::MultiThread::block_on::h44c594da2be2f6c5
20: 0x55a65d60c22e - tokio::runtime::Runtime::block_on::hdc7affd610a62c07
21: 0x55a65d5d0f25 - hx::main::h3502fc2a3489134c
22: 0x55a65d5d4213 - std::sys_common::backtrace::__rust_begin_short_backtrace::h4f9548a5e84dface
23: 0x55a65d5ec6ad - std::rt::lang_start::{{closure}}::h1c682f4407c90018
24: 0x55a65d76514b - std::rt::lang_start_internal::h9c06694362b5b80c
25: 0x55a65d5d1032 - main
26: 0x7f7582fd124e - __libc_start_call_main
27: 0x7f7582fd1309 - __libc_start_main@@GLIBC_2.34
28: 0x55a65cf437d5 - _start
29: 0x0 - <unknown>
It looks like this was introduced by 665e27ff9dc017ee47f646187d98f5e4cdb18411
minimal reproduction:
{
startup.hook = ''
sh
''
}
I assume it has something to do with this: https://github.com/helix-editor/helix/blob/eb81cf3c013232fb1b01c51e9f3edba4cf39d977/runtime/queries/nix/injections.scm#L17 I'll dig into it a little bit later
looking at this the query: https://github.com/helix-editor/helix/blob/eb81cf3c013232fb1b01c51e9f3edba4cf39d977/runtime/queries/nix/injections.scm#L11-L19 matches twice for the above nix text
QueryMatch { id: 0, pattern_index: 2, captures: [QueryCapture { node: {Node identifier (1, 2) - (1, 9)}, index: 2 }, QueryCapture { node: {Node string_fragment (1, 19) - (3, 2)}, index: 0 }] }
QueryMatch { id: 1, pattern_index: 2, captures: [QueryCapture { node: {Node identifier (1, 10) - (1, 14)}, index: 2 }, QueryCapture { node: {Node string_fragment (1, 19) - (3, 2)}, index: 0 }] }
so there is duplicated content nodes
[{Node string_fragment (1, 19) - (3, 2)}, {Node string_fragment (1, 19) - (3, 2)}]
which creates duplicated ranges: https://github.com/helix-editor/helix/blob/eb81cf3c013232fb1b01c51e9f3edba4cf39d977/helix-core/src/syntax.rs#L1192-L1197
adding ranges.dedup(); after the above line did fix this issue but I am pretty sure that is not the correct fix