Mercurial > vim
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( |