Mercurial > vim
view src/testdir/test_vim9_assign.vim @ 33399:95db67c7b754 v9.0.1958
patch 9.0.1958: cannot complete option values
Commit: https://github.com/vim/vim/commit/900894b09a95398dfc75599e9f0aa2ea25723384
Author: Yee Cheng Chin <ychin.git@gmail.com>
Date: Fri Sep 29 20:42:32 2023 +0200
patch 9.0.1958: cannot complete option values
Problem: cannot complete option values
Solution: Add completion functions for several options
Add cmdline tab-completion for setting string options
Add tab-completion for setting string options on the cmdline using
`:set=` (along with `:set+=` and `:set-=`).
The existing tab completion for setting options currently only works
when nothing is typed yet, and it only fills in with the existing value,
e.g. when the user does `:set diffopt=<Tab>` it will be completed to
`set diffopt=internal,filler,closeoff` and nothing else. This isn't too
useful as a user usually wants auto-complete to suggest all the possible
values, such as 'iblank', or 'algorithm:patience'.
For set= and set+=, this adds a new optional callback function for each
option that can be invoked when doing completion. This allows for each
option to have control over how completion works. For example, in
'diffopt', it will suggest the default enumeration, but if `algorithm:`
is selected, it will further suggest different algorithm types like
'meyers' and 'patience'. When using set=, the existing option value will
be filled in as the first choice to preserve the existing behavior. When
using set+= this won't happen as it doesn't make sense.
For flag list options (e.g. 'mouse' and 'guioptions'), completion will
take into account existing typed values (and in the case of set+=, the
existing option value) to make sure it doesn't suggest duplicates.
For set-=, there is a new `ExpandSettingSubtract` function which will
handle flag list and comma-separated options smartly, by only suggesting
values that currently exist in the option.
Note that Vim has some existing code that adds special handling for
'filetype', 'syntax', and misc dir options like 'backupdir'. This change
preserves them as they already work, instead of converting to the new
callback API for each option.
closes: #13182
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Fri, 29 Sep 2023 20:45:04 +0200 |
parents | 695b50472e85 |
children | 3de472480e91 |
line wrap: on
line source
" Test Vim9 assignments source check.vim import './vim9.vim' as v9 source term_util.vim let s:appendToMe = 'xxx' let s:addToMe = 111 let s:newVar = '' let g:existing = 'yes' let g:inc_counter = 1 let $SOME_ENV_VAR = 'some' let g:alist = [7] let g:adict = #{a: 1} let g:astring = 'text' def Test_assignment_bool() var bool1: bool = true assert_equal(v:true, bool1) var bool2: bool = false assert_equal(v:false, bool2) var bool3: bool = 0 assert_equal(false, bool3) var bool4: bool = 1 assert_equal(true, bool4) var bool5: bool = 1 && true assert_equal(true, bool5) var bool6: bool = 0 && 1 assert_equal(false, bool6) var bool7: bool = 0 || 1 && true assert_equal(true, bool7) var lines =<< trim END vim9script def GetFlag(): bool var flag: bool = 1 return flag enddef var flag: bool = GetFlag() assert_equal(true, flag) flag = 0 assert_equal(false, flag) flag = 1 assert_equal(true, flag) flag = 1 || true assert_equal(true, flag) flag = 1 && false assert_equal(false, flag) var cp: bool = &cp var fen: bool = &l:fen END v9.CheckScriptSuccess(lines) v9.CheckDefAndScriptFailure(['var x: bool = 2'], 'E1012:') v9.CheckDefAndScriptFailure(['var x: bool = -1'], 'E1012:') v9.CheckDefAndScriptFailure(['var x: bool = [1]'], 'E1012:') v9.CheckDefAndScriptFailure(['var x: bool = {}'], 'E1012:') v9.CheckDefAndScriptFailure(['var x: bool = "x"'], 'E1012:') v9.CheckDefAndScriptFailure(['var x: bool = "x"', '', 'eval 0'], 'E1012:', 1) enddef def Test_syntax() var name = 234 var other: list<string> = ['asdf'] enddef def Test_assignment() v9.CheckDefFailure(['var x:string'], 'E1069:') v9.CheckDefFailure(['var x:string = "x"'], 'E1069:') v9.CheckDefFailure(['var a:string = "x"'], 'E1069:') v9.CheckDefFailure(['var lambda = () => "lambda"'], 'E704:') v9.CheckScriptFailure(['var x = "x"'], 'E1124:') # lower case name is OK for a list var lambdaLines =<< trim END var lambdaList: list<func> = [g:Test_syntax] lambdaList[0] = () => "lambda" END v9.CheckDefAndScriptSuccess(lambdaLines) var nr: number = 1234 v9.CheckDefFailure(['var nr: number = "asdf"'], 'E1012:') var a: number = 6 #comment assert_equal(6, a) if has('channel') var chan1: channel assert_equal('fail', ch_status(chan1)) var job1: job assert_equal('fail', job_status(job1)) # calling job_start() is in test_vim9_fails.vim, it causes leak reports endif var float1: float = 3.4 var Funky1: func var Funky2: func = function('len') var Party2: func = funcref('g:Test_syntax') g:newvar = 'new' #comment assert_equal('new', g:newvar) assert_equal('yes', g:existing) g:existing = 'no' assert_equal('no', g:existing) v:char = 'abc' assert_equal('abc', v:char) $ENVVAR = 'foobar' assert_equal('foobar', $ENVVAR) $ENVVAR = '' var lines =<< trim END vim9script $ENVVAR = 'barfoo' assert_equal('barfoo', $ENVVAR) $ENVVAR = '' END v9.CheckScriptSuccess(lines) appendToMe ..= 'yyy' assert_equal('xxxyyy', appendToMe) addToMe += 222 assert_equal(333, addToMe) newVar = 'new' assert_equal('new', newVar) set ts=7 var ts: number = &ts assert_equal(7, ts) &ts += 1 assert_equal(8, &ts) &ts -= 3 assert_equal(5, &ts) &ts *= 2 assert_equal(10, &ts) &ts /= 3 assert_equal(3, &ts) set ts=10 &ts %= 4 assert_equal(2, &ts) assert_fails('&ts /= 0', ['E1154:', 'E1154:']) assert_fails('&ts %= 0', ['E1154:', 'E1154:']) assert_fails('&ts /= []', ['E745:', 'E745:']) assert_fails('&ts %= []', ['E745:', 'E745:']) assert_equal(2, &ts) var f100: float = 100.0 f100 /= 5 assert_equal(20.0, f100) var f200: float = 200.0 f200 /= 5.0 assert_equal(40.0, f200) v9.CheckDefFailure(['var nr: number = 200', 'nr /= 5.0'], 'E1012:') lines =<< trim END &ts = 6 &ts += 3 assert_equal(9, &ts) &l:ts = 6 assert_equal(6, &ts) &l:ts += 2 assert_equal(8, &ts) &g:ts = 6 assert_equal(6, &g:ts) &g:ts += 2 assert_equal(8, &g:ts) &number = true assert_equal(true, &number) &number = 0 assert_equal(false, &number) &number = 1 assert_equal(true, &number) &number = false assert_equal(false, &number) END v9.CheckDefAndScriptSuccess(lines) v9.CheckDefFailure(['¬ex += 3'], 'E113:') v9.CheckDefFailure(['&ts ..= "xxx"'], 'E1019:') v9.CheckDefFailure(['&ts = [7]'], 'E1012:') v9.CheckDefExecFailure(['&ts = g:alist'], 'E1012: Type mismatch; expected number but got list<number>') v9.CheckDefFailure(['&ts = "xx"'], 'E1012:') v9.CheckDefExecFailure(['&ts = g:astring'], 'E1012: Type mismatch; expected number but got string') v9.CheckDefFailure(['&path += 3'], 'E1012:') v9.CheckDefExecFailure(['&bs = "asdf"'], 'E474:') # test freeing ISN_STOREOPT v9.CheckDefFailure(['&ts = 3', 'var asdf'], 'E1022:') &ts = 8 lines =<< trim END var save_TI = &t_TI &t_TI = '' assert_equal('', &t_TI) &t_TI = 'xxx' assert_equal('xxx', &t_TI) &t_TI = save_TI END v9.CheckDefAndScriptSuccess(lines) v9.CheckDefFailure(['&t_TI = 123'], 'E1012:') v9.CheckScriptFailure(['vim9script', '&t_TI = 123'], 'E928:') v9.CheckDefFailure(['var s:var = 123'], 'E1101:') v9.CheckDefFailure(['var s:var: number'], 'E1101:') v9.CheckDefAndScriptFailure(['var $VAR: number'], ['E1016:', 'E475:']) lines =<< trim END vim9script def SomeFunc() s:var = 123 enddef defcompile END v9.CheckScriptFailure(lines, 'E1268:') g:inc_counter += 1 assert_equal(2, g:inc_counter) var f: float f += 1 assert_equal(1.0, f) $SOME_ENV_VAR ..= 'more' assert_equal('somemore', $SOME_ENV_VAR) v9.CheckDefFailure(['$SOME_ENV_VAR += "more"'], 'E1051:') v9.CheckDefFailure(['$SOME_ENV_VAR += 123'], 'E1012:') v:errmsg = 'none' v:errmsg ..= 'again' assert_equal('noneagain', v:errmsg) v9.CheckDefFailure(['v:errmsg += "more"'], 'E1051:') v9.CheckDefFailure(['v:errmsg += 123'], 'E1012:') var text =<< trim END some text END enddef def Test_float_and_number() var lines =<< trim END var f: float f += 2 f -= 1 assert_equal(1.0, f) ++f --f assert_equal(1.0, f) END v9.CheckDefAndScriptSuccess(lines) enddef let g:someNumber = 43 def Test_assign_concat() var lines =<< trim END var s = '-' s ..= 99 s ..= true s ..= '-' s ..= v:null s ..= g:someNumber assert_equal('-99true-null43', s) END v9.CheckDefAndScriptSuccess(lines) lines =<< trim END var s = '-' s ..= [1, 2] END v9.CheckDefAndScriptFailure(lines, ['E1105: Cannot convert list to string', 'E734: Wrong variable type for .='], 2) lines =<< trim END var s = '-' s ..= {a: 2} END v9.CheckDefAndScriptFailure(lines, ['E1105: Cannot convert dict to string', 'E734: Wrong variable type for .='], 2) lines =<< trim END var ls: list<string> = [] ls[-1] ..= 'foo' END v9.CheckDefExecAndScriptFailure(lines, 'E684: List index out of range: -1', 2) enddef def Test_assign_register() var lines =<< trim END @c = 'areg' @c ..= 'add' assert_equal('aregadd', @c) @@ = 'some text' assert_equal('some text', getreg('"')) END v9.CheckDefAndScriptSuccess(lines) v9.CheckDefFailure(['@a += "more"'], 'E1051:') v9.CheckDefFailure(['@a += 123'], 'E1012:') enddef def Test_reserved_name() var more_names = ['null_job', 'null_channel'] if !has('job') more_names = [] endif for name in ['true', 'false', 'this', 'super', 'null', 'null_blob', 'null_dict', 'null_function', 'null_list', 'null_partial', 'null_string', ] + more_names v9.CheckDefExecAndScriptFailure(['var ' .. name .. ' = 0'], 'E1034:') v9.CheckDefExecAndScriptFailure(['var ' .. name .. ': bool'], 'E1034:') endfor var lines =<< trim END vim9script def Foo(super: bool) echo 'something' enddef defcompile END v9.CheckScriptFailure(lines, 'E1034:') enddef def Test_null_values() var lines =<< trim END var b: blob = null_blob var dn: dict<number> = null_dict var ds: dict<string> = null_dict var ln: list<number> = null_list var ls: list<string> = null_list var Ff: func(string): string = null_function var Fp: func(number): number = null_partial var s: string = null_string if has('job') var j: job = null_job var c: channel = null_channel endif var d: dict<func> = {a: function('tr'), b: null_function} var bl: list<blob> = [0z12, null_blob] var dnl: list<dict<number>> = [{a: 1}, null_dict] var dsl: list<dict<string>> = [{a: 'x'}, null_dict] var lnl: list<list<number>> = [[1], null_list] var lsl: list<list<string>> = [['x'], null_list] def Len(v: string): number return len(v) enddef var Ffl: list<func(string): number> = [Len, null_function] var Fpl: list<func(string): number> = [Len, null_partial] var sl: list<string> = ['x', null_string] if has('job') var jl: list<job> = [null_job] var cl: list<channel> = [null_channel] endif END v9.CheckDefAndScriptSuccess(lines) enddef def Test_type_with_extra_white() var lines =<< trim END const x : number = 3 END v9.CheckDefExecAndScriptFailure(lines, 'E1059') enddef def Test_keep_type_after_assigning_null() var lines =<< trim END var b: blob b = null_blob b = 'text' END v9.CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected blob but got string') lines =<< trim END var l: list<number> l = null_list l = ['text'] END v9.CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected list<number> but got list<string>') lines =<< trim END var d: dict<string> d = null_dict d = {a: 1, b: 2} END v9.CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected dict<string> but got dict<number>') enddef def Test_skipped_assignment() var lines =<< trim END for x in [] var i: number = 1 while false i += 1 endwhile endfor END v9.CheckDefAndScriptSuccess(lines) enddef def Test_assign_keep_type() var lines =<< trim END vim9script var l: list<number> = [123] l = [123] l->add('string') END v9.CheckScriptFailure(lines, 'E1012:', 4) enddef def Test_assign_unpack() var lines =<< trim END var v1: number var v2: number [v1, v2] = [1, 2] assert_equal(1, v1) assert_equal(2, v2) [v1, _, v2, _] = [1, 99, 2, 77] assert_equal(1, v1) assert_equal(2, v2) [v1, v2; _] = [1, 2, 3, 4, 5] assert_equal(1, v1) assert_equal(2, v2) var _x: number [_x, v2] = [6, 7] assert_equal(6, _x) assert_equal(7, v2) var reslist = [] for text in ['aaa {bbb} ccc', 'ddd {eee} fff'] var before: string var middle: string var after: string [_, before, middle, after; _] = text->matchlist('\(.\{-\}\){\(.\{-\}\)}\(.*\)') reslist->add(before)->add(middle)->add(after) endfor assert_equal(['aaa ', 'bbb', ' ccc', 'ddd ', 'eee', ' fff'], reslist) var a = 1 var b = 3 [a, b] += [2, 4] assert_equal(3, a) assert_equal(7, b) [a, b] -= [1, 2] assert_equal(2, a) assert_equal(5, b) [a, b] *= [3, 2] assert_equal(6, a) assert_equal(10, b) [a, b] /= [2, 4] assert_equal(3, a) assert_equal(2, b) [a, b] = [17, 15] [a, b] %= [5, 3] assert_equal(2, a) assert_equal(0, b) END v9.CheckDefAndScriptSuccess(lines) lines =<< trim END var v1: number var v2: number [v1, v2] = [1, 2, 3] END v9.CheckDefFailure(lines, 'E1093: Expected 2 items but got 3', 3) lines =<< trim END var v1: number var v2: number [v1, v2] = [1] END v9.CheckDefFailure(lines, 'E1093: Expected 2 items but got 1', 3) lines =<< trim END var v1: number var v2: number [v1, v2; _] = [1] END v9.CheckDefFailure(lines, 'E1093: Expected 2 items but got 1', 3) lines =<< trim END var v1: number var v2: number [v1, v2] = END v9.CheckDefFailure(lines, 'E1097:', 5) lines =<< trim END var v1: number var v2: number [v1, v2] = xxx END v9.CheckDefFailure(lines, 'E1001:', 3) lines =<< trim END var v1: number var v2: number [v1, v2] = popup_clear() END v9.CheckDefFailure(lines, 'E1031:', 3) lines =<< trim END [v1, v2] = [1, 2] END v9.CheckDefFailure(lines, 'E1089', 1) v9.CheckScriptFailure(['vim9script'] + lines, 'E1089', 2) lines =<< trim END var v1: number var v2: number [v1, v2] = '' END v9.CheckDefFailure(lines, 'E1012: Type mismatch; expected list<any> but got string', 3) lines =<< trim END g:values = [false, 0] var x: bool var y: string [x, y] = g:values END v9.CheckDefExecAndScriptFailure(lines, 'E1163: Variable 2: type mismatch, expected string but got number') lines =<< trim END var x: number var y: number var z: string [x, y, z] = [1, 2, 3] END v9.CheckDefAndScriptFailure(lines, 'E1163: Variable 3: type mismatch, expected string but got number') lines =<< trim END var x: number var y: string var z: string [x, y, z] = [1, '2', 3] END v9.CheckDefExecAndScriptFailure(lines, 'E1163: Variable 3: type mismatch, expected string but got number') enddef def Test_assign_linebreak() var nr: number nr = 123 assert_equal(123, nr) var n2: number [nr, n2] = [12, 34] assert_equal(12, nr) assert_equal(34, n2) v9.CheckDefFailure(["var x = #"], 'E1097:', 3) var lines =<< trim END var x: list<string> = ['a'] var y: list<number> = x ->copy() ->copy() END v9.CheckDefExecFailure(lines, 'E1012:', 4) lines =<< trim END var x: any x.key = 1 + 2 + 3 + 4 + 5 END v9.CheckDefExecAndScriptFailure(lines, ['E1148:', 'E1203:'], 2) enddef def Test_assign_index() # list of list var l1: list<number> l1[0] = 123 assert_equal([123], l1) var l2: list<list<number>> l2[0] = [] l2[0][0] = 123 assert_equal([[123]], l2) var l3: list<list<list<number>>> l3[0] = [] l3[0][0] = [] l3[0][0][0] = 123 assert_equal([[[123]]], l3) var lines =<< trim END var l3: list<list<number>> l3[0] = [] l3[0][0] = [] END v9.CheckDefFailure(lines, 'E1012: Type mismatch; expected number but got list<unknown>', 3) # dict of dict var d1: dict<number> d1.one = 1 assert_equal({one: 1}, d1) var d2: dict<dict<number>> d2.one = {} d2.one.two = 123 assert_equal({one: {two: 123}}, d2) var d3: dict<dict<dict<number>>> d3.one = {} d3.one.two = {} d3.one.two.three = 123 assert_equal({one: {two: {three: 123}}}, d3) # blob var bl: blob = 0z11223344 bl[0] = 0x77 assert_equal(0z77223344, bl) bl[-2] = 0x66 assert_equal(0z77226644, bl) lines =<< trim END g:val = '22' var bl = 0z11 bl[1] = g:val END v9.CheckDefExecAndScriptFailure(lines, 'E1030: Using a String as a Number: "22"') # should not read the next line when generating "a.b" var a = {} a.b = {} a.b.c = {} ->copy() lines =<< trim END var d3: dict<dict<number>> d3.one = {} d3.one.two = {} END v9.CheckDefFailure(lines, 'E1012: Type mismatch; expected number but got dict<unknown>', 3) lines =<< trim END var lines: list<string> lines['a'] = 'asdf' END v9.CheckDefFailure(lines, 'E1012:', 2) lines =<< trim END var lines: string lines[9] = 'asdf' END v9.CheckDefFailure(lines, 'E1141:', 2) # list of dict var ld: list<dict<number>> ld[0] = {} ld[0].one = 123 assert_equal([{one: 123}], ld) lines =<< trim END var ld: list<dict<number>> ld[0] = [] END v9.CheckDefFailure(lines, 'E1012: Type mismatch; expected dict<number> but got list<unknown>', 2) # dict of list var dl: dict<list<number>> dl.one = [] dl.one[0] = 123 assert_equal({one: [123]}, dl) lines =<< trim END var dl: dict<list<number>> dl.one = {} END v9.CheckDefFailure(lines, 'E1012: Type mismatch; expected list<number> but got dict<unknown>', 2) lines =<< trim END g:l = [1, 2] g:l['x'] = 3 END v9.CheckDefExecAndScriptFailure(lines, ['E39:', 'E1030:'], 2) lines =<< trim END var bl: blob = test_null_blob() bl[1] = 8 END v9.CheckDefExecAndScriptFailure(lines, ['E1184:', 'E979:'], 2) lines =<< trim END g:bl = 'not a blob' g:bl[1 : 2] = 8 END v9.CheckDefExecAndScriptFailure(lines, ['E897:', 'E689:'], 2) enddef def Test_init_in_for_loop() var lines =<< trim END var l: list<number> = [] for i in [3, 4] var n: number add(l, n) n = 123 endfor assert_equal([0, 0], l) END v9.CheckDefAndScriptSuccess(lines) lines =<< trim END var l: list<number> = [] for i in [3, 4] var n: number = 0 add(l, n) n = 123 endfor assert_equal([0, 0], l) END v9.CheckDefAndScriptSuccess(lines) lines =<< trim END var l: list<number> = [] for i in [3, 4] var n: number = 3 add(l, n) n = 123 endfor assert_equal([3, 3], l) END v9.CheckDefAndScriptSuccess(lines) enddef def Test_redir_is_not_assign() if false redir => res echo var_job redir END endif enddef def Test_extend_list() # using uninitialized list assigns empty list var lines =<< trim END var l1: list<number> var l2 = l1 assert_true(l1 is l2) l1 += [123] assert_equal([123], l1) assert_true(l1 is l2) END v9.CheckDefAndScriptSuccess(lines) lines =<< trim END var list: list<string> extend(list, ['x']) assert_equal(['x'], list) END v9.CheckDefAndScriptSuccess(lines) # appending to uninitialized list from a function works lines =<< trim END vim9script var list: list<string> def Func() list += ['a', 'b'] enddef Func() assert_equal(['a', 'b'], list) END v9.CheckScriptSuccess(lines) lines =<< trim END vim9script var list: list<string> def Func() extend(list, ['x', 'b']) enddef Func() assert_equal(['x', 'b'], list) END v9.CheckScriptSuccess(lines) # initialized to null, with type, does not default to empty list lines =<< trim END vim9script var l: list<string> = test_null_list() extend(l, ['x']) END v9.CheckScriptFailure(lines, 'E1134:', 3) # initialized to null, without type, does not default to empty list lines =<< trim END vim9script var l = null_list extend(l, ['x']) END v9.CheckScriptFailure(lines, 'E1134:', 3) # assigned null, does not default to empty list lines =<< trim END vim9script var l: list<string> l = null_list extend(l, ['x']) END v9.CheckScriptFailure(lines, 'E1134:', 4) lines =<< trim END vim9script extend(test_null_list(), ['x']) END v9.CheckScriptFailure(lines, 'E1134:', 2) # using global var has no declared type g:myList = [] g:myList->extend([1]) g:myList->extend(['x']) assert_equal([1, 'x'], g:myList) unlet g:myList # using declared list gives an error lines =<< trim END var l: list<number> g:myList = l g:myList->extend([1]) g:myList->extend(['x']) END v9.CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected list<number> but got list<string>', 4) unlet g:myList lines =<< trim END vim9script var lds = [1, 2, 3] def Func() echo lds->extend(['x']) enddef defcompile END v9.CheckScriptFailure(lines, 'E1013:') enddef def Test_extend_dict() var lines =<< trim END vim9script var d: dict<number> extend(d, {a: 1}) assert_equal({a: 1}, d) var d2: dict<number> d2['one'] = 1 assert_equal({one: 1}, d2) END v9.CheckScriptSuccess(lines) lines =<< trim END vim9script var d: dict<string> = test_null_dict() extend(d, {a: 'x'}) END v9.CheckScriptFailure(lines, 'E1133:', 3) lines =<< trim END vim9script extend(test_null_dict(), {a: 'x'}) END v9.CheckScriptFailure(lines, 'E1133:', 2) enddef def Test_single_letter_vars() # single letter variables var a: number = 123 a = 123 assert_equal(123, a) var b: number b = 123 assert_equal(123, b) var g: number g = 123 assert_equal(123, g) var s: number s = 123 assert_equal(123, s) var t: number t = 123 assert_equal(123, t) var v: number v = 123 assert_equal(123, v) var w: number w = 123 assert_equal(123, w) enddef def Test_vim9_single_char_vars() var lines =<< trim END vim9script # single character variable declarations work var a: string var b: number var l: list<any> var s: string var t: number var v: number var w: number # script-local variables can be used without s: prefix a = 'script-a' b = 111 l = [1, 2, 3] s = 'script-s' t = 222 v = 333 w = 444 assert_equal('script-a', a) assert_equal(111, b) assert_equal([1, 2, 3], l) assert_equal('script-s', s) assert_equal(222, t) assert_equal(333, v) assert_equal(444, w) END writefile(lines, 'Xsinglechar', 'D') source Xsinglechar enddef def Test_assignment_list() var list1: list<bool> = [false, true, false] var list2: list<number> = [1, 2, 3] var list3: list<string> = ['sdf', 'asdf'] var list4: list<any> = ['yes', true, 1234] var list5: list<blob> = [0z01, 0z02] var listS: list<string> = [] var listN: list<number> = [] assert_equal([1, 2, 3], list2) list2[-1] = 99 assert_equal([1, 2, 99], list2) list2[-2] = 88 assert_equal([1, 88, 99], list2) list2[-3] = 77 assert_equal([77, 88, 99], list2) list2 += [100] assert_equal([77, 88, 99, 100], list2) list3 += ['end'] assert_equal(['sdf', 'asdf', 'end'], list3) v9.CheckDefExecFailure(['var ll = [1, 2, 3]', 'll[-4] = 6'], 'E684:') v9.CheckDefExecFailure(['var ll = [1, 2, 3]', 'unlet ll[8 : 9]'], 'E684:') v9.CheckDefExecFailure(['var ll = [1, 2, 3]', 'unlet ll[1 : -9]'], 'E684:') v9.CheckDefExecFailure(['var ll = [1, 2, 3]', 'unlet ll[2 : 1]'], 'E684:') # type becomes list<any> var somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c'] # type is list<any> even though initializer is list<number> var anyList: list<any> = [0] assert_equal([0, 'x'], extend(anyList, ['x'])) var lines =<< trim END var d = {dd: test_null_list()} d.dd[0] = 0 END v9.CheckDefExecFailure(lines, 'E1147:', 2) lines =<< trim END def OneArg(x: bool) enddef def TwoArgs(x: bool, y: bool) enddef var fl: list<func(bool, bool, bool)> = [OneArg, TwoArgs] END v9.CheckDefExecAndScriptFailure(lines, 'E1012:', 5) enddef def Test_list_declaration() var [v1, v2] = [1, 2] v1 += 3 assert_equal(4, v1) v2 *= 3 assert_equal(6, v2) var lines =<< trim END var [v1, v2] = [1] END v9.CheckDefExecAndScriptFailure(lines, ['E1093: Expected 2 items but got 1', 'E688:']) lines =<< trim END var testlist = [1] var [v1, v2] = testlist END v9.CheckDefExecAndScriptFailure(lines, ['E1093: Expected 2 items but got 1', 'E688:']) lines =<< trim END var [v1, v2] = [1, 2, 3] END v9.CheckDefExecAndScriptFailure(lines, ['E1093: Expected 2 items but got 3', 'E687:']) lines =<< trim END var testlist = [1, 2, 3] var [v1, v2] = testlist END v9.CheckDefExecAndScriptFailure(lines, ['E1093: Expected 2 items but got 3', 'E687:']) var [vnr, vstr] = [123, 'text'] vnr += 3 assert_equal(126, vnr) vstr ..= 'end' assert_equal('textend', vstr) var [vnr2: number, vstr2: string] = [123, 'text'] vnr2 += 3 assert_equal(126, vnr2) vstr2 ..= 'end' assert_equal('textend', vstr2) var [vnr3: number; vlist: list<string>] = [123, 'foo', 'bar'] vnr3 += 5 assert_equal(128, vnr3) assert_equal(['foo', 'bar'], vlist) lines =<< trim END var [vnr2: number, vstr2: number] = [123, 'text'] END v9.CheckDefExecAndScriptFailure(lines, ['E1163: Variable 2: type mismatch, expected number but got string', 'E1012: Type mismatch; expected number but got string']) lines =<< trim END var testlist = [234, 'text'] var [vnr2: number, vstr2: number] = testlist END v9.CheckDefExecAndScriptFailure(lines, ['E1163: Variable 2: type mismatch, expected number but got string', 'E1012: Type mismatch; expected number but got string']) enddef def PartFuncBool(b: bool): string return 'done' enddef def Test_assignment_partial() var lines =<< trim END var Partial: func(): string = function(g:PartFuncBool, [true]) assert_equal('done', Partial()) END v9.CheckDefAndScriptSuccess(lines) lines =<< trim END vim9script def Func(b: bool) enddef var Ref: func = function(Func, [true]) assert_equal('func()', typename(Ref)) Ref() END v9.CheckScriptSuccess(lines) lines =<< trim END vim9script var nres: any var sres: any def Func(nr: number, s = '') nres = nr sres = s enddef var n: number var Ref = function(Func, [n]) Ref('x') assert_equal(0, nres) assert_equal('x', sres) END v9.CheckScriptSuccess(lines) lines =<< trim END vim9script def Func(nr: number, s = '') enddef var n: number var Ref = function(Func, [n]) Ref(0) END v9.CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected string but got number') enddef def Test_assignment_list_any_index() var l: list<number> = [1, 2] for [x, y, _] in [[0, 1, ''], [1, 3, '']] l[x] = l[x] + y endfor assert_equal([2, 5], l) enddef def Test_assignment_list_vim9script() var lines =<< trim END vim9script var v1: number var v2: number var v3: number [v1, v2, v3] = [1, 2, 3] assert_equal([1, 2, 3], [v1, v2, v3]) END v9.CheckScriptSuccess(lines) enddef def Test_assignment_dict() var dict1: dict<bool> = {one: false, two: true} var dict2: dict<number> = {one: 1, two: 2} var dict3: dict<string> = {key: 'value'} var dict4: dict<any> = {one: 1, two: '2'} var dict5: dict<blob> = {one: 0z01, two: 0z02} # check the type is OK var events: dict<string> = v:event # overwrite dict3['key'] = 'another' assert_equal(dict3, {key: 'another'}) dict3.key = 'yet another' assert_equal(dict3, {key: 'yet another'}) # member "any" can also be a dict and assigned to var anydict: dict<any> = {nest: {}, nr: 0} anydict.nest['this'] = 123 anydict.nest.that = 456 assert_equal({nest: {this: 123, that: 456}, nr: 0}, anydict) var lines =<< trim END var dd = {} dd.two = 2 assert_equal({two: 2}, dd) END v9.CheckDefAndScriptSuccess(lines) lines =<< trim END var d = {dd: {}} d.dd[0] = 2 d.dd['x'] = 3 d.dd.y = 4 assert_equal({dd: {0: 2, x: 3, y: 4}}, d) END v9.CheckDefAndScriptSuccess(lines) lines =<< trim END var key = 'foo' g:[key] = 'value' assert_equal('value', g:foo) unlet g:foo END v9.CheckDefAndScriptSuccess(lines) lines =<< trim END var dd = {one: 1} dd.one) = 2 END v9.CheckDefFailure(lines, 'E488:', 2) lines =<< trim END var dd = {one: 1} var dd.one = 2 END v9.CheckDefAndScriptFailure(lines, 'E1017:', 2) # empty key can be used var dd = {} dd[""] = 6 assert_equal({['']: 6}, dd) # type becomes dict<any> var somedict = rand() > 0 ? {a: 1, b: 2} : {a: 'a', b: 'b'} # type is dict<any> even though initializer is dict<number> var anyDict: dict<any> = {a: 0} assert_equal({a: 0, b: 'x'}, extend(anyDict, {b: 'x'})) # using global var, which has no declared type g:myDict = {} g:myDict->extend({a: 1}) g:myDict->extend({b: 'x'}) assert_equal({a: 1, b: 'x'}, g:myDict) unlet g:myDict # using list with declared type gives an error lines =<< trim END var d: dict<number> g:myDict = d g:myDict->extend({a: 1}) g:myDict->extend({b: 'x'}) END v9.CheckDefExecAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected dict<number> but got dict<string>', 4) unlet g:myDict # assignment to script-local dict lines =<< trim END vim9script var test: dict<any> = {} def FillDict(): dict<any> test['a'] = 43 return test enddef assert_equal({a: 43}, FillDict()) END v9.CheckScriptSuccess(lines) lines =<< trim END vim9script var test: dict<any> def FillDict(): dict<any> test['a'] = 43 return test enddef FillDict() assert_equal({a: 43}, test) END v9.CheckScriptSuccess(lines) # assignment to global dict lines =<< trim END vim9script g:test = {} def FillDict(): dict<any> g:test['a'] = 43 return g:test enddef assert_equal({a: 43}, FillDict()) END v9.CheckScriptSuccess(lines) # assignment to buffer dict lines =<< trim END vim9script b:test = {} def FillDict(): dict<any> b:test['a'] = 43 return b:test enddef assert_equal({a: 43}, FillDict()) END v9.CheckScriptSuccess(lines) lines =<< trim END var d = {dd: test_null_dict()} d.dd[0] = 0 END v9.CheckDefExecFailure(lines, 'E1103:', 2) lines =<< trim END var d = {dd: 'string'} d.dd[0] = 0 END v9.CheckDefExecFailure(lines, 'E1148:', 2) lines =<< trim END var n: any n.key = 5 END v9.CheckDefExecAndScriptFailure(lines, ['E1148:', 'E1203: Dot can only be used on a dictionary: n.key = 5'], 2) enddef def Test_assignment_local() # Test in a separated file in order not to the current buffer/window/tab is # changed. var script_lines: list<string> =<< trim END let b:existing = 'yes' let w:existing = 'yes' let t:existing = 'yes' def Test_assignment_local_internal() b:newvar = 'new' assert_equal('new', b:newvar) assert_equal('yes', b:existing) b:existing = 'no' assert_equal('no', b:existing) b:existing ..= 'NO' assert_equal('noNO', b:existing) w:newvar = 'new' assert_equal('new', w:newvar) assert_equal('yes', w:existing) w:existing = 'no' assert_equal('no', w:existing) w:existing ..= 'NO' assert_equal('noNO', w:existing) t:newvar = 'new' assert_equal('new', t:newvar) assert_equal('yes', t:existing) t:existing = 'no' assert_equal('no', t:existing) t:existing ..= 'NO' assert_equal('noNO', t:existing) enddef call Test_assignment_local_internal() END v9.CheckScriptSuccess(script_lines) enddef def Test_assignment_default() # Test default values. var thebool: bool assert_equal(v:false, thebool) var thenumber: number assert_equal(0, thenumber) var thefloat: float assert_equal(0.0, thefloat) var thestring: string assert_equal('', thestring) var theblob: blob assert_equal(0z, theblob) var Thefunc: func assert_equal(test_null_function(), Thefunc) var thelist: list<any> assert_equal([], thelist) var thedict: dict<any> assert_equal({}, thedict) if has('channel') var thejob: job assert_equal(test_null_job(), thejob) var thechannel: channel assert_equal(test_null_channel(), thechannel) if has('unix') && executable('cat') # check with non-null job and channel, types must match thejob = job_start("cat ", {}) thechannel = job_getchannel(thejob) job_stop(thejob, 'kill') endif endif var nr = 1234 | nr = 5678 assert_equal(5678, nr) enddef def Test_script_var_default() var lines =<< trim END vim9script var l: list<number> var li = [1, 2] var bl: blob var bli = 0z12 var d: dict<number> var di = {'a': 1, 'b': 2} def Echo() assert_equal([], l) assert_equal([1, 2], li) assert_equal(0z, bl) assert_equal(0z12, bli) assert_equal({}, d) assert_equal({'a': 1, 'b': 2}, di) enddef Echo() END v9.CheckScriptSuccess(lines) enddef let s:scriptvar = 'init' def Test_assignment_var_list() var lines =<< trim END var v1: string var v2: string var vrem: list<string> [v1] = ['aaa'] assert_equal('aaa', v1) [v1, v2] = ['one', 'two'] assert_equal('one', v1) assert_equal('two', v2) [v1, v2; vrem] = ['one', 'two'] assert_equal('one', v1) assert_equal('two', v2) assert_equal([], vrem) [v1, v2; vrem] = ['one', 'two', 'three'] assert_equal('one', v1) assert_equal('two', v2) assert_equal(['three'], vrem) [&ts, &sw] = [3, 4] assert_equal(3, &ts) assert_equal(4, &sw) set ts=8 sw=4 [@a, @z] = ['aa', 'zz'] assert_equal('aa', @a) assert_equal('zz', @z) [$SOME_VAR, $OTHER_VAR] = ['some', 'other'] assert_equal('some', $SOME_VAR) assert_equal('other', $OTHER_VAR) [g:globalvar, b:bufvar, w:winvar, t:tabvar, v:errmsg] = ['global', 'buf', 'win', 'tab', 'error'] assert_equal('global', g:globalvar) assert_equal('buf', b:bufvar) assert_equal('win', w:winvar) assert_equal('tab', t:tabvar) assert_equal('error', v:errmsg) unlet g:globalvar END v9.CheckDefAndScriptSuccess(lines) [g:globalvar, scriptvar, b:bufvar] = ['global', 'script', 'buf'] assert_equal('global', g:globalvar) assert_equal('script', scriptvar) assert_equal('buf', b:bufvar) lines =<< trim END vim9script var scriptvar = 'init' [g:globalvar, scriptvar, w:winvar] = ['global', 'script', 'win'] assert_equal('global', g:globalvar) assert_equal('script', scriptvar) assert_equal('win', w:winvar) END v9.CheckScriptSuccess(lines) enddef def Test_assignment_empty_list() var lines =<< trim END var l2: list<any> = [] var l: list<string> l = l2 END v9.CheckDefAndScriptSuccess(lines) enddef def Test_assignment_vim9script() var lines =<< trim END vim9script def Func(): list<number> return [1, 2] enddef var name1: number var name2: number [name1, name2] = Func() assert_equal(1, name1) assert_equal(2, name2) var ll = Func() assert_equal([1, 2], ll) @/ = 'text' assert_equal('text', @/) @0 = 'zero' assert_equal('zero', @0) @1 = 'one' assert_equal('one', @1) @9 = 'nine' assert_equal('nine', @9) @- = 'minus' assert_equal('minus', @-) if has('clipboard_working') @* = 'star' assert_equal('star', @*) @+ = 'plus' assert_equal('plus', @+) endif var a: number = 123 assert_equal(123, a) var s: string = 'yes' assert_equal('yes', s) var b: number = 42 assert_equal(42, b) var w: number = 43 assert_equal(43, w) var t: number = 44 assert_equal(44, t) var to_var = 0 to_var = 3 assert_equal(3, to_var) END v9.CheckScriptSuccess(lines) lines =<< trim END vim9script var n: number def Func() n = 'string' enddef defcompile END v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected number but got string') enddef def Mess(): string v:foldstart = 123 return 'xxx' enddef def Test_assignment_failure() v9.CheckDefFailure(['var name=234'], 'E1004:') v9.CheckDefFailure(['var name =234'], 'E1004:') v9.CheckDefFailure(['var name= 234'], 'E1004:') v9.CheckScriptFailure(['vim9script', 'var name=234'], 'E1004:') v9.CheckScriptFailure(['vim9script', 'var name=234'], "before and after '='") v9.CheckScriptFailure(['vim9script', 'var name =234'], 'E1004:') v9.CheckScriptFailure(['vim9script', 'var name= 234'], 'E1004:') v9.CheckScriptFailure(['vim9script', 'var name = 234', 'name+=234'], 'E1004:') v9.CheckScriptFailure(['vim9script', 'var name = 234', 'name+=234'], "before and after '+='") v9.CheckScriptFailure(['vim9script', 'var name = "x"', 'name..="y"'], 'E1004:') v9.CheckScriptFailure(['vim9script', 'var name = "x"', 'name..="y"'], "before and after '..='") v9.CheckDefFailure(['var true = 1'], 'E1034:') v9.CheckDefFailure(['var false = 1'], 'E1034:') v9.CheckDefFailure(['var null = 1'], 'E1034:') v9.CheckDefFailure(['var this = 1'], 'E1034:') v9.CheckDefFailure(['var super = 1'], 'E1034:') v9.CheckDefFailure(['[a; b; c] = g:list'], 'E1001:') v9.CheckDefFailure(['var [a; b; c] = g:list'], 'E1080:') v9.CheckDefExecFailure(['var a: number', '[a] = test_null_list()'], 'E1093:') v9.CheckDefExecFailure(['var a: number', '[a] = []'], 'E1093:') v9.CheckDefExecFailure(['var x: number', 'var y: number', '[x, y] = [1]'], 'E1093:') v9.CheckDefExecFailure(['var x: string', 'var y: string', '[x, y] = ["x"]'], 'E1093:') v9.CheckDefExecFailure(['var x: number', 'var y: number', 'var z: list<number>', '[x, y; z] = [1]'], 'E1093:') v9.CheckDefFailure(['var somevar'], "E1022:") v9.CheckDefFailure(['var &tabstop = 4'], 'E1052:') v9.CheckDefFailure(['&g:option = 5'], 'E113:') v9.CheckScriptFailure(['vim9script', 'var &tabstop = 4'], 'E1052:') v9.CheckDefFailure(['var $VAR = 5'], 'E1016: Cannot declare an environment variable:') v9.CheckScriptFailure(['vim9script', 'var $ENV = "xxx"'], 'E1016:') if has('dnd') v9.CheckDefFailure(['var @~ = 5'], 'E1066:') else v9.CheckDefFailure(['var @~ = 5'], 'E354:') v9.CheckDefFailure(['@~ = 5'], 'E354:') endif v9.CheckDefFailure(['var @a = 5'], 'E1066:') v9.CheckDefFailure(['var @/ = "x"'], 'E1066:') v9.CheckScriptFailure(['vim9script', 'var @a = "abc"'], 'E1066:') v9.CheckDefFailure(['var g:var = 5'], 'E1016: Cannot declare a global variable:') v9.CheckDefFailure(['var w:var = 5'], 'E1016: Cannot declare a window variable:') v9.CheckDefFailure(['var b:var = 5'], 'E1016: Cannot declare a buffer variable:') v9.CheckDefFailure(['var t:var = 5'], 'E1016: Cannot declare a tab variable:') v9.CheckDefFailure(['var anr = 4', 'anr ..= "text"'], 'E1019:') v9.CheckDefFailure(['var xnr += 4'], 'E1020:', 1) v9.CheckScriptFailure(['vim9script', 'var xnr += 4'], 'E1020:') v9.CheckDefFailure(["var xnr = xnr + 1"], 'E1001:', 1) v9.CheckScriptFailure(['vim9script', 'var xnr = xnr + 4'], 'E121:') v9.CheckScriptFailure(['vim9script', 'def Func()', 'var dummy = notfound', 'enddef', 'defcompile'], 'E1001:') v9.CheckDefFailure(['var name: list<string> = [123]'], 'expected list<string> but got list<number>') v9.CheckDefFailure(['var name: list<number> = ["xx"]'], 'expected list<number> but got list<string>') v9.CheckDefFailure(['var name: dict<string> = {key: 123}'], 'expected dict<string> but got dict<number>') v9.CheckDefFailure(['var name: dict<number> = {key: "xx"}'], 'expected dict<number> but got dict<string>') v9.CheckDefFailure(['var name = feedkeys("0")'], 'E1031:') v9.CheckDefFailure(['var name: number = feedkeys("0")'], 'expected number but got void') v9.CheckDefFailure(['var name: dict <number>'], 'E1068:') v9.CheckDefFailure(['var name: dict<number'], 'E1009: Missing > after type: <number') assert_fails('s/^/\=g:Mess()/n', 'E794:') v9.CheckDefFailure(['var name: dict<number'], 'E1009:') v9.CheckDefFailure(['w:foo: number = 10'], 'E1016: Cannot declare a window variable: w:foo') v9.CheckDefFailure(['t:foo: bool = true'], 'E1016: Cannot declare a tab variable: t:foo') v9.CheckDefFailure(['b:foo: string = "x"'], 'E1016: Cannot declare a buffer variable: b:foo') v9.CheckDefFailure(['g:foo: number = 123'], 'E1016: Cannot declare a global variable: g:foo') v9.CheckScriptFailure(['vim9script', 'w:foo: number = 123'], 'E1304: Cannot use type with this variable: w:foo:') v9.CheckScriptFailure(['vim9script', 't:foo: number = 123'], 'E1304: Cannot use type with this variable: t:foo:') v9.CheckScriptFailure(['vim9script', 'b:foo: number = 123'], 'E1304: Cannot use type with this variable: b:foo:') v9.CheckScriptFailure(['vim9script', 'g:foo: number = 123'], 'E1304: Cannot use type with this variable: g:foo:') v9.CheckScriptFailure(['vim9script', 'const w:FOO: number = 123'], 'E1304: Cannot use type with this variable: w:FOO:') v9.CheckScriptFailure(['vim9script', 'const t:FOO: number = 123'], 'E1304: Cannot use type with this variable: t:FOO:') v9.CheckScriptFailure(['vim9script', 'const b:FOO: number = 123'], 'E1304: Cannot use type with this variable: b:FOO:') v9.CheckScriptFailure(['vim9script', 'const g:FOO: number = 123'], 'E1304: Cannot use type with this variable: g:FOO:') enddef def Test_assign_list() var lines =<< trim END var l: list<string> = [] l[0] = 'value' assert_equal('value', l[0]) l[1] = 'asdf' assert_equal('value', l[0]) assert_equal('asdf', l[1]) assert_equal('asdf', l[-1]) assert_equal('value', l[-2]) var nrl: list<number> = [] for i in range(5) nrl[i] = i endfor assert_equal([0, 1, 2, 3, 4], nrl) var ul: list<any> ul[0] = 1 ul[1] = 2 ul[2] = 3 assert_equal([1, 2, 3], ul) END v9.CheckDefAndScriptSuccess(lines) lines =<< trim END var l = [1, 2] g:idx = 'x' l[g:idx : 1] = [0] echo l END v9.CheckDefExecAndScriptFailure(lines, ['E1012: Type mismatch; expected number but got string', 'E1030: Using a String as a Number: "x"']) lines =<< trim END var l = [1, 2] g:idx = 3 l[g:idx : 1] = [0] echo l END v9.CheckDefExecAndScriptFailure(lines, 'E684: List index out of range: 3') lines =<< trim END var l = [1, 2] g:idx = 'y' l[1 : g:idx] = [0] echo l END v9.CheckDefExecAndScriptFailure(lines, ['E1012: Type mismatch; expected number but got string', 'E1030: Using a String as a Number: "y"']) v9.CheckDefFailure(["var l: list<number> = ['', true]"], 'E1012: Type mismatch; expected list<number> but got list<any>', 1) v9.CheckDefFailure(["var l: list<list<number>> = [['', true]]"], 'E1012: Type mismatch; expected list<list<number>> but got list<list<any>>', 1) enddef def Test_assign_dict() var lines =<< trim END var d: dict<string> = {} d['key'] = 'value' assert_equal('value', d['key']) d[123] = 'qwerty' assert_equal('qwerty', d[123]) assert_equal('qwerty', d['123']) var nrd: dict<number> = {} for i in range(3) nrd[i] = i endfor assert_equal({0: 0, 1: 1, 2: 2}, nrd) d.somekey = 'someval' assert_equal({key: 'value', '123': 'qwerty', somekey: 'someval'}, d) unlet d.somekey assert_equal({key: 'value', '123': 'qwerty'}, d) END v9.CheckDefAndScriptSuccess(lines) v9.CheckDefFailure(["var d: dict<number> = {a: '', b: true}"], 'E1012: Type mismatch; expected dict<number> but got dict<any>', 1) v9.CheckDefFailure(["var d: dict<dict<number>> = {x: {a: '', b: true}}"], 'E1012: Type mismatch; expected dict<dict<number>> but got dict<dict<any>>', 1) v9.CheckDefFailure(["var d = {x: 1}", "d[1 : 2] = {y: 2}"], 'E1165: Cannot use a range with an assignment: d[1 : 2] =', 2) enddef def Test_assign_dict_unknown_type() var lines =<< trim END vim9script var mylist = [] mylist += [{one: 'one'}] def Func() var dd = mylist[0] assert_equal('one', dd.one) enddef Func() END v9.CheckScriptSuccess(lines) lines =<< trim END vim9script var mylist = [[]] mylist[0] += [{one: 'one'}] def Func() var dd = mylist[0][0] assert_equal('one', dd.one) enddef Func() END v9.CheckScriptSuccess(lines) enddef def Test_assign_dict_with_op() var lines =<< trim END var ds: dict<string> = {a: 'x'} ds['a'] ..= 'y' ds.a ..= 'z' assert_equal('xyz', ds.a) var dn: dict<number> = {a: 9} dn['a'] += 2 assert_equal(11, dn.a) dn.a += 2 assert_equal(13, dn.a) dn['a'] -= 3 assert_equal(10, dn.a) dn.a -= 2 assert_equal(8, dn.a) dn['a'] *= 2 assert_equal(16, dn.a) dn.a *= 2 assert_equal(32, dn.a) dn['a'] /= 3 assert_equal(10, dn.a) dn.a /= 2 assert_equal(5, dn.a) dn['a'] %= 3 assert_equal(2, dn.a) dn.a %= 6 assert_equal(2, dn.a) var dd: dict<dict<list<any>>> dd.a = {} dd.a.b = [0] dd.a.b += [1] assert_equal({a: {b: [0, 1]}}, dd) var dab = {a: ['b']} dab.a[0] ..= 'c' assert_equal({a: ['bc']}, dab) END v9.CheckDefAndScriptSuccess(lines) enddef def Test_assign_list_with_op() var lines =<< trim END var ls: list<string> = ['x'] ls[0] ..= 'y' assert_equal('xy', ls[0]) var ln: list<number> = [9] ln[0] += 2 assert_equal(11, ln[0]) ln[0] -= 3 assert_equal(8, ln[0]) ln[0] *= 2 assert_equal(16, ln[0]) ln[0] /= 3 assert_equal(5, ln[0]) ln[0] %= 3 assert_equal(2, ln[0]) END v9.CheckDefAndScriptSuccess(lines) enddef def Test_assign_with_op_fails() var lines =<< trim END var s = 'abc' s[1] += 'x' END v9.CheckDefAndScriptFailure(lines, ['E1141:', 'E689:'], 2) lines =<< trim END var s = 'abc' s[1] ..= 'x' END v9.CheckDefAndScriptFailure(lines, ['E1141:', 'E689:'], 2) lines =<< trim END var dd: dict<dict<list<any>>> dd.a = {} dd.a.b += [1] END v9.CheckDefExecAndScriptFailure(lines, 'E716:', 3) enddef def Test_assign_lambda() # check if assign a lambda to a variable which type is func or any. var lines =<< trim END vim9script var FuncRef = () => 123 assert_equal(123, FuncRef()) var FuncRef_Func: func = () => 123 assert_equal(123, FuncRef_Func()) var FuncRef_Any: any = () => 123 assert_equal(123, FuncRef_Any()) var FuncRef_Number: func(): number = () => 321 assert_equal(321, FuncRef_Number()) END v9.CheckScriptSuccess(lines) lines =<< trim END var Ref: func(number) Ref = (j) => !j END v9.CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected func(number) but got func(any): bool') lines =<< trim END echo filter([1, 2, 3], (_, v: string) => v + 1) END v9.CheckDefAndScriptFailure(lines, 'E1051:') enddef def Test_heredoc() # simple heredoc var lines =<< trim END var text =<< trim TEXT # comment abc TEXT assert_equal(['abc'], text) END v9.CheckDefAndScriptSuccess(lines) # empty heredoc lines =<< trim END var text =<< trim TEXT TEXT assert_equal([], text) END v9.CheckDefAndScriptSuccess(lines) # heredoc with a single empty line lines =<< trim END var text =<< trim TEXT TEXT assert_equal([''], text) END v9.CheckDefAndScriptSuccess(lines) # assign heredoc to variable with type lines =<< trim END var text: list<string> =<< trim TEXT var foo =<< trim FOO TEXT assert_equal(['var foo =<< trim FOO'], text) END v9.CheckDefAndScriptSuccess(lines) # extra whitespace before type is allowed lines =<< trim END var text: list<string> =<< trim TEXT var foo =<< trim FOO TEXT assert_equal(['var foo =<< trim FOO'], text) END v9.CheckDefAndScriptSuccess(lines) # missing whitespace before type is an error lines =<< trim END var text:list<string> =<< trim TEXT var foo =<< trim FOO TEXT assert_equal(['var foo =<< trim FOO'], text) END v9.CheckDefAndScriptFailure(lines, 'E1069:') # assign heredoc to list slice lines =<< trim END var text = [''] text[ : ] =<< trim TEXT var foo =<< trim FOO TEXT assert_equal(['var foo =<< trim FOO'], text) END v9.CheckDefAndScriptSuccess(lines) # assign heredoc to curly braces name in legacy function in Vim9 script lines =<< trim END vim9script func Func() let foo_3_bar = [''] let foo_{1 + 2}_bar[ : ] =<< trim TEXT var foo =<< trim FOO TEXT call assert_equal(['var foo =<< trim FOO'], foo_3_bar) endfunc Func() END v9.CheckScriptSuccess(lines) v9.CheckDefFailure(['var lines =<< trim END X', 'END'], 'E488:') v9.CheckDefFailure(['var lines =<< trim END " comment', 'END'], 'E488:') lines =<< trim [END] def Func() var&lines =<< trim END x x enddef defcompile [END] v9.CheckScriptFailure(lines, 'E1145: Missing heredoc end marker: END') delfunc! g:Func lines =<< trim [END] def Func() var lines =<< trim END x x x x x x x x enddef call Func() [END] v9.CheckScriptFailure(lines, 'E1145: Missing heredoc end marker: END') delfunc! g:Func lines =<< trim END var lines: number =<< trim STOP aaa bbb STOP END v9.CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got list<string>', 1) lines =<< trim END var lines=<< STOP xxx STOP END v9.CheckDefAndScriptFailure(lines, 'E1004: White space required before and after ''=<<'' at "=<< STOP"', 1) lines =<< trim END var lines =<<STOP xxx STOP END v9.CheckDefAndScriptFailure(lines, 'E1004: White space required before and after ''=<<'' at "=<<STOP"', 1) lines =<< trim END var lines=<<STOP xxx STOP END v9.CheckDefAndScriptFailure(lines, 'E1004: White space required before and after ''=<<'' at "=<<STOP"', 1) enddef def Test_var_func_call() var lines =<< trim END vim9script func GetValue() if exists('g:count') let g:count += 1 else let g:count = 1 endif return 'this' endfunc var val: string = GetValue() # env var is always a string var env = $TERM END writefile(lines, 'Xfinished', 'D') source Xfinished # GetValue() is not called during discovery phase assert_equal(1, g:count) unlet g:count enddef def Test_var_missing_type() var lines =<< trim END vim9script var name = g:unknown END v9.CheckScriptFailure(lines, 'E121:') lines =<< trim END vim9script var nr: number = 123 var name = nr END v9.CheckScriptSuccess(lines) enddef def Test_var_declaration() var lines =<< trim END vim9script var name: string g:var_uninit = name name = 'text' g:var_test = name # prefixing s: is not allowed name = 'prefixed' g:var_prefixed = name const FOO: number = 123 assert_equal(123, FOO) const FOOS = 'foos' assert_equal('foos', FOOS) final FLIST = [1] assert_equal([1], FLIST) FLIST[0] = 11 assert_equal([11], FLIST) const g:FOOS = 'gfoos' assert_equal('gfoos', g:FOOS) final g:FLIST = [2] assert_equal([2], g:FLIST) g:FLIST[0] = 22 assert_equal([22], g:FLIST) def SetGlobalConst() const g:globConst = 123 enddef SetGlobalConst() assert_equal(123, g:globConst) assert_true(islocked('g:globConst')) const w:FOOS = 'wfoos' assert_equal('wfoos', w:FOOS) final w:FLIST = [3] assert_equal([3], w:FLIST) w:FLIST[0] = 33 assert_equal([33], w:FLIST) var s:other: number other = 1234 g:other_var = other var xyz: string # comment # type is inferred var dict = {['a']: 222} def GetDictVal(key: any) g:dict_val = dict[key] enddef GetDictVal('a') final adict: dict<string> = {} def ChangeAdict() adict.foo = 'foo' enddef ChangeAdict() END v9.CheckScriptSuccess(lines) assert_equal('', g:var_uninit) assert_equal('text', g:var_test) assert_equal('prefixed', g:var_prefixed) assert_equal(1234, g:other_var) assert_equal(222, g:dict_val) unlet g:var_uninit unlet g:var_test unlet g:var_prefixed unlet g:other_var unlet g:globConst unlet g:FOOS unlet g:FLIST unlet w:FOOS unlet w:FLIST enddef def Test_create_list_after_const() const a = 1 g:ll = [] assert_equal(0, islocked('g:ll')) unlet g:ll enddef def Test_var_declaration_fails() var lines =<< trim END vim9script final var: string END v9.CheckScriptFailure(lines, 'E1125:') lines =<< trim END vim9script const g:constvar = 'string' g:constvar = 'xx' END v9.CheckScriptFailure(lines, 'E741:') unlet g:constvar lines =<< trim END vim9script var name = 'one' lockvar name def SetLocked() name = 'two' enddef SetLocked() END v9.CheckScriptFailure(lines, 'E741: Value is locked: name', 1) lines =<< trim END let s:legacy = 'one' lockvar s:legacy def SetLocked() s:legacy = 'two' enddef call SetLocked() END v9.CheckScriptFailure(lines, 'E741: Value is locked: s:legacy', 1) lines =<< trim END vim9script def SetGlobalConst() const g:globConst = 123 enddef SetGlobalConst() g:globConst = 234 END v9.CheckScriptFailure(lines, 'E741: Value is locked: g:globConst', 6) unlet g:globConst lines =<< trim END vim9script const cdict: dict<string> = {} def Change() cdict.foo = 'foo' enddef defcompile END v9.CheckScriptFailure(lines, 'E46:') lines =<< trim END vim9script final w:finalvar = [9] w:finalvar = [8] END v9.CheckScriptFailure(lines, 'E1122:') unlet w:finalvar lines =<< trim END vim9script const var: string END v9.CheckScriptFailure(lines, 'E1021:') lines =<< trim END vim9script var 9var: string END v9.CheckScriptFailure(lines, 'E488:') v9.CheckDefFailure(['var foo.bar = 2'], 'E1087:') v9.CheckDefFailure(['var foo[3] = 2'], 'E1087:') v9.CheckDefFailure(['const foo: number'], 'E1021:') lines =<< trim END va foo = 123 END v9.CheckDefAndScriptFailure(lines, 'E1065:', 1) lines =<< trim END var foo: func(number END v9.CheckDefAndScriptFailure(lines, 'E110:', 1) lines =<< trim END var foo: func(number): func( END v9.CheckDefAndScriptFailure(lines, 'E110:', 1) for type in ['num_ber', 'anys', 'ani', 'bools', 'boel', 'blobs', 'blub', 'channels', 'channol', 'dicts', 'duct', 'floats', 'floot', 'funcs', 'funk', 'jobs', 'jop', 'lists', 'last', 'numbers', 'numbar', 'strings', 'strung', 'voids', 'viod'] v9.CheckDefAndScriptFailure([$'var foo: {type}'], 'E1010:', 1) endfor enddef def Test_var_declaration_inferred() # check that type is set on the list so that extend() fails var lines =<< trim END vim9script def GetList(): list<number> var l = [1, 2, 3] return l enddef echo GetList()->extend(['x']) END v9.CheckScriptFailure(lines, 'E1013:', 6) lines =<< trim END vim9script def GetNr(): number return 5 enddef def TestOne() var some = [function('len'), GetNr] g:res = typename(some) enddef TestOne() assert_equal('list<func(): number>', g:res) def TestTwo() var some = [function('len'), GetNr] g:res = typename(some) enddef TestTwo() assert_equal('list<func(): number>', g:res) unlet g:res # FIXME: why is the type different? var first = [function('len'), GetNr] assert_equal('list<func(...): number>', typename(first)) var second = [GetNr, function('len')] assert_equal('list<func(...): number>', typename(second)) END v9.CheckScriptSuccess(lines) enddef def Test_script_local_in_legacy() # OK to define script-local later but before compiling var lines =<< trim END def SetLater() legvar = 'two' enddef let s:legvar = 'one' defcompile call SetLater() call assert_equal('two', s:legvar) END v9.CheckScriptSuccess(lines) # OK to leave out s: prefix when script-local already defined lines =<< trim END let s:legvar = 'one' def SetNoPrefix() legvar = 'two' enddef call SetNoPrefix() call assert_equal('two', s:legvar) END v9.CheckScriptSuccess(lines) # Not OK to leave out s: prefix when script-local defined after compiling lines =<< trim END def SetLaterNoPrefix() legvar = 'two' enddef defcompile let s:legvar = 'one' END v9.CheckScriptFailure(lines, 'E476:', 1) edit! Xslfile lines =<< trim END var edit: bool legacy edit END v9.CheckDefAndScriptSuccess(lines) enddef def Test_var_type_check() var lines =<< trim END vim9script var name: string name = 1234 END v9.CheckScriptFailure(lines, 'E1012:') lines =<< trim END vim9script var name:string END v9.CheckScriptFailure(lines, 'E1069:') v9.CheckDefAndScriptFailure(['var n:number = 42'], 'E1069:') lines =<< trim END vim9script var name: asdf END v9.CheckScriptFailure(lines, 'E1010:') lines =<< trim END vim9script var l: list<number> l = [] END v9.CheckScriptSuccess(lines) lines =<< trim END vim9script var d: dict<number> d = {} END v9.CheckScriptSuccess(lines) lines =<< trim END vim9script var d = {a: 1, b: [2]} def Func(b: bool) var l: list<number> = b ? d.b : [3] enddef defcompile END v9.CheckScriptSuccess(lines) enddef let g:dict_number = #{one: 1, two: 2} def Test_var_list_dict_type() var ll: list<number> ll = [1, 2, 2, 3, 3, 3]->uniq() ll->assert_equal([1, 2, 3]) var dd: dict<number> dd = g:dict_number dd->assert_equal(g:dict_number) var lines =<< trim END var ll: list<number> ll = [1, 2, 3]->map('"one"') END v9.CheckDefExecFailure(lines, 'E1012: Type mismatch; expected list<number> but got list<string>') enddef def Test_cannot_use_let() v9.CheckDefAndScriptFailure(['let a = 34'], 'E1126:', 1) enddef def Test_unlet() g:somevar = 'yes' assert_true(exists('g:somevar')) unlet g:somevar assert_false(exists('g:somevar')) unlet! g:somevar # also works for script-local variable in legacy Vim script s:somevar = 'legacy' assert_true(exists('s:somevar')) unlet s:somevar assert_false(exists('s:somevar')) unlet! s:somevar if 0 unlet g:does_not_exist endif v9.CheckDefExecFailure(['unlet v:notfound.key'], 'E1001:') v9.CheckDefExecFailure([ 'var dd = 111', 'unlet dd', ], 'E1081:', 2) # dict unlet var dd = {a: 1, b: 2, c: 3, 4: 4} unlet dd['a'] unlet dd.c unlet dd[4] assert_equal({b: 2}, dd) # null key works like empty string dd = {'': 1, x: 9} unlet dd[null_string] assert_equal({x: 9}, dd) # list unlet var ll = [1, 2, 3, 4] unlet ll[1] unlet ll[-1] assert_equal([1, 3], ll) ll = [1, 2, 3, 4] unlet ll[0 : 1] assert_equal([3, 4], ll) ll = [1, 2, 3, 4] unlet ll[2 : 8] assert_equal([1, 2], ll) ll = [1, 2, 3, 4] unlet ll[-2 : -1] assert_equal([1, 2], ll) g:nrdict = {1: 1, 2: 2} g:idx = 1 unlet g:nrdict[g:idx] assert_equal({2: 2}, g:nrdict) unlet g:nrdict unlet g:idx v9.CheckDefFailure([ 'var ll = [1, 2]', 'll[1 : 2] = 7', ], 'E1012: Type mismatch; expected list<number> but got number', 2) v9.CheckDefFailure([ 'var dd = {a: 1}', 'unlet dd["a" : "a"]', ], 'E1166:', 2) v9.CheckDefExecFailure([ 'unlet g:adict[0 : 1]', ], 'E1148:', 1) v9.CheckDefFailure([ 'var ll = [1, 2]', 'unlet ll[0:1]', ], 'E1004:', 2) v9.CheckDefFailure([ 'var ll = [1, 2]', 'unlet ll[0 :1]', ], 'E1004:', 2) v9.CheckDefFailure([ 'var ll = [1, 2]', 'unlet ll[0: 1]', ], 'E1004:', 2) v9.CheckDefExecFailure([ 'g:ll = [1, 2]', 'g:idx = "x"', 'unlet g:ll[g:idx]', ], 'E1029: Expected number but got string', 3) v9.CheckDefExecFailure([ 'g:ll = [1, 2, 3]', 'g:idx = "x"', 'unlet g:ll[g:idx : 2]', ], 'E1029: Expected number but got string', 3) v9.CheckDefExecFailure([ 'g:ll = [1, 2, 3]', 'g:idx = "x"', 'unlet g:ll[0 : g:idx]', ], 'E1029: Expected number but got string', 3) # command recognized as assignment when skipping, should not give an error v9.CheckScriptSuccess([ 'vim9script', 'for i in []', " put =''", 'endfor']) v9.CheckDefFailure([ 'var ll = [1, 2]', 'unlet ll["x" : 1]', ], 'E1012:', 2) v9.CheckDefFailure([ 'var ll = [1, 2]', 'unlet ll[0 : "x"]', ], 'E1012:', 2) # list of dict unlet var dl = [{a: 1, b: 2}, {c: 3}] unlet dl[0]['b'] assert_equal([{a: 1}, {c: 3}], dl) v9.CheckDefExecFailure([ 'var ll = test_null_list()', 'unlet ll[0]', ], 'E684:', 2) v9.CheckDefExecFailure([ 'var ll = [1]', 'unlet ll[2]', ], 'E684:', 2) v9.CheckDefExecFailure([ 'var ll = [1]', 'unlet ll[g:astring]', ], 'E1012:', 2) v9.CheckDefExecFailure([ 'var dd = test_null_dict()', 'unlet dd["a"]', ], 'E716:', 2) v9.CheckDefExecFailure([ 'var dd = {a: 1}', 'unlet dd["b"]', ], 'E716:', 2) v9.CheckDefExecFailure([ 'var dd = {a: 1}', 'unlet dd[g:alist]', ], 'E1105:', 2) v9.CheckDefExecFailure([ 'g:dd = {"a": 1, 2: 2}', 'unlet g:dd[0z11]', ], 'E1029:', 2) v9.CheckDefExecFailure([ 'g:str = "a string"', 'unlet g:str[0]', ], 'E1148: Cannot index a string', 2) # can compile unlet before variable exists g:someDict = {key: 'val'} var k = 'key' unlet g:someDict[k] assert_equal({}, g:someDict) unlet g:someDict assert_false(exists('g:someDict')) v9.CheckScriptFailure([ 'vim9script', 'var svar = 123', 'unlet svar', ], 'E1081:') v9.CheckScriptFailure([ 'vim9script', 'var svar = 123', 'unlet s:svar', ], 'E1268:') v9.CheckScriptFailure([ 'vim9script', 'var svar = 123', 'def Func()', ' unlet svar', 'enddef', 'defcompile', ], 'E1081:') v9.CheckScriptFailure([ 'vim9script', 'var svar = 123', 'func Func()', ' unlet s:svar', 'endfunc', 'Func()', ], 'E1081:') v9.CheckScriptFailure([ 'vim9script', 'var svar = 123', 'def Func()', ' unlet s:svar', 'enddef', 'defcompile', ], 'E1081:') v9.CheckScriptFailure([ 'vim9script', 'def Delcount(dict: dict<any>)', ' unlet dict.count', 'enddef', 'Delcount(v:)', ], 'E742:') v9.CheckScriptFailure([ 'vim9script', 'def DelChangedtick(dict: dict<any>)', ' unlet dict.changedtick', 'enddef', 'DelChangedtick(b:)', ], 'E795:') writefile(['vim9script', 'export var svar = 1234'], 'XunletExport.vim', 'D') var lines =<< trim END vim9script import './XunletExport.vim' as exp def UnletSvar() unlet exp.svar enddef defcompile END v9.CheckScriptFailure(lines, 'E1260:', 1) $ENVVAR = 'foobar' assert_equal('foobar', $ENVVAR) unlet $ENVVAR assert_equal('', $ENVVAR) enddef def Test_expr_error_no_assign() var lines =<< trim END vim9script var x = invalid echo x END v9.CheckScriptFailureList(lines, ['E121:', 'E121:']) lines =<< trim END vim9script var x = 1 / 0 echo x END v9.CheckScriptFailure(lines, 'E1154:') lines =<< trim END vim9script var x = 1 % 0 echo x END v9.CheckScriptFailure(lines, 'E1154:') lines =<< trim END var x: string 'string' END v9.CheckDefAndScriptFailure(lines, 'E488:') enddef def Test_assign_command_modifier() var lines =<< trim END var verbose = 0 verbose = 1 assert_equal(1, verbose) silent verbose = 2 assert_equal(2, verbose) silent verbose += 2 assert_equal(4, verbose) silent verbose -= 1 assert_equal(3, verbose) var topleft = {one: 1} sandbox topleft.one = 3 assert_equal({one: 3}, topleft) leftabove topleft[' '] = 4 assert_equal({one: 3, ' ': 4}, topleft) var x: number var y: number silent [x, y] = [1, 2] assert_equal(1, x) assert_equal(2, y) END v9.CheckDefAndScriptSuccess(lines) enddef def Test_assign_alt_buf_register() var lines =<< trim END edit 'file_b1' var b1 = bufnr() edit 'file_b2' var b2 = bufnr() assert_equal(b1, bufnr('#')) @# = b2 assert_equal(b2, bufnr('#')) END v9.CheckDefAndScriptSuccess(lines) enddef def Test_script_funcref_case() var lines =<< trim END var Len = (s: string): number => len(s) + 1 assert_equal(5, Len('asdf')) END v9.CheckDefAndScriptSuccess(lines) lines =<< trim END var len = (s: string): number => len(s) + 1 END v9.CheckDefAndScriptFailure(lines, 'E704:') lines =<< trim END vim9script var Len = (s: string): number => len(s) + 2 assert_equal(6, Len('asdf')) END v9.CheckScriptSuccess(lines) lines =<< trim END vim9script var len = (s: string): number => len(s) + 1 END v9.CheckScriptFailure(lines, 'E704:') enddef def Test_script_funcref_runtime_type_check() var lines =<< trim END vim9script def FuncWithNumberArg(n: number) enddef def Test() var Ref: func(string) = function(FuncWithNumberArg) enddef defcompile END # OK at compile time v9.CheckScriptSuccess(lines) # Type check fails at runtime v9.CheckScriptFailure(lines + ['Test()'], 'E1012: Type mismatch; expected func(string) but got func(number)') enddef def Test_inc_dec() var lines =<< trim END var nr = 7 ++nr assert_equal(8, nr) --nr assert_equal(7, nr) ++nr | ++nr assert_equal(9, nr) ++nr # comment assert_equal(10, nr) var ll = [1, 2] --ll[0] ++ll[1] assert_equal([0, 3], ll) g:count = 1 ++g:count --g:count assert_equal(1, g:count) unlet g:count END v9.CheckDefAndScriptSuccess(lines) lines =<< trim END var nr = 7 ++ nr END v9.CheckDefAndScriptFailure(lines, "E1202: No white space allowed after '++': ++ nr") enddef def Test_abort_after_error() # should abort after strpart() fails, not give another type error var lines =<< trim END vim9script var x: string x = strpart(1, 2) END writefile(lines, 'Xtestscript', 'D') var expected = 'E1174: String required for argument 1' assert_fails('so Xtestscript', [expected, expected], 3) enddef def Test_using_s_var_in_function() var lines =<< trim END vim9script var scriptlevel = 123 def SomeFunc() echo s:scriptlevel enddef SomeFunc() END v9.CheckScriptFailure(lines, 'E1268:') # OK in legacy script lines =<< trim END let s:scriptlevel = 123 def s:SomeFunc() echo s:scriptlevel enddef call s:SomeFunc() END v9.CheckScriptSuccess(lines) lines =<< trim END vim9script var scriptlevel = 123 def SomeFunc() s:scriptlevel = 456 enddef SomeFunc() END v9.CheckScriptFailure(lines, 'E1268:') # OK in legacy script lines =<< trim END let s:scriptlevel = 123 def s:SomeFunc() s:scriptlevel = 456 enddef call s:SomeFunc() call assert_equal(456, s:scriptlevel) END v9.CheckScriptSuccess(lines) enddef let g:someVar = 'X' " Test for heredoc with Vim expressions. " This messes up highlighting, keep it near the end. def Test_heredoc_expr() var lines =<< trim CODE var s = "local" var a1 = "1" var a2 = "2" var a3 = "3" var a4 = "" var code =<< trim eval END var a = {5 + 10} var b = {min([10, 6])} + {max([4, 6])} var c = "{s}" var d = x{a1}x{a2}x{a3}x{a4} END assert_equal(['var a = 15', 'var b = 6 + 6', 'var c = "local"', 'var d = x1x2x3x'], code) CODE v9.CheckDefAndScriptSuccess(lines) lines =<< trim CODE var code =<< eval trim END var s = "{$SOME_ENV_VAR}" END assert_equal(['var s = "somemore"'], code) CODE v9.CheckDefAndScriptSuccess(lines) lines =<< trim CODE var code =<< eval END var s = "{$SOME_ENV_VAR}" END assert_equal([' var s = "somemore"'], code) CODE v9.CheckDefAndScriptSuccess(lines) lines =<< trim CODE var code =<< eval trim END let a = {{abc}} let b = {g:someVar} let c = {{ END assert_equal(['let a = {abc}', 'let b = X', 'let c = {'], code) CODE v9.CheckDefAndScriptSuccess(lines) lines =<< trim LINES var text =<< eval trim END let b = { END LINES v9.CheckDefAndScriptFailure(lines, "E1279: Missing '}'") lines =<< trim LINES var text =<< eval trim END let b = {abc END LINES v9.CheckDefAndScriptFailure(lines, "E1279: Missing '}'") lines =<< trim LINES var text =<< eval trim END let b = {} END LINES v9.CheckDefAndScriptFailure(lines, 'E15: Invalid expression: "}"') enddef " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker