nvim-treesitter / nvim-treesitter

Nvim Treesitter configurations and abstraction layer
Apache License 2.0
10.7k stars 894 forks source link

How to highlight JSX elements? #94

Closed JoosepAlviste closed 4 years ago

JoosepAlviste commented 4 years ago

Describe the bug I'm trying to add a custom highlighting color to JSX elements, but am failing to do so. I have the following query in after/queries/javascript/highlights.scm:

(jsx_text) @function

But when I open Neovim, then I get this error:

Error detected while processing <home dir>/.local/share/nvim/plugged/nvim-treesitter/plugin/nvim-treesitter.vim:
line   20:
E5108: Error executing lua ...m/HEAD-a0a84fc/share/nvim/runtime/lua/vim/treesitter.lua:127: query: invalid node type at position 3054

I saw that the tree-sitter-javascript parser includes the JSX queries in highlights-jsx.scm not highlights.scm. Could that be the reason why it's failing for me? I tried to move this query to highlights-jsx.scm but it doesn't look like that file is read.

To Reproduce Here is a minimal case to reproduce the problem:

init.vim:

call plug#begin(stdpath('data') . '/plugged')
Plug 'nvim-treesitter/nvim-treesitter'
call plug#end()

syntax off

lua <<EOF
require'nvim-treesitter.configs'.setup {
    highlight = {
        enable = true,
    },
    incremental_selection = {
        enable = false,
    },
    ensure_installed = {'javascript'}
}
EOF

after/queries/javascript/highlights.scm:

(jsx_text) @function

An example JSX file (MyComponent.js):

import React from 'react';

const MyComponent = () => (
  <div>Hello World</div>
);

export const MyComponent;

Expected behavior I would expect there to not be an error and the JSX text element should be highlighted with the highlight group I specified.

Output of :checkhealth nvim_treesitter

health#nvim_treesitter#check
========================================================================
  - ERROR: Failed to run healthcheck for "nvim_treesitter" plugin. Exception:
    function health#check[21]..health#nvim_treesitter#check, line 1
    Vim(lua):E5108: Error executing lua ...m/HEAD-a0a84fc/share/nvim/runtime/lua/vim/treesitter.lua:127: query: invalid node type at position 3054

Here is the health check results if I remove the query:

health#nvim_treesitter#check
========================================================================
## Installation
  - OK: `git` executable found.
  - OK: `cc` executable found.

## typescript parser healthcheck
  - OK: typescript parser found.
  - OK: `locals.scm` found.
  - OK: `highlights.scm` found.

## javascript parser healthcheck
  - OK: javascript parser found.
  - OK: `locals.scm` found.
  - OK: `highlights.scm` found.

## tsx parser healthcheck
  - OK: tsx parser found.
  - OK: `locals.scm` found.
  - OK: `highlights.scm` found.

