Patch 8.2.2607
Problem:    strcharpart() cannot include composing characters.
Solution:   Add the {skipcc} argument.
Files:      runtime/doc/eval.txt, src/evalfunc.c,
            src/testdir/test_expr_utf8.vim


*** ../vim-8.2.2606/runtime/doc/eval.txt        2021-03-14 19:01:34.492421821 
+0100
--- runtime/doc/eval.txt        2021-03-14 19:44:29.039406627 +0100
***************
*** 1187,1193 ****
  
  In Vim9 script:
  If expr8 is a String this results in a String that contains the expr1'th
! single character from expr8.  To use byte indexes use |strpart()|.
  
  Index zero gives the first byte or character.  Careful: text column numbers
  start with one!
--- 1187,1194 ----
  
  In Vim9 script:
  If expr8 is a String this results in a String that contains the expr1'th
! single character (including any composing characters) from expr8.  To use byte
! indexes use |strpart()|.
  
  Index zero gives the first byte or character.  Careful: text column numbers
  start with one!
***************
*** 1217,1224 ****
  multibyte encodings, see |byteidx()| for computing the indexes.  If expr8 is
  a Number it is first converted to a String.
  
! In Vim9 script the indexes are character indexes.  To use byte indexes use
! |strpart()|.
  
  The item at index expr1b is included, it is inclusive.  For an exclusive index
  use the |slice()| function.
--- 1218,1226 ----
  multibyte encodings, see |byteidx()| for computing the indexes.  If expr8 is
  a Number it is first converted to a String.
  
! In Vim9 script the indexes are character indexes and include composing
! characters.  To use byte indexes use |strpart()|.  To use character indexes
! without including composing characters use |strcharpart()|.
  
  The item at index expr1b is included, it is inclusive.  For an exclusive index
  use the |slice()| function.
***************
*** 2924,2930 ****
  str2nr({expr} [, {base} [, {quoted}]])
                                Number  convert String to Number
  strcharlen({expr})            Number  character length of the String {expr}
! strcharpart({str}, {start} [, {len}])
                                String  {len} characters of {str} at
                                        character {start}
  strchars({expr} [, {skipcc}]) Number  character count of the String {expr}
--- 2926,2932 ----
  str2nr({expr} [, {base} [, {quoted}]])
                                Number  convert String to Number
  strcharlen({expr})            Number  character length of the String {expr}
! strcharpart({str}, {start} [, {len} [, {skipcc}]])
                                String  {len} characters of {str} at
                                        character {start}
  strchars({expr} [, {skipcc}]) Number  character count of the String {expr}
***************
*** 5904,5909 ****
--- 5911,5917 ----
                When the register was not set an empty list is returned.
  
                If {regname} is not specified, |v:register| is used.
+               In |Vim9-script| {regname} must be one character.
  
                Can also be used as a |method|: >
                        GetRegname()->getreg()
***************
*** 5931,5936 ****
--- 5939,5945 ----
                will be returned.
                If {regname} is not specified, |v:register| is used.
                The returned Dictionary can be passed to |setreg()|.
+               In |Vim9-script| {regname} must be one character.
  
                Can also be used as a |method|: >
                        GetRegname()->getreginfo()
***************
*** 5944,5949 ****
--- 5953,5959 ----
                    ""                  for an empty or unknown register
                <CTRL-V> is one character with value 0x16.
                If {regname} is not specified, |v:register| is used.
+               In |Vim9-script| {regname} must be one character.
  
                Can also be used as a |method|: >
                        GetRegname()->getregtype()
***************
*** 9659,9664 ****
--- 9669,9675 ----
  setreg({regname}, {value} [, {options}])
                Set the register {regname} to {value}.
                If {regname} is "" or "@", the unnamed register '"' is used.
+               In |Vim9-script| {regname} must be one character.
  
                {value} may be any value returned by |getreg()| or
                |getreginfo()|, including a |List| or |Dict|.
***************
*** 9910,9916 ****
                Similar to using a |slice| "expr[start : end]", but "end" is
                used exclusive.  And for a string the indexes are used as
                character indexes instead of byte indexes, like in
!               |vim9script|.
                When {end} is omitted the slice continues to the last item.
                When {end} is -1 the last item is omitted.
  
--- 9921,9927 ----
                Similar to using a |slice| "expr[start : end]", but "end" is
                used exclusive.  And for a string the indexes are used as
                character indexes instead of byte indexes, like in
!               |vim9script|.  Also, composing characters are not counted.
                When {end} is omitted the slice continues to the last item.
                When {end} is -1 the last item is omitted.
  
***************
*** 10281,10292 ****
                        GetText()->strcharlen()
  
  
! strcharpart({src}, {start} [, {len}])                 *strcharpart()*
                Like |strpart()| but using character index and length instead
!               of byte index and length.  Composing characters are counted
!               separately.
                When a character index is used where a character does not
!               exist it is assumed to be one character.  For example: >
                        strcharpart('abc', -1, 2)
  <             results in 'a'.
  
--- 10292,10307 ----
                        GetText()->strcharlen()
  
  
! strcharpart({src}, {start} [, {len} [, {skipcc}]])            *strcharpart()*
                Like |strpart()| but using character index and length instead
