HiPhish / rainbow-delimiters.nvim

Rainbow delimiters for Neovim with Tree-sitter
https://gitlab.com/HiPhish/rainbow-delimiters.nvim
Apache License 2.0
466 stars 34 forks source link

[Bug] With tsx, highlighting of delimiters is inconsistent when trying to include attribute names #88

Closed noomly closed 5 months ago

noomly commented 5 months ago

The current tsx query (at queries/tsx/rainbow-delimiters.scm) works correctly but is only highlights tags, as illustrated here: 2024_01_17-16_06_21_904549567

I would like it to highlight the attributes names as well. I've tried modifying the query linked above to do this, and came up with:

; inherits: typescript

(jsx_element
  open_tag: (jsx_opening_element
              "<" @delimiter
              name: (identifier) @delimiter
              attribute: (jsx_attribute
                           (property_identifier) @delimiter)?
              ">" @delimiter)
  close_tag: (jsx_closing_element
               "</" @delimiter
               name: (identifier) @delimiter
               ">" @delimiter @sentinel)) @container

(jsx_element
  open_tag: (jsx_opening_element
              "<" @delimiter
              name: (member_expression) @delimiter
              attribute: (jsx_attribute
                           (property_identifier) @delimiter)?
              ">" @delimiter)
  close_tag: (jsx_closing_element
              "</" @delimiter
               name: (member_expression) @delimiter
              ">" @delimiter @sentinel)) @container

(jsx_self_closing_element
  "<" @delimiter
  name: (identifier) @delimiter
  attribute: (jsx_attribute
               (property_identifier) @delimiter)?
  "/>" @delimiter @sentinel) @container

(jsx_self_closing_element
  "<" @delimiter
  name: (member_expression) @delimiter
  attribute: (jsx_attribute
               (property_identifier) @delimiter)?
  "/>" @delimiter @sentinel) @container

(jsx_expression
  "{" @delimiter
  "}" @delimiter @sentinel) @container

Which produces the following result: 2024_01_17-16_07_02_961896557

It does include the attribute tags in the highlighting but it now has some inconsistencies. For example, you can see in the screenshot that for the element Text.h1, the opening bracket of the opening tag and the closing bracket of the closing tag are inconsistent with the color of the rest of the element. Is there something wrong with my query or is this a bug with rainbow-delimiters?

I'm using Neovim v0.9.4.

HiPhish commented 5 months ago

Your pattern is too complicated. Since you want to highlight the entire opening and closing tag you can capture the entire thing.

(jsx_element
  (jsx_opening_element) @delimiter
  (jsx_closing_element) @delimiter @sentinel) @container
noomly commented 5 months ago

Thank you for taking a look!

The issue with your solution is that I'd like to keep the syntax highlighting on the attribute values... I specifically want to only include the attribute names in the capture, and I can't really see how to make the capture "less complicated" with that in mind. By the way, it doesn't seem to be much more complicated than the default query I linked, as it only adds the following:

attribute: (jsx_attribute
             (property_identifier) @delimiter)?

To a few statements, which doesn't seem excessive when compared to the original query?

I'm not familiar with the plugin's internals at all so I can't really tell where the inconsistencies I'm seeing are coming from. Is it an issue with the way I wrote the query? Or Is rainbow-delimiters currently unable to reliably highlight captures in a single color once they reach a certain degree of complexity?

Danielkonge commented 5 months ago
(jsx_element
  open_tag: (jsx_opening_element
              "<" @delimiter
              name: (member_expression) @delimiter
              attribute: (jsx_attribute
                           (property_identifier) @delimiter)?
              ">" @delimiter)
  close_tag: (jsx_closing_element
              "</" @delimiter
               name: (member_expression) @delimiter
              ">" @delimiter @sentinel)) @container

should be

(jsx_element
  open_tag: (jsx_opening_element
              "<" @delimiter
              name: (member_expression) @delimiter
              attribute: (jsx_attribute
                           (property_identifier) @delimiter)*
              ">" @delimiter)
  close_tag: (jsx_closing_element
              "</" @delimiter
               name: (member_expression) @delimiter
              ">" @delimiter @sentinel)) @container

to get what you want. Note * instead of ?. ? is used if there can only be exactly zero or one of the given query, but here you have multiple in your example.

When I test the updated query with the Text.h1 part of your example, it fixes the highlighting.

A similar fix of ? to * should be applied in your other queries too, and I think it will give you the highlighting you are asking for.

HiPhish commented 5 months ago

The issue with your solution is that I'd like to keep the syntax highlighting on the attribute values... I specifically want to only include the attribute names in the capture

Sorry, I misunderstood you then. In that case @Danielkonge is correction, you need to use the * quantifier instead of ?. It works similar to regular expressions in that Tree-sitter will never match too few or too many nodes, but exactly as many as you specify. Here is what it looks like for me:

Screenshot_20240121_190842

Notice how style, class and foo all have the same colour as the tag name.

noomly commented 5 months ago

This works exactly as expected, thank you both. And many thanks for your work on the plugin!