Terminal Color Schemes (Part 2)
When the Alacritty configuration is changed, the changes immediately apply to all open instances. This has both positive and negative implications. On the positive side, it is pretty convenient for working on color schemes. I have long wanted to improve my Vim color scheme to get rid of some unfortunate color combinations, and Alacritty makes this easier. I want to better understand how Vim color schemes work, so I created a seemingly simple challenge: to determine exactly where a specific color on my screen is configured. This turned out to not be so simple!
There is a light green color that is used pretty prominently in my
current Vim color scheme but is not part of my Alacritty color
scheme. For example, the Haskell keyword module
is
displayed in this color. I took a screenshot and used Gimp to determine that the color is
#87ffaf
. My goal is to determine exactly how the string
module
maps to the color #87ffaf
.
First, I checked the haskell.vim
syntax script. The
module
keyword is assigned to the hsModule
syntax group.
syn keyword hsModule module
In the same file, hsModule
is linked to the
hsStructure
syntax group.
hi def link hsModule hsStructure
In the same file, hsStructure
is linked to the
Structure
syntax group. As the group name indicates, it is
not specific to Haskell.
hi def link hsStructure Structure
Next, I checked my Vim color scheme configuration. I am using the
default
color scheme, as confirmed by typing
:colorscheme
without arguments. The
default.vim
color scheme script does not contain any color
configuration, so it was not very helpful. Searching online, I read that
the ron
color scheme is the actual default with my
settings, and switching to the ron
color scheme explicitly
indeed results in no color changes. The ron.vim
color
scheme script contains color configuration, but it did not have any
configuration for the Structure
syntax group.
After lots of searching (using find
and
grep
), I was eventually able to find the
syncolor.vim
syntax script. This file defines the
highlighting defaults, and it is loaded by the syntax reset
command, which is executed by the color scheme scripts. The default
settings include many different colors, not just the terminal emulator
colors. This is probably a good way to configure the defaults because
some people may use terminals that are not configured well, but this is
the cause of the unfortunate color combinations that I want to get rid
of.
At this point, I realized that I will likely need to create my own
Vim color scheme, since even the default
color scheme uses
colors that are not in my selected palette. Perhaps it is possible to
create a color scheme that uses only the terminal emulator color scheme.
Note that there is a termguicolors
flag that looked like it
might be what I want, but I confirmed that other colors are used even
when that flag is set.
In the syncolor.vim
syntax script,
Structure
is linked to the Type
syntax group.
Note that the SynLink
command is defined earlier in the
script according to the current settings.
SynLink Structure Type
In the same file, Type
is given color settings!
SynColor Type term=underline cterm=NONE ctermfg=LightGreen ctermbg=NONE gui=bold guifg=#60ff60 guibg=NONE
The foreground color in the terminal is set to
LightGreen
. This looks promising, but I now need to find
how this identifier is mapped to the color code. Color names are defined
in the colors/lists/default.vim
file, and string
lightgreen
is associated with a different color than the
one that I see!
\ 'lightgreen': '#90ee90',
I also found the same setting in the src/highlight.c
file in the source repository.
{(char_u *)"lightgreen", RGB(0x90, 0xEE, 0x90)},
None of the colors are set to #87ffaf
. I tried
(case-insensitive) searching all of the Vim files (under
/usr/share/vim
as well as the Vim source repository), and
the only hit is a 2html.vim
syntax script that is sued to
“transform a file to HTML, using the current syntax highlighting”
according to the comments.
\ 121: "#87ffaf", 122: "#87ffd7", 123: "#87ffff", 124: "#af0000",
The color is associated with number 121, and searching online
indicates that it is a standard color in the 256 color palette, named
PaleGreen1
. In the colors/lists/default.vim
file, there is a different color associated with string
palegreen1
!
\ 'palegreen1': '#9aff9a',
You can query the current highlight settings for a syntax group using
the highlight
command. (I eventually realized that the
xxx
is just placeholder text used to show the colors. That
is an odd choice of placeholder text! There is no need to search for it
on the internet…)
:highlight Type
Type xxx term=underline ctermfg=121 gui=bold guifg=seagreen
So, the actual setting is 121, aka PaleGreen1
, which is
indeed the color that I am looking for according to online references.
That does not match the configuration that I see in the
scripts, however! You can get a bit more information using the
verbose
command.
:verbose highlight Type
Type xxx term=underline ctermfg=121 gui=bold guifg=#60ff60
Last set from /usr/share/vim/vim82/syntax/syncolor.vim line 40
This is the line that I pasted above, setting the color to
LightGreen
! Is the LightGreen
identifier
mapped to 121 somewhere? Searching for the string 121
, I
found it in the src/highlight.c
file in the source
repository.
// for xterm with 256 colors...
static int color_numbers_256[28] = {0, 4, 2, 6,
1, 5, 130, 3,
248, 248, 7, 7,
242, 242,
12, 81, 10, 121,
14, 159, 9, 224, 13,
225, 11, 229, 15, -1};
The 121 value is in index 17, which corresponds to the index of the
LightGreen
color name in the same file.
static char *(color_names[28]) = {
"Black", "DarkBlue", "DarkGreen", "DarkCyan",
"DarkRed", "DarkMagenta", "Brown", "DarkYellow",
"Gray", "Grey", "LightGray", "LightGrey",
"DarkGray", "DarkGrey",
"Blue", "LightBlue", "Green", "LightGreen",
"Cyan", "LightCyan", "Red", "LightRed", "Magenta",
"LightMagenta", "Yellow", "LightYellow", "White", "NONE"};
The lookup_color
function uses these two arrays to map
the string LightGreen
to value 121. Perhaps that is a bug
in Vim, as LightGreen
is assigned indexes 119 or 120
according to online references. The 121 value is interpreted by my
terminal emulator, which uses the correct color even though the colors
in Vim are incorrect. I finally understand why
module
is displayed using that particular color.