mirror of
https://github.com/neovim/neovim.git
synced 2025-11-06 10:44:22 +00:00
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:
@@ -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
|
||||||
|
|||||||
@@ -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},
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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')
|
||||||
|
|||||||
Reference in New Issue
Block a user