terminal: Vim background color renders incorrectly

  • Your Windows build number: (Type ver at a Windows Command Prompt) Microsoft Windows [Version 10.0.18362.86]

  • What you’re doing and what’s happening: (Copy & paste specific commands and their output, or include screen shots) In conhost or Windows Terminal, using both Vim.exe and WSL Vim, background color rendering becomes broken if a background color >16 or true colors is used.

With an example file, e.g. https://github.com/GilbertsHub/web-utils/blob/master/cgibinIntercept.sh:

vim -u NONE cgibinIntercept.sh +"hi Normal ctermbg=17" # for Windows: +"set t_Co=256"
# scroll down with CTRL-D

In general it is much easier to reproduce in WSL than Vim.exe, because it doesn’t seem to occur after the initial scroll on Vim.exe and the effects are a bit different as described below. I can reproduce with any combination of conhost/terminal and Vim 8.1.883 on Ubuntu/8.0 on Debian/8.1 on Win32. Does not reproduce with neovim (v0.4.0-430-g8698830cb).

A few cases of example behavior:

  • Debian with conhost, Vim from official repository
$ sudo apt install vim
$ vim --version
VIM - Vi IMproved 8.0 (2016 Sep 12, compiled Sep 30 2017 18:21:38)
Included patches: 1-197, 322, 377-378, 550, 703, 706-707

vim-bg Same behavior in the new terminal.

  • What’s wrong / what should be happening instead: Background rendered the whole width of the window, e.g. in wsltty: vim-bg-wsltty

The effect is very similar to the issue https://github.com/microsoft/terminal/issues/375, however that one happens with bg color set to <16 (darkBlue). However I cannot reproduce that issue anymore, including the terminal bg change.

The issues for Win32 and Linux versions might be separate, since their effects are pretty different as described above.

I also haven’t been able to reproduce this using VT sequences, but I hope the bug report is still useful.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 15
  • Comments: 16 (1 by maintainers)

Commits related to this issue

Most upvoted comments

The common fix is to disable Vim’s “Background Color Erase (BCE)” option by setting t_ut to an empty string, like this:

:set t_ut=“” (then CTRL-L to re-draw)

This tells Vim to erase areas of the screen, as it does when back-scrolling, using the current background color (from the Vim color scheme) instead of relying on that specific Terminal’s implementation of Background Color Erase (BCE) mode. Otherwise, areas are simply erased without regard for background color, which means the Terminal’s DEFAULT background value would be used.

Exactly. Well, it can also happen if t_Co=256 and/or term=xterm

Also, to prevent those flashes of the wrong bg color during rapid scrolling when bce mode is disabled, you’ll want to additionally configure the maximum number of lines that vim will scroll before redrawing the screen. Set it to 1 line. The following works well placed in a vimrc file:

if (&term =~ '^xterm' && &t_Co == 256)
  set t_ut= | set ttyscroll=1
endif

I’m think Microsoft/WSL #1706 was maybe an end-of-line/newline erase bug or something like that, but Microsoft/Terminal #70 sounds like the same Vim bce issue we’re discussing here.

I am experiencing similar issues using vim in Windows Terminal 1.2.2381.0. As you can see, guifg and guibg are set to NONE, but the background is being painted black. This is definitely not Windows Terminal’s background color, which was explicitly set to match the chosen vim theme. image Notably, this problem appears to be specific to Windows and does not occur in WSL: image

On Windows 10 1903 (18362.175) with WSL Ubuntu 18.04, the @xtremeperf workarounds involving set t_ut did not work for me. I found another workaround in an answer to a stack overflow question. In ~/.vimrc put:

highlight Normal ctermfg=black ctermbg=lightgrey

When in vim, this sets the text color to black and the background color to lightgrey. Other colors are listed in /usr/share/vim/vim80/rgb.txt Not all those colors are supported on a 256 color xterm.

This issue should be reopened as it is NOT resolved.

🎉This issue was addressed in #2668, which has now been successfully released as Windows Terminal Preview v0.5.2661.0.🎉

Handy links:

Note that you are setting the background to color 7 (and not to a true-color or 16-256 terminal colors) using lightgrey, which you can see in :help cterm-colors in Vim. As I noted above, this problem only occurs if the background color is set to either >=16 or an RGB value.

This looks very similar to issue #70 - might be a duplicate. What is happening when you scroll, is you get a delete lines (DL) or insert lines (IL) escape sequence, which should fill the new space with the current background color, but it doesn’t work correctly when using colors from the 256-color palette or RGB mode. A simple test case would be something like this:

printf "\ec\e[1;10r\e[H\e[48;5;2m\e[10M\nBG COLOR\e[r\e[m"

That sets a scroll region of 10 lines, and then erases those 10 lines with a green background color from the 256-color palette. While the BG COLOR text shows what the color should have been, the background is actually filled with black. If you replace the \e[48;5;2m sequence with the simpler 16-color sequence \e[42m it’ll work.

printf "\ec\e[1;10r\e[H\e[42m\e[10M\nBG COLOR\e[r\e[m"

The reason for the failure can be found in the DoSrvPrivateModifyLinesImpl method, which calls the ScrollConsoleScreenBufferWImpl method to handle the scrolling. The latter only accepts legacy 16-color attributes, so it tries to derive an appropriate value using the TextAttribute::GetLegacyAttributes method. Unfortunately that method is essentially useless for anything that isn’t already a legacy color.

That said, the ScrollConsoleScreenBufferWImpl does try to make up for the limitations of the API, and map the 16-color attributes back to their original RGB values. It does this by comparing the legacy value against the legacy equivalent of the current colors - if they match then it will use the full RGB values of the current colors. Unfortunately this doesn’t work because it uses a different calculation for the legacy attributes (the Settings::GenerateLegacyAttributes method).

Assuming the ScrollConsoleScreenBufferWImpl can’t be updated to handle full RGB attributes, the next best thing would be to use a better legacy attribute calculation in the DoSrvPrivateModifyLinesImpl method. If we were to use the same Settings::GenerateLegacyAttributes on both ends then the mapping back to RGB should work correctly. And in the event it can’t map, because it really doesn’t match the current color, then it should at least give a better approximation of the requested color.