!               of byte index and length.
!               When {skipcc} is omitted or zero, composing characters are
!               counted separately.
!               When {skipcc} set to 1, Composing characters are ignored,
!               similar to  |slice()|.
                When a character index is used where a character does not
!               exist it is omitted and counted as one character.  For
!               example: >
                        strcharpart('abc', -1, 2)
  <             results in 'a'.
  
***************
*** 10300,10306 ****
                When {skipcc} is omitted or zero, composing characters are
                counted separately.
                When {skipcc} set to 1, Composing characters are ignored.
!               |strcharlen()| does the same.
  
                Also see |strlen()|, |strdisplaywidth()| and |strwidth()|.
  
--- 10315,10321 ----
                When {skipcc} is omitted or zero, composing characters are
                counted separately.
                When {skipcc} set to 1, Composing characters are ignored.
!               |strcharlen()| always does this.
  
                Also see |strlen()|, |strdisplaywidth()| and |strwidth()|.
  
*** ../vim-8.2.2606/src/evalfunc.c      2021-03-14 19:01:34.496421810 +0100
--- src/evalfunc.c      2021-03-14 19:25:38.477783640 +0100
***************
*** 1575,1581 ****
                        ret_number,         f_str2nr},
      {"strcharlen",    1, 1, FEARG_1,      NULL,
                        ret_number,         f_strcharlen},
!     {"strcharpart",   2, 3, FEARG_1,      NULL,
                        ret_string,         f_strcharpart},
      {"strchars",      1, 2, FEARG_1,      NULL,
                        ret_number,         f_strchars},
--- 1575,1581 ----
                        ret_number,         f_str2nr},
      {"strcharlen",    1, 1, FEARG_1,      NULL,
                        ret_number,         f_strcharlen},
!     {"strcharpart",   2, 4, FEARG_1,      NULL,
                        ret_string,         f_strcharpart},
      {"strchars",      1, 2, FEARG_1,      NULL,
                        ret_number,         f_strchars},
***************
*** 9316,9321 ****
--- 9316,9322 ----
      int               nchar;
      int               nbyte = 0;
      int               charlen;
+     int               skipcc = FALSE;
      int               len = 0;
      int               slen;
      int               error = FALSE;
***************
*** 9326,9335 ****
      nchar = (int)tv_get_number_chk(&argvars[1], &error);
      if (!error)
      {
        if (nchar > 0)
            while (nchar > 0 && nbyte < slen)
            {
!               nbyte += MB_CPTR2LEN(p + nbyte);
                --nchar;
            }
        else
--- 9327,9350 ----
      nchar = (int)tv_get_number_chk(&argvars[1], &error);
      if (!error)
      {
+       if (argvars[2].v_type != VAR_UNKNOWN
+                                          && argvars[3].v_type != VAR_UNKNOWN)
+       {
+           skipcc = tv_get_bool(&argvars[3]);
+           if (skipcc < 0 || skipcc > 1)
+           {
+               semsg(_(e_using_number_as_bool_nr), skipcc);
+               return;
+           }
+       }
+ 
        if (nchar > 0)
            while (nchar > 0 && nbyte < slen)
            {
!               if (skipcc)
!                   nbyte += mb_ptr2len(p + nbyte);
!               else
!                   nbyte += MB_CPTR2LEN(p + nbyte);
                --nchar;
            }
        else
***************
*** 9344,9350 ****
                if (off < 0)
                    len += 1;
                else
!                   len += MB_CPTR2LEN(p + off);
                --charlen;
            }
        }
--- 9359,9370 ----
                if (off < 0)
                    len += 1;
                else
!               {
!                   if (skipcc)
!                       len += mb_ptr2len(p + off);
!                   else
!                       len += MB_CPTR2LEN(p + off);
!               }
                --charlen;
            }
        }
*** ../vim-8.2.2606/src/testdir/test_expr_utf8.vim      2020-08-12 
18:50:31.875655822 +0200
--- src/testdir/test_expr_utf8.vim      2021-03-14 19:27:18.829578382 +0100
***************
*** 31,36 ****
--- 31,44 ----
    call assert_equal('a', strcharpart('àxb', 0, 1))
    call assert_equal('̀', strcharpart('àxb', 1, 1))
    call assert_equal('x', strcharpart('àxb', 2, 1))
+ 
+ 
+   call assert_equal('a', strcharpart('àxb', 0, 1, 0))
+   call assert_equal('à', strcharpart('àxb', 0, 1, 1))
+   call assert_equal('x', strcharpart('àxb', 1, 1, 1))
+ 
+   call assert_fails("let v = strcharpart('abc', 0, 0, [])", 'E745:')
+   call assert_fails("let v = strcharpart('abc', 0, 0, 2)", 'E1023:')
  endfunc
  
  " vim: shiftwidth=2 sts=2 expandtab
*** ../vim-8.2.2606/src/version.c       2021-03-14 19:01:34.496421810 +0100
--- src/version.c       2021-03-14 19:16:57.962730581 +0100
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     2607,
  /**/

-- 
"You're fired." (1980)
"You're laid off." (1985)
"You're downsized." (1990)
"You're rightsized." (1992)
                                (Scott Adams - The Dilbert principle)

 /// 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/202103141847.12EIlETY306258%40masaka.moolenaar.net.

Raspunde prin e-mail lui