Patch 8.2.0669
Problem: MS-Windows: display in VTP is a bit slow.
Solution: Optimize the code. (Nobuhiro Takasaki, closes #6014)
Files: src/os_win32.c, src/screen.c
*** ../vim-8.2.0668/src/os_win32.c 2020-04-28 20:44:38.872258441 +0200
--- src/os_win32.c 2020-04-30 20:55:23.813526617 +0200
***************
*** 5579,5590 ****
COORD coord,
DWORD n)
{
- DWORD dwDummy;
-
- FillConsoleOutputCharacter(g_hConOut, ' ', n, coord, &dwDummy);
-
if (!USE_VTP)
! FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, n, coord, &dwDummy);
else
{
set_console_color_rgb();
--- 5579,5592 ----
COORD coord,
DWORD n)
{
if (!USE_VTP)
! {
! DWORD dwDummy;
!
! FillConsoleOutputCharacter(g_hConOut, ' ', n, coord, &dwDummy);
! FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, n, coord,
! &dwDummy);
! }
else
{
set_console_color_rgb();
***************
*** 6036,6058 ****
{
COORD coord = g_coord;
DWORD written;
! DWORD n, cchwritten, cells;
static WCHAR *unicodebuf = NULL;
static int unibuflen = 0;
! int length;
int cp = enc_utf8 ? CP_UTF8 : enc_codepage;
!
! length = MultiByteToWideChar(cp, 0, (LPCSTR)pchBuf, cbToWrite, 0, 0);
! if (unicodebuf == NULL || length > unibuflen)
{
! vim_free(unicodebuf);
! unicodebuf = LALLOC_MULT(WCHAR, length);
! unibuflen = length;
}
- MultiByteToWideChar(cp, 0, (LPCSTR)pchBuf, cbToWrite,
- unicodebuf, unibuflen);
-
- cells = mb_string2cells(pchBuf, cbToWrite);
if (!USE_VTP)
{
--- 6038,6094 ----
{
COORD coord = g_coord;
DWORD written;
! DWORD n, cchwritten;
! static DWORD cells;
static WCHAR *unicodebuf = NULL;
static int unibuflen = 0;
! static int length;
int cp = enc_utf8 ? CP_UTF8 : enc_codepage;
! static WCHAR *utf8spbuf = NULL;
! static int utf8splength;
! static DWORD utf8spcells;
! static WCHAR **utf8usingbuf = &unicodebuf;
!
! if (cbToWrite != 1 || *pchBuf != ' ' || !enc_utf8)
! {
! utf8usingbuf = &unicodebuf;
! do
! {
! length = MultiByteToWideChar(cp, 0, (LPCSTR)pchBuf, cbToWrite,
! unicodebuf, unibuflen);
! if (length && length <= unibuflen)
! break;
! vim_free(unicodebuf);
! unicodebuf = length ? LALLOC_MULT(WCHAR, length) : NULL;
! unibuflen = unibuflen ? 0 : length;
! } while(1);
! cells = mb_string2cells(pchBuf, cbToWrite);
! }
! else // cbToWrite == 1 && *pchBuf == ' ' && enc_utf8
{
! if (utf8usingbuf != &utf8spbuf)
! {
! if (utf8spbuf == NULL)
! {
! cells = mb_string2cells((char_u *)" ", 1);
! length = MultiByteToWideChar(CP_UTF8, 0, " ", 1, NULL, 0);
! utf8spbuf = LALLOC_MULT(WCHAR, length);
! if (utf8spbuf != NULL)
! {
! MultiByteToWideChar(CP_UTF8, 0, " ", 1, utf8spbuf, length);
! utf8usingbuf = &utf8spbuf;
! utf8splength = length;
! utf8spcells = cells;
! }
! }
! else
! {
! utf8usingbuf = &utf8spbuf;
! length = utf8splength;
! cells = utf8spcells;
! }
! }
}
if (!USE_VTP)
{
***************
*** 6060,6073 ****
coord, &written);
// When writing fails or didn't write a single character, pretend one
// character was written, otherwise we get stuck.
! if (WriteConsoleOutputCharacterW(g_hConOut, unicodebuf, length,
coord, &cchwritten) == 0
|| cchwritten == 0 || cchwritten == (DWORD)-1)
cchwritten = 1;
}
else
{
! if (WriteConsoleW(g_hConOut, unicodebuf, length, &cchwritten,
NULL) == 0 || cchwritten == 0)
cchwritten = 1;
}
--- 6096,6109 ----
coord, &written);
// When writing fails or didn't write a single character, pretend one
// character was written, otherwise we get stuck.
! if (WriteConsoleOutputCharacterW(g_hConOut, *utf8usingbuf, length,
coord, &cchwritten) == 0
|| cchwritten == 0 || cchwritten == (DWORD)-1)
cchwritten = 1;
}
else
{
! if (WriteConsoleW(g_hConOut, *utf8usingbuf, length, &cchwritten,
NULL) == 0 || cchwritten == 0)
cchwritten = 1;
}
***************
*** 6093,6103 ****
g_coord.Y++;
}
! gotoxy(g_coord.X + 1, g_coord.Y + 1);
return written;
}
/*
* mch_write(): write the output buffer to the screen, translating ESC
--- 6129,6247 ----
g_coord.Y++;
}
! // Cursor under VTP is always in the correct position, no need to reset.
! if (!USE_VTP)
! gotoxy(g_coord.X + 1, g_coord.Y + 1);
return written;
}
+ static char_u *
+ get_seq(
+ int *args,
+ int *count,
+ char_u *head)
+ {
+ int argc;
+ char_u *p;
+
+ if (head == NULL || *head != '\033')
+ return NULL;
+
+ argc = 0;
+ p = head;
+ ++p;
+ do
+ {
+ ++p;
+ args[argc] = getdigits(&p);
+ argc += (argc < 15) ? 1 : 0;
+ } while (*p == ';');
+ *count = argc;
+
+ return p;
+ }
+
+ static char_u *
+ get_sgr(
+ int *args,
+ int *count,
+ char_u *head)
+ {
+ char_u *p = get_seq(args, count, head);
+
+ return (p && *p == 'm') ? ++p : NULL;
+ }
+
+ /*
+ * Pointer to next if SGR (^[[n;2;*;*;*m), NULL otherwise.
+ */
+ static char_u *
+ sgrn2(
+ char_u *head,
+ int n)
+ {
+ int argc;
+ int args[16];
+ char_u *p = get_sgr(args, &argc, head);
+
+ return p && argc == 5 && args[0] == n && args[1] == 2 ? p : NULL;
+ }
+
+ /*
+ * Pointer to next if SGR(^[[nm)<space>ESC, NULL otherwise.
+ */
+ static char_u *
+ sgrnc(
+ char_u *head,
+ int n)
+ {
+ int argc;
+ int args[16];
+ char_u *p = get_sgr(args, &argc, head);
+
+ return p && argc == 1 && args[0] == n && (p = skipwhite(p)) && *p == '\033'
+ ? p : NULL;
+ }
+
+ static char_u *
+ skipblank(char_u *q)
+ {
+ char_u *p = q;
+
+ while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')
+ ++p;
+ return p;
+ }
+
+ /*
+ * Pointer to the next if any whitespace that may follow SGR is ESC, otherwise
+ * NULL.
+ */
+ static char_u *
+ sgrn2c(
+ char_u *head,
+ int n)
+ {
+ char_u *p = sgrn2(head, n);
+
+ return p && *p != NUL && (p = skipblank(p)) && *p == '\033' ? p : NULL;
+ }
+
+ /*
+ * If there is only a newline between the sequence immediately following it,
+ * a pointer to the character following the newline is returned.
+ * Otherwise NULL.
+ */
+ static char_u *
+ sgrn2cn(
+ char_u *head,
+ int n)
+ {
+ char_u *p = sgrn2(head, n);
+
+ return p && p[0] == 0x0a && p[1] == '\033' ? ++p : NULL;
+ }
/*
* mch_write(): write the output buffer to the screen, translating ESC
***************
*** 6124,6132 ****
// translate ESC | sequences into faked bios calls
while (len--)
{
! // optimization: use one single write_chars for runs of text,
! // rather than once per character It ain't curses, but it helps.
! DWORD prefix = (DWORD)strcspn((char *)s, "\n\r\b\a\033");
if (p_wd)
{
--- 6268,6288 ----
// translate ESC | sequences into faked bios calls
while (len--)
{
! int prefix = -1;
! char_u ch;
!
! // While processing a sequence, on rare occasions it seems that another
! // sequence may be inserted asynchronously.
! if (len < 0)
! {
! redraw_all_later(CLEAR);
! return;
! }
!
! while((ch = s[++prefix]))
! if (ch <= 0x1e && !(ch != '\n' && ch != '\r' && ch != '\b'
! && ch != '\a' && ch != '\033'))
! break;
if (p_wd)
{
***************
*** 6213,6236 ****
# endif
char_u *p;
int arg1 = 0, arg2 = 0, argc = 0, args[16];
switch (s[2])
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
! p = s + 1;
! do
! {
! ++p;
! args[argc] = getdigits(&p);
! argc += (argc < 15) ? 1 : 0;
! if (p > s + len)
! break;
! } while (*p == ';');
! if (p > s + len)
break;
arg1 = args[0];
arg2 = args[1];
if (*p == 'm')
--- 6369,6420 ----
# endif
char_u *p;
int arg1 = 0, arg2 = 0, argc = 0, args[16];
+ char_u *sp;
switch (s[2])
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
! if (*(p = get_seq(args, &argc, s)) != 'm')
! goto notsgr;
! p = s;
!
! // Handling frequent optional sequences. Output to the screen
! // takes too long, so do not output as much as possible.
!
! // If resetFG,FG,BG,<cr>,BG,FG are connected, the preceding
! // resetFG,FG,BG are omitted.
! if (sgrn2(sgrn2(sgrn2cn(sgrn2(sgrnc(p, 39), 38), 48), 48), 38))
! {
! p = sgrn2(sgrn2(sgrnc(p, 39), 38), 48);
! len = len + 1 - (int)(p - s);
! s = p;
break;
+ }
+
+ // If FG,BG,BG,FG of SGR are connected, the first FG can be
+ // omitted.
+ if (sgrn2(sgrn2(sgrn2c((sp = sgrn2(p, 38)), 48), 48), 38))
+ p = sp;
+
+ // If FG,BG,FG,BG of SGR are connected, the first FG can be
+ // omitted.
+ if (sgrn2(sgrn2(sgrn2c((sp = sgrn2(p, 38)), 48), 38), 48))
+ p = sp;
+
+ // If BG,BG of SGR are connected, the first BG can be omitted.
+ if (sgrn2((sp = sgrn2(p, 48)), 48))
+ p = sp;
+
+ // If restoreFG and FG are connected, the restoreFG can be
+ // omitted.
+ if (sgrn2((sp = sgrnc(p, 39)), 38))
+ p = sp;
+
+ p = get_seq(args, &argc, p);
+ notsgr:
arg1 = args[0];
arg2 = args[1];
if (*p == 'm')
***************
*** 7406,7416 ****
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;
}
--- 7590,7601 ----
char_u buf[100];
va_list list;
DWORD result;
+ int len;
va_start(list, format);
! len = vim_vsnprintf((char *)buf, 100, (char *)format, list);
va_end(list);
! WriteConsoleA(g_hConOut, buf, (DWORD)len, &result, NULL);
return (int)result;
}
***************
*** 7424,7453 ****
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);
}
# ifdef FEAT_TERMGUICOLORS
--- 7609,7758 ----
vtp_sgr_bulks(1, args);
}
+ #define FAST256(x) \
+ if ((*p-- = "0123456789"[(n = x % 10)]) \
+ && x >= 10 && (*p-- = "0123456789"[((m = x % 100) - n) / 10]) \
+ && x >= 100 && (*p-- = "012"[((x & 0xff) - m) / 100]));
+
+ #define FAST256CASE(x) \
+ case x: \
+ FAST256(newargs[x - 1]);
+
static void
vtp_sgr_bulks(
int argc,
! int *args)
{
! #define MAXSGR 16
! #define SGRBUFSIZE 2 + 4 * MAXSGR + 1 // '\033[' + SGR + 'm'
! char_u buf[SGRBUFSIZE];
! char_u *p;
! int in, out;
! int newargs[16];
! static int sgrfgr = -1, sgrfgg, sgrfgb;
! static int sgrbgr = -1, sgrbgg, sgrbgb;
! if (argc == 0)
! {
! sgrfgr = sgrbgr = -1;
! vtp_printf("033[m");
! return;
! }
! in = out = 0;
! while (in < argc)
{
! int s = args[in];
! int copylen = 1;
!
! if (s == 38)
! {
! if (argc - in >= 5 && args[in + 1] == 2)
! {
! if (sgrfgr == args[in + 2] && sgrfgg == args[in + 3]
! && sgrfgb == args[in + 4])
! {
! in += 5;
! copylen = 0;
! }
! else
! {
! sgrfgr = args[in + 2];
! sgrfgg = args[in + 3];
! sgrfgb = args[in + 4];
! copylen = 5;
! }
! }
! else if (argc - in >= 3 && args[in + 1] == 5)
! {
! sgrfgr = -1;
! copylen = 3;
! }
! }
! else if (s == 48)
! {
! if (argc - in >= 5 && args[in + 1] == 2)
! {
! if (sgrbgr == args[in + 2] && sgrbgg == args[in + 3]
! && sgrbgb == args[in + 4])
! {
! in += 5;
! copylen = 0;
! }
! else
! {
! sgrbgr = args[in + 2];
! sgrbgg = args[in + 3];
! sgrbgb = args[in + 4];
! copylen = 5;
! }
! }
! else if (argc - in >= 3 && args[in + 1] == 5)
! {
! sgrbgr = -1;
! copylen = 3;
! }
! }
! else if (30 <= s && s <= 39)
! sgrfgr = -1;
! else if (90 <= s && s <= 97)
! sgrfgr = -1;
! else if (40 <= s && s <= 49)
! sgrbgr = -1;
! else if (100 <= s && s <= 107)
! sgrbgr = -1;
! else if (s == 0)
! sgrfgr = sgrbgr = -1;
!
! while (copylen--)
! newargs[out++] = args[in++];
! }
!
! p = &buf[sizeof(buf) - 1];
! *p-- = 'm';
!
! switch (out)
! {
! int n, m;
! DWORD r;
!
! FAST256CASE(16);
! *p-- = ';';
! FAST256CASE(15);
! *p-- = ';';
! FAST256CASE(14);
! *p-- = ';';
! FAST256CASE(13);
! *p-- = ';';
! FAST256CASE(12);
! *p-- = ';';
! FAST256CASE(11);
! *p-- = ';';
! FAST256CASE(10);
! *p-- = ';';
! FAST256CASE(9);
! *p-- = ';';
! FAST256CASE(8);
! *p-- = ';';
! FAST256CASE(7);
! *p-- = ';';
! FAST256CASE(6);
! *p-- = ';';
! FAST256CASE(5);
! *p-- = ';';
! FAST256CASE(4);
! *p-- = ';';
! FAST256CASE(3);
! *p-- = ';';
! FAST256CASE(2);
! *p-- = ';';
! FAST256CASE(1);
! *p-- = '[';
! *p = '\033';
! WriteConsoleA(g_hConOut, p, (DWORD)(&buf[SGRBUFSIZE] - p), &r, NULL);
! default:
! break;
}
}
# ifdef FEAT_TERMGUICOLORS
*** ../vim-8.2.0668/src/screen.c 2020-04-24 22:18:57.167585301 +0200
--- src/screen.c 2020-04-30 20:55:23.813526617 +0200
***************
*** 1880,1885 ****
--- 1880,1888 ----
screen_stop_highlight(void)
{
int do_ME = FALSE; // output T_ME code
+ #if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
+ int do_ME_fg, do_ME_bg;
+ #endif
if (screen_attr != 0
#ifdef MSWIN
***************
*** 1913,1928 ****
--- 1916,1957 ----
#ifdef FEAT_TERMGUICOLORS
p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR
? aep->ae_u.cterm.fg_rgb != INVALCOLOR
+ # ifdef FEAT_VTP
+ ? !(do_ME_fg = TRUE) : (do_ME_fg = FALSE)
+ # endif
:
#endif
aep->ae_u.cterm.fg_color) || (
#ifdef FEAT_TERMGUICOLORS
p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR
? aep->ae_u.cterm.bg_rgb != INVALCOLOR
+ # ifdef FEAT_VTP
+ ? !(do_ME_bg = TRUE) : (do_ME_bg = FALSE)
+ # endif
:
#endif
aep->ae_u.cterm.bg_color)))
do_ME = TRUE;
+ #if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS)
+ if (use_vtp())
+ {
+ if (do_ME_fg && do_ME_bg)
+ do_ME = TRUE;
+
+ // FG and BG cannot be separated in T_ME, which is not
+ // efficient.
+ if (!do_ME && do_ME_fg)
+ out_str((char_u *)"\033|39m"); // restore FG
+ if (!do_ME && do_ME_bg)
+ out_str((char_u *)"\033|49m"); // restore BG
+ }
+ else
+ {
+ // Process FG and BG at once.
+ if (!do_ME)
+ do_ME = do_ME_fg | do_ME_bg;
+ }
+ #endif
}
else
{
*** ../vim-8.2.0668/src/version.c 2020-04-30 20:21:36.028020847 +0200
--- src/version.c 2020-04-30 20:56:34.073287954 +0200
***************
*** 748,749 ****
--- 748,751 ----
{ /* Add new patch number below this line */
+ /**/
+ 669,
/**/
--
Due knot trussed yore spell chequer two fined awl miss steaks.
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language --
http://www.Zimbu.org ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///