Merge pull request #12786 from janlazo/vim-8.1.1516

vim-patch:8.1.{1516,1677,2051,2089,2275,2364},8.2.{423,1517}
This commit is contained in:
Jan Edmund Lazo
2020-08-24 20:59:40 -04:00
committed by GitHub
6 changed files with 122 additions and 51 deletions

View File

@@ -2409,7 +2409,8 @@ str2list({expr} [, {utf8}]) List convert each character of {expr} to
str2nr({expr} [, {base}]) Number convert String to Number str2nr({expr} [, {base}]) Number convert String to Number
strchars({expr} [, {skipcc}]) Number character length of the String {expr} strchars({expr} [, {skipcc}]) Number character length of the String {expr}
strcharpart({str}, {start} [, {len}]) strcharpart({str}, {start} [, {len}])
String {len} characters of {str} at {start} String {len} characters of {str} at
character {start}
strdisplaywidth({expr} [, {col}]) Number display length of the String {expr} strdisplaywidth({expr} [, {col}]) Number display length of the String {expr}
strftime({format} [, {time}]) String time in specified format strftime({format} [, {time}]) String time in specified format
strgetchar({str}, {index}) Number get char {index} from {str} strgetchar({str}, {index}) Number get char {index} from {str}
@@ -2417,8 +2418,9 @@ stridx({haystack}, {needle} [, {start}])
Number index of {needle} in {haystack} Number index of {needle} in {haystack}
string({expr}) String String representation of {expr} value string({expr}) String String representation of {expr} value
strlen({expr}) Number length of the String {expr} strlen({expr}) Number length of the String {expr}
strpart({str}, {start} [, {len}]) strpart({str}, {start} [, {len} [, {chars}]])
String {len} characters of {str} at {start} String {len} bytes/chars of {str} at
byte {start}
strridx({haystack}, {needle} [, {start}]) strridx({haystack}, {needle} [, {start}])
Number last index of {needle} in {haystack} Number last index of {needle} in {haystack}
strtrans({expr}) String translate string to make it printable strtrans({expr}) String translate string to make it printable
@@ -2906,7 +2908,8 @@ byte2line({byte}) *byte2line()*
byteidx({expr}, {nr}) *byteidx()* byteidx({expr}, {nr}) *byteidx()*
Return byte index of the {nr}'th character in the string Return byte index of the {nr}'th character in the string
{expr}. Use zero for the first character, it returns zero. {expr}. Use zero for the first character, it then returns
zero.
This function is only useful when there are multibyte This function is only useful when there are multibyte
characters, otherwise the returned value is equal to {nr}. characters, otherwise the returned value is equal to {nr}.
Composing characters are not counted separately, their byte Composing characters are not counted separately, their byte
@@ -8438,14 +8441,19 @@ strlen({expr}) The result is a Number, which is the length of the String
{expr} in bytes. {expr} in bytes.
If the argument is a Number it is first converted to a String. If the argument is a Number it is first converted to a String.
For other types an error is given. For other types an error is given.
If you want to count the number of multi-byte characters use If you want to count the number of multibyte characters use
|strchars()|. |strchars()|.
Also see |len()|, |strdisplaywidth()| and |strwidth()|. Also see |len()|, |strdisplaywidth()| and |strwidth()|.
strpart({src}, {start} [, {len}]) *strpart()* strpart({src}, {start} [, {len} [, {chars}]]) *strpart()*
The result is a String, which is part of {src}, starting from The result is a String, which is part of {src}, starting from
byte {start}, with the byte length {len}. byte {start}, with the byte length {len}.
To count characters instead of bytes use |strcharpart()|. When {chars} is present and TRUE then {len} is the number of
characters positions (composing characters are not counted
separately, thus "1" means one base character and any
following composing characters).
To count {start} as characters instead of bytes use
|strcharpart()|.
When bytes are selected which do not exist, this doesn't When bytes are selected which do not exist, this doesn't
result in an error, the bytes are simply omitted. result in an error, the bytes are simply omitted.
@@ -8457,8 +8465,8 @@ strpart({src}, {start} [, {len}]) *strpart()*
strpart("abcdefg", 3) == "defg" strpart("abcdefg", 3) == "defg"
< Note: To get the first character, {start} must be 0. For < Note: To get the first character, {start} must be 0. For
example, to get three bytes under and after the cursor: > example, to get the character under the cursor: >
strpart(getline("."), col(".") - 1, 3) strpart(getline("."), col(".") - 1, 1, v:true)
< <
strridx({haystack}, {needle} [, {start}]) *strridx()* strridx({haystack}, {needle} [, {start}]) *strridx()*
The result is a Number, which gives the byte index in The result is a Number, which gives the byte index in

View File

@@ -336,7 +336,7 @@ return {
stridx={args={2, 3}}, stridx={args={2, 3}},
string={args=1}, string={args=1},
strlen={args=1}, strlen={args=1},
strpart={args={2, 3}}, strpart={args={2, 4}},
strridx={args={2, 3}}, strridx={args={2, 3}},
strtrans={args=1}, strtrans={args=1},
strwidth={args=1}, strwidth={args=1},

View File

@@ -9946,6 +9946,16 @@ static void f_strpart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
len = slen - n; len = slen - n;
} }
if (argvars[2].v_type != VAR_UNKNOWN && argvars[3].v_type != VAR_UNKNOWN) {
int off;
// length in characters
for (off = n; off < (int)slen && len > 0; len--) {
off += utfc_ptr2len((char_u *)p + off);
}
len = off - n;
}
rettv->v_type = VAR_STRING; rettv->v_type = VAR_STRING;
rettv->vval.v_string = (char_u *)xmemdupz(p + n, (size_t)len); rettv->vval.v_string = (char_u *)xmemdupz(p + n, (size_t)len);
} }

View File

@@ -7,6 +7,19 @@
" ../vim -u NONE -S runtest.vim test_channel.vim open_delay " ../vim -u NONE -S runtest.vim test_channel.vim open_delay
" The output can be found in the "messages" file. " The output can be found in the "messages" file.
" "
" If the environment variable $TEST_FILTER is set then only test functions
" matching this pattern are executed. E.g. for sh/bash:
" export TEST_FILTER=Test_channel
" For csh:
" setenv TEST_FILTER Test_channel
"
" To ignore failure for tests that are known to fail in a certain environment,
" set $TEST_MAY_FAIL to a comma separated list of function names. E.g. for
" sh/bash:
" export TEST_MAY_FAIL=Test_channel_one,Test_channel_other
" The failure report will then not be included in the test.log file and
" "make test" will not fail.
"
" The test script may contain anything, only functions that start with " The test script may contain anything, only functions that start with
" "Test_" are special. These will be invoked and should contain assert " "Test_" are special. These will be invoked and should contain assert
" functions. See test_assert.vim for an example. " functions. See test_assert.vim for an example.
@@ -65,10 +78,14 @@ set encoding=utf-8
let s:test_script_fname = expand('%') let s:test_script_fname = expand('%')
au! SwapExists * call HandleSwapExists() au! SwapExists * call HandleSwapExists()
func HandleSwapExists() func HandleSwapExists()
" Only ignore finding a swap file for the test script (the user might be " Ignore finding a swap file for the test script (the user might be
" editing it and do ":make test_name") and the output file. " editing it and do ":make test_name") and the output file.
" Report finding another swap file and chose 'q' to avoid getting stuck.
if expand('<afile>') == 'messages' || expand('<afile>') =~ s:test_script_fname if expand('<afile>') == 'messages' || expand('<afile>') =~ s:test_script_fname
let v:swapchoice = 'e' let v:swapchoice = 'e'
else
call assert_report('Unexpected swap file: ' .. v:swapname)
let v:swapchoice = 'q'
endif endif
endfunc endfunc
@@ -136,13 +153,6 @@ func RunTheTest(test)
endtry endtry
endif endif
let message = 'Executed ' . a:test
if has('reltime')
let message ..= ' in ' .. reltimestr(reltime(func_start)) .. ' seconds'
endif
call add(s:messages, message)
let s:done += 1
if a:test =~ 'Test_nocatch_' if a:test =~ 'Test_nocatch_'
" Function handles errors itself. This avoids skipping commands after the " Function handles errors itself. This avoids skipping commands after the
" error. " error.
@@ -196,13 +206,26 @@ func RunTheTest(test)
endwhile endwhile
exe 'cd ' . save_cwd exe 'cd ' . save_cwd
let message = 'Executed ' . a:test
if has('reltime')
let message ..= ' in ' .. reltimestr(reltime(func_start)) .. ' seconds'
endif
call add(s:messages, message)
let s:done += 1
endfunc endfunc
func AfterTheTest() func AfterTheTest(func_name)
if len(v:errors) > 0 if len(v:errors) > 0
if match(s:may_fail_list, '^' .. a:func_name) >= 0
let s:fail_expected += 1
call add(s:errors_expected, 'Found errors in ' . s:test . ':')
call extend(s:errors_expected, v:errors)
else
let s:fail += 1 let s:fail += 1
call add(s:errors, 'Found errors in ' . s:test . ':') call add(s:errors, 'Found errors in ' . s:test . ':')
call extend(s:errors, v:errors) call extend(s:errors, v:errors)
endif
let v:errors = [] let v:errors = []
endif endif
endfunc endfunc
@@ -218,7 +241,7 @@ endfunc
" This function can be called by a test if it wants to abort testing. " This function can be called by a test if it wants to abort testing.
func FinishTesting() func FinishTesting()
call AfterTheTest() call AfterTheTest('')
" Don't write viminfo on exit. " Don't write viminfo on exit.
set viminfo= set viminfo=
@@ -226,7 +249,7 @@ func FinishTesting()
" Clean up files created by setup.vim " Clean up files created by setup.vim
call delete('XfakeHOME', 'rf') call delete('XfakeHOME', 'rf')
if s:fail == 0 if s:fail == 0 && s:fail_expected == 0
" Success, create the .res file so that make knows it's done. " Success, create the .res file so that make knows it's done.
exe 'split ' . fnamemodify(g:testname, ':r') . '.res' exe 'split ' . fnamemodify(g:testname, ':r') . '.res'
write write
@@ -242,11 +265,18 @@ func FinishTesting()
endif endif
if s:done == 0 if s:done == 0
let message = 'NO tests executed' if s:filtered > 0
let message = "NO tests match $TEST_FILTER: '" .. $TEST_FILTER .. "'"
else else
let message = 'NO tests executed'
endif
else
if s:filtered > 0
call add(s:messages, "Filtered " .. s:filtered .. " tests with $TEST_FILTER")
endif
let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test') let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
endif endif
if has('reltime') if s:done > 0 && has('reltime')
let message ..= ' in ' .. reltimestr(reltime(s:start_time)) .. ' seconds' let message ..= ' in ' .. reltimestr(reltime(s:start_time)) .. ' seconds'
endif endif
echo message echo message
@@ -257,6 +287,12 @@ func FinishTesting()
call add(s:messages, message) call add(s:messages, message)
call extend(s:messages, s:errors) call extend(s:messages, s:errors)
endif endif
if s:fail_expected > 0
let message = s:fail_expected . ' FAILED (matching $TEST_MAY_FAIL):'
echo message
call add(s:messages, message)
call extend(s:messages, s:errors_expected)
endif
" Add SKIPPED messages " Add SKIPPED messages
call extend(s:messages, s:skipped) call extend(s:messages, s:skipped)
@@ -276,11 +312,13 @@ endfunc
let g:testname = expand('%') let g:testname = expand('%')
let s:done = 0 let s:done = 0
let s:fail = 0 let s:fail = 0
let s:fail_expected = 0
let s:errors = [] let s:errors = []
let s:errors_expected = []
let s:messages = [] let s:messages = []
let s:skipped = [] let s:skipped = []
if expand('%') =~ 'test_vimscript.vim' if expand('%') =~ 'test_vimscript.vim'
" this test has intentional s:errors, don't use try/catch. " this test has intentional errors, don't use try/catch.
source % source %
else else
try try
@@ -311,11 +349,12 @@ let s:flaky_tests = [
\ 'Test_repeat_three()', \ 'Test_repeat_three()',
\ 'Test_state()', \ 'Test_state()',
\ 'Test_stop_all_in_callback()', \ 'Test_stop_all_in_callback()',
\ 'Test_term_mouse_double_click_to_create_tab', \ 'Test_term_mouse_double_click_to_create_tab()',
\ 'Test_term_mouse_multiple_clicks_to_visually_select()', \ 'Test_term_mouse_multiple_clicks_to_visually_select()',
\ 'Test_terminal_composing_unicode()', \ 'Test_terminal_composing_unicode()',
\ 'Test_terminal_redir_file()', \ 'Test_terminal_redir_file()',
\ 'Test_terminal_tmap()', \ 'Test_terminal_tmap()',
\ 'Test_termwinscroll()',
\ 'Test_with_partial_callback()', \ 'Test_with_partial_callback()',
\ ] \ ]
@@ -335,8 +374,17 @@ endif
" If the environment variable $TEST_FILTER is set then filter the function " If the environment variable $TEST_FILTER is set then filter the function
" names against it. " names against it.
let s:filtered = 0
if $TEST_FILTER != '' if $TEST_FILTER != ''
let s:filtered = len(s:tests)
let s:tests = filter(s:tests, 'v:val =~ $TEST_FILTER') let s:tests = filter(s:tests, 'v:val =~ $TEST_FILTER')
let s:filtered -= len(s:tests)
endif
let s:may_fail_list = []
if $TEST_MAY_FAIL != ''
" Split the list at commas and add () to make it match s:test.
let s:may_fail_list = split($TEST_MAY_FAIL, ',')->map({i, v -> v .. '()'})
endif endif
" Execute the tests in alphabetical order. " Execute the tests in alphabetical order.
@@ -388,7 +436,7 @@ for s:test in sort(s:tests)
endwhile endwhile
endif endif
call AfterTheTest() call AfterTheTest(s:test)
endfor endfor
call FinishTesting() call FinishTesting()

