HiPhish / rainbow-delimiters.nvim

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

[Bug]: Invalid highlighting after buffer changes from outside neovim #28

Closed LiadOz closed 1 year ago

LiadOz commented 1 year ago

Neovim version

0.9.1

Language affected

No response

Query

No response

Strategy

No response

Description

When a file content changes outside of neovim the existing buffer highlights are still the same, meaning that it may highlight characters that were in a position of brackets before the change. In believe this is the same issue as https://github.com/HiPhish/nvim-ts-rainbow2/issues/49#issue-1755563524 https://github.com/mrjones2014/nvim-ts-rainbow/issues/9 https://github.com/p00f/nvim-ts-rainbow/issues/112 I have submitted the following fix to one of the rainbow forks https://github.com/mrjones2014/nvim-ts-rainbow/pull/8 I believe it should be a similar fix here. To easily reproduce create a file called a.py with the following content:

hello
((()))

Then with another editor add a line before hello, when switching back to neovim you should see that hello has highlights.

HiPhish commented 1 year ago

Yes, that's a known issue. This will most likely take a good while to fix. In the meantime you can :edit the file to force highlighting to be fixed.

LiadOz commented 1 year ago

I don't think the solution should be too complex, here is a dirty way to achieve it:

diff --git a/plugin/rainbow-delimiters.lua b/plugin/rainbow-delimiters.lua
index 6dfbe70..59f811e 100644
--- a/plugin/rainbow-delimiters.lua
+++ b/plugin/rainbow-delimiters.lua
@@ -55,11 +55,18 @@ function attach(bufnr)
        end
        log.trace('Attaching to buffer %d with language %s.', bufnr, lang)

+       local first = true
        if lib.buffers[bufnr] then
-               if lib.buffers[bufnr].lang == lang then return end
-               -- The file type of the buffer has change, so we need to detach first
-               -- before we re-attach
-               detach(bufnr)
+               if lib.buffers[bufnr].lang == lang then
+                       local _, parser = pcall(get_parser, bufnr, lang)
+                       parser:invalidate(true)
+                       parser:parse()
+                       first = false
+               else
+                       -- The file type of the buffer has change, so we need to detach first
+                       -- before we re-attach
+                       detach(bufnr)
+               end
        end

        local parser
@@ -85,15 +92,17 @@ function attach(bufnr)
                log.warn('No strategy defined for %s', lang)
        end

-       parser:register_cbs {
-               on_detach = function(bnr)
-                       if not lib.buffers[bnr] then return end
-                       detach(bufnr)
-               end,
-               on_child_removed = function(child)
-                       lib.clear_namespace(bufnr, child:lang())
-               end,
-       }
+       if first then
+               parser:register_cbs {
+                       on_detach = function(bnr)
+                               if not lib.buffers[bnr] then return end
+                               detach(bufnr)
+                       end,
+                       on_child_removed = function(child)
+                               lib.clear_namespace(bufnr, child:lang())
+                       end,
+               }
+       end

        local settings = {
                strategy = strategy,

The idea here is to use lib.buffers[bufnr].lang to check if the buffer is already loaded then invalidate the current parser. Then you need to update all of the highlights in the buffer, in the global strategy calling on_attach will do a full update of all the highlights of the buffer. To make this prettier, an on_reload function can be added to the strategies which goes over the entire tree and updates all the highlights.

HiPhish commented 1 year ago

I like your idea, especially the on_reset function. However, when I press u to undo the edit the attach does not get called. It's still better than what we have now, so I will adopt it, but it is not perfect.

HiPhish commented 1 year ago

Can you please try the current master branch with a recent snapshot of Neovim 0.10? Undo will not work on 0.9 and if you redo after an undo there will be stray extmarks again. But it should work fine on 0.10.

chrisgrieser commented 1 year ago

I am on 0.9 and just tried the current master. The issue is fixed for me, and undo works fine for me.

LiadOz commented 1 year ago

@HiPhish works for me, thanks!