patch 8.0.1531: cannot use 24 bit colors in MS-Windows console

Problem:    Cannot use 24 bit colors in MS-Windows console.
Solution:   Add support for vcon. (Nobuhiro Takasaki, Ken Takasaki,
            fixes #1270, fixes #2060)
This commit is contained in:
Bram Moolenaar
2018-02-22 21:07:09 +01:00
parent 19eb6658ec
commit cafafb381a
13 changed files with 710 additions and 123 deletions

View File

@@ -1,4 +1,4 @@
*options.txt* For Vim version 8.0. Last change: 2018 Feb 03 *options.txt* For Vim version 8.0. Last change: 2018 Feb 22
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@@ -5203,8 +5203,11 @@ A jump table for the options with a short description can be found at |Q_op|.
{not in Vi} {not in Vi}
Maximum amount of memory (in Kbyte) to use for one buffer. When this Maximum amount of memory (in Kbyte) to use for one buffer. When this
limit is reached allocating extra memory for a buffer will cause limit is reached allocating extra memory for a buffer will cause
other memory to be freed. The maximum usable value is about 2000000. other memory to be freed.
Use this to work without a limit. Also see 'maxmemtot'. The maximum usable value is about 2000000. Use this to work without a
limit.
The value is ignored when 'swapfile' is off.
Also see 'maxmemtot'.
*'maxmempattern'* *'mmp'* *'maxmempattern'* *'mmp'*
'maxmempattern' 'mmp' number (default 1000) 'maxmempattern' 'mmp' number (default 1000)
@@ -5233,6 +5236,8 @@ A jump table for the options with a short description can be found at |Q_op|.
need more than 2 Gbyte for text editing? Keep in mind that text is need more than 2 Gbyte for text editing? Keep in mind that text is
stored in the swap file, one can edit files > 2 Gbyte anyway. We do stored in the swap file, one can edit files > 2 Gbyte anyway. We do
need the memory to store undo info. need the memory to store undo info.
Buffers with 'swapfile' off still count to the total amount of memory
used.
Also see 'maxmem'. Also see 'maxmem'.
*'menuitems'* *'mis'* *'menuitems'* *'mis'*
@@ -5956,14 +5961,13 @@ A jump table for the options with a short description can be found at |Q_op|.
|ins-completion-menu|. |ins-completion-menu|.
*'pumwidth'* *'pw'* *'pumwidth'* *'pw'*
'pumwidth' 'pw' number (default 0) 'pumwidth' 'pw' number (default 15)
global global
{not available when compiled without the {not available when compiled without the
|+insert_expand| feature} |+insert_expand| feature}
{not in Vi} {not in Vi}
Determines the minium width to use for the popup menu for Insert mode Determines the minium width to use for the popup menu for Insert mode
completion. When zero the default of 15 screen cells is used. completion. |ins-completion-menu|.
|ins-completion-menu|.
*'pythondll'* *'pythondll'*
'pythondll' string (default depends on the build) 'pythondll' string (default depends on the build)
@@ -7903,17 +7907,23 @@ A jump table for the options with a short description can be found at |Q_op|.
:set encoding=utf-8 :set encoding=utf-8
< You need to do this when your system has no locale support for UTF-8. < You need to do this when your system has no locale support for UTF-8.
*'termguicolors'* *'tgc'* *'termguicolors'* *'tgc'* *E954*
'termguicolors' 'tgc' boolean (default off) 'termguicolors' 'tgc' boolean (default off)
global global
{not in Vi} {not in Vi}
{not available when compiled without the {not available when compiled without the
|+termguicolors| feature} |+termguicolors| feature}
When on, uses |highlight-guifg| and |highlight-guibg| attributes in When on, uses |highlight-guifg| and |highlight-guibg| attributes in
the terminal (thus using 24-bit color). Requires a ISO-8613-3 the terminal (thus using 24-bit color).
compatible terminal.
If setting this option does not work (produces a colorless UI) Requires a ISO-8613-3 compatible terminal. If setting this option
reading |xterm-true-color| might help. does not work (produces a colorless UI) reading |xterm-true-color|
might help.
For Win32 console, Windows 10 version 1703 (Creators Update) or later
is required. Use this check to find out: >
if has('vcon')
<
Note that the "cterm" attributes are still used, not the "gui" ones. Note that the "cterm" attributes are still used, not the "gui" ones.
NOTE: This option is reset when 'compatible' is set. NOTE: This option is reset when 'compatible' is set.

View File

@@ -851,7 +851,7 @@ static struct fst
#ifdef FEAT_TERMINAL #ifdef FEAT_TERMINAL
{"term_dumpdiff", 2, 3, f_term_dumpdiff}, {"term_dumpdiff", 2, 3, f_term_dumpdiff},
{"term_dumpload", 1, 2, f_term_dumpload}, {"term_dumpload", 1, 2, f_term_dumpload},
{"term_dumpwrite", 2, 4, f_term_dumpwrite}, {"term_dumpwrite", 2, 3, f_term_dumpwrite},
{"term_getaltscreen", 1, 1, f_term_getaltscreen}, {"term_getaltscreen", 1, 1, f_term_getaltscreen},
{"term_getattr", 2, 2, f_term_getattr}, {"term_getattr", 2, 2, f_term_getattr},
{"term_getcursor", 1, 1, f_term_getcursor}, {"term_getcursor", 1, 1, f_term_getcursor},
@@ -6323,9 +6323,9 @@ f_has(typval_T *argvars, typval_T *rettv)
else if (STRICMP(name, "syntax_items") == 0) else if (STRICMP(name, "syntax_items") == 0)
n = syntax_present(curwin); n = syntax_present(curwin);
#endif #endif
#if defined(WIN3264) #ifdef FEAT_VTP
else if (STRICMP(name, "win95") == 0) else if (STRICMP(name, "vcon") == 0)
n = FALSE; /* Win9x is no more supported. */ n = has_vtp_working();
#endif #endif
#ifdef FEAT_NETBEANS_INTG #ifdef FEAT_NETBEANS_INTG
else if (STRICMP(name, "netbeans_enabled") == 0) else if (STRICMP(name, "netbeans_enabled") == 0)

View File

@@ -1394,3 +1394,10 @@
|| (defined(WIN3264) && defined(FEAT_GUI_W32)) || (defined(WIN3264) && defined(FEAT_GUI_W32))
# define FEAT_FILTERPIPE # define FEAT_FILTERPIPE
#endif #endif
/*
* +vtp: Win32 virtual console.
*/
#if !defined(FEAT_GUI) && defined(WIN3264)
# define FEAT_VTP
#endif

View File

@@ -3714,7 +3714,22 @@ vim_beep(
&& !(gui.in_use && gui.starting) && !(gui.in_use && gui.starting)
#endif #endif
) )
{
out_str_cf(T_VB); out_str_cf(T_VB);
#ifdef FEAT_VTP
/* No restore color information, refresh the screen. */
if (has_vtp_working() != 0
# ifdef FEAT_TERMGUICOLORS
&& p_tgc
# endif
)
{
redraw_later(CLEAR);
update_screen(0);
redrawcmd();
}
#endif
}
else else
out_char(BELL); out_char(BELL);
#ifdef ELAPSED_FUNC #ifdef ELAPSED_FUNC

View File

@@ -8690,10 +8690,25 @@ set_bool_option(
/* 'termguicolors' */ /* 'termguicolors' */
else if ((int *)varp == &p_tgc) else if ((int *)varp == &p_tgc)
{ {
# ifdef FEAT_VTP
/* Do not turn on 'tgc' when 24-bit colors are not supported. */
if (!has_vtp_working())
{
p_tgc = 0;
return (char_u*)N_("E954: 24-bit colors are not supported on this environment");
}
swap_tcap();
# endif
# ifdef FEAT_GUI # ifdef FEAT_GUI
if (!gui.in_use && !gui.starting) if (!gui.in_use && !gui.starting)
# endif # endif
highlight_gui_started(); highlight_gui_started();
# ifdef FEAT_VTP
control_console_color_rgb();
/* reset t_Co */
if (STRCMP(T_NAME, "win32") == 0)
set_termname(T_NAME);
# endif
} }
#endif #endif

View File

@@ -202,6 +202,32 @@ static int win32_getattrs(char_u *name);
static int win32_setattrs(char_u *name, int attrs); static int win32_setattrs(char_u *name, int attrs);
static int win32_set_archive(char_u *name); static int win32_set_archive(char_u *name);
#ifndef FEAT_GUI_W32
static int vtp_working = 0;
static void vtp_init();
static void vtp_exit();
static int vtp_printf(char *format, ...);
static void vtp_sgr_bulk(int arg);
static void vtp_sgr_bulks(int argc, int *argv);
static guicolor_T save_console_bg_rgb;
static guicolor_T save_console_fg_rgb;
# ifdef FEAT_TERMGUICOLORS
# define USE_VTP (vtp_working && p_tgc)
# else
# define USE_VTP 0
# endif
static void set_console_color_rgb(void);
static void reset_console_color_rgb(void);
#endif
/* This flag is newly created from Windows 10 */
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
# define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#endif
#ifndef FEAT_GUI_W32 #ifndef FEAT_GUI_W32
static int suppress_winsize = 1; /* don't fiddle with console */ static int suppress_winsize = 1; /* don't fiddle with console */
#endif #endif
@@ -211,6 +237,54 @@ static char_u *exe_path = NULL;
static BOOL win8_or_later = FALSE; static BOOL win8_or_later = FALSE;
#ifndef FEAT_GUI_W32 #ifndef FEAT_GUI_W32
/* Dynamic loading for portability */
typedef struct _DYN_CONSOLE_SCREEN_BUFFER_INFOEX
{
ULONG cbSize;
COORD dwSize;
COORD dwCursorPosition;
WORD wAttributes;
SMALL_RECT srWindow;
COORD dwMaximumWindowSize;
WORD wPopupAttributes;
BOOL bFullscreenSupported;
COLORREF ColorTable[16];
} DYN_CONSOLE_SCREEN_BUFFER_INFOEX, *PDYN_CONSOLE_SCREEN_BUFFER_INFOEX;
typedef BOOL (WINAPI *PfnGetConsoleScreenBufferInfoEx)(HANDLE, PDYN_CONSOLE_SCREEN_BUFFER_INFOEX);
static PfnGetConsoleScreenBufferInfoEx pGetConsoleScreenBufferInfoEx;
typedef BOOL (WINAPI *PfnSetConsoleScreenBufferInfoEx)(HANDLE, PDYN_CONSOLE_SCREEN_BUFFER_INFOEX);
static PfnSetConsoleScreenBufferInfoEx pSetConsoleScreenBufferInfoEx;
static BOOL has_csbiex = FALSE;
/*
* Get version number including build number
*/
typedef BOOL (WINAPI *PfnRtlGetVersion)(LPOSVERSIONINFOW);
# define MAKE_VER(major, minor, build) \
(((major) << 24) | ((minor) << 16) | (build))
static DWORD
get_build_number(void)
{
OSVERSIONINFOW osver = {sizeof(OSVERSIONINFOW)};
HMODULE hNtdll;
PfnRtlGetVersion pRtlGetVersion;
DWORD ver = MAKE_VER(0, 0, 0);
hNtdll = GetModuleHandle("ntdll.dll");
if (hNtdll != NULL)
{
pRtlGetVersion =
(PfnRtlGetVersion)GetProcAddress(hNtdll, "RtlGetVersion");
pRtlGetVersion(&osver);
ver = MAKE_VER(min(osver.dwMajorVersion, 255),
min(osver.dwMinorVersion, 255),
min(osver.dwBuildNumber, 32767));
}
return ver;
}
/* /*
* Version of ReadConsoleInput() that works with IME. * Version of ReadConsoleInput() that works with IME.
* Works around problems on Windows 8. * Works around problems on Windows 8.
@@ -2537,6 +2611,7 @@ mch_init(void)
/* set termcap codes to current text attributes */ /* set termcap codes to current text attributes */
update_tcap(g_attrCurrent); update_tcap(g_attrCurrent);
swap_tcap();
GetConsoleCursorInfo(g_hConOut, &g_cci); GetConsoleCursorInfo(g_hConOut, &g_cci);
GetConsoleMode(g_hConIn, &g_cmodein); GetConsoleMode(g_hConIn, &g_cmodein);
@@ -2577,6 +2652,8 @@ mch_init(void)
#ifdef FEAT_CLIPBOARD #ifdef FEAT_CLIPBOARD
win_clip_init(); win_clip_init();
#endif #endif
vtp_init();
} }
/* /*
@@ -2589,6 +2666,8 @@ mch_exit(int r)
{ {
exiting = TRUE; exiting = TRUE;
vtp_exit();
stoptermcap(); stoptermcap();
if (g_fWindInitCalled) if (g_fWindInitCalled)
settmode(TMODE_COOK); settmode(TMODE_COOK);
@@ -3801,7 +3880,15 @@ mch_settmode(int tmode)
if (g_fMouseActive) if (g_fMouseActive)
cmodein |= ENABLE_MOUSE_INPUT; cmodein |= ENABLE_MOUSE_INPUT;
#endif #endif
cmodeout &= ~(ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT); cmodeout &= ~(
#ifdef FEAT_TERMGUICOLORS
/* Do not turn off the ENABLE_PROCESSRD_OUTPUT flag when using
* VTP. */
((vtp_working) ? 0 : ENABLE_PROCESSED_OUTPUT) |
#else
ENABLE_PROCESSED_OUTPUT |
#endif
ENABLE_WRAP_AT_EOL_OUTPUT);
bEnableHandler = TRUE; bEnableHandler = TRUE;
} }
else /* cooked */ else /* cooked */
@@ -5448,6 +5535,7 @@ termcap_mode_start(void)
* to restore the actual contents of the buffer. * to restore the actual contents of the buffer.
*/ */
RestoreConsoleBuffer(&g_cbTermcap, FALSE); RestoreConsoleBuffer(&g_cbTermcap, FALSE);
reset_console_color_rgb();
SetConsoleWindowInfo(g_hConOut, TRUE, &g_cbTermcap.Info.srWindow); SetConsoleWindowInfo(g_hConOut, TRUE, &g_cbTermcap.Info.srWindow);
Rows = g_cbTermcap.Info.dwSize.Y; Rows = g_cbTermcap.Info.dwSize.Y;
Columns = g_cbTermcap.Info.dwSize.X; Columns = g_cbTermcap.Info.dwSize.X;
@@ -5460,6 +5548,7 @@ termcap_mode_start(void)
* size. We will use this as the size of our editing environment. * size. We will use this as the size of our editing environment.
*/ */
ClearConsoleBuffer(g_attrCurrent); ClearConsoleBuffer(g_attrCurrent);
set_console_color_rgb();
ResizeConBufAndWindow(g_hConOut, Columns, Rows); ResizeConBufAndWindow(g_hConOut, Columns, Rows);
} }
@@ -5508,6 +5597,7 @@ termcap_mode_end(void)
cb = &g_cbNonTermcap; cb = &g_cbNonTermcap;
#endif #endif
RestoreConsoleBuffer(cb, p_rs); RestoreConsoleBuffer(cb, p_rs);
reset_console_color_rgb();
SetConsoleCursorInfo(g_hConOut, &g_cci); SetConsoleCursorInfo(g_hConOut, &g_cci);
if (p_rs || exiting) if (p_rs || exiting)
@@ -5562,7 +5652,11 @@ clear_chars(
DWORD dwDummy; DWORD dwDummy;
FillConsoleOutputCharacter(g_hConOut, ' ', n, coord, &dwDummy); FillConsoleOutputCharacter(g_hConOut, ' ', n, coord, &dwDummy);
if (!USE_VTP)
FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, n, coord, &dwDummy); FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, n, coord, &dwDummy);
else
FillConsoleOutputAttribute(g_hConOut, 0, n, coord, &dwDummy);
} }
@@ -5573,7 +5667,15 @@ clear_chars(
clear_screen(void) clear_screen(void)
{ {
g_coord.X = g_coord.Y = 0; g_coord.X = g_coord.Y = 0;
if (!USE_VTP)
clear_chars(g_coord, Rows * Columns); clear_chars(g_coord, Rows * Columns);
else
{
set_console_color_rgb();
gotoxy(1, 1);
vtp_printf("\033[2J");
}
} }
@@ -5583,8 +5685,20 @@ clear_screen(void)
static void static void
clear_to_end_of_display(void) clear_to_end_of_display(void)
{ {
COORD save = g_coord;
if (!USE_VTP)
clear_chars(g_coord, (Rows - g_coord.Y - 1) clear_chars(g_coord, (Rows - g_coord.Y - 1)
* Columns + (Columns - g_coord.X)); * Columns + (Columns - g_coord.X));
else
{
set_console_color_rgb();
gotoxy(g_coord.X + 1, g_coord.Y + 1);
vtp_printf("\033[0J");
gotoxy(save.X + 1, save.Y + 1);
g_coord = save;
}
} }
@@ -5594,7 +5708,19 @@ clear_to_end_of_display(void)
static void static void
clear_to_end_of_line(void) clear_to_end_of_line(void)
{ {
COORD save = g_coord;
if (!USE_VTP)
clear_chars(g_coord, Columns - g_coord.X); clear_chars(g_coord, Columns - g_coord.X);
else
{
set_console_color_rgb();
gotoxy(g_coord.X + 1, g_coord.Y + 1);
vtp_printf("\033[0K");
gotoxy(save.X + 1, save.Y + 1);
g_coord = save;
}
} }
@@ -5633,6 +5759,9 @@ set_scroll_region(
g_srScrollRegion.Top = top; g_srScrollRegion.Top = top;
g_srScrollRegion.Right = right; g_srScrollRegion.Right = right;
g_srScrollRegion.Bottom = bottom; g_srScrollRegion.Bottom = bottom;
if (USE_VTP)
vtp_printf("\033[%d;%dr", top + 1, bottom + 1);
} }
@@ -5654,10 +5783,20 @@ insert_lines(unsigned cLines)
source.Right = g_srScrollRegion.Right; source.Right = g_srScrollRegion.Right;
source.Bottom = g_srScrollRegion.Bottom - cLines; source.Bottom = g_srScrollRegion.Bottom - cLines;
if (!USE_VTP)
{
fill.Char.AsciiChar = ' '; fill.Char.AsciiChar = ' ';
fill.Attributes = g_attrCurrent; fill.Attributes = g_attrCurrent;
ScrollConsoleScreenBuffer(g_hConOut, &source, NULL, dest, &fill); ScrollConsoleScreenBuffer(g_hConOut, &source, NULL, dest, &fill);
}
else
{
set_console_color_rgb();
gotoxy(1, source.Top + 1);
vtp_printf("\033[%dT", cLines);
}
/* Here we have to deal with a win32 console flake: If the scroll /* Here we have to deal with a win32 console flake: If the scroll
* region looks like abc and we scroll c to a and fill with d we get * region looks like abc and we scroll c to a and fill with d we get
@@ -5696,10 +5835,20 @@ delete_lines(unsigned cLines)
source.Right = g_srScrollRegion.Right; source.Right = g_srScrollRegion.Right;
source.Bottom = g_srScrollRegion.Bottom; source.Bottom = g_srScrollRegion.Bottom;
if (!USE_VTP)
{
fill.Char.AsciiChar = ' '; fill.Char.AsciiChar = ' ';
fill.Attributes = g_attrCurrent; fill.Attributes = g_attrCurrent;
ScrollConsoleScreenBuffer(g_hConOut, &source, NULL, dest, &fill); ScrollConsoleScreenBuffer(g_hConOut, &source, NULL, dest, &fill);
}
else
{
set_console_color_rgb();
gotoxy(1, source.Top + 1);
vtp_printf("\033[%dS", cLines);
}
/* Here we have to deal with a win32 console flake: If the scroll /* Here we have to deal with a win32 console flake: If the scroll
* region looks like abc and we scroll c to a and fill with d we get * region looks like abc and we scroll c to a and fill with d we get
@@ -5735,7 +5884,11 @@ gotoxy(
/* external cursor coords are 1-based; internal are 0-based */ /* external cursor coords are 1-based; internal are 0-based */
g_coord.X = x - 1; g_coord.X = x - 1;
g_coord.Y = y - 1; g_coord.Y = y - 1;
if (!USE_VTP)
SetConsoleCursorPosition(g_hConOut, g_coord); SetConsoleCursorPosition(g_hConOut, g_coord);
else
vtp_printf("\033[%d;%dH", y, x);
} }
@@ -5757,7 +5910,10 @@ textcolor(WORD wAttr)
{ {
g_attrCurrent = (g_attrCurrent & 0xf0) + (wAttr & 0x0f); g_attrCurrent = (g_attrCurrent & 0xf0) + (wAttr & 0x0f);
if (!USE_VTP)
SetConsoleTextAttribute(g_hConOut, g_attrCurrent); SetConsoleTextAttribute(g_hConOut, g_attrCurrent);
else
vtp_sgr_bulk(wAttr);
} }
@@ -5766,7 +5922,10 @@ textbackground(WORD wAttr)
{ {
g_attrCurrent = (g_attrCurrent & 0x0f) + ((wAttr & 0x0f) << 4); g_attrCurrent = (g_attrCurrent & 0x0f) + ((wAttr & 0x0f) << 4);
if (!USE_VTP)
SetConsoleTextAttribute(g_hConOut, g_attrCurrent); SetConsoleTextAttribute(g_hConOut, g_attrCurrent);
else
vtp_sgr_bulk(wAttr);
} }
@@ -5776,7 +5935,10 @@ textbackground(WORD wAttr)
static void static void
normvideo(void) normvideo(void)
{ {
if (!USE_VTP)
textattr(g_attrDefault); textattr(g_attrDefault);
else
vtp_sgr_bulk(0);
} }
@@ -5789,6 +5951,7 @@ static WORD g_attrPreStandout = 0;
standout(void) standout(void)
{ {
g_attrPreStandout = g_attrCurrent; g_attrPreStandout = g_attrCurrent;
textattr((WORD) (g_attrCurrent|FOREGROUND_INTENSITY|BACKGROUND_INTENSITY)); textattr((WORD) (g_attrCurrent|FOREGROUND_INTENSITY|BACKGROUND_INTENSITY));
} }
@@ -5800,11 +5963,10 @@ standout(void)
standend(void) standend(void)
{ {
if (g_attrPreStandout) if (g_attrPreStandout)
{
textattr(g_attrPreStandout); textattr(g_attrPreStandout);
g_attrPreStandout = 0; g_attrPreStandout = 0;
} }
}
/* /*
@@ -5818,7 +5980,11 @@ mch_set_normal_colors(void)
cterm_normal_fg_color = (g_attrDefault & 0xf) + 1; cterm_normal_fg_color = (g_attrDefault & 0xf) + 1;
cterm_normal_bg_color = ((g_attrDefault >> 4) & 0xf) + 1; cterm_normal_bg_color = ((g_attrDefault >> 4) & 0xf) + 1;
if (T_ME[0] == ESC && T_ME[1] == '|') if (
#ifdef FEAT_TERMGUICOLORS
!p_tgc &&
#endif
T_ME[0] == ESC && T_ME[1] == '|')
{ {
p = T_ME + 2; p = T_ME + 2;
n = getdigits(&p); n = getdigits(&p);
@@ -5828,6 +5994,10 @@ mch_set_normal_colors(void)
cterm_normal_bg_color = ((n >> 4) & 0xf) + 1; cterm_normal_bg_color = ((n >> 4) & 0xf) + 1;
} }
} }
#ifdef FEAT_TERMGUICOLORS
cterm_normal_fg_gui_color = INVALCOLOR;
cterm_normal_bg_gui_color = INVALCOLOR;
#endif
} }
@@ -5851,6 +6021,7 @@ visual_bell(void)
coordOrigin, &dwDummy); coordOrigin, &dwDummy);
Sleep(15); /* wait for 15 msec */ Sleep(15); /* wait for 15 msec */
if (!USE_VTP)
WriteConsoleOutputAttribute(g_hConOut, oldattrs, Rows * Columns, WriteConsoleOutputAttribute(g_hConOut, oldattrs, Rows * Columns,
coordOrigin, &dwDummy); coordOrigin, &dwDummy);
vim_free(oldattrs); vim_free(oldattrs);
@@ -5901,6 +6072,9 @@ write_chars(
unicodebuf, unibuflen); unicodebuf, unibuflen);
cells = mb_string2cells(pchBuf, cbToWrite); cells = mb_string2cells(pchBuf, cbToWrite);
if (!USE_VTP)
{
FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cells, FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cells,
coord, &written); coord, &written);
/* When writing fails or didn't write a single character, pretend one /* When writing fails or didn't write a single character, pretend one
@@ -5909,6 +6083,13 @@ write_chars(
coord, &cchwritten) == 0 coord, &cchwritten) == 0
|| cchwritten == 0) || cchwritten == 0)
cchwritten = 1; cchwritten = 1;
}
else
{
if (WriteConsoleW(g_hConOut, unicodebuf, length, &cchwritten,
NULL) == 0 || cchwritten == 0)
cchwritten = 1;
}
if (cchwritten == length) if (cchwritten == length)
{ {
@@ -5926,6 +6107,8 @@ write_chars(
} }
else else
#endif #endif
{
if (!USE_VTP)
{ {
FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cbToWrite, FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cbToWrite,
coord, &written); coord, &written);
@@ -5935,6 +6118,13 @@ write_chars(
coord, &written) == 0 coord, &written) == 0
|| written == 0) || written == 0)
written = 1; written = 1;
}
else
{
if (WriteConsole(g_hConOut, (LPCSTR)pchBuf, cbToWrite, &written,
NULL) == 0 || written == 0)
written = 1;
}
g_coord.X += (SHORT) written; g_coord.X += (SHORT) written;
} }
@@ -6060,67 +6250,76 @@ mch_write(
char_u *old_s = s; char_u *old_s = s;
#endif #endif
char_u *p; char_u *p;
int arg1 = 0, arg2 = 0; int arg1 = 0, arg2 = 0, argc = 0, args[16];
switch (s[2]) switch (s[2])
{ {
/* one or two numeric arguments, separated by ';' */
case '0': case '1': case '2': case '3': case '4': case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': case '5': case '6': case '7': case '8': case '9':
p = s + 2; p = s + 1;
arg1 = getdigits(&p); /* no check for length! */ do
if (p > s + len)
break;
if (*p == ';')
{ {
++p; ++p;
arg2 = getdigits(&p); /* no check for length! */ args[argc] = getdigits(&p);
argc += (argc < 15) ? 1 : 0;
if (p > s + len)
break;
} while (*p == ';');
if (p > s + len) if (p > s + len)
break; break;
if (*p == 'H') arg1 = args[0];
gotoxy(arg2, arg1); arg2 = args[1];
else if (*p == 'r') if (*p == 'm')
set_scroll_region(0, arg1 - 1, Columns - 1, arg2 - 1);
}
else if (*p == 'A')
{ {
/* move cursor up arg1 lines in same column */ if (argc == 1 && args[0] == 0)
gotoxy(g_coord.X + 1,
max(g_srScrollRegion.Top, g_coord.Y - arg1) + 1);
}
else if (*p == 'C')
{
/* move cursor right arg1 columns in same line */
gotoxy(min(g_srScrollRegion.Right, g_coord.X + arg1) + 1,
g_coord.Y + 1);
}
else if (*p == 'H')
{
gotoxy(1, arg1);
}
else if (*p == 'L')
{
insert_lines(arg1);
}
else if (*p == 'm')
{
if (arg1 == 0)
normvideo(); normvideo();
else if (argc == 1)
{
if (USE_VTP)
textcolor((WORD) arg1);
else else
textattr((WORD) arg1); textattr((WORD) arg1);
} }
else if (*p == 'f') else if (USE_VTP)
{ vtp_sgr_bulks(argc, args);
textcolor((WORD) arg1);
} }
else if (*p == 'b') else if (argc == 2 && *p == 'H')
{
gotoxy(arg2, arg1);
}
else if (argc == 2 && *p == 'r')
{
set_scroll_region(0, arg1 - 1, Columns - 1, arg2 - 1);
}
else if (argc == 1 && *p == 'A')
{
gotoxy(g_coord.X + 1,
max(g_srScrollRegion.Top, g_coord.Y - arg1) + 1);
}
else if (argc == 1 && *p == 'b')
{ {
textbackground((WORD) arg1); textbackground((WORD) arg1);
} }
else if (*p == 'M') else if (argc == 1 && *p == 'C')
{
gotoxy(min(g_srScrollRegion.Right, g_coord.X + arg1) + 1,
g_coord.Y + 1);
}
else if (argc == 1 && *p == 'f')
{
textcolor((WORD) arg1);
}
else if (argc == 1 && *p == 'H')
{
gotoxy(1, arg1);
}
else if (argc == 1 && *p == 'L')
{
insert_lines(arg1);
}
else if (argc == 1 && *p == 'M')
{ {
delete_lines(arg1); delete_lines(arg1);
} }
@@ -6129,11 +6328,7 @@ mch_write(
s = p + 1; s = p + 1;
break; break;
/* Three-character escape sequences */
case 'A': case 'A':
/* move cursor up one line in same column */
gotoxy(g_coord.X + 1, gotoxy(g_coord.X + 1,
max(g_srScrollRegion.Top, g_coord.Y - 1) + 1); max(g_srScrollRegion.Top, g_coord.Y - 1) + 1);
goto got3; goto got3;
@@ -6143,7 +6338,6 @@ mch_write(
goto got3; goto got3;
case 'C': case 'C':
/* move cursor right one column in same line */
gotoxy(min(g_srScrollRegion.Right, g_coord.X + 1) + 1, gotoxy(min(g_srScrollRegion.Right, g_coord.X + 1) + 1,
g_coord.Y + 1); g_coord.Y + 1);
goto got3; goto got3;
@@ -7242,3 +7436,186 @@ mch_setenv(char *var, char *value, int x)
return 0; return 0;
} }
#ifndef FEAT_GUI_W32
/*
* Support for 256 colors and 24-bit colors was added in Windows 10
* version 1703 (Creators update).
*/
# define VTP_FIRST_SUPPORT_BUILD MAKE_VER(10, 0, 15063)
static void
vtp_init(void)
{
DWORD ver, mode;
HMODULE hKerneldll;
DYN_CONSOLE_SCREEN_BUFFER_INFOEX csbi;
ver = get_build_number();
vtp_working = (ver >= VTP_FIRST_SUPPORT_BUILD) ? 1 : 0;
GetConsoleMode(g_hConOut, &mode);
mode |= (ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
if (SetConsoleMode(g_hConOut, mode) == 0)
vtp_working = 0;
/* Use functions supported from Vista */
hKerneldll = GetModuleHandle("kernel32.dll");
if (hKerneldll != NULL)
{
pGetConsoleScreenBufferInfoEx =
(PfnGetConsoleScreenBufferInfoEx)GetProcAddress(
hKerneldll, "GetConsoleScreenBufferInfoEx");
pSetConsoleScreenBufferInfoEx =
(PfnSetConsoleScreenBufferInfoEx)GetProcAddress(
hKerneldll, "SetConsoleScreenBufferInfoEx");
if (pGetConsoleScreenBufferInfoEx != NULL
&& pSetConsoleScreenBufferInfoEx != NULL)
has_csbiex = TRUE;
}
csbi.cbSize = sizeof(csbi);
if (has_csbiex)
pGetConsoleScreenBufferInfoEx(g_hConOut, &csbi);
save_console_bg_rgb = (guicolor_T)csbi.ColorTable[0];
save_console_fg_rgb = (guicolor_T)csbi.ColorTable[7];
set_console_color_rgb();
}
static void
vtp_exit(void)
{
reset_console_color_rgb();
}
static int
vtp_printf(
char *format,
...)
{
char_u buf[100];
va_list list;
DWORD result;
va_start(list, format);
vim_vsnprintf((char *)buf, 100, (char *)format, list);
va_end(list);
WriteConsoleA(g_hConOut, buf, (DWORD)STRLEN(buf), &result, NULL);
return (int)result;
}
static void
vtp_sgr_bulk(
int arg)
{
int args[1];
args[0] = arg;
vtp_sgr_bulks(1, args);
}
static void
vtp_sgr_bulks(
int argc,
int *args
)
{
/* 2('\033[') + 4('255.') * 16 + NUL */
char_u buf[2 + (4 * 16) + 1];
char_u *p;
int i;
p = buf;
*p++ = '\033';
*p++ = '[';
for (i = 0; i < argc; ++i)
{
p += vim_snprintf((char *)p, 4, "%d", args[i] & 0xff);
*p++ = ';';
}
p--;
*p++ = 'm';
*p = NUL;
vtp_printf((char *)buf);
}
static void
set_console_color_rgb(void)
{
# ifdef FEAT_TERMGUICOLORS
DYN_CONSOLE_SCREEN_BUFFER_INFOEX csbi;
int id;
guicolor_T fg = INVALCOLOR;
guicolor_T bg = INVALCOLOR;
if (!USE_VTP)
return;
id = syn_name2id((char_u *)"Normal");
if (id > 0)
syn_id2colors(id, &fg, &bg);
if (fg == INVALCOLOR)
fg = 0xc0c0c0; /* white text */
if (bg == INVALCOLOR)
bg = 0x000000; /* black background */
fg = (GetRValue(fg) << 16) | (GetGValue(fg) << 8) | GetBValue(fg);
bg = (GetRValue(bg) << 16) | (GetGValue(bg) << 8) | GetBValue(bg);
csbi.cbSize = sizeof(csbi);
if (has_csbiex)
pGetConsoleScreenBufferInfoEx(g_hConOut, &csbi);
csbi.cbSize = sizeof(csbi);
csbi.srWindow.Right += 1;
csbi.srWindow.Bottom += 1;
csbi.ColorTable[0] = (COLORREF)bg;
csbi.ColorTable[7] = (COLORREF)fg;
if (has_csbiex)
pSetConsoleScreenBufferInfoEx(g_hConOut, &csbi);
# endif
}
static void
reset_console_color_rgb(void)
{
# ifdef FEAT_TERMGUICOLORS
DYN_CONSOLE_SCREEN_BUFFER_INFOEX csbi;
csbi.cbSize = sizeof(csbi);
if (has_csbiex)
pGetConsoleScreenBufferInfoEx(g_hConOut, &csbi);
csbi.cbSize = sizeof(csbi);
csbi.srWindow.Right += 1;
csbi.srWindow.Bottom += 1;
csbi.ColorTable[0] = (COLORREF)save_console_bg_rgb;
csbi.ColorTable[7] = (COLORREF)save_console_fg_rgb;
if (has_csbiex)
pSetConsoleScreenBufferInfoEx(g_hConOut, &csbi);
# endif
}
void
control_console_color_rgb(void)
{
if (USE_VTP)
set_console_color_rgb();
else
reset_console_color_rgb();
}
int
has_vtp_working(void)
{
return vtp_working;
}
int
use_vtp(void)
{
return USE_VTP;
}
#endif

View File

@@ -42,6 +42,7 @@ void mch_set_shellsize(void);
void mch_new_shellsize(void); void mch_new_shellsize(void);
void mch_set_winsize_now(void); void mch_set_winsize_now(void);
int mch_call_shell(char_u *cmd, int options); int mch_call_shell(char_u *cmd, int options);
void win32_build_env(dict_T *env, garray_T *gap, int is_terminal);
void mch_job_start(char *cmd, job_T *job, jobopt_T *options); void mch_job_start(char *cmd, job_T *job, jobopt_T *options);
char *mch_job_status(job_T *job); char *mch_job_status(job_T *job);
job_T *mch_detect_ended_job(job_T *job_list); job_T *mch_detect_ended_job(job_T *job_list);
@@ -67,5 +68,7 @@ void used_file_arg(char *name, int literal, int full_path, int diff_mode);
void set_alist_count(void); void set_alist_count(void);
void fix_arg_enc(void); void fix_arg_enc(void);
int mch_setenv(char *var, char *value, int x); int mch_setenv(char *var, char *value, int x);
void win32_build_env(dict_T *l, garray_T *gap, int is_terminal); void control_console_color_rgb(void);
int has_vtp_working(void);
int use_vtp(void);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@@ -73,6 +73,7 @@ void show_termcodes(void);
int show_one_termcode(char_u *name, char_u *code, int printit); int show_one_termcode(char_u *name, char_u *code, int printit);
char_u *translate_mapping(char_u *str, int expmap); char_u *translate_mapping(char_u *str, int expmap);
void update_tcap(int attr); void update_tcap(int attr);
void swap_tcap(void);
guicolor_T gui_get_color_cmn(char_u *name); guicolor_T gui_get_color_cmn(char_u *name);
guicolor_T gui_get_rgb_color_cmn(int r, int g, int b); guicolor_T gui_get_rgb_color_cmn(int r, int g, int b);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@@ -2177,6 +2177,25 @@ win_update(win_T *wp)
* End of loop over all window lines. * End of loop over all window lines.
*/ */
#ifdef FEAT_VTP
/* Rewrite the character at the end of the screen line. */
if (use_vtp())
{
int i;
for (i = 0; i < Rows; ++i)
# ifdef FEAT_MBYTE
if (enc_utf8)
if ((*mb_off2cells)(LineOffset[i] + Columns - 2,
LineOffset[i] + screen_Columns) > 1)
screen_draw_rectangle(i, Columns - 2, 1, 2, FALSE);
else
screen_draw_rectangle(i, Columns - 1, 1, 1, FALSE);
else
# endif
screen_char(LineOffset[i] + Columns - 1, i, Columns - 1);
}
#endif
if (idx > wp->w_lines_valid) if (idx > wp->w_lines_valid)
wp->w_lines_valid = idx; wp->w_lines_valid = idx;

View File

@@ -8927,6 +8927,10 @@ get_cterm_attr_idx(int attr, int fg, int bg)
attrentry_T at_en; attrentry_T at_en;
vim_memset(&at_en, 0, sizeof(attrentry_T)); vim_memset(&at_en, 0, sizeof(attrentry_T));
#ifdef FEAT_TERMGUICOLORS
at_en.ae_u.cterm.fg_rgb = INVALCOLOR;
at_en.ae_u.cterm.bg_rgb = INVALCOLOR;
#endif
at_en.ae_attr = attr; at_en.ae_attr = attr;
at_en.ae_u.cterm.fg_color = fg; at_en.ae_u.cterm.fg_color = fg;
at_en.ae_u.cterm.bg_color = bg; at_en.ae_u.cterm.bg_color = bg;
@@ -9566,6 +9570,23 @@ set_hl_attr(
at_en.ae_u.cterm.fg_color = sgp->sg_cterm_fg; at_en.ae_u.cterm.fg_color = sgp->sg_cterm_fg;
at_en.ae_u.cterm.bg_color = sgp->sg_cterm_bg; at_en.ae_u.cterm.bg_color = sgp->sg_cterm_bg;
# ifdef FEAT_TERMGUICOLORS # ifdef FEAT_TERMGUICOLORS
# ifdef WIN3264
{
int id;
guicolor_T fg, bg;
id = syn_name2id((char_u *)"Normal");
if (id > 0)
{
syn_id2colors(id, &fg, &bg);
if (sgp->sg_gui_fg == INVALCOLOR)
sgp->sg_gui_fg = fg;
if (sgp->sg_gui_bg == INVALCOLOR)
sgp->sg_gui_bg = bg;
}
}
# endif
at_en.ae_u.cterm.fg_rgb = GUI_MCH_GET_RGB2(sgp->sg_gui_fg); at_en.ae_u.cterm.fg_rgb = GUI_MCH_GET_RGB2(sgp->sg_gui_fg);
at_en.ae_u.cterm.bg_rgb = GUI_MCH_GET_RGB2(sgp->sg_gui_bg); at_en.ae_u.cterm.bg_rgb = GUI_MCH_GET_RGB2(sgp->sg_gui_bg);
# endif # endif

View File

@@ -76,7 +76,6 @@ struct builtin_term
static struct builtin_term *find_builtin_term(char_u *name); static struct builtin_term *find_builtin_term(char_u *name);
static void parse_builtin_tcap(char_u *s); static void parse_builtin_tcap(char_u *s);
static void term_color(char_u *s, int n);
static void gather_termleader(void); static void gather_termleader(void);
#ifdef FEAT_TERMRESPONSE #ifdef FEAT_TERMRESPONSE
static void req_codes_from_term(void); static void req_codes_from_term(void);
@@ -600,6 +599,10 @@ static struct builtin_term builtin_termcaps[] =
# else # else
{(int)KS_CS, "\033|%i%d;%dr"},/* scroll region */ {(int)KS_CS, "\033|%i%d;%dr"},/* scroll region */
# endif # endif
# ifdef FEAT_TERMGUICOLORS
{(int)KS_8F, "\033|38;2;%lu;%lu;%lum"},
{(int)KS_8B, "\033|48;2;%lu;%lu;%lum"},
# endif
{K_UP, "\316H"}, {K_UP, "\316H"},
{K_DOWN, "\316P"}, {K_DOWN, "\316P"},
@@ -2007,6 +2010,11 @@ set_termname(char_u *term)
may_req_termresponse(); may_req_termresponse();
#endif #endif
#if defined(WIN3264) && !defined(FEAT_GUI) && defined(FEAT_TERMGUICOLORS)
if (STRCMP(term, "win32") == 0)
set_color_count((p_tgc) ? 256 : 16);
#endif
return OK; return OK;
} }
@@ -2818,31 +2826,12 @@ term_set_winsize(int height, int width)
} }
#endif #endif
void
term_fg_color(int n)
{
/* Use "AF" termcap entry if present, "Sf" entry otherwise */
if (*T_CAF)
term_color(T_CAF, n);
else if (*T_CSF)
term_color(T_CSF, n);
}
void
term_bg_color(int n)
{
/* Use "AB" termcap entry if present, "Sb" entry otherwise */
if (*T_CAB)
term_color(T_CAB, n);
else if (*T_CSB)
term_color(T_CSB, n);
}
static void static void
term_color(char_u *s, int n) term_color(char_u *s, int n)
{ {
char buf[20]; char buf[20];
int i = 2; /* index in s[] just after <Esc>[ or CSI */ int i = *s == CSI ? 1 : 2;
/* index in s[] just after <Esc>[ or CSI */
/* Special handling of 16 colors, because termcap can't handle it */ /* Special handling of 16 colors, because termcap can't handle it */
/* Also accept "\e[3%dm" for TERMINFO, it is sometimes used */ /* Also accept "\e[3%dm" for TERMINFO, it is sometimes used */
@@ -2869,6 +2858,26 @@ term_color(char_u *s, int n)
OUT_STR(tgoto((char *)s, 0, n)); OUT_STR(tgoto((char *)s, 0, n));
} }
void
term_fg_color(int n)
{
/* Use "AF" termcap entry if present, "Sf" entry otherwise */
if (*T_CAF)
term_color(T_CAF, n);
else if (*T_CSF)
term_color(T_CSF, n);
}
void
term_bg_color(int n)
{
/* Use "AB" termcap entry if present, "Sb" entry otherwise */
if (*T_CAB)
term_color(T_CAB, n);
else if (*T_CSB)
term_color(T_CSB, n);
}
#if defined(FEAT_TERMGUICOLORS) || defined(PROTO) #if defined(FEAT_TERMGUICOLORS) || defined(PROTO)
#define RED(rgb) (((long_u)(rgb) >> 16) & 0xFF) #define RED(rgb) (((long_u)(rgb) >> 16) & 0xFF)
@@ -6614,6 +6623,106 @@ update_tcap(int attr)
++p; ++p;
} }
} }
struct ks_tbl_s
{
int code; /* value of KS_ */
char *vtp; /* code in vtp mode */
char *buf; /* buffer in non-vtp mode */
char *vbuf; /* buffer in vtp mode */
};
static struct ks_tbl_s ks_tbl[] =
{
{(int)KS_ME, "\033|0m" }, /* normal */
{(int)KS_MR, "\033|7m" }, /* reverse */
{(int)KS_MD, "\033|1m" }, /* bold */
{(int)KS_SO, "\033|91m"}, /* standout: bright red text */
{(int)KS_SE, "\033|39m"}, /* standout end: default color */
{(int)KS_CZH, "\033|95m"}, /* italic: bright magenta text */
{(int)KS_CZR, "\033|0m",}, /* italic end */
{(int)KS_US, "\033|4m",}, /* underscore */
{(int)KS_UE, "\033|24m"}, /* underscore end */
{(int)KS_NAME, NULL}
};
static struct builtin_term *
find_first_tcap(
char_u *name,
int code)
{
struct builtin_term *p;
p = find_builtin_term(name);
while (p->bt_string != NULL)
{
if (p->bt_entry == code)
return p;
p++;
}
return NULL;
}
/*
* For Win32 console: replace the sequence immediately after termguicolors.
*/
void
swap_tcap(void)
{
# ifdef FEAT_TERMGUICOLORS
static int init = 0;
static int last_tgc;
struct ks_tbl_s *ks;
struct builtin_term *bt;
/* buffer initialization */
if (init == 0)
{
ks = ks_tbl;
while (ks->vtp != NULL)
{
bt = find_first_tcap(DEFAULT_TERM, ks->code);
ks->buf = bt->bt_string;
ks->vbuf = ks->vtp;
ks++;
}
init++;
last_tgc = p_tgc;
return;
}
if (last_tgc != p_tgc)
{
if (p_tgc)
{
/* switch to special character sequence */
ks = ks_tbl;
while (ks->vtp != NULL)
{
bt = find_first_tcap(DEFAULT_TERM, ks->code);
ks->buf = bt->bt_string;
bt->bt_string = ks->vbuf;
ks++;
}
}
else
{
/* switch to index color */
ks = ks_tbl;
while (ks->vtp != NULL)
{
bt = find_first_tcap(DEFAULT_TERM, ks->code);
ks->vbuf = bt->bt_string;
bt->bt_string = ks->buf;
ks++;
}
}
last_tgc = p_tgc;
}
# endif
}
#endif #endif
#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) || defined(PROTO) #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) || defined(PROTO)

