Skip to content

Commit

Permalink
Work around inconsistent undercurl support
Browse files Browse the repository at this point in the history
Terminals have only recently started supporting undercurls, due to the
xterm extensions advanced by the Kitty terminal emulator. So clearing
the terminal defaults for the Spell* groups (per ccaf8de) just left
them with no highlighting whatsoever in the terminal. I found this was
the only case where gui and guisp weren't translating over as I wanted.

First off, you have to use cterm=undercurl, not just gui=undercurl. Even
then you have to make Vim output the right escape sequences to the
terminal with

  let &t_Cs = "\e[4:3m"
  let &t_Ce = "\e[4:0m"

I of course won't set those directly from the color scheme, since it's
not a given that your terminal will support the escape codes. Though to
their credit, most terminals seem to at least gracefully fallback to
straight underlines.

But even with curly underlines, it doesn't seem like many macOS
terminals actually support coloring the underline separately from the
foreground. Although Kitty supports it just fine (and I should hope so,
being the project that promoted this feature), I've found that neither
iTerm2, Alacritty, nor Hyper could render differently-colored undercurls
in Vim. And I can't really find any other high-profile macOS terminals,
so in my mind Kitty is the only one where this works! (There seems to be
some evidence floating around that neovim does something different to
get undercurls right, maybe? But I don't really understand it, and I'm
not about to go down that rabbit hole.)

There also doesn't seem to be a good way to automatically detect if a
terminal supports colored undercurls. So, I'm just going with the better
safe than sorry approach, which at least works in my current terminal of
choice (iTerm2). Namely:

1. Make sure to set cterm=undercurl as well as gui=undercurl. As a
   general extension, I think it's true that we want to set cterm to
   whatever attributes I use for the gui (across the whole color scheme,
   I only use undercurl and bold), so it's natural to just stick this in
   s:hi directly.

2. As a compromise, the terminal will use guifg instead of guisp for the
   Spell* groups. That way, we'll get *some* sort of color onto the
   screen, albeit for the whole word + the undercurl instead of only for
   the undercurl. I can't do this in a single call to s:hi, though,
   because I don't want to use guifg when the GUI is running (it can
   just can make proper use of guisp). So I wrap the Spell* groups in a
   gui_running check.

This is the only case I found in the whole scheme that needed a fallback
plan for terminal support. Otherwise, termguicolors seems to take care
of the rest.

Further reading:
* https://sw.kovidgoyal.net/kitty/protocol-extensions.html
* https://gitlab.com/gnachman/iterm2/-/issues/6382
* vim/vim#1306
* vim/vim#6687
* vim/vim#2405
* neovim/neovim#7479
* alacritty/alacritty#1628 (comment)
  • Loading branch information
ajvondrak committed Jan 12, 2021
1 parent ccaf8de commit f7d829d
Showing 1 changed file with 12 additions and 4 deletions.
16 changes: 12 additions & 4 deletions colors/vondark.vim
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ let s:pink = "#dc67ea"
function! s:hi(group, gui)
execute "highlight clear " . a:group
execute "highlight " . a:group . " gui=" . get(a:gui, "ui", "NONE")
execute "highlight " . a:group . " cterm=" . get(a:gui, "ui", "NONE")
execute "highlight " . a:group . " guifg=" . get(a:gui, "fg", "NONE")
execute "highlight " . a:group . " guibg=" . get(a:gui, "bg", "NONE")
execute "highlight " . a:group . " guisp=" . get(a:gui, "sp", "NONE")
Expand Down Expand Up @@ -103,10 +104,17 @@ call s:hi("PmenuSbar", {"bg": s:dimmer})
call s:hi("PmenuThumb", {"bg": s:fg})

" Spelling
call s:hi("SpellBad", {"sp": s:red, "ui": "undercurl"})
call s:hi("SpellCap", {"sp": s:aqua, "ui": "undercurl"})
call s:hi("SpellLocal", {"sp": s:yellow, "ui": "undercurl"})
call s:hi("SpellRare", {"sp": s:yellow, "ui": "undercurl"})
if has("gui_running")
call s:hi("SpellBad", {"sp": s:red, "ui": "undercurl"})
call s:hi("SpellCap", {"sp": s:aqua, "ui": "undercurl"})
call s:hi("SpellLocal", {"sp": s:yellow, "ui": "undercurl"})
call s:hi("SpellRare", {"sp": s:yellow, "ui": "undercurl"})
else
call s:hi("SpellBad", {"fg": s:red, "ui": "undercurl"})
call s:hi("SpellCap", {"fg": s:aqua, "ui": "undercurl"})
call s:hi("SpellLocal", {"fg": s:yellow, "ui": "undercurl"})
call s:hi("SpellRare", {"fg": s:yellow, "ui": "undercurl"})
end

" Tabs & Splits
call s:hi("TabLine", {"fg": s:fg, "bg": s:dimmest})
Expand Down

0 comments on commit f7d829d

Please sign in to comment.