gorbit99 / codewindow.nvim

MIT License
441 stars 17 forks source link

Question: would it be possible for treesitter highlights to stretch fully? #54

Open pocco81 opened 1 year ago

pocco81 commented 1 year ago

(I'm not very familiar with treesitter's internals or terminology, so please bear with me)

I'm not sure if the following two examples regarding syntax highlighting count as expected behavior, but if they do, I'd like to "fix" them:

Example 1

Let's say I have a license file:

 ... the terms of this License, in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied...

treesitter highlights the a) ... line teal (in my particular case). That line has around 350 chars, all of which are teal, however Codewindow only highlights the beginning of them:

image

(This is an average GPL v3 license. It has many a), b), c), ..., points that are all highlighted green, but they appear all white (default fg color))

It gets worse when I set width_multiplier = 1... there is no color at this point:

image

Example 2

This also happens while editing some actual code. For instance, this Lua chunk:

image

It appears almost entirely white, even though the actual code in the buffer looks like a rainbow with only a couple words having a white fg.

Questions

  1. How does Codewindow calculate the length of the highlights?
  2. What would it take for it to render colors appropriately and not just truncate most of it and fall back to <user's fg color>?
gorbit99 commented 1 year ago

Interesting, I must be looping through the highlighted area incorrectly. Let me investigate and write up something quickly.

So how treesitter works, is that it gives you a bunch of highlights with starts and ends. This can be translated over to neovim ranges. This can be seen here:

          local start_row, start_col, end_row, end_col =
            ts_utils.get_vim_range({ vim.treesitter.get_node_range(node) }, buffer)

I then gather these up into a table[^1], that, for each character in your code, stores what highlights are active there. For example, if you have a line like this:

local var = 5

all of the characters of "local" would get a keyword in their table fields, = would get a symbol, 5 would be a number, etc etc. After this I go through each rendered character and decide which highlight(s) to draw for that based on the most common ones that are in the area they occupy.

The issue probably happens, because when I ask for a vim range, what I get is a starting row and column and an ending row and column. I use this as the top left and bottom right corners of a rectangle. My assumption is that it's actually the character in the string I should start going from and the character in the string I should stop at. This would cause an issue like this, if the ending point of the highlight doesn't reach as far as the longest line in that highlight.

So tl;dr, the solution is quite simple, would need to change lines 106-111, so that instead of doing a double for loop, it just goes through the lines until it reaches the correct character.

This would have a tiny bit of a performance penalty, since now it would simply cover more characters, but theoretically there could be an optimized approach, where full lines are treated in one go instead of having to loop through and check each time.

If you want to go ahead and try your hand at a fix, I appreciate PRs, but I won't be in a place to fix this until at least later tonight, more likely tomorrow.

Interestingly, I remember thinking about this and fixing it, but apparently I was way too high on sleeplessness at that time and I just imagined the whole thing.

[^1]: for the sake of correctness, at this point they get collected into buckets made for each rendered character, they don't actually have individual cells in the table

pocco81 commented 1 year ago

If you want to go ahead and try your hand at a fix, I appreciate PRs, but I won't be in a place to fix this until at least later tonight, more likely tomorrow.

I think I'm going to let this one to you, since you are more familiar with treesitter and the codebase. Alternatively, if you put the fix up on a draft I could try to help, but I can't promise anything.

pocco81 commented 1 year ago

Hey @gorbit99! I was wondering when this fix would be coming along.

Thanks!

gorbit99 commented 1 year ago

Sorry, been a bit busy the last few weeks, I'll get to it as soon as I can.