Skip to content

vim.treesitter query problem #22055

@sergii4

Description

@sergii4

Describe the bug

vim.treesitter can't capture big number of nodes of one pattern. Fox example, if you have a Go test with more than 5 tables test cases, vim.treesitter starts skipping previous tests names. That query highlights 5 test cases name instead of 6
Screenshot 2023-01-30 at 12 32 16

It seems that problem somewhere in vim.treesitter.parse_query and iterating over it with :iter_matches

Steps to reproduce

With nvim treesitter playground:

  • Install nvim treesitter with playgound
  • Create a Go test file, for example, table_test.go:
package main

import (
	"fmt"
	"net/http"
	"testing"
)

func TestSomeTest(t *testing.T) {
	tt := []struct {
		name   string
		method string
		url    string
		apiKey string
		status int
	}{
		{name: "AccessDenied1", method: http.MethodGet, url: "/api/nothing", apiKey: "lalala", status: http.StatusForbidden},
		{name: "AccessDenied2", method: http.MethodGet, url: "/api/nothing", apiKey: "lalala", status: http.StatusForbidden},
		{name: "AccessDenied3", method: http.MethodGet, url: "/api/nothing", apiKey: "lalala", status: http.StatusForbidden},
		{name: "AccessDenied4", method: http.MethodGet, url: "/api/nothing", apiKey: "lalala", status: http.StatusForbidden},
		{name: "AccessDenied5", method: http.MethodGet, url: "/api/nothing", apiKey: "lalala", status: http.StatusForbidden},
		{name: "AccessDenied6", method: http.MethodGet, url: "/api/nothing", apiKey: "lalala", status: http.StatusForbidden},
	}

	for _, tc := range tt {
		tc := tc
		t.Run(tc.name, func(_ *testing.T) {
			fmt.Println(tc.name, tc.method, tc.url, tc.apiKey, tc.status)
		})
	}

}
  • open playground (:TSPlaygroundToggle), open query editor(o), use that query:
(block
      (short_var_declaration
        left: (expression_list
          (identifier) @test.cases)
        right: (expression_list
          (composite_literal
            body:(literal_value
              (literal_element
                (literal_value
                  (keyed_element
                    (literal_element
                      (identifier) @test.field.name1)
                    (literal_element
                      (interpreted_string_literal) @test.name)))) @test.definition))))
      (for_statement
        body: (block
          (call_expression
            function: (selector_expression
              field: (field_identifier) @test.method)
              (#match? @test.method "^Run$")
            arguments: (argument_list
              (selector_expression
                field: (field_identifier) @test.field.name2
                (#eq? @test.field.name1 @test.field.name2)
		))))))

  • put cursor under capture @test.name

With programming and output:

  • create table_test.go file with content as described above
  • create run.lua file with content
local q = require"vim.treesitter.query"

local function i(value)
    print(vim.inspect(value))
end

local bufnr = 9 -- output Go test file buffer number with `:echo bufnr()`

local language_tree = vim.treesitter.get_parser(bufnr, 'go')
local syntax_tree = language_tree:parse()
local root = syntax_tree[1]:root()

local query = vim.treesitter.parse_query('go', [[
(block
      (short_var_declaration
        left: (expression_list
          (identifier) @test.cases)
        right: (expression_list
          (composite_literal
            body:(literal_value
              (literal_element
                (literal_value
                  (keyed_element
                    (literal_element
                      (identifier) @test.field.name1)
                    (literal_element
                      (interpreted_string_literal) @test.name)))) @test.definition))))
      (for_statement
        body: (block
          (call_expression
            function: (selector_expression
              field: (field_identifier) @test.method)
              (#match? @test.method "^Run$")
            arguments: (argument_list
              (selector_expression
                field: (field_identifier) @test.field.name2
                (#eq? @test.field.name1 @test.field.name2)
		))))))   

]])

for _, captures, metadata in query:iter_matches(root, bufnr) do
    i(q.get_node_text(captures[3], bufnr))
end
  • split window having Go test in one part and lua in another
  • execute lua file :luafile %

You will see and output such as

'"AccessDenied2"'
'"AccessDenied3"'
'"AccessDenied4"'
'"AccessDenied5"'
'"AccessDenied6"'

Expected behavior

vim.treesitter captures each node successfully

Neovim version (nvim -v)

NVIM v0.8.1

Vim (not Nvim) behaves the same?

vim doesn't support tresitter natively

Operating system/version

macOS 13.1 (22C65)

Terminal name/version

kitty 0.26.5

$TERM environment variable

tmux-256color

Installation

homebrew

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions