Skip to content

Commit 86855ea

Browse files
koronchrisbra
authored andcommitted
patch 9.1.2006: MS-Windows: ANSI colors not correct in terminal
Problem: ANSI escape colors are not displayed correctly in non-termguicolors in vim (cli) on Windows. The red and blue channels seem to be swapped. Cause: When converting VTerm ANSI index colors to cterm colors in terminal.c, the Windows case equivalent to NR-16 (:help cterm-colors) is ignored. Solution: Created and used a table to convert ANSI indexed colors to cterm's NR-16 representation (Windows only). This table corresponds to the inverse conversion of cterm_ansi_idx in term.c. The values in both tables are exactly the same, but the meanings are opposite, so they are separate tables (Muraoka Taro). closes: #18931 Signed-off-by: Muraoka Taro <koron.kaoriya@gmail.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
1 parent 3913f13 commit 86855ea

5 files changed

Lines changed: 73 additions & 2 deletions

File tree

src/term.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7642,7 +7642,7 @@ static const char_u ansi_table[16][3] = {
76427642

76437643
# if defined(MSWIN)
76447644
// Mapping between cterm indices < 16 and their counterpart in the ANSI palette.
7645-
static const char_u cterm_ansi_idx[] = {
7645+
const char_u cterm_ansi_idx[] = {
76467646
0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15
76477647
};
76487648
# endif

src/termdefs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,8 @@ typedef enum {
233233
TMODE_RAW, // terminal mode for Normal and Insert mode
234234
TMODE_UNKNOWN // after executing a shell
235235
} tmode_T;
236+
237+
#if defined(MSWIN)
238+
// Mapping between cterm indices < 16 and their counterpart in the ANSI palette.
239+
extern const char_u cterm_ansi_idx[];
240+
#endif

src/terminal.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3033,7 +3033,20 @@ color2index(VTermColor *color, int fg, int *boldp)
30333033
{
30343034
// Use the color as-is if possible, give up otherwise.
30353035
if (color->index < t_colors)
3036-
return color->index + 1;
3036+
{
3037+
uint8_t index = color->index;
3038+
#ifdef MSWIN
3039+
// Convert ANSI palette to cterm color index.
3040+
// cterm_ansi_idx is a table for the reverse conversion from cterm
3041+
// color index to ANSI palette. However, the current table can
3042+
// be used for this conversion as well.
3043+
// Note: If the contents of cterm_ansi_idx change in the future, a
3044+
// different table may be needed for this purpose.
3045+
if (index < 16)
3046+
index = cterm_ansi_idx[index];
3047+
#endif
3048+
return index + 1;
3049+
}
30373050
// 8-color terminals can actually display twice as many colors by
30383051
// setting the high-intensity/bold bit.
30393052
else if (t_colors == 8 && fg && color->index < 16)

src/testdir/test_terminal3.vim

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,4 +1037,55 @@ func Test_terminal_visual_empty_listchars()
10371037
call StopVimInTerminal(buf)
10381038
endfunc
10391039

1040+
func Test_terminal_ansi_color_windows_cui()
1041+
if !has('win32') || has('gui_running')
1042+
throw 'Skipped: only for the Windows CUI'
1043+
endif
1044+
if exists('$APPVEYOR')
1045+
throw 'Skipped: this test cannot be performed because AppVeyor does not support ANSI escape sequences'
1046+
endif
1047+
1048+
call assert_equal('dark', &background)
1049+
1050+
" Outputs 16 ANSI colors as background colors
1051+
let ansi = ''
1052+
for i in range(16)
1053+
let ansi ..= printf("\e[%dm%X", i + (i < 8 ? 40 : 92), i)
1054+
endfor
1055+
let ansi ..= "\e[40m\n"
1056+
call writefile([ansi], 'XANSIcolor', 'D')
1057+
1058+
let expected_chars = '0123456789ABCDEF'
1059+
let expected_colors = [
1060+
\ '#000000', '#e00000', '#00e000', '#e0e000',
1061+
\ '#0000e0', '#e000e0', '#00e0e0', '#e0e0e0',
1062+
\ '#808080', '#ff4040', '#40ff40', '#ffff40',
1063+
\ '#4040ff', '#ff40ff', '#40ffff', '#ffffff',
1064+
\ ]
1065+
1066+
" Ideally, 16 colors should be checked. However, in the current CI
1067+
" environment, the 16th color is something other than white, and we don't
1068+
" know the cause nor solution. After discussion, we decided to check only 15
1069+
" colors for the time being.
1070+
" FIXME: Check all 16 colors in the future.
1071+
let len_to_check = 15
1072+
let expected_colors = expected_colors[:len_to_check-1]
1073+
1074+
" First, make sure vim can display correct ANSI color text in terminal.
1075+
let buf = term_start("cmd /C type XANSIcolor")
1076+
call WaitForAssert({-> assert_equal(expected_chars, term_scrape(buf, 1)[:15]->map({_, v -> v['chars']})->join(''))})
1077+
call assert_equal(expected_colors, term_scrape(buf, 1)[:len_to_check-1]->map({_, v -> v['bg']}))
1078+
bwipeout!
1079+
1080+
" Next, check if vim can do the same thing in the vim terminal in terminal.
1081+
let lines = [
1082+
\ 'call term_start("cmd /C type XANSIcolor")'
1083+
\ ]
1084+
call writefile(lines, 'XloadANSI', 'D')
1085+
let cmd = GetVimCommandCleanTerm()
1086+
let buf = term_start(cmd .. '-S XloadANSI')
1087+
call WaitForAssert({-> assert_equal(expected_chars, term_scrape(buf, 1)[:15]->map({_, v -> v['chars']})->join(''))})
1088+
call assert_equal(expected_colors, term_scrape(buf, 1)[:len_to_check-1]->map({_, v -> v['bg']}))
1089+
endfunc
1090+
10401091
" vim: shiftwidth=2 sts=2 expandtab

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,8 @@ static char *(features[]) =
734734

735735
static int included_patches[] =
736736
{ /* Add new patch number below this line */
737+
/**/
738+
2006,
737739
/**/
738740
2005,
739741
/**/

0 commit comments

Comments
 (0)