View File

@@ -334,6 +334,10 @@ func Test_strpart()
call assert_equal('lép', strpart('éléphant', 2, 4)) call assert_equal('lép', strpart('éléphant', 2, 4))
call assert_equal('léphant', strpart('éléphant', 2)) call assert_equal('léphant', strpart('éléphant', 2))
call assert_equal('é', strpart('éléphant', 0, 1, 1))
call assert_equal('ép', strpart('éléphant', 3, 2, v:true))
call assert_equal('ó', strpart('cómposed', 1, 1, 1))
endfunc endfunc
func Test_tolower() func Test_tolower()

View File

@@ -9,6 +9,29 @@ endif
source shared.vim source shared.vim
source term_util.vim source term_util.vim
" Test for storing global and local argument list in a session file
" This one must be done first.
func Test__mksession_arglocal()
enew | only
n a b c
new
arglocal
mksession! Xtest_mks.out
%bwipe!
%argdelete
argglobal
source Xtest_mks.out
call assert_equal(2, winnr('$'))
call assert_equal(2, arglistid(1))
call assert_equal(0, arglistid(2))
%bwipe!
%argdelete
argglobal
call delete('Xtest_mks.out')
endfunc
func Test_mksession() func Test_mksession()
tabnew tabnew
let wrap_save = &wrap let wrap_save = &wrap
@@ -359,28 +382,6 @@ func Test_mksession_slash()
set sessionoptions& set sessionoptions&
endfunc endfunc
" Test for storing global and local argument list in a session file
func Test_mkseesion_arglocal()
enew | only
n a b c
new
arglocal
mksession! Xtest_mks.out
%bwipe!
%argdelete
argglobal
source Xtest_mks.out
call assert_equal(2, winnr('$'))
call assert_equal(2, arglistid(1))
call assert_equal(0, arglistid(2))
%bwipe!
%argdelete
argglobal
call delete('Xtest_mks.out')
endfunc
" Test for changing directory to the session file directory " Test for changing directory to the session file directory
func Test_mksession_sesdir() func Test_mksession_sesdir()
call mkdir('Xproj') call mkdir('Xproj')