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 -- [email protected] -- 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    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202004301900.03UJ0ZTi031717%40masaka.moolenaar.net.

Raspunde prin e-mail lui