Mercurial > vim
view src/testdir/test_vim9_script.vim @ 27970:212c5894b8b1 v8.2.4510
patch 8.2.4510: Vim9: shortening commands leads to confusing script
Commit: https://github.com/vim/vim/commit/204852ae2adfdde10c656ca7f14e5b4207a69172
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Mar 5 12:56:44 2022 +0000
patch 8.2.4510: Vim9: shortening commands leads to confusing script
Problem: Vim9: shortening commands leads to confusing script.
Solution: In Vim9 script require at least ":cont" for ":continue", "const"
instead of "cons", "break" instead of "brea", "catch" instead of
"cat", "else" instead of "el" "elseif" instead of "elsei" "endfor"
instead of "endfo" "endif" instead of "en" "endtry" instead of
"endt", "finally" instead of "fina", "throw" instead of "th",
"while" instead of "wh".
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sat, 05 Mar 2022 14:00:03 +0100 |
parents | 80f398bfc19f |
children | 442ca2007bec |
line wrap: on
line source
" Test various aspects of the Vim9 script language. source check.vim source term_util.vim import './vim9.vim' as v9 source screendump.vim source shared.vim def Test_vim9script_feature() # example from the help, here the feature is always present var lines =<< trim END " old style comment if !has('vim9script') " legacy commands would go here finish endif vim9script # Vim9 script commands go here g:didit = true END v9.CheckScriptSuccess(lines) assert_equal(true, g:didit) unlet g:didit enddef def Test_range_only() new setline(1, ['blah', 'Blah']) :/Blah/ assert_equal(2, getcurpos()[1]) bwipe! # without range commands use current line new setline(1, ['one', 'two', 'three']) :2 print assert_equal('two', g:Screenline(&lines)) :3 list assert_equal('three$', g:Screenline(&lines)) # missing command does not print the line var lines =<< trim END vim9script :1| assert_equal('three$', g:Screenline(&lines)) :| assert_equal('three$', g:Screenline(&lines)) END v9.CheckScriptSuccess(lines) bwipe! lines =<< trim END set cpo+=- :1,999 END v9.CheckDefExecAndScriptFailure(lines, 'E16:', 2) set cpo&vim v9.CheckDefExecAndScriptFailure([":'x"], 'E20:', 1) # won't generate anything if false :123 endif enddef let g:alist = [7] let g:astring = 'text' let g:anumber = 123 def Test_delfunction() # Check function is defined in script namespace v9.CheckScriptSuccess([ 'vim9script', 'func CheckMe()', ' return 123', 'endfunc', 'func DoTest()', ' call assert_equal(123, s:CheckMe())', 'endfunc', 'DoTest()', ]) # Check function in script namespace cannot be deleted v9.CheckScriptFailure([ 'vim9script', 'func DeleteMe1()', 'endfunc', 'delfunction DeleteMe1', ], 'E1084:') v9.CheckScriptFailure([ 'vim9script', 'func DeleteMe2()', 'endfunc', 'def DoThat()', ' delfunction DeleteMe2', 'enddef', 'DoThat()', ], 'E1084:') v9.CheckScriptFailure([ 'vim9script', 'def DeleteMe3()', 'enddef', 'delfunction DeleteMe3', ], 'E1084:') v9.CheckScriptFailure([ 'vim9script', 'def DeleteMe4()', 'enddef', 'def DoThat()', ' delfunction DeleteMe4', 'enddef', 'DoThat()', ], 'E1084:') # Check that global :def function can be replaced and deleted var lines =<< trim END vim9script def g:Global(): string return "yes" enddef assert_equal("yes", g:Global()) def! g:Global(): string return "no" enddef assert_equal("no", g:Global()) delfunc g:Global assert_false(exists('*g:Global')) END v9.CheckScriptSuccess(lines) # Check that global function can be replaced by a :def function and deleted lines =<< trim END vim9script func g:Global() return "yes" endfunc assert_equal("yes", g:Global()) def! g:Global(): string return "no" enddef assert_equal("no", g:Global()) delfunc g:Global assert_false(exists('*g:Global')) END v9.CheckScriptSuccess(lines) # Check that global :def function can be replaced by a function and deleted lines =<< trim END vim9script def g:Global(): string return "yes" enddef assert_equal("yes", g:Global()) func! g:Global() return "no" endfunc assert_equal("no", g:Global()) delfunc g:Global assert_false(exists('*g:Global')) END v9.CheckScriptSuccess(lines) enddef def Test_wrong_type() v9.CheckDefFailure(['var name: list<nothing>'], 'E1010:') v9.CheckDefFailure(['var name: list<list<nothing>>'], 'E1010:') v9.CheckDefFailure(['var name: dict<nothing>'], 'E1010:') v9.CheckDefFailure(['var name: dict<dict<nothing>>'], 'E1010:') v9.CheckDefFailure(['var name: dict<number'], 'E1009:') v9.CheckDefFailure(['var name: dict<list<number>'], 'E1009:') v9.CheckDefFailure(['var name: ally'], 'E1010:') v9.CheckDefFailure(['var name: bram'], 'E1010:') v9.CheckDefFailure(['var name: cathy'], 'E1010:') v9.CheckDefFailure(['var name: dom'], 'E1010:') v9.CheckDefFailure(['var name: freddy'], 'E1010:') v9.CheckDefFailure(['var name: john'], 'E1010:') v9.CheckDefFailure(['var name: larry'], 'E1010:') v9.CheckDefFailure(['var name: ned'], 'E1010:') v9.CheckDefFailure(['var name: pam'], 'E1010:') v9.CheckDefFailure(['var name: sam'], 'E1010:') v9.CheckDefFailure(['var name: vim'], 'E1010:') v9.CheckDefFailure(['var Ref: number', 'Ref()'], 'E1085:') v9.CheckDefFailure(['var Ref: string', 'var res = Ref()'], 'E1085:') enddef def Test_script_namespace() # defining a function or variable with s: is not allowed var lines =<< trim END vim9script def s:Function() enddef END v9.CheckScriptFailure(lines, 'E1268:') for decl in ['var', 'const', 'final'] lines =<< trim END vim9script var s:var = 'var' END v9.CheckScriptFailure([ 'vim9script', decl .. ' s:var = "var"', ], 'E1268:') endfor # Calling a function or using a variable with s: is not allowed at script # level lines =<< trim END vim9script def Function() enddef s:Function() END v9.CheckScriptFailure(lines, 'E1268:') lines =<< trim END vim9script def Function() enddef call s:Function() END v9.CheckScriptFailure(lines, 'E1268:') lines =<< trim END vim9script var var = 'var' echo s:var END v9.CheckScriptFailure(lines, 'E1268:') enddef def Test_script_wrong_type() var lines =<< trim END vim9script var dict: dict<string> dict['a'] = ['x'] END v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got list<string>', 3) enddef def Test_const() v9.CheckDefFailure(['final name = 234', 'name = 99'], 'E1018:') v9.CheckDefFailure(['final one = 234', 'var one = 99'], 'E1017:') v9.CheckDefFailure(['final list = [1, 2]', 'var list = [3, 4]'], 'E1017:') v9.CheckDefFailure(['final two'], 'E1125:') v9.CheckDefFailure(['final &option'], 'E996:') var lines =<< trim END final list = [1, 2, 3] list[0] = 4 list->assert_equal([4, 2, 3]) const other = [5, 6, 7] other->assert_equal([5, 6, 7]) var varlist = [7, 8] const constlist = [1, varlist, 3] varlist[0] = 77 constlist[1][1] = 88 var cl = constlist[1] cl[1] = 88 constlist->assert_equal([1, [77, 88], 3]) var vardict = {five: 5, six: 6} const constdict = {one: 1, two: vardict, three: 3} vardict['five'] = 55 constdict['two']['six'] = 66 var cd = constdict['two'] cd['six'] = 66 constdict->assert_equal({one: 1, two: {five: 55, six: 66}, three: 3}) END v9.CheckDefAndScriptSuccess(lines) enddef def Test_const_bang() var lines =<< trim END const var = 234 var = 99 END v9.CheckDefExecFailure(lines, 'E1018:', 2) v9.CheckScriptFailure(['vim9script'] + lines, 'E46:', 3) lines =<< trim END const ll = [2, 3, 4] ll[0] = 99 END v9.CheckDefExecFailure(lines, 'E1119:', 2) v9.CheckScriptFailure(['vim9script'] + lines, 'E741:', 3) lines =<< trim END const ll = [2, 3, 4] ll[3] = 99 END v9.CheckDefExecFailure(lines, 'E1118:', 2) v9.CheckScriptFailure(['vim9script'] + lines, 'E684:', 3) lines =<< trim END const dd = {one: 1, two: 2} dd["one"] = 99 END v9.CheckDefExecFailure(lines, 'E1121:', 2) v9.CheckScriptFailure(['vim9script'] + lines, 'E741:', 3) lines =<< trim END const dd = {one: 1, two: 2} dd["three"] = 99 END v9.CheckDefExecFailure(lines, 'E1120:') v9.CheckScriptFailure(['vim9script'] + lines, 'E741:', 3) enddef def Test_range_no_colon() v9.CheckDefFailure(['%s/a/b/'], 'E1050:') v9.CheckDefFailure(['+ s/a/b/'], 'E1050:') v9.CheckDefFailure(['- s/a/b/'], 'E1050:') v9.CheckDefFailure(['. s/a/b/'], 'E1050:') enddef def Test_block() var outer = 1 { var inner = 2 assert_equal(1, outer) assert_equal(2, inner) } assert_equal(1, outer) {|echo 'yes'|} enddef def Test_block_failure() v9.CheckDefFailure(['{', 'var inner = 1', '}', 'echo inner'], 'E1001:') v9.CheckDefFailure(['}'], 'E1025:') v9.CheckDefFailure(['{', 'echo 1'], 'E1026:') enddef def Test_block_local_vars() var lines =<< trim END vim9script v:testing = 1 if true var text = ['hello'] def SayHello(): list<string> return text enddef def SetText(v: string) text = [v] enddef endif if true var text = ['again'] def SayAgain(): list<string> return text enddef endif # test that the "text" variables are not cleaned up test_garbagecollect_now() defcompile assert_equal(['hello'], SayHello()) assert_equal(['again'], SayAgain()) SetText('foobar') assert_equal(['foobar'], SayHello()) call writefile(['ok'], 'Xdidit') qall! END # need to execute this with a separate Vim instance to avoid the current # context gets garbage collected. writefile(lines, 'Xscript') g:RunVim([], [], '-S Xscript') assert_equal(['ok'], readfile('Xdidit')) delete('Xscript') delete('Xdidit') enddef def Test_block_local_vars_with_func() var lines =<< trim END vim9script if true var foo = 'foo' if true var bar = 'bar' def Func(): list<string> return [foo, bar] enddef endif endif # function is compiled here, after blocks have finished, can still access # "foo" and "bar" assert_equal(['foo', 'bar'], Func()) END v9.CheckScriptSuccess(lines) enddef " legacy func for command that's defined later func s:InvokeSomeCommand() SomeCommand endfunc def Test_autocommand_block() com SomeCommand { g:someVar = 'some' } InvokeSomeCommand() assert_equal('some', g:someVar) delcommand SomeCommand unlet g:someVar enddef def Test_command_block() au BufNew *.xml { g:otherVar = 'other' } split other.xml assert_equal('other', g:otherVar) bwipe! au! BufNew *.xml unlet g:otherVar enddef func g:NoSuchFunc() echo 'none' endfunc def Test_try_catch_throw() var l = [] try # comment add(l, '1') throw 'wrong' add(l, '2') catch # comment add(l, v:exception) finally # comment add(l, '3') endtry # comment assert_equal(['1', 'wrong', '3'], l) l = [] try try add(l, '1') throw 'wrong' add(l, '2') catch /right/ add(l, v:exception) endtry catch /wrong/ add(l, 'caught') finally add(l, 'finally') endtry assert_equal(['1', 'caught', 'finally'], l) var n: number try n = l[3] catch /E684:/ n = 99 endtry assert_equal(99, n) var done = 'no' if 0 try | catch | endtry else done = 'yes' endif assert_equal('yes', done) done = 'no' if 1 done = 'yes' else try | catch | endtry done = 'never' endif assert_equal('yes', done) if 1 else try | catch /pat/ | endtry try | catch /pat/ endtry try catch /pat/ | endtry try catch /pat/ endtry endif try # string slice returns a string, not a number n = g:astring[3] catch /E1012:/ n = 77 endtry assert_equal(77, n) try n = l[g:astring] catch /E1012:/ n = 88 endtry assert_equal(88, n) try n = s:does_not_exist catch /E121:/ n = 111 endtry assert_equal(111, n) try n = g:does_not_exist catch /E121:/ n = 121 endtry assert_equal(121, n) var d = {one: 1} try n = d[g:astring] catch /E716:/ n = 222 endtry assert_equal(222, n) try n = -g:astring catch /E1012:/ n = 233 endtry assert_equal(233, n) try n = +g:astring catch /E1012:/ n = 244 endtry assert_equal(244, n) try n = +g:alist catch /E1012:/ n = 255 endtry assert_equal(255, n) var nd: dict<any> try nd = {[g:alist]: 1} catch /E1105:/ n = 266 endtry assert_equal(266, n) l = [1, 2, 3] try [n] = l catch /E1093:/ n = 277 endtry assert_equal(277, n) try &ts = g:astring catch /E1012:/ n = 288 endtry assert_equal(288, n) try &backspace = 'asdf' catch /E474:/ n = 299 endtry assert_equal(299, n) l = [1] try l[3] = 3 catch /E684:/ n = 300 endtry assert_equal(300, n) try unlet g:does_not_exist catch /E108:/ n = 322 endtry assert_equal(322, n) try d = {text: 1, [g:astring]: 2} catch /E721:/ n = 333 endtry assert_equal(333, n) try l = g:DeletedFunc() catch /E933:/ n = 344 endtry assert_equal(344, n) try echo range(1, 2, 0) catch /E726:/ n = 355 endtry assert_equal(355, n) var P = function('g:NoSuchFunc') delfunc g:NoSuchFunc try echo P() catch /E117:/ n = 366 endtry assert_equal(366, n) try echo g:NoSuchFunc() catch /E117:/ n = 377 endtry assert_equal(377, n) try echo g:alist + 4 catch /E745:/ n = 388 endtry assert_equal(388, n) try echo 4 + g:alist catch /E745:/ n = 399 endtry assert_equal(399, n) try echo g:alist.member catch /E715:/ n = 400 endtry assert_equal(400, n) try echo d.member catch /E716:/ n = 411 endtry assert_equal(411, n) var counter = 0 for i in range(4) try eval [][0] catch endtry counter += 1 endfor assert_equal(4, counter) # no requirement for spaces before | try|echo 0|catch|endtry # return in try with finally def ReturnInTry(): number var ret = 4 try return ret catch /this/ return -1 catch /that/ return -1 finally # changing ret has no effect ret = 7 endtry return -2 enddef assert_equal(4, ReturnInTry()) # return in catch with finally def ReturnInCatch(): number var ret = 5 try throw 'getout' return -1 catch /getout/ # ret is evaluated here return ret finally # changing ret later has no effect ret = -3 endtry return -2 enddef assert_equal(5, ReturnInCatch()) # return in finally after empty catch def ReturnInFinally(): number try finally return 6 endtry enddef assert_equal(6, ReturnInFinally()) var lines =<< trim END vim9script try acos('0.5') ->setline(1) catch g:caught = v:exception endtry END v9.CheckScriptSuccess(lines) assert_match('E1219: Float or Number required for argument 1', g:caught) unlet g:caught # missing catch and/or finally lines =<< trim END vim9script try echo 'something' endtry END v9.CheckScriptFailure(lines, 'E1032:') # skipping try-finally-endtry when try-finally-endtry is used in another block lines =<< trim END if v:true try finally endtry else try finally endtry endif END v9.CheckDefAndScriptSuccess(lines) enddef def Test_try_var_decl() var lines =<< trim END vim9script try var in_try = 1 assert_equal(1, get(s:, 'in_try', -1)) throw "getout" catch var in_catch = 2 assert_equal(-1, get(s:, 'in_try', -1)) assert_equal(2, get(s:, 'in_catch', -1)) finally var in_finally = 3 assert_equal(-1, get(s:, 'in_try', -1)) assert_equal(-1, get(s:, 'in_catch', -1)) assert_equal(3, get(s:, 'in_finally', -1)) endtry assert_equal(-1, get(s:, 'in_try', -1)) assert_equal(-1, get(s:, 'in_catch', -1)) assert_equal(-1, get(s:, 'in_finally', -1)) END v9.CheckScriptSuccess(lines) enddef def Test_try_ends_in_return() var lines =<< trim END vim9script def Foo(): string try return 'foo' catch return 'caught' endtry enddef assert_equal('foo', Foo()) END v9.CheckScriptSuccess(lines) lines =<< trim END vim9script def Foo(): string try return 'foo' catch return 'caught' endtry echo 'notreached' enddef assert_equal('foo', Foo()) END v9.CheckScriptFailure(lines, 'E1095:') lines =<< trim END vim9script def Foo(): string try return 'foo' catch /x/ return 'caught' endtry enddef assert_equal('foo', Foo()) END v9.CheckScriptFailure(lines, 'E1027:') lines =<< trim END vim9script def Foo(): string try echo 'foo' catch echo 'caught' finally return 'done' endtry enddef assert_equal('done', Foo()) END v9.CheckScriptSuccess(lines) enddef def Test_try_in_catch() var lines =<< trim END vim9script var seq = [] def DoIt() try seq->add('throw 1') eval [][0] seq->add('notreached') catch seq->add('catch') try seq->add('throw 2') eval [][0] seq->add('notreached') catch /nothing/ seq->add('notreached') endtry seq->add('done') endtry enddef DoIt() assert_equal(['throw 1', 'catch', 'throw 2', 'done'], seq) END enddef def Test_error_in_catch() var lines =<< trim END try eval [][0] catch /E684:/ eval [][0] endtry END v9.CheckDefExecFailure(lines, 'E684:', 4) enddef " :while at the very start of a function that :continue jumps to def s:TryContinueFunc() while g:Count < 2 g:sequence ..= 't' try echoerr 'Test' catch g:Count += 1 g:sequence ..= 'c' continue endtry g:sequence ..= 'e' g:Count += 1 endwhile enddef def Test_continue_in_try_in_while() g:Count = 0 g:sequence = '' TryContinueFunc() assert_equal('tctc', g:sequence) unlet g:Count unlet g:sequence enddef def Test_nocatch_return_in_try() # return in try block returns normally def ReturnInTry(): string try return '"some message"' catch endtry return 'not reached' enddef exe 'echoerr ' .. ReturnInTry() enddef def Test_cnext_works_in_catch() var lines =<< trim END vim9script au BufEnter * eval 1 + 2 writefile(['text'], 'Xfile1') writefile(['text'], 'Xfile2') var items = [ {lnum: 1, filename: 'Xfile1', valid: true}, {lnum: 1, filename: 'Xfile2', valid: true} ] setqflist([], ' ', {items: items}) cwindow def CnextOrCfirst() # if cnext fails, cfirst is used try cnext catch cfirst endtry enddef CnextOrCfirst() CnextOrCfirst() writefile([getqflist({idx: 0}).idx], 'Xresult') qall END writefile(lines, 'XCatchCnext') g:RunVim([], [], '--clean -S XCatchCnext') assert_equal(['1'], readfile('Xresult')) delete('Xfile1') delete('Xfile2') delete('XCatchCnext') delete('Xresult') enddef def Test_throw_skipped() if 0 throw dontgethere endif enddef def Test_nocatch_throw_silenced() var lines =<< trim END vim9script def Func() throw 'error' enddef silent! Func() END writefile(lines, 'XthrowSilenced') source XthrowSilenced delete('XthrowSilenced') enddef def DeletedFunc(): list<any> return ['delete me'] enddef defcompile delfunc DeletedFunc def s:ThrowFromDef() throw "getout" # comment enddef func s:CatchInFunc() try call s:ThrowFromDef() catch let g:thrown_func = v:exception endtry endfunc def s:CatchInDef() try ThrowFromDef() catch g:thrown_def = v:exception endtry enddef def s:ReturnFinally(): string try return 'intry' finally g:in_finally = 'finally' endtry return 'end' enddef def Test_try_catch_nested() CatchInFunc() assert_equal('getout', g:thrown_func) CatchInDef() assert_equal('getout', g:thrown_def) assert_equal('intry', ReturnFinally()) assert_equal('finally', g:in_finally) var l = [] try l->add('1') throw 'bad' l->add('x') catch /bad/ l->add('2') try l->add('3') throw 'one' l->add('x') catch /one/ l->add('4') try l->add('5') throw 'more' l->add('x') catch /more/ l->add('6') endtry endtry endtry assert_equal(['1', '2', '3', '4', '5', '6'], l) l = [] try try l->add('1') throw 'foo' l->add('x') catch l->add('2') throw 'bar' l->add('x') finally l->add('3') endtry l->add('x') catch /bar/ l->add('4') endtry assert_equal(['1', '2', '3', '4'], l) enddef def s:TryOne(): number try return 0 catch endtry return 0 enddef def s:TryTwo(n: number): string try var x = {} catch endtry return 'text' enddef def Test_try_catch_twice() assert_equal('text', TryOne()->TryTwo()) enddef def Test_try_catch_match() var seq = 'a' try throw 'something' catch /nothing/ seq ..= 'x' catch /some/ seq ..= 'b' catch /asdf/ seq ..= 'x' catch ?a\?sdf? seq ..= 'y' finally seq ..= 'c' endtry assert_equal('abc', seq) enddef def Test_try_catch_fails() v9.CheckDefFailure(['catch'], 'E603:') v9.CheckDefFailure(['try', 'echo 0', 'catch', 'catch'], 'E1033:') v9.CheckDefFailure(['try', 'echo 0', 'catch /pat'], 'E1067:') v9.CheckDefFailure(['finally'], 'E606:') v9.CheckDefFailure(['try', 'echo 0', 'finally', 'echo 1', 'finally'], 'E607:') v9.CheckDefFailure(['endtry'], 'E602:') v9.CheckDefFailure(['while 1', 'endtry'], 'E170:') v9.CheckDefFailure(['for i in range(5)', 'endtry'], 'E170:') v9.CheckDefFailure(['if 1', 'endtry'], 'E171:') v9.CheckDefFailure(['try', 'echo 1', 'endtry'], 'E1032:') v9.CheckDefFailure(['throw'], 'E1143:') v9.CheckDefFailure(['throw xxx'], 'E1001:') enddef def Try_catch_skipped() var l = [] try finally endtry if 1 else try endtry endif enddef " The skipped try/endtry was updating the wrong instruction. def Test_try_catch_skipped() var instr = execute('disassemble Try_catch_skipped') assert_match("NEWLIST size 0\n", instr) enddef def Test_throw_line_number() def Func() eval 1 + 1 eval 2 + 2 throw 'exception' enddef try Func() catch /exception/ assert_match('line 3', v:throwpoint) endtry enddef def Test_throw_vimscript() # only checks line continuation var lines =<< trim END vim9script try throw 'one' .. 'two' catch assert_equal('onetwo', v:exception) endtry END v9.CheckScriptSuccess(lines) lines =<< trim END vim9script @r = '' def Func() throw @r enddef var result = '' try Func() catch /E1129:/ result = 'caught' endtry assert_equal('caught', result) END v9.CheckScriptSuccess(lines) enddef def Test_error_in_nested_function() # an error in a nested :function aborts executing in the calling :def function var lines =<< trim END vim9script def Func() Error() g:test_var = 1 enddef func Error() abort eval [][0] endfunc Func() END g:test_var = 0 v9.CheckScriptFailure(lines, 'E684:') assert_equal(0, g:test_var) enddef def Test_abort_after_error() var lines =<< trim END vim9script while true echo notfound endwhile g:gotthere = true END g:gotthere = false v9.CheckScriptFailure(lines, 'E121:') assert_false(g:gotthere) unlet g:gotthere enddef def Test_cexpr_vimscript() # only checks line continuation set errorformat=File\ %f\ line\ %l var lines =<< trim END vim9script cexpr 'File' .. ' someFile' .. ' line 19' assert_equal(19, getqflist()[0].lnum) END v9.CheckScriptSuccess(lines) set errorformat& enddef def Test_statusline_syntax() # legacy syntax is used for 'statusline' var lines =<< trim END vim9script func g:Status() return '%{"x" is# "x"}' endfunc set laststatus=2 statusline=%!Status() redrawstatus set laststatus statusline= END v9.CheckScriptSuccess(lines) enddef def Test_list_vimscript() # checks line continuation and comments var lines =<< trim END vim9script var mylist = [ 'one', # comment 'two', # empty line follows 'three', ] assert_equal(['one', 'two', 'three'], mylist) END v9.CheckScriptSuccess(lines) # check all lines from heredoc are kept lines =<< trim END # comment 1 two # comment 3 five # comment 6 END assert_equal(['# comment 1', 'two', '# comment 3', '', 'five', '# comment 6'], lines) lines =<< trim END [{ a: 0}]->string()->assert_equal("[{'a': 0}]") END v9.CheckDefAndScriptSuccess(lines) enddef if has('channel') let someJob = test_null_job() def FuncWithError() echomsg g:someJob enddef func Test_convert_emsg_to_exception() try call FuncWithError() catch call assert_match('Vim:E908:', v:exception) endtry endfunc endif def Test_vim9script_mix() var lines =<< trim END if has(g:feature) " legacy script let g:legacy = 1 finish endif vim9script g:legacy = 0 END g:feature = 'eval' g:legacy = -1 v9.CheckScriptSuccess(lines) assert_equal(1, g:legacy) g:feature = 'noteval' g:legacy = -1 v9.CheckScriptSuccess(lines) assert_equal(0, g:legacy) enddef def Test_vim9script_fails() v9.CheckScriptFailure(['scriptversion 2', 'vim9script'], 'E1039:') v9.CheckScriptFailure(['vim9script', 'scriptversion 2'], 'E1040:') v9.CheckScriptFailure(['vim9script', 'var str: string', 'str = 1234'], 'E1012:') v9.CheckScriptFailure(['vim9script', 'const str = "asdf"', 'str = "xxx"'], 'E46:') assert_fails('vim9script', 'E1038:') v9.CheckDefFailure(['vim9script'], 'E1038:') # no error when skipping if has('nothing') vim9script endif enddef def Test_script_var_shadows_function() var lines =<< trim END vim9script def Func(): number return 123 enddef var Func = 1 END v9.CheckScriptFailure(lines, 'E1041:', 5) enddef def Test_function_shadows_script_var() var lines =<< trim END vim9script var Func = 1 def Func(): number return 123 enddef END v9.CheckScriptFailure(lines, 'E1041:', 3) enddef def Test_script_var_shadows_command() var lines =<< trim END var undo = 1 undo = 2 assert_equal(2, undo) END v9.CheckDefAndScriptSuccess(lines) lines =<< trim END var undo = 1 undo END v9.CheckDefAndScriptFailure(lines, 'E1207:', 2) enddef def Test_vim9script_call_wrong_type() var lines =<< trim END vim9script var Time = 'localtime' Time() END v9.CheckScriptFailure(lines, 'E1085:') enddef def Test_vim9script_reload_delfunc() var first_lines =<< trim END vim9script def FuncYes(): string return 'yes' enddef END var withno_lines =<< trim END def FuncNo(): string return 'no' enddef def g:DoCheck(no_exists: bool) assert_equal('yes', FuncYes()) assert_equal('no', FuncNo()) enddef END var nono_lines =<< trim END def g:DoCheck(no_exists: bool) assert_equal('yes', FuncYes()) assert_fails('FuncNo()', 'E117:', '', 2, 'DoCheck') enddef END # FuncNo() is defined writefile(first_lines + withno_lines, 'Xreloaded.vim') source Xreloaded.vim g:DoCheck(true) # FuncNo() is not redefined writefile(first_lines + nono_lines, 'Xreloaded.vim') source Xreloaded.vim g:DoCheck(false) # FuncNo() is back writefile(first_lines + withno_lines, 'Xreloaded.vim') source Xreloaded.vim g:DoCheck(false) delete('Xreloaded.vim') enddef def Test_vim9script_reload_delvar() # write the script with a script-local variable var lines =<< trim END vim9script var name = 'string' END writefile(lines, 'XreloadVar.vim') source XreloadVar.vim # now write the script using the same variable locally - works lines =<< trim END vim9script def Func() var name = 'string' enddef END writefile(lines, 'XreloadVar.vim') source XreloadVar.vim delete('XreloadVar.vim') enddef def Test_func_redefine_error() var lines = [ 'vim9script', 'def Func()', ' eval [][0]', 'enddef', 'Func()', ] writefile(lines, 'Xtestscript.vim') for count in range(3) try source Xtestscript.vim catch /E684/ # function name should contain <SNR> every time assert_match('E684: list index out of range', v:exception) assert_match('function <SNR>\d\+_Func, line 1', v:throwpoint) endtry endfor delete('Xtestscript.vim') enddef def Test_func_redefine_fails() var lines =<< trim END vim9script def Func() echo 'one' enddef def Func() echo 'two' enddef END v9.CheckScriptFailure(lines, 'E1073:') lines =<< trim END vim9script def Foo(): string return 'foo' enddef def Func() var Foo = {-> 'lambda'} enddef defcompile END v9.CheckScriptFailure(lines, 'E1073:') enddef def Test_fixed_size_list() # will be allocated as one piece of memory, check that changes work var l = [1, 2, 3, 4] l->remove(0) l->add(5) l->insert(99, 1) assert_equal([2, 99, 3, 4, 5], l) enddef def Test_no_insert_xit() v9.CheckDefExecFailure(['a = 1'], 'E1100:') v9.CheckDefExecFailure(['c = 1'], 'E1100:') v9.CheckDefExecFailure(['i = 1'], 'E1100:') v9.CheckDefExecFailure(['t = 1'], 'E1100:') v9.CheckDefExecFailure(['x = 1'], 'E1100:') v9.CheckScriptFailure(['vim9script', 'a = 1'], 'E488:') v9.CheckScriptFailure(['vim9script', 'a'], 'E1100:') v9.CheckScriptFailure(['vim9script', 'c = 1'], 'E488:') v9.CheckScriptFailure(['vim9script', 'c'], 'E1100:') v9.CheckScriptFailure(['vim9script', 'i = 1'], 'E488:') v9.CheckScriptFailure(['vim9script', 'i'], 'E1100:') v9.CheckScriptFailure(['vim9script', 'o = 1'], 'E1100:') v9.CheckScriptFailure(['vim9script', 'o'], 'E1100:') v9.CheckScriptFailure(['vim9script', 't'], 'E1100:') v9.CheckScriptFailure(['vim9script', 't = 1'], 'E1100:') v9.CheckScriptFailure(['vim9script', 'x = 1'], 'E1100:') enddef def s:IfElse(what: number): string var res = '' if what == 1 res = "one" elseif what == 2 res = "two" else res = "three" endif return res enddef def Test_if_elseif_else() assert_equal('one', IfElse(1)) assert_equal('two', IfElse(2)) assert_equal('three', IfElse(3)) enddef def Test_if_elseif_else_fails() v9.CheckDefFailure(['elseif true'], 'E582:') v9.CheckDefFailure(['else'], 'E581:') v9.CheckDefFailure(['endif'], 'E580:') v9.CheckDefFailure(['if g:abool', 'elseif xxx'], 'E1001:') v9.CheckDefFailure(['if true', 'echo 1'], 'E171:') var lines =<< trim END var s = '' if s = '' endif END v9.CheckDefFailure(lines, 'E488:') lines =<< trim END var s = '' if s == '' elseif s = '' endif END v9.CheckDefFailure(lines, 'E488:') enddef let g:bool_true = v:true let g:bool_false = v:false def Test_if_const_expr() var res = false if true ? true : false res = true endif assert_equal(true, res) g:glob = 2 if false execute('g:glob = 3') endif assert_equal(2, g:glob) if true execute('g:glob = 3') endif assert_equal(3, g:glob) res = false if g:bool_true ? true : false res = true endif assert_equal(true, res) res = false if true ? g:bool_true : false res = true endif assert_equal(true, res) res = false if true ? true : g:bool_false res = true endif assert_equal(true, res) res = false if true ? false : true res = true endif assert_equal(false, res) res = false if false ? false : true res = true endif assert_equal(true, res) res = false if false ? true : false res = true endif assert_equal(false, res) res = false if has('xyz') ? true : false res = true endif assert_equal(false, res) res = false if true && true res = true endif assert_equal(true, res) res = false if true && false res = true endif assert_equal(false, res) res = false if g:bool_true && false res = true endif assert_equal(false, res) res = false if true && g:bool_false res = true endif assert_equal(false, res) res = false if false && false res = true endif assert_equal(false, res) res = false if true || false res = true endif assert_equal(true, res) res = false if g:bool_true || false res = true endif assert_equal(true, res) res = false if true || g:bool_false res = true endif assert_equal(true, res) res = false if false || false res = true endif assert_equal(false, res) # with constant "false" expression may be invalid so long as the syntax is OK if false | eval 1 + 2 | endif if false | eval burp + 234 | endif if false | echo burp 234 'asd' | endif if false burp endif if 0 if 1 echo nothing elseif 1 echo still nothing endif endif # expression with line breaks skipped if false ('aaa' .. 'bbb' .. 'ccc' )->setline(1) endif enddef def Test_if_const_expr_fails() v9.CheckDefFailure(['if "aaa" == "bbb'], 'E114:') v9.CheckDefFailure(["if 'aaa' == 'bbb"], 'E115:') v9.CheckDefFailure(["if has('aaa'"], 'E110:') v9.CheckDefFailure(["if has('aaa') ? true false"], 'E109:') enddef def s:RunNested(i: number): number var x: number = 0 if i % 2 if 1 # comment else # comment endif x += 1 else x += 1000 endif return x enddef def Test_nested_if() assert_equal(1, RunNested(1)) assert_equal(1000, RunNested(2)) enddef def Test_execute_cmd() # missing argument is ignored execute execute # comment new setline(1, 'default') execute 'setline(1, "execute-string")' assert_equal('execute-string', getline(1)) execute "setline(1, 'execute-string')" assert_equal('execute-string', getline(1)) var cmd1 = 'setline(1,' var cmd2 = '"execute-var")' execute cmd1 cmd2 # comment assert_equal('execute-var', getline(1)) execute cmd1 cmd2 '|setline(1, "execute-var-string")' assert_equal('execute-var-string', getline(1)) var cmd_first = 'call ' var cmd_last = 'setline(1, "execute-var-var")' execute cmd_first .. cmd_last assert_equal('execute-var-var', getline(1)) bwipe! var n = true execute 'echomsg' (n ? '"true"' : '"no"') assert_match('^true$', g:Screenline(&lines)) echomsg [1, 2, 3] {a: 1, b: 2} assert_match('^\[1, 2, 3\] {''a'': 1, ''b'': 2}$', g:Screenline(&lines)) v9.CheckDefFailure(['execute xxx'], 'E1001:', 1) v9.CheckDefExecFailure(['execute "tabnext " .. 8'], 'E475:', 1) v9.CheckDefFailure(['execute "cmd"# comment'], 'E488:', 1) if has('channel') v9.CheckDefExecFailure(['execute test_null_channel()'], 'E908:', 1) endif enddef def Test_execute_cmd_vimscript() # only checks line continuation var lines =<< trim END vim9script execute 'g:someVar' .. ' = ' .. '28' assert_equal(28, g:someVar) unlet g:someVar END v9.CheckScriptSuccess(lines) enddef def Test_echo_cmd() echo 'some' # comment echon 'thing' assert_match('^something$', g:Screenline(&lines)) echo "some" # comment echon "thing" assert_match('^something$', g:Screenline(&lines)) var str1 = 'some' var str2 = 'more' echo str1 str2 assert_match('^some more$', g:Screenline(&lines)) v9.CheckDefFailure(['echo "xxx"# comment'], 'E488:') enddef def Test_echomsg_cmd() echomsg 'some' 'more' # comment assert_match('^some more$', g:Screenline(&lines)) echo 'clear' :1messages assert_match('^some more$', g:Screenline(&lines)) v9.CheckDefFailure(['echomsg "xxx"# comment'], 'E488:') enddef def Test_echomsg_cmd_vimscript() # only checks line continuation var lines =<< trim END vim9script echomsg 'here' .. ' is ' .. 'a message' assert_match('^here is a message$', g:Screenline(&lines)) END v9.CheckScriptSuccess(lines) enddef def Test_echoerr_cmd() var local = 'local' try echoerr 'something' local 'wrong' # comment catch assert_match('something local wrong', v:exception) endtry enddef def Test_echoerr_cmd_vimscript() # only checks line continuation var lines =<< trim END vim9script try echoerr 'this' .. ' is ' .. 'wrong' catch assert_match('this is wrong', v:exception) endtry END v9.CheckScriptSuccess(lines) enddef def Test_echoconsole_cmd() var local = 'local' echoconsole 'something' local # comment # output goes anywhere enddef def Test_for_outside_of_function() var lines =<< trim END vim9script new for var in range(0, 3) append(line('$'), var) endfor assert_equal(['', '0', '1', '2', '3'], getline(1, '$')) bwipe! var result = '' for i in [1, 2, 3] var loop = ' loop ' .. i result ..= loop endfor assert_equal(' loop 1 loop 2 loop 3', result) END writefile(lines, 'Xvim9for.vim') source Xvim9for.vim delete('Xvim9for.vim') enddef def Test_for_skipped_block() # test skipped blocks at outside of function var lines =<< trim END var result = [] if true for n in [1, 2] result += [n] endfor else for n in [3, 4] result += [n] endfor endif assert_equal([1, 2], result) result = [] if false for n in [1, 2] result += [n] endfor else for n in [3, 4] result += [n] endfor endif assert_equal([3, 4], result) END v9.CheckDefAndScriptSuccess(lines) # test skipped blocks at inside of function lines =<< trim END def DefTrue() var result = [] if true for n in [1, 2] result += [n] endfor else for n in [3, 4] result += [n] endfor endif assert_equal([1, 2], result) enddef DefTrue() def DefFalse() var result = [] if false for n in [1, 2] result += [n] endfor else for n in [3, 4] result += [n] endfor endif assert_equal([3, 4], result) enddef DefFalse() END v9.CheckDefAndScriptSuccess(lines) enddef def Test_for_loop() var lines =<< trim END var result = '' for cnt in range(7) if cnt == 4 break endif if cnt == 2 continue endif result ..= cnt .. '_' endfor assert_equal('0_1_3_', result) var concat = '' for str in eval('["one", "two"]') concat ..= str endfor assert_equal('onetwo', concat) var total = 0 for nr in [1, 2, 3] total += nr endfor assert_equal(6, total) total = 0 for nr in [1, 2, 3] total += nr endfor assert_equal(6, total) total = 0 for nr in [1, 2, 3] total += nr endfor assert_equal(6, total) # with type total = 0 for n: number in [1, 2, 3] total += n endfor assert_equal(6, total) var chars = '' for s: string in 'foobar' chars ..= s endfor assert_equal('foobar', chars) chars = '' for x: string in {a: 'a', b: 'b'}->values() chars ..= x endfor assert_equal('ab', chars) # unpack with type var res = '' for [n: number, s: string] in [[1, 'a'], [2, 'b']] res ..= n .. s endfor assert_equal('1a2b', res) # unpack with one var var reslist = [] for [x] in [['aaa'], ['bbb']] reslist->add(x) endfor assert_equal(['aaa', 'bbb'], reslist) # loop over string res = '' for c in 'aéc̀d' res ..= c .. '-' endfor assert_equal('a-é-c̀-d-', res) res = '' for c in '' res ..= c .. '-' endfor assert_equal('', res) res = '' for c in test_null_string() res ..= c .. '-' endfor assert_equal('', res) var foo: list<dict<any>> = [ {a: 'Cat'} ] for dd in foo dd.counter = 12 endfor assert_equal([{a: 'Cat', counter: 12}], foo) reslist = [] for _ in range(3) reslist->add('x') endfor assert_equal(['x', 'x', 'x'], reslist) END v9.CheckDefAndScriptSuccess(lines) enddef def Test_for_loop_with_closure() var lines =<< trim END var flist: list<func> for i in range(5) var inloop = i flist[i] = () => inloop endfor for i in range(5) assert_equal(4, flist[i]()) endfor END v9.CheckDefAndScriptSuccess(lines) lines =<< trim END var flist: list<func> for i in range(5) var inloop = i flist[i] = () => { return inloop } endfor for i in range(5) assert_equal(4, flist[i]()) endfor END v9.CheckDefAndScriptSuccess(lines) enddef def Test_for_loop_fails() v9.CheckDefAndScriptFailure(['for '], ['E1097:', 'E690:']) v9.CheckDefAndScriptFailure(['for x'], ['E1097:', 'E690:']) v9.CheckDefAndScriptFailure(['for x in'], ['E1097:', 'E15:']) v9.CheckDefAndScriptFailure(['for # in range(5)'], 'E690:') v9.CheckDefAndScriptFailure(['for i In range(5)'], 'E690:') v9.CheckDefAndScriptFailure(['var x = 5', 'for x in range(5)', 'endfor'], ['E1017:', 'E1041:']) v9.CheckScriptFailure(['vim9script', 'var x = 5', 'for x in range(5)', '# comment', 'endfor'], 'E1041:', 3) v9.CheckScriptFailure(['def Func(arg: any)', 'for arg in range(5)', 'enddef', 'defcompile'], 'E1006:') delfunc! g:Func v9.CheckDefFailure(['for i in xxx'], 'E1001:') v9.CheckDefFailure(['endfor'], 'E588:') v9.CheckDefFailure(['for i in range(3)', 'echo 3'], 'E170:') # wrong type detected at compile time v9.CheckDefFailure(['for i in {a: 1}', 'echo 3', 'endfor'], 'E1177: For loop on dict not supported') # wrong type detected at runtime g:adict = {a: 1} v9.CheckDefExecFailure(['for i in g:adict', 'echo 3', 'endfor'], 'E1177: For loop on dict not supported') unlet g:adict var lines =<< trim END var d: list<dict<any>> = [{a: 0}] for e in d e = {a: 0, b: ''} endfor END v9.CheckDefAndScriptFailure(lines, ['E1018:', 'E46:'], 3) lines =<< trim END for nr: number in ['foo'] endfor END v9.CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got string', 1) lines =<< trim END for n : number in [1, 2] echo n endfor END v9.CheckDefAndScriptFailure(lines, 'E1059:', 1) lines =<< trim END var d: dict<number> = {a: 1, b: 2} for [k: job, v: job] in d->items() echo k v endfor END v9.CheckDefExecAndScriptFailure(lines, ['E1013: Argument 1: type mismatch, expected job but got string', 'E1012: Type mismatch; expected job but got string'], 2) lines =<< trim END var i = 0 for i in [1, 2, 3] echo i endfor END v9.CheckDefExecAndScriptFailure(lines, ['E1017:', 'E1041:']) lines =<< trim END var l = [0] for l[0] in [1, 2, 3] echo l[0] endfor END v9.CheckDefExecAndScriptFailure(lines, ['E461:', 'E1017:']) lines =<< trim END var d = {x: 0} for d.x in [1, 2, 3] echo d.x endfor END v9.CheckDefExecAndScriptFailure(lines, ['E461:', 'E1017:']) lines =<< trim END var l: list<dict<any>> = [{a: 1, b: 'x'}] for item: dict<number> in l echo item endfor END v9.CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected dict<number> but got dict<any>') lines =<< trim END var l: list<dict<any>> = [{n: 1}] for item: dict<number> in l item->extend({s: ''}) endfor END v9.CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected dict<number> but got dict<string>') enddef def Test_for_loop_script_var() # cannot use s:var in a :def function v9.CheckDefFailure(['for s:var in range(3)', 'echo 3'], 'E1254:') # can use s:var in Vim9 script, with or without s: var lines =<< trim END vim9script var total = 0 for s:var in [1, 2, 3] total += s:var endfor assert_equal(6, total) total = 0 for var in [1, 2, 3] total += var endfor assert_equal(6, total) END enddef def Test_for_loop_unpack() var lines =<< trim END var result = [] for [v1, v2] in [[1, 2], [3, 4]] result->add(v1) result->add(v2) endfor assert_equal([1, 2, 3, 4], result) result = [] for [v1, v2; v3] in [[1, 2], [3, 4, 5, 6]] result->add(v1) result->add(v2) result->add(v3) endfor assert_equal([1, 2, [], 3, 4, [5, 6]], result) result = [] for [&ts, &sw] in [[1, 2], [3, 4]] result->add(&ts) result->add(&sw) endfor assert_equal([1, 2, 3, 4], result) var slist: list<string> for [$LOOPVAR, @r, v:errmsg] in [['a', 'b', 'c'], ['d', 'e', 'f']] slist->add($LOOPVAR) slist->add(@r) slist->add(v:errmsg) endfor assert_equal(['a', 'b', 'c', 'd', 'e', 'f'], slist) slist = [] for [g:globalvar, b:bufvar, w:winvar, t:tabvar] in [['global', 'buf', 'win', 'tab'], ['1', '2', '3', '4']] slist->add(g:globalvar) slist->add(b:bufvar) slist->add(w:winvar) slist->add(t:tabvar) endfor assert_equal(['global', 'buf', 'win', 'tab', '1', '2', '3', '4'], slist) unlet! g:globalvar b:bufvar w:winvar t:tabvar var res = [] for [_, n, _] in [[1, 2, 3], [4, 5, 6]] res->add(n) endfor assert_equal([2, 5], res) END v9.CheckDefAndScriptSuccess(lines) lines =<< trim END for [v1, v2] in [[1, 2, 3], [3, 4]] echo v1 v2 endfor END v9.CheckDefExecFailure(lines, 'E710:', 1) lines =<< trim END for [v1, v2] in [[1], [3, 4]] echo v1 v2 endfor END v9.CheckDefExecFailure(lines, 'E711:', 1) lines =<< trim END for [v1, v1] in [[1, 2], [3, 4]] echo v1 endfor END v9.CheckDefExecFailure(lines, 'E1017:', 1) enddef def Test_for_loop_with_try_continue() var lines =<< trim END var looped = 0 var cleanup = 0 for i in range(3) looped += 1 try eval [][0] catch continue finally cleanup += 1 endtry endfor assert_equal(3, looped) assert_equal(3, cleanup) END v9.CheckDefAndScriptSuccess(lines) enddef def Test_while_skipped_block() # test skipped blocks at outside of function var lines =<< trim END var result = [] var n = 0 if true n = 1 while n < 3 result += [n] n += 1 endwhile else n = 3 while n < 5 result += [n] n += 1 endwhile endif assert_equal([1, 2], result) result = [] if false n = 1 while n < 3 result += [n] n += 1 endwhile else n = 3 while n < 5 result += [n] n += 1 endwhile endif assert_equal([3, 4], result) END v9.CheckDefAndScriptSuccess(lines) # test skipped blocks at inside of function lines =<< trim END def DefTrue() var result = [] var n = 0 if true n = 1 while n < 3 result += [n] n += 1 endwhile else n = 3 while n < 5 result += [n] n += 1 endwhile endif assert_equal([1, 2], result) enddef DefTrue() def DefFalse() var result = [] var n = 0 if false n = 1 while n < 3 result += [n] n += 1 endwhile else n = 3 while n < 5 result += [n] n += 1 endwhile endif assert_equal([3, 4], result) enddef DefFalse() END v9.CheckDefAndScriptSuccess(lines) enddef def Test_while_loop() var result = '' var cnt = 0 while cnt < 555 if cnt == 3 break endif cnt += 1 if cnt == 2 continue endif result ..= cnt .. '_' endwhile assert_equal('1_3_', result) var s = '' while s == 'x' # {comment} endwhile enddef def Test_while_loop_in_script() var lines =<< trim END vim9script var result = '' var cnt = 0 while cnt < 3 var s = 'v' .. cnt result ..= s cnt += 1 endwhile assert_equal('v0v1v2', result) END v9.CheckScriptSuccess(lines) enddef def Test_while_loop_fails() v9.CheckDefFailure(['while xxx'], 'E1001:') v9.CheckDefFailure(['endwhile'], 'E588:') v9.CheckDefFailure(['continue'], 'E586:') v9.CheckDefFailure(['if true', 'continue'], 'E586:') v9.CheckDefFailure(['break'], 'E587:') v9.CheckDefFailure(['if true', 'break'], 'E587:') v9.CheckDefFailure(['while 1', 'echo 3'], 'E170:') var lines =<< trim END var s = '' while s = '' endwhile END v9.CheckDefFailure(lines, 'E488:') enddef def Test_interrupt_loop() var caught = false var x = 0 try while 1 x += 1 if x == 100 feedkeys("\<C-C>", 'Lt') endif endwhile catch caught = true assert_equal(100, x) endtry assert_true(caught, 'should have caught an exception') # consume the CTRL-C getchar(0) enddef def Test_automatic_line_continuation() var mylist = [ 'one', 'two', 'three', ] # comment assert_equal(['one', 'two', 'three'], mylist) var mydict = { ['one']: 1, ['two']: 2, ['three']: 3, } # comment assert_equal({one: 1, two: 2, three: 3}, mydict) mydict = { one: 1, # comment two: # comment 2, # comment three: 3 # comment } assert_equal({one: 1, two: 2, three: 3}, mydict) mydict = { one: 1, two: 2, three: 3 } assert_equal({one: 1, two: 2, three: 3}, mydict) assert_equal( ['one', 'two', 'three'], split('one two three') ) enddef def Test_vim9_comment() v9.CheckScriptSuccess([ 'vim9script', '# something', '#something', '#{something', ]) split Xfile v9.CheckScriptSuccess([ 'vim9script', 'edit #something', ]) v9.CheckScriptSuccess([ 'vim9script', 'edit #{something', ]) close v9.CheckScriptFailure([ 'vim9script', ':# something', ], 'E488:') v9.CheckScriptFailure([ '# something', ], 'E488:') v9.CheckScriptFailure([ ':# something', ], 'E488:') { # block start } # block end v9.CheckDefFailure([ '{# comment', ], 'E488:') v9.CheckDefFailure([ '{', '}# comment', ], 'E488:') echo "yes" # comment v9.CheckDefFailure([ 'echo "yes"# comment', ], 'E488:') v9.CheckScriptSuccess([ 'vim9script', 'echo "yes" # something', ]) v9.CheckScriptFailure([ 'vim9script', 'echo "yes"# something', ], 'E121:') v9.CheckScriptFailure([ 'vim9script', 'echo# something', ], 'E1144:') v9.CheckScriptFailure([ 'echo "yes" # something', ], 'E121:') exe "echo" # comment v9.CheckDefFailure([ 'exe "echo"# comment', ], 'E488:') v9.CheckScriptSuccess([ 'vim9script', 'exe "echo" # something', ]) v9.CheckScriptFailure([ 'vim9script', 'exe "echo"# something', ], 'E121:') v9.CheckScriptFailure([ 'vim9script', 'exe# something', ], 'E1144:') v9.CheckScriptFailure([ 'exe "echo" # something', ], 'E121:') v9.CheckDefFailure([ 'try# comment', ' echo "yes"', 'catch', 'endtry', ], 'E1144:') v9.CheckScriptFailure([ 'vim9script', 'try# comment', 'echo "yes"', ], 'E1144:') v9.CheckDefFailure([ 'try', ' throw#comment', 'catch', 'endtry', ], 'E1144:') v9.CheckDefFailure([ 'try', ' throw "yes"#comment', 'catch', 'endtry', ], 'E488:') v9.CheckDefFailure([ 'try', ' echo "yes"', 'catch# comment', 'endtry', ], 'E1144:') v9.CheckScriptFailure([ 'vim9script', 'try', ' echo "yes"', 'catch# comment', 'endtry', ], 'E1144:') v9.CheckDefFailure([ 'try', ' echo "yes"', 'catch /pat/# comment', 'endtry', ], 'E488:') v9.CheckDefFailure([ 'try', 'echo "yes"', 'catch', 'endtry# comment', ], 'E1144:') v9.CheckScriptFailure([ 'vim9script', 'try', ' echo "yes"', 'catch', 'endtry# comment', ], 'E1144:') v9.CheckScriptSuccess([ 'vim9script', 'hi # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'hi# comment', ], 'E1144:') v9.CheckScriptSuccess([ 'vim9script', 'hi Search # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'hi Search# comment', ], 'E416:') v9.CheckScriptSuccess([ 'vim9script', 'hi link This Search # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'hi link This That# comment', ], 'E413:') v9.CheckScriptSuccess([ 'vim9script', 'hi clear This # comment', 'hi clear # comment', ]) # not tested, because it doesn't give an error but a warning: # hi clear This# comment', v9.CheckScriptFailure([ 'vim9script', 'hi clear# comment', ], 'E416:') v9.CheckScriptSuccess([ 'vim9script', 'hi Group term=bold', 'match Group /todo/ # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'hi Group term=bold', 'match Group /todo/# comment', ], 'E488:') v9.CheckScriptSuccess([ 'vim9script', 'match # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'match# comment', ], 'E1144:') v9.CheckScriptSuccess([ 'vim9script', 'match none # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'match none# comment', ], 'E475:') v9.CheckScriptSuccess([ 'vim9script', 'menutrans clear # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'menutrans clear# comment text', ], 'E474:') v9.CheckScriptSuccess([ 'vim9script', 'syntax clear # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'syntax clear# comment text', ], 'E28:') v9.CheckScriptSuccess([ 'vim9script', 'syntax keyword Word some', 'syntax clear Word # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'syntax keyword Word some', 'syntax clear Word# comment text', ], 'E28:') v9.CheckScriptSuccess([ 'vim9script', 'syntax list # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'syntax list# comment text', ], 'E28:') v9.CheckScriptSuccess([ 'vim9script', 'syntax match Word /pat/ oneline # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'syntax match Word /pat/ oneline# comment', ], 'E475:') v9.CheckScriptSuccess([ 'vim9script', 'syntax keyword Word word # comm[ent', ]) v9.CheckScriptFailure([ 'vim9script', 'syntax keyword Word word# comm[ent', ], 'E789:') v9.CheckScriptSuccess([ 'vim9script', 'syntax match Word /pat/ # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'syntax match Word /pat/# comment', ], 'E402:') v9.CheckScriptSuccess([ 'vim9script', 'syntax match Word /pat/ contains=Something # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'syntax match Word /pat/ contains=Something# comment', ], 'E475:') v9.CheckScriptFailure([ 'vim9script', 'syntax match Word /pat/ contains= # comment', ], 'E406:') v9.CheckScriptFailure([ 'vim9script', 'syntax match Word /pat/ contains=# comment', ], 'E475:') v9.CheckScriptSuccess([ 'vim9script', 'syntax region Word start=/pat/ end=/pat/ # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'syntax region Word start=/pat/ end=/pat/# comment', ], 'E402:') v9.CheckScriptSuccess([ 'vim9script', 'syntax sync # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'syntax sync# comment', ], 'E404:') v9.CheckScriptSuccess([ 'vim9script', 'syntax sync ccomment # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'syntax sync ccomment# comment', ], 'E404:') v9.CheckScriptSuccess([ 'vim9script', 'syntax cluster Some contains=Word # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'syntax cluster Some contains=Word# comment', ], 'E475:') v9.CheckScriptSuccess([ 'vim9script', 'command Echo echo # comment', 'command Echo # comment', 'delcommand Echo', ]) v9.CheckScriptFailure([ 'vim9script', 'command Echo echo# comment', 'Echo', ], 'E1144:') delcommand Echo var curdir = getcwd() v9.CheckScriptSuccess([ 'command Echo cd " comment', 'Echo', 'delcommand Echo', ]) v9.CheckScriptSuccess([ 'vim9script', 'command Echo cd # comment', 'Echo', 'delcommand Echo', ]) v9.CheckScriptFailure([ 'vim9script', 'command Echo cd " comment', 'Echo', ], 'E344:') delcommand Echo chdir(curdir) v9.CheckScriptFailure([ 'vim9script', 'command Echo# comment', ], 'E182:') v9.CheckScriptFailure([ 'vim9script', 'command Echo echo', 'command Echo# comment', ], 'E182:') delcommand Echo v9.CheckScriptSuccess([ 'vim9script', 'function # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'function " comment', ], 'E129:') v9.CheckScriptFailure([ 'vim9script', 'function# comment', ], 'E1144:') v9.CheckScriptSuccess([ 'vim9script', 'import "./vim9.vim" as v9', 'function v9.CheckScriptSuccess # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'import "./vim9.vim" as v9', 'function v9.CheckScriptSuccess# comment', ], 'E1048: Item not found in script: CheckScriptSuccess#') v9.CheckScriptSuccess([ 'vim9script', 'func g:DeleteMeA()', 'endfunc', 'delfunction g:DeleteMeA # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'func g:DeleteMeB()', 'endfunc', 'delfunction g:DeleteMeB# comment', ], 'E488:') v9.CheckScriptSuccess([ 'vim9script', 'call execute("ls") # comment', ]) v9.CheckScriptFailure([ 'vim9script', 'call execute("ls")# comment', ], 'E488:') v9.CheckScriptFailure([ 'def Test() " comment', 'enddef', ], 'E488:') v9.CheckScriptFailure([ 'vim9script', 'def Test() " comment', 'enddef', ], 'E488:') v9.CheckScriptSuccess([ 'func Test() " comment', 'endfunc', 'delfunc Test', ]) v9.CheckScriptSuccess([ 'vim9script', 'func Test() " comment', 'endfunc', ]) v9.CheckScriptSuccess([ 'def Test() # comment', 'enddef', ]) v9.CheckScriptFailure([ 'func Test() # comment', 'endfunc', ], 'E488:') var lines =<< trim END vim9script syn region Text \ start='foo' #\ comment \ end='bar' syn region Text start='foo' #\ comment \ end='bar' END v9.CheckScriptSuccess(lines) lines =<< trim END vim9script syn region Text \ start='foo' "\ comment \ end='bar' END v9.CheckScriptFailure(lines, 'E399:') enddef def Test_vim9_comment_gui() CheckCanRunGui v9.CheckScriptFailure([ 'vim9script', 'gui#comment' ], 'E1144:') v9.CheckScriptFailure([ 'vim9script', 'gui -f#comment' ], 'E194:') enddef def Test_vim9_comment_not_compiled() au TabEnter *.vim g:entered = 1 au TabEnter *.x g:entered = 2 edit test.vim doautocmd TabEnter #comment assert_equal(1, g:entered) doautocmd TabEnter f.x assert_equal(2, g:entered) g:entered = 0 doautocmd TabEnter f.x #comment assert_equal(2, g:entered) assert_fails('doautocmd Syntax#comment', 'E216:') au! TabEnter unlet g:entered v9.CheckScriptSuccess([ 'vim9script', 'g:var = 123', 'b:var = 456', 'w:var = 777', 't:var = 888', 'unlet g:var w:var # something', ]) v9.CheckScriptFailure([ 'vim9script', 'let var = 123', ], 'E1126: Cannot use :let in Vim9 script') v9.CheckScriptFailure([ 'vim9script', 'var g:var = 123', ], 'E1016: Cannot declare a global variable:') v9.CheckScriptFailure([ 'vim9script', 'var b:var = 123', ], 'E1016: Cannot declare a buffer variable:') v9.CheckScriptFailure([ 'vim9script', 'var w:var = 123', ], 'E1016: Cannot declare a window variable:') v9.CheckScriptFailure([ 'vim9script', 'var t:var = 123', ], 'E1016: Cannot declare a tab variable:') v9.CheckScriptFailure([ 'vim9script', 'var v:version = 123', ], 'E1016: Cannot declare a v: variable:') v9.CheckScriptFailure([ 'vim9script', 'var $VARIABLE = "text"', ], 'E1016: Cannot declare an environment variable:') v9.CheckScriptFailure([ 'vim9script', 'g:var = 123', 'unlet g:var# comment1', ], 'E108:') v9.CheckScriptFailure([ 'let g:var = 123', 'unlet g:var # something', ], 'E488:') v9.CheckScriptSuccess([ 'vim9script', 'if 1 # comment2', ' echo "yes"', 'elseif 2 #comment', ' echo "no"', 'endif', ]) v9.CheckScriptFailure([ 'vim9script', 'if 1# comment3', ' echo "yes"', 'endif', ], 'E488:') v9.CheckScriptFailure([ 'vim9script', 'if 0 # comment4', ' echo "yes"', 'elseif 2#comment', ' echo "no"', 'endif', ], 'E488:') v9.CheckScriptSuccess([ 'vim9script', 'var v = 1 # comment5', ]) v9.CheckScriptFailure([ 'vim9script', 'var v = 1# comment6', ], 'E488:') v9.CheckScriptSuccess([ 'vim9script', 'new' 'setline(1, ["# define pat", "last"])', ':$', 'dsearch /pat/ #comment', 'bwipe!', ]) v9.CheckScriptFailure([ 'vim9script', 'new' 'setline(1, ["# define pat", "last"])', ':$', 'dsearch /pat/#comment', 'bwipe!', ], 'E488:') v9.CheckScriptFailure([ 'vim9script', 'func! SomeFunc()', ], 'E477:') enddef def Test_finish() var lines =<< trim END vim9script g:res = 'one' if v:false | finish | endif g:res = 'two' finish g:res = 'three' END writefile(lines, 'Xfinished') source Xfinished assert_equal('two', g:res) unlet g:res delete('Xfinished') enddef def Test_forward_declaration() var lines =<< trim END vim9script def GetValue(): string return theVal enddef var theVal = 'something' g:initVal = GetValue() theVal = 'else' g:laterVal = GetValue() END writefile(lines, 'Xforward') source Xforward assert_equal('something', g:initVal) assert_equal('else', g:laterVal) unlet g:initVal unlet g:laterVal delete('Xforward') enddef def Test_declare_script_var_in_func() var lines =<< trim END vim9script func Declare() let s:local = 123 endfunc Declare() END v9.CheckScriptFailure(lines, 'E1269:') enddef def Test_lock_script_var() var lines =<< trim END vim9script var local = 123 assert_equal(123, local) var error: string try local = 'asdf' catch error = v:exception endtry assert_match('E1012: Type mismatch; expected number but got string', error) lockvar local try local = 999 catch error = v:exception endtry assert_match('E741: Value is locked: local', error) END v9.CheckScriptSuccess(lines) enddef func Test_vim9script_not_global() " check that items defined in Vim9 script are script-local, not global let vim9lines =<< trim END vim9script var name = 'local' func TheFunc() echo 'local' endfunc def DefFunc() echo 'local' enddef END call writefile(vim9lines, 'Xvim9script.vim') source Xvim9script.vim try echo g:var assert_report('did not fail') catch /E121:/ " caught endtry try call TheFunc() assert_report('did not fail') catch /E117:/ " caught endtry try call DefFunc() assert_report('did not fail') catch /E117:/ " caught endtry call delete('Xvim9script.vim') endfunc def Test_vim9_copen() # this was giving an error for setting w:quickfix_title copen quit enddef def Test_script_var_in_autocmd() # using a script variable from an autocommand, defined in a :def function in a # legacy Vim script, cannot check the variable type. var lines =<< trim END let s:counter = 1 def s:Func() au! CursorHold au CursorHold * s:counter += 1 enddef call s:Func() doau CursorHold call assert_equal(2, s:counter) au! CursorHold END v9.CheckScriptSuccess(lines) enddef def Test_error_in_autoload_script() var save_rtp = &rtp var dir = getcwd() .. '/Xruntime' &rtp = dir mkdir(dir .. '/autoload', 'p') var lines =<< trim END vim9script noclear export def Autoloaded() enddef def Broken() var x: any = '' eval x != 0 enddef Broken() END writefile(lines, dir .. '/autoload/script.vim') lines =<< trim END vim9script def CallAutoloaded() script#Autoloaded() enddef function Legacy() try call s:CallAutoloaded() catch call assert_match('E1030: Using a String as a Number', v:exception) endtry endfunction Legacy() END v9.CheckScriptSuccess(lines) &rtp = save_rtp delete(dir, 'rf') enddef def Test_invalid_sid() assert_fails('func <SNR>1234_func', 'E123:') if g:RunVim([], ['wq! Xdidit'], '+"func <SNR>1_func"') assert_equal([], readfile('Xdidit')) endif delete('Xdidit') enddef def Test_restoring_cpo() writefile(['vim9script', 'set nocp'], 'Xsourced') writefile(['call writefile(["done"], "Xdone")', 'quit!'], 'Xclose') if g:RunVim([], [], '-u NONE +"set cpo+=a" -S Xsourced -S Xclose') assert_equal(['done'], readfile('Xdone')) endif delete('Xsourced') delete('Xclose') delete('Xdone') writefile(['vim9script', 'g:cpoval = &cpo'], 'XanotherScript') set cpo=aABceFsMny> edit XanotherScript so % assert_equal('aABceFsMny>', &cpo) assert_equal('aABceFs', g:cpoval) :1del setline(1, 'let g:cpoval = &cpo') w so % assert_equal('aABceFsMny>', &cpo) assert_equal('aABceFsMny>', g:cpoval) delete('XanotherScript') set cpo&vim unlet g:cpoval if has('unix') # 'cpo' is not restored in main vimrc var save_HOME = $HOME $HOME = getcwd() .. '/Xhome' mkdir('Xhome') var lines =<< trim END vim9script writefile(['before: ' .. &cpo], 'Xresult') set cpo+=M writefile(['after: ' .. &cpo], 'Xresult', 'a') END writefile(lines, 'Xhome/.vimrc') lines =<< trim END call writefile(['later: ' .. &cpo], 'Xresult', 'a') END writefile(lines, 'Xlegacy') lines =<< trim END vim9script call writefile(['vim9: ' .. &cpo], 'Xresult', 'a') qa END writefile(lines, 'Xvim9') var cmd = g:GetVimCommand() .. " -S Xlegacy -S Xvim9" cmd = substitute(cmd, '-u NONE', '', '') exe "silent !" .. cmd assert_equal([ 'before: aABceFs', 'after: aABceFsM', 'later: aABceFsM', 'vim9: aABceFs'], readfile('Xresult')) $HOME = save_HOME delete('Xhome', 'rf') delete('Xlegacy') delete('Xvim9') delete('Xresult') endif enddef " Use :function so we can use Check commands func Test_no_redraw_when_restoring_cpo() CheckScreendump CheckFeature timers call Run_test_no_redraw_when_restoring_cpo() endfunc def Run_test_no_redraw_when_restoring_cpo() var lines =<< trim END vim9script export def Func() enddef END mkdir('Xdir/autoload', 'p') writefile(lines, 'Xdir/autoload/script.vim') lines =<< trim END vim9script set cpo+=M exe 'set rtp^=' .. getcwd() .. '/Xdir' au CmdlineEnter : ++once timer_start(0, (_) => script#Func()) setline(1, 'some text') END writefile(lines, 'XTest_redraw_cpo') var buf = g:RunVimInTerminal('-S XTest_redraw_cpo', {'rows': 6}) term_sendkeys(buf, "V:") g:VerifyScreenDump(buf, 'Test_vim9_no_redraw', {}) # clean up term_sendkeys(buf, "\<Esc>u") g:StopVimInTerminal(buf) delete('XTest_redraw_cpo') delete('Xdir', 'rf') enddef func Test_reject_declaration() CheckScreendump call Run_test_reject_declaration() endfunc def Run_test_reject_declaration() var buf = g:RunVimInTerminal('', {'rows': 6}) term_sendkeys(buf, ":vim9cmd var x: number\<CR>") g:VerifyScreenDump(buf, 'Test_vim9_reject_declaration_1', {}) term_sendkeys(buf, ":\<CR>") term_sendkeys(buf, ":vim9cmd g:foo = 123 | echo g:foo\<CR>") g:VerifyScreenDump(buf, 'Test_vim9_reject_declaration_2', {}) # clean up g:StopVimInTerminal(buf) enddef def Test_minimal_command_name_length() var names = [ 'cons', 'brea', 'cat', 'catc', 'con', 'el', 'els', 'elsei', 'endfo', 'en', 'end', 'endi', 'endw', 'endt', 'endtr', 'fina', 'finall', 'th', 'thr', 'thro', 'wh', 'whi', 'whil', ] for name in names v9.CheckDefAndScriptFailure([name .. ' '], 'E1065:') endfor enddef def Test_unset_any_variable() var lines =<< trim END var name: any assert_equal(0, name) END v9.CheckDefAndScriptSuccess(lines) enddef func Test_define_func_at_command_line() CheckRunVimInTerminal " call indirectly to avoid compilation error for missing functions call Run_Test_define_func_at_command_line() endfunc def Run_Test_define_func_at_command_line() # run in a separate Vim instance to avoid the script context var lines =<< trim END func CheckAndQuit() call assert_fails('call Afunc()', 'E117: Unknown function: Bfunc') call writefile(['errors: ' .. string(v:errors)], 'Xdidcmd') endfunc END writefile([''], 'Xdidcmd') writefile(lines, 'XcallFunc') var buf = g:RunVimInTerminal('-S XcallFunc', {rows: 6}) # define Afunc() on the command line term_sendkeys(buf, ":def Afunc()\<CR>Bfunc()\<CR>enddef\<CR>") term_sendkeys(buf, ":call CheckAndQuit()\<CR>") g:WaitForAssert(() => assert_equal(['errors: []'], readfile('Xdidcmd'))) call g:StopVimInTerminal(buf) delete('XcallFunc') delete('Xdidcmd') enddef def Test_script_var_scope() var lines =<< trim END vim9script if true if true var one = 'one' echo one endif echo one endif END v9.CheckScriptFailure(lines, 'E121:', 7) lines =<< trim END vim9script if true if false var one = 'one' echo one else var one = 'one' echo one endif echo one endif END v9.CheckScriptFailure(lines, 'E121:', 10) lines =<< trim END vim9script while true var one = 'one' echo one break endwhile echo one END v9.CheckScriptFailure(lines, 'E121:', 7) lines =<< trim END vim9script for i in range(1) var one = 'one' echo one endfor echo one END v9.CheckScriptFailure(lines, 'E121:', 6) lines =<< trim END vim9script { var one = 'one' assert_equal('one', one) } assert_false(exists('one')) assert_false(exists('s:one')) END v9.CheckScriptSuccess(lines) lines =<< trim END vim9script { var one = 'one' echo one } echo one END v9.CheckScriptFailure(lines, 'E121:', 6) enddef def Test_catch_exception_in_callback() var lines =<< trim END vim9script def Callback(...l: list<any>) try var x: string var y: string # this error should be caught with CHECKLEN var sl = [''] [x, y] = sl catch g:caught = 'yes' endtry enddef popup_menu('popup', {callback: Callback}) feedkeys("\r", 'xt') END v9.CheckScriptSuccess(lines) unlet g:caught enddef def Test_no_unknown_error_after_error() if !has('unix') || !has('job') throw 'Skipped: not unix of missing +job feature' endif # FIXME: this check should not be needed if has('win32') throw 'Skipped: does not work on MS-Windows' endif var lines =<< trim END vim9script var source: list<number> def Out_cb(...l: list<any>) eval [][0] enddef def Exit_cb(...l: list<any>) sleep 1m source += l enddef var myjob = job_start('echo burp', {out_cb: Out_cb, exit_cb: Exit_cb, mode: 'raw'}) while job_status(myjob) == 'run' sleep 10m endwhile # wait for Exit_cb() to be called sleep 200m END writefile(lines, 'Xdef') assert_fails('so Xdef', ['E684:', 'E1012:']) delete('Xdef') enddef def InvokeNormal() exe "norm! :m+1\r" enddef def Test_invoke_normal_in_visual_mode() xnoremap <F3> <Cmd>call <SID>InvokeNormal()<CR> new setline(1, ['aaa', 'bbb']) feedkeys("V\<F3>", 'xt') assert_equal(['bbb', 'aaa'], getline(1, 2)) xunmap <F3> enddef def Test_white_space_after_command() var lines =<< trim END exit_cb: Func}) END v9.CheckDefAndScriptFailure(lines, 'E1144:', 1) lines =<< trim END e# END v9.CheckDefAndScriptFailure(lines, 'E1144:', 1) enddef def Test_script_var_gone_when_sourced_twice() var lines =<< trim END vim9script if exists('g:guard') finish endif g:guard = 1 var name = 'thename' def g:GetName(): string return name enddef def g:SetName(arg: string) name = arg enddef END writefile(lines, 'XscriptTwice.vim') so XscriptTwice.vim assert_equal('thename', g:GetName()) g:SetName('newname') assert_equal('newname', g:GetName()) so XscriptTwice.vim assert_fails('call g:GetName()', 'E1149:') assert_fails('call g:SetName("x")', 'E1149:') delfunc g:GetName delfunc g:SetName delete('XscriptTwice.vim') unlet g:guard enddef def Test_unsupported_commands() var lines =<< trim END ka END v9.CheckDefAndScriptFailure(lines, ['E476:', 'E492:']) lines =<< trim END :1ka END v9.CheckDefAndScriptFailure(lines, ['E476:', 'E492:']) lines =<< trim END t END v9.CheckDefAndScriptFailure(lines, 'E1100:') lines =<< trim END x END v9.CheckDefAndScriptFailure(lines, 'E1100:') lines =<< trim END xit END v9.CheckDefAndScriptFailure(lines, 'E1100:') lines =<< trim END Print END v9.CheckDefAndScriptFailure(lines, ['E476: Invalid command: Print', 'E492: Not an editor command: Print']) lines =<< trim END mode 4 END v9.CheckDefAndScriptFailure(lines, ['E476: Invalid command: mode 4', 'E492: Not an editor command: mode 4']) enddef def Test_mapping_line_number() var lines =<< trim END vim9script def g:FuncA() # Some comment FuncB(0) enddef # Some comment def FuncB( # Some comment n: number ) exe 'nno ' # Some comment .. '<F3> a' .. 'b' .. 'c' enddef END v9.CheckScriptSuccess(lines) var res = execute('verbose nmap <F3>') assert_match('No mapping found', res) g:FuncA() res = execute('verbose nmap <F3>') assert_match(' <F3> .* abc.*Last set from .*XScriptSuccess\d\+ line 11', res) nunmap <F3> delfunc g:FuncA enddef def Test_option_set() # legacy script allows for white space var lines =<< trim END set foldlevel =11 call assert_equal(11, &foldlevel) END v9.CheckScriptSuccess(lines) set foldlevel set foldlevel=12 assert_equal(12, &foldlevel) set foldlevel+=2 assert_equal(14, &foldlevel) set foldlevel-=3 assert_equal(11, &foldlevel) lines =<< trim END set foldlevel =1 END v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: =1') lines =<< trim END set foldlevel +=1 END v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: +=1') lines =<< trim END set foldlevel ^=1 END v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: ^=1') lines =<< trim END set foldlevel -=1 END v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: -=1') set foldlevel& enddef def Test_option_modifier() # legacy script allows for white space var lines =<< trim END set hlsearch & hlsearch ! call assert_equal(1, &hlsearch) END v9.CheckScriptSuccess(lines) set hlsearch set hlsearch! assert_equal(false, &hlsearch) set hlsearch set hlsearch& assert_equal(false, &hlsearch) lines =<< trim END set hlsearch & END v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: &') lines =<< trim END set hlsearch ! END v9.CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: !') set hlsearch& enddef " This must be called last, it may cause following :def functions to fail def Test_xxx_echoerr_line_number() var lines =<< trim END echoerr 'some' .. ' error' .. ' continued' END v9.CheckDefExecAndScriptFailure(lines, 'some error continued', 1) enddef func Test_debug_with_lambda() CheckRunVimInTerminal " call indirectly to avoid compilation error for missing functions call Run_Test_debug_with_lambda() endfunc def Run_Test_debug_with_lambda() var lines =<< trim END vim9script def Func() var n = 0 echo [0]->filter((_, v) => v == n) enddef breakadd func Func Func() END writefile(lines, 'XdebugFunc') var buf = g:RunVimInTerminal('-S XdebugFunc', {rows: 6, wait_for_ruler: 0}) g:WaitForAssert(() => assert_match('^>', term_getline(buf, 6))) term_sendkeys(buf, "cont\<CR>") g:WaitForAssert(() => assert_match('\[0\]', term_getline(buf, 5))) g:StopVimInTerminal(buf) delete('XdebugFunc') enddef func Test_debug_running_out_of_lines() CheckRunVimInTerminal " call indirectly to avoid compilation error for missing functions call Run_Test_debug_running_out_of_lines() endfunc def Run_Test_debug_running_out_of_lines() var lines =<< trim END vim9script def Crash() # # # # # # # if true # endif enddef breakadd func Crash Crash() END writefile(lines, 'XdebugFunc') var buf = g:RunVimInTerminal('-S XdebugFunc', {rows: 6, wait_for_ruler: 0}) g:WaitForAssert(() => assert_match('^>', term_getline(buf, 6))) term_sendkeys(buf, "next\<CR>") g:TermWait(buf) g:WaitForAssert(() => assert_match('^>', term_getline(buf, 6))) term_sendkeys(buf, "cont\<CR>") g:TermWait(buf) g:StopVimInTerminal(buf) delete('XdebugFunc') enddef def s:ProfiledWithLambda() var n = 3 echo [[1, 2], [3, 4]]->filter((_, l) => l[0] == n) enddef def s:ProfiledNested() var x = 0 def Nested(): any return x enddef Nested() enddef def ProfiledNestedProfiled() var x = 0 def Nested(): any return x enddef Nested() enddef def Test_ambigous_command_error() var lines =<< trim END vim9script command CmdA echomsg 'CmdA' command CmdB echomsg 'CmdB' Cmd END v9.CheckScriptFailure(lines, 'E464: Ambiguous use of user-defined command: Cmd', 4) lines =<< trim END vim9script def Func() Cmd enddef Func() END v9.CheckScriptFailure(lines, 'E464: Ambiguous use of user-defined command: Cmd', 1) lines =<< trim END vim9script nnoremap <F3> <ScriptCmd>Cmd<CR> feedkeys("\<F3>", 'xt') END v9.CheckScriptFailure(lines, 'E464: Ambiguous use of user-defined command: Cmd', 3) delcommand CmdA delcommand CmdB nunmap <F3> enddef " Execute this near the end, profiling doesn't stop until Vim exits. " This only tests that it works, not the profiling output. def Test_xx_profile_with_lambda() CheckFeature profile profile start Xprofile.log profile func ProfiledWithLambda ProfiledWithLambda() profile func ProfiledNested ProfiledNested() # Also profile the nested function. Use a different function, although the # contents is the same, to make sure it was not already compiled. profile func * g:ProfiledNestedProfiled() profdel func * profile pause enddef " Keep this last, it messes up highlighting. def Test_substitute_cmd() new setline(1, 'something') :substitute(some(other( assert_equal('otherthing', getline(1)) bwipe! # also when the context is Vim9 script var lines =<< trim END vim9script new setline(1, 'something') :substitute(some(other( assert_equal('otherthing', getline(1)) bwipe! END writefile(lines, 'Xvim9lines') source Xvim9lines delete('Xvim9lines') enddef " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker