This implements extended underlines; all alternative styles as well as custom underline colors, as defined in https://sw.kovidgoyal.net/kitty/underlines/
Underline style+color is stored in the extra row member. This is additional data that is only allocated when necessary. This is also where OSC-8 hyperlinks are stored. Just like OSC-8, the styled underlines are stored as ranges, covering one or more cells.
We only use the extra row data when we actually need to; legacy underlines do not require it. We only need it when a custom style, or a custom color has been set.
TODO
- More testing, especially text reflow
- Measure memory usage
- vtebench
- See if we can share more code between OSC-8 and underlines
- Additional terminfo capabilities (we now define
Su,Smulx,Setulc)
This PR re-uses the logic for rendering the underlines from #1099.
This PR replaces #1099
Closes #828
Memory usage
I haven't measured it, but analyzing it, I think the current implementation is acceptable.
- The cell struct has not been changed, which means no additional memory usage unless the application actually emits styled underlines (or OSC-8 hyperlinks).
- The
extrarow member is still (i.e. like before, with OSC-8) allocated on-demand, which means no additional row memory usage until the application emits styled underlines (or OSC-8 hyperlinks) - The
extrarow member has grown in size - it now has two "range" arrays rather than one. Each range array is 8+4+4 bytes. This is the only place where we've increased the size of an already existing data structure. So, in an application that only emits OSC-8, memory usage has gone up by 12 bytes per row. - Each range (for styled underlines) is 4+4+16 = 24 bytes. They would be 20 bytes, except there's a union in there, and the OSC-8 part of that is 16 bytes vs. 12 bytes for styled underlines. We could compress the underline part even further, but it's hard to do anything about the OSC-8 part. In any case, since underlines are rarely single characters only, we quickly "save" the extra space used, compared to growing the cell struct and using it to store underline data.
Vtebench
Only affected benchmark is the "dense cells". This isn't unsurprising, since it applies underlines to all cells.
| Branch | Time |
|---|---|
| master | 42.78ms avg (90% < 50ms) +-6.84ms |
| curly-underlines | 46.89ms avg (90% < 57ms) +-7.74ms |
I'll try to spend some time to see if we can improve it. My guess is it's the VT parser that's slower (rendering is also slower, due to the curly range lookup, but I don't think that's causing the slowdown we see here).
Terminfo
There's no real standard here... we define the same capabilities kitty does:
Su- a boolean, indicates support for styled underlinesSmulx- a string capability, for emitting styled underlines (not color)Setulc- a string capability, for emitting colored underlines (color only, not style).
From what I can tell, upstream (ncurses) allows Smulx (I see it defined for a couple of entries), but not Su and not Setulc. This is something we should document (non-standard terminfo capabilities defined in "our" terminfo, but not ncurses', is currently documented in the wiki, but perhaps we should document it in the README too).