comparison src/os_win32.c @ 20227:f2e4c12b24b3 v8.2.0669

patch 8.2.0669: MS-Windows: display in VTP is a bit slow Commit: https://github.com/vim/vim/commit/4e5534fab798ab7c95554da3bc80b08336aedc2b Author: Bram Moolenaar <Bram@vim.org> Date: Thu Apr 30 20:59:57 2020 +0200 patch 8.2.0669: MS-Windows: display in VTP is a bit slow Problem: MS-Windows: display in VTP is a bit slow. Solution: Optimize the code. (Nobuhiro Takasaki, closes https://github.com/vim/vim/issues/6014)
author Bram Moolenaar <Bram@vim.org>
date Thu, 30 Apr 2020 21:15:04 +0200
parents 304015471ae9
children 3bb4dea4a164
comparison
equal deleted inserted replaced
20226:6ffcab677df2 20227:f2e4c12b24b3
5577 static void 5577 static void
5578 clear_chars( 5578 clear_chars(
5579 COORD coord, 5579 COORD coord,
5580 DWORD n) 5580 DWORD n)
5581 { 5581 {
5582 DWORD dwDummy;
5583
5584 FillConsoleOutputCharacter(g_hConOut, ' ', n, coord, &dwDummy);
5585
5586 if (!USE_VTP) 5582 if (!USE_VTP)
5587 FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, n, coord, &dwDummy); 5583 {
5584 DWORD dwDummy;
5585
5586 FillConsoleOutputCharacter(g_hConOut, ' ', n, coord, &dwDummy);
5587 FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, n, coord,
5588 &dwDummy);
5589 }
5588 else 5590 else
5589 { 5591 {
5590 set_console_color_rgb(); 5592 set_console_color_rgb();
5591 gotoxy(coord.X + 1, coord.Y + 1); 5593 gotoxy(coord.X + 1, coord.Y + 1);
5592 vtp_printf("\033[%dX", n); 5594 vtp_printf("\033[%dX", n);
6034 char_u *pchBuf, 6036 char_u *pchBuf,
6035 DWORD cbToWrite) 6037 DWORD cbToWrite)
6036 { 6038 {
6037 COORD coord = g_coord; 6039 COORD coord = g_coord;
6038 DWORD written; 6040 DWORD written;
6039 DWORD n, cchwritten, cells; 6041 DWORD n, cchwritten;
6042 static DWORD cells;
6040 static WCHAR *unicodebuf = NULL; 6043 static WCHAR *unicodebuf = NULL;
6041 static int unibuflen = 0; 6044 static int unibuflen = 0;
6042 int length; 6045 static int length;
6043 int cp = enc_utf8 ? CP_UTF8 : enc_codepage; 6046 int cp = enc_utf8 ? CP_UTF8 : enc_codepage;
6044 6047 static WCHAR *utf8spbuf = NULL;
6045 length = MultiByteToWideChar(cp, 0, (LPCSTR)pchBuf, cbToWrite, 0, 0); 6048 static int utf8splength;
6046 if (unicodebuf == NULL || length > unibuflen) 6049 static DWORD utf8spcells;
6047 { 6050 static WCHAR **utf8usingbuf = &unicodebuf;
6048 vim_free(unicodebuf); 6051
6049 unicodebuf = LALLOC_MULT(WCHAR, length); 6052 if (cbToWrite != 1 || *pchBuf != ' ' || !enc_utf8)
6050 unibuflen = length; 6053 {
6051 } 6054 utf8usingbuf = &unicodebuf;
6052 MultiByteToWideChar(cp, 0, (LPCSTR)pchBuf, cbToWrite, 6055 do
6053 unicodebuf, unibuflen); 6056 {
6054 6057 length = MultiByteToWideChar(cp, 0, (LPCSTR)pchBuf, cbToWrite,
6055 cells = mb_string2cells(pchBuf, cbToWrite); 6058 unicodebuf, unibuflen);
6059 if (length && length <= unibuflen)
6060 break;
6061 vim_free(unicodebuf);
6062 unicodebuf = length ? LALLOC_MULT(WCHAR, length) : NULL;
6063 unibuflen = unibuflen ? 0 : length;
6064 } while(1);
6065 cells = mb_string2cells(pchBuf, cbToWrite);
6066 }
6067 else // cbToWrite == 1 && *pchBuf == ' ' && enc_utf8
6068 {
6069 if (utf8usingbuf != &utf8spbuf)
6070 {
6071 if (utf8spbuf == NULL)
6072 {
6073 cells = mb_string2cells((char_u *)" ", 1);
6074 length = MultiByteToWideChar(CP_UTF8, 0, " ", 1, NULL, 0);
6075 utf8spbuf = LALLOC_MULT(WCHAR, length);
6076 if (utf8spbuf != NULL)
6077 {
6078 MultiByteToWideChar(CP_UTF8, 0, " ", 1, utf8spbuf, length);
6079 utf8usingbuf = &utf8spbuf;
6080 utf8splength = length;
6081 utf8spcells = cells;
6082 }
6083 }
6084 else
6085 {
6086 utf8usingbuf = &utf8spbuf;
6087 length = utf8splength;
6088 cells = utf8spcells;
6089 }
6090 }
6091 }
6056 6092
6057 if (!USE_VTP) 6093 if (!USE_VTP)
6058 { 6094 {
6059 FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cells, 6095 FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, cells,
6060 coord, &written); 6096 coord, &written);
6061 // When writing fails or didn't write a single character, pretend one 6097 // When writing fails or didn't write a single character, pretend one
6062 // character was written, otherwise we get stuck. 6098 // character was written, otherwise we get stuck.
6063 if (WriteConsoleOutputCharacterW(g_hConOut, unicodebuf, length, 6099 if (WriteConsoleOutputCharacterW(g_hConOut, *utf8usingbuf, length,
6064 coord, &cchwritten) == 0 6100 coord, &cchwritten) == 0
6065 || cchwritten == 0 || cchwritten == (DWORD)-1) 6101 || cchwritten == 0 || cchwritten == (DWORD)-1)
6066 cchwritten = 1; 6102 cchwritten = 1;
6067 } 6103 }
6068 else 6104 else
6069 { 6105 {
6070 if (WriteConsoleW(g_hConOut, unicodebuf, length, &cchwritten, 6106 if (WriteConsoleW(g_hConOut, *utf8usingbuf, length, &cchwritten,
6071 NULL) == 0 || cchwritten == 0) 6107 NULL) == 0 || cchwritten == 0)
6072 cchwritten = 1; 6108 cchwritten = 1;
6073 } 6109 }
6074 6110
6075 if (cchwritten == length) 6111 if (cchwritten == length)
6091 g_coord.X -= (SHORT) Columns; 6127 g_coord.X -= (SHORT) Columns;
6092 if (g_coord.Y < g_srScrollRegion.Bottom) 6128 if (g_coord.Y < g_srScrollRegion.Bottom)
6093 g_coord.Y++; 6129 g_coord.Y++;
6094 } 6130 }
6095 6131
6096 gotoxy(g_coord.X + 1, g_coord.Y + 1); 6132 // Cursor under VTP is always in the correct position, no need to reset.
6133 if (!USE_VTP)
6134 gotoxy(g_coord.X + 1, g_coord.Y + 1);
6097 6135
6098 return written; 6136 return written;
6099 } 6137 }
6100 6138
6139 static char_u *
6140 get_seq(
6141 int *args,
6142 int *count,
6143 char_u *head)
6144 {
6145 int argc;
6146 char_u *p;
6147
6148 if (head == NULL || *head != '\033')
6149 return NULL;
6150
6151 argc = 0;
6152 p = head;
6153 ++p;
6154 do
6155 {
6156 ++p;
6157 args[argc] = getdigits(&p);
6158 argc += (argc < 15) ? 1 : 0;
6159 } while (*p == ';');
6160 *count = argc;
6161
6162 return p;
6163 }
6164
6165 static char_u *
6166 get_sgr(
6167 int *args,
6168 int *count,
6169 char_u *head)
6170 {
6171 char_u *p = get_seq(args, count, head);
6172
6173 return (p && *p == 'm') ? ++p : NULL;
6174 }
6175
6176 /*
6177 * Pointer to next if SGR (^[[n;2;*;*;*m), NULL otherwise.
6178 */
6179 static char_u *
6180 sgrn2(
6181 char_u *head,
6182 int n)
6183 {
6184 int argc;
6185 int args[16];
6186 char_u *p = get_sgr(args, &argc, head);
6187
6188 return p && argc == 5 && args[0] == n && args[1] == 2 ? p : NULL;
6189 }
6190
6191 /*
6192 * Pointer to next if SGR(^[[nm)<space>ESC, NULL otherwise.
6193 */
6194 static char_u *
6195 sgrnc(
6196 char_u *head,
6197 int n)
6198 {
6199 int argc;
6200 int args[16];
6201 char_u *p = get_sgr(args, &argc, head);
6202
6203 return p && argc == 1 && args[0] == n && (p = skipwhite(p)) && *p == '\033'
6204 ? p : NULL;
6205 }
6206
6207 static char_u *
6208 skipblank(char_u *q)
6209 {
6210 char_u *p = q;
6211
6212 while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')
6213 ++p;
6214 return p;
6215 }
6216
6217 /*
6218 * Pointer to the next if any whitespace that may follow SGR is ESC, otherwise
6219 * NULL.
6220 */
6221 static char_u *
6222 sgrn2c(
6223 char_u *head,
6224 int n)
6225 {
6226 char_u *p = sgrn2(head, n);
6227
6228 return p && *p != NUL && (p = skipblank(p)) && *p == '\033' ? p : NULL;
6229 }
6230
6231 /*
6232 * If there is only a newline between the sequence immediately following it,
6233 * a pointer to the character following the newline is returned.
6234 * Otherwise NULL.
6235 */
6236 static char_u *
6237 sgrn2cn(
6238 char_u *head,
6239 int n)
6240 {
6241 char_u *p = sgrn2(head, n);
6242
6243 return p && p[0] == 0x0a && p[1] == '\033' ? ++p : NULL;
6244 }
6101 6245
6102 /* 6246 /*
6103 * mch_write(): write the output buffer to the screen, translating ESC 6247 * mch_write(): write the output buffer to the screen, translating ESC
6104 * sequences into calls to console output routines. 6248 * sequences into calls to console output routines.
6105 */ 6249 */
6122 } 6266 }
6123 6267
6124 // translate ESC | sequences into faked bios calls 6268 // translate ESC | sequences into faked bios calls
6125 while (len--) 6269 while (len--)
6126 { 6270 {
6127 // optimization: use one single write_chars for runs of text, 6271 int prefix = -1;
6128 // rather than once per character It ain't curses, but it helps. 6272 char_u ch;
6129 DWORD prefix = (DWORD)strcspn((char *)s, "\n\r\b\a\033"); 6273
6274 // While processing a sequence, on rare occasions it seems that another
6275 // sequence may be inserted asynchronously.
6276 if (len < 0)
6277 {
6278 redraw_all_later(CLEAR);
6279 return;
6280 }
6281
6282 while((ch = s[++prefix]))
6283 if (ch <= 0x1e && !(ch != '\n' && ch != '\r' && ch != '\b'
6284 && ch != '\a' && ch != '\033'))
6285 break;
6130 6286
6131 if (p_wd) 6287 if (p_wd)
6132 { 6288 {
6133 WaitForChar(p_wd, FALSE); 6289 WaitForChar(p_wd, FALSE);
6134 if (prefix != 0) 6290 if (prefix != 0)
6211 # ifdef MCH_WRITE_DUMP 6367 # ifdef MCH_WRITE_DUMP
6212 char_u *old_s = s; 6368 char_u *old_s = s;
6213 # endif 6369 # endif
6214 char_u *p; 6370 char_u *p;
6215 int arg1 = 0, arg2 = 0, argc = 0, args[16]; 6371 int arg1 = 0, arg2 = 0, argc = 0, args[16];
6372 char_u *sp;
6216 6373
6217 switch (s[2]) 6374 switch (s[2])
6218 { 6375 {
6219 case '0': case '1': case '2': case '3': case '4': 6376 case '0': case '1': case '2': case '3': case '4':
6220 case '5': case '6': case '7': case '8': case '9': 6377 case '5': case '6': case '7': case '8': case '9':
6221 p = s + 1; 6378 if (*(p = get_seq(args, &argc, s)) != 'm')
6222 do 6379 goto notsgr;
6380
6381 p = s;
6382
6383 // Handling frequent optional sequences. Output to the screen
6384 // takes too long, so do not output as much as possible.
6385
6386 // If resetFG,FG,BG,<cr>,BG,FG are connected, the preceding
6387 // resetFG,FG,BG are omitted.
6388 if (sgrn2(sgrn2(sgrn2cn(sgrn2(sgrnc(p, 39), 38), 48), 48), 38))
6223 { 6389 {
6224 ++p; 6390 p = sgrn2(sgrn2(sgrnc(p, 39), 38), 48);
6225 args[argc] = getdigits(&p); 6391 len = len + 1 - (int)(p - s);
6226 argc += (argc < 15) ? 1 : 0; 6392 s = p;
6227 if (p > s + len)
6228 break;
6229 } while (*p == ';');
6230
6231 if (p > s + len)
6232 break; 6393 break;
6233 6394 }
6395
6396 // If FG,BG,BG,FG of SGR are connected, the first FG can be
6397 // omitted.
6398 if (sgrn2(sgrn2(sgrn2c((sp = sgrn2(p, 38)), 48), 48), 38))
6399 p = sp;
6400
6401 // If FG,BG,FG,BG of SGR are connected, the first FG can be
6402 // omitted.
6403 if (sgrn2(sgrn2(sgrn2c((sp = sgrn2(p, 38)), 48), 38), 48))
6404 p = sp;
6405
6406 // If BG,BG of SGR are connected, the first BG can be omitted.
6407 if (sgrn2((sp = sgrn2(p, 48)), 48))
6408 p = sp;
6409
6410 // If restoreFG and FG are connected, the restoreFG can be
6411 // omitted.
6412 if (sgrn2((sp = sgrnc(p, 39)), 38))
6413 p = sp;
6414
6415 p = get_seq(args, &argc, p);
6416
6417 notsgr:
6234 arg1 = args[0]; 6418 arg1 = args[0];
6235 arg2 = args[1]; 6419 arg2 = args[1];
6236 if (*p == 'm') 6420 if (*p == 'm')
6237 { 6421 {
6238 if (argc == 1 && args[0] == 0) 6422 if (argc == 1 && args[0] == 0)
7404 ...) 7588 ...)
7405 { 7589 {
7406 char_u buf[100]; 7590 char_u buf[100];
7407 va_list list; 7591 va_list list;
7408 DWORD result; 7592 DWORD result;
7593 int len;
7409 7594
7410 va_start(list, format); 7595 va_start(list, format);
7411 vim_vsnprintf((char *)buf, 100, (char *)format, list); 7596 len = vim_vsnprintf((char *)buf, 100, (char *)format, list);
7412 va_end(list); 7597 va_end(list);
7413 WriteConsoleA(g_hConOut, buf, (DWORD)STRLEN(buf), &result, NULL); 7598 WriteConsoleA(g_hConOut, buf, (DWORD)len, &result, NULL);
7414 return (int)result; 7599 return (int)result;
7415 } 7600 }
7416 7601
7417 static void 7602 static void
7418 vtp_sgr_bulk( 7603 vtp_sgr_bulk(
7422 7607
7423 args[0] = arg; 7608 args[0] = arg;
7424 vtp_sgr_bulks(1, args); 7609 vtp_sgr_bulks(1, args);
7425 } 7610 }
7426 7611
7612 #define FAST256(x) \
7613 if ((*p-- = "0123456789"[(n = x % 10)]) \
7614 && x >= 10 && (*p-- = "0123456789"[((m = x % 100) - n) / 10]) \
7615 && x >= 100 && (*p-- = "012"[((x & 0xff) - m) / 100]));
7616
7617 #define FAST256CASE(x) \
7618 case x: \
7619 FAST256(newargs[x - 1]);
7620
7427 static void 7621 static void
7428 vtp_sgr_bulks( 7622 vtp_sgr_bulks(
7429 int argc, 7623 int argc,
7430 int *args 7624 int *args)
7431 ) 7625 {
7432 { 7626 #define MAXSGR 16
7433 // 2('\033[') + 4('255.') * 16 + NUL 7627 #define SGRBUFSIZE 2 + 4 * MAXSGR + 1 // '\033[' + SGR + 'm'
7434 char_u buf[2 + (4 * 16) + 1]; 7628 char_u buf[SGRBUFSIZE];
7435 char_u *p; 7629 char_u *p;
7436 int i; 7630 int in, out;
7437 7631 int newargs[16];
7438 p = buf; 7632 static int sgrfgr = -1, sgrfgg, sgrfgb;
7439 *p++ = '\033'; 7633 static int sgrbgr = -1, sgrbgg, sgrbgb;
7440 *p++ = '['; 7634
7441 7635 if (argc == 0)
7442 for (i = 0; i < argc; ++i) 7636 {
7443 { 7637 sgrfgr = sgrbgr = -1;
7444 p += vim_snprintf((char *)p, 4, "%d", args[i] & 0xff); 7638 vtp_printf("033[m");
7445 *p++ = ';'; 7639 return;
7446 } 7640 }
7447 p--; 7641
7448 *p++ = 'm'; 7642 in = out = 0;
7449 *p = NUL; 7643 while (in < argc)
7450 vtp_printf((char *)buf); 7644 {
7645 int s = args[in];
7646 int copylen = 1;
7647
7648 if (s == 38)
7649 {
7650 if (argc - in >= 5 && args[in + 1] == 2)
7651 {
7652 if (sgrfgr == args[in + 2] && sgrfgg == args[in + 3]
7653 && sgrfgb == args[in + 4])
7654 {
7655 in += 5;
7656 copylen = 0;
7657 }
7658 else
7659 {
7660 sgrfgr = args[in + 2];
7661 sgrfgg = args[in + 3];
7662 sgrfgb = args[in + 4];
7663 copylen = 5;
7664 }
7665 }
7666 else if (argc - in >= 3 && args[in + 1] == 5)
7667 {
7668 sgrfgr = -1;
7669 copylen = 3;
7670 }
7671 }
7672 else if (s == 48)
7673 {
7674 if (argc - in >= 5 && args[in + 1] == 2)
7675 {
7676 if (sgrbgr == args[in + 2] && sgrbgg == args[in + 3]
7677 && sgrbgb == args[in + 4])
7678 {
7679 in += 5;
7680 copylen = 0;
7681 }
7682 else
7683 {
7684 sgrbgr = args[in + 2];
7685 sgrbgg = args[in + 3];
7686 sgrbgb = args[in + 4];
7687 copylen = 5;
7688 }
7689 }
7690 else if (argc - in >= 3 && args[in + 1] == 5)
7691 {
7692 sgrbgr = -1;
7693 copylen = 3;
7694 }
7695 }
7696 else if (30 <= s && s <= 39)
7697 sgrfgr = -1;
7698 else if (90 <= s && s <= 97)
7699 sgrfgr = -1;
7700 else if (40 <= s && s <= 49)
7701 sgrbgr = -1;
7702 else if (100 <= s && s <= 107)
7703 sgrbgr = -1;
7704 else if (s == 0)
7705 sgrfgr = sgrbgr = -1;
7706
7707 while (copylen--)
7708 newargs[out++] = args[in++];
7709 }
7710
7711 p = &buf[sizeof(buf) - 1];
7712 *p-- = 'm';
7713
7714 switch (out)
7715 {
7716 int n, m;
7717 DWORD r;
7718
7719 FAST256CASE(16);
7720 *p-- = ';';
7721 FAST256CASE(15);
7722 *p-- = ';';
7723 FAST256CASE(14);
7724 *p-- = ';';
7725 FAST256CASE(13);
7726 *p-- = ';';
7727 FAST256CASE(12);
7728 *p-- = ';';
7729 FAST256CASE(11);
7730 *p-- = ';';
7731 FAST256CASE(10);
7732 *p-- = ';';
7733 FAST256CASE(9);
7734 *p-- = ';';
7735 FAST256CASE(8);
7736 *p-- = ';';
7737 FAST256CASE(7);
7738 *p-- = ';';
7739 FAST256CASE(6);
7740 *p-- = ';';
7741 FAST256CASE(5);
7742 *p-- = ';';
7743 FAST256CASE(4);
7744 *p-- = ';';
7745 FAST256CASE(3);
7746 *p-- = ';';
7747 FAST256CASE(2);
7748 *p-- = ';';
7749 FAST256CASE(1);
7750 *p-- = '[';
7751 *p = '\033';
7752 WriteConsoleA(g_hConOut, p, (DWORD)(&buf[SGRBUFSIZE] - p), &r, NULL);
7753 default:
7754 break;
7755 }
7451 } 7756 }
7452 7757
7453 # ifdef FEAT_TERMGUICOLORS 7758 # ifdef FEAT_TERMGUICOLORS
7454 static int 7759 static int
7455 ctermtoxterm( 7760 ctermtoxterm(