tomtom / tcomment_vim

An extensible & universal comment vim-plugin that also handles embedded filetypes
http://www.vim.org/scripts/script.php?script_id=1173
GNU General Public License v3.0
1.4k stars 103 forks source link

neovim + treesitter + vue.js + tcomment_vim not working in JS section #284

Closed eduardoarandah closed 2 years ago

eduardoarandah commented 3 years ago

Comments aren't working fine with treesitter

I'm not sure if this is an issue to be reported here or in https://github.com/ikatyang/tree-sitter-vue so I'll post in both sites

neovim + treesitter commenting the same in html, js

image

Debug info:

:echo tcomment#debug#CollectInfo()

on template section:

TCOMMENT: &ft = vue => vue
TCOMMENT: stx =  => 
TCOMMENT: ct  = {'_args': {'beg': 98, 'fallbackFiletype': '', 'end': 98, 'filetype': 'vue', 'comment_mode': ''}, 'commentstring': '/*%s*/', 'mode': '', 'whitespace': 'both'}

on js section:


TCOMMENT: &ft = vue => vue
TCOMMENT: stx =  => 
TCOMMENT: ct  = {'_args': {'beg': 115, 'fallbackFiletype': '', 'end': 115, 'filetype': 'vue', 'comment_mode': ''}, 'commentstring': '/*%s*/', 'mode': '', 'whitespace': 'both'}

vim + polyglot works fine!

image

on template part:

TCOMMENT: &ft = vue => vue
TCOMMENT: stx = htmlTag => htmlTag
TCOMMENT: ct  = {'_args': {'beg': 55, 'fallbackFiletype': '', 'end': 55, 'filetype': 'vue', 'comment_mode': ''}, 'commentstring': '<!-- %s -->', 'replacements': {'&': '&#38;', '-': '&#45;'}, 'mode': '', 'filetype': 'html'}

on js part:

TCOMMENT: &ft = vue => vue
TCOMMENT: stx = jsObjectSeparator => javascriptObjectSeparator
TCOMMENT: ct  = {'rxmid': '', 'rxend': '', '_args': {'beg': 76, 'fallbackFiletype': '', 'end': 76, 'filetype': 'vue', 'comment_mode': ''}, 'commentstring': '// %s', 'commentstring_rx': '\%%(// %s\|/* %s */\)', 'mode': '', 'filetype': 'javascript', 'replacements': {'*/': {'subst': '|)}>#', 'guard_rx': '^\s*/\?\*'}, '/*': {'subst': '#<{(|', 'guard_rx': '^\s*/\?\*'}}, 'rxbeg': '\*\+'}
eduardoarandah commented 3 years ago

issue also reported in https://github.com/ikatyang/tree-sitter-vue/issues/8

eduardoarandah commented 3 years ago

If you're here with same issue, you can use non-treesitter syntax with:

if (has("nvim"))
  " Treesitter
  Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'}  " We recommend updating the parsers on update
endif

" also install Vue syntax
Plug 'posva/vim-vue', { 'for': ['vue' ] }

and later, add disable to vue

" treesitter enable
if (has("nvim"))
lua <<EOF
require'nvim-treesitter.configs'.setup {
  ensure_installed ={ "javascript", "json", "css", .... here others....  }, -- one of "all", "maintained" (parsers with maintainers), or a list of languages
  highlight = {
    enable = true,
    disable = { "vue" }
  },
  indent = {
    enable = false
  },
}
EOF
endif
gegoune commented 3 years ago

Not sure that disabling treesitter should be an acceptable solution here.

eduardoarandah commented 3 years ago

Not sure that disabling treesitter should be an acceptable solution here.

@cloggier Agree. It's just a temporary workaround. In debug info there's some clues on what might be happening: 'posva/vim-vue' reports filetype: html and javascript. treesitter reports "vue" everywhere

I'd be glad to help but I've no idea how treesitter-vue works

gegoune commented 3 years ago

treesitter-vue does very little actually, it only injects other languages for each block (js, css, html). It shouldn't be over complicated to retrieve what parser/grammar is used in a block under cursor and set comment string accordingly.

gegoune commented 3 years ago

And @joosepalviste did just that in amazing https://github.com/JoosepAlviste/nvim-ts-context-commentstring, which works with any commentstringbased commenting plugin.

eduardoarandah commented 3 years ago

@cloggier thanks for the tip!

Installed that plugin and is setting up comment string correctly https://github.com/JoosepAlviste/nvim-ts-context-commentstring

However, tcomment is not commenting based on that info.

