diff options
Diffstat (limited to '')
-rw-r--r-- | src/testdir/test_vim9_import.vim | 2923 |
1 files changed, 2923 insertions, 0 deletions
diff --git a/src/testdir/test_vim9_import.vim b/src/testdir/test_vim9_import.vim new file mode 100644 index 0000000..7d3691a --- /dev/null +++ b/src/testdir/test_vim9_import.vim @@ -0,0 +1,2923 @@ +" Test import/export of the Vim9 script language. +" Also the autoload mechanism. + +source check.vim +source term_util.vim +import './vim9.vim' as v9 + +let s:export_script_lines =<< trim END + vim9script + var name: string = 'bob' + def Concat(arg: string): string + return name .. arg + enddef + g:result = Concat('bie') + g:localname = name + + export const CONST = 1234 + export var exported = 9876 + export var exp_name = 'John' + export def Exported(): string + return 'Exported' + enddef + export def ExportedValue(): number + return exported + enddef + export def ExportedInc() + exported += 5 + enddef + export final theList = [1] + export def AddSome(s: string): string + return s .. 'some' + enddef + export var AddRef = AddSome +END + +def s:Undo_export_script_lines() + unlet g:result + unlet g:localname +enddef + +def Test_vim9_import_export() + writefile(s:export_script_lines, 'Xexport.vim', 'D') + var import_script_lines =<< trim END + vim9script + var dir = './' + var ext = ".vim" + import dir .. 'Xexport' .. ext as expo + + g:exported1 = expo.exported + expo.exported += 3 + g:exported2 = expo.exported + g:exported3 = expo.ExportedValue() + + expo.ExportedInc() + g:exported_i1 = expo.exported + g:exported_i2 = expo.ExportedValue() + + expo.exported = 11 + g:exported_s1 = expo.exported + g:exported_s2 = expo.ExportedValue() + + g:imported_func = expo.Exported() + + def GetExported(): string + var local_dict = {ref: expo.Exported} + return local_dict.ref() + enddef + g:funcref_result = GetExported() + + def GetName(): string + return expo.exp_name .. 'son' + enddef + g:long_name = GetName() + + g:imported_name = expo.exp_name + expo.exp_name ..= ' Doe' + expo.exp_name = expo.exp_name .. ' Maar' + g:imported_name_appended = expo.exp_name + g:exported_later = expo.exported + + expo.theList->add(2) + assert_equal([1, 2], expo.theList) + + assert_equal('andthensome', 'andthen'->expo.AddSome()) + assert_equal('awesome', 'awe'->expo.AddRef()) + END + writefile(import_script_lines, 'Ximport.vim', 'D') + source Ximport.vim + + assert_equal('bobbie', g:result) + assert_equal('bob', g:localname) + assert_equal(9876, g:exported1) + assert_equal(9879, g:exported2) + assert_equal(9879, g:exported3) + + assert_equal(9884, g:exported_i1) + assert_equal(9884, g:exported_i2) + + assert_equal(11, g:exported_s1) + assert_equal(11, g:exported_s2) + assert_equal(11, g:exported_later) + + assert_equal('Exported', g:imported_func) + assert_equal('Exported', g:funcref_result) + assert_equal('John', g:imported_name) + assert_equal('Johnson', g:long_name) + assert_equal('John Doe Maar', g:imported_name_appended) + assert_false(exists('g:name')) + + Undo_export_script_lines() + unlet g:exported1 + unlet g:exported2 + unlet g:exported3 + unlet g:exported_i1 + unlet g:exported_i2 + unlet g:exported_later + unlet g:imported_func + unlet g:imported_name g:long_name g:imported_name_appended + delete('Ximport.vim') + + # similar, with line breaks + var import_line_break_script_lines =<< trim END + vim9script + import './Xexport.vim' + as expo + g:exported = expo.exported + expo.exported += 7 + g:exported_added = expo.exported + g:imported_func = expo.Exported() + END + writefile(import_line_break_script_lines, 'Ximport_lbr.vim') + source Ximport_lbr.vim + + assert_equal(11, g:exported) + assert_equal(18, g:exported_added) + assert_equal('Exported', g:imported_func) + + # exported script not sourced again + assert_false(exists('g:result')) + unlet g:exported + unlet g:exported_added + unlet g:imported_func + delete('Ximport_lbr.vim') + + var import_shadows_cmdmod_lines =<< trim END + vim9script + import './Xexport.vim' as vim9 + vim9.exp_name = 'Shadow' + assert_equal('Shadow', vim9.exp_name) + END + v9.CheckScriptSuccess(import_shadows_cmdmod_lines) + + var line_break_before_dot =<< trim END + vim9script + import './Xexport.vim' as expo + g:exported = expo + .exported + END + writefile(line_break_before_dot, 'Ximport_lbr_before_dot.vim') + assert_fails('source Ximport_lbr_before_dot.vim', 'E1060:', '', 3) + delete('Ximport_lbr_before_dot.vim') + + var line_break_after_dot =<< trim END + vim9script + import './Xexport.vim' as expo + g:exported = expo. + exported + END + writefile(line_break_after_dot, 'Ximport_lbr_after_dot.vim') + assert_fails('source Ximport_lbr_after_dot.vim', 'E1074:', '', 3) + delete('Ximport_lbr_after_dot.vim') + + var import_star_as_lines =<< trim END + vim9script + import './Xexport.vim' as Export + def UseExport() + g:exported_def = Export.exported + enddef + g:exported_script = Export.exported + assert_equal(1, exists('Export.exported')) + assert_equal(0, exists('Export.notexported')) + UseExport() + END + writefile(import_star_as_lines, 'Ximport.vim') + source Ximport.vim + + assert_equal(18, g:exported_def) + assert_equal(18, g:exported_script) + unlet g:exported_def + unlet g:exported_script + + var import_star_as_lines_no_dot =<< trim END + vim9script + import './Xexport.vim' as Export + def Func() + var dummy = 1 + var imported = Export + dummy + enddef + defcompile + END + writefile(import_star_as_lines_no_dot, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E1060:', '', 2, 'Func') + + var import_star_as_lines_dot_space =<< trim END + vim9script + import './Xexport.vim' as Export + def Func() + var imported = Export . exported + enddef + defcompile + END + writefile(import_star_as_lines_dot_space, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E1074:', '', 1, 'Func') + + writefile(s:export_script_lines, 'Xexport2.vim') + var import_as_duplicated =<< trim END + vim9script + import './Xexport.vim' as expo + import './Xexport2.vim' as expo + END + writefile(import_as_duplicated, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E1073:', '', 3, 'Ximport.vim') + delete('Xexport2.vim') + + var import_star_as_lines_script_no_dot =<< trim END + vim9script + import './Xexport.vim' as Export + g:imported_script = Export exported + END + writefile(import_star_as_lines_script_no_dot, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E1060: Expected dot after name: Export exported') + + var import_star_as_lines_script_space_after_dot =<< trim END + vim9script + import './Xexport.vim' as Export + g:imported_script = Export. exported + END + writefile(import_star_as_lines_script_space_after_dot, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E1074:') + + var import_star_as_lines_missing_name =<< trim END + vim9script + import './Xexport.vim' as Export + def Func() + var imported = Export. + enddef + defcompile + END + writefile(import_star_as_lines_missing_name, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E1048:', '', 1, 'Func') + + var import_star_as_lbr_lines =<< trim END + vim9script + import './Xexport.vim' + as Export + def UseExport() + g:exported = Export.exported + enddef + UseExport() + END + writefile(import_star_as_lbr_lines, 'Ximport.vim') + source Ximport.vim + assert_equal(18, g:exported) + unlet g:exported + + # try to use something that exists but is not exported + var import_not_exported_lines =<< trim END + vim9script + import './Xexport.vim' as expo + echo expo.name + END + writefile(import_not_exported_lines, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E1049:', '', 3, 'Ximport.vim') + + # try to import something that is already defined + var import_already_defined =<< trim END + vim9script + var exported = 'something' + import './Xexport.vim' as exported + END + writefile(import_already_defined, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E1054:', '', 3, 'Ximport.vim') + + # try changing an imported const + var import_assign_to_const =<< trim END + vim9script + import './Xexport.vim' as expo + def Assign() + expo.CONST = 987 + enddef + defcompile + END + writefile(import_assign_to_const, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E46:', '', 1, '_Assign') + + # try changing an imported final + var import_assign_to_final =<< trim END + vim9script + import './Xexport.vim' as expo + def Assign() + expo.theList = [2] + enddef + defcompile + END + writefile(import_assign_to_final, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E46:', '', 1, '_Assign') + + var import_no_as_lines =<< trim END + vim9script + import './Xexport.vim' name + END + writefile(import_no_as_lines, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E488:', '', 2, 'Ximport.vim') + + # trailing starts with "as" + var import_bad_as_lines =<< trim END + vim9script + import './Xexport.vim' asname + END + writefile(import_no_as_lines, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E488:', '', 2, 'Ximport.vim') + + var import_invalid_string_lines =<< trim END + vim9script + import Xexport.vim + END + writefile(import_invalid_string_lines, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E121:', '', 2, 'Ximport.vim') + + var import_wrong_name_lines =<< trim END + vim9script + import './XnoExport.vim' + END + writefile(import_wrong_name_lines, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E1053:', '', 2, 'Ximport.vim') + + var import_redefining_lines =<< trim END + vim9script + import './Xexport.vim' as exported + var exported = 5 + END + writefile(import_redefining_lines, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E1213: Redefining imported item "exported"', '', 3) + + var import_missing_dot_lines =<< trim END + vim9script + import './Xexport.vim' as expo + def Test() + expo = 9 + enddef + defcompile + END + writefile(import_missing_dot_lines, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E1258:', '', 1) + + var import_missing_name_lines =<< trim END + vim9script + import './Xexport.vim' as expo + def Test() + expo.99 = 9 + enddef + defcompile + END + writefile(import_missing_name_lines, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E1259:', '', 1) + + var import_assign_wrong_type_lines =<< trim END + vim9script + import './Xexport.vim' as expo + expo.exported = 'xxx' + END + writefile(import_assign_wrong_type_lines, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E1012: Type mismatch; expected number but got string', '', 3) + + var import_assign_const_lines =<< trim END + vim9script + import './Xexport.vim' as expo + expo.CONST = 4321 + END + writefile(import_assign_const_lines, 'Ximport.vim') + assert_fails('source Ximport.vim', 'E46: Cannot change read-only variable "CONST"', '', 3) + + # Check that in a Vim9 script 'cpo' is set to the Vim default. + # Flags added or removed are also applied to the restored value. + set cpo=abcd + var lines =<< trim END + vim9script + g:cpo_in_vim9script = &cpo + set cpo+=f + set cpo-=c + g:cpo_after_vim9script = &cpo + END + writefile(lines, 'Xvim9_script', 'D') + source Xvim9_script + assert_equal('fabd', &cpo) + set cpo&vim + assert_equal(&cpo, g:cpo_in_vim9script) + var newcpo = substitute(&cpo, 'c', '', '') .. 'f' + assert_equal(newcpo, g:cpo_after_vim9script) + + delete('Xvim9_script') +enddef + +def Test_import_very_long_name() + var lines =<< trim END + vim9script + + export var verylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongname = 'asdf' + END + writefile(lines, 'Xverylong.vim', 'D') + + lines =<< trim END + vim9script + import './Xverylong.vim' + + g:result = Xverylong.verylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongnameverylongname + END + v9.CheckScriptSuccess(lines) + assert_equal('asdf', g:result) + + unlet g:result +enddef + +def Test_import_funcref() + var lines =<< trim END + vim9script + export def F(): number + return 42 + enddef + export const G = F + END + writefile(lines, 'Xlib.vim', 'D') + + lines =<< trim END + vim9script + import './Xlib.vim' as lib + const Foo = lib.G() + assert_equal(42, Foo) + + def DoTest() + const Goo = lib.G() + assert_equal(42, Goo) + enddef + DoTest() + END + v9.CheckScriptSuccess(lines) +enddef + +def Test_export_closure() + # tests that the closure in block can be compiled, not the import part + var lines =<< trim END + vim9script + { + var foo = 42 + export def Bar(): number + return foo + enddef + } + assert_equal(42, Bar()) + END + v9.CheckScriptSuccess(lines) +enddef + +def Test_import_duplicate_function() + # Function Hover() exists in both scripts, partial should refer to the right + # one. + var lines =<< trim END + vim9script + + def Hover(d: dict<any>): string + return 'found it' + enddef + + export def NewLspServer(): dict<any> + var d: dict<any> = {} + d->extend({hover: function('Hover', [d])}) + return d + enddef + + NewLspServer() + END + writefile(lines, 'Xserver.vim', 'D') + + lines =<< trim END + vim9script + + import './Xserver.vim' as server + + export def Hover() + enddef + + def AddServer() + var d: dict<any> = server.NewLspServer() + assert_equal('found it', d.hover()) + enddef + AddServer() + END + v9.CheckScriptSuccess(lines) +enddef + + +def Test_import_fails() + writefile([], 'Xfoo.vim', 'D') + var lines =<< trim END + import './Xfoo.vim' as foo + foo = 'bar' + END + v9.CheckDefAndScriptFailure(lines, ['E1094:', 'E1236: Cannot use foo itself']) + lines =<< trim END + vim9script + import './Xfoo.vim' as foo + var that = foo + END + v9.CheckScriptFailure(lines, 'E1060: Expected dot after name: foo') + lines =<< trim END + vim9script + import './Xfoo.vim' as foo + var that: any + that += foo + END + v9.CheckScriptFailure(lines, 'E1060: Expected dot after name: foo') + lines =<< trim END + vim9script + import './Xfoo.vim' as foo + foo += 9 + END + v9.CheckScriptFailure(lines, 'E1060: Expected dot after name: foo') + + lines =<< trim END + vim9script + import './Xfoo.vim' as 9foo + END + v9.CheckScriptFailure(lines, 'E1047:') + lines =<< trim END + vim9script + import './Xfoo.vim' as the#foo + END + v9.CheckScriptFailure(lines, 'E1047:') + lines =<< trim END + vim9script + import './Xfoo.vim' as g:foo + END + v9.CheckScriptFailure(lines, 'E1047:') + + lines =<< trim END + vim9script + def TheFunc() + echo 'the func' + enddef + export var Ref = TheFunc + END + writefile([], 'Xthat.vim') + + lines =<< trim END + import './Xthat.vim' as That + That() + END + v9.CheckDefAndScriptFailure(lines, ['E1094:', 'E1236: Cannot use That itself']) + + lines =<< trim END + vim9script + import './Xthat.vim' as That + def Func() + echo That() + enddef + Func() + END + v9.CheckScriptFailure(lines, 'E1236: Cannot use That itself') + + lines =<< trim END + import './Xthat.vim' as one + import './Xthat.vim' as two + END + v9.CheckScriptFailure(lines, 'E1262:') + + delete('Xthat.vim') + + lines =<< trim END + vim9script + export var item = 'hello' + import './Xyourself.vim' + END + writefile(lines, 'Xyourself.vim', 'D') + assert_fails('source Xyourself.vim', 'E1088:') + + mkdir('Ximport', 'R') + + writefile(['vim9script'], 'Ximport/.vim') + lines =<< trim END + vim9script + import './Ximport/.vim' + END + v9.CheckScriptFailure(lines, 'E1261: Cannot import .vim without using "as"') + lines =<< trim END + vim9script + import './Ximport/.vim' as vim + END + v9.CheckScriptSuccess(lines) + + writefile(['vim9script'], 'Ximport/.vimrc') + lines =<< trim END + vim9script + import './Ximport/.vimrc' + END + v9.CheckScriptFailure(lines, 'E1257: Imported script must use "as" or end in .vim') + lines =<< trim END + vim9script + import './Ximport/.vimrc' as vimrc + END + v9.CheckScriptSuccess(lines) + + new + setline(1, ['vim9script', 'import "" as abc']) + assert_fails('source', 'E1071: Invalid string for :import: "" as abc') + setline(2, 'import [] as abc') + assert_fails('source', 'E1071: Invalid string for :import: [] as abc') + setline(2, 'import test_null_string() as abc') + assert_fails('source', 'E1071: Invalid string for :import: test_null_string() as abc') + bw! + call writefile(['vim9script', "import './Xfoo.vim' ask expo"], 'Xbar.vim') + assert_fails('source Xbar.vim', 'E488: Trailing characters: ask expo') + writefile([], 'Xtemp') + call writefile(['vim9script', "import './Xtemp'"], 'Xbar.vim') + assert_fails('source Xbar.vim', 'E1257: Imported script must use "as" or end in .vim: Xtemp') + delete('Xtemp') + call writefile(['vim9script', "import './Xfoo.vim' as abc | foobar"], 'Xbar.vim') + assert_fails('source Xbar.vim', 'E492: Not an editor command: foobar') + call delete('Xbar.vim') +enddef + +func g:Trigger() + source Ximport.vim + return "echo 'yes'\<CR>" +endfunc + +def Test_import_export_expr_map() + # check that :import and :export work when buffer is locked + var export_lines =<< trim END + vim9script + export def That(): string + return 'yes' + enddef + END + writefile(export_lines, 'Xexport_that.vim', 'D') + + var import_lines =<< trim END + vim9script + import './Xexport_that.vim' as that + assert_equal('yes', that.That()) + END + writefile(import_lines, 'Ximport.vim', 'D') + + nnoremap <expr> trigger g:Trigger() + feedkeys('trigger', "xt") + + nunmap trigger +enddef + +def Test_import_in_filetype() + # check that :import works when the buffer is locked + mkdir('ftplugin', 'pR') + var export_lines =<< trim END + vim9script + export var That = 'yes' + END + writefile(export_lines, 'ftplugin/Xexport_ft.vim') + + var import_lines =<< trim END + vim9script + import './Xexport_ft.vim' as ft + assert_equal('yes', ft.That) + g:did_load_mytpe = 1 + END + writefile(import_lines, 'ftplugin/qf.vim') + + var save_rtp = &rtp + &rtp = getcwd() .. ',' .. &rtp + + filetype plugin on + copen + assert_equal(1, g:did_load_mytpe) + + quit! + &rtp = save_rtp +enddef + +def Test_use_import_in_mapping() + var lines =<< trim END + vim9script + export def Funcx(nr: number) + g:result = nr + enddef + END + writefile(lines, 'XsomeExport.vim', 'D') + lines =<< trim END + vim9script + import './XsomeExport.vim' as some + var Funcy = some.Funcx + nnoremap <F3> :call <sid>Funcy(42)<cr> + nnoremap <F4> :call <sid>some.Funcx(44)<cr> + END + writefile(lines, 'Xmapscript.vim', 'D') + + source Xmapscript.vim + feedkeys("\<F3>", "xt") + assert_equal(42, g:result) + feedkeys("\<F4>", "xt") + assert_equal(44, g:result) + + unlet g:result + nunmap <F3> + nunmap <F4> +enddef + +def Test_use_relative_autoload_import_in_mapping() + var lines =<< trim END + vim9script + export def Func() + g:result = 42 + enddef + END + writefile(lines, 'XrelautoloadExport.vim', 'D') + lines =<< trim END + vim9script + import autoload './XrelautoloadExport.vim' as some + nnoremap <F3> :call <SID>some.Func()<CR> + END + writefile(lines, 'Xmapscript.vim', 'D') + + source Xmapscript.vim + assert_match('\d\+ A: .*XrelautoloadExport.vim', execute('scriptnames')->split("\n")[-1]) + var l = getscriptinfo() + assert_match('XrelautoloadExport.vim$', l[-1].name) + assert_true(l[-1].autoload) + feedkeys("\<F3>", "xt") + assert_equal(42, g:result) + l = getscriptinfo({name: 'XrelautoloadExport'}) + assert_true(len(l) == 1) + assert_match('XrelautoloadExport.vim$', l[0].name) + assert_false(l[0].autoload) + assert_equal(999999, l[0].version) + + unlet g:result + nunmap <F3> +enddef + +def Test_autoload_import_var() + # variable name starts with "autoload" + var lines =<< trim END + vim9script + var autoloaded = "Xtest.vim" + import autoloaded + END + v9.CheckScriptFailure(lines, 'E1053: Could not import "Xtest.vim') +enddef + +def Test_use_autoload_import_in_mapping() + var lines =<< trim END + vim9script + export def Func() + g:result = 49 + enddef + END + mkdir('Ximpdir/autoload', 'pR') + writefile(lines, 'Ximpdir/autoload/XautoloadExport.vim') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Ximpdir' + + lines =<< trim END + vim9script + import autoload 'XautoloadExport.vim' as some + nnoremap <F3> :call <SID>some.Func()<CR> + END + writefile(lines, 'Xmapscript.vim', 'D') + + source Xmapscript.vim + assert_match('\d\+ A: .*autoload/XautoloadExport.vim', execute('scriptnames')->split("\n")[-1]) + feedkeys("\<F3>", "xt") + assert_equal(49, g:result) + + unlet g:result + nunmap <F3> + &rtp = save_rtp +enddef + +def Test_use_import_in_command_completion() + var lines =<< trim END + vim9script + export def Complete(..._): list<string> + return ['abcd'] + enddef + END + writefile(lines, 'Xscript.vim', 'D') + + lines =<< trim END + vim9script + import './Xscript.vim' + + command -nargs=1 -complete=customlist,Xscript.Complete Cmd echo 'ok' + feedkeys(":Cmd ab\<Tab>\<C-B>#\<CR>", 'xnt') + assert_equal('#Cmd abcd', @:) + END + v9.CheckScriptSuccess(lines) + + delcommand Cmd +enddef + +def Test_use_import_with_funcref_in_command_completion() + var lines =<< trim END + vim9script + export def Complete(..._): list<string> + return ['abcd'] + enddef + END + writefile(lines, 'Xscript.vim', 'D') + + lines =<< trim END + vim9script + import './Xscript.vim' + + var Ref = Xscript.Complete + exe "command -nargs=1 -complete=customlist," .. expand('<SID>') .. "Ref Cmd echo 'ok'" + feedkeys(":Cmd ab\<Tab>\<C-B>#\<CR>", 'xnt') + assert_equal('#Cmd abcd', @:) + END + v9.CheckScriptSuccess(lines) + + delcommand Cmd +enddef + +def Test_use_autoload_import_in_insert_completion() + mkdir('Xinsdir/autoload', 'pR') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xinsdir' + + var lines =<< trim END + vim9script + export def ThesaurusFunc(findbase: bool, _): any + if findbase + return 1 + endif + return [ + 'check', + 'experiment', + 'test', + 'verification' + ] + enddef + g:completion_loaded = 'yes' + END + writefile(lines, 'Xinsdir/autoload/completion.vim') + + new + lines =<< trim END + vim9script + g:completion_loaded = 'no' + import autoload 'completion.vim' + set thesaurusfunc=completion.ThesaurusFunc + assert_equal('no', g:completion_loaded) + feedkeys("i\<C-X>\<C-T>\<C-N>\<Esc>", 'xt') + assert_equal('experiment', getline(1)) + assert_equal('yes', g:completion_loaded) + END + v9.CheckScriptSuccess(lines) + + set thesaurusfunc= + bwipe! + &rtp = save_rtp +enddef + +def Test_use_autoload_import_partial_in_opfunc() + mkdir('Xpartdir/autoload', 'pR') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xpartdir' + + var lines =<< trim END + vim9script + export def Opfunc1(..._) + g:opfunc_called = 'yes' + enddef + END + writefile(lines, 'Xpartdir/autoload/opfunc.vim') + + new + lines =<< trim END + vim9script + import autoload 'opfunc.vim' + nnoremap <expr> <F3> TheFunc() + def TheFunc(): string + &operatorfunc = function('opfunc.Opfunc1', [0]) + return 'g@' + enddef + feedkeys("\<F3>l", 'xt') + assert_equal('yes', g:opfunc_called) + END + v9.CheckScriptSuccess(lines) + + set opfunc= + bwipe! + nunmap <F3> + &rtp = save_rtp +enddef + +def Test_set_opfunc_to_autoload_func_directly() + mkdir('Xdirdir/autoload', 'pR') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xdirdir' + + var lines =<< trim END + vim9script + export def Opfunc2(..._) + g:opfunc_called = 'yes' + enddef + END + writefile(lines, 'Xdirdir/autoload/opfunc.vim') + + new + lines =<< trim END + vim9script + import autoload 'opfunc.vim' + nnoremap <expr> <F3> TheFunc() + def TheFunc(): string + &operatorfunc = opfunc.Opfunc2 + return 'g@' + enddef + feedkeys("\<F3>l", 'xt') + assert_equal('yes', g:opfunc_called) + END + v9.CheckScriptSuccess(lines) + + set opfunc= + bwipe! + nunmap <F3> + &rtp = save_rtp +enddef + +def Test_use_autoload_import_in_fold_expression() + mkdir('Xfolddir/autoload', 'pR') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xfolddir' + + var lines =<< trim END + vim9script + export def Expr(): string + return getline(v:lnum) =~ '^#' ? '>1' : '1' + enddef + export def Text(): string + return 'fold text' + enddef + g:fold_loaded = 'yes' + END + writefile(lines, 'Xfolddir/autoload/fold.vim') + + lines =<< trim END + vim9script + import autoload 'fold.vim' + &foldexpr = 'fold.Expr()' + &foldtext = 'fold.Text()' + &foldmethod = 'expr' + &debug = 'throw' + END + new + setline(1, ['# one', 'text', '# two', 'text']) + g:fold_loaded = 'no' + v9.CheckScriptSuccess(lines) + assert_equal('no', g:fold_loaded) + redraw + assert_equal('yes', g:fold_loaded) + + # Check that script context of 'foldexpr' is copied to another buffer. + edit! otherfile + redraw + + set foldexpr= foldtext& foldmethod& debug= + bwipe! + &rtp = save_rtp +enddef + +def Test_autoload_import_relative() + var lines =<< trim END + vim9script + + g:loaded = 'yes' + export def RelFunc(): string + return 'relfunc' + enddef + def NotExported() + echo 'not' + enddef + + export var someText = 'some text' + var notexp = 'bad' + END + writefile(lines, 'XimportRel.vim', 'D') + writefile(lines, 'XimportRel2.vim', 'D') + writefile(lines, 'XimportRel3.vim', 'D') + writefile(lines, 'XimportRel4.vim', 'D') + writefile(lines, 'XimportRel5.vim', 'D') + + lines =<< trim END + vim9script + g:loaded = 'no' + import autoload './XimportRel.vim' + assert_equal('no', g:loaded) + + def AFunc(): string + var res = '' + res ..= XimportRel.RelFunc() + res ..= '/' + res ..= XimportRel.someText + XimportRel.someText = 'from AFunc' + return res + enddef + # script not loaded when compiling + defcompile + assert_equal('no', g:loaded) + + assert_equal('relfunc/some text', AFunc()) + assert_equal('yes', g:loaded) + unlet g:loaded + + assert_equal('from AFunc', XimportRel.someText) + XimportRel.someText = 'from script' + assert_equal('from script', XimportRel.someText) + END + v9.CheckScriptSuccess(lines) + + lines =<< trim END + vim9script + import autoload './XimportRel.vim' + echo XimportRel.NotExported() + END + v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: NotExported', 3) + + lines =<< trim END + vim9script + import autoload './XimportRel.vim' + echo XimportRel.notexp + END + v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: notexp', 3) + + lines =<< trim END + vim9script + import autoload './XimportRel.vim' + XimportRel.notexp = 'bad' + END + v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: notexp', 3) + + lines =<< trim END + vim9script + import autoload './XimportRel.vim' + def Func() + echo XimportRel.NotExported() + enddef + Func() + END + v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: NotExported', 1) + + lines =<< trim END + vim9script + import autoload './XimportRel.vim' + def Func() + echo XimportRel.notexp + enddef + Func() + END + v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: notexp', 1) + + # Same, script not imported before + lines =<< trim END + vim9script + import autoload './XimportRel4.vim' + def Func() + echo XimportRel4.notexp + enddef + Func() + END + v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: notexp', 1) + + # does not fail if the script wasn't loaded yet and only compiling + g:loaded = 'no' + lines =<< trim END + vim9script + import autoload './XimportRel2.vim' + def Func() + echo XimportRel2.notexp + enddef + defcompile + END + v9.CheckScriptSuccess(lines) + assert_equal('no', g:loaded) + + lines =<< trim END + vim9script + import autoload './XimportRel.vim' + def Func() + XimportRel.notexp = 'bad' + enddef + Func() + END + v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: notexp', 1) + + # fails with a not loaded import + lines =<< trim END + vim9script + import autoload './XimportRel3.vim' + def Func() + XimportRel3.notexp = 'bad' + enddef + Func() + END + v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: notexp', 1) + assert_equal('yes', g:loaded) + unlet g:loaded + + lines =<< trim END + vim9script + import autoload './XimportRel5.vim' + def Func() + XimportRel5.nosuchvar = 'bad' + enddef + Func() + END + v9.CheckScriptFailure(lines, 'E121: Undefined variable: nosuchvar', 1) + unlet g:loaded + + # nasty: delete script after compiling function + writefile(['vim9script'], 'XimportRelDel.vim') + lines =<< trim END + vim9script + + import autoload './XimportRelDel.vim' + def DoIt() + echo XimportRelDel.var + enddef + defcompile + delete('XimportRelDel.vim') + DoIt() + END + v9.CheckScriptFailure(lines, 'E484:') +enddef + +def Test_autoload_import_relative_autoload_dir() + mkdir('autoload', 'pR') + var lines =<< trim END + vim9script + export def Bar() + g:called_bar = 'yes' + enddef + END + writefile(lines, 'autoload/script.vim') + + lines =<< trim END + vim9script + import autoload './autoload/script.vim' + def Foo() + script.Bar() + enddef + Foo() + assert_equal('yes', g:called_bar) + END + v9.CheckScriptSuccess(lines) + + unlet g:called_bar +enddef + +def Test_autoload_import_deleted() + var lines =<< trim END + vim9script + export const FOO = 1 + END + writefile(lines, 'Xa.vim', 'D') + + lines =<< trim END + vim9script + import autoload './Xa.vim' + + delete('Xa.vim') + var x = Xa.FOO + END + v9.CheckScriptFailure(lines, 'E484:') +enddef + +def Test_autoload_import_using_const() + mkdir('Xdir/autoload', 'pR') + var lines =<< trim END + vim9script + export const FOO = 42 + echomsg FOO + END + writefile(lines, 'Xdir/autoload/exp.vim') + + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xdir' + lines =<< trim END + vim9script + import autoload 'exp.vim' + assert_equal(42, exp.FOO) + END + v9.CheckScriptSuccess(lines) + &rtp = save_rtp +enddef + +func Test_import_in_diffexpr() + CheckExecutable diff + + call Run_Test_import_in_diffexpr() +endfunc + +def Run_Test_import_in_diffexpr() + var lines =<< trim END + vim9script + + export def DiffExpr() + # Prepend some text to check diff type detection + writefile(['warning', ' message'], v:fname_out) + silent exe '!diff ' .. v:fname_in .. ' ' + .. v:fname_new .. '>>' .. v:fname_out + enddef + END + writefile(lines, 'Xdiffexpr', 'D') + + lines =<< trim END + vim9script + import './Xdiffexpr' as diff + + set diffexpr=diff.DiffExpr() + set diffopt=foldcolumn:0 + END + v9.CheckScriptSuccess(lines) + + enew! + call setline(1, ['one', 'two', 'three']) + diffthis + + botright vert new + call setline(1, ['one', 'two', 'three.']) + diffthis + # we only check if this does not cause errors + redraw + + diffoff! + set diffexpr= + set diffopt& + bwipe! + bwipe! +enddef + +def Test_import_in_patchexpr() + var lines =<< trim END + vim9script + export def TPatch() + call writefile(['output file'], v:fname_out) + enddef + END + writefile(lines, 'Xpatchexpr', 'D') + + lines =<< trim END + vim9script + import './Xpatchexpr' as patch + set patchexpr=patch.TPatch() + END + v9.CheckScriptSuccess(lines) + + call writefile(['input file'], 'Xinput', 'D') + call writefile(['diff file'], 'Xdiff', 'D') + :%bwipe! + edit Xinput + diffpatch Xdiff + call assert_equal('output file', getline(1)) + + set patchexpr& + :%bwipe! +enddef + +def Test_import_in_formatexpr() + var lines =<< trim END + vim9script + export def MyFormatExpr(): number + g:did_format = 'yes' + return 0 + enddef + END + writefile(lines, 'Xformatter', 'D') + + lines =<< trim END + vim9script + import './Xformatter' as format + set formatexpr=format.MyFormatExpr() + END + v9.CheckScriptSuccess(lines) + + new + setline(1, ['a', 'b', 'c']) + normal gqG + assert_equal('yes', g:did_format) + + bwipe! + unlet g:did_format + set formatexpr= +enddef + +def Test_import_in_includeexpr() + writefile(['found it'], 'Xthisfile', 'D') + new + + var lines =<< trim END + vim9script + export def DoSub(): string + return substitute(v:fname, 'that', 'this', '') + enddef + END + writefile(lines, 'Xinclude.vim', 'D') + + lines =<< trim END + vim9script + import './Xinclude.vim' + set includeexpr=Xinclude.DoSub() + END + v9.CheckScriptSuccess(lines) + + setline(1, ['Xthatfile']) + exe "normal \<C-W>f" + assert_equal('Xthisfile', expand('%')) + + bwipe! + bwipe! + set includeexpr= +enddef + +def Test_import_in_indentexpr() + var lines =<< trim END + vim9script + export def GetIndent(): number + return 5 + enddef + END + writefile(lines, 'Xindenter', 'D') + + lines =<< trim END + vim9script + import './Xindenter' as indent + set indentexpr=indent.GetIndent() + set debug=throw + END + v9.CheckScriptSuccess(lines) + + new + setline(1, 'hello') + normal == + assert_equal(' hello', getline(1)) + + bwipe! + set indentexpr= debug= +enddef + +func Test_import_in_printexpr() + CheckFeature postscript + call Run_Test_import_in_printexpr() +endfunc + +def Run_Test_import_in_printexpr() + var lines =<< trim END + vim9script + export def PrintFile(): bool + g:printed = 'yes' + delete('v:fname_in') + return false + enddef + END + writefile(lines, 'Xprint.vim', 'D') + + lines =<< trim END + vim9script + import './Xprint.vim' + set printexpr=Xprint.PrintFile() + END + v9.CheckScriptSuccess(lines) + + help + hardcopy dummy args + assert_equal('yes', g:printed) + + set printexpr= +enddef + +def Test_import_in_charconvert() + var lines =<< trim END + vim9script + export def MakeUpper(): bool + var data = readfile(v:fname_in) + map(data, 'toupper(v:val)') + writefile(data, v:fname_out) + return false # success + enddef + END + writefile(lines, 'Xconvert.vim', 'D') + + lines =<< trim END + vim9script + import './Xconvert.vim' as conv + set charconvert=conv.MakeUpper() + END + v9.CheckScriptSuccess(lines) + + writefile(['one', 'two'], 'Xiicfile', 'D') + new Xiicfile + write ++enc=ucase Xiicfile1 + assert_equal(['ONE', 'TWO'], readfile('Xiicfile1')) + + delete('Xiicfile1') + bwipe! + set charconvert& +enddef + +func Test_import_in_spellsuggest_expr() + CheckFeature spell + call Run_Test_import_in_spellsuggest_expr() +endfunc + +def Run_Test_import_in_spellsuggest_expr() + var lines =<< trim END + vim9script + export def MySuggest(): list<any> + return [['Fox', 8], ['Fop', 9]] + enddef + END + writefile(lines, 'Xsuggest.vim', 'D') + + lines =<< trim END + vim9script + import './Xsuggest.vim' as sugg + set spell spellsuggest=expr:sugg.MySuggest() + END + v9.CheckScriptSuccess(lines) + + set verbose=1 # report errors + call assert_equal(['Fox', 'Fop'], spellsuggest('Fo', 2)) + + set nospell spellsuggest& verbose=0 +enddef + +def Test_import_in_lambda_method() + var lines =<< trim END + vim9script + export def Retarg(e: any): any + return e + enddef + END + writefile(lines, 'XexportRetarg.vim', 'D') + lines =<< trim END + vim9script + import './XexportRetarg.vim' + def Lambda(): string + var F = (x) => x->XexportRetarg.Retarg() + return F('arg') + enddef + assert_equal('arg', Lambda()) + END + v9.CheckScriptSuccess(lines) +enddef + +def Test_export_shadows_global_function() + mkdir('Xglobdir/autoload', 'pR') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xglobdir' + + var lines =<< trim END + vim9script + export def Shadow(): string + return 'Shadow()' + enddef + END + writefile(lines, 'Xglobdir/autoload/shadow.vim') + + lines =<< trim END + vim9script + + def g:Shadow(): string + return 'global' + enddef + + import autoload 'shadow.vim' + assert_equal('Shadow()', shadow.Shadow()) + END + v9.CheckScriptSuccess(lines) + + delfunc g:Shadow + bwipe! + &rtp = save_rtp +enddef + +def Test_export_fails() + v9.CheckScriptFailure(['export var some = 123'], 'E1042:') + v9.CheckScriptFailure(['vim9script', 'export var g:some'], 'E1022:') + v9.CheckScriptFailure(['vim9script', 'export echo 134'], 'E1043:') + v9.CheckScriptFailure(['vim9script', 'export function /a1b2c3'], 'E1044:') + + assert_fails('export echo 1', 'E1043:') +enddef + +func Test_import_fails_without_script() + CheckRunVimInTerminal + + " call indirectly to avoid compilation error for missing functions + call Run_Test_import_fails_on_command_line() +endfunc + +def Run_Test_import_fails_on_command_line() + var export =<< trim END + vim9script + export def Foo(): number + return 0 + enddef + END + writefile(export, 'XexportCmd.vim', 'D') + + var buf = g:RunVimInTerminal('-c "import Foo from ''./XexportCmd.vim''"', { + rows: 6, wait_for_ruler: 0}) + g:WaitForAssert(() => assert_match('^E1094:', term_getline(buf, 5))) + + g:StopVimInTerminal(buf) +enddef + +def Test_vim9_reload_noclear() + var lines =<< trim END + vim9script + export var exported = 'thexport' + + export def TheFunc(x = 0) + enddef + END + writefile(lines, 'XExportReload', 'D') + lines =<< trim END + vim9script noclear + g:loadCount += 1 + var reloaded = 'init' + import './XExportReload' as exp + + def Again(): string + return 'again' + enddef + + exp.TheFunc() + + if exists('loaded') | finish | endif + var loaded = true + + var notReloaded = 'yes' + reloaded = 'first' + def g:Values(): list<string> + return [reloaded, notReloaded, Again(), Once(), exp.exported] + enddef + + def Once(): string + return 'once' + enddef + END + writefile(lines, 'XReloaded', 'D') + g:loadCount = 0 + source XReloaded + assert_equal(1, g:loadCount) + assert_equal(['first', 'yes', 'again', 'once', 'thexport'], g:Values()) + source XReloaded + assert_equal(2, g:loadCount) + assert_equal(['init', 'yes', 'again', 'once', 'thexport'], g:Values()) + source XReloaded + assert_equal(3, g:loadCount) + assert_equal(['init', 'yes', 'again', 'once', 'thexport'], g:Values()) + + delfunc g:Values + unlet g:loadCount + + lines =<< trim END + vim9script + def Inner() + enddef + END + lines->writefile('XreloadScript.vim', 'D') + source XreloadScript.vim + + lines =<< trim END + vim9script + def Outer() + def Inner() + enddef + enddef + defcompile + END + lines->writefile('XreloadScript.vim') + source XreloadScript.vim +enddef + +def Test_vim_reload_noclear_arg_count() + var lines =<< trim END + vim9script noclear + + if !exists('g:didload') + def Test(a: string, b: string) + echo a b + enddef + def Call() + Test('a', 'b') + enddef + else + # redefine with one argument less + def Test(a: string) + echo a + enddef + endif + Call() + g:didload = 1 + END + lines->writefile('XreloadScript_1.vim', 'D') + source XreloadScript_1.vim + assert_fails('source XreloadScript_1.vim', 'E1106: One argument too many') + unlet g:didload + + lines =<< trim END + vim9script noclear + + if !exists('g:didload') + def Test(a: string, b: string, c: string) + echo a b + enddef + def Call() + Test('a', 'b', 'c') + enddef + else + # redefine with one argument less + def Test(a: string) + echo a + enddef + endif + Call() + g:didload = 1 + END + lines->writefile('XreloadScript_2.vim', 'D') + source XreloadScript_2.vim + assert_fails('source XreloadScript_2.vim', 'E1106: 2 arguments too many') + unlet g:didload + + lines =<< trim END + vim9script noclear + + if !exists('g:didload') + def Test(a: string) + echo a + enddef + def Call() + Test('a') + enddef + else + # redefine with one argument extra + def Test(a: string, b: string) + echo a b + enddef + endif + Call() + g:didload = 1 + END + lines->writefile('XreloadScript_3.vim', 'D') + source XreloadScript_3.vim + assert_fails('source XreloadScript_3.vim', 'E1190: One argument too few') + unlet g:didload + + lines =<< trim END + vim9script noclear + + if !exists('g:didload') + def Test(a: string) + echo a + enddef + def Call() + Test('a') + enddef + else + # redefine with two arguments extra + def Test(a: string, b: string, c: string) + echo a b + enddef + endif + Call() + g:didload = 1 + END + lines->writefile('XreloadScript_4.vim', 'D') + source XreloadScript_4.vim + assert_fails('source XreloadScript_4.vim', 'E1190: 2 arguments too few') + unlet g:didload +enddef + +def Test_vim9_reload_noclear_error() + var lines =<< trim END + vim9script noclear + + if !exists('g:didload') + def Test(a: string) + echo a + enddef + def Call() + Test('a') + enddef + else + # redefine with a compile error + def Test(a: string) + echo ax + enddef + endif + Call() + g:didload = 1 + END + lines->writefile('XreloadScriptErr.vim', 'D') + source XreloadScriptErr.vim + assert_fails('source XreloadScriptErr.vim', 'E1001: Variable not found: ax') + + unlet g:didload +enddef + +def Test_vim9_reload_import() + var lines =<< trim END + vim9script + const var = '' + var valone = 1234 + def MyFunc(arg: string) + valone = 5678 + enddef + END + var morelines =<< trim END + var valtwo = 222 + export def GetValtwo(): number + return valtwo + enddef + END + writefile(lines + morelines, 'Xreload.vim', 'D') + source Xreload.vim + source Xreload.vim + source Xreload.vim + + # cannot declare a var twice + lines =<< trim END + vim9script + var valone = 1234 + var valone = 5678 + END + writefile(lines, 'Xreload.vim') + assert_fails('source Xreload.vim', 'E1041:', '', 3, 'Xreload.vim') + + delete('Ximport.vim') +enddef + +" if a script is reloaded with a script-local variable that changed its type, a +" compiled function using that variable must fail. +def Test_script_reload_change_type() + var lines =<< trim END + vim9script noclear + var str = 'string' + def g:GetStr(): string + return str .. 'xxx' + enddef + END + writefile(lines, 'Xreload.vim', 'D') + source Xreload.vim + echo g:GetStr() + + lines =<< trim END + vim9script noclear + var str = 1234 + END + writefile(lines, 'Xreload.vim') + source Xreload.vim + assert_fails('echo g:GetStr()', 'E1150:') + + delfunc g:GetStr +enddef + +" Define CallFunc so that the test can be compiled +command CallFunc echo 'nop' + +def Test_script_reload_from_function() + var lines =<< trim END + vim9script + + if exists('g:loadedThis') + finish + endif + g:loadedThis = 1 + delcommand CallFunc + command CallFunc Func() + def Func() + so XreloadFunc.vim + g:didTheFunc = 1 + enddef + END + writefile(lines, 'XreloadFunc.vim', 'D') + source XreloadFunc.vim + CallFunc + assert_equal(1, g:didTheFunc) + + delcommand CallFunc + unlet g:loadedThis + unlet g:didTheFunc +enddef + +def s:RetSome(): string + return 'some' +enddef + +" Not exported function that is referenced needs to be accessed by the +" script-local name. +def Test_vim9_funcref() + var sortlines =<< trim END + vim9script + def Compare(i1: number, i2: number): number + return i2 - i1 + enddef + + export def FastSort(): list<number> + return range(5)->sort(Compare) + enddef + + export def GetString(arg: string): string + return arg + enddef + END + writefile(sortlines, 'Xsort.vim', 'D') + + var lines =<< trim END + vim9script + import './Xsort.vim' + def Test() + g:result = Xsort.FastSort() + enddef + Test() + END + writefile(lines, 'Xscript.vim', 'D') + source Xscript.vim + assert_equal([4, 3, 2, 1, 0], g:result) + unlet g:result + + lines =<< trim END + vim9script + # using a function imported with "as" + import './Xsort.vim' as anAlias + assert_equal('yes', anAlias.GetString('yes')) + + # using the function from a compiled function + def TestMore(): string + var s = s:anAlias.GetString('foo') + return s .. anAlias.GetString('bar') + enddef + assert_equal('foobar', TestMore()) + + # error when using a function that isn't exported + assert_fails('anAlias.Compare(1, 2)', 'E1049:') + END + writefile(lines, 'Xscript.vim') + + var Funcref = function('s:RetSome') + assert_equal('some', Funcref()) +enddef + +" Check that when searching for "FilterFunc" it finds the import in the +" script where FastFilter() is called from, both as a string and as a direct +" function reference. +def Test_vim9_funcref_other_script() + var filterLines =<< trim END + vim9script + export def FilterFunc(idx: number, val: number): bool + return idx % 2 == 1 + enddef + export def FastFilter(): list<number> + return range(10)->filter('FilterFunc(v:key, v:val)') + enddef + export def FastFilterDirect(): list<number> + return range(10)->filter(FilterFunc) + enddef + END + writefile(filterLines, 'Xfilter.vim', 'D') + + var lines =<< trim END + vim9script + import './Xfilter.vim' as filter + def Test() + var x: list<number> = filter.FastFilter() + enddef + Test() + def TestDirect() + var x: list<number> = filter.FastFilterDirect() + enddef + TestDirect() + END + v9.CheckScriptSuccess(lines) +enddef + +def Test_import_absolute() + var import_lines = [ + 'vim9script', + 'import "' .. escape(getcwd(), '\') .. '/Xexport_abs.vim" as abs', + 'def UseExported()', + ' g:imported_abs = abs.exported', + ' abs.exported = 8888', + ' g:imported_after = abs.exported', + 'enddef', + 'UseExported()', + 'g:import_disassembled = execute("disass UseExported")', + ] + writefile(import_lines, 'Ximport_abs.vim', 'D') + writefile(s:export_script_lines, 'Xexport_abs.vim', 'D') + + source Ximport_abs.vim + + assert_equal(9876, g:imported_abs) + assert_equal(8888, g:imported_after) + assert_match('<SNR>\d\+_UseExported\_s*' .. + 'g:imported_abs = abs.exported\_s*' .. + '0 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' .. + '1 STOREG g:imported_abs\_s*' .. + 'abs.exported = 8888\_s*' .. + '2 PUSHNR 8888\_s*' .. + '3 STORESCRIPT exported-2 in .*Xexport_abs.vim\_s*' .. + 'g:imported_after = abs.exported\_s*' .. + '4 LOADSCRIPT exported-2 from .*Xexport_abs.vim\_s*' .. + '5 STOREG g:imported_after', + g:import_disassembled) + + Undo_export_script_lines() + unlet g:imported_abs + unlet g:import_disassembled +enddef + +def Test_import_rtp() + var import_lines = [ + 'vim9script', + 'import "Xexport_rtp.vim" as rtp', + 'g:imported_rtp = rtp.exported', + ] + writefile(import_lines, 'Ximport_rtp.vim', 'D') + mkdir('import', 'pR') + writefile(s:export_script_lines, 'import/Xexport_rtp.vim') + + var save_rtp = &rtp + &rtp = getcwd() + source Ximport_rtp.vim + &rtp = save_rtp + + assert_equal(9876, g:imported_rtp) + + Undo_export_script_lines() + unlet g:imported_rtp +enddef + +def Test_import_compile_error() + var export_lines = [ + 'vim9script', + 'export def ExpFunc(): string', + ' return notDefined', + 'enddef', + ] + writefile(export_lines, 'Xexported.vim', 'D') + + var import_lines = [ + 'vim9script', + 'import "./Xexported.vim" as expo', + 'def ImpFunc()', + ' echo expo.ExpFunc()', + 'enddef', + 'defcompile', + ] + writefile(import_lines, 'Ximport.vim', 'D') + + try + source Ximport.vim + catch /E1001/ + # Error should be before the Xexported.vim file. + assert_match('E1001: Variable not found: notDefined', v:exception) + assert_match('function <SNR>\d\+_ImpFunc\[1\]..<SNR>\d\+_ExpFunc, line 1', v:throwpoint) + endtry +enddef + +def Test_func_overrules_import_fails() + var export_lines =<< trim END + vim9script + export def Func() + echo 'imported' + enddef + END + writefile(export_lines, 'XexportedFunc.vim', 'D') + + var lines =<< trim END + vim9script + import './XexportedFunc.vim' as Func + def Func() + echo 'local to function' + enddef + END + v9.CheckScriptFailure(lines, 'E1213: Redefining imported item "Func"') + + lines =<< trim END + vim9script + import './XexportedFunc.vim' as Func + def Outer() + def Func() + echo 'local to function' + enddef + enddef + defcompile + END + v9.CheckScriptFailure(lines, 'E1236:') +enddef + +def Test_source_vim9_from_legacy() + var vim9_lines =<< trim END + vim9script + var local = 'local' + g:global = 'global' + export var exported = 'exported' + export def GetText(): string + return 'text' + enddef + END + writefile(vim9_lines, 'Xvim9_script.vim', 'D') + + var legacy_lines =<< trim END + source Xvim9_script.vim + + call assert_false(exists('local')) + call assert_false(exists('exported')) + call assert_false(exists('s:exported')) + call assert_equal('global', global) + call assert_equal('global', g:global) + END + writefile(legacy_lines, 'Xlegacy_script.vim', 'D') + + source Xlegacy_script.vim + assert_equal('global', g:global) + unlet g:global + + legacy_lines =<< trim END + import './Xvim9_script.vim' + let g:global = s:Xvim9_script.GetText() + END + writefile(legacy_lines, 'Xlegacyimport.vim', 'D') + source Xlegacyimport.vim + assert_equal('text', g:global) + unlet g:global +enddef + +def Test_import_vim9_from_legacy() + var vim9_lines =<< trim END + vim9script + var local = 'local' + g:global = 'global' + export var exported = 'exported' + export def GetText(): string + return 'text' + enddef + END + writefile(vim9_lines, 'Xvim9_export.vim', 'D') + + var legacy_lines =<< trim END + import './Xvim9_export.vim' as vim9 + + call assert_false(exists('vim9')) + call assert_false(exists('local')) + call assert_false(exists('s:vim9.local')) + call assert_equal('global', global) + call assert_equal('global', g:global) + call assert_false(exists('exported')) + call assert_false(exists('s:exported')) + call assert_false(exists('*GetText')) + + " imported symbol is script-local + call assert_equal('exported', s:vim9.exported) + call assert_equal('text', s:vim9.GetText()) + END + writefile(legacy_lines, 'Xlegacy_script.vim', 'D') + + source Xlegacy_script.vim + assert_equal('global', g:global) + unlet g:global +enddef + +def Test_cmdline_win() + # if the Vim syntax highlighting uses Vim9 constructs they can be used from + # the command line window. + mkdir('rtp/syntax', 'pR') + var export_lines =<< trim END + vim9script + export var That = 'yes' + END + writefile(export_lines, 'rtp/syntax/Xexport.vim') + var import_lines =<< trim END + vim9script + import './Xexport.vim' as exp + echo exp.That + END + writefile(import_lines, 'rtp/syntax/vim.vim') + var save_rtp = &rtp + &rtp = getcwd() .. '/rtp' .. ',' .. &rtp + syntax on + augroup CmdWin + autocmd CmdwinEnter * g:got_there = 'yes' + augroup END + # this will open and also close the cmdline window + feedkeys('q:', 'xt') + assert_equal('yes', g:got_there) + + augroup CmdWin + au! + augroup END + &rtp = save_rtp +enddef + +def Test_import_gone_when_sourced_twice() + var exportlines =<< trim END + vim9script + if exists('g:guard') + finish + endif + g:guard = 1 + export var name = 'someName' + END + writefile(exportlines, 'XexportScript.vim', 'D') + + var lines =<< trim END + vim9script + import './XexportScript.vim' as expo + def g:GetName(): string + return expo.name + enddef + END + writefile(lines, 'XscriptImport.vim', 'D') + so XscriptImport.vim + assert_equal('someName', g:GetName()) + + so XexportScript.vim + assert_fails('call g:GetName()', 'E1149:') + + delfunc g:GetName + unlet g:guard +enddef + +" test using an auto-loaded function and variable +def Test_vim9_autoload_full_name() + var lines =<< trim END + vim9script + export def Gettest(): string + return 'test' + enddef + g:some#name = 'name' + g:some#dict = {key: 'value'} + + export def Varargs(a1: string, ...l: list<string>): string + return a1 .. l[0] .. l[1] + enddef + END + + mkdir('Xfulldir/autoload', 'pR') + writefile(lines, 'Xfulldir/autoload/some.vim') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xfulldir' + + assert_equal('test', g:some#Gettest()) + assert_equal('name', g:some#name) + assert_equal('value', g:some#dict.key) + g:some#other = 'other' + assert_equal('other', g:some#other) + + assert_equal('abc', some#Varargs('a', 'b', 'c')) + + # upper case script name works + lines =<< trim END + vim9script + export def GetOther(): string + return 'other' + enddef + END + writefile(lines, 'Xfulldir/autoload/Other.vim') + assert_equal('other', g:Other#GetOther()) + + &rtp = save_rtp +enddef + +def Test_vim9script_autoload() + mkdir('Xaldir/autoload', 'pR') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xaldir' + + # when the path has "/autoload/" prefix is not needed + var lines =<< trim END + vim9script + g:prefixed_loaded += 1 + + export def Gettest(): string + return 'test' + enddef + + export var name = 'name' + + export func GetFunc() + return Gettest() .. 'more' .. s:name + endfunc + + export def GetDef(): string + return Gettest() .. 'more' .. name + enddef + + export final fname = 'final' + export const cname = 'const' + END + writefile(lines, 'Xaldir/autoload/prefixed.vim') + + g:prefixed_loaded = 0 + g:expected_loaded = 0 + lines =<< trim END + vim9script + import autoload 'prefixed.vim' + assert_equal(g:expected_loaded, g:prefixed_loaded) + assert_equal('test', prefixed.Gettest()) + assert_equal(1, g:prefixed_loaded) + + assert_equal('testmorename', prefixed.GetFunc()) + assert_equal('testmorename', prefixed.GetDef()) + assert_equal('name', prefixed.name) + assert_equal('final', prefixed.fname) + assert_equal('const', prefixed.cname) + END + v9.CheckScriptSuccess(lines) + # can source it again, autoload script not loaded again + g:expected_loaded = 1 + v9.CheckScriptSuccess(lines) + + # can also get the items by autoload name + lines =<< trim END + call assert_equal('test', prefixed#Gettest()) + call assert_equal('testmorename', prefixed#GetFunc()) + call assert_equal('name', prefixed#name) + call assert_equal('final', prefixed#fname) + call assert_equal('const', prefixed#cname) + END + v9.CheckScriptSuccess(lines) + + unlet g:prefixed_loaded + unlet g:expected_loaded + &rtp = save_rtp +enddef + +def Test_import_autoload_not_exported() + mkdir('Xnimdir/autoload', 'pR') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xnimdir' + + # error when using an item that is not exported from an autoload script + var exportLines =<< trim END + vim9script + var notExported = 123 + def NotExport() + echo 'nop' + enddef + END + writefile(exportLines, 'Xnimdir/autoload/notExport1.vim') + + var lines =<< trim END + vim9script + import autoload 'notExport1.vim' + echo notExport1.notFound + END + v9.CheckScriptFailure(lines, 'E1048: Item not found in script: notFound') + + lines =<< trim END + vim9script + import autoload 'notExport1.vim' + echo notExport1.notExported + END + v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: notExported') + + lines =<< trim END + vim9script + import autoload 'notExport1.vim' + echo notExport1.NotFunc() + END + v9.CheckScriptFailure(lines, 'E1048: Item not found in script: NotFunc') + + lines =<< trim END + vim9script + import autoload 'notExport1.vim' + echo notExport1.NotExport() + END + v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: NotExport') + + lines =<< trim END + vim9script + import autoload 'notExport1.vim' + echo 'text'->notExport1.NotFunc() + END + v9.CheckScriptFailure(lines, 'E1048: Item not found in script: NotFunc') + + lines =<< trim END + vim9script + import autoload 'notExport1.vim' + echo 'text'->notExport1.NotExport() + END + v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: NotExport') + + # using a :def function we use a different autoload script every time so that + # the function is compiled without the script loaded + writefile(exportLines, 'Xnimdir/autoload/notExport2.vim') + lines =<< trim END + vim9script + import autoload 'notExport2.vim' + def Testit() + echo notExport2.notFound + enddef + Testit() + END + v9.CheckScriptFailure(lines, 'E1048: Item not found in script: notExport2#notFound') + + writefile(exportLines, 'Xnimdir/autoload/notExport3.vim') + lines =<< trim END + vim9script + import autoload 'notExport3.vim' + def Testit() + echo notExport3.notExported + enddef + Testit() + END + # don't get E1049 because it is too complicated to figure out + v9.CheckScriptFailure(lines, 'E1048: Item not found in script: notExport3#notExported') + + writefile(exportLines, 'Xnimdir/autoload/notExport4.vim') + lines =<< trim END + vim9script + import autoload 'notExport4.vim' + def Testit() + echo notExport4.NotFunc() + enddef + Testit() + END + v9.CheckScriptFailure(lines, 'E117: Unknown function: notExport4#NotFunc') + + writefile(exportLines, 'Xnimdir/autoload/notExport5.vim') + lines =<< trim END + vim9script + import autoload 'notExport5.vim' + def Testit() + echo notExport5.NotExport() + enddef + Testit() + END + v9.CheckScriptFailure(lines, 'E117: Unknown function: notExport5#NotExport') + + writefile(exportLines, 'Xnimdir/autoload/notExport6.vim') + lines =<< trim END + vim9script + import autoload 'notExport6.vim' + def Testit() + echo 'text'->notExport6.NotFunc() + enddef + Testit() + END + v9.CheckScriptFailure(lines, 'E117: Unknown function: notExport6#NotFunc') + + writefile(exportLines, 'Xnimdir/autoload/notExport7.vim') + lines =<< trim END + vim9script + import autoload 'notExport7.vim' + def Testit() + echo 'text'->notExport7.NotExport() + enddef + Testit() + END + v9.CheckScriptFailure(lines, 'E117: Unknown function: notExport7#NotExport') + + &rtp = save_rtp +enddef + +def Test_vim9script_autoload_call() + mkdir('Xcalldir/autoload', 'pR') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xcalldir' + + var lines =<< trim END + vim9script + + export def RetArg(arg: string): string + return arg + enddef + + export def Getother() + g:result = 'other' + enddef + END + writefile(lines, 'Xcalldir/autoload/another.vim') + + lines =<< trim END + vim9script + import autoload 'another.vim' + + # compile this before 'another.vim' is loaded + def CallAnother() + assert_equal('foo', 'foo'->another.RetArg()) + enddef + CallAnother() + + call another.Getother() + assert_equal('other', g:result) + + assert_equal('arg', call('another.RetArg', ['arg'])) + + verbose function another.Getother + # should we disallow this? + verbose function another#Getother + END + v9.CheckScriptSuccess(lines) + + unlet g:result + &rtp = save_rtp +enddef + +def Test_vim9script_noclear_autoload() + mkdir('Xnocdir/autoload', 'pR') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xnocdir' + + var lines =<< trim END + vim9script + export def Func(): string + return 'called' + enddef + g:double_loaded = 'yes' + END + writefile(lines, 'Xnocdir/autoload/double.vim') + + lines =<< trim END + vim9script noclear + if exists('g:script_loaded') + finish + endif + g:script_loaded = true + + import autoload 'double.vim' + nnoremap <F3> <ScriptCmd>g:result = double.Func()<CR> + END + g:double_loaded = 'no' + writefile(lines, 'Xloaddouble', 'D') + source Xloaddouble + assert_equal('no', g:double_loaded) + assert_equal(true, g:script_loaded) + source Xloaddouble + feedkeys("\<F3>", 'xt') + assert_equal('called', g:result) + assert_equal('yes', g:double_loaded) + + unlet g:double_loaded + unlet g:script_loaded + unlet g:result + &rtp = save_rtp +enddef + +def Test_vim9script_autoload_duplicate() + mkdir('Xdupdir/autoload', 'pR') + + var lines =<< trim END + vim9script + + export def Func() + enddef + + def Func() + enddef + END + writefile(lines, 'Xdupdir/autoload/dupfunc.vim') + assert_fails('source Xdupdir/autoload/dupfunc.vim', 'E1073:') + + lines =<< trim END + vim9script + + def Func() + enddef + + export def Func() + enddef + END + writefile(lines, 'Xdupdir/autoload/dup2func.vim') + assert_fails('source Xdupdir/autoload/dup2func.vim', 'E1073:') + + lines =<< trim END + vim9script + + def Func() + enddef + + export var Func = 'asdf' + END + writefile(lines, 'Xdupdir/autoload/dup3func.vim') + assert_fails('source Xdupdir/autoload/dup3func.vim', 'E1041: Redefining script item: "Func"') + + lines =<< trim END + vim9script + + export var Func = 'asdf' + + def Func() + enddef + END + writefile(lines, 'Xdupdir/autoload/dup4func.vim') + assert_fails('source Xdupdir/autoload/dup4func.vim', 'E1041:') + + lines =<< trim END + vim9script + + var Func = 'asdf' + + export def Func() + enddef + END + writefile(lines, 'Xdupdir/autoload/dup5func.vim') + assert_fails('source Xdupdir/autoload/dup5func.vim', 'E707:') + + lines =<< trim END + vim9script + + export def Func() + enddef + + var Func = 'asdf' + END + writefile(lines, 'Xdupdir/autoload/dup6func.vim') + assert_fails('source Xdupdir/autoload/dup6func.vim', 'E1041: Redefining script item: "Func"') +enddef + +def Test_autoload_missing_function_name() + mkdir('Xmisdir/autoload', 'pR') + + var lines =<< trim END + vim9script + + def loadme#() + enddef + END + writefile(lines, 'Xmisdir/autoload/loadme.vim') + assert_fails('source Xmisdir/autoload/loadme.vim', 'E129:') +enddef + +def Test_autoload_name_wrong() + var lines =<< trim END + def Xscriptname#Func() + enddef + END + writefile(lines, 'Xscriptname.vim', 'D') + v9.CheckScriptFailure(lines, 'E746:') + + mkdir('Xwrodir/autoload', 'pR') + lines =<< trim END + vim9script + def somescript#Func() + enddef + END + writefile(lines, 'Xwrodir/autoload/somescript.vim') + assert_fails('source Xwrodir/autoload/somescript.vim', 'E1263:') + + delete('Xwrodir', 'rf') +enddef + +def Test_import_autoload_postponed() + mkdir('Xpostdir/autoload', 'pR') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xpostdir' + + var lines =<< trim END + vim9script + + g:loaded_postponed = 'true' + export var variable = 'bla' + export def Function(): string + return 'bla' + enddef + END + writefile(lines, 'Xpostdir/autoload/postponed.vim') + + lines =<< trim END + vim9script + + import autoload 'postponed.vim' + def Tryit() + echo postponed.variable + echo postponed.Function() + enddef + defcompile + END + v9.CheckScriptSuccess(lines) + assert_false(exists('g:loaded_postponed')) + v9.CheckScriptSuccess(lines + ['Tryit()']) + assert_equal('true', g:loaded_postponed) + + unlet g:loaded_postponed + &rtp = save_rtp +enddef + +def Test_import_autoload_override() + mkdir('Xoverdir/autoload', 'pR') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xoverdir' + test_override('autoload', 1) + + var lines =<< trim END + vim9script + + g:loaded_override = 'true' + export var variable = 'bla' + export def Function(): string + return 'bla' + enddef + END + writefile(lines, 'Xoverdir/autoload/override.vim') + + lines =<< trim END + vim9script + + import autoload 'override.vim' + assert_equal('true', g:loaded_override) + + def Tryit() + echo override.doesNotExist + enddef + defcompile + END + v9.CheckScriptFailure(lines, 'E1048: Item not found in script: doesNotExist', 1) + + test_override('autoload', 0) + unlet g:loaded_override + &rtp = save_rtp +enddef + +def Test_autoload_mapping() + mkdir('Xmapdir/autoload', 'pR') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xmapdir' + + var lines =<< trim END + vim9script + + g:toggle_loaded = 'yes' + + export def Toggle(): string + return ":g:toggle_called = 'yes'\<CR>" + enddef + export def Doit() + g:doit_called = 'yes' + enddef + END + writefile(lines, 'Xmapdir/autoload/toggle.vim') + + lines =<< trim END + vim9script + + import autoload 'toggle.vim' + + nnoremap <silent> <expr> tt toggle.Toggle() + nnoremap <silent> xx <ScriptCmd>toggle.Doit()<CR> + nnoremap <silent> yy <Cmd>toggle.Doit()<CR> + END + v9.CheckScriptSuccess(lines) + assert_false(exists("g:toggle_loaded")) + assert_false(exists("g:toggle_called")) + assert_match('\d A: \f*[/\\]toggle.vim', execute('scriptnames')) + + feedkeys("tt", 'xt') + assert_equal('yes', g:toggle_loaded) + assert_equal('yes', g:toggle_called) + assert_match('\d: \f*[/\\]toggle.vim', execute('scriptnames')) + + feedkeys("xx", 'xt') + assert_equal('yes', g:doit_called) + + assert_fails('call feedkeys("yy", "xt")', 'E121: Undefined variable: toggle') + + nunmap tt + nunmap xx + nunmap yy + unlet g:toggle_loaded + unlet g:toggle_called + &rtp = save_rtp +enddef + +def Test_vim9script_autoload_fails() + var lines =<< trim END + vim9script autoload + var n = 0 + END + v9.CheckScriptFailure(lines, 'E475: Invalid argument: autoload') + + lines =<< trim END + vim9script noclear noclear + var n = 0 + END + v9.CheckScriptFailure(lines, 'E983: Duplicate argument: noclear') + + lines =<< trim END + vim9script noclears + var n = 0 + END + v9.CheckScriptFailure(lines, 'E475: Invalid argument: noclears') +enddef + +def Test_import_autoload_fails() + var lines =<< trim END + vim9script + import autoload autoload 'prefixed.vim' + END + v9.CheckScriptFailure(lines, 'E121: Undefined variable: autoload') + + lines =<< trim END + vim9script + import autoload './doesNotExist.vim' + END + v9.CheckScriptFailure(lines, 'E282:', 2) + + lines =<< trim END + vim9script + import autoload '/dir/doesNotExist.vim' + END + v9.CheckScriptFailure(lines, 'E282:', 2) + + lines =<< trim END + vim9script + import autoload '../testdir' + END + v9.CheckScriptFailure(lines, 'E17:', 2) + + lines =<< trim END + vim9script + import autoload 'doesNotExist.vim' + END + v9.CheckScriptFailure(lines, 'E1053: Could not import "doesNotExist.vim"') +enddef + +" test disassembling an auto-loaded function starting with "debug" +def Test_vim9_autoload_disass() + mkdir('Xdasdir/autoload', 'pR') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xdasdir' + + var lines =<< trim END + vim9script + export def Test(): string + return 'debug' + enddef + END + writefile(lines, 'Xdasdir/autoload/debugit.vim') + + lines =<< trim END + vim9script + export def Test(): string + return 'profile' + enddef + END + writefile(lines, 'Xdasdir/autoload/profileit.vim') + + lines =<< trim END + vim9script + assert_equal('debug', debugit#Test()) + disass debugit#Test + assert_equal('profile', profileit#Test()) + disass profileit#Test + END + v9.CheckScriptSuccess(lines) + + &rtp = save_rtp +enddef + +" test using a vim9script that is auto-loaded from an autocmd +def Test_vim9_aucmd_autoload() + var lines =<< trim END + vim9script + export def Test() + echomsg getreg('"') + enddef + END + + mkdir('Xauldir/autoload', 'pR') + writefile(lines, 'Xauldir/autoload/foo.vim') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xauldir' + augroup test + autocmd TextYankPost * call foo#Test() + augroup END + + normal Y + + augroup test + autocmd! + augroup END + &rtp = save_rtp +enddef + +" test using a autoloaded file that is case sensitive +def Test_vim9_autoload_case_sensitive() + var lines =<< trim END + vim9script + export def CaseSensitive(): string + return 'done' + enddef + END + + mkdir('Xcasedir/autoload', 'pR') + writefile(lines, 'Xcasedir/autoload/CaseSensitive.vim') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xcasedir' + + lines =<< trim END + vim9script + import autoload 'CaseSensitive.vim' + assert_equal('done', CaseSensitive.CaseSensitive()) + END + v9.CheckScriptSuccess(lines) + + if !has('fname_case') + lines =<< trim END + vim9script + import autoload 'CaseSensitive.vim' + import autoload 'casesensitive.vim' + END + v9.CheckScriptFailure(lines, 'E1262:') + endif + + &rtp = save_rtp +enddef + +" This was causing a crash because suppress_errthrow wasn't reset. +def Test_vim9_autoload_error() + var lines =<< trim END + vim9script + def crash#func() + try + for x in List() + endfor + catch + endtry + g:ok = true + enddef + fu List() + invalid + endfu + try + alsoinvalid + catch /wontmatch/ + endtry + END + call mkdir('Xruntime/autoload', 'pR') + call writefile(lines, 'Xruntime/autoload/crash.vim') + + # run in a separate Vim to avoid the side effects of assert_fails() + lines =<< trim END + exe 'set rtp^=' .. getcwd() .. '/Xruntime' + call crash#func() + call writefile(['ok'], 'Xdidit') + qall! + END + writefile(lines, 'Xscript', 'D') + g:RunVim([], [], '-S Xscript') + assert_equal(['ok'], readfile('Xdidit')) + + delete('Xdidit') + + lines =<< trim END + vim9script + var foo#bar = 'asdf' + END + v9.CheckScriptFailure(lines, 'E461: Illegal variable name: foo#bar', 2) +enddef + +def Test_vim9_import_symlink() + if !has('unix') + CheckUnix + else + mkdir('Xto/plugin', 'pR') + var lines =<< trim END + vim9script + import autoload 'bar.vim' + g:resultFunc = bar.Func() + g:resultValue = bar.value + END + writefile(lines, 'Xto/plugin/foo.vim') + + mkdir('Xto/autoload', 'pR') + lines =<< trim END + vim9script + export def Func(): string + return 'func' + enddef + export var value = 'val' + END + writefile(lines, 'Xto/autoload/bar.vim') + + var save_rtp = &rtp + &rtp = getcwd() .. '/Xfrom' + system('ln -s ' .. getcwd() .. '/Xto Xfrom') + + source Xfrom/plugin/foo.vim + assert_equal('func', g:resultFunc) + assert_equal('val', g:resultValue) + + var infoTo = getscriptinfo()->filter((_, v) => v.name =~ 'Xto/autoload/bar') + var infoFrom = getscriptinfo()->filter((_, v) => v.name =~ 'Xfrom/autoload/bar') + assert_equal(1, len(infoTo)) + assert_equal(1, len(infoFrom)) + assert_equal(infoTo[0].sid, infoFrom[0].sourced) + var output: string + redir => output + scriptnames + redir END + assert_match(infoFrom[0].sid .. '->' .. infoFrom[0].sourced .. '.*Xfrom', output) + + unlet g:resultFunc + unlet g:resultValue + &rtp = save_rtp + delete('Xfrom', 'rf') + endif +enddef + + +" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker |