To: vim_dev@googlegroups.com Subject: Patch 8.2.2607 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 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 -- Bram@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 ///