(Moved to https://github.com/tpope/vim-commentary/ and it works fine)

Cursor in JS part:

image

Cursor in HTML part:

image

tomtom commented 3 years ago

tcomment also uses commentstring if no special comment definition is defined. If tcomment doesn't use commentstring, then something in autoload/tcomment/types/default.vim or maybe syntax based syntax definition interferes with it.

I don't do JS/JSX/etc myself so I have to rely on pull requests from users. My main problem with these bug reports is that they are selfcontradictory and inconsistent to some extent -- at least that what it appears to me.

I a simpler comment plugin suffices for you needs please use that one.

If you want to continue using tcomment, please tell me exactly what kind of behaviour you observe under exacly which conditions and what behaviour you expect. Just telling me "Comments aren't working fine with treesitter" isn't exactly useful because I have no idea what treesitter is and I don't have the time to look it up.

eduardoarandah commented 3 years ago

@tomtom neovim 0.5 (not released yet, stable is 0.4.4) is promoting treesitter as an alternative to vim regex-based syntax.

Treesitter is a parsing library (builds a syntax tree) and is supposed to have advantages over regex.

Is there a list of variables that I can dump to make this issue productive? this might be an issue with the other plugin (treesitter) not this one, of course!

Links:

https://github.com/nvim-treesitter/nvim-treesitter

https://github.com/tree-sitter/tree-sitter

tomtom commented 3 years ago

Do I get this right that synIDattr(synID(...), 'name') doesn't work with treesitter? How could you get the syntax name at the cursor position then?

eduardoarandah commented 3 years ago

I've little experience with this, if you want to play with treesitter parsing, you can do this:

1) install neovim nightly https://gist.github.com/eduardoarandah/40e18928363d0462b30aa18ffe2e1fbe

2) In your .vimrc add treesitter and the playground. Example with VimPlug:

if (has("nvim"))
  " Treesitter
  Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'}  " We recommend updating the parsers on update
  Plug 'nvim-treesitter/playground' 
endif

3) After call plug#end() configure treesitter, example:

" treesitter enable
if (has("nvim"))
lua <<EOF
require'nvim-treesitter.configs'.setup {
  ensure_installed ={ "javascript", "json", "css", "php", "html", "python", "bash", "regex", "ruby", "yaml", "jsonc", "tsx", "lua", "vue" }, -- one of "all", "maintained" (parsers with maintainers), or a list of languages
  highlight = {
    enable = true,
    disable = { "php" },  -- list of language that will be disabled
  },
  indent = {
    enable = false
  },
}
EOF
endif

4) Now you can see treesitter parsing with TSPlayground check video:

https://user-images.githubusercontent.com/4065733/112895329-36948b00-909a-11eb-8d61-84bd742a1c38.mp4

I don't know much more about how to query the parser to get the exact syntax info. This plugin code might be helpful: https://github.com/JoosepAlviste/nvim-ts-context-commentstring

tomtom commented 3 years ago

Without further help, I don't think I can help much here.

You could try to set g:tcomment#filetype#guess_vue = 0 to disable syntax based commenting. tcomment should then use the value of commentstring. In conjunction with that other plugin, this could work ... maybe.

WhyNotHugo commented 2 years ago

I'm having the same issue too (pretty much same setup: nvim + treesitter).

The issue is just with vuejs files (which embed multiple languages into different blocks). No matter where I comment, this plugin always uses <-- %s --> to comment -- which is not valid in javascript blocks.

In other words, it seems that the plugin won't properly detect which language is the one under the cursor.

I hacked around this for a while (this was challenging, but I'm happy with the solution I've found), and managed to write this snippet to determine the language at the cursor's current position. It works with just one level of nested languages, which I think is a reasonable limitation:

local function print_language_at_cursor()
  local parsers = require("nvim-treesitter.parsers")

  local root = parsers.get_parser()
  local cursor = vim.api.nvim_win_get_cursor(0)

  local range = { cursor[1], cursor[2], cursor[1], cursor[2] }
  local node_lang = root

  -- TODO: Should be able to use `root:for_each_tree()` with a callback to get
  -- the last leaf language that contains this range.
  for _, child in pairs(root:children()) do
    if child:contains(range) then
      node_lang = child
    end
  end

  print(vim.inspect(node_lang:lang()))
end
-- Mapping I used to test this:
vim.keymap.set("n", "<Leader>I", print_language_at_cursor)

I tested this with vue files, and it recognises typescript and css just fine. The HTML portion is recognised as vue, but that's kind find, since both vue and html use the same comment format (this is also the correct language, since them template portion of vue files has special syntax that's not strictly HTML).

WhyNotHugo commented 2 years ago

Oh, this is actually pretty close to what Comment.nvim does, so I think I'll just use that (it seems like a better fit for neovim+treesitter) never mind, it has all kind of quirky bugs.

Thanks for this plugin; it's served me well many many years! :beers:

WhyNotHugo commented 2 years ago

So I guess that including a bunch of lua code inside this plugin is too out-of-scope, and explicit tree-sitter support might be too invasive.

As a less invasive approach, I wonder if a new setting could be added (something like tcomment#commentstringFunc) which is a function that one can provide and returns the commentstring that should be used.

So basically, if this is set try and use it to determine commentstring, otherwise, use commentstring normally.

The key details her is that since this is a function, it can return a new value for commentstring depending on the current cursor position.

Thoughts?

tomtom commented 2 years ago

An alternative approach would be to set the variable b:commentstring on each cursor move or on CursorHold(I) events.

WhyNotHugo commented 2 years ago

Yup, I noticed that some plugins do that, but it seems inefficient, there's a lot of parsing and work getting done on each CursorHold. I'd rather the work be done only when needed (e.g.: when actually commenting a line).

Thanks for the change, I'll figure out the rest and leave the result for reference in case anyone else is interested.

tomtom commented 2 years ago

I'm open to pull requests. The only requirement is that the plugin keeps functional by default with vim8.

Since I don't use neovim (and since I don't plan to switch to neovim because I now use IntelliJ IDEA most of the time), I cannot contribute much though.

The proposal to implement a parameter à la tcomment#commentstringFunc should be easily doable. It would be nice though if you could contribute such a function for neovim users. Thanks.