helix-editor / helix

A post-modern modal text editor.
https://helix-editor.com
Mozilla Public License 2.0
34.08k stars 2.52k forks source link

Syntax Highlighting related panic: IncludedRangesError(1) #3816

Closed sevenautumns closed 1 year ago

sevenautumns commented 2 years ago

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: 1. `hx flake.nix` 2. go to line 32 3. add `'` after the `=`-symbol of that line 4. crash
flake.nix ```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 - ::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::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 - ::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 - as core::future::future::Future>::poll::h2bcdc355d267fb0f 23: 0x55e701f80342 - std::thread::local::LocalKey::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 - ```
### Platform Linux (NixOS) ### Terminal Emulator alacritty ### Helix Version helix 22.08.1 (0361217)
AlexanderBrevig commented 2 years ago

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?

archseer commented 2 years ago

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.

sudormrfbin commented 2 years ago

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).

AlexanderBrevig commented 2 years ago

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?

sevenautumns commented 2 years ago

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

sevenautumns commented 2 years ago

@AlexanderBrevig

Here is a flake.nix which just straight up crashes helix.

flake.nix <----- Collapsible ```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"; }; }); } ```

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 - ::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 - as core::future::future::Future>::poll::h5f3b37062c32a82c 17: 0x55a65d5ecb42 - std::thread::local::LocalKey::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 - ```
the-mikedavis commented 2 years ago

It looks like this was introduced by 665e27ff9dc017ee47f646187d98f5e4cdb18411

gabydd commented 1 year ago

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

gabydd commented 1 year ago

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