To: vim_dev@googlegroups.com Subject: Patch 9.0.1617 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.1617 Problem: charidx() and utf16idx() result is not consistent with byteidx(). Solution: When the index is equal to the length of the text return the lenght of the text instead of -1. (Yegappan Lakshmanan, closes #12503) Files: runtime/doc/builtin.txt, src/evalfunc.c, src/strings.c, src/testdir/test_functions.vim, src/testdir/test_vim9_builtin.vim *** ../vim-9.0.1616/runtime/doc/builtin.txt 2023-05-06 14:08:10.139045046 +0100 --- runtime/doc/builtin.txt 2023-06-08 17:04:20.819726310 +0100 *************** *** 1528,1538 **** When {utf16} is present and TRUE, {idx} is used as the UTF-16 index in the String {expr} instead of as the byte index. ! Returns -1 if the arguments are invalid or if {idx} is greater ! than the index of the last byte in {string}. An error is ! given if the first argument is not a string, the second ! argument is not a number or when the third argument is present ! and is not zero or one. See |byteidx()| and |byteidxcomp()| for getting the byte index from the character index and |utf16idx()| for getting the --- 1528,1540 ---- When {utf16} is present and TRUE, {idx} is used as the UTF-16 index in the String {expr} instead of as the byte index. ! Returns -1 if the arguments are invalid or if there are less ! than {idx} bytes. If there are exactly {idx} bytes the length ! of the string in characters is returned. ! ! An error is given and -1 is returned if the first argument is ! not a string, the second argument is not a number or when the ! third argument is present and is not zero or one. See |byteidx()| and |byteidxcomp()| for getting the byte index from the character index and |utf16idx()| for getting the *************** *** 10106,10113 **** < *utf16idx()* utf16idx({string}, {idx} [, {countcc} [, {charidx}]]) ! Same as |charidx()| but returns the UTF-16 index of the byte ! at {idx} in {string} (after converting it to UTF-16). When {charidx} is present and TRUE, {idx} is used as the character index in the String {string} instead of as the byte --- 10121,10128 ---- < *utf16idx()* utf16idx({string}, {idx} [, {countcc} [, {charidx}]]) ! Same as |charidx()| but returns the UTF-16 code unit index of ! the byte at {idx} in {string} (after converting it to UTF-16). When {charidx} is present and TRUE, {idx} is used as the character index in the String {string} instead of as the byte *************** *** 10115,10120 **** --- 10130,10139 ---- An {idx} in the middle of a UTF-8 sequence is rounded upwards to the end of that sequence. + Returns -1 if the arguments are invalid or if there are less + than {idx} bytes in {string}. If there are exactly {idx} bytes + the length of the string in UTF-16 code units is returned. + See |byteidx()| and |byteidxcomp()| for getting the byte index from the UTF-16 index and |charidx()| for getting the character index from the UTF-16 index. *** ../vim-9.0.1616/src/evalfunc.c 2023-06-01 20:26:52.060180250 +0100 --- src/evalfunc.c 2023-06-08 16:58:53.682021173 +0100 *************** *** 1099,1104 **** --- 1099,1105 ---- static argcheck_T arg4_number_number_string_any[] = {arg_number, arg_number, arg_string, NULL}; static argcheck_T arg4_string_string_any_string[] = {arg_string, arg_string, NULL, arg_string}; static argcheck_T arg4_string_string_number_string[] = {arg_string, arg_string, arg_number, arg_string}; + static argcheck_T arg4_string_number_bool_bool[] = {arg_string, arg_number, arg_bool, arg_bool}; /* Function specific argument types (not covered by the above) */ static argcheck_T arg15_assert_fails[] = {arg_string_or_nr, arg_string_or_list_any, NULL, arg_number, arg_string}; static argcheck_T arg34_assert_inrange[] = {arg_float_or_nr, arg_float_or_nr, arg_float_or_nr, arg_string}; *************** *** 1814,1820 **** ret_number, f_charclass}, {"charcol", 1, 2, FEARG_1, arg2_string_or_list_number, ret_number, f_charcol}, ! {"charidx", 2, 4, FEARG_1, arg3_string_number_bool, ret_number, f_charidx}, {"chdir", 1, 1, FEARG_1, arg1_string, ret_string, f_chdir}, --- 1815,1821 ---- ret_number, f_charclass}, {"charcol", 1, 2, FEARG_1, arg2_string_or_list_number, ret_number, f_charcol}, ! {"charidx", 2, 4, FEARG_1, arg4_string_number_bool_bool, ret_number, f_charidx}, {"chdir", 1, 1, FEARG_1, arg1_string, ret_string, f_chdir}, *************** *** 2798,2804 **** ret_dict_any, f_undotree}, {"uniq", 1, 3, FEARG_1, arg13_sortuniq, ret_first_arg, f_uniq}, ! {"utf16idx", 2, 4, FEARG_1, arg3_string_number_bool, ret_number, f_utf16idx}, {"values", 1, 1, FEARG_1, arg1_dict_any, ret_list_member, f_values}, --- 2799,2805 ---- ret_dict_any, f_undotree}, {"uniq", 1, 3, FEARG_1, arg13_sortuniq, ret_first_arg, f_uniq}, ! {"utf16idx", 2, 4, FEARG_1, arg4_string_number_bool_bool, ret_number, f_utf16idx}, {"values", 1, 1, FEARG_1, arg1_dict_any, ret_list_member, f_values}, *************** *** 3630,3636 **** /* * Set the cursor position. ! * If 'charcol' is TRUE, then use the column number as a character offset. * Otherwise use the column number as a byte offset. */ static void --- 3631,3637 ---- /* * Set the cursor position. ! * If "charcol" is TRUE, then use the column number as a character offset. * Otherwise use the column number as a byte offset. */ static void *** ../vim-9.0.1616/src/strings.c 2023-05-08 15:31:34.247545088 +0100 --- src/strings.c 2023-06-08 16:58:53.682021173 +0100 *************** *** 1054,1060 **** if (in_vim9script() && (check_for_string_arg(argvars, 0) == FAIL ! || check_for_number_arg(argvars, 1) == FAIL)) return; char_u *str = tv_get_string_chk(&argvars[0]); --- 1054,1061 ---- if (in_vim9script() && (check_for_string_arg(argvars, 0) == FAIL ! || check_for_number_arg(argvars, 1) == FAIL ! || check_for_opt_bool_arg(argvars, 2) == FAIL)) return; char_u *str = tv_get_string_chk(&argvars[0]); *************** *** 1158,1164 **** --- 1159,1172 ---- for (p = str, len = 0; utf16idx ? idx >= 0 : p <= str + idx; len++) { if (*p == NUL) + { + // If the index is exactly the number of bytes or utf-16 code units + // in the string then return the length of the string in + // characters. + if (utf16idx ? (idx == 0) : (p == (str + idx))) + rettv->vval.v_number = len; return; + } if (utf16idx) { idx--; *************** *** 1775,1781 **** --- 1783,1796 ---- for (p = str, len = 0; charidx ? idx >= 0 : p <= str + idx; len++) { if (*p == NUL) + { + // If the index is exactly the number of bytes or characters in the + // string then return the length of the string in utf-16 code + // units. + if (charidx ? (idx == 0) : (p == (str + idx))) + rettv->vval.v_number = len; return; + } int clen = ptr2len(p); int c = (clen > 1) ? utf_ptr2char(p) : *p; if (c > 0xFFFF) *** ../vim-9.0.1616/src/testdir/test_functions.vim 2023-06-01 20:26:52.060180250 +0100 --- src/testdir/test_functions.vim 2023-06-08 16:58:53.682021173 +0100 *************** *** 1395,1401 **** call assert_equal(1, charidx(a, 3)) call assert_equal(2, charidx(a, 4)) call assert_equal(3, charidx(a, 7)) ! call assert_equal(-1, charidx(a, 8)) call assert_equal(-1, charidx(a, -1)) " count composing characters --- 1395,1402 ---- call assert_equal(1, charidx(a, 3)) call assert_equal(2, charidx(a, 4)) call assert_equal(3, charidx(a, 7)) ! call assert_equal(4, charidx(a, 8)) ! call assert_equal(-1, charidx(a, 9)) call assert_equal(-1, charidx(a, -1)) " count composing characters *************** *** 1403,1416 **** call assert_equal(2, a->charidx(2, 1)) call assert_equal(3, a->charidx(4, 1)) call assert_equal(5, a->charidx(7, 1)) ! call assert_equal(-1, a->charidx(8, 1)) " empty string ! call assert_equal(-1, charidx('', 0)) ! call assert_equal(-1, charidx('', 0, 1)) " error cases ! call assert_equal(-1, charidx(test_null_string(), 0)) call assert_fails('let x = charidx([], 1)', 'E1174:') call assert_fails('let x = charidx("abc", [])', 'E1210:') call assert_fails('let x = charidx("abc", 1, [])', 'E1212:') --- 1404,1421 ---- call assert_equal(2, a->charidx(2, 1)) call assert_equal(3, a->charidx(4, 1)) call assert_equal(5, a->charidx(7, 1)) ! call assert_equal(6, a->charidx(8, 1)) ! call assert_equal(-1, a->charidx(9, 1)) " empty string ! call assert_equal(0, charidx('', 0)) ! call assert_equal(-1, charidx('', 1)) ! call assert_equal(0, charidx('', 0, 1)) ! call assert_equal(-1, charidx('', 1, 1)) " error cases ! call assert_equal(0, charidx(test_null_string(), 0)) ! call assert_equal(-1, charidx(test_null_string(), 1)) call assert_fails('let x = charidx([], 1)', 'E1174:') call assert_fails('let x = charidx("abc", [])', 'E1210:') call assert_fails('let x = charidx("abc", 1, [])', 'E1212:') *************** *** 1422,1431 **** func Test_charidx_from_utf16_index() " string with single byte characters let str = "abc" ! for i in range(3) call assert_equal(i, charidx(str, i, v:false, v:true)) endfor ! call assert_equal(-1, charidx(str, 3, v:false, v:true)) " string with two byte characters let str = "a漏漏b" --- 1427,1436 ---- func Test_charidx_from_utf16_index() " string with single byte characters let str = "abc" ! for i in range(4) call assert_equal(i, charidx(str, i, v:false, v:true)) endfor ! call assert_equal(-1, charidx(str, 4, v:false, v:true)) " string with two byte characters let str = "a漏漏b" *************** *** 1433,1439 **** call assert_equal(1, charidx(str, 1, v:false, v:true)) call assert_equal(2, charidx(str, 2, v:false, v:true)) call assert_equal(3, charidx(str, 3, v:false, v:true)) ! call assert_equal(-1, charidx(str, 4, v:false, v:true)) " string with four byte characters let str = "a馃槉馃槉b" --- 1438,1445 ---- call assert_equal(1, charidx(str, 1, v:false, v:true)) call assert_equal(2, charidx(str, 2, v:false, v:true)) call assert_equal(3, charidx(str, 3, v:false, v:true)) ! call assert_equal(4, charidx(str, 4, v:false, v:true)) ! call assert_equal(-1, charidx(str, 5, v:false, v:true)) " string with four byte characters let str = "a馃槉馃槉b" *************** *** 1443,1480 **** call assert_equal(2, charidx(str, 3, v:false, v:true)) call assert_equal(2, charidx(str, 4, v:false, v:true)) call assert_equal(3, charidx(str, 5, v:false, v:true)) ! call assert_equal(-1, charidx(str, 6, v:false, v:true)) " string with composing characters let str = '-a虂-b虂' for i in str->strcharlen()->range() call assert_equal(i, charidx(str, i, v:false, v:true)) endfor ! call assert_equal(-1, charidx(str, 4, v:false, v:true)) for i in str->strchars()->range() call assert_equal(i, charidx(str, i, v:true, v:true)) endfor ! call assert_equal(-1, charidx(str, 6, v:true, v:true)) " string with multiple composing characters let str = '-a台虂-a台虂' for i in str->strcharlen()->range() call assert_equal(i, charidx(str, i, v:false, v:true)) endfor ! call assert_equal(-1, charidx(str, 4, v:false, v:true)) for i in str->strchars()->range() call assert_equal(i, charidx(str, i, v:true, v:true)) endfor ! call assert_equal(-1, charidx(str, 8, v:true, v:true)) " empty string ! call assert_equal(-1, charidx('', 0, v:false, v:true)) ! call assert_equal(-1, charidx('', 0, v:true, v:true)) " error cases ! call assert_equal(-1, charidx('', 0, v:false, v:true)) ! call assert_equal(-1, charidx('', 0, v:true, v:true)) ! call assert_equal(-1, charidx(test_null_string(), 0, v:false, v:true)) call assert_fails('let x = charidx("abc", 1, v:false, [])', 'E1212:') call assert_fails('let x = charidx("abc", 1, v:true, [])', 'E1212:') endfunc --- 1449,1496 ---- call assert_equal(2, charidx(str, 3, v:false, v:true)) call assert_equal(2, charidx(str, 4, v:false, v:true)) call assert_equal(3, charidx(str, 5, v:false, v:true)) ! call assert_equal(4, charidx(str, 6, v:false, v:true)) ! call assert_equal(-1, charidx(str, 7, v:false, v:true)) " string with composing characters let str = '-a虂-b虂' for i in str->strcharlen()->range() call assert_equal(i, charidx(str, i, v:false, v:true)) endfor ! call assert_equal(4, charidx(str, 4, v:false, v:true)) ! call assert_equal(-1, charidx(str, 5, v:false, v:true)) for i in str->strchars()->range() call assert_equal(i, charidx(str, i, v:true, v:true)) endfor ! call assert_equal(6, charidx(str, 6, v:true, v:true)) ! call assert_equal(-1, charidx(str, 7, v:true, v:true)) " string with multiple composing characters let str = '-a台虂-a台虂' for i in str->strcharlen()->range() call assert_equal(i, charidx(str, i, v:false, v:true)) endfor ! call assert_equal(4, charidx(str, 4, v:false, v:true)) ! call assert_equal(-1, charidx(str, 5, v:false, v:true)) for i in str->strchars()->range() call assert_equal(i, charidx(str, i, v:true, v:true)) endfor ! call assert_equal(8, charidx(str, 8, v:true, v:true)) ! call assert_equal(-1, charidx(str, 9, v:true, v:true)) " empty string ! call assert_equal(0, charidx('', 0, v:false, v:true)) ! call assert_equal(-1, charidx('', 1, v:false, v:true)) ! call assert_equal(0, charidx('', 0, v:true, v:true)) ! call assert_equal(-1, charidx('', 1, v:true, v:true)) " error cases ! call assert_equal(0, charidx('', 0, v:false, v:true)) ! call assert_equal(-1, charidx('', 1, v:false, v:true)) ! call assert_equal(0, charidx('', 0, v:true, v:true)) ! call assert_equal(-1, charidx('', 1, v:true, v:true)) ! call assert_equal(0, charidx(test_null_string(), 0, v:false, v:true)) ! call assert_equal(-1, charidx(test_null_string(), 1, v:false, v:true)) call assert_fails('let x = charidx("abc", 1, v:false, [])', 'E1212:') call assert_fails('let x = charidx("abc", 1, v:true, [])', 'E1212:') endfunc *************** *** 1483,1492 **** func Test_utf16idx_from_byteidx() " UTF-16 index of a string with single byte characters let str = "abc" ! for i in range(3) call assert_equal(i, utf16idx(str, i)) endfor ! call assert_equal(-1, utf16idx(str, 3)) " UTF-16 index of a string with two byte characters let str = 'a漏漏b' --- 1499,1508 ---- func Test_utf16idx_from_byteidx() " UTF-16 index of a string with single byte characters let str = "abc" ! for i in range(4) call assert_equal(i, utf16idx(str, i)) endfor ! call assert_equal(-1, utf16idx(str, 4)) " UTF-16 index of a string with two byte characters let str = 'a漏漏b' *************** *** 1496,1502 **** call assert_equal(2, str->utf16idx(3)) call assert_equal(2, str->utf16idx(4)) call assert_equal(3, str->utf16idx(5)) ! call assert_equal(-1, str->utf16idx(6)) " UTF-16 index of a string with four byte characters let str = 'a馃槉馃槉b' --- 1512,1519 ---- call assert_equal(2, str->utf16idx(3)) call assert_equal(2, str->utf16idx(4)) call assert_equal(3, str->utf16idx(5)) ! call assert_equal(4, str->utf16idx(6)) ! call assert_equal(-1, str->utf16idx(7)) " UTF-16 index of a string with four byte characters let str = 'a馃槉馃槉b' *************** *** 1510,1516 **** call assert_equal(4, utf16idx(str, 7)) call assert_equal(4, utf16idx(str, 8)) call assert_equal(5, utf16idx(str, 9)) ! call assert_equal(-1, utf16idx(str, 10)) " UTF-16 index of a string with composing characters let str = '-a虂-b虂' --- 1527,1534 ---- call assert_equal(4, utf16idx(str, 7)) call assert_equal(4, utf16idx(str, 8)) call assert_equal(5, utf16idx(str, 9)) ! call assert_equal(6, utf16idx(str, 10)) ! call assert_equal(-1, utf16idx(str, 11)) " UTF-16 index of a string with composing characters let str = '-a虂-b虂' *************** *** 1522,1528 **** call assert_equal(3, utf16idx(str, 5)) call assert_equal(3, utf16idx(str, 6)) call assert_equal(3, utf16idx(str, 7)) ! call assert_equal(-1, utf16idx(str, 8)) call assert_equal(0, utf16idx(str, 0, v:true)) call assert_equal(1, utf16idx(str, 1, v:true)) call assert_equal(2, utf16idx(str, 2, v:true)) --- 1540,1547 ---- call assert_equal(3, utf16idx(str, 5)) call assert_equal(3, utf16idx(str, 6)) call assert_equal(3, utf16idx(str, 7)) ! call assert_equal(4, utf16idx(str, 8)) ! call assert_equal(-1, utf16idx(str, 9)) call assert_equal(0, utf16idx(str, 0, v:true)) call assert_equal(1, utf16idx(str, 1, v:true)) call assert_equal(2, utf16idx(str, 2, v:true)) *************** *** 1531,1537 **** call assert_equal(4, utf16idx(str, 5, v:true)) call assert_equal(5, utf16idx(str, 6, v:true)) call assert_equal(5, utf16idx(str, 7, v:true)) ! call assert_equal(-1, utf16idx(str, 8, v:true)) " string with multiple composing characters let str = '-a台虂-a台虂' --- 1550,1557 ---- call assert_equal(4, utf16idx(str, 5, v:true)) call assert_equal(5, utf16idx(str, 6, v:true)) call assert_equal(5, utf16idx(str, 7, v:true)) ! call assert_equal(6, utf16idx(str, 8, v:true)) ! call assert_equal(-1, utf16idx(str, 9, v:true)) " string with multiple composing characters let str = '-a台虂-a台虂' *************** *** 1547,1553 **** call assert_equal(3, utf16idx(str, 9)) call assert_equal(3, utf16idx(str, 10)) call assert_equal(3, utf16idx(str, 11)) ! call assert_equal(-1, utf16idx(str, 12)) call assert_equal(0, utf16idx(str, 0, v:true)) call assert_equal(1, utf16idx(str, 1, v:true)) call assert_equal(2, utf16idx(str, 2, v:true)) --- 1567,1574 ---- call assert_equal(3, utf16idx(str, 9)) call assert_equal(3, utf16idx(str, 10)) call assert_equal(3, utf16idx(str, 11)) ! call assert_equal(4, utf16idx(str, 12)) ! call assert_equal(-1, utf16idx(str, 13)) call assert_equal(0, utf16idx(str, 0, v:true)) call assert_equal(1, utf16idx(str, 1, v:true)) call assert_equal(2, utf16idx(str, 2, v:true)) *************** *** 1560,1575 **** call assert_equal(6, utf16idx(str, 9, v:true)) call assert_equal(7, utf16idx(str, 10, v:true)) call assert_equal(7, utf16idx(str, 11, v:true)) ! call assert_equal(-1, utf16idx(str, 12, v:true)) " empty string ! call assert_equal(-1, utf16idx('', 0)) ! call assert_equal(-1, utf16idx('', 0, v:true)) " error cases ! call assert_equal(-1, utf16idx("", 0)) call assert_equal(-1, utf16idx("abc", -1)) ! call assert_equal(-1, utf16idx(test_null_string(), 0)) call assert_fails('let l = utf16idx([], 0)', 'E1174:') call assert_fails('let l = utf16idx("ab", [])', 'E1210:') call assert_fails('let l = utf16idx("ab", 0, [])', 'E1212:') --- 1581,1601 ---- call assert_equal(6, utf16idx(str, 9, v:true)) call assert_equal(7, utf16idx(str, 10, v:true)) call assert_equal(7, utf16idx(str, 11, v:true)) ! call assert_equal(8, utf16idx(str, 12, v:true)) ! call assert_equal(-1, utf16idx(str, 13, v:true)) " empty string ! call assert_equal(0, utf16idx('', 0)) ! call assert_equal(-1, utf16idx('', 1)) ! call assert_equal(0, utf16idx('', 0, v:true)) ! call assert_equal(-1, utf16idx('', 1, v:true)) " error cases ! call assert_equal(0, utf16idx("", 0)) ! call assert_equal(-1, utf16idx("", 1)) call assert_equal(-1, utf16idx("abc", -1)) ! call assert_equal(0, utf16idx(test_null_string(), 0)) ! call assert_equal(-1, utf16idx(test_null_string(), 1)) call assert_fails('let l = utf16idx([], 0)', 'E1174:') call assert_fails('let l = utf16idx("ab", [])', 'E1210:') call assert_fails('let l = utf16idx("ab", 0, [])', 'E1212:') *************** *** 1581,1594 **** for i in str->strcharlen()->range() call assert_equal(i, utf16idx(str, i, v:false, v:true)) endfor ! call assert_equal(-1, utf16idx(str, 3, v:false, v:true)) " UTF-16 index of a string with two byte characters let str = "a漏漏b" for i in str->strcharlen()->range() call assert_equal(i, utf16idx(str, i, v:false, v:true)) endfor ! call assert_equal(-1, utf16idx(str, 4, v:false, v:true)) " UTF-16 index of a string with four byte characters let str = "a馃槉馃槉b" --- 1607,1622 ---- for i in str->strcharlen()->range() call assert_equal(i, utf16idx(str, i, v:false, v:true)) endfor ! call assert_equal(3, utf16idx(str, 3, v:false, v:true)) ! call assert_equal(-1, utf16idx(str, 4, v:false, v:true)) " UTF-16 index of a string with two byte characters let str = "a漏漏b" for i in str->strcharlen()->range() call assert_equal(i, utf16idx(str, i, v:false, v:true)) endfor ! call assert_equal(4, utf16idx(str, 4, v:false, v:true)) ! call assert_equal(-1, utf16idx(str, 5, v:false, v:true)) " UTF-16 index of a string with four byte characters let str = "a馃槉馃槉b" *************** *** 1596,1631 **** call assert_equal(2, utf16idx(str, 1, v:false, v:true)) call assert_equal(4, utf16idx(str, 2, v:false, v:true)) call assert_equal(5, utf16idx(str, 3, v:false, v:true)) ! call assert_equal(-1, utf16idx(str, 4, v:false, v:true)) " UTF-16 index of a string with composing characters let str = '-a虂-b虂' for i in str->strcharlen()->range() call assert_equal(i, utf16idx(str, i, v:false, v:true)) endfor ! call assert_equal(-1, utf16idx(str, 4, v:false, v:true)) for i in str->strchars()->range() call assert_equal(i, utf16idx(str, i, v:true, v:true)) endfor ! call assert_equal(-1, utf16idx(str, 6, v:true, v:true)) " string with multiple composing characters let str = '-a台虂-a台虂' for i in str->strcharlen()->range() call assert_equal(i, utf16idx(str, i, v:false, v:true)) endfor ! call assert_equal(-1, utf16idx(str, 4, v:false, v:true)) for i in str->strchars()->range() call assert_equal(i, utf16idx(str, i, v:true, v:true)) endfor ! call assert_equal(-1, utf16idx(str, 8, v:true, v:true)) " empty string ! call assert_equal(-1, utf16idx('', 0, v:false, v:true)) ! call assert_equal(-1, utf16idx('', 0, v:true, v:true)) " error cases ! call assert_equal(-1, utf16idx(test_null_string(), 0, v:true, v:true)) call assert_fails('let l = utf16idx("ab", 0, v:false, [])', 'E1212:') endfunc --- 1624,1667 ---- call assert_equal(2, utf16idx(str, 1, v:false, v:true)) call assert_equal(4, utf16idx(str, 2, v:false, v:true)) call assert_equal(5, utf16idx(str, 3, v:false, v:true)) ! call assert_equal(6, utf16idx(str, 4, v:false, v:true)) ! call assert_equal(-1, utf16idx(str, 5, v:false, v:true)) " UTF-16 index of a string with composing characters let str = '-a虂-b虂' for i in str->strcharlen()->range() call assert_equal(i, utf16idx(str, i, v:false, v:true)) endfor ! call assert_equal(4, utf16idx(str, 4, v:false, v:true)) ! call assert_equal(-1, utf16idx(str, 5, v:false, v:true)) for i in str->strchars()->range() call assert_equal(i, utf16idx(str, i, v:true, v:true)) endfor ! call assert_equal(6, utf16idx(str, 6, v:true, v:true)) ! call assert_equal(-1, utf16idx(str, 7, v:true, v:true)) " string with multiple composing characters let str = '-a台虂-a台虂' for i in str->strcharlen()->range() call assert_equal(i, utf16idx(str, i, v:false, v:true)) endfor ! call assert_equal(4, utf16idx(str, 4, v:false, v:true)) ! call assert_equal(-1, utf16idx(str, 5, v:false, v:true)) for i in str->strchars()->range() call assert_equal(i, utf16idx(str, i, v:true, v:true)) endfor ! call assert_equal(8, utf16idx(str, 8, v:true, v:true)) ! call assert_equal(-1, utf16idx(str, 9, v:true, v:true)) " empty string ! call assert_equal(0, utf16idx('', 0, v:false, v:true)) ! call assert_equal(-1, utf16idx('', 1, v:false, v:true)) ! call assert_equal(0, utf16idx('', 0, v:true, v:true)) ! call assert_equal(-1, utf16idx('', 1, v:true, v:true)) " error cases ! call assert_equal(0, utf16idx(test_null_string(), 0, v:true, v:true)) ! call assert_equal(-1, utf16idx(test_null_string(), 1, v:true, v:true)) call assert_fails('let l = utf16idx("ab", 0, v:false, [])', 'E1212:') endfunc *** ../vim-9.0.1616/src/testdir/test_vim9_builtin.vim 2023-05-11 15:02:52.231456894 +0100 --- src/testdir/test_vim9_builtin.vim 2023-06-08 16:58:53.682021173 +0100 *************** *** 460,465 **** --- 460,466 ---- def Test_byteidx() v9.CheckDefAndScriptFailure(['byteidx(1, 2)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1']) v9.CheckDefAndScriptFailure(['byteidx("a", "b")'], ['E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2']) + v9.CheckDefAndScriptFailure(['byteidx("a", 0, "")'], ['E1013: Argument 3: type mismatch, expected bool but got string', 'E1212: Bool required for argument 3']) byteidx('', 0)->assert_equal(0) byteidx('', 1)->assert_equal(-1) enddef *************** *** 467,472 **** --- 468,474 ---- def Test_byteidxcomp() v9.CheckDefAndScriptFailure(['byteidxcomp(1, 2)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1']) v9.CheckDefAndScriptFailure(['byteidxcomp("a", "b")'], ['E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2']) + v9.CheckDefAndScriptFailure(['byteidxcomp("a", 0, "")'], ['E1013: Argument 3: type mismatch, expected bool but got string', 'E1212: Bool required for argument 3']) enddef def Test_call_call() *************** *** 702,708 **** v9.CheckDefAndScriptFailure(['charidx(0z10, 1)'], ['E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1']) v9.CheckDefAndScriptFailure(['charidx("a", "b")'], ['E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2']) v9.CheckDefAndScriptFailure(['charidx("a", 1, "")'], ['E1013: Argument 3: type mismatch, expected bool but got string', 'E1212: Bool required for argument 3']) ! charidx('', 0)->assert_equal(-1) charidx('', 1)->assert_equal(-1) enddef --- 704,711 ---- v9.CheckDefAndScriptFailure(['charidx(0z10, 1)'], ['E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1']) v9.CheckDefAndScriptFailure(['charidx("a", "b")'], ['E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2']) v9.CheckDefAndScriptFailure(['charidx("a", 1, "")'], ['E1013: Argument 3: type mismatch, expected bool but got string', 'E1212: Bool required for argument 3']) ! v9.CheckDefAndScriptFailure(['charidx("a", 1, 0, "")'], ['E1013: Argument 4: type mismatch, expected bool but got string', 'E1212: Bool required for argument 4']) ! charidx('', 0)->assert_equal(0) charidx('', 1)->assert_equal(-1) enddef *************** *** 4305,4310 **** --- 4308,4321 ---- strtrans('')->assert_equal('') enddef + def Test_strutf16len() + v9.CheckDefAndScriptFailure(['strutf16len([])'], ['E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1']) + v9.CheckDefAndScriptFailure(['strutf16len("a", "")'], ['E1013: Argument 2: type mismatch, expected bool but got string', 'E1212: Bool required for argument 2']) + ""->strutf16len()->assert_equal(0) + '-a台虂-a台虂'->strutf16len(true)->assert_equal(8) + '-a台虂-a台虂'->strutf16len(false)->assert_equal(4) + enddef + def Test_strwidth() v9.CheckDefAndScriptFailure(['strwidth(10)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1']) assert_equal(4, strwidth('abcd')) *************** *** 4727,4732 **** --- 4738,4752 ---- v9.CheckDefFailure(['var l: list = uniq(["a", "b"])'], 'E1012: Type mismatch; expected list but got list') enddef + def Test_utf16idx() + v9.CheckDefAndScriptFailure(['utf16idx(0z10, 1)'], ['E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1']) + v9.CheckDefAndScriptFailure(['utf16idx("a", "b")'], ['E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2']) + v9.CheckDefAndScriptFailure(['utf16idx("a", 1, "")'], ['E1013: Argument 3: type mismatch, expected bool but got string', 'E1212: Bool required for argument 3']) + v9.CheckDefAndScriptFailure(['utf16idx("a", 1, 0, "")'], ['E1013: Argument 4: type mismatch, expected bool but got string', 'E1212: Bool required for argument 4']) + utf16idx('', 0)->assert_equal(0) + utf16idx('', 1)->assert_equal(-1) + enddef + def Test_uniq_const() var lines =<< trim END const l = [1, 2, 3, 4] *** ../vim-9.0.1616/src/version.c 2023-06-07 19:09:52.536499675 +0100 --- src/version.c 2023-06-08 17:03:06.647411042 +0100 *************** *** 697,698 **** --- 697,700 ---- { /* Add new patch number below this line */ + /**/ + 1617, /**/ -- There are three kinds of persons: Those who can count and those who can't. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///