patch 9.0.1617: charidx() result is not consistent with byteidx()
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)
diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim
index 715da0b..d7e7f92 100644
--- a/src/testdir/test_functions.vim
+++ b/src/testdir/test_functions.vim
@@ -1395,7 +1395,8 @@
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(4, charidx(a, 8))
+ call assert_equal(-1, charidx(a, 9))
call assert_equal(-1, charidx(a, -1))
" count composing characters
@@ -1403,14 +1404,18 @@
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))
+ call assert_equal(6, a->charidx(8, 1))
+ call assert_equal(-1, a->charidx(9, 1))
" empty string
- call assert_equal(-1, charidx('', 0))
- call assert_equal(-1, charidx('', 0, 1))
+ 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(-1, charidx(test_null_string(), 0))
+ 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,10 +1427,10 @@
func Test_charidx_from_utf16_index()
" string with single byte characters
let str = "abc"
- for i in range(3)
+ for i in range(4)
call assert_equal(i, charidx(str, i, v:false, v:true))
endfor
- call assert_equal(-1, charidx(str, 3, v:false, v:true))
+ call assert_equal(-1, charidx(str, 4, v:false, v:true))
" string with two byte characters
let str = "a©©b"
@@ -1433,7 +1438,8 @@
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))
+ 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,38 +1449,48 @@
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))
+ 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(-1, charidx(str, 4, 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))
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))
+ 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(-1, charidx(str, 4, 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))
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))
+ 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(-1, charidx('', 0, v:false, v:true))
- call assert_equal(-1, charidx('', 0, v:true, v:true))
+ 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(-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_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,10 +1499,10 @@
func Test_utf16idx_from_byteidx()
" UTF-16 index of a string with single byte characters
let str = "abc"
- for i in range(3)
+ for i in range(4)
call assert_equal(i, utf16idx(str, i))
endfor
- call assert_equal(-1, utf16idx(str, 3))
+ call assert_equal(-1, utf16idx(str, 4))
" UTF-16 index of a string with two byte characters
let str = 'a©©b'
@@ -1496,7 +1512,8 @@
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))
+ 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,7 +1527,8 @@
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))
+ 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,7 +1540,8 @@
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(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,7 +1550,8 @@
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))
+ 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,7 +1567,8 @@
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(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,16 +1581,21 @@
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))
+ call assert_equal(8, utf16idx(str, 12, v:true))
+ call assert_equal(-1, utf16idx(str, 13, v:true))
" empty string
- call assert_equal(-1, utf16idx('', 0))
- call assert_equal(-1, utf16idx('', 0, v:true))
+ 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(-1, utf16idx("", 0))
+ call assert_equal(0, utf16idx("", 0))
+ call assert_equal(-1, utf16idx("", 1))
call assert_equal(-1, utf16idx("abc", -1))
- call assert_equal(-1, utf16idx(test_null_string(), 0))
+ 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,14 +1607,16 @@
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))
+ 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(-1, utf16idx(str, 4, v:false, v:true))
+ 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,36 +1624,44 @@
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))
+ 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(-1, utf16idx(str, 4, v:false, v:true))
+ 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(-1, utf16idx(str, 6, v:true, v:true))
+ 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(-1, utf16idx(str, 4, v:false, v:true))
+ 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(-1, utf16idx(str, 8, v:true, v:true))
+ 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(-1, utf16idx('', 0, v:false, v:true))
- call assert_equal(-1, utf16idx('', 0, v:true, v:true))
+ 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(-1, utf16idx(test_null_string(), 0, v:true, v:true))
+ 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
diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim
index 8cf16a2..a226bb2 100644
--- a/src/testdir/test_vim9_builtin.vim
+++ b/src/testdir/test_vim9_builtin.vim
@@ -460,6 +460,7 @@
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,6 +468,7 @@
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,7 +704,8 @@
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)
+ 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,6 +4308,14 @@
strtrans('')->assert_equal('')
enddef
+def Test_strutf16len()
+ v9.CheckDefAndScriptFailure(['strutf16len([])'], ['E1013: Argument 1: type mismatch, expected string but got list<unknown>', '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,6 +4738,15 @@
v9.CheckDefFailure(['var l: list<number> = uniq(["a", "b"])'], 'E1012: Type mismatch; expected list<number> but got list<string>')
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]