## Missing parsers
  - WARNING: Some parsers are not installed:
    csharp
    html
    c
    regex
    swift
    java
    python
    nix
    yaml
    elm
    cpp
    vue
    lua
    ruby
    ocaml
    go
    scala
    haskell
    rust
    json
    toml
    css
    julia
    markdown
    php
    bash
    - ADVICE:
      - Install them using `:TSInstall language

Output of nvim --version

NVIM v0.5.0-a0a84fc9e
Build type: Release
LuaJIT 2.0.5
Compilation: /usr/local/Homebrew/Library/Homebrew/shims/mac/super/clang -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -DNDEBUG -Wall -Wextra -pedantic -Wno-unused-parameter -Wstrict-prototypes -std=gnu99 -Wshadow -Wconversion -Wmissing-prototypes -Wimplicit-fallthrough -Wvla -fstack-protector-strong -fno-common -fdiagnostics-color=auto -DINCLUDE_GENERATED_DECLARATIONS -D_GNU_SOURCE -DNVIM_MSGPACK_HAS_FLOAT32 -DNVIM_UNIBI_HAS_VAR_FROM -DMIN_LOG_LEVEL=3 -I/tmp/neovim-20200614-7434-2psdhv/build/config -I/tmp/neovim-20200614-7434-2psdhv/src -I/usr/local/include -I/tmp/neovim-20200614-7434-2psdhv/deps-build/include -I/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/include -I/usr/local/opt/gettext/include -I/tmp/neovim-20200614-7434-2psdhv/build/src/nvim/auto -I/tmp/neovim-20200614-7434-2psdhv/build/include
Compiled by me@my-MacBook-Pro.local

Features: +acl +iconv +tui
See ":help feature-compile"

   system vimrc file: "$VIM/sysinit.vim"
  fall-back for $VIM: "/usr/local/Cellar/neovim/HEAD-a0a84fc/share/nvim"

Run :checkhealth for more info

Additional context

I tried a bunch of other JSX related queries as well and none of them seemed to work. For example:

(jsx_opening_element (identifier) @tag)
theHamsta commented 4 years ago

Hi. This is really strange since nvim-treesitter is parsing the AST of your file correctly with jsx_text as valid node type:

AST of example file:

program [0, 0] - [8, 0])
  import_statement [0, 0] - [0, 26])
    import_clause [0, 7] - [0, 12])
      identifier [0, 7] - [0, 12])
    source: string [0, 18] - [0, 25])
  lexical_declaration [2, 0] - [4, 2])
    variable_declarator [2, 6] - [4, 1])
      name: identifier [2, 6] - [2, 17])
      value: arrow_function [2, 20] - [4, 1])
        parameters: formal_parameters [2, 20] - [2, 22])
        body: parenthesized_expression [2, 26] - [4, 1])
          jsx_element [3, 2] - [3, 24])
            open_tag: jsx_opening_element [3, 2] - [3, 7])
              name: identifier [3, 3] - [3, 6])
            jsx_text [3, 7] - [3, 18])
            close_tag: jsx_closing_element [3, 18] - [3, 24])
              name: identifier [3, 20] - [3, 23])
  export_statement [6, 0] - [6, 25])
    declaration: lexical_declaration [6, 7] - [6, 25])
      variable_declarator [6, 13] - [6, 24])
        name: identifier [6, 13] - [6, 24])

Same result parsing result when using nvim-treesitter. Capturing @parenthesized_expression works, @jsx_element works not, @jsx_text neither.

JoosepAlviste commented 4 years ago

Hey! It is weird indeed. I think that the angle brackets within the JSX (< and >) get highlighted as if they were operators:

image

Maybe the AST is correct, but the issue is only related to highlighting?

vigoux commented 4 years ago

Hi ! thanks for reporting that, can you try adding a newline at the start of you custom query ? The error seems to be related to a malformed query...

JoosepAlviste commented 4 years ago

Hey! I tried that but am still getting the same error. I printed out the query string here, it might help:

; Types

; Javascript
; Special identifiers
;--------------------

((identifier) @constant
 (#match? @constant "^[A-Z_][A-Z\\d_]+$"))

((shorthand_property_identifier) @constant
 (#match? @constant "^[A-Z_][A-Z\\d_]+$"))

((identifier) @constructor
 (#match? @constructor "^[A-Z]"))

((identifier) @variable.builtin
 (#match? @variable.builtin "^(arguments|module|console|window|document)$"))

((identifier) @function.builtin
 (#eq? @function.builtin "require"))

; Function and method definitions
;--------------------------------

(function
  name: (identifier) @function)
(function_declaration
  name: (identifier) @function)
(method_definition
  name: (property_identifier) @function.method)

(pair
  key: (property_identifier) @function.method
  value: (function))
(pair
  key: (property_identifier) @function.method
  value: (arrow_function))

(assignment_expression
  left: (member_expression
    property: (property_identifier) @function.method)
  right: (arrow_function))
(assignment_expression
  left: (member_expression
    property: (property_identifier) @function.method)
  right: (function))

(variable_declarator
  name: (identifier) @function
  value: (arrow_function))
(variable_declarator
  name: (identifier) @function
  value: (function))

(assignment_expression
  left: (identifier) @function
  right: (arrow_function))
(assignment_expression
  left: (identifier) @function
  right: (function))

; Function and method calls
;--------------------------

(call_expression
  function: (identifier) @function)

(call_expression
  function: (member_expression
    property: (property_identifier) @function.method))

; Variables
;----------

(formal_parameters (identifier) @variable.parameter)

(identifier) @variable

; Properties
;-----------

(property_identifier) @property

; Literals
;---------

(this) @variable.builtin
(super) @variable.builtin

(true) @boolean
(false) @boolean
(null) @constant.builtin
(comment) @comment
(string) @string
(regex) @string.special
(template_string) @string
(number) @number

; Punctuation
;------------

(template_substitution
  "${" @punctuation.special
  "}" @punctuation.special) @embedded

";" @punctuation.delimiter
"." @punctuation.delimiter
"," @punctuation.delimiter

"--" @operator
"-" @operator
"-=" @operator
"&&" @operator
"+" @operator
"++" @operator
"+=" @operator
"<" @operator
"<<" @operator
"=" @operator
"==" @operator
"===" @operator
"=>" @operator
">" @operator
">>" @operator
"||" @operator
"??" @operator

"(" @punctuation.bracket
")" @punctuation.bracket
"[" @punctuation.bracket
"]" @punctuation.bracket
"{" @punctuation.bracket
"}" @punctuation.bracket

; Keywords
;----------

[
"if"
"else"
"switch"
"case"
"default"
] @conditional

[
"import"
"from"
"as"
] @include

[
"for"
"of"
"do"
"while"
"continue"
] @repeat

[
"async"
"await"
"break"
"catch"
"class"
"const"
"debugger"
"delete"
"export"
"extends"
"finally"
"function"
"get"
"in"
"instanceof"
"let"
"new"
"return"
"set"
"static"
"switch"
"target"
"throw"
"try"
"typeof"
"var"
"void"
"with"
"yield"
] @keyword

((jsx_text) @function)[
"abstract"
"declare"
"enum"
"export"
"implements"
"interface"
"keyof"
"namespace"
"private"
"protected"
"public"
"type"
] @keyword

(readonly) @keyword
(type_identifier) @type
(predefined_type) @type.builtin

(type_arguments
  "<" @punctuation.bracket
  ">" @punctuation.bracket)

; Variables

(required_parameter (identifier) @variable.parameter)
(optional_parameter (identifier) @variable.parameter)
vigoux commented 4 years ago

Could you try #102 to see if that solves the issue ?

theHamsta commented 4 years ago

The weird thing is really: if you are directly on a jsx node: nvim-treesitter/statusline tells you that the current node is jsx_element or jsx_text. But Neovim insists that jsx_text is not a valid node. Maybe its missing from the list of named nodes that you can ask the tree sitter parser for.

I tried to recompile the parser and give jsx nodes different names but the result stays the same.

This seems to be a Nvim bug not related to this plugin.

vigoux commented 4 years ago

Here is the thing that bugs me : when you look at the query string above you will se that there is no space after the ((jsx_text) @function) match, and it goes directly to another match. I am not a pro on how the query parser works, but I think that it can be a problem.

JoosepAlviste commented 4 years ago

I played around a little bit and managed to have it working correctly a few times. It seems that when only the javascript parser is installed, then it works, but if the typescript parser is also installed, then it shows the error in the issue description.

To reproduce (following the instructions in the issue):

  1. Remove the typescript (and tsx) parsers:
    rm nvim-treesitter/parsers/typescript.so nvim-treesitter/parsers/tsx.so
  2. Open the MyComponent.js file
  3. See the correct highlight:
image
  1. Install the typescript parser with :TSInstall typescript
  2. Open the MyComponent.js file
  3. See the error above (and no highlighting)

So, it looks like there is some kind of a conflict between the parsers. I have no idea whether the problem could be specific to this plugin, Neovim's treesitter support, or the parsers.

vigoux commented 4 years ago

@kyazdani42 do you have some clues on this one ?

kyazdani42 commented 4 years ago

well i cannot reproduce...

kyazdani42 commented 4 years ago

just works fine for me, with the tsx/typescript parsers installed or withtout them. It shouldn't matter though.

kyazdani42 commented 4 years ago

but my neovim version is a little bit older. I'll update and come back with some result.

kyazdani42 commented 4 years ago

well i was wrong. Actually the issue does not raise when running the highlighting with TSBufEnable or TSEnableAll, but raises if i run highlighting on start

kyazdani42 commented 4 years ago

The problem is:

kyazdani42 commented 4 years ago

Also it is not happening on TSBufEnable and such because when running these, it will only enable the given feature on the given buffers, and it will not try to check if the typescript parser works so it doesn't fail :) PS: the culprit here is the get_query function.

JoosepAlviste commented 4 years ago

Thanks for looking into it! I can confirm that a workaround for javascript files is to add TSBufEnable highlight to my ftplugin/javascript.vim.

However, the same thing doesn't work for typescript files. Probably because typescript queries inherit from javascript queries (where I've defined (jsx_text) @function). If I set the TypeScript file's filetype to typescriptreact and then run :TSBufEnable highlight, then it works.

Is there a way to only include JSX queries for javascript and tsx filetypes and ignore them for typescript files?

kyazdani42 commented 4 years ago

yup because typescriptreact loads tsx, which understand jsx. What we might need to do here is either duplicate the queries (which is not really a good option), or add query extensions depending on the language, thus javascript could import a jsx_hl.scm query file and not typescript, but typescript could still import javascript without javascript importing the jsx definitons. Another thing we could do is not fail each time a query name is not recognized, but i think this is another subject.

kyazdani42 commented 4 years ago

I think this is not yet fixed because we need to define parsers per filetype.

luisiacc commented 3 years ago

Hey! It is weird indeed. I think that the angle brackets within the JSX (< and >) get highlighted as if they were operators:

image

Maybe the AST is correct, but the issue is only related to highlighting?

Whick onedark repository is that colorscheme from?

JoosepAlviste commented 3 years ago

@luisiacc Hey! That is a slightly modified version of this material theme (palenight variant): https://github.com/kaicataldo/material.vim. You can see the customizations in my dotfiles.

luisiacc commented 3 years ago

So I have a little doubt here, if I want to highlight differenltly the jsx props the(onClick, href, customProps, etc...) what highlight group should I target, because when I do :TSHighlightCapturesUnderCursor it only shows @TSProperty, but that is very general and would highlight much more, what should I do if I want to just highlight the jxs props?.

kyazdani42 commented 3 years ago

jsx props are object properties, you would loose semantic highlighting by changing their highlight. If you still wish to override these, you could override the jsx query to set a different highlight group for the props. I'll leave you to the docs to understand how to do this :) good luck

niyabits commented 3 years ago

I am still getting a similar issue where in my .js file I don't get jsx syntax highlighting even though in Treesitter Playground it parses JSX correctly.

It works correctly on .tsx files though

I am on neovim version - NVIM v0.5.0-dev+1178-gf0ace6d41 I just tried updating Treesitter and I am still continue having this issue.

Can somebody help? image

kyazdani42 commented 3 years ago

mine is properly highlighted and i've got the same version as you. Could you :TSHighlightCaptureUnderCursor over the component to see which highlight groups get applied ? By looking at your code, i'm pretty sure TSConstructor is not highlighted with your colorscheme.

niyabits commented 3 years ago

@kyazdani42 This is what I am getting.

image

kyazdani42 commented 3 years ago

This is correct. Looks like your colorscheme doesn't highlight TSConstructor which means you don't get any color for this group. Maybe you should look here :)

Delhi-Babu commented 3 years ago

looks like this issue still exists, steps to reproduce

  1. install latest nvim
  2. update treesitter
  3. open any jsx file (for first time opening the buffer lacks most of the highlights) changing to another buffer and going back to the first opened buffer (bam every highlight is applied)
  4. looks like tsx files works properly or using :bufdo e after nvim is launched solves the problem
linkinmedo commented 3 years ago

I really wonder why this is closed, I still have this issue to this day. Highlight works fine for tsx files and there is no highlight in js/jsx files, no matter what I do I can't get highlighting.

stsewd commented 3 years ago

@linkinmedo please open a new issue with the steps and files to reproduce the problem with a minimal init.vim