nvim-treesitter / nvim-treesitter/nvim-treesitter-context

Ruby context query with repeated when pattern can hang Neovim in ts_query_cursor__advance

Open
#673 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Janet
Stars
3.2k
Forks
241
PR merge metrics
No merged PRs in 30d

Description

Description

Ruby context query can hang Neovim in ts_query_cursor__advance

  nvim-treesitter-context commit: b311b30
  Neovim: v0.13.0-dev-507+g45e63ee3a8
  Filetype: ruby

The Ruby context query pattern:

  (case
    (when
      (_) @context.end)*
    (else
      (_) @context.end)?) @context

causes Neovim to peg CPU at 100% while scrolling a Ruby file with large case statements.

Sampling shows:
querycursor_next_match
ts_query_cursor_next_match
ts_query_cursor__advance

A reduced headless repro confirms it is independent of LSP and my user config. Replacing the quantified case pattern with separate non-quantified case/when/else patterns avoids the spin.

This local override avoids the hang for me by replacing the quantified case pattern with separate case, when, and else patterns:

  (case) @context

  (when
    (_) @context.end) @context

  (else
    (_) @context.end) @context

This replaced the original pattern:

  (case
    (when
      (_) @context.end)*
    (else
      (_) @context.end)?) @context
Neovim version

v0.13.0-dev-507+g45e63ee3a8

Expected behavior

No response

Actual behavior

Neovim becomes unresponsive and one nvim process pegs a CPU core at 100% while scrolling a Ruby buffer containing large/nested case statements.

Sampling the process shows it stuck in Tree-sitter query matching:

  querycursor_next_match
  ts_query_cursor_next_match
  ts_query_cursor__advance

The issue reproduces without Ruby LSP and without my full user config using a reduced headless repro that runs the Ruby context.scm query against the file.

Minimal config
-- minimal_init.lua
  vim.opt.runtimepath:prepend('/path/to/nvim-treesitter-context')

  vim.filetype.add({
    extension = { rb = 'ruby' },
  })

  vim.api.nvim_create_autocmd('FileType', {
    pattern = 'ruby',
    callback = function(args)
      vim.treesitter.start(args.buf, 'ruby')
    end,
  })

  require('treesitter-context').setup({
    max_lines = 2,
  })
Steps to reproduce

I used the following Ruby code to reproduce:

class Example
    def route(type, client)
      case [type, client]
      when [:a, :one]
        :a_one
      when [:a, :two]
        :a_two
      when [:a, :three]
        case client
        when :x
          :nested_x
        when :y
          :nested_y
        else
          :nested_other
        end
      when [:b, :one]
        :b_one
      when [:b, :two]
        :b_two
      when [:b, :three]
        case client
        when :x
          :nested_b_x
        when :y
          :nested_b_y
        else
          :nested_b_other
        end
      when [:c, :one]
        :c_one
      when [:c, :two]
        :c_two
      when [:c, :three]
        :c_three
      else
        :unknown
      end
    end
  end

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the Ruby context query pattern and run the reduced headless repro against the supplied nested case example. Compare the quantified pattern with the separate case, when, and else patterns in the issue. Done means scrolling the Ruby buffer no longer hangs or pins a CPU, while context rendering still works.

Written by the indexing model from the issue text.

Assessment

Tech stack
neovim, ruby
Domain
performance, tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.