Search code examples
neovimtreesitter

How to create a new capture group with treesitter for updating highlight priority in neovim?


Just as a preface - I'm very new to Neovim (installed and configured it last week), so forgive me for my knowledge gaps.

I'm trying to update the priority defined by treesitter for the @lsp.typemod.variable.declaration.typescriptreact highlight group, since it has the same priority as @lsp.typemod.variable.readonly.typescriptreact and I would like the former group to take priority. My goal is to colour variable declarations with the same highlight colour as Type (in my case, yellow), while keeping non-declarations the same colour as @constant.

enter image description here

I tried using highlight link, but since they have the same priority, sometimes the former group takes precedence and sometimes the latter group takes precedence.

From the docs and from reading online, it seems like creating a new capture group associated with @lsp.typemod.variable.declaration.typescriptreact and setting a higher priority would be the solution here.

Unfortunately, everything I've tried so far doesn't seem to work. I've created a highlights.scm folder under nvim/after/queries/tsx/highlights.scm and added this code:

;; extends

((variable_declaration) @lsp.typemod.variable.declaration.typescriptreact (#set! "priority" 128))

And in my setup function for treesitter I've added this code (using lazy.nvim):

  {
    'nvim-treesitter/nvim-treesitter',
    opts = {
      ...
      highlight = {
        enable = true,
        additional_vim_regex_highlighting = false,
        custom_captures = {
          ["variable_declaration"] = "Type"
        }
      },
    },
    ...
  }

Here, I'm attempting to map the variable_declaration capture group that I've just defined to the Type highlight colour.

I'm sure I'm missing something obvious here, but I've been banging my head against the wall trying tons of different solutions so I figured I'd bring my question here.

Thanks for the help!


Solution

  • Alright, I figured it out.

    Needed to RTFM to learn the Treesitter query syntax and it worked like a charm. I used :InspectTree to get the capture group, and :Inspect to see whether my custom capture group was recognized by treesitter.

    Here what I read to figure out the syntax:

    nvim/after/queries/typescript/highlights.scm

    ;; extends
    
    (
     (variable_declarator
       name: (identifier) @variable_declaration 
     ) 
     (#set! "priority" 128)
    )
    
    (
     (variable_declarator
      name: (array_pattern
        (identifier) @declaration_array_member
          ))
     (#set! "priority" 128)
     )
    

    Here, the first query is grabbing all identifiers that appear in a variable_declarator and sets the name of the identifier to @variable_declaration. The second capture group is grabbing all identifiers that appear in array_patterns and naming those identifiers @declaration_array_member. The second one I'm using for destructuring arrays (eg. const [foo, bar] = someFunction()).

    For some reason the "custom_captures" prop in the Treesitter setup function wasn't working for me, so I ended up using highlights instead.

    nvim/lua/plugins.lua

      {
        'nvim-treesitter/nvim-treesitter',
        opts = {
          ...
          highlight = {
            enable = true,
            additional_vim_regex_highlighting = false,
          -- Removed since it wasn't working
          -- custom_captures = {
          -- ["variable_declaration"] = "Type"         
          -- }
          },
        },
        config = function()
        vim.cmd([[
         highlight! link @variable_declaration @type
         highlight! link @declaration_array_member @type
        ]])
        
        ...
        end
        ...
      }
    

    I hope this helps somebody else if they're also stuck with a similar problem.

    TL;DR: RTFM.