Skip to main content

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.

Author

Travis Cardwell

Published

Tags
Related Blog Entries