New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle different underlining styles supported by neovim #1469
Handle different underlining styles supported by neovim #1469
Conversation
This overhauls the drawing of underlines and actually implements the undercurl that was simulated with underdashes before. Implemented in this commit: * underline * underdouble * underdashed * underdotted * undercurl
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! This is great.
By the way, how did you even manage to set the "invalid" modifier names? :hi! Normal gui=underdouble
results into neovim yelling at me with "invalid value".
src/renderer/grid_renderer.rs
Outdated
UnderlineStyle::UnderCurl => { | ||
let p1 = (p1.x, p1.y - 2.); | ||
let p2 = (p2.x, p2.y - 2.); | ||
underline_paint | ||
.set_path_effect(None) | ||
.set_anti_alias(true) | ||
.set_style(skia_safe::paint::Style::Stroke); | ||
let mut path = Path::default(); | ||
path.move_to(p1); | ||
let mut i = p1.0; | ||
let mut sin = -2.; | ||
while i <= p2.0 { | ||
sin *= -1.; | ||
i += 4.; | ||
path.quad_to((i - 2., p1.1 + sin), (i, p1.1)); | ||
} | ||
canvas.draw_path(&path, &underline_paint); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your concerns about HiDPI and the curl appearing too thin are rightfully:
I think this could be patched up by making the line slightly thicker, doing less iterations of the loop and doing larger steps each time, though this is indeed tricky. To be honest, I don't think we'll be coming to a really aesthetic solution there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I was afraid of this.
To be fair: no terminal I've tested handles it any better than what we're seeing here. So, maybe we could just release this like this and then improve upon it in some way?
A quick win would be to make the line thickness a configuration option, as well as maybe the pattern length (which can be used to scale the dashes and dots as well). Trying to automatically render this the best way seems like a doomed idea, or at least much harder than the rest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Allowing configuration seems like the most sensible option. There's lots of cases where relying on the scale factor the system gives us is wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another idea would be to actually scale with the font height, but round the numbers so that they stay pixel perfect. Everything should still be 1px thick at low DPIs, but it should scale nicely after that, without any aliasing shenanigans. I'll see if I can come up with a quick example of this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, so, I worked on this a little and I'm a bit stuck.
On one hand, automatic scaling looks pretty nice:
On the other hand... this can't actually work consistently and this seems to be a limitation of the whole rendering strategy of neovide.
The issue is that everything is drawn asynchronously through a message queue, which works under the premise everything that'll get drawn (within a window) is on its own independent region of the screen, meaning there's no conflict anywhere.
But to draw thick underlines, we need them to be drawn between two lines. They can't be confined to the line the text belongs to, or they will simply strike through it at higher thicknesses (especially the undercurl). But by removing them from the line's canvas so they don't get clipped, they get randomly overwritten by the line below, leaving only two pixels to work with.
What's needed would be to redraw the underlines alone every time the line of text below them gets drawn. It seems pretty hard to do with how the code is currently set up, unless there's an easy solution I'm missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you're right, draw_foreground
only ever gets called with text fragments, and not the whole current text buffer. This is yet another issue which could be handled through keeping state about the whole text visible at all times, and also redrawing the line below when drawing underlines. But as of now, Neovide doesn't have such a facility.
For now, the line below "sometimes" overlapping the curl is as far as you can get without taking quite a few hoops in terms of re-writing code architecture, I fear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a little better when I:
- Draw lines from the bottom up instead of the top down when drawing everything
- Redraw the line above after any line that's individually drawn
But there are still plenty of glitches here and there. I'm hopeful they can be ironed out, but it'll all just be hacks for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright. Then feel free to push your changes, I'll create an issue about possible ways to approach the larger needed change after merging this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that's sensible.
For now, the automatic scaling works well so long as line thickness doesn't get above 1. Above that, underlines get clipped here and there. Perhaps it would make sense to put the automatic scaling behind a configuration option for now? I'll push those changes up for review.
The latest neovim versions have aligned with vim's names. Therefore, |
Yeah, this is fair. In this case you should be able to just match both patterns using the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Text rendering has one issue with lines not being redrawn when window size changes, this can be reproduced easily by changing the window size in floating window mode:
Else, one
:let g:neovide_underline_automatic_rescaling=v:true
:hi! Keyword gui=undercurl
later, I can confirm that clipping of the undercurl does happen, but I don't think it's too bad for now:
Nice work regardless.
(also, small sidenote since formatting seems to be quite your nemesis: check out |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! One last thing I'd like to have addressed before merging, though I'll just patch it myself quickly.
Alright. Truly, thank you! I'll merge this now. |
What kind of change does this PR introduce?
Did this PR introduce a breaking change?
Content
This overhauls the drawing of underlines and actually implements the
undercurl that was simulated with underdashes before.
Implemented in this PR:
underline
underdouble
underdashed
underdotted
undercurl
Points to note
underdotted
should be widened? I'm worried it'll look like a thin solid line on high-dpi screens.