View File

@@ -129,6 +129,7 @@ let test_values = {
\ 'switchbuf': [['', 'useopen', 'split,newtab'], ['xxx']], \ 'switchbuf': [['', 'useopen', 'split,newtab'], ['xxx']],
\ 'tagcase': [['smart', 'match'], ['', 'xxx', 'smart,match']], \ 'tagcase': [['smart', 'match'], ['', 'xxx', 'smart,match']],
\ 'term': [[], []], \ 'term': [[], []],
\ 'termguicolors': [[], []],
\ 'termsize': [['', '24x80', '0x80', '32x0', '0x0'], ['xxx', '80', '8ax9', '24x80b']], \ 'termsize': [['', '24x80', '0x80', '32x0', '0x0'], ['xxx', '80', '8ax9', '24x80b']],
\ 'termencoding': [has('gui_gtk') ? [] : ['', 'utf-8'], ['xxx']], \ 'termencoding': [has('gui_gtk') ? [] : ['', 'utf-8'], ['xxx']],
\ 'toolbar': [['', 'icons', 'text'], ['xxx']], \ 'toolbar': [['', 'icons', 'text'], ['xxx']],

View File

@@ -699,6 +699,13 @@ static char *(features[]) =
#else #else
"-vreplace", "-vreplace",
#endif #endif
#ifdef WIN3264
# ifdef FEAT_VTP
"+vtp",
# else
"-vtp",
# endif
#endif
#ifdef FEAT_WILDIGN #ifdef FEAT_WILDIGN
"+wildignore", "+wildignore",
#else #else
@@ -771,6 +778,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1531,
/**/ /**/
1530, 1530,
/**/ /**/