Skip to content

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

Description

@datanoise

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions