1" Test various aspects of the Vim9 script language.
2
3source check.vim
4source term_util.vim
5source view_util.vim
6source vim9.vim
7source shared.vim
8source screendump.vim
9
10def Test_range_only()
11  new
12  setline(1, ['blah', 'Blah'])
13  :/Blah/
14  assert_equal(2, getcurpos()[1])
15  bwipe!
16
17  # without range commands use current line
18  new
19  setline(1, ['one', 'two', 'three'])
20  :2
21  print
22  assert_equal('two', Screenline(&lines))
23  :3
24  list
25  assert_equal('three$', Screenline(&lines))
26
27  # missing command does not print the line
28  var lines =<< trim END
29    vim9script
30    :1|
31    assert_equal('three$', Screenline(&lines))
32    :|
33    assert_equal('three$', Screenline(&lines))
34  END
35  CheckScriptSuccess(lines)
36
37  bwipe!
38
39  # won't generate anything
40  if false
41    :123
42  endif
43enddef
44
45let g:alist = [7]
46let g:astring = 'text'
47let g:anumber = 123
48
49def Test_delfunction()
50  # Check function is defined in script namespace
51  CheckScriptSuccess([
52      'vim9script',
53      'func CheckMe()',
54      '  return 123',
55      'endfunc',
56      'assert_equal(123, s:CheckMe())',
57      ])
58
59  # Check function in script namespace cannot be deleted
60  CheckScriptFailure([
61      'vim9script',
62      'func DeleteMe1()',
63      'endfunc',
64      'delfunction DeleteMe1',
65      ], 'E1084:')
66  CheckScriptFailure([
67      'vim9script',
68      'func DeleteMe2()',
69      'endfunc',
70      'def DoThat()',
71      '  delfunction DeleteMe2',
72      'enddef',
73      'DoThat()',
74      ], 'E1084:')
75  CheckScriptFailure([
76      'vim9script',
77      'def DeleteMe3()',
78      'enddef',
79      'delfunction DeleteMe3',
80      ], 'E1084:')
81  CheckScriptFailure([
82      'vim9script',
83      'def DeleteMe4()',
84      'enddef',
85      'def DoThat()',
86      '  delfunction DeleteMe4',
87      'enddef',
88      'DoThat()',
89      ], 'E1084:')
90
91  # Check that global :def function can be replaced and deleted
92  var lines =<< trim END
93      vim9script
94      def g:Global(): string
95        return "yes"
96      enddef
97      assert_equal("yes", g:Global())
98      def! g:Global(): string
99        return "no"
100      enddef
101      assert_equal("no", g:Global())
102      delfunc g:Global
103      assert_false(exists('*g:Global'))
104  END
105  CheckScriptSuccess(lines)
106
107  # Check that global function can be replaced by a :def function and deleted
108  lines =<< trim END
109      vim9script
110      func g:Global()
111        return "yes"
112      endfunc
113      assert_equal("yes", g:Global())
114      def! g:Global(): string
115        return "no"
116      enddef
117      assert_equal("no", g:Global())
118      delfunc g:Global
119      assert_false(exists('*g:Global'))
120  END
121  CheckScriptSuccess(lines)
122
123  # Check that global :def function can be replaced by a function and deleted
124  lines =<< trim END
125      vim9script
126      def g:Global(): string
127        return "yes"
128      enddef
129      assert_equal("yes", g:Global())
130      func! g:Global()
131        return "no"
132      endfunc
133      assert_equal("no", g:Global())
134      delfunc g:Global
135      assert_false(exists('*g:Global'))
136  END
137  CheckScriptSuccess(lines)
138enddef
139
140def Test_wrong_type()
141  CheckDefFailure(['var name: list<nothing>'], 'E1010:')
142  CheckDefFailure(['var name: list<list<nothing>>'], 'E1010:')
143  CheckDefFailure(['var name: dict<nothing>'], 'E1010:')
144  CheckDefFailure(['var name: dict<dict<nothing>>'], 'E1010:')
145
146  CheckDefFailure(['var name: dict<number'], 'E1009:')
147  CheckDefFailure(['var name: dict<list<number>'], 'E1009:')
148
149  CheckDefFailure(['var name: ally'], 'E1010:')
150  CheckDefFailure(['var name: bram'], 'E1010:')
151  CheckDefFailure(['var name: cathy'], 'E1010:')
152  CheckDefFailure(['var name: dom'], 'E1010:')
153  CheckDefFailure(['var name: freddy'], 'E1010:')
154  CheckDefFailure(['var name: john'], 'E1010:')
155  CheckDefFailure(['var name: larry'], 'E1010:')
156  CheckDefFailure(['var name: ned'], 'E1010:')
157  CheckDefFailure(['var name: pam'], 'E1010:')
158  CheckDefFailure(['var name: sam'], 'E1010:')
159  CheckDefFailure(['var name: vim'], 'E1010:')
160
161  CheckDefFailure(['var Ref: number', 'Ref()'], 'E1085:')
162  CheckDefFailure(['var Ref: string', 'var res = Ref()'], 'E1085:')
163enddef
164
165def Test_script_wrong_type()
166  var lines =<< trim END
167      vim9script
168      var s:dict: dict<string>
169      s:dict['a'] = ['x']
170  END
171  CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got list<string>', 3)
172enddef
173
174def Test_const()
175  CheckDefFailure(['final name = 234', 'name = 99'], 'E1018:')
176  CheckDefFailure(['final one = 234', 'var one = 99'], 'E1017:')
177  CheckDefFailure(['final list = [1, 2]', 'var list = [3, 4]'], 'E1017:')
178  CheckDefFailure(['final two'], 'E1125:')
179  CheckDefFailure(['final &option'], 'E996:')
180
181  var lines =<< trim END
182    final list = [1, 2, 3]
183    list[0] = 4
184    list->assert_equal([4, 2, 3])
185    const other = [5, 6, 7]
186    other->assert_equal([5, 6, 7])
187
188    var varlist = [7, 8]
189    const constlist = [1, varlist, 3]
190    varlist[0] = 77
191    # TODO: does not work yet
192    # constlist[1][1] = 88
193    var cl = constlist[1]
194    cl[1] = 88
195    constlist->assert_equal([1, [77, 88], 3])
196
197    var vardict = {five: 5, six: 6}
198    const constdict = {one: 1, two: vardict, three: 3}
199    vardict['five'] = 55
200    # TODO: does not work yet
201    # constdict['two']['six'] = 66
202    var cd = constdict['two']
203    cd['six'] = 66
204    constdict->assert_equal({one: 1, two: {five: 55, six: 66}, three: 3})
205  END
206  CheckDefAndScriptSuccess(lines)
207enddef
208
209def Test_const_bang()
210  var lines =<< trim END
211      const var = 234
212      var = 99
213  END
214  CheckDefExecFailure(lines, 'E1018:', 2)
215  CheckScriptFailure(['vim9script'] + lines, 'E46:', 3)
216
217  lines =<< trim END
218      const ll = [2, 3, 4]
219      ll[0] = 99
220  END
221  CheckDefExecFailure(lines, 'E1119:', 2)
222  CheckScriptFailure(['vim9script'] + lines, 'E741:', 3)
223
224  lines =<< trim END
225      const ll = [2, 3, 4]
226      ll[3] = 99
227  END
228  CheckDefExecFailure(lines, 'E1118:', 2)
229  CheckScriptFailure(['vim9script'] + lines, 'E684:', 3)
230
231  lines =<< trim END
232      const dd = {one: 1, two: 2}
233      dd["one"] = 99
234  END
235  CheckDefExecFailure(lines, 'E1121:', 2)
236  CheckScriptFailure(['vim9script'] + lines, 'E741:', 3)
237
238  lines =<< trim END
239      const dd = {one: 1, two: 2}
240      dd["three"] = 99
241  END
242  CheckDefExecFailure(lines, 'E1120:')
243  CheckScriptFailure(['vim9script'] + lines, 'E741:', 3)
244enddef
245
246def Test_range_no_colon()
247  CheckDefFailure(['%s/a/b/'], 'E1050:')
248  CheckDefFailure(['+ s/a/b/'], 'E1050:')
249  CheckDefFailure(['- s/a/b/'], 'E1050:')
250  CheckDefFailure(['. s/a/b/'], 'E1050:')
251enddef
252
253
254def Test_block()
255  var outer = 1
256  {
257    var inner = 2
258    assert_equal(1, outer)
259    assert_equal(2, inner)
260  }
261  assert_equal(1, outer)
262
263  {|echo 'yes'|}
264enddef
265
266def Test_block_failure()
267  CheckDefFailure(['{', 'var inner = 1', '}', 'echo inner'], 'E1001:')
268  CheckDefFailure(['}'], 'E1025:')
269  CheckDefFailure(['{', 'echo 1'], 'E1026:')
270enddef
271
272def Test_block_local_vars()
273  var lines =<< trim END
274      vim9script
275      v:testing = 1
276      if true
277        var text = ['hello']
278        def SayHello(): list<string>
279          return text
280        enddef
281        def SetText(v: string)
282          text = [v]
283        enddef
284      endif
285
286      if true
287        var text = ['again']
288        def SayAgain(): list<string>
289          return text
290        enddef
291      endif
292
293      # test that the "text" variables are not cleaned up
294      test_garbagecollect_now()
295
296      defcompile
297
298      assert_equal(['hello'], SayHello())
299      assert_equal(['again'], SayAgain())
300
301      SetText('foobar')
302      assert_equal(['foobar'], SayHello())
303
304      call writefile(['ok'], 'Xdidit')
305      qall!
306  END
307
308  # need to execute this with a separate Vim instance to avoid the current
309  # context gets garbage collected.
310  writefile(lines, 'Xscript')
311  RunVim([], [], '-S Xscript')
312  assert_equal(['ok'], readfile('Xdidit'))
313
314  delete('Xscript')
315  delete('Xdidit')
316enddef
317
318def Test_block_local_vars_with_func()
319  var lines =<< trim END
320      vim9script
321      if true
322        var foo = 'foo'
323        if true
324          var bar = 'bar'
325          def Func(): list<string>
326            return [foo, bar]
327          enddef
328        endif
329      endif
330      # function is compiled here, after blocks have finished, can still access
331      # "foo" and "bar"
332      assert_equal(['foo', 'bar'], Func())
333  END
334  CheckScriptSuccess(lines)
335enddef
336
337func g:NoSuchFunc()
338  echo 'none'
339endfunc
340
341def Test_try_catch_throw()
342  var l = []
343  try # comment
344    add(l, '1')
345    throw 'wrong'
346    add(l, '2')
347  catch # comment
348    add(l, v:exception)
349  finally # comment
350    add(l, '3')
351  endtry # comment
352  assert_equal(['1', 'wrong', '3'], l)
353
354  l = []
355  try
356    try
357      add(l, '1')
358      throw 'wrong'
359      add(l, '2')
360    catch /right/
361      add(l, v:exception)
362    endtry
363  catch /wrong/
364    add(l, 'caught')
365  fina
366    add(l, 'finally')
367  endtry
368  assert_equal(['1', 'caught', 'finally'], l)
369
370  var n: number
371  try
372    n = l[3]
373  catch /E684:/
374    n = 99
375  endtry
376  assert_equal(99, n)
377
378  var done = 'no'
379  if 0
380    try | catch | endtry
381  else
382    done = 'yes'
383  endif
384  assert_equal('yes', done)
385
386  done = 'no'
387  if 1
388    done = 'yes'
389  else
390    try | catch | endtry
391    done = 'never'
392  endif
393  assert_equal('yes', done)
394
395  if 1
396  else
397    try | catch /pat/ | endtry
398    try | catch /pat/
399    endtry
400    try
401    catch /pat/ | endtry
402    try
403    catch /pat/
404    endtry
405  endif
406
407  try
408    # string slice returns a string, not a number
409    n = g:astring[3]
410  catch /E1012:/
411    n = 77
412  endtry
413  assert_equal(77, n)
414
415  try
416    n = l[g:astring]
417  catch /E1012:/
418    n = 88
419  endtry
420  assert_equal(88, n)
421
422  try
423    n = s:does_not_exist
424  catch /E121:/
425    n = 111
426  endtry
427  assert_equal(111, n)
428
429  try
430    n = g:does_not_exist
431  catch /E121:/
432    n = 121
433  endtry
434  assert_equal(121, n)
435
436  var d = {one: 1}
437  try
438    n = d[g:astring]
439  catch /E716:/
440    n = 222
441  endtry
442  assert_equal(222, n)
443
444  try
445    n = -g:astring
446  catch /E39:/
447    n = 233
448  endtry
449  assert_equal(233, n)
450
451  try
452    n = +g:astring
453  catch /E1030:/
454    n = 244
455  endtry
456  assert_equal(244, n)
457
458  try
459    n = +g:alist
460  catch /E745:/
461    n = 255
462  endtry
463  assert_equal(255, n)
464
465  var nd: dict<any>
466  try
467    nd = {[g:alist]: 1}
468  catch /E1105:/
469    n = 266
470  endtry
471  assert_equal(266, n)
472
473  try
474    [n] = [1, 2, 3]
475  catch /E1093:/
476    n = 277
477  endtry
478  assert_equal(277, n)
479
480  try
481    &ts = g:astring
482  catch /E1012:/
483    n = 288
484  endtry
485  assert_equal(288, n)
486
487  try
488    &backspace = 'asdf'
489  catch /E474:/
490    n = 299
491  endtry
492  assert_equal(299, n)
493
494  l = [1]
495  try
496    l[3] = 3
497  catch /E684:/
498    n = 300
499  endtry
500  assert_equal(300, n)
501
502  try
503    unlet g:does_not_exist
504  catch /E108:/
505    n = 322
506  endtry
507  assert_equal(322, n)
508
509  try
510    d = {text: 1, [g:astring]: 2}
511  catch /E721:/
512    n = 333
513  endtry
514  assert_equal(333, n)
515
516  try
517    l = DeletedFunc()
518  catch /E933:/
519    n = 344
520  endtry
521  assert_equal(344, n)
522
523  try
524    echo len(v:true)
525  catch /E701:/
526    n = 355
527  endtry
528  assert_equal(355, n)
529
530  var P = function('g:NoSuchFunc')
531  delfunc g:NoSuchFunc
532  try
533    echo P()
534  catch /E117:/
535    n = 366
536  endtry
537  assert_equal(366, n)
538
539  try
540    echo g:NoSuchFunc()
541  catch /E117:/
542    n = 377
543  endtry
544  assert_equal(377, n)
545
546  try
547    echo g:alist + 4
548  catch /E745:/
549    n = 388
550  endtry
551  assert_equal(388, n)
552
553  try
554    echo 4 + g:alist
555  catch /E745:/
556    n = 399
557  endtry
558  assert_equal(399, n)
559
560  try
561    echo g:alist.member
562  catch /E715:/
563    n = 400
564  endtry
565  assert_equal(400, n)
566
567  try
568    echo d.member
569  catch /E716:/
570    n = 411
571  endtry
572  assert_equal(411, n)
573
574  var counter = 0
575  for i in range(4)
576    try
577      eval [][0]
578    catch
579    endtry
580    counter += 1
581  endfor
582  assert_equal(4, counter)
583
584  # return in finally after empty catch
585  def ReturnInFinally(): number
586    try
587    finally
588      return 4
589    endtry
590    return 2
591  enddef
592  assert_equal(4, ReturnInFinally())
593
594  var lines =<< trim END
595      vim9script
596      try
597        acos('0.5')
598          ->setline(1)
599      catch
600        g:caught = v:exception
601      endtry
602  END
603  CheckScriptSuccess(lines)
604  assert_match('E808: Number or Float required', g:caught)
605  unlet g:caught
606
607  # missing catch and/or finally
608  lines =<< trim END
609      vim9script
610      try
611        echo 'something'
612      endtry
613  END
614  CheckScriptFailure(lines, 'E1032:')
615enddef
616
617def Test_try_in_catch()
618  var lines =<< trim END
619      vim9script
620      var seq = []
621      def DoIt()
622        try
623          seq->add('throw 1')
624          eval [][0]
625          seq->add('notreached')
626        catch
627          seq->add('catch')
628          try
629            seq->add('throw 2')
630            eval [][0]
631            seq->add('notreached')
632          catch /nothing/
633            seq->add('notreached')
634          endtry
635          seq->add('done')
636        endtry
637      enddef
638      DoIt()
639      assert_equal(['throw 1', 'catch', 'throw 2', 'done'], seq)
640  END
641enddef
642
643def Test_error_in_catch()
644  var lines =<< trim END
645      try
646        eval [][0]
647      catch /E684:/
648        eval [][0]
649      endtry
650  END
651  CheckDefExecFailure(lines, 'E684:', 4)
652enddef
653
654" :while at the very start of a function that :continue jumps to
655def TryContinueFunc()
656 while g:Count < 2
657   g:sequence ..= 't'
658    try
659      echoerr 'Test'
660    catch
661      g:Count += 1
662      g:sequence ..= 'c'
663      continue
664    endtry
665    g:sequence ..= 'e'
666    g:Count += 1
667  endwhile
668enddef
669
670def Test_continue_in_try_in_while()
671  g:Count = 0
672  g:sequence = ''
673  TryContinueFunc()
674  assert_equal('tctc', g:sequence)
675  unlet g:Count
676  unlet g:sequence
677enddef
678
679def Test_nocatch_return_in_try()
680  # return in try block returns normally
681  def ReturnInTry(): string
682    try
683      return '"some message"'
684    catch
685    endtry
686    return 'not reached'
687  enddef
688  exe 'echoerr ' .. ReturnInTry()
689enddef
690
691def Test_cnext_works_in_catch()
692  var lines =<< trim END
693      vim9script
694      au BufEnter * eval 1 + 2
695      writefile(['text'], 'Xfile1')
696      writefile(['text'], 'Xfile2')
697      var items = [
698          {lnum: 1, filename: 'Xfile1', valid: true},
699          {lnum: 1, filename: 'Xfile2', valid: true}
700        ]
701      setqflist([], ' ', {items: items})
702      cwindow
703
704      def CnextOrCfirst()
705        # if cnext fails, cfirst is used
706        try
707          cnext
708        catch
709          cfirst
710        endtry
711      enddef
712
713      CnextOrCfirst()
714      CnextOrCfirst()
715      writefile([getqflist({idx: 0}).idx], 'Xresult')
716      qall
717  END
718  writefile(lines, 'XCatchCnext')
719  RunVim([], [], '--clean -S XCatchCnext')
720  assert_equal(['1'], readfile('Xresult'))
721
722  delete('Xfile1')
723  delete('Xfile2')
724  delete('XCatchCnext')
725  delete('Xresult')
726enddef
727
728def Test_throw_skipped()
729  if 0
730    throw dontgethere
731  endif
732enddef
733
734def Test_nocatch_throw_silenced()
735  var lines =<< trim END
736    vim9script
737    def Func()
738      throw 'error'
739    enddef
740    silent! Func()
741  END
742  writefile(lines, 'XthrowSilenced')
743  source XthrowSilenced
744  delete('XthrowSilenced')
745enddef
746
747def DeletedFunc(): list<any>
748  return ['delete me']
749enddef
750defcompile
751delfunc DeletedFunc
752
753def ThrowFromDef()
754  throw "getout" # comment
755enddef
756
757func CatchInFunc()
758  try
759    call ThrowFromDef()
760  catch
761    let g:thrown_func = v:exception
762  endtry
763endfunc
764
765def CatchInDef()
766  try
767    ThrowFromDef()
768  catch
769    g:thrown_def = v:exception
770  endtry
771enddef
772
773def ReturnFinally(): string
774  try
775    return 'intry'
776  finall
777    g:in_finally = 'finally'
778  endtry
779  return 'end'
780enddef
781
782def Test_try_catch_nested()
783  CatchInFunc()
784  assert_equal('getout', g:thrown_func)
785
786  CatchInDef()
787  assert_equal('getout', g:thrown_def)
788
789  assert_equal('intry', ReturnFinally())
790  assert_equal('finally', g:in_finally)
791
792  var l = []
793  try
794    l->add('1')
795    throw 'bad'
796    l->add('x')
797  catch /bad/
798    l->add('2')
799    try
800      l->add('3')
801      throw 'one'
802      l->add('x')
803    catch /one/
804      l->add('4')
805      try
806        l->add('5')
807        throw 'more'
808        l->add('x')
809      catch /more/
810        l->add('6')
811      endtry
812    endtry
813  endtry
814  assert_equal(['1', '2', '3', '4', '5', '6'], l)
815
816  l = []
817  try
818    try
819      l->add('1')
820      throw 'foo'
821      l->add('x')
822    catch
823      l->add('2')
824      throw 'bar'
825      l->add('x')
826    finally
827      l->add('3')
828    endtry
829    l->add('x')
830  catch /bar/
831    l->add('4')
832  endtry
833  assert_equal(['1', '2', '3', '4'], l)
834enddef
835
836def TryOne(): number
837  try
838    return 0
839  catch
840  endtry
841  return 0
842enddef
843
844def TryTwo(n: number): string
845  try
846    var x = {}
847  catch
848  endtry
849  return 'text'
850enddef
851
852def Test_try_catch_twice()
853  assert_equal('text', TryOne()->TryTwo())
854enddef
855
856def Test_try_catch_match()
857  var seq = 'a'
858  try
859    throw 'something'
860  catch /nothing/
861    seq ..= 'x'
862  catch /some/
863    seq ..= 'b'
864  catch /asdf/
865    seq ..= 'x'
866  catch ?a\?sdf?
867    seq ..= 'y'
868  finally
869    seq ..= 'c'
870  endtry
871  assert_equal('abc', seq)
872enddef
873
874def Test_try_catch_fails()
875  CheckDefFailure(['catch'], 'E603:')
876  CheckDefFailure(['try', 'echo 0', 'catch', 'catch'], 'E1033:')
877  CheckDefFailure(['try', 'echo 0', 'catch /pat'], 'E1067:')
878  CheckDefFailure(['finally'], 'E606:')
879  CheckDefFailure(['try', 'echo 0', 'finally', 'echo 1', 'finally'], 'E607:')
880  CheckDefFailure(['endtry'], 'E602:')
881  CheckDefFailure(['while 1', 'endtry'], 'E170:')
882  CheckDefFailure(['for i in range(5)', 'endtry'], 'E170:')
883  CheckDefFailure(['if 1', 'endtry'], 'E171:')
884  CheckDefFailure(['try', 'echo 1', 'endtry'], 'E1032:')
885
886  CheckDefFailure(['throw'], 'E1143:')
887  CheckDefFailure(['throw xxx'], 'E1001:')
888enddef
889
890def Try_catch_skipped()
891  var l = []
892  try
893  finally
894  endtry
895
896  if 1
897  else
898    try
899    endtry
900  endif
901enddef
902
903" The skipped try/endtry was updating the wrong instruction.
904def Test_try_catch_skipped()
905  var instr = execute('disassemble Try_catch_skipped')
906  assert_match("NEWLIST size 0\n", instr)
907enddef
908
909
910
911def Test_throw_vimscript()
912  # only checks line continuation
913  var lines =<< trim END
914      vim9script
915      try
916        throw 'one'
917              .. 'two'
918      catch
919        assert_equal('onetwo', v:exception)
920      endtry
921  END
922  CheckScriptSuccess(lines)
923
924  lines =<< trim END
925    vim9script
926    @r = ''
927    def Func()
928      throw @r
929    enddef
930    var result = ''
931    try
932      Func()
933    catch /E1129:/
934      result = 'caught'
935    endtry
936    assert_equal('caught', result)
937  END
938  CheckScriptSuccess(lines)
939enddef
940
941def Test_error_in_nested_function()
942  # an error in a nested :function aborts executing in the calling :def function
943  var lines =<< trim END
944      vim9script
945      def Func()
946        Error()
947        g:test_var = 1
948      enddef
949      func Error() abort
950        eval [][0]
951      endfunc
952      Func()
953  END
954  g:test_var = 0
955  CheckScriptFailure(lines, 'E684:')
956  assert_equal(0, g:test_var)
957enddef
958
959def Test_abort_after_error()
960  var lines =<< trim END
961      vim9script
962      while true
963        echo notfound
964      endwhile
965      g:gotthere = true
966  END
967  g:gotthere = false
968  CheckScriptFailure(lines, 'E121:')
969  assert_false(g:gotthere)
970  unlet g:gotthere
971enddef
972
973def Test_cexpr_vimscript()
974  # only checks line continuation
975  set errorformat=File\ %f\ line\ %l
976  var lines =<< trim END
977      vim9script
978      cexpr 'File'
979                .. ' someFile' ..
980                   ' line 19'
981      assert_equal(19, getqflist()[0].lnum)
982  END
983  CheckScriptSuccess(lines)
984  set errorformat&
985enddef
986
987def Test_statusline_syntax()
988  # legacy syntax is used for 'statusline'
989  var lines =<< trim END
990      vim9script
991      func g:Status()
992        return '%{"x" is# "x"}'
993      endfunc
994      set laststatus=2 statusline=%!Status()
995      redrawstatus
996      set laststatus statusline=
997  END
998  CheckScriptSuccess(lines)
999enddef
1000
1001def Test_list_vimscript()
1002  # checks line continuation and comments
1003  var lines =<< trim END
1004      vim9script
1005      var mylist = [
1006            'one',
1007            # comment
1008            'two', # empty line follows
1009
1010            'three',
1011            ]
1012      assert_equal(['one', 'two', 'three'], mylist)
1013  END
1014  CheckScriptSuccess(lines)
1015
1016  # check all lines from heredoc are kept
1017  lines =<< trim END
1018      # comment 1
1019      two
1020      # comment 3
1021
1022      five
1023      # comment 6
1024  END
1025  assert_equal(['# comment 1', 'two', '# comment 3', '', 'five', '# comment 6'], lines)
1026
1027  lines =<< trim END
1028    [{
1029      a: 0}]->string()->assert_equal("[{'a': 0}]")
1030  END
1031  CheckDefAndScriptSuccess(lines)
1032enddef
1033
1034if has('channel')
1035  let someJob = test_null_job()
1036
1037  def FuncWithError()
1038    echomsg g:someJob
1039  enddef
1040
1041  func Test_convert_emsg_to_exception()
1042    try
1043      call FuncWithError()
1044    catch
1045      call assert_match('Vim:E908:', v:exception)
1046    endtry
1047  endfunc
1048endif
1049
1050let s:export_script_lines =<< trim END
1051  vim9script
1052  var name: string = 'bob'
1053  def Concat(arg: string): string
1054    return name .. arg
1055  enddef
1056  g:result = Concat('bie')
1057  g:localname = name
1058
1059  export const CONST = 1234
1060  export var exported = 9876
1061  export var exp_name = 'John'
1062  export def Exported(): string
1063    return 'Exported'
1064  enddef
1065  export final theList = [1]
1066END
1067
1068def Undo_export_script_lines()
1069  unlet g:result
1070  unlet g:localname
1071enddef
1072
1073def Test_vim9_import_export()
1074  var import_script_lines =<< trim END
1075    vim9script
1076    import {exported, Exported} from './Xexport.vim'
1077    g:imported = exported
1078    exported += 3
1079    g:imported_added = exported
1080    g:imported_func = Exported()
1081
1082    def GetExported(): string
1083      var local_dict = {ref: Exported}
1084      return local_dict.ref()
1085    enddef
1086    g:funcref_result = GetExported()
1087
1088    var dir = './'
1089    var ext = ".vim"
1090    import {exp_name} from dir .. 'Xexport' .. ext
1091    g:imported_name = exp_name
1092    exp_name ..= ' Doe'
1093    g:imported_name_appended = exp_name
1094    g:imported_later = exported
1095
1096    import theList from './Xexport.vim'
1097    theList->add(2)
1098    assert_equal([1, 2], theList)
1099  END
1100
1101  writefile(import_script_lines, 'Ximport.vim')
1102  writefile(s:export_script_lines, 'Xexport.vim')
1103
1104  source Ximport.vim
1105
1106  assert_equal('bobbie', g:result)
1107  assert_equal('bob', g:localname)
1108  assert_equal(9876, g:imported)
1109  assert_equal(9879, g:imported_added)
1110  assert_equal(9879, g:imported_later)
1111  assert_equal('Exported', g:imported_func)
1112  assert_equal('Exported', g:funcref_result)
1113  assert_equal('John', g:imported_name)
1114  assert_equal('John Doe', g:imported_name_appended)
1115  assert_false(exists('g:name'))
1116
1117  Undo_export_script_lines()
1118  unlet g:imported
1119  unlet g:imported_added
1120  unlet g:imported_later
1121  unlet g:imported_func
1122  unlet g:imported_name g:imported_name_appended
1123  delete('Ximport.vim')
1124
1125  # similar, with line breaks
1126  var import_line_break_script_lines =<< trim END
1127    vim9script
1128    import {
1129        exported,
1130        Exported,
1131        }
1132        from
1133        './Xexport.vim'
1134    g:imported = exported
1135    exported += 5
1136    g:imported_added = exported
1137    g:imported_func = Exported()
1138  END
1139  writefile(import_line_break_script_lines, 'Ximport_lbr.vim')
1140  source Ximport_lbr.vim
1141
1142  assert_equal(9876, g:imported)
1143  assert_equal(9881, g:imported_added)
1144  assert_equal('Exported', g:imported_func)
1145
1146  # exported script not sourced again
1147  assert_false(exists('g:result'))
1148  unlet g:imported
1149  unlet g:imported_added
1150  unlet g:imported_func
1151  delete('Ximport_lbr.vim')
1152
1153  var import_star_as_lines =<< trim END
1154    vim9script
1155    import * as Export from './Xexport.vim'
1156    def UseExport()
1157      g:imported_def = Export.exported
1158    enddef
1159    g:imported_script = Export.exported
1160    assert_equal(1, exists('Export.exported'))
1161    assert_equal(0, exists('Export.notexported'))
1162    UseExport()
1163  END
1164  writefile(import_star_as_lines, 'Ximport.vim')
1165  source Ximport.vim
1166  # FIXME: this should be 9881
1167  assert_equal(9876, g:imported_def)
1168  assert_equal(9876, g:imported_script)
1169
1170  var import_star_as_lines_no_dot =<< trim END
1171    vim9script
1172    import * as Export from './Xexport.vim'
1173    def Func()
1174      var dummy = 1
1175      var imported = Export + dummy
1176    enddef
1177    defcompile
1178  END
1179  writefile(import_star_as_lines_no_dot, 'Ximport.vim')
1180  assert_fails('source Ximport.vim', 'E1060:', '', 2, 'Func')
1181
1182  var import_star_as_lines_dot_space =<< trim END
1183    vim9script
1184    import * as Export from './Xexport.vim'
1185    def Func()
1186      var imported = Export . exported
1187    enddef
1188    defcompile
1189  END
1190  writefile(import_star_as_lines_dot_space, 'Ximport.vim')
1191  assert_fails('source Ximport.vim', 'E1074:', '', 1, 'Func')
1192
1193  var import_star_as_duplicated =<< trim END
1194    vim9script
1195    import * as Export from './Xexport.vim'
1196    var some = 'other'
1197    import * as Export from './Xexport.vim'
1198    defcompile
1199  END
1200  writefile(import_star_as_duplicated, 'Ximport.vim')
1201  assert_fails('source Ximport.vim', 'E1073:', '', 4, 'Ximport.vim')
1202
1203  var import_star_as_lines_script_no_dot =<< trim END
1204    vim9script
1205    import * as Export from './Xexport.vim'
1206    g:imported_script = Export exported
1207  END
1208  writefile(import_star_as_lines_script_no_dot, 'Ximport.vim')
1209  assert_fails('source Ximport.vim', 'E1029:')
1210
1211  var import_star_as_lines_script_space_after_dot =<< trim END
1212    vim9script
1213    import * as Export from './Xexport.vim'
1214    g:imported_script = Export. exported
1215  END
1216  writefile(import_star_as_lines_script_space_after_dot, 'Ximport.vim')
1217  assert_fails('source Ximport.vim', 'E1074:')
1218
1219  var import_star_as_lines_missing_name =<< trim END
1220    vim9script
1221    import * as Export from './Xexport.vim'
1222    def Func()
1223      var imported = Export.
1224    enddef
1225    defcompile
1226  END
1227  writefile(import_star_as_lines_missing_name, 'Ximport.vim')
1228  assert_fails('source Ximport.vim', 'E1048:', '', 1, 'Func')
1229
1230  var import_star_as_lbr_lines =<< trim END
1231    vim9script
1232    import *
1233        as Export
1234        from
1235        './Xexport.vim'
1236    def UseExport()
1237      g:imported = Export.exported
1238    enddef
1239    UseExport()
1240  END
1241  writefile(import_star_as_lbr_lines, 'Ximport.vim')
1242  source Ximport.vim
1243  assert_equal(9876, g:imported)
1244
1245  var import_star_lines =<< trim END
1246    vim9script
1247    import * from './Xexport.vim'
1248  END
1249  writefile(import_star_lines, 'Ximport.vim')
1250  assert_fails('source Ximport.vim', 'E1045:', '', 2, 'Ximport.vim')
1251
1252  # try to import something that exists but is not exported
1253  var import_not_exported_lines =<< trim END
1254    vim9script
1255    import name from './Xexport.vim'
1256  END
1257  writefile(import_not_exported_lines, 'Ximport.vim')
1258  assert_fails('source Ximport.vim', 'E1049:', '', 2, 'Ximport.vim')
1259
1260  # try to import something that is already defined
1261  var import_already_defined =<< trim END
1262    vim9script
1263    var exported = 'something'
1264    import exported from './Xexport.vim'
1265  END
1266  writefile(import_already_defined, 'Ximport.vim')
1267  assert_fails('source Ximport.vim', 'E1054:', '', 3, 'Ximport.vim')
1268
1269  # try to import something that is already defined
1270  import_already_defined =<< trim END
1271    vim9script
1272    var exported = 'something'
1273    import * as exported from './Xexport.vim'
1274  END
1275  writefile(import_already_defined, 'Ximport.vim')
1276  assert_fails('source Ximport.vim', 'E1054:', '', 3, 'Ximport.vim')
1277
1278  # try to import something that is already defined
1279  import_already_defined =<< trim END
1280    vim9script
1281    var exported = 'something'
1282    import {exported} from './Xexport.vim'
1283  END
1284  writefile(import_already_defined, 'Ximport.vim')
1285  assert_fails('source Ximport.vim', 'E1054:', '', 3, 'Ximport.vim')
1286
1287  # try changing an imported const
1288  var import_assign_to_const =<< trim END
1289    vim9script
1290    import CONST from './Xexport.vim'
1291    def Assign()
1292      CONST = 987
1293    enddef
1294    defcompile
1295  END
1296  writefile(import_assign_to_const, 'Ximport.vim')
1297  assert_fails('source Ximport.vim', 'E46:', '', 1, '_Assign')
1298
1299  # try changing an imported final
1300  var import_assign_to_final =<< trim END
1301    vim9script
1302    import theList from './Xexport.vim'
1303    def Assign()
1304      theList = [2]
1305    enddef
1306    defcompile
1307  END
1308  writefile(import_assign_to_final, 'Ximport.vim')
1309  assert_fails('source Ximport.vim', 'E46:', '', 1, '_Assign')
1310
1311  # import a very long name, requires making a copy
1312  var import_long_name_lines =<< trim END
1313    vim9script
1314    import name012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 from './Xexport.vim'
1315  END
1316  writefile(import_long_name_lines, 'Ximport.vim')
1317  assert_fails('source Ximport.vim', 'E1048:', '', 2, 'Ximport.vim')
1318
1319  var import_no_from_lines =<< trim END
1320    vim9script
1321    import name './Xexport.vim'
1322  END
1323  writefile(import_no_from_lines, 'Ximport.vim')
1324  assert_fails('source Ximport.vim', 'E1070:', '', 2, 'Ximport.vim')
1325
1326  var import_invalid_string_lines =<< trim END
1327    vim9script
1328    import name from Xexport.vim
1329  END
1330  writefile(import_invalid_string_lines, 'Ximport.vim')
1331  assert_fails('source Ximport.vim', 'E121:', '', 2, 'Ximport.vim')
1332
1333  var import_wrong_name_lines =<< trim END
1334    vim9script
1335    import name from './XnoExport.vim'
1336  END
1337  writefile(import_wrong_name_lines, 'Ximport.vim')
1338  assert_fails('source Ximport.vim', 'E1053:', '', 2, 'Ximport.vim')
1339
1340  var import_missing_comma_lines =<< trim END
1341    vim9script
1342    import {exported name} from './Xexport.vim'
1343  END
1344  writefile(import_missing_comma_lines, 'Ximport3.vim')
1345  assert_fails('source Ximport3.vim', 'E1046:', '', 2, 'Ximport3.vim')
1346
1347  delete('Ximport.vim')
1348  delete('Ximport3.vim')
1349  delete('Xexport.vim')
1350
1351  # Check that in a Vim9 script 'cpo' is set to the Vim default.
1352  # Flags added or removed are also applied to the restored value.
1353  set cpo=abcd
1354  var lines =<< trim END
1355    vim9script
1356    g:cpo_in_vim9script = &cpo
1357    set cpo+=f
1358    set cpo-=c
1359    g:cpo_after_vim9script = &cpo
1360  END
1361  writefile(lines, 'Xvim9_script')
1362  source Xvim9_script
1363  assert_equal('fabd', &cpo)
1364  set cpo&vim
1365  assert_equal(&cpo, g:cpo_in_vim9script)
1366  var newcpo = substitute(&cpo, 'c', '', '') .. 'f'
1367  assert_equal(newcpo, g:cpo_after_vim9script)
1368
1369  delete('Xvim9_script')
1370enddef
1371
1372def Test_import_as()
1373  var export_lines =<< trim END
1374    vim9script
1375    export var one = 1
1376    export var yes = 'yes'
1377    export var slist: list<string>
1378  END
1379  writefile(export_lines, 'XexportAs')
1380
1381  var import_lines =<< trim END
1382    vim9script
1383    var one = 'notused'
1384    var yes = 777
1385    import one as thatOne from './XexportAs'
1386    assert_equal(1, thatOne)
1387    import yes as yesYes from './XexportAs'
1388    assert_equal('yes', yesYes)
1389  END
1390  CheckScriptSuccess(import_lines)
1391
1392  import_lines =<< trim END
1393    vim9script
1394    import {one as thatOne, yes as yesYes} from './XexportAs'
1395    assert_equal(1, thatOne)
1396    assert_equal('yes', yesYes)
1397    assert_fails('echo one', 'E121:')
1398    assert_fails('echo yes', 'E121:')
1399  END
1400  CheckScriptSuccess(import_lines)
1401
1402  import_lines =<< trim END
1403    vim9script
1404    import {slist as impSlist} from './XexportAs'
1405    impSlist->add(123)
1406  END
1407  CheckScriptFailure(import_lines, 'E1012: Type mismatch; expected string but got number')
1408
1409  delete('XexportAs')
1410enddef
1411
1412func g:Trigger()
1413  source Ximport.vim
1414  return "echo 'yes'\<CR>"
1415endfunc
1416
1417def Test_import_export_expr_map()
1418  # check that :import and :export work when buffer is locked
1419  var export_lines =<< trim END
1420    vim9script
1421    export def That(): string
1422      return 'yes'
1423    enddef
1424  END
1425  writefile(export_lines, 'Xexport_that.vim')
1426
1427  var import_lines =<< trim END
1428    vim9script
1429    import That from './Xexport_that.vim'
1430    assert_equal('yes', That())
1431  END
1432  writefile(import_lines, 'Ximport.vim')
1433
1434  nnoremap <expr> trigger g:Trigger()
1435  feedkeys('trigger', "xt")
1436
1437  delete('Xexport_that.vim')
1438  delete('Ximport.vim')
1439  nunmap trigger
1440enddef
1441
1442def Test_import_in_filetype()
1443  # check that :import works when the buffer is locked
1444  mkdir('ftplugin', 'p')
1445  var export_lines =<< trim END
1446    vim9script
1447    export var That = 'yes'
1448  END
1449  writefile(export_lines, 'ftplugin/Xexport_ft.vim')
1450
1451  var import_lines =<< trim END
1452    vim9script
1453    import That from './Xexport_ft.vim'
1454    assert_equal('yes', That)
1455    g:did_load_mytpe = 1
1456  END
1457  writefile(import_lines, 'ftplugin/qf.vim')
1458
1459  var save_rtp = &rtp
1460  &rtp = getcwd() .. ',' .. &rtp
1461
1462  filetype plugin on
1463  copen
1464  assert_equal(1, g:did_load_mytpe)
1465
1466  quit!
1467  delete('Xexport_ft.vim')
1468  delete('ftplugin', 'rf')
1469  &rtp = save_rtp
1470enddef
1471
1472def Test_use_import_in_mapping()
1473  var lines =<< trim END
1474      vim9script
1475      export def Funcx()
1476        g:result = 42
1477      enddef
1478  END
1479  writefile(lines, 'XsomeExport.vim')
1480  lines =<< trim END
1481      vim9script
1482      import Funcx from './XsomeExport.vim'
1483      nnoremap <F3> :call <sid>Funcx()<cr>
1484  END
1485  writefile(lines, 'Xmapscript.vim')
1486
1487  source Xmapscript.vim
1488  feedkeys("\<F3>", "xt")
1489  assert_equal(42, g:result)
1490
1491  unlet g:result
1492  delete('XsomeExport.vim')
1493  delete('Xmapscript.vim')
1494  nunmap <F3>
1495enddef
1496
1497def Test_vim9script_mix()
1498  var lines =<< trim END
1499    if has(g:feature)
1500      " legacy script
1501      let g:legacy = 1
1502      finish
1503    endif
1504    vim9script
1505    g:legacy = 0
1506  END
1507  g:feature = 'eval'
1508  g:legacy = -1
1509  CheckScriptSuccess(lines)
1510  assert_equal(1, g:legacy)
1511
1512  g:feature = 'noteval'
1513  g:legacy = -1
1514  CheckScriptSuccess(lines)
1515  assert_equal(0, g:legacy)
1516enddef
1517
1518def Test_vim9script_fails()
1519  CheckScriptFailure(['scriptversion 2', 'vim9script'], 'E1039:')
1520  CheckScriptFailure(['vim9script', 'scriptversion 2'], 'E1040:')
1521  CheckScriptFailure(['export var some = 123'], 'E1042:')
1522  CheckScriptFailure(['import some from "./Xexport.vim"'], 'E1048:')
1523  CheckScriptFailure(['vim9script', 'export var g:some'], 'E1022:')
1524  CheckScriptFailure(['vim9script', 'export echo 134'], 'E1043:')
1525
1526  CheckScriptFailure(['vim9script', 'var str: string', 'str = 1234'], 'E1012:')
1527  CheckScriptFailure(['vim9script', 'const str = "asdf"', 'str = "xxx"'], 'E46:')
1528
1529  assert_fails('vim9script', 'E1038:')
1530  assert_fails('export something', 'E1043:')
1531enddef
1532
1533func Test_import_fails_without_script()
1534  CheckRunVimInTerminal
1535
1536  " call indirectly to avoid compilation error for missing functions
1537  call Run_Test_import_fails_on_command_line()
1538endfunc
1539
1540def Run_Test_import_fails_on_command_line()
1541  var export =<< trim END
1542    vim9script
1543    export def Foo(): number
1544        return 0
1545    enddef
1546  END
1547  writefile(export, 'XexportCmd.vim')
1548
1549  var buf = RunVimInTerminal('-c "import Foo from ''./XexportCmd.vim''"', {
1550                rows: 6, wait_for_ruler: 0})
1551  WaitForAssert(() => assert_match('^E1094:', term_getline(buf, 5)))
1552
1553  delete('XexportCmd.vim')
1554  StopVimInTerminal(buf)
1555enddef
1556
1557def Test_vim9script_reload_noclear()
1558  var lines =<< trim END
1559    vim9script
1560    export var exported = 'thexport'
1561  END
1562  writefile(lines, 'XExportReload')
1563  lines =<< trim END
1564    vim9script noclear
1565    g:loadCount += 1
1566    var s:reloaded = 'init'
1567    import exported from './XExportReload'
1568
1569    def Again(): string
1570      return 'again'
1571    enddef
1572
1573    if exists('s:loaded') | finish | endif
1574    var s:loaded = true
1575
1576    var s:notReloaded = 'yes'
1577    s:reloaded = 'first'
1578    def g:Values(): list<string>
1579      return [s:reloaded, s:notReloaded, Again(), Once(), exported]
1580    enddef
1581
1582    def Once(): string
1583      return 'once'
1584    enddef
1585  END
1586  writefile(lines, 'XReloaded')
1587  g:loadCount = 0
1588  source XReloaded
1589  assert_equal(1, g:loadCount)
1590  assert_equal(['first', 'yes', 'again', 'once', 'thexport'], g:Values())
1591  source XReloaded
1592  assert_equal(2, g:loadCount)
1593  assert_equal(['init', 'yes', 'again', 'once', 'thexport'], g:Values())
1594  source XReloaded
1595  assert_equal(3, g:loadCount)
1596  assert_equal(['init', 'yes', 'again', 'once', 'thexport'], g:Values())
1597
1598  delete('XReloaded')
1599  delete('XExportReload')
1600  delfunc g:Values
1601  unlet g:loadCount
1602
1603  lines =<< trim END
1604      vim9script
1605      def Inner()
1606      enddef
1607  END
1608  lines->writefile('XreloadScript.vim')
1609  source XreloadScript.vim
1610
1611  lines =<< trim END
1612      vim9script
1613      def Outer()
1614        def Inner()
1615        enddef
1616      enddef
1617      defcompile
1618  END
1619  lines->writefile('XreloadScript.vim')
1620  source XreloadScript.vim
1621
1622  delete('XreloadScript.vim')
1623enddef
1624
1625def Test_vim9script_reload_import()
1626  var lines =<< trim END
1627    vim9script
1628    const var = ''
1629    var valone = 1234
1630    def MyFunc(arg: string)
1631       valone = 5678
1632    enddef
1633  END
1634  var morelines =<< trim END
1635    var valtwo = 222
1636    export def GetValtwo(): number
1637      return valtwo
1638    enddef
1639  END
1640  writefile(lines + morelines, 'Xreload.vim')
1641  source Xreload.vim
1642  source Xreload.vim
1643  source Xreload.vim
1644
1645  # cannot declare a var twice
1646  lines =<< trim END
1647    vim9script
1648    var valone = 1234
1649    var valone = 5678
1650  END
1651  writefile(lines, 'Xreload.vim')
1652  assert_fails('source Xreload.vim', 'E1041:', '', 3, 'Xreload.vim')
1653
1654  delete('Xreload.vim')
1655  delete('Ximport.vim')
1656enddef
1657
1658" if a script is reloaded with a script-local variable that changed its type, a
1659" compiled function using that variable must fail.
1660def Test_script_reload_change_type()
1661  var lines =<< trim END
1662    vim9script noclear
1663    var str = 'string'
1664    def g:GetStr(): string
1665      return str .. 'xxx'
1666    enddef
1667  END
1668  writefile(lines, 'Xreload.vim')
1669  source Xreload.vim
1670  echo g:GetStr()
1671
1672  lines =<< trim END
1673    vim9script noclear
1674    var str = 1234
1675  END
1676  writefile(lines, 'Xreload.vim')
1677  source Xreload.vim
1678  assert_fails('echo g:GetStr()', 'E1150:')
1679
1680  delfunc g:GetStr
1681  delete('Xreload.vim')
1682enddef
1683
1684" Define CallFunc so that the test can be compiled
1685command CallFunc echo 'nop'
1686
1687def Test_script_reload_from_function()
1688  var lines =<< trim END
1689      vim9script
1690
1691      if exists('g:loaded')
1692        finish
1693      endif
1694      g:loaded = 1
1695      delcommand CallFunc
1696      command CallFunc Func()
1697      def Func()
1698        so XreloadFunc.vim
1699        g:didTheFunc = 1
1700      enddef
1701  END
1702  writefile(lines, 'XreloadFunc.vim')
1703  source XreloadFunc.vim
1704  CallFunc
1705  assert_equal(1, g:didTheFunc)
1706
1707  delete('XreloadFunc.vim')
1708  delcommand CallFunc
1709  unlet g:loaded
1710  unlet g:didTheFunc
1711enddef
1712
1713def Test_script_var_shadows_function()
1714  var lines =<< trim END
1715      vim9script
1716      def Func(): number
1717        return 123
1718      enddef
1719      var Func = 1
1720  END
1721  CheckScriptFailure(lines, 'E1041:', 5)
1722enddef
1723
1724def Test_script_var_shadows_command()
1725  var lines =<< trim END
1726      var undo = 1
1727      undo = 2
1728      assert_equal(2, undo)
1729  END
1730  CheckDefAndScriptSuccess(lines)
1731
1732  lines =<< trim END
1733      var undo = 1
1734      undo
1735  END
1736  CheckDefAndScriptFailure(lines, 'E1207:', 2)
1737enddef
1738
1739def s:RetSome(): string
1740  return 'some'
1741enddef
1742
1743" Not exported function that is referenced needs to be accessed by the
1744" script-local name.
1745def Test_vim9script_funcref()
1746  var sortlines =<< trim END
1747      vim9script
1748      def Compare(i1: number, i2: number): number
1749        return i2 - i1
1750      enddef
1751
1752      export def FastSort(): list<number>
1753        return range(5)->sort(Compare)
1754      enddef
1755
1756      export def GetString(arg: string): string
1757        return arg
1758      enddef
1759  END
1760  writefile(sortlines, 'Xsort.vim')
1761
1762  var lines =<< trim END
1763    vim9script
1764    import FastSort from './Xsort.vim'
1765    def Test()
1766      g:result = FastSort()
1767    enddef
1768    Test()
1769
1770    # using a function imported with "as"
1771    import * as anAlias from './Xsort.vim'
1772    assert_equal('yes', anAlias.GetString('yes'))
1773
1774    # using the function from a compiled function
1775    def TestMore(): string
1776      var s = s:anAlias.GetString('foo')
1777      return s .. anAlias.GetString('bar')
1778    enddef
1779    assert_equal('foobar', TestMore())
1780
1781    # error when using a function that isn't exported
1782    assert_fails('anAlias.Compare(1, 2)', 'E1049:')
1783  END
1784  writefile(lines, 'Xscript.vim')
1785
1786  source Xscript.vim
1787  assert_equal([4, 3, 2, 1, 0], g:result)
1788
1789  unlet g:result
1790  delete('Xsort.vim')
1791  delete('Xscript.vim')
1792
1793  var Funcref = function('s:RetSome')
1794  assert_equal('some', Funcref())
1795enddef
1796
1797" Check that when searching for "FilterFunc" it finds the import in the
1798" script where FastFilter() is called from, both as a string and as a direct
1799" function reference.
1800def Test_vim9script_funcref_other_script()
1801  var filterLines =<< trim END
1802    vim9script
1803    export def FilterFunc(idx: number, val: number): bool
1804      return idx % 2 == 1
1805    enddef
1806    export def FastFilter(): list<number>
1807      return range(10)->filter('FilterFunc')
1808    enddef
1809    export def FastFilterDirect(): list<number>
1810      return range(10)->filter(FilterFunc)
1811    enddef
1812  END
1813  writefile(filterLines, 'Xfilter.vim')
1814
1815  var lines =<< trim END
1816    vim9script
1817    import {FilterFunc, FastFilter, FastFilterDirect} from './Xfilter.vim'
1818    def Test()
1819      var x: list<number> = FastFilter()
1820    enddef
1821    Test()
1822    def TestDirect()
1823      var x: list<number> = FastFilterDirect()
1824    enddef
1825    TestDirect()
1826  END
1827  CheckScriptSuccess(lines)
1828  delete('Xfilter.vim')
1829enddef
1830
1831def Test_vim9script_reload_delfunc()
1832  var first_lines =<< trim END
1833    vim9script
1834    def FuncYes(): string
1835      return 'yes'
1836    enddef
1837  END
1838  var withno_lines =<< trim END
1839    def FuncNo(): string
1840      return 'no'
1841    enddef
1842    def g:DoCheck(no_exists: bool)
1843      assert_equal('yes', FuncYes())
1844      assert_equal('no', FuncNo())
1845    enddef
1846  END
1847  var nono_lines =<< trim END
1848    def g:DoCheck(no_exists: bool)
1849      assert_equal('yes', FuncYes())
1850      assert_fails('FuncNo()', 'E117:', '', 2, 'DoCheck')
1851    enddef
1852  END
1853
1854  # FuncNo() is defined
1855  writefile(first_lines + withno_lines, 'Xreloaded.vim')
1856  source Xreloaded.vim
1857  g:DoCheck(true)
1858
1859  # FuncNo() is not redefined
1860  writefile(first_lines + nono_lines, 'Xreloaded.vim')
1861  source Xreloaded.vim
1862  g:DoCheck(false)
1863
1864  # FuncNo() is back
1865  writefile(first_lines + withno_lines, 'Xreloaded.vim')
1866  source Xreloaded.vim
1867  g:DoCheck(false)
1868
1869  delete('Xreloaded.vim')
1870enddef
1871
1872def Test_vim9script_reload_delvar()
1873  # write the script with a script-local variable
1874  var lines =<< trim END
1875    vim9script
1876    var name = 'string'
1877  END
1878  writefile(lines, 'XreloadVar.vim')
1879  source XreloadVar.vim
1880
1881  # now write the script using the same variable locally - works
1882  lines =<< trim END
1883    vim9script
1884    def Func()
1885      var name = 'string'
1886    enddef
1887  END
1888  writefile(lines, 'XreloadVar.vim')
1889  source XreloadVar.vim
1890
1891  delete('XreloadVar.vim')
1892enddef
1893
1894def Test_import_absolute()
1895  var import_lines = [
1896        'vim9script',
1897        'import exported from "' .. escape(getcwd(), '\') .. '/Xexport_abs.vim"',
1898        'def UseExported()',
1899        '  g:imported_abs = exported',
1900        '  exported = 8888',
1901        '  g:imported_after = exported',
1902        'enddef',
1903        'UseExported()',
1904        'g:import_disassembled = execute("disass UseExported")',
1905        ]
1906  writefile(import_lines, 'Ximport_abs.vim')
1907  writefile(s:export_script_lines, 'Xexport_abs.vim')
1908
1909  source Ximport_abs.vim
1910
1911  assert_equal(9876, g:imported_abs)
1912  assert_equal(8888, g:imported_after)
1913  assert_match('<SNR>\d\+_UseExported\_s*' ..
1914          'g:imported_abs = exported\_s*' ..
1915          '0 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' ..
1916          '1 STOREG g:imported_abs\_s*' ..
1917          'exported = 8888\_s*' ..
1918          '2 PUSHNR 8888\_s*' ..
1919          '3 STORESCRIPT exported-2 in .*Xexport_abs.vim\_s*' ..
1920          'g:imported_after = exported\_s*' ..
1921          '4 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' ..
1922          '5 STOREG g:imported_after',
1923        g:import_disassembled)
1924
1925  Undo_export_script_lines()
1926  unlet g:imported_abs
1927  unlet g:import_disassembled
1928
1929  delete('Ximport_abs.vim')
1930  delete('Xexport_abs.vim')
1931enddef
1932
1933def Test_import_rtp()
1934  var import_lines = [
1935        'vim9script',
1936        'import exported from "Xexport_rtp.vim"',
1937        'g:imported_rtp = exported',
1938        ]
1939  writefile(import_lines, 'Ximport_rtp.vim')
1940  mkdir('import', 'p')
1941  writefile(s:export_script_lines, 'import/Xexport_rtp.vim')
1942
1943  var save_rtp = &rtp
1944  &rtp = getcwd()
1945  source Ximport_rtp.vim
1946  &rtp = save_rtp
1947
1948  assert_equal(9876, g:imported_rtp)
1949
1950  Undo_export_script_lines()
1951  unlet g:imported_rtp
1952  delete('Ximport_rtp.vim')
1953  delete('import', 'rf')
1954enddef
1955
1956def Test_import_compile_error()
1957  var export_lines = [
1958        'vim9script',
1959        'export def ExpFunc(): string',
1960        '  return notDefined',
1961        'enddef',
1962        ]
1963  writefile(export_lines, 'Xexported.vim')
1964
1965  var import_lines = [
1966        'vim9script',
1967        'import ExpFunc from "./Xexported.vim"',
1968        'def ImpFunc()',
1969        '  echo ExpFunc()',
1970        'enddef',
1971        'defcompile',
1972        ]
1973  writefile(import_lines, 'Ximport.vim')
1974
1975  try
1976    source Ximport.vim
1977  catch /E1001/
1978    # Error should be fore the Xexported.vim file.
1979    assert_match('E1001: Variable not found: notDefined', v:exception)
1980    assert_match('function <SNR>\d\+_ImpFunc\[1\]..<SNR>\d\+_ExpFunc, line 1', v:throwpoint)
1981  endtry
1982
1983  delete('Xexported.vim')
1984  delete('Ximport.vim')
1985enddef
1986
1987def Test_func_redefine_error()
1988  var lines = [
1989        'vim9script',
1990        'def Func()',
1991        '  eval [][0]',
1992        'enddef',
1993        'Func()',
1994        ]
1995  writefile(lines, 'Xtestscript.vim')
1996
1997  for count in range(3)
1998    try
1999      source Xtestscript.vim
2000    catch /E684/
2001      # function name should contain <SNR> every time
2002      assert_match('E684: list index out of range', v:exception)
2003      assert_match('function <SNR>\d\+_Func, line 1', v:throwpoint)
2004    endtry
2005  endfor
2006
2007  delete('Xtestscript.vim')
2008enddef
2009
2010def Test_func_overrules_import_fails()
2011  var export_lines =<< trim END
2012      vim9script
2013      export def Func()
2014        echo 'imported'
2015      enddef
2016  END
2017  writefile(export_lines, 'XexportedFunc.vim')
2018
2019  var lines =<< trim END
2020    vim9script
2021    import Func from './XexportedFunc.vim'
2022    def Func()
2023      echo 'local to function'
2024    enddef
2025  END
2026  CheckScriptFailure(lines, 'E1073:')
2027
2028  lines =<< trim END
2029    vim9script
2030    import Func from './XexportedFunc.vim'
2031    def Outer()
2032      def Func()
2033        echo 'local to function'
2034      enddef
2035    enddef
2036    defcompile
2037  END
2038  CheckScriptFailure(lines, 'E1073:')
2039
2040  delete('XexportedFunc.vim')
2041enddef
2042
2043def Test_func_redefine_fails()
2044  var lines =<< trim END
2045    vim9script
2046    def Func()
2047      echo 'one'
2048    enddef
2049    def Func()
2050      echo 'two'
2051    enddef
2052  END
2053  CheckScriptFailure(lines, 'E1073:')
2054
2055  lines =<< trim END
2056    vim9script
2057    def Foo(): string
2058      return 'foo'
2059      enddef
2060    def Func()
2061      var  Foo = {-> 'lambda'}
2062    enddef
2063    defcompile
2064  END
2065  CheckScriptFailure(lines, 'E1073:')
2066enddef
2067
2068def Test_fixed_size_list()
2069  # will be allocated as one piece of memory, check that changes work
2070  var l = [1, 2, 3, 4]
2071  l->remove(0)
2072  l->add(5)
2073  l->insert(99, 1)
2074  assert_equal([2, 99, 3, 4, 5], l)
2075enddef
2076
2077def Test_no_insert_xit()
2078  CheckDefExecFailure(['a = 1'], 'E1100:')
2079  CheckDefExecFailure(['c = 1'], 'E1100:')
2080  CheckDefExecFailure(['i = 1'], 'E1100:')
2081  CheckDefExecFailure(['t = 1'], 'E1100:')
2082  CheckDefExecFailure(['x = 1'], 'E1100:')
2083
2084  CheckScriptFailure(['vim9script', 'a = 1'], 'E488:')
2085  CheckScriptFailure(['vim9script', 'a'], 'E1100:')
2086  CheckScriptFailure(['vim9script', 'c = 1'], 'E488:')
2087  CheckScriptFailure(['vim9script', 'c'], 'E1100:')
2088  CheckScriptFailure(['vim9script', 'i = 1'], 'E488:')
2089  CheckScriptFailure(['vim9script', 'i'], 'E1100:')
2090  CheckScriptFailure(['vim9script', 'o = 1'], 'E1100:')
2091  CheckScriptFailure(['vim9script', 'o'], 'E1100:')
2092  CheckScriptFailure(['vim9script', 't'], 'E1100:')
2093  CheckScriptFailure(['vim9script', 't = 1'], 'E1100:')
2094  CheckScriptFailure(['vim9script', 'x = 1'], 'E1100:')
2095enddef
2096
2097def IfElse(what: number): string
2098  var res = ''
2099  if what == 1
2100    res = "one"
2101  elseif what == 2
2102    res = "two"
2103  else
2104    res = "three"
2105  endif
2106  return res
2107enddef
2108
2109def Test_if_elseif_else()
2110  assert_equal('one', IfElse(1))
2111  assert_equal('two', IfElse(2))
2112  assert_equal('three', IfElse(3))
2113enddef
2114
2115def Test_if_elseif_else_fails()
2116  CheckDefFailure(['elseif true'], 'E582:')
2117  CheckDefFailure(['else'], 'E581:')
2118  CheckDefFailure(['endif'], 'E580:')
2119  CheckDefFailure(['if g:abool', 'elseif xxx'], 'E1001:')
2120  CheckDefFailure(['if true', 'echo 1'], 'E171:')
2121
2122  var lines =<< trim END
2123      var s = ''
2124      if s = ''
2125      endif
2126  END
2127  CheckDefFailure(lines, 'E488:')
2128
2129  lines =<< trim END
2130      var s = ''
2131      if s == ''
2132      elseif s = ''
2133      endif
2134  END
2135  CheckDefFailure(lines, 'E488:')
2136enddef
2137
2138let g:bool_true = v:true
2139let g:bool_false = v:false
2140
2141def Test_if_const_expr()
2142  var res = false
2143  if true ? true : false
2144    res = true
2145  endif
2146  assert_equal(true, res)
2147
2148  g:glob = 2
2149  if false
2150    execute('g:glob = 3')
2151  endif
2152  assert_equal(2, g:glob)
2153  if true
2154    execute('g:glob = 3')
2155  endif
2156  assert_equal(3, g:glob)
2157
2158  res = false
2159  if g:bool_true ? true : false
2160    res = true
2161  endif
2162  assert_equal(true, res)
2163
2164  res = false
2165  if true ? g:bool_true : false
2166    res = true
2167  endif
2168  assert_equal(true, res)
2169
2170  res = false
2171  if true ? true : g:bool_false
2172    res = true
2173  endif
2174  assert_equal(true, res)
2175
2176  res = false
2177  if true ? false : true
2178    res = true
2179  endif
2180  assert_equal(false, res)
2181
2182  res = false
2183  if false ? false : true
2184    res = true
2185  endif
2186  assert_equal(true, res)
2187
2188  res = false
2189  if false ? true : false
2190    res = true
2191  endif
2192  assert_equal(false, res)
2193
2194  res = false
2195  if has('xyz') ? true : false
2196    res = true
2197  endif
2198  assert_equal(false, res)
2199
2200  res = false
2201  if true && true
2202    res = true
2203  endif
2204  assert_equal(true, res)
2205
2206  res = false
2207  if true && false
2208    res = true
2209  endif
2210  assert_equal(false, res)
2211
2212  res = false
2213  if g:bool_true && false
2214    res = true
2215  endif
2216  assert_equal(false, res)
2217
2218  res = false
2219  if true && g:bool_false
2220    res = true
2221  endif
2222  assert_equal(false, res)
2223
2224  res = false
2225  if false && false
2226    res = true
2227  endif
2228  assert_equal(false, res)
2229
2230  res = false
2231  if true || false
2232    res = true
2233  endif
2234  assert_equal(true, res)
2235
2236  res = false
2237  if g:bool_true || false
2238    res = true
2239  endif
2240  assert_equal(true, res)
2241
2242  res = false
2243  if true || g:bool_false
2244    res = true
2245  endif
2246  assert_equal(true, res)
2247
2248  res = false
2249  if false || false
2250    res = true
2251  endif
2252  assert_equal(false, res)
2253
2254  # with constant "false" expression may be invalid so long as the syntax is OK
2255  if false | eval 1 + 2 | endif
2256  if false | eval burp + 234 | endif
2257  if false | echo burp 234 'asd' | endif
2258  if false
2259    burp
2260  endif
2261enddef
2262
2263def Test_if_const_expr_fails()
2264  CheckDefFailure(['if "aaa" == "bbb'], 'E114:')
2265  CheckDefFailure(["if 'aaa' == 'bbb"], 'E115:')
2266  CheckDefFailure(["if has('aaa'"], 'E110:')
2267  CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
2268enddef
2269
2270def RunNested(i: number): number
2271  var x: number = 0
2272  if i % 2
2273    if 1
2274      # comment
2275    else
2276      # comment
2277    endif
2278    x += 1
2279  else
2280    x += 1000
2281  endif
2282  return x
2283enddef
2284
2285def Test_nested_if()
2286  assert_equal(1, RunNested(1))
2287  assert_equal(1000, RunNested(2))
2288enddef
2289
2290def Test_execute_cmd()
2291  # missing argument is ignored
2292  execute
2293  execute # comment
2294
2295  new
2296  setline(1, 'default')
2297  execute 'setline(1, "execute-string")'
2298  assert_equal('execute-string', getline(1))
2299
2300  execute "setline(1, 'execute-string')"
2301  assert_equal('execute-string', getline(1))
2302
2303  var cmd1 = 'setline(1,'
2304  var cmd2 = '"execute-var")'
2305  execute cmd1 cmd2 # comment
2306  assert_equal('execute-var', getline(1))
2307
2308  execute cmd1 cmd2 '|setline(1, "execute-var-string")'
2309  assert_equal('execute-var-string', getline(1))
2310
2311  var cmd_first = 'call '
2312  var cmd_last = 'setline(1, "execute-var-var")'
2313  execute cmd_first .. cmd_last
2314  assert_equal('execute-var-var', getline(1))
2315  bwipe!
2316
2317  var n = true
2318  execute 'echomsg' (n ? '"true"' : '"no"')
2319  assert_match('^true$', Screenline(&lines))
2320
2321  echomsg [1, 2, 3] {a: 1, b: 2}
2322  assert_match('^\[1, 2, 3\] {''a'': 1, ''b'': 2}$', Screenline(&lines))
2323
2324  CheckDefFailure(['execute xxx'], 'E1001:', 1)
2325  CheckDefExecFailure(['execute "tabnext " .. 8'], 'E475:', 1)
2326  CheckDefFailure(['execute "cmd"# comment'], 'E488:', 1)
2327enddef
2328
2329def Test_execute_cmd_vimscript()
2330  # only checks line continuation
2331  var lines =<< trim END
2332      vim9script
2333      execute 'g:someVar'
2334                .. ' = ' ..
2335                   '28'
2336      assert_equal(28, g:someVar)
2337      unlet g:someVar
2338  END
2339  CheckScriptSuccess(lines)
2340enddef
2341
2342def Test_echo_cmd()
2343  echo 'some' # comment
2344  echon 'thing'
2345  assert_match('^something$', Screenline(&lines))
2346
2347  echo "some" # comment
2348  echon "thing"
2349  assert_match('^something$', Screenline(&lines))
2350
2351  var str1 = 'some'
2352  var str2 = 'more'
2353  echo str1 str2
2354  assert_match('^some more$', Screenline(&lines))
2355
2356  CheckDefFailure(['echo "xxx"# comment'], 'E488:')
2357enddef
2358
2359def Test_echomsg_cmd()
2360  echomsg 'some' 'more' # comment
2361  assert_match('^some more$', Screenline(&lines))
2362  echo 'clear'
2363  :1messages
2364  assert_match('^some more$', Screenline(&lines))
2365
2366  CheckDefFailure(['echomsg "xxx"# comment'], 'E488:')
2367enddef
2368
2369def Test_echomsg_cmd_vimscript()
2370  # only checks line continuation
2371  var lines =<< trim END
2372      vim9script
2373      echomsg 'here'
2374                .. ' is ' ..
2375                   'a message'
2376      assert_match('^here is a message$', Screenline(&lines))
2377  END
2378  CheckScriptSuccess(lines)
2379enddef
2380
2381def Test_echoerr_cmd()
2382  try
2383    echoerr 'something' 'wrong' # comment
2384  catch
2385    assert_match('something wrong', v:exception)
2386  endtry
2387enddef
2388
2389def Test_echoerr_cmd_vimscript()
2390  # only checks line continuation
2391  var lines =<< trim END
2392      vim9script
2393      try
2394        echoerr 'this'
2395                .. ' is ' ..
2396                   'wrong'
2397      catch
2398        assert_match('this is wrong', v:exception)
2399      endtry
2400  END
2401  CheckScriptSuccess(lines)
2402enddef
2403
2404def Test_for_outside_of_function()
2405  var lines =<< trim END
2406    vim9script
2407    new
2408    for var in range(0, 3)
2409      append(line('$'), var)
2410    endfor
2411    assert_equal(['', '0', '1', '2', '3'], getline(1, '$'))
2412    bwipe!
2413
2414    var result = ''
2415    for i in [1, 2, 3]
2416      var loop = ' loop ' .. i
2417      result ..= loop
2418    endfor
2419    assert_equal(' loop 1 loop 2 loop 3', result)
2420  END
2421  writefile(lines, 'Xvim9for.vim')
2422  source Xvim9for.vim
2423  delete('Xvim9for.vim')
2424enddef
2425
2426def Test_for_loop()
2427  var lines =<< trim END
2428      var result = ''
2429      for cnt in range(7)
2430        if cnt == 4
2431          break
2432        endif
2433        if cnt == 2
2434          continue
2435        endif
2436        result ..= cnt .. '_'
2437      endfor
2438      assert_equal('0_1_3_', result)
2439
2440      var concat = ''
2441      for str in eval('["one", "two"]')
2442        concat ..= str
2443      endfor
2444      assert_equal('onetwo', concat)
2445
2446      var total = 0
2447      for nr in
2448          [1, 2, 3]
2449        total += nr
2450      endfor
2451      assert_equal(6, total)
2452
2453      total = 0
2454      for nr
2455        in [1, 2, 3]
2456        total += nr
2457      endfor
2458      assert_equal(6, total)
2459
2460      total = 0
2461      for nr
2462        in
2463        [1, 2, 3]
2464        total += nr
2465      endfor
2466      assert_equal(6, total)
2467
2468      # with type
2469      total = 0
2470      for n: number in [1, 2, 3]
2471        total += n
2472      endfor
2473      assert_equal(6, total)
2474
2475      var chars = ''
2476      for s: string in 'foobar'
2477        chars ..= s
2478      endfor
2479      assert_equal('foobar', chars)
2480
2481      chars = ''
2482      for x: string in {a: 'a', b: 'b'}->values()
2483        chars ..= x
2484      endfor
2485      assert_equal('ab', chars)
2486
2487      # unpack with type
2488      var res = ''
2489      for [n: number, s: string] in [[1, 'a'], [2, 'b']]
2490        res ..= n .. s
2491      endfor
2492      assert_equal('1a2b', res)
2493
2494      # unpack with one var
2495      var reslist = []
2496      for [x] in [['aaa'], ['bbb']]
2497        reslist->add(x)
2498      endfor
2499      assert_equal(['aaa', 'bbb'], reslist)
2500
2501      # loop over string
2502      res = ''
2503      for c in 'aéc̀d'
2504        res ..= c .. '-'
2505      endfor
2506      assert_equal('a-é-c̀-d-', res)
2507
2508      res = ''
2509      for c in ''
2510        res ..= c .. '-'
2511      endfor
2512      assert_equal('', res)
2513
2514      res = ''
2515      for c in test_null_string()
2516        res ..= c .. '-'
2517      endfor
2518      assert_equal('', res)
2519
2520      var foo: list<dict<any>> = [
2521              {a: 'Cat'}
2522            ]
2523      for dd in foo
2524        dd.counter = 12
2525      endfor
2526      assert_equal([{a: 'Cat', counter: 12}], foo)
2527
2528      reslist = []
2529      for _ in range(3)
2530        reslist->add('x')
2531      endfor
2532      assert_equal(['x', 'x', 'x'], reslist)
2533  END
2534  CheckDefAndScriptSuccess(lines)
2535enddef
2536
2537def Test_for_loop_fails()
2538  CheckDefAndScriptFailure2(['for '], 'E1097:', 'E690:')
2539  CheckDefAndScriptFailure2(['for x'], 'E1097:', 'E690:')
2540  CheckDefAndScriptFailure2(['for x in'], 'E1097:', 'E15:')
2541  CheckDefAndScriptFailure(['for # in range(5)'], 'E690:')
2542  CheckDefAndScriptFailure(['for i In range(5)'], 'E690:')
2543  CheckDefAndScriptFailure2(['var x = 5', 'for x in range(5)', 'endfor'], 'E1017:', 'E1041:')
2544  CheckScriptFailure(['vim9script', 'var x = 5', 'for x in range(5)', '# comment', 'endfor'], 'E1041:', 3)
2545  CheckScriptFailure(['def Func(arg: any)', 'for arg in range(5)', 'enddef', 'defcompile'], 'E1006:')
2546  delfunc! g:Func
2547  CheckDefFailure(['for i in xxx'], 'E1001:')
2548  CheckDefFailure(['endfor'], 'E588:')
2549  CheckDefFailure(['for i in range(3)', 'echo 3'], 'E170:')
2550
2551  # wrong type detected at compile time
2552  CheckDefFailure(['for i in {a: 1}', 'echo 3', 'endfor'], 'E1177: For loop on dict not supported')
2553
2554  # wrong type detected at runtime
2555  g:adict = {a: 1}
2556  CheckDefExecFailure(['for i in g:adict', 'echo 3', 'endfor'], 'E1177: For loop on dict not supported')
2557  unlet g:adict
2558
2559  var lines =<< trim END
2560      var d: list<dict<any>> = [{a: 0}]
2561      for e in d
2562        e = {a: 0, b: ''}
2563      endfor
2564  END
2565  CheckDefAndScriptFailure2(lines, 'E1018:', 'E46:', 3)
2566
2567  lines =<< trim END
2568      for nr: number in ['foo']
2569      endfor
2570  END
2571  CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected number but got string', 1)
2572
2573  lines =<< trim END
2574      for n : number in [1, 2]
2575        echo n
2576      endfor
2577  END
2578  CheckDefAndScriptFailure(lines, 'E1059:', 1)
2579
2580  lines =<< trim END
2581      var d: dict<number> = {a: 1, b: 2}
2582      for [k: job, v: job] in d->items()
2583        echo k v
2584      endfor
2585  END
2586  CheckDefExecAndScriptFailure(lines, 'E1012: Type mismatch; expected job but got string', 2)
2587enddef
2588
2589def Test_for_loop_script_var()
2590  # cannot use s:var in a :def function
2591  CheckDefFailure(['for s:var in range(3)', 'echo 3'], 'E1101:')
2592
2593  # can use s:var in Vim9 script, with or without s:
2594  var lines =<< trim END
2595    vim9script
2596    var total = 0
2597    for s:var in [1, 2, 3]
2598      total += s:var
2599    endfor
2600    assert_equal(6, total)
2601
2602    total = 0
2603    for var in [1, 2, 3]
2604      total += var
2605    endfor
2606    assert_equal(6, total)
2607  END
2608enddef
2609
2610def Test_for_loop_unpack()
2611  var lines =<< trim END
2612      var result = []
2613      for [v1, v2] in [[1, 2], [3, 4]]
2614        result->add(v1)
2615        result->add(v2)
2616      endfor
2617      assert_equal([1, 2, 3, 4], result)
2618
2619      result = []
2620      for [v1, v2; v3] in [[1, 2], [3, 4, 5, 6]]
2621        result->add(v1)
2622        result->add(v2)
2623        result->add(v3)
2624      endfor
2625      assert_equal([1, 2, [], 3, 4, [5, 6]], result)
2626
2627      result = []
2628      for [&ts, &sw] in [[1, 2], [3, 4]]
2629        result->add(&ts)
2630        result->add(&sw)
2631      endfor
2632      assert_equal([1, 2, 3, 4], result)
2633
2634      var slist: list<string>
2635      for [$LOOPVAR, @r, v:errmsg] in [['a', 'b', 'c'], ['d', 'e', 'f']]
2636        slist->add($LOOPVAR)
2637        slist->add(@r)
2638        slist->add(v:errmsg)
2639      endfor
2640      assert_equal(['a', 'b', 'c', 'd', 'e', 'f'], slist)
2641
2642      slist = []
2643      for [g:globalvar, b:bufvar, w:winvar, t:tabvar] in [['global', 'buf', 'win', 'tab'], ['1', '2', '3', '4']]
2644        slist->add(g:globalvar)
2645        slist->add(b:bufvar)
2646        slist->add(w:winvar)
2647        slist->add(t:tabvar)
2648      endfor
2649      assert_equal(['global', 'buf', 'win', 'tab', '1', '2', '3', '4'], slist)
2650      unlet! g:globalvar b:bufvar w:winvar t:tabvar
2651
2652      var res = []
2653      for [_, n, _] in [[1, 2, 3], [4, 5, 6]]
2654        res->add(n)
2655      endfor
2656      assert_equal([2, 5], res)
2657  END
2658  CheckDefAndScriptSuccess(lines)
2659
2660  lines =<< trim END
2661      for [v1, v2] in [[1, 2, 3], [3, 4]]
2662        echo v1 v2
2663      endfor
2664  END
2665  CheckDefExecFailure(lines, 'E710:', 1)
2666
2667  lines =<< trim END
2668      for [v1, v2] in [[1], [3, 4]]
2669        echo v1 v2
2670      endfor
2671  END
2672  CheckDefExecFailure(lines, 'E711:', 1)
2673
2674  lines =<< trim END
2675      for [v1, v1] in [[1, 2], [3, 4]]
2676        echo v1
2677      endfor
2678  END
2679  CheckDefExecFailure(lines, 'E1017:', 1)
2680enddef
2681
2682def Test_for_loop_with_try_continue()
2683  var lines =<< trim END
2684      var looped = 0
2685      var cleanup = 0
2686      for i in range(3)
2687        looped += 1
2688        try
2689          eval [][0]
2690        catch
2691          continue
2692        finally
2693          cleanup += 1
2694        endtry
2695      endfor
2696      assert_equal(3, looped)
2697      assert_equal(3, cleanup)
2698  END
2699  CheckDefAndScriptSuccess(lines)
2700enddef
2701
2702def Test_while_loop()
2703  var result = ''
2704  var cnt = 0
2705  while cnt < 555
2706    if cnt == 3
2707      break
2708    endif
2709    cnt += 1
2710    if cnt == 2
2711      continue
2712    endif
2713    result ..= cnt .. '_'
2714  endwhile
2715  assert_equal('1_3_', result)
2716
2717  var s = ''
2718  while s == 'x' # {comment}
2719  endwhile
2720enddef
2721
2722def Test_while_loop_fails()
2723  CheckDefFailure(['while xxx'], 'E1001:')
2724  CheckDefFailure(['endwhile'], 'E588:')
2725  CheckDefFailure(['continue'], 'E586:')
2726  CheckDefFailure(['if true', 'continue'], 'E586:')
2727  CheckDefFailure(['break'], 'E587:')
2728  CheckDefFailure(['if true', 'break'], 'E587:')
2729  CheckDefFailure(['while 1', 'echo 3'], 'E170:')
2730
2731  var lines =<< trim END
2732      var s = ''
2733      while s = ''
2734      endwhile
2735  END
2736  CheckDefFailure(lines, 'E488:')
2737enddef
2738
2739def Test_interrupt_loop()
2740  var caught = false
2741  var x = 0
2742  try
2743    while 1
2744      x += 1
2745      if x == 100
2746        feedkeys("\<C-C>", 'Lt')
2747      endif
2748    endwhile
2749  catch
2750    caught = true
2751    assert_equal(100, x)
2752  endtry
2753  assert_true(caught, 'should have caught an exception')
2754  # consume the CTRL-C
2755  getchar(0)
2756enddef
2757
2758def Test_automatic_line_continuation()
2759  var mylist = [
2760      'one',
2761      'two',
2762      'three',
2763      ] # comment
2764  assert_equal(['one', 'two', 'three'], mylist)
2765
2766  var mydict = {
2767      ['one']: 1,
2768      ['two']: 2,
2769      ['three']:
2770          3,
2771      } # comment
2772  assert_equal({one: 1, two: 2, three: 3}, mydict)
2773  mydict = {
2774      one: 1,  # comment
2775      two:     # comment
2776           2,  # comment
2777      three: 3 # comment
2778      }
2779  assert_equal({one: 1, two: 2, three: 3}, mydict)
2780  mydict = {
2781      one: 1,
2782      two:
2783           2,
2784      three: 3
2785      }
2786  assert_equal({one: 1, two: 2, three: 3}, mydict)
2787
2788  assert_equal(
2789        ['one', 'two', 'three'],
2790        split('one two three')
2791        )
2792enddef
2793
2794def Test_vim9_comment()
2795  CheckScriptSuccess([
2796      'vim9script',
2797      '# something',
2798      '#something',
2799      '#{something',
2800      ])
2801
2802  split Xfile
2803  CheckScriptSuccess([
2804      'vim9script',
2805      'edit #something',
2806      ])
2807  CheckScriptSuccess([
2808      'vim9script',
2809      'edit #{something',
2810      ])
2811  close
2812
2813  CheckScriptFailure([
2814      'vim9script',
2815      ':# something',
2816      ], 'E488:')
2817  CheckScriptFailure([
2818      '# something',
2819      ], 'E488:')
2820  CheckScriptFailure([
2821      ':# something',
2822      ], 'E488:')
2823
2824  { # block start
2825  } # block end
2826  CheckDefFailure([
2827      '{# comment',
2828      ], 'E488:')
2829  CheckDefFailure([
2830      '{',
2831      '}# comment',
2832      ], 'E488:')
2833
2834  echo "yes" # comment
2835  CheckDefFailure([
2836      'echo "yes"# comment',
2837      ], 'E488:')
2838  CheckScriptSuccess([
2839      'vim9script',
2840      'echo "yes" # something',
2841      ])
2842  CheckScriptFailure([
2843      'vim9script',
2844      'echo "yes"# something',
2845      ], 'E121:')
2846  CheckScriptFailure([
2847      'vim9script',
2848      'echo# something',
2849      ], 'E1144:')
2850  CheckScriptFailure([
2851      'echo "yes" # something',
2852      ], 'E121:')
2853
2854  exe "echo" # comment
2855  CheckDefFailure([
2856      'exe "echo"# comment',
2857      ], 'E488:')
2858  CheckScriptSuccess([
2859      'vim9script',
2860      'exe "echo" # something',
2861      ])
2862  CheckScriptFailure([
2863      'vim9script',
2864      'exe "echo"# something',
2865      ], 'E121:')
2866  CheckScriptFailure([
2867      'vim9script',
2868      'exe# something',
2869      ], 'E1144:')
2870  CheckScriptFailure([
2871      'exe "echo" # something',
2872      ], 'E121:')
2873
2874  CheckDefFailure([
2875      'try# comment',
2876      '  echo "yes"',
2877      'catch',
2878      'endtry',
2879      ], 'E1144:')
2880  CheckScriptFailure([
2881      'vim9script',
2882      'try# comment',
2883      'echo "yes"',
2884      ], 'E1144:')
2885  CheckDefFailure([
2886      'try',
2887      '  throw#comment',
2888      'catch',
2889      'endtry',
2890      ], 'E1144:')
2891  CheckDefFailure([
2892      'try',
2893      '  throw "yes"#comment',
2894      'catch',
2895      'endtry',
2896      ], 'E488:')
2897  CheckDefFailure([
2898      'try',
2899      '  echo "yes"',
2900      'catch# comment',
2901      'endtry',
2902      ], 'E1144:')
2903  CheckScriptFailure([
2904      'vim9script',
2905      'try',
2906      '  echo "yes"',
2907      'catch# comment',
2908      'endtry',
2909      ], 'E1144:')
2910  CheckDefFailure([
2911      'try',
2912      '  echo "yes"',
2913      'catch /pat/# comment',
2914      'endtry',
2915      ], 'E488:')
2916  CheckDefFailure([
2917      'try',
2918      'echo "yes"',
2919      'catch',
2920      'endtry# comment',
2921      ], 'E1144:')
2922  CheckScriptFailure([
2923      'vim9script',
2924      'try',
2925      '  echo "yes"',
2926      'catch',
2927      'endtry# comment',
2928      ], 'E1144:')
2929
2930  CheckScriptSuccess([
2931      'vim9script',
2932      'hi # comment',
2933      ])
2934  CheckScriptFailure([
2935      'vim9script',
2936      'hi# comment',
2937      ], 'E1144:')
2938  CheckScriptSuccess([
2939      'vim9script',
2940      'hi Search # comment',
2941      ])
2942  CheckScriptFailure([
2943      'vim9script',
2944      'hi Search# comment',
2945      ], 'E416:')
2946  CheckScriptSuccess([
2947      'vim9script',
2948      'hi link This Search # comment',
2949      ])
2950  CheckScriptFailure([
2951      'vim9script',
2952      'hi link This That# comment',
2953      ], 'E413:')
2954  CheckScriptSuccess([
2955      'vim9script',
2956      'hi clear This # comment',
2957      'hi clear # comment',
2958      ])
2959  # not tested, because it doesn't give an error but a warning:
2960  # hi clear This# comment',
2961  CheckScriptFailure([
2962      'vim9script',
2963      'hi clear# comment',
2964      ], 'E416:')
2965
2966  CheckScriptSuccess([
2967      'vim9script',
2968      'hi Group term=bold',
2969      'match Group /todo/ # comment',
2970      ])
2971  CheckScriptFailure([
2972      'vim9script',
2973      'hi Group term=bold',
2974      'match Group /todo/# comment',
2975      ], 'E488:')
2976  CheckScriptSuccess([
2977      'vim9script',
2978      'match # comment',
2979      ])
2980  CheckScriptFailure([
2981      'vim9script',
2982      'match# comment',
2983      ], 'E1144:')
2984  CheckScriptSuccess([
2985      'vim9script',
2986      'match none # comment',
2987      ])
2988  CheckScriptFailure([
2989      'vim9script',
2990      'match none# comment',
2991      ], 'E475:')
2992
2993  CheckScriptSuccess([
2994      'vim9script',
2995      'menutrans clear # comment',
2996      ])
2997  CheckScriptFailure([
2998      'vim9script',
2999      'menutrans clear# comment text',
3000      ], 'E474:')
3001
3002  CheckScriptSuccess([
3003      'vim9script',
3004      'syntax clear # comment',
3005      ])
3006  CheckScriptFailure([
3007      'vim9script',
3008      'syntax clear# comment text',
3009      ], 'E28:')
3010  CheckScriptSuccess([
3011      'vim9script',
3012      'syntax keyword Word some',
3013      'syntax clear Word # comment',
3014      ])
3015  CheckScriptFailure([
3016      'vim9script',
3017      'syntax keyword Word some',
3018      'syntax clear Word# comment text',
3019      ], 'E28:')
3020
3021  CheckScriptSuccess([
3022      'vim9script',
3023      'syntax list # comment',
3024      ])
3025  CheckScriptFailure([
3026      'vim9script',
3027      'syntax list# comment text',
3028      ], 'E28:')
3029
3030  CheckScriptSuccess([
3031      'vim9script',
3032      'syntax match Word /pat/ oneline # comment',
3033      ])
3034  CheckScriptFailure([
3035      'vim9script',
3036      'syntax match Word /pat/ oneline# comment',
3037      ], 'E475:')
3038
3039  CheckScriptSuccess([
3040      'vim9script',
3041      'syntax keyword Word word # comm[ent',
3042      ])
3043  CheckScriptFailure([
3044      'vim9script',
3045      'syntax keyword Word word# comm[ent',
3046      ], 'E789:')
3047
3048  CheckScriptSuccess([
3049      'vim9script',
3050      'syntax match Word /pat/ # comment',
3051      ])
3052  CheckScriptFailure([
3053      'vim9script',
3054      'syntax match Word /pat/# comment',
3055      ], 'E402:')
3056
3057  CheckScriptSuccess([
3058      'vim9script',
3059      'syntax match Word /pat/ contains=Something # comment',
3060      ])
3061  CheckScriptFailure([
3062      'vim9script',
3063      'syntax match Word /pat/ contains=Something# comment',
3064      ], 'E475:')
3065  CheckScriptFailure([
3066      'vim9script',
3067      'syntax match Word /pat/ contains= # comment',
3068      ], 'E406:')
3069  CheckScriptFailure([
3070      'vim9script',
3071      'syntax match Word /pat/ contains=# comment',
3072      ], 'E475:')
3073
3074  CheckScriptSuccess([
3075      'vim9script',
3076      'syntax region Word start=/pat/ end=/pat/ # comment',
3077      ])
3078  CheckScriptFailure([
3079      'vim9script',
3080      'syntax region Word start=/pat/ end=/pat/# comment',
3081      ], 'E402:')
3082
3083  CheckScriptSuccess([
3084      'vim9script',
3085      'syntax sync # comment',
3086      ])
3087  CheckScriptFailure([
3088      'vim9script',
3089      'syntax sync# comment',
3090      ], 'E404:')
3091  CheckScriptSuccess([
3092      'vim9script',
3093      'syntax sync ccomment # comment',
3094      ])
3095  CheckScriptFailure([
3096      'vim9script',
3097      'syntax sync ccomment# comment',
3098      ], 'E404:')
3099
3100  CheckScriptSuccess([
3101      'vim9script',
3102      'syntax cluster Some contains=Word # comment',
3103      ])
3104  CheckScriptFailure([
3105      'vim9script',
3106      'syntax cluster Some contains=Word# comment',
3107      ], 'E475:')
3108
3109  CheckScriptSuccess([
3110      'vim9script',
3111      'command Echo echo # comment',
3112      'command Echo # comment',
3113      'delcommand Echo',
3114      ])
3115  CheckScriptFailure([
3116      'vim9script',
3117      'command Echo echo# comment',
3118      'Echo',
3119      ], 'E1144:')
3120  delcommand Echo
3121
3122  var curdir = getcwd()
3123  CheckScriptSuccess([
3124      'command Echo cd " comment',
3125      'Echo',
3126      'delcommand Echo',
3127      ])
3128  CheckScriptSuccess([
3129      'vim9script',
3130      'command Echo cd # comment',
3131      'Echo',
3132      'delcommand Echo',
3133      ])
3134  CheckScriptFailure([
3135      'vim9script',
3136      'command Echo cd " comment',
3137      'Echo',
3138      ], 'E344:')
3139  delcommand Echo
3140  chdir(curdir)
3141
3142  CheckScriptFailure([
3143      'vim9script',
3144      'command Echo# comment',
3145      ], 'E182:')
3146  CheckScriptFailure([
3147      'vim9script',
3148      'command Echo echo',
3149      'command Echo# comment',
3150      ], 'E182:')
3151  delcommand Echo
3152
3153  CheckScriptSuccess([
3154      'vim9script',
3155      'function # comment',
3156      ])
3157  CheckScriptFailure([
3158      'vim9script',
3159      'function " comment',
3160      ], 'E129:')
3161  CheckScriptFailure([
3162      'vim9script',
3163      'function# comment',
3164      ], 'E1144:')
3165  CheckScriptSuccess([
3166      'vim9script',
3167      'function CheckScriptSuccess # comment',
3168      ])
3169  CheckScriptFailure([
3170      'vim9script',
3171      'function CheckScriptSuccess# comment',
3172      ], 'E488:')
3173
3174  CheckScriptSuccess([
3175      'vim9script',
3176      'func g:DeleteMeA()',
3177      'endfunc',
3178      'delfunction g:DeleteMeA # comment',
3179      ])
3180  CheckScriptFailure([
3181      'vim9script',
3182      'func g:DeleteMeB()',
3183      'endfunc',
3184      'delfunction g:DeleteMeB# comment',
3185      ], 'E488:')
3186
3187  CheckScriptSuccess([
3188      'vim9script',
3189      'call execute("ls") # comment',
3190      ])
3191  CheckScriptFailure([
3192      'vim9script',
3193      'call execute("ls")# comment',
3194      ], 'E488:')
3195
3196  CheckScriptFailure([
3197      'def Test() " comment',
3198      'enddef',
3199      ], 'E488:')
3200  CheckScriptFailure([
3201      'vim9script',
3202      'def Test() " comment',
3203      'enddef',
3204      ], 'E488:')
3205
3206  CheckScriptSuccess([
3207      'func Test() " comment',
3208      'endfunc',
3209      'delfunc Test',
3210      ])
3211  CheckScriptSuccess([
3212      'vim9script',
3213      'func Test() " comment',
3214      'endfunc',
3215      ])
3216
3217  CheckScriptSuccess([
3218      'def Test() # comment',
3219      'enddef',
3220      ])
3221  CheckScriptFailure([
3222      'func Test() # comment',
3223      'endfunc',
3224      ], 'E488:')
3225
3226  var lines =<< trim END
3227      vim9script
3228      syn region Text
3229      \ start='foo'
3230      #\ comment
3231      \ end='bar'
3232      syn region Text start='foo'
3233      #\ comment
3234      \ end='bar'
3235  END
3236  CheckScriptSuccess(lines)
3237
3238  lines =<< trim END
3239      vim9script
3240      syn region Text
3241      \ start='foo'
3242      "\ comment
3243      \ end='bar'
3244  END
3245  CheckScriptFailure(lines, 'E399:')
3246enddef
3247
3248def Test_vim9_comment_gui()
3249  CheckCanRunGui
3250
3251  CheckScriptFailure([
3252      'vim9script',
3253      'gui#comment'
3254      ], 'E1144:')
3255  CheckScriptFailure([
3256      'vim9script',
3257      'gui -f#comment'
3258      ], 'E499:')
3259enddef
3260
3261def Test_vim9_comment_not_compiled()
3262  au TabEnter *.vim g:entered = 1
3263  au TabEnter *.x g:entered = 2
3264
3265  edit test.vim
3266  doautocmd TabEnter #comment
3267  assert_equal(1, g:entered)
3268
3269  doautocmd TabEnter f.x
3270  assert_equal(2, g:entered)
3271
3272  g:entered = 0
3273  doautocmd TabEnter f.x #comment
3274  assert_equal(2, g:entered)
3275
3276  assert_fails('doautocmd Syntax#comment', 'E216:')
3277
3278  au! TabEnter
3279  unlet g:entered
3280
3281  CheckScriptSuccess([
3282      'vim9script',
3283      'g:var = 123',
3284      'b:var = 456',
3285      'w:var = 777',
3286      't:var = 888',
3287      'unlet g:var w:var # something',
3288      ])
3289
3290  CheckScriptFailure([
3291      'vim9script',
3292      'let var = 123',
3293      ], 'E1126: Cannot use :let in Vim9 script')
3294
3295  CheckScriptFailure([
3296      'vim9script',
3297      'var g:var = 123',
3298      ], 'E1016: Cannot declare a global variable:')
3299
3300  CheckScriptFailure([
3301      'vim9script',
3302      'var b:var = 123',
3303      ], 'E1016: Cannot declare a buffer variable:')
3304
3305  CheckScriptFailure([
3306      'vim9script',
3307      'var w:var = 123',
3308      ], 'E1016: Cannot declare a window variable:')
3309
3310  CheckScriptFailure([
3311      'vim9script',
3312      'var t:var = 123',
3313      ], 'E1016: Cannot declare a tab variable:')
3314
3315  CheckScriptFailure([
3316      'vim9script',
3317      'var v:version = 123',
3318      ], 'E1016: Cannot declare a v: variable:')
3319
3320  CheckScriptFailure([
3321      'vim9script',
3322      'var $VARIABLE = "text"',
3323      ], 'E1016: Cannot declare an environment variable:')
3324
3325  CheckScriptFailure([
3326      'vim9script',
3327      'g:var = 123',
3328      'unlet g:var# comment1',
3329      ], 'E108:')
3330
3331  CheckScriptFailure([
3332      'let g:var = 123',
3333      'unlet g:var # something',
3334      ], 'E488:')
3335
3336  CheckScriptSuccess([
3337      'vim9script',
3338      'if 1 # comment2',
3339      '  echo "yes"',
3340      'elseif 2 #comment',
3341      '  echo "no"',
3342      'endif',
3343      ])
3344
3345  CheckScriptFailure([
3346      'vim9script',
3347      'if 1# comment3',
3348      '  echo "yes"',
3349      'endif',
3350      ], 'E488:')
3351
3352  CheckScriptFailure([
3353      'vim9script',
3354      'if 0 # comment4',
3355      '  echo "yes"',
3356      'elseif 2#comment',
3357      '  echo "no"',
3358      'endif',
3359      ], 'E488:')
3360
3361  CheckScriptSuccess([
3362      'vim9script',
3363      'var v = 1 # comment5',
3364      ])
3365
3366  CheckScriptFailure([
3367      'vim9script',
3368      'var v = 1# comment6',
3369      ], 'E488:')
3370
3371  CheckScriptSuccess([
3372      'vim9script',
3373      'new'
3374      'setline(1, ["# define pat", "last"])',
3375      ':$',
3376      'dsearch /pat/ #comment',
3377      'bwipe!',
3378      ])
3379
3380  CheckScriptFailure([
3381      'vim9script',
3382      'new'
3383      'setline(1, ["# define pat", "last"])',
3384      ':$',
3385      'dsearch /pat/#comment',
3386      'bwipe!',
3387      ], 'E488:')
3388
3389  CheckScriptFailure([
3390      'vim9script',
3391      'func! SomeFunc()',
3392      ], 'E477:')
3393enddef
3394
3395def Test_finish()
3396  var lines =<< trim END
3397    vim9script
3398    g:res = 'one'
3399    if v:false | finish | endif
3400    g:res = 'two'
3401    finish
3402    g:res = 'three'
3403  END
3404  writefile(lines, 'Xfinished')
3405  source Xfinished
3406  assert_equal('two', g:res)
3407
3408  unlet g:res
3409  delete('Xfinished')
3410enddef
3411
3412def Test_forward_declaration()
3413  var lines =<< trim END
3414    vim9script
3415    def GetValue(): string
3416      return theVal
3417    enddef
3418    var theVal = 'something'
3419    g:initVal = GetValue()
3420    theVal = 'else'
3421    g:laterVal = GetValue()
3422  END
3423  writefile(lines, 'Xforward')
3424  source Xforward
3425  assert_equal('something', g:initVal)
3426  assert_equal('else', g:laterVal)
3427
3428  unlet g:initVal
3429  unlet g:laterVal
3430  delete('Xforward')
3431enddef
3432
3433def Test_source_vim9_from_legacy()
3434  var vim9_lines =<< trim END
3435    vim9script
3436    var local = 'local'
3437    g:global = 'global'
3438    export var exported = 'exported'
3439    export def GetText(): string
3440       return 'text'
3441    enddef
3442  END
3443  writefile(vim9_lines, 'Xvim9_script.vim')
3444
3445  var legacy_lines =<< trim END
3446    source Xvim9_script.vim
3447
3448    call assert_false(exists('local'))
3449    call assert_false(exists('exported'))
3450    call assert_false(exists('s:exported'))
3451    call assert_equal('global', global)
3452    call assert_equal('global', g:global)
3453
3454    " imported variable becomes script-local
3455    import exported from './Xvim9_script.vim'
3456    call assert_equal('exported', s:exported)
3457    call assert_false(exists('exported'))
3458
3459    " imported function becomes script-local
3460    import GetText from './Xvim9_script.vim'
3461    call assert_equal('text', s:GetText())
3462    call assert_false(exists('*GetText'))
3463  END
3464  writefile(legacy_lines, 'Xlegacy_script.vim')
3465
3466  source Xlegacy_script.vim
3467  assert_equal('global', g:global)
3468  unlet g:global
3469
3470  delete('Xlegacy_script.vim')
3471  delete('Xvim9_script.vim')
3472enddef
3473
3474def Test_declare_script_in_func()
3475  var lines =<< trim END
3476      vim9script
3477      func Declare()
3478        let s:local = 123
3479      endfunc
3480      Declare()
3481      assert_equal(123, local)
3482
3483      var error: string
3484      try
3485        local = 'asdf'
3486      catch
3487        error = v:exception
3488      endtry
3489      assert_match('E1012: Type mismatch; expected number but got string', error)
3490
3491      lockvar local
3492      try
3493        local = 999
3494      catch
3495        error = v:exception
3496      endtry
3497      assert_match('E741: Value is locked: local', error)
3498  END
3499  CheckScriptSuccess(lines)
3500enddef
3501
3502
3503func Test_vim9script_not_global()
3504  " check that items defined in Vim9 script are script-local, not global
3505  let vim9lines =<< trim END
3506    vim9script
3507    var name = 'local'
3508    func TheFunc()
3509      echo 'local'
3510    endfunc
3511    def DefFunc()
3512      echo 'local'
3513    enddef
3514  END
3515  call writefile(vim9lines, 'Xvim9script.vim')
3516  source Xvim9script.vim
3517  try
3518    echo g:var
3519    assert_report('did not fail')
3520  catch /E121:/
3521    " caught
3522  endtry
3523  try
3524    call TheFunc()
3525    assert_report('did not fail')
3526  catch /E117:/
3527    " caught
3528  endtry
3529  try
3530    call DefFunc()
3531    assert_report('did not fail')
3532  catch /E117:/
3533    " caught
3534  endtry
3535
3536  call delete('Xvim9script.vim')
3537endfunc
3538
3539def Test_vim9_copen()
3540  # this was giving an error for setting w:quickfix_title
3541  copen
3542  quit
3543enddef
3544
3545" test using an auto-loaded function and variable
3546def Test_vim9_autoload()
3547  var lines =<< trim END
3548     vim9script
3549     def some#gettest(): string
3550       return 'test'
3551     enddef
3552     g:some#name = 'name'
3553     g:some#dict = {key: 'value'}
3554
3555     def some#varargs(a1: string, ...l: list<string>): string
3556       return a1 .. l[0] .. l[1]
3557     enddef
3558  END
3559
3560  mkdir('Xdir/autoload', 'p')
3561  writefile(lines, 'Xdir/autoload/some.vim')
3562  var save_rtp = &rtp
3563  exe 'set rtp^=' .. getcwd() .. '/Xdir'
3564
3565  assert_equal('test', g:some#gettest())
3566  assert_equal('name', g:some#name)
3567  assert_equal('value', g:some#dict.key)
3568  g:some#other = 'other'
3569  assert_equal('other', g:some#other)
3570
3571  assert_equal('abc', some#varargs('a', 'b', 'c'))
3572
3573  # upper case script name works
3574  lines =<< trim END
3575     vim9script
3576     def Other#getOther(): string
3577       return 'other'
3578     enddef
3579  END
3580  writefile(lines, 'Xdir/autoload/Other.vim')
3581  assert_equal('other', g:Other#getOther())
3582
3583  delete('Xdir', 'rf')
3584  &rtp = save_rtp
3585enddef
3586
3587" test using a vim9script that is auto-loaded from an autocmd
3588def Test_vim9_aucmd_autoload()
3589  var lines =<< trim END
3590     vim9script
3591     def foo#test()
3592         echomsg getreg('"')
3593     enddef
3594  END
3595
3596  mkdir('Xdir/autoload', 'p')
3597  writefile(lines, 'Xdir/autoload/foo.vim')
3598  var save_rtp = &rtp
3599  exe 'set rtp^=' .. getcwd() .. '/Xdir'
3600  augroup test
3601    autocmd TextYankPost * call foo#test()
3602  augroup END
3603
3604  normal Y
3605
3606  augroup test
3607    autocmd!
3608  augroup END
3609  delete('Xdir', 'rf')
3610  &rtp = save_rtp
3611enddef
3612
3613" This was causing a crash because suppress_errthrow wasn't reset.
3614def Test_vim9_autoload_error()
3615  var lines =<< trim END
3616      vim9script
3617      def crash#func()
3618          try
3619              for x in List()
3620              endfor
3621          catch
3622          endtry
3623          g:ok = true
3624      enddef
3625      fu List()
3626          invalid
3627      endfu
3628      try
3629          alsoinvalid
3630      catch /wontmatch/
3631      endtry
3632  END
3633  call mkdir('Xruntime/autoload', 'p')
3634  call writefile(lines, 'Xruntime/autoload/crash.vim')
3635
3636  # run in a separate Vim to avoid the side effects of assert_fails()
3637  lines =<< trim END
3638    exe 'set rtp^=' .. getcwd() .. '/Xruntime'
3639    call crash#func()
3640    call writefile(['ok'], 'Xdidit')
3641    qall!
3642  END
3643  writefile(lines, 'Xscript')
3644  RunVim([], [], '-S Xscript')
3645  assert_equal(['ok'], readfile('Xdidit'))
3646
3647  delete('Xdidit')
3648  delete('Xscript')
3649  delete('Xruntime', 'rf')
3650
3651  lines =<< trim END
3652    vim9script
3653    var foo#bar = 'asdf'
3654  END
3655  CheckScriptFailure(lines, 'E461: Illegal variable name: foo#bar', 2)
3656enddef
3657
3658def Test_script_var_in_autocmd()
3659  # using a script variable from an autocommand, defined in a :def function in a
3660  # legacy Vim script, cannot check the variable type.
3661  var lines =<< trim END
3662    let s:counter = 1
3663    def s:Func()
3664      au! CursorHold
3665      au CursorHold * s:counter += 1
3666    enddef
3667    call s:Func()
3668    doau CursorHold
3669    call assert_equal(2, s:counter)
3670    au! CursorHold
3671  END
3672  CheckScriptSuccess(lines)
3673enddef
3674
3675def Test_error_in_autoload_script()
3676  var save_rtp = &rtp
3677  var dir = getcwd() .. '/Xruntime'
3678  &rtp = dir
3679  mkdir(dir .. '/autoload', 'p')
3680
3681  var lines =<< trim END
3682      vim9script noclear
3683      def script#autoloaded()
3684      enddef
3685      def Broken()
3686        var x: any = ''
3687        eval x != 0
3688      enddef
3689      Broken()
3690  END
3691  writefile(lines, dir .. '/autoload/script.vim')
3692
3693  lines =<< trim END
3694      vim9script
3695      def CallAutoloaded()
3696        script#autoloaded()
3697      enddef
3698
3699      function Legacy()
3700        try
3701          call s:CallAutoloaded()
3702        catch
3703          call assert_match('E1030: Using a String as a Number', v:exception)
3704        endtry
3705      endfunction
3706
3707      Legacy()
3708  END
3709  CheckScriptSuccess(lines)
3710
3711  &rtp = save_rtp
3712  delete(dir, 'rf')
3713enddef
3714
3715def Test_cmdline_win()
3716  # if the Vim syntax highlighting uses Vim9 constructs they can be used from
3717  # the command line window.
3718  mkdir('rtp/syntax', 'p')
3719  var export_lines =<< trim END
3720    vim9script
3721    export var That = 'yes'
3722  END
3723  writefile(export_lines, 'rtp/syntax/Xexport.vim')
3724  var import_lines =<< trim END
3725    vim9script
3726    import That from './Xexport.vim'
3727  END
3728  writefile(import_lines, 'rtp/syntax/vim.vim')
3729  var save_rtp = &rtp
3730  &rtp = getcwd() .. '/rtp' .. ',' .. &rtp
3731  syntax on
3732  augroup CmdWin
3733    autocmd CmdwinEnter * g:got_there = 'yes'
3734  augroup END
3735  # this will open and also close the cmdline window
3736  feedkeys('q:', 'xt')
3737  assert_equal('yes', g:got_there)
3738
3739  augroup CmdWin
3740    au!
3741  augroup END
3742  &rtp = save_rtp
3743  delete('rtp', 'rf')
3744enddef
3745
3746def Test_invalid_sid()
3747  assert_fails('func <SNR>1234_func', 'E123:')
3748
3749  if RunVim([], ['wq! Xdidit'], '+"func <SNR>1_func"')
3750    assert_equal([], readfile('Xdidit'))
3751  endif
3752  delete('Xdidit')
3753enddef
3754
3755def Test_restoring_cpo()
3756  writefile(['vim9script', 'set nocp'], 'Xsourced')
3757  writefile(['call writefile(["done"], "Xdone")', 'quit!'], 'Xclose')
3758  if RunVim([], [], '-u NONE +"set cpo+=a" -S Xsourced -S Xclose')
3759    assert_equal(['done'], readfile('Xdone'))
3760  endif
3761  delete('Xsourced')
3762  delete('Xclose')
3763  delete('Xdone')
3764
3765  writefile(['vim9script'], 'XanotherScript')
3766  set cpo=aABceFsMny>
3767  edit XanotherScript
3768  so %
3769  assert_equal('aABceFsMny>', &cpo)
3770  :1del
3771  w
3772  so %
3773  assert_equal('aABceFsMny>', &cpo)
3774
3775  delete('XanotherScript')
3776  set cpo&vim
3777enddef
3778
3779" Use :function so we can use Check commands
3780func Test_no_redraw_when_restoring_cpo()
3781  CheckScreendump
3782  CheckFeature timers
3783
3784  let lines =<< trim END
3785    vim9script
3786    def script#func()
3787    enddef
3788  END
3789  call mkdir('Xdir/autoload', 'p')
3790  call writefile(lines, 'Xdir/autoload/script.vim')
3791
3792  let lines =<< trim END
3793      vim9script
3794      set cpo+=M
3795      exe 'set rtp^=' .. getcwd() .. '/Xdir'
3796      au CmdlineEnter : ++once timer_start(0, (_) => script#func())
3797      setline(1, 'some text')
3798  END
3799  call writefile(lines, 'XTest_redraw_cpo')
3800  let buf = RunVimInTerminal('-S XTest_redraw_cpo', {'rows': 6})
3801  call term_sendkeys(buf, "V:")
3802  call VerifyScreenDump(buf, 'Test_vim9_no_redraw', {})
3803
3804  " clean up
3805  call term_sendkeys(buf, "\<Esc>u")
3806  call StopVimInTerminal(buf)
3807  call delete('XTest_redraw_cpo')
3808  call delete('Xdir', 'rf')
3809endfunc
3810
3811
3812def Test_unset_any_variable()
3813  var lines =<< trim END
3814    var name: any
3815    assert_equal(0, name)
3816  END
3817  CheckDefAndScriptSuccess(lines)
3818enddef
3819
3820func Test_define_func_at_command_line()
3821  CheckRunVimInTerminal
3822
3823  " call indirectly to avoid compilation error for missing functions
3824  call Run_Test_define_func_at_command_line()
3825endfunc
3826
3827def Run_Test_define_func_at_command_line()
3828  # run in a separate Vim instance to avoid the script context
3829  var lines =<< trim END
3830    func CheckAndQuit()
3831      call assert_fails('call Afunc()', 'E117: Unknown function: Bfunc')
3832      call writefile(['errors: ' .. string(v:errors)], 'Xdidcmd')
3833    endfunc
3834  END
3835  writefile([''], 'Xdidcmd')
3836  writefile(lines, 'XcallFunc')
3837  var buf = RunVimInTerminal('-S XcallFunc', {rows: 6})
3838  # define Afunc() on the command line
3839  term_sendkeys(buf, ":def Afunc()\<CR>Bfunc()\<CR>enddef\<CR>")
3840  term_sendkeys(buf, ":call CheckAndQuit()\<CR>")
3841  WaitForAssert(() => assert_equal(['errors: []'], readfile('Xdidcmd')))
3842
3843  call StopVimInTerminal(buf)
3844  delete('XcallFunc')
3845  delete('Xdidcmd')
3846enddef
3847
3848def Test_script_var_scope()
3849  var lines =<< trim END
3850      vim9script
3851      if true
3852        if true
3853          var one = 'one'
3854          echo one
3855        endif
3856        echo one
3857      endif
3858  END
3859  CheckScriptFailure(lines, 'E121:', 7)
3860
3861  lines =<< trim END
3862      vim9script
3863      if true
3864        if false
3865          var one = 'one'
3866          echo one
3867        else
3868          var one = 'one'
3869          echo one
3870        endif
3871        echo one
3872      endif
3873  END
3874  CheckScriptFailure(lines, 'E121:', 10)
3875
3876  lines =<< trim END
3877      vim9script
3878      while true
3879        var one = 'one'
3880        echo one
3881        break
3882      endwhile
3883      echo one
3884  END
3885  CheckScriptFailure(lines, 'E121:', 7)
3886
3887  lines =<< trim END
3888      vim9script
3889      for i in range(1)
3890        var one = 'one'
3891        echo one
3892      endfor
3893      echo one
3894  END
3895  CheckScriptFailure(lines, 'E121:', 6)
3896
3897  lines =<< trim END
3898      vim9script
3899      {
3900        var one = 'one'
3901        assert_equal('one', one)
3902      }
3903      assert_false(exists('one'))
3904      assert_false(exists('s:one'))
3905  END
3906  CheckScriptSuccess(lines)
3907
3908  lines =<< trim END
3909      vim9script
3910      {
3911        var one = 'one'
3912        echo one
3913      }
3914      echo one
3915  END
3916  CheckScriptFailure(lines, 'E121:', 6)
3917enddef
3918
3919def Test_catch_exception_in_callback()
3920  var lines =<< trim END
3921    vim9script
3922    def Callback(...l: list<any>)
3923      try
3924        var x: string
3925        var y: string
3926        # this error should be caught with CHECKLEN
3927        [x, y] = ['']
3928      catch
3929        g:caught = 'yes'
3930      endtry
3931    enddef
3932    popup_menu('popup', {callback: Callback})
3933    feedkeys("\r", 'xt')
3934  END
3935  CheckScriptSuccess(lines)
3936
3937  unlet g:caught
3938enddef
3939
3940def Test_no_unknown_error_after_error()
3941  if !has('unix') || !has('job')
3942    throw 'Skipped: not unix of missing +job feature'
3943  endif
3944  var lines =<< trim END
3945      vim9script
3946      var source: list<number>
3947      def Out_cb(...l: list<any>)
3948          eval [][0]
3949      enddef
3950      def Exit_cb(...l: list<any>)
3951          sleep 1m
3952          source += l
3953      enddef
3954      var myjob = job_start('echo burp', {out_cb: Out_cb, exit_cb: Exit_cb, mode: 'raw'})
3955      while job_status(myjob) == 'run'
3956        sleep 10m
3957      endwhile
3958      # wait for Exit_cb() to be called
3959      sleep 200m
3960  END
3961  writefile(lines, 'Xdef')
3962  assert_fails('so Xdef', ['E684:', 'E1012:'])
3963  delete('Xdef')
3964enddef
3965
3966def InvokeNormal()
3967  exe "norm! :m+1\r"
3968enddef
3969
3970def Test_invoke_normal_in_visual_mode()
3971  xnoremap <F3> <Cmd>call <SID>InvokeNormal()<CR>
3972  new
3973  setline(1, ['aaa', 'bbb'])
3974  feedkeys("V\<F3>", 'xt')
3975  assert_equal(['bbb', 'aaa'], getline(1, 2))
3976  xunmap <F3>
3977enddef
3978
3979def Test_white_space_after_command()
3980  var lines =<< trim END
3981    exit_cb: Func})
3982  END
3983  CheckDefAndScriptFailure(lines, 'E1144:', 1)
3984
3985  lines =<< trim END
3986    e#
3987  END
3988  CheckDefAndScriptFailure(lines, 'E1144:', 1)
3989enddef
3990
3991def Test_script_var_gone_when_sourced_twice()
3992  var lines =<< trim END
3993      vim9script
3994      if exists('g:guard')
3995        finish
3996      endif
3997      g:guard = 1
3998      var name = 'thename'
3999      def g:GetName(): string
4000        return name
4001      enddef
4002      def g:SetName(arg: string)
4003        name = arg
4004      enddef
4005  END
4006  writefile(lines, 'XscriptTwice.vim')
4007  so XscriptTwice.vim
4008  assert_equal('thename', g:GetName())
4009  g:SetName('newname')
4010  assert_equal('newname', g:GetName())
4011  so XscriptTwice.vim
4012  assert_fails('call g:GetName()', 'E1149:')
4013  assert_fails('call g:SetName("x")', 'E1149:')
4014
4015  delfunc g:GetName
4016  delfunc g:SetName
4017  delete('XscriptTwice.vim')
4018  unlet g:guard
4019enddef
4020
4021def Test_import_gone_when_sourced_twice()
4022  var exportlines =<< trim END
4023      vim9script
4024      if exists('g:guard')
4025        finish
4026      endif
4027      g:guard = 1
4028      export var name = 'someName'
4029  END
4030  writefile(exportlines, 'XexportScript.vim')
4031
4032  var lines =<< trim END
4033      vim9script
4034      import name from './XexportScript.vim'
4035      def g:GetName(): string
4036        return name
4037      enddef
4038  END
4039  writefile(lines, 'XscriptImport.vim')
4040  so XscriptImport.vim
4041  assert_equal('someName', g:GetName())
4042
4043  so XexportScript.vim
4044  assert_fails('call g:GetName()', 'E1149:')
4045
4046  delfunc g:GetName
4047  delete('XexportScript.vim')
4048  delete('XscriptImport.vim')
4049  unlet g:guard
4050enddef
4051
4052def Test_unsupported_commands()
4053  var lines =<< trim END
4054      ka
4055  END
4056  CheckDefFailure(lines, 'E476:')
4057  CheckScriptFailure(['vim9script'] + lines, 'E492:')
4058
4059  lines =<< trim END
4060      :1ka
4061  END
4062  CheckDefFailure(lines, 'E476:')
4063  CheckScriptFailure(['vim9script'] + lines, 'E492:')
4064
4065  lines =<< trim END
4066    t
4067  END
4068  CheckDefFailure(lines, 'E1100:')
4069  CheckScriptFailure(['vim9script'] + lines, 'E1100:')
4070
4071  lines =<< trim END
4072    x
4073  END
4074  CheckDefFailure(lines, 'E1100:')
4075  CheckScriptFailure(['vim9script'] + lines, 'E1100:')
4076
4077  lines =<< trim END
4078    xit
4079  END
4080  CheckDefFailure(lines, 'E1100:')
4081  CheckScriptFailure(['vim9script'] + lines, 'E1100:')
4082enddef
4083
4084def Test_mapping_line_number()
4085  var lines =<< trim END
4086      vim9script
4087      def g:FuncA()
4088          # Some comment
4089          FuncB(0)
4090      enddef
4091          # Some comment
4092      def FuncB(
4093          # Some comment
4094          n: number
4095      )
4096          exe 'nno '
4097              # Some comment
4098              .. '<F3> a'
4099              .. 'b'
4100              .. 'c'
4101      enddef
4102  END
4103  CheckScriptSuccess(lines)
4104  var res = execute('verbose nmap <F3>')
4105  assert_match('No mapping found', res)
4106
4107  g:FuncA()
4108  res = execute('verbose nmap <F3>')
4109  assert_match(' <F3> .* abc.*Last set from .*XScriptSuccess\d\+ line 11', res)
4110
4111  nunmap <F3>
4112  delfunc g:FuncA
4113enddef
4114
4115def Test_option_set()
4116  # legacy script allows for white space
4117  var lines =<< trim END
4118      set foldlevel  =11
4119      call assert_equal(11, &foldlevel)
4120  END
4121  CheckScriptSuccess(lines)
4122
4123  set foldlevel
4124  set foldlevel=12
4125  assert_equal(12, &foldlevel)
4126  set foldlevel+=2
4127  assert_equal(14, &foldlevel)
4128  set foldlevel-=3
4129  assert_equal(11, &foldlevel)
4130
4131  lines =<< trim END
4132      set foldlevel =1
4133  END
4134  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: =1')
4135
4136  lines =<< trim END
4137      set foldlevel +=1
4138  END
4139  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: +=1')
4140
4141  lines =<< trim END
4142      set foldlevel ^=1
4143  END
4144  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: ^=1')
4145
4146  lines =<< trim END
4147      set foldlevel -=1
4148  END
4149  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: -=1')
4150
4151  set foldlevel&
4152enddef
4153
4154def Test_option_modifier()
4155  # legacy script allows for white space
4156  var lines =<< trim END
4157      set hlsearch &  hlsearch  !
4158      call assert_equal(1, &hlsearch)
4159  END
4160  CheckScriptSuccess(lines)
4161
4162  set hlsearch
4163  set hlsearch!
4164  assert_equal(false, &hlsearch)
4165
4166  set hlsearch
4167  set hlsearch&
4168  assert_equal(false, &hlsearch)
4169
4170  lines =<< trim END
4171      set hlsearch &
4172  END
4173  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: &')
4174
4175  lines =<< trim END
4176      set hlsearch   !
4177  END
4178  CheckDefExecAndScriptFailure(lines, 'E1205: No white space allowed between option and: !')
4179
4180  set hlsearch&
4181enddef
4182
4183" This must be called last, it may cause following :def functions to fail
4184def Test_xxx_echoerr_line_number()
4185  var lines =<< trim END
4186      echoerr 'some'
4187         .. ' error'
4188         .. ' continued'
4189  END
4190  CheckDefExecAndScriptFailure(lines, 'some error continued', 1)
4191enddef
4192
4193def ProfiledWithLambda()
4194  var n = 3
4195  echo [[1, 2], [3, 4]]->filter((_, l) => l[0] == n)
4196enddef
4197
4198def ProfiledNested()
4199  var x = 0
4200  def Nested(): any
4201      return x
4202  enddef
4203  Nested()
4204enddef
4205
4206def ProfiledNestedProfiled()
4207  var x = 0
4208  def Nested(): any
4209      return x
4210  enddef
4211  Nested()
4212enddef
4213
4214" Execute this near the end, profiling doesn't stop until Vim exists.
4215" This only tests that it works, not the profiling output.
4216def Test_xx_profile_with_lambda()
4217  CheckFeature profile
4218
4219  profile start Xprofile.log
4220  profile func ProfiledWithLambda
4221  ProfiledWithLambda()
4222
4223  profile func ProfiledNested
4224  ProfiledNested()
4225
4226  # Also profile the nested function.  Use a different function, although the
4227  # contents is the same, to make sure it was not already compiled.
4228  profile func *
4229  ProfiledNestedProfiled()
4230
4231  profdel func *
4232  profile pause
4233enddef
4234
4235" Keep this last, it messes up highlighting.
4236def Test_substitute_cmd()
4237  new
4238  setline(1, 'something')
4239  :substitute(some(other(
4240  assert_equal('otherthing', getline(1))
4241  bwipe!
4242
4243  # also when the context is Vim9 script
4244  var lines =<< trim END
4245    vim9script
4246    new
4247    setline(1, 'something')
4248    :substitute(some(other(
4249    assert_equal('otherthing', getline(1))
4250    bwipe!
4251  END
4252  writefile(lines, 'Xvim9lines')
4253  source Xvim9lines
4254
4255  delete('Xvim9lines')
4256enddef
4257
4258" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
4259