blob: e9d94734a304596d1f05535f214658c0254e81b9 [file] [log] [blame]
Bram Moolenaard8448622022-01-07 21:39:52 +00001" Test import/export of the Vim9 script language.
Bram Moolenaar160aa862022-01-10 21:29:57 +00002" Also the autoload mechanism.
Bram Moolenaard8448622022-01-07 21:39:52 +00003
4source check.vim
5source term_util.vim
6source vim9.vim
7
8let s:export_script_lines =<< trim END
9 vim9script
10 var name: string = 'bob'
11 def Concat(arg: string): string
12 return name .. arg
13 enddef
14 g:result = Concat('bie')
15 g:localname = name
16
17 export const CONST = 1234
18 export var exported = 9876
19 export var exp_name = 'John'
20 export def Exported(): string
21 return 'Exported'
22 enddef
23 export def ExportedValue(): number
24 return exported
25 enddef
26 export def ExportedInc()
27 exported += 5
28 enddef
29 export final theList = [1]
30END
31
32def Undo_export_script_lines()
33 unlet g:result
34 unlet g:localname
35enddef
36
37def Test_vim9_import_export()
38 writefile(s:export_script_lines, 'Xexport.vim')
39 var import_script_lines =<< trim END
40 vim9script
41 var dir = './'
42 var ext = ".vim"
43 import dir .. 'Xexport' .. ext as expo
44
45 g:exported1 = expo.exported
46 expo.exported += 3
47 g:exported2 = expo.exported
48 g:exported3 = expo.ExportedValue()
49
50 expo.ExportedInc()
51 g:exported_i1 = expo.exported
52 g:exported_i2 = expo.ExportedValue()
53
54 expo.exported = 11
55 g:exported_s1 = expo.exported
56 g:exported_s2 = expo.ExportedValue()
57
58 g:imported_func = expo.Exported()
59
60 def GetExported(): string
61 var local_dict = {ref: expo.Exported}
62 return local_dict.ref()
63 enddef
64 g:funcref_result = GetExported()
65
66 g:imported_name = expo.exp_name
67 expo.exp_name ..= ' Doe'
68 g:imported_name_appended = expo.exp_name
69 g:exported_later = expo.exported
70
71 expo.theList->add(2)
72 assert_equal([1, 2], expo.theList)
73 END
74 writefile(import_script_lines, 'Ximport.vim')
75 source Ximport.vim
76
77 assert_equal('bobbie', g:result)
78 assert_equal('bob', g:localname)
79 assert_equal(9876, g:exported1)
80 assert_equal(9879, g:exported2)
81 assert_equal(9879, g:exported3)
82
83 assert_equal(9884, g:exported_i1)
84 assert_equal(9884, g:exported_i2)
85
86 assert_equal(11, g:exported_s1)
87 assert_equal(11, g:exported_s2)
88 assert_equal(11, g:exported_later)
89
90 assert_equal('Exported', g:imported_func)
91 assert_equal('Exported', g:funcref_result)
92 assert_equal('John', g:imported_name)
93 assert_equal('John Doe', g:imported_name_appended)
94 assert_false(exists('g:name'))
95
96 Undo_export_script_lines()
97 unlet g:exported1
98 unlet g:exported2
99 unlet g:exported3
100 unlet g:exported_i1
101 unlet g:exported_i2
102 unlet g:exported_later
103 unlet g:imported_func
104 unlet g:imported_name g:imported_name_appended
105 delete('Ximport.vim')
106
107 # similar, with line breaks
108 var import_line_break_script_lines =<< trim END
109 vim9script
110 import './Xexport.vim'
111 as expo
112 g:exported = expo.exported
113 expo.exported += 7
114 g:exported_added = expo.exported
115 g:imported_func = expo.Exported()
116 END
117 writefile(import_line_break_script_lines, 'Ximport_lbr.vim')
118 source Ximport_lbr.vim
119
120 assert_equal(11, g:exported)
121 assert_equal(18, g:exported_added)
122 assert_equal('Exported', g:imported_func)
123
124 # exported script not sourced again
125 assert_false(exists('g:result'))
126 unlet g:exported
127 unlet g:exported_added
128 unlet g:imported_func
129 delete('Ximport_lbr.vim')
130
131 var line_break_before_dot =<< trim END
132 vim9script
133 import './Xexport.vim' as expo
134 g:exported = expo
135 .exported
136 END
137 writefile(line_break_before_dot, 'Ximport_lbr_before_dot.vim')
138 assert_fails('source Ximport_lbr_before_dot.vim', 'E1060:', '', 3)
139 delete('Ximport_lbr_before_dot.vim')
140
141 var line_break_after_dot =<< trim END
142 vim9script
143 import './Xexport.vim' as expo
144 g:exported = expo.
145 exported
146 END
147 writefile(line_break_after_dot, 'Ximport_lbr_after_dot.vim')
148 assert_fails('source Ximport_lbr_after_dot.vim', 'E1074:', '', 3)
149 delete('Ximport_lbr_after_dot.vim')
150
151 var import_star_as_lines =<< trim END
152 vim9script
153 import './Xexport.vim' as Export
154 def UseExport()
155 g:exported_def = Export.exported
156 enddef
157 g:exported_script = Export.exported
158 assert_equal(1, exists('Export.exported'))
159 assert_equal(0, exists('Export.notexported'))
160 UseExport()
161 END
162 writefile(import_star_as_lines, 'Ximport.vim')
163 source Ximport.vim
164
165 assert_equal(18, g:exported_def)
166 assert_equal(18, g:exported_script)
167 unlet g:exported_def
168 unlet g:exported_script
169
170 var import_star_as_lines_no_dot =<< trim END
171 vim9script
172 import './Xexport.vim' as Export
173 def Func()
174 var dummy = 1
175 var imported = Export + dummy
176 enddef
177 defcompile
178 END
179 writefile(import_star_as_lines_no_dot, 'Ximport.vim')
180 assert_fails('source Ximport.vim', 'E1060:', '', 2, 'Func')
181
182 var import_star_as_lines_dot_space =<< trim END
183 vim9script
184 import './Xexport.vim' as Export
185 def Func()
186 var imported = Export . exported
187 enddef
188 defcompile
189 END
190 writefile(import_star_as_lines_dot_space, 'Ximport.vim')
191 assert_fails('source Ximport.vim', 'E1074:', '', 1, 'Func')
192
Bram Moolenaar7c24dfd2022-01-08 17:03:55 +0000193 writefile(s:export_script_lines, 'Xexport2.vim')
194 var import_as_duplicated =<< trim END
Bram Moolenaard8448622022-01-07 21:39:52 +0000195 vim9script
196 import './Xexport.vim' as expo
Bram Moolenaar7c24dfd2022-01-08 17:03:55 +0000197 import './Xexport2.vim' as expo
Bram Moolenaard8448622022-01-07 21:39:52 +0000198 END
Bram Moolenaar7c24dfd2022-01-08 17:03:55 +0000199 writefile(import_as_duplicated, 'Ximport.vim')
Bram Moolenaard8448622022-01-07 21:39:52 +0000200 assert_fails('source Ximport.vim', 'E1073:', '', 3, 'Ximport.vim')
Bram Moolenaar7c24dfd2022-01-08 17:03:55 +0000201 delete('Xexport2.vim')
Bram Moolenaard8448622022-01-07 21:39:52 +0000202
203 var import_star_as_lines_script_no_dot =<< trim END
204 vim9script
205 import './Xexport.vim' as Export
206 g:imported_script = Export exported
207 END
208 writefile(import_star_as_lines_script_no_dot, 'Ximport.vim')
209 assert_fails('source Ximport.vim', 'E1060: Expected dot after name: Export exported')
210
211 var import_star_as_lines_script_space_after_dot =<< trim END
212 vim9script
213 import './Xexport.vim' as Export
214 g:imported_script = Export. exported
215 END
216 writefile(import_star_as_lines_script_space_after_dot, 'Ximport.vim')
217 assert_fails('source Ximport.vim', 'E1074:')
218
219 var import_star_as_lines_missing_name =<< trim END
220 vim9script
221 import './Xexport.vim' as Export
222 def Func()
223 var imported = Export.
224 enddef
225 defcompile
226 END
227 writefile(import_star_as_lines_missing_name, 'Ximport.vim')
228 assert_fails('source Ximport.vim', 'E1048:', '', 1, 'Func')
229
230 var import_star_as_lbr_lines =<< trim END
231 vim9script
232 import './Xexport.vim'
233 as Export
234 def UseExport()
235 g:exported = Export.exported
236 enddef
237 UseExport()
238 END
239 writefile(import_star_as_lbr_lines, 'Ximport.vim')
240 source Ximport.vim
241 assert_equal(18, g:exported)
242 unlet g:exported
243
244 # try to use something that exists but is not exported
245 var import_not_exported_lines =<< trim END
246 vim9script
247 import './Xexport.vim' as expo
248 echo expo.name
249 END
250 writefile(import_not_exported_lines, 'Ximport.vim')
251 assert_fails('source Ximport.vim', 'E1049:', '', 3, 'Ximport.vim')
252
253 # try to import something that is already defined
254 var import_already_defined =<< trim END
255 vim9script
256 var exported = 'something'
257 import './Xexport.vim' as exported
258 END
259 writefile(import_already_defined, 'Ximport.vim')
260 assert_fails('source Ximport.vim', 'E1054:', '', 3, 'Ximport.vim')
261
262 # try changing an imported const
263 var import_assign_to_const =<< trim END
264 vim9script
265 import './Xexport.vim' as expo
266 def Assign()
267 expo.CONST = 987
268 enddef
269 defcompile
270 END
271 writefile(import_assign_to_const, 'Ximport.vim')
272 assert_fails('source Ximport.vim', 'E46:', '', 1, '_Assign')
273
274 # try changing an imported final
275 var import_assign_to_final =<< trim END
276 vim9script
277 import './Xexport.vim' as expo
278 def Assign()
279 expo.theList = [2]
280 enddef
281 defcompile
282 END
283 writefile(import_assign_to_final, 'Ximport.vim')
284 assert_fails('source Ximport.vim', 'E46:', '', 1, '_Assign')
285
286 var import_no_as_lines =<< trim END
287 vim9script
288 import './Xexport.vim' name
289 END
290 writefile(import_no_as_lines, 'Ximport.vim')
291 assert_fails('source Ximport.vim', 'E488:', '', 2, 'Ximport.vim')
292
293 var import_invalid_string_lines =<< trim END
294 vim9script
295 import Xexport.vim
296 END
297 writefile(import_invalid_string_lines, 'Ximport.vim')
298 assert_fails('source Ximport.vim', 'E121:', '', 2, 'Ximport.vim')
299
300 var import_wrong_name_lines =<< trim END
301 vim9script
302 import './XnoExport.vim'
303 END
304 writefile(import_wrong_name_lines, 'Ximport.vim')
305 assert_fails('source Ximport.vim', 'E1053:', '', 2, 'Ximport.vim')
306
307 var import_redefining_lines =<< trim END
308 vim9script
309 import './Xexport.vim' as exported
310 var exported = 5
311 END
312 writefile(import_redefining_lines, 'Ximport.vim')
313 assert_fails('source Ximport.vim', 'E1213: Redefining imported item "exported"', '', 3)
314
Bram Moolenaar160aa862022-01-10 21:29:57 +0000315 var import_missing_dot_lines =<< trim END
316 vim9script
317 import './Xexport.vim' as expo
318 def Test()
319 expo = 9
320 enddef
321 defcompile
322 END
323 writefile(import_missing_dot_lines, 'Ximport.vim')
324 assert_fails('source Ximport.vim', 'E1258:', '', 1)
325
326 var import_missing_name_lines =<< trim END
327 vim9script
328 import './Xexport.vim' as expo
329 def Test()
330 expo.99 = 9
331 enddef
332 defcompile
333 END
334 writefile(import_missing_name_lines, 'Ximport.vim')
Bram Moolenaar76283822022-01-10 21:39:03 +0000335 assert_fails('source Ximport.vim', 'E1259:', '', 1)
Bram Moolenaar160aa862022-01-10 21:29:57 +0000336
Bram Moolenaard8448622022-01-07 21:39:52 +0000337 var import_assign_wrong_type_lines =<< trim END
338 vim9script
339 import './Xexport.vim' as expo
340 expo.exported = 'xxx'
341 END
342 writefile(import_assign_wrong_type_lines, 'Ximport.vim')
343 assert_fails('source Ximport.vim', 'E1012: Type mismatch; expected number but got string', '', 3)
344
345 var import_assign_const_lines =<< trim END
346 vim9script
347 import './Xexport.vim' as expo
348 expo.CONST = 4321
349 END
350 writefile(import_assign_const_lines, 'Ximport.vim')
351 assert_fails('source Ximport.vim', 'E46: Cannot change read-only variable "CONST"', '', 3)
352
353 delete('Ximport.vim')
354 delete('Ximport3.vim')
355 delete('Xexport.vim')
356
357 # Check that in a Vim9 script 'cpo' is set to the Vim default.
358 # Flags added or removed are also applied to the restored value.
359 set cpo=abcd
360 var lines =<< trim END
361 vim9script
362 g:cpo_in_vim9script = &cpo
363 set cpo+=f
364 set cpo-=c
365 g:cpo_after_vim9script = &cpo
366 END
367 writefile(lines, 'Xvim9_script')
368 source Xvim9_script
369 assert_equal('fabd', &cpo)
370 set cpo&vim
371 assert_equal(&cpo, g:cpo_in_vim9script)
372 var newcpo = substitute(&cpo, 'c', '', '') .. 'f'
373 assert_equal(newcpo, g:cpo_after_vim9script)
374
375 delete('Xvim9_script')
376enddef
377
378def Test_import_funcref()
379 var lines =<< trim END
380 vim9script
381 export def F(): number
382 return 42
383 enddef
384 export const G = F
385 END
386 writefile(lines, 'Xlib.vim')
387
388 lines =<< trim END
389 vim9script
390 import './Xlib.vim' as lib
391 const Foo = lib.G()
392 assert_equal(42, Foo)
393
394 def DoTest()
395 const Goo = lib.G()
396 assert_equal(42, Goo)
397 enddef
398 DoTest()
399 END
400 CheckScriptSuccess(lines)
401
402 delete('Xlib.vim')
403enddef
404
405def Test_import_fails()
406 writefile([], 'Xfoo.vim')
407 var lines =<< trim END
408 import './Xfoo.vim' as foo
409 foo = 'bar'
410 END
411 CheckDefAndScriptFailure(lines, ['E1094:', 'E1236: Cannot use foo itself'])
412 lines =<< trim END
413 vim9script
414 import './Xfoo.vim' as foo
415 var that = foo
416 END
417 CheckScriptFailure(lines, 'E1060: Expected dot after name: foo')
418
419 lines =<< trim END
420 vim9script
421 import './Xfoo.vim' as 9foo
422 END
423 CheckScriptFailure(lines, 'E1047:')
424 lines =<< trim END
425 vim9script
426 import './Xfoo.vim' as the#foo
427 END
428 CheckScriptFailure(lines, 'E1047:')
429 lines =<< trim END
430 vim9script
431 import './Xfoo.vim' as g:foo
432 END
433 CheckScriptFailure(lines, 'E1047:')
434
435 delete('Xfoo.vim')
436
437 lines =<< trim END
438 vim9script
439 def TheFunc()
440 echo 'the func'
441 enddef
442 export var Ref = TheFunc
443 END
444 writefile([], 'Xthat.vim')
Bram Moolenaar7c24dfd2022-01-08 17:03:55 +0000445
Bram Moolenaard8448622022-01-07 21:39:52 +0000446 lines =<< trim END
447 import './Xthat.vim' as That
448 That()
449 END
450 CheckDefAndScriptFailure(lines, ['E1094:', 'E1236: Cannot use That itself'])
Bram Moolenaar7c24dfd2022-01-08 17:03:55 +0000451
452 lines =<< trim END
453 import './Xthat.vim' as one
454 import './Xthat.vim' as two
455 END
456 CheckScriptFailure(lines, 'E1262:')
457
458 delete('Xthat.vim')
Bram Moolenaard8448622022-01-07 21:39:52 +0000459
460 mkdir('Ximport')
461
462 writefile(['vim9script'], 'Ximport/.vim')
463 lines =<< trim END
464 vim9script
465 import './Ximport/.vim'
466 END
467 CheckScriptFailure(lines, 'E1261: Cannot import .vim without using "as"')
468 lines =<< trim END
469 vim9script
470 import './Ximport/.vim' as vim
471 END
472 CheckScriptSuccess(lines)
473
474 writefile(['vim9script'], 'Ximport/.vimrc')
475 lines =<< trim END
476 vim9script
477 import './Ximport/.vimrc'
478 END
479 CheckScriptFailure(lines, 'E1257: Imported script must use "as" or end in .vim')
480 lines =<< trim END
481 vim9script
482 import './Ximport/.vimrc' as vimrc
483 END
484 CheckScriptSuccess(lines)
485
486 delete('Ximport', 'rf')
487enddef
488
489func g:Trigger()
490 source Ximport.vim
491 return "echo 'yes'\<CR>"
492endfunc
493
494def Test_import_export_expr_map()
495 # check that :import and :export work when buffer is locked
496 var export_lines =<< trim END
497 vim9script
498 export def That(): string
499 return 'yes'
500 enddef
501 END
502 writefile(export_lines, 'Xexport_that.vim')
503
504 var import_lines =<< trim END
505 vim9script
506 import './Xexport_that.vim' as that
507 assert_equal('yes', that.That())
508 END
509 writefile(import_lines, 'Ximport.vim')
510
511 nnoremap <expr> trigger g:Trigger()
512 feedkeys('trigger', "xt")
513
514 delete('Xexport_that.vim')
515 delete('Ximport.vim')
516 nunmap trigger
517enddef
518
519def Test_import_in_filetype()
520 # check that :import works when the buffer is locked
521 mkdir('ftplugin', 'p')
522 var export_lines =<< trim END
523 vim9script
524 export var That = 'yes'
525 END
526 writefile(export_lines, 'ftplugin/Xexport_ft.vim')
527
528 var import_lines =<< trim END
529 vim9script
530 import './Xexport_ft.vim' as ft
531 assert_equal('yes', ft.That)
532 g:did_load_mytpe = 1
533 END
534 writefile(import_lines, 'ftplugin/qf.vim')
535
536 var save_rtp = &rtp
537 &rtp = getcwd() .. ',' .. &rtp
538
539 filetype plugin on
540 copen
541 assert_equal(1, g:did_load_mytpe)
542
543 quit!
544 delete('Xexport_ft.vim')
545 delete('ftplugin', 'rf')
546 &rtp = save_rtp
547enddef
548
549def Test_use_import_in_mapping()
550 var lines =<< trim END
551 vim9script
552 export def Funcx()
553 g:result = 42
554 enddef
555 END
556 writefile(lines, 'XsomeExport.vim')
557 lines =<< trim END
558 vim9script
559 import './XsomeExport.vim' as some
560 var Funcy = some.Funcx
561 nnoremap <F3> :call <sid>Funcy()<cr>
562 END
563 writefile(lines, 'Xmapscript.vim')
564
565 source Xmapscript.vim
566 feedkeys("\<F3>", "xt")
567 assert_equal(42, g:result)
568
569 unlet g:result
570 delete('XsomeExport.vim')
571 delete('Xmapscript.vim')
572 nunmap <F3>
573enddef
574
575def Test_export_fails()
576 CheckScriptFailure(['export var some = 123'], 'E1042:')
577 CheckScriptFailure(['vim9script', 'export var g:some'], 'E1022:')
578 CheckScriptFailure(['vim9script', 'export echo 134'], 'E1043:')
579
580 assert_fails('export something', 'E1043:')
581enddef
582
583func Test_import_fails_without_script()
584 CheckRunVimInTerminal
585
586 " call indirectly to avoid compilation error for missing functions
587 call Run_Test_import_fails_on_command_line()
588endfunc
589
590def Run_Test_import_fails_on_command_line()
591 var export =<< trim END
592 vim9script
593 export def Foo(): number
594 return 0
595 enddef
596 END
597 writefile(export, 'XexportCmd.vim')
598
599 var buf = RunVimInTerminal('-c "import Foo from ''./XexportCmd.vim''"', {
600 rows: 6, wait_for_ruler: 0})
601 WaitForAssert(() => assert_match('^E1094:', term_getline(buf, 5)))
602
603 delete('XexportCmd.vim')
604 StopVimInTerminal(buf)
605enddef
606
607def Test_vim9_reload_noclear()
608 var lines =<< trim END
609 vim9script
610 export var exported = 'thexport'
611
612 export def TheFunc(x = 0)
613 enddef
614 END
615 writefile(lines, 'XExportReload')
616 lines =<< trim END
617 vim9script noclear
618 g:loadCount += 1
619 var s:reloaded = 'init'
620 import './XExportReload' as exp
621
622 def Again(): string
623 return 'again'
624 enddef
625
626 exp.TheFunc()
627
628 if exists('s:loaded') | finish | endif
629 var s:loaded = true
630
631 var s:notReloaded = 'yes'
632 s:reloaded = 'first'
633 def g:Values(): list<string>
634 return [s:reloaded, s:notReloaded, Again(), Once(), exp.exported]
635 enddef
636
637 def Once(): string
638 return 'once'
639 enddef
640 END
641 writefile(lines, 'XReloaded')
642 g:loadCount = 0
643 source XReloaded
644 assert_equal(1, g:loadCount)
645 assert_equal(['first', 'yes', 'again', 'once', 'thexport'], g:Values())
646 source XReloaded
647 assert_equal(2, g:loadCount)
648 assert_equal(['init', 'yes', 'again', 'once', 'thexport'], g:Values())
649 source XReloaded
650 assert_equal(3, g:loadCount)
651 assert_equal(['init', 'yes', 'again', 'once', 'thexport'], g:Values())
652
653 delete('XReloaded')
654 delete('XExportReload')
655 delfunc g:Values
656 unlet g:loadCount
657
658 lines =<< trim END
659 vim9script
660 def Inner()
661 enddef
662 END
663 lines->writefile('XreloadScript.vim')
664 source XreloadScript.vim
665
666 lines =<< trim END
667 vim9script
668 def Outer()
669 def Inner()
670 enddef
671 enddef
672 defcompile
673 END
674 lines->writefile('XreloadScript.vim')
675 source XreloadScript.vim
676
677 delete('XreloadScript.vim')
678enddef
679
680def Test_vim9_reload_import()
681 var lines =<< trim END
682 vim9script
683 const var = ''
684 var valone = 1234
685 def MyFunc(arg: string)
686 valone = 5678
687 enddef
688 END
689 var morelines =<< trim END
690 var valtwo = 222
691 export def GetValtwo(): number
692 return valtwo
693 enddef
694 END
695 writefile(lines + morelines, 'Xreload.vim')
696 source Xreload.vim
697 source Xreload.vim
698 source Xreload.vim
699
700 # cannot declare a var twice
701 lines =<< trim END
702 vim9script
703 var valone = 1234
704 var valone = 5678
705 END
706 writefile(lines, 'Xreload.vim')
707 assert_fails('source Xreload.vim', 'E1041:', '', 3, 'Xreload.vim')
708
709 delete('Xreload.vim')
710 delete('Ximport.vim')
711enddef
712
713" if a script is reloaded with a script-local variable that changed its type, a
714" compiled function using that variable must fail.
715def Test_script_reload_change_type()
716 var lines =<< trim END
717 vim9script noclear
718 var str = 'string'
719 def g:GetStr(): string
720 return str .. 'xxx'
721 enddef
722 END
723 writefile(lines, 'Xreload.vim')
724 source Xreload.vim
725 echo g:GetStr()
726
727 lines =<< trim END
728 vim9script noclear
729 var str = 1234
730 END
731 writefile(lines, 'Xreload.vim')
732 source Xreload.vim
733 assert_fails('echo g:GetStr()', 'E1150:')
734
735 delfunc g:GetStr
736 delete('Xreload.vim')
737enddef
738
739" Define CallFunc so that the test can be compiled
740command CallFunc echo 'nop'
741
742def Test_script_reload_from_function()
743 var lines =<< trim END
744 vim9script
745
746 if exists('g:loaded')
747 finish
748 endif
749 g:loaded = 1
750 delcommand CallFunc
751 command CallFunc Func()
752 def Func()
753 so XreloadFunc.vim
754 g:didTheFunc = 1
755 enddef
756 END
757 writefile(lines, 'XreloadFunc.vim')
758 source XreloadFunc.vim
759 CallFunc
760 assert_equal(1, g:didTheFunc)
761
762 delete('XreloadFunc.vim')
763 delcommand CallFunc
764 unlet g:loaded
765 unlet g:didTheFunc
766enddef
767
768def s:RetSome(): string
769 return 'some'
770enddef
771
772" Not exported function that is referenced needs to be accessed by the
773" script-local name.
774def Test_vim9_funcref()
775 var sortlines =<< trim END
776 vim9script
777 def Compare(i1: number, i2: number): number
778 return i2 - i1
779 enddef
780
781 export def FastSort(): list<number>
782 return range(5)->sort(Compare)
783 enddef
784
785 export def GetString(arg: string): string
786 return arg
787 enddef
788 END
789 writefile(sortlines, 'Xsort.vim')
790
791 var lines =<< trim END
792 vim9script
793 import './Xsort.vim'
794 def Test()
795 g:result = Xsort.FastSort()
796 enddef
797 Test()
Bram Moolenaar7c24dfd2022-01-08 17:03:55 +0000798 END
799 writefile(lines, 'Xscript.vim')
800 source Xscript.vim
801 assert_equal([4, 3, 2, 1, 0], g:result)
802 unlet g:result
Bram Moolenaard8448622022-01-07 21:39:52 +0000803
Bram Moolenaar7c24dfd2022-01-08 17:03:55 +0000804 lines =<< trim END
805 vim9script
Bram Moolenaard8448622022-01-07 21:39:52 +0000806 # using a function imported with "as"
807 import './Xsort.vim' as anAlias
808 assert_equal('yes', anAlias.GetString('yes'))
809
810 # using the function from a compiled function
811 def TestMore(): string
812 var s = s:anAlias.GetString('foo')
813 return s .. anAlias.GetString('bar')
814 enddef
815 assert_equal('foobar', TestMore())
816
817 # error when using a function that isn't exported
818 assert_fails('anAlias.Compare(1, 2)', 'E1049:')
819 END
820 writefile(lines, 'Xscript.vim')
821
Bram Moolenaard8448622022-01-07 21:39:52 +0000822 delete('Xsort.vim')
823 delete('Xscript.vim')
824
825 var Funcref = function('s:RetSome')
826 assert_equal('some', Funcref())
827enddef
828
829" Check that when searching for "FilterFunc" it finds the import in the
830" script where FastFilter() is called from, both as a string and as a direct
831" function reference.
832def Test_vim9_funcref_other_script()
833 var filterLines =<< trim END
834 vim9script
835 export def FilterFunc(idx: number, val: number): bool
836 return idx % 2 == 1
837 enddef
838 export def FastFilter(): list<number>
839 return range(10)->filter('FilterFunc(v:key, v:val)')
840 enddef
841 export def FastFilterDirect(): list<number>
842 return range(10)->filter(FilterFunc)
843 enddef
844 END
845 writefile(filterLines, 'Xfilter.vim')
846
847 var lines =<< trim END
848 vim9script
849 import './Xfilter.vim' as filter
850 def Test()
851 var x: list<number> = filter.FastFilter()
852 enddef
853 Test()
854 def TestDirect()
855 var x: list<number> = filter.FastFilterDirect()
856 enddef
857 TestDirect()
858 END
859 CheckScriptSuccess(lines)
860 delete('Xfilter.vim')
861enddef
862
863def Test_import_absolute()
864 var import_lines = [
865 'vim9script',
866 'import "' .. escape(getcwd(), '\') .. '/Xexport_abs.vim" as abs',
867 'def UseExported()',
868 ' g:imported_abs = abs.exported',
869 ' abs.exported = 8888',
870 ' g:imported_after = abs.exported',
871 'enddef',
872 'UseExported()',
873 'g:import_disassembled = execute("disass UseExported")',
874 ]
875 writefile(import_lines, 'Ximport_abs.vim')
876 writefile(s:export_script_lines, 'Xexport_abs.vim')
877
878 source Ximport_abs.vim
879
880 assert_equal(9876, g:imported_abs)
881 assert_equal(8888, g:imported_after)
882 assert_match('<SNR>\d\+_UseExported\_s*' ..
883 'g:imported_abs = abs.exported\_s*' ..
884 '0 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' ..
885 '1 STOREG g:imported_abs\_s*' ..
886 'abs.exported = 8888\_s*' ..
887 '2 PUSHNR 8888\_s*' ..
888 '3 STORESCRIPT exported-2 in .*Xexport_abs.vim\_s*' ..
889 'g:imported_after = abs.exported\_s*' ..
890 '4 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' ..
891 '5 STOREG g:imported_after',
892 g:import_disassembled)
893
894 Undo_export_script_lines()
895 unlet g:imported_abs
896 unlet g:import_disassembled
897
898 delete('Ximport_abs.vim')
899 delete('Xexport_abs.vim')
900enddef
901
902def Test_import_rtp()
903 var import_lines = [
904 'vim9script',
905 'import "Xexport_rtp.vim" as rtp',
906 'g:imported_rtp = rtp.exported',
907 ]
908 writefile(import_lines, 'Ximport_rtp.vim')
909 mkdir('import', 'p')
910 writefile(s:export_script_lines, 'import/Xexport_rtp.vim')
911
912 var save_rtp = &rtp
913 &rtp = getcwd()
914 source Ximport_rtp.vim
915 &rtp = save_rtp
916
917 assert_equal(9876, g:imported_rtp)
918
919 Undo_export_script_lines()
920 unlet g:imported_rtp
921 delete('Ximport_rtp.vim')
922 delete('import', 'rf')
923enddef
924
925def Test_import_compile_error()
926 var export_lines = [
927 'vim9script',
928 'export def ExpFunc(): string',
929 ' return notDefined',
930 'enddef',
931 ]
932 writefile(export_lines, 'Xexported.vim')
933
934 var import_lines = [
935 'vim9script',
936 'import "./Xexported.vim" as expo',
937 'def ImpFunc()',
938 ' echo expo.ExpFunc()',
939 'enddef',
940 'defcompile',
941 ]
942 writefile(import_lines, 'Ximport.vim')
943
944 try
945 source Ximport.vim
946 catch /E1001/
947 # Error should be before the Xexported.vim file.
948 assert_match('E1001: Variable not found: notDefined', v:exception)
949 assert_match('function <SNR>\d\+_ImpFunc\[1\]..<SNR>\d\+_ExpFunc, line 1', v:throwpoint)
950 endtry
951
952 delete('Xexported.vim')
953 delete('Ximport.vim')
954enddef
955
956def Test_func_overrules_import_fails()
957 var export_lines =<< trim END
958 vim9script
959 export def Func()
960 echo 'imported'
961 enddef
962 END
963 writefile(export_lines, 'XexportedFunc.vim')
964
965 var lines =<< trim END
966 vim9script
967 import './XexportedFunc.vim' as Func
968 def Func()
969 echo 'local to function'
970 enddef
971 END
972 CheckScriptFailure(lines, 'E1236:')
973
974 lines =<< trim END
975 vim9script
976 import './XexportedFunc.vim' as Func
977 def Outer()
978 def Func()
979 echo 'local to function'
980 enddef
981 enddef
982 defcompile
983 END
984 CheckScriptFailure(lines, 'E1236:')
985
986 delete('XexportedFunc.vim')
987enddef
988
989def Test_source_vim9_from_legacy()
990 var vim9_lines =<< trim END
991 vim9script
992 var local = 'local'
993 g:global = 'global'
994 export var exported = 'exported'
995 export def GetText(): string
996 return 'text'
997 enddef
998 END
999 writefile(vim9_lines, 'Xvim9_script.vim')
1000
1001 var legacy_lines =<< trim END
1002 source Xvim9_script.vim
1003
1004 call assert_false(exists('local'))
1005 call assert_false(exists('exported'))
1006 call assert_false(exists('s:exported'))
1007 call assert_equal('global', global)
1008 call assert_equal('global', g:global)
1009
1010 "" imported variable becomes script-local
1011 "import exported from './Xvim9_script.vim'
1012 "call assert_equal('exported', s:exported)
1013 "call assert_false(exists('exported'))
1014
1015 "" imported function becomes script-local
1016 "import GetText from './Xvim9_script.vim'
1017 "call assert_equal('text', s:GetText())
1018 "call assert_false(exists('*GetText'))
1019 END
1020 writefile(legacy_lines, 'Xlegacy_script.vim')
1021
1022 source Xlegacy_script.vim
1023 assert_equal('global', g:global)
1024 unlet g:global
1025
1026 delete('Xlegacy_script.vim')
1027 delete('Xvim9_script.vim')
1028enddef
1029
1030def Test_cmdline_win()
1031 # if the Vim syntax highlighting uses Vim9 constructs they can be used from
1032 # the command line window.
1033 mkdir('rtp/syntax', 'p')
1034 var export_lines =<< trim END
1035 vim9script
1036 export var That = 'yes'
1037 END
1038 writefile(export_lines, 'rtp/syntax/Xexport.vim')
1039 var import_lines =<< trim END
1040 vim9script
1041 import './Xexport.vim' as exp
1042 echo exp.That
1043 END
1044 writefile(import_lines, 'rtp/syntax/vim.vim')
1045 var save_rtp = &rtp
1046 &rtp = getcwd() .. '/rtp' .. ',' .. &rtp
1047 syntax on
1048 augroup CmdWin
1049 autocmd CmdwinEnter * g:got_there = 'yes'
1050 augroup END
1051 # this will open and also close the cmdline window
1052 feedkeys('q:', 'xt')
1053 assert_equal('yes', g:got_there)
1054
1055 augroup CmdWin
1056 au!
1057 augroup END
1058 &rtp = save_rtp
1059 delete('rtp', 'rf')
1060enddef
1061
1062def Test_import_gone_when_sourced_twice()
1063 var exportlines =<< trim END
1064 vim9script
1065 if exists('g:guard')
1066 finish
1067 endif
1068 g:guard = 1
1069 export var name = 'someName'
1070 END
1071 writefile(exportlines, 'XexportScript.vim')
1072
1073 var lines =<< trim END
1074 vim9script
1075 import './XexportScript.vim' as expo
1076 def g:GetName(): string
1077 return expo.name
1078 enddef
1079 END
1080 writefile(lines, 'XscriptImport.vim')
1081 so XscriptImport.vim
1082 assert_equal('someName', g:GetName())
1083
1084 so XexportScript.vim
1085 assert_fails('call g:GetName()', 'E1149:')
1086
1087 delfunc g:GetName
1088 delete('XexportScript.vim')
1089 delete('XscriptImport.vim')
1090 unlet g:guard
1091enddef
1092
Bram Moolenaar160aa862022-01-10 21:29:57 +00001093" test using an auto-loaded function and variable
1094def Test_vim9_autoload()
1095 var lines =<< trim END
1096 vim9script
1097 def some#gettest(): string
1098 return 'test'
1099 enddef
1100 g:some#name = 'name'
1101 g:some#dict = {key: 'value'}
1102
1103 def some#varargs(a1: string, ...l: list<string>): string
1104 return a1 .. l[0] .. l[1]
1105 enddef
1106 END
1107
1108 mkdir('Xdir/autoload', 'p')
1109 writefile(lines, 'Xdir/autoload/some.vim')
1110 var save_rtp = &rtp
1111 exe 'set rtp^=' .. getcwd() .. '/Xdir'
1112
1113 assert_equal('test', g:some#gettest())
1114 assert_equal('name', g:some#name)
1115 assert_equal('value', g:some#dict.key)
1116 g:some#other = 'other'
1117 assert_equal('other', g:some#other)
1118
1119 assert_equal('abc', some#varargs('a', 'b', 'c'))
1120
1121 # upper case script name works
1122 lines =<< trim END
1123 vim9script
1124 def Other#getOther(): string
1125 return 'other'
1126 enddef
1127 END
1128 writefile(lines, 'Xdir/autoload/Other.vim')
1129 assert_equal('other', g:Other#getOther())
1130
1131 delete('Xdir', 'rf')
1132 &rtp = save_rtp
1133enddef
1134
1135def Test_vim9script_autoload()
1136 mkdir('Xdir/autoload', 'p')
1137 var save_rtp = &rtp
1138 exe 'set rtp^=' .. getcwd() .. '/Xdir'
1139
1140 # when using "vim9script autoload" prefix is not needed
1141 var lines =<< trim END
1142 vim9script autoload
Bram Moolenaar17d36cb2022-01-12 11:46:40 +00001143 g:prefixed_loaded += 1
Bram Moolenaar160aa862022-01-10 21:29:57 +00001144
1145 export def Gettest(): string
1146 return 'test'
1147 enddef
1148
Bram Moolenaarb8822442022-01-11 15:24:05 +00001149 export func GetMore()
1150 return Gettest() .. 'more'
Bram Moolenaar160aa862022-01-10 21:29:57 +00001151 endfunc
1152
1153 export var name = 'name'
1154 export final fname = 'final'
1155 export const cname = 'const'
1156 END
1157 writefile(lines, 'Xdir/autoload/prefixed.vim')
1158
Bram Moolenaar17d36cb2022-01-12 11:46:40 +00001159 g:prefixed_loaded = 0
1160 g:expected_loaded = 0
Bram Moolenaar160aa862022-01-10 21:29:57 +00001161 lines =<< trim END
1162 vim9script
1163 import autoload 'prefixed.vim'
Bram Moolenaar17d36cb2022-01-12 11:46:40 +00001164 assert_equal(g:expected_loaded, g:prefixed_loaded)
Bram Moolenaar160aa862022-01-10 21:29:57 +00001165 assert_equal('test', prefixed.Gettest())
Bram Moolenaar17d36cb2022-01-12 11:46:40 +00001166 assert_equal(1, g:prefixed_loaded)
Bram Moolenaar160aa862022-01-10 21:29:57 +00001167
Bram Moolenaarb8822442022-01-11 15:24:05 +00001168 assert_equal('testmore', prefixed.GetMore())
Bram Moolenaar160aa862022-01-10 21:29:57 +00001169 assert_equal('name', prefixed.name)
1170 assert_equal('final', prefixed.fname)
1171 assert_equal('const', prefixed.cname)
1172 END
1173 CheckScriptSuccess(lines)
Bram Moolenaar17d36cb2022-01-12 11:46:40 +00001174 # can source it again, autoload script not loaded again
1175 g:expected_loaded = 1
1176 CheckScriptSuccess(lines)
Bram Moolenaar160aa862022-01-10 21:29:57 +00001177
1178 # can also get the items by autoload name
1179 lines =<< trim END
1180 call assert_equal('test', prefixed#Gettest())
Bram Moolenaarb8822442022-01-11 15:24:05 +00001181 call assert_equal('testmore', prefixed#GetMore())
Bram Moolenaar160aa862022-01-10 21:29:57 +00001182 call assert_equal('name', prefixed#name)
1183 call assert_equal('final', prefixed#fname)
1184 call assert_equal('const', prefixed#cname)
1185 END
1186 CheckScriptSuccess(lines)
1187
Bram Moolenaarf111cdf2022-01-12 12:48:17 +00001188 unlet g:prefixed_loaded
1189 unlet g:expected_loaded
1190 delete('Xdir', 'rf')
1191 &rtp = save_rtp
1192enddef
1193
1194def Test_vim9script_autoload_call()
1195 mkdir('Xdir/autoload', 'p')
1196 var save_rtp = &rtp
1197 exe 'set rtp^=' .. getcwd() .. '/Xdir'
1198
1199 var lines =<< trim END
1200 vim9script autoload
1201
1202 export def Getother()
1203 g:result = 'other'
1204 enddef
1205 END
Bram Moolenaar5d982692022-01-12 15:15:27 +00001206 writefile(lines, 'Xdir/autoload/another.vim')
Bram Moolenaarf111cdf2022-01-12 12:48:17 +00001207
1208 lines =<< trim END
1209 vim9script
Bram Moolenaar5d982692022-01-12 15:15:27 +00001210 import autoload 'another.vim'
1211 call another.Getother()
Bram Moolenaarf111cdf2022-01-12 12:48:17 +00001212 assert_equal('other', g:result)
1213 END
1214 CheckScriptSuccess(lines)
1215
1216 unlet g:result
Bram Moolenaar160aa862022-01-10 21:29:57 +00001217 delete('Xdir', 'rf')
1218 &rtp = save_rtp
1219enddef
1220
Bram Moolenaard041f422022-01-12 19:54:00 +00001221def Test_import_autoload_postponed()
1222 mkdir('Xdir/autoload', 'p')
1223 var save_rtp = &rtp
1224 exe 'set rtp^=' .. getcwd() .. '/Xdir'
1225
1226 var lines =<< trim END
1227 vim9script autoload
1228
1229 g:loaded_postponed = 'true'
1230 export var variable = 'bla'
1231 export def Function(): string
1232 return 'bla'
1233 enddef
1234 END
1235 writefile(lines, 'Xdir/autoload/postponed.vim')
1236
1237 lines =<< trim END
1238 vim9script
1239
1240 import autoload 'postponed.vim'
1241 def Tryit()
1242 echo postponed.variable
1243 echo postponed.Function()
1244 enddef
1245 defcompile
1246 END
1247 CheckScriptSuccess(lines)
1248 assert_false(exists('g:loaded_postponed'))
1249 CheckScriptSuccess(lines + ['Tryit()'])
1250 assert_equal('true', g:loaded_postponed)
1251
1252 unlet g:loaded_postponed
1253 delete('Xdir', 'rf')
1254 &rtp = save_rtp
1255enddef
1256
Bram Moolenaar19db9e62022-01-11 11:58:19 +00001257def Test_autoload_mapping()
1258 mkdir('Xdir/autoload', 'p')
1259 var save_rtp = &rtp
1260 exe 'set rtp^=' .. getcwd() .. '/Xdir'
1261
1262 var lines =<< trim END
1263 vim9script autoload
1264
1265 g:toggle_loaded = 'yes'
1266
1267 export def Toggle(): string
1268 return ":g:toggle_called = 'yes'\<CR>"
1269 enddef
1270 END
1271 writefile(lines, 'Xdir/autoload/toggle.vim')
1272
1273 lines =<< trim END
1274 vim9script
1275
1276 import autoload 'toggle.vim'
1277
1278 nnoremap <silent> <expr> tt toggle.Toggle()
1279 END
1280 CheckScriptSuccess(lines)
1281 assert_false(exists("g:toggle_loaded"))
1282 assert_false(exists("g:toggle_called"))
1283
1284 feedkeys("tt", 'xt')
1285 assert_equal('yes', g:toggle_loaded)
1286 assert_equal('yes', g:toggle_called)
1287
1288 nunmap tt
1289 unlet g:toggle_loaded
1290 unlet g:toggle_called
1291 delete('Xdir', 'rf')
1292 &rtp = save_rtp
1293enddef
1294
Bram Moolenaar160aa862022-01-10 21:29:57 +00001295def Test_vim9script_autoload_fails()
1296 var lines =<< trim END
1297 vim9script autoload
1298 var n = 0
1299 END
1300 CheckScriptFailure(lines, 'E1263:')
1301enddef
1302
1303def Test_import_autoload_fails()
1304 var lines =<< trim END
1305 vim9script
1306 import autoload autoload 'prefixed.vim'
1307 END
1308 CheckScriptFailure(lines, 'E121: Undefined variable: autoload')
1309
1310 lines =<< trim END
1311 vim9script
1312 import autoload 'doesNotExist.vim'
1313 END
1314 CheckScriptFailure(lines, 'E1264:')
1315enddef
1316
1317" test disassembling an auto-loaded function starting with "debug"
1318def Test_vim9_autoload_disass()
1319 mkdir('Xdir/autoload', 'p')
1320 var save_rtp = &rtp
1321 exe 'set rtp^=' .. getcwd() .. '/Xdir'
1322
1323 var lines =<< trim END
1324 vim9script
1325 def debugit#test(): string
1326 return 'debug'
1327 enddef
1328 END
1329 writefile(lines, 'Xdir/autoload/debugit.vim')
1330
1331 lines =<< trim END
1332 vim9script
1333 def profileit#test(): string
1334 return 'profile'
1335 enddef
1336 END
1337 writefile(lines, 'Xdir/autoload/profileit.vim')
1338
1339 lines =<< trim END
1340 vim9script
1341 assert_equal('debug', debugit#test())
1342 disass debugit#test
1343 assert_equal('profile', profileit#test())
1344 disass profileit#test
1345 END
1346 CheckScriptSuccess(lines)
1347
1348 delete('Xdir', 'rf')
1349 &rtp = save_rtp
1350enddef
1351
1352" test using a vim9script that is auto-loaded from an autocmd
1353def Test_vim9_aucmd_autoload()
1354 var lines =<< trim END
1355 vim9script
1356 def foo#test()
1357 echomsg getreg('"')
1358 enddef
1359 END
1360
1361 mkdir('Xdir/autoload', 'p')
1362 writefile(lines, 'Xdir/autoload/foo.vim')
1363 var save_rtp = &rtp
1364 exe 'set rtp^=' .. getcwd() .. '/Xdir'
1365 augroup test
1366 autocmd TextYankPost * call foo#test()
1367 augroup END
1368
1369 normal Y
1370
1371 augroup test
1372 autocmd!
1373 augroup END
1374 delete('Xdir', 'rf')
1375 &rtp = save_rtp
1376enddef
1377
Bram Moolenaar3049fcf2022-01-13 19:25:50 +00001378" test using a autoloaded file that is case sensitive
1379def Test_vim9_autoload_case_sensitive()
1380 var lines =<< trim END
1381 vim9script autoload
1382 export def CaseSensitive(): string
1383 return 'done'
1384 enddef
1385 END
1386
1387 mkdir('Xdir/autoload', 'p')
1388 writefile(lines, 'Xdir/autoload/CaseSensitive.vim')
1389 var save_rtp = &rtp
1390 exe 'set rtp^=' .. getcwd() .. '/Xdir'
1391
1392 lines =<< trim END
1393 vim9script
1394 import autoload 'CaseSensitive.vim'
1395 assert_equal('done', CaseSensitive.CaseSensitive())
1396 END
1397 CheckScriptSuccess(lines)
1398
1399 delete('Xdir', 'rf')
1400 &rtp = save_rtp
1401enddef
1402
Bram Moolenaar160aa862022-01-10 21:29:57 +00001403" This was causing a crash because suppress_errthrow wasn't reset.
1404def Test_vim9_autoload_error()
1405 var lines =<< trim END
1406 vim9script
1407 def crash#func()
1408 try
1409 for x in List()
1410 endfor
1411 catch
1412 endtry
1413 g:ok = true
1414 enddef
1415 fu List()
1416 invalid
1417 endfu
1418 try
1419 alsoinvalid
1420 catch /wontmatch/
1421 endtry
1422 END
1423 call mkdir('Xruntime/autoload', 'p')
1424 call writefile(lines, 'Xruntime/autoload/crash.vim')
1425
1426 # run in a separate Vim to avoid the side effects of assert_fails()
1427 lines =<< trim END
1428 exe 'set rtp^=' .. getcwd() .. '/Xruntime'
1429 call crash#func()
1430 call writefile(['ok'], 'Xdidit')
1431 qall!
1432 END
1433 writefile(lines, 'Xscript')
1434 RunVim([], [], '-S Xscript')
1435 assert_equal(['ok'], readfile('Xdidit'))
1436
1437 delete('Xdidit')
1438 delete('Xscript')
1439 delete('Xruntime', 'rf')
1440
1441 lines =<< trim END
1442 vim9script
1443 var foo#bar = 'asdf'
1444 END
1445 CheckScriptFailure(lines, 'E461: Illegal variable name: foo#bar', 2)
1446enddef
1447
Bram Moolenaard8448622022-01-07 21:39:52 +00001448
1449" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker