Files
vim-mirror/src/testdir/test_vim9_import.vim
Yegappan Lakshmanan e9ae35f265 patch 9.1.1154: Vim9: not able to use autoload class accross scripts
Problem:  Vim9: not able to use autoload class accross scripts
Solution: make it work, re-enable the test (Yegappan Lakshmanan)

fixes: #15031
closes: #16748

Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
2025-02-27 19:12:00 +01:00

3699 lines
89 KiB
VimL
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
" 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
" autoload relative, access from compiled function.
" Github issues: #14565, #14579
def Test_autoload_import_relative_compiled_buffer()
var lines =<< trim END
vim9script
export def F1(): string
return 'InFile.vim'
enddef
END
writefile(lines, 'Ximportrelativebuffer.vim', 'D')
lines =<< trim END
vim9script
import autoload './Ximportrelativebuffer.vim' as xfile
def F(): string
return xfile.F1()
enddef
assert_equal('InFile.vim', F())
END
new
setline(1, lines)
:source
# source one more time to detect issues with clearing the script state and
# variables
:source
:bw!
enddef
" Test for relative import when sourcing a buffer in another directory
def Test_autoload_import_relative_from_buffer_in_dir()
mkdir('Ximportrelative/dir1/dir2', 'pR')
var lines =<< trim END
vim9script
export def F1(): string
return 'InFile.vim'
enddef
END
writefile(lines, 'Ximportrelative/dir1/dir2/Ximport.vim')
lines =<< trim END
vim9script
import autoload './Ximport.vim' as xfile
def F(): string
return xfile.F1()
enddef
assert_equal('InFile.vim', F())
END
writefile(lines, 'Ximportrelative/dir1/dir2/Xrelative.vim')
split Ximportrelative/dir1/dir2/Xrelative.vim
:source
# source one more time to detect issues with clearing the script state and
# variables
:source
:bw!
enddef
" Test modifying exported autoload variable. Github issue: #14591
def Test_autoload_export_variables()
mkdir('Xautoload_vars/autoload', 'pR')
var lines =<< trim END
vim9script
g:Xautoload_vars_autoload = true
export var val = 11
val = 42
END
# Test that the imported script, above, can modify the exported variable;
# and test that the importing script, below, can modify the variable.
writefile(lines, 'Xautoload_vars/autoload/Xauto_vars_f2.vim', 'D')
lines =<< trim END
vim9script
g:Xautoload_vars_autoload = false
import autoload './Xautoload_vars/autoload/Xauto_vars_f2.vim' as f2
# Verify that the import statement does not load the file.
assert_equal(false, g:Xautoload_vars_autoload)
def F(): number
return f2.val
enddef
# Verify compile does not load the file.
defcompile F
assert_equal(false, g:Xautoload_vars_autoload)
# load the file by accessing the exported variable
assert_equal(42, F())
assert_equal(true, g:Xautoload_vars_autoload)
unlet g:Xautoload_vars_autoload
assert_equal(42, f2.val)
f2.val = 17
assert_equal(17, f2.val)
def G()
f2.val = 19
enddef
G()
assert_equal(19, f2.val)
END
v9.CheckScriptSuccess(lines)
# Test const var is not modifiable.
lines =<< trim END
vim9script
export const val = 11
val = 42
END
writefile(lines, 'Xautoload_vars/autoload/Xauto_vars_f3.vim', 'D')
lines =<< trim END
vim9script
import autoload './Xautoload_vars/autoload/Xauto_vars_f3.vim' as f3
var x = f3.val
END
v9.CheckScriptFailure(lines, 'E46:')
# Test const var is not modifiable from importing script.
lines =<< trim END
vim9script
export const val = 11
END
writefile(lines, 'Xautoload_vars/autoload/Xauto_vars_f4.vim', 'D')
lines =<< trim END
vim9script
import autoload './Xautoload_vars/autoload/Xauto_vars_f4.vim' as f4
f4.val = 13
END
v9.CheckScriptFailure(lines, 'E46:')
# Test const var is not modifiable from importing script from :def.
# Github issue: #14606
lines =<< trim END
vim9script
export const val = 11
END
writefile(lines, 'Xautoload_vars/autoload/Xauto_vars_f5.vim', 'D')
lines =<< trim END
vim9script
import autoload './Xautoload_vars/autoload/Xauto_vars_f5.vim' as f5
def F()
f5.val = 13
enddef
F()
END
v9.CheckScriptFailure(lines, 'E741:')
# Still part of Github issue: #14606
lines =<< trim END
vim9script
export var val = 11
END
writefile(lines, 'Xautoload_vars/autoload/Xauto_vars_f6.vim', 'D')
lines =<< trim END
vim9script
import autoload './Xautoload_vars/autoload/Xauto_vars_f6.vim' as f6
def F()
f6.val = 13
enddef
F()
assert_equal(13, f6.val)
END
v9.CheckScriptSuccess(lines)
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
" Test for using an imported function as 'findfunc'
func Test_import_in_findfunc()
call Run_Test_import_in_findfunc()
endfunc
def Run_Test_import_in_findfunc()
var lines =<< trim END
vim9script
export def FindFunc(pat: string, cmdexpand: bool): list<string>
var fnames = ['Xfile1.c', 'Xfile2.c', 'Xfile3.c']
return fnames->filter((_, v) => v =~? pat)
enddef
END
writefile(lines, 'Xfindfunc', 'D')
# Test using the "set" command
lines =<< trim END
vim9script
import './Xfindfunc' as find1
set findfunc=find1.FindFunc
END
v9.CheckScriptSuccess(lines)
enew!
find Xfile2
assert_equal('Xfile2.c', @%)
bwipe!
botright vert new
find Xfile1
assert_equal('Xfile1.c', @%)
bw!
# Test using the option variable
lines =<< trim END
vim9script
import './Xfindfunc' as find2
&findfunc = find2.FindFunc
END
v9.CheckScriptSuccess(lines)
enew!
find Xfile2
assert_equal('Xfile2.c', @%)
bwipe!
botright vert new
find Xfile1
assert_equal('Xfile1.c', @%)
set findfunc=
bwipe!
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
export var exported_nr: number = 22
def AddNum(n: number)
exported_nr += n
enddef
export var exportedDict: dict<func> = {Fn: AddNum}
export const CONST = 10
export final finalVar = 'abc'
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())
call s:vim9.exportedDict.Fn(5)
call assert_equal(27, s:vim9.exported_nr)
call call(s:vim9.exportedDict.Fn, [3])
call assert_equal(30, s:vim9.exported_nr)
call assert_fails('let s:vim9.CONST = 20', 'E46: Cannot change read-only variable "CONST"')
call assert_fails('let s:vim9.finalVar = ""', 'E46: Cannot change read-only variable "finalVar"')
call assert_fails('let s:vim9.non_existing_var = 20', 'E1048: Item not found in script: non_existing_var')
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'
def FooFunc(): string
return bar.Func()
enddef
g:resultFunc = FooFunc()
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')
# Access item from :def imported through symbolic linked directory. #14536
mkdir('Xto/real_dir', 'pR')
lines =<< trim END
vim9script
export const val = 17
export def F(): number
return 23
enddef
END
writefile(lines, 'Xto/real_dir/real_file.vim')
system('ln -s real_dir Xto/syml_dir')
defer delete('Xto/syml_dir')
lines =<< trim END
vim9script
import autoload './Xto/syml_dir/real_file.vim'
def Fmain()
assert_equal(17, real_file.val)
enddef
def F2()
assert_equal(23, real_file.F())
enddef
Fmain()
F2()
END
v9.CheckScriptSuccess(lines)
endif
enddef
def Test_export_in_conditional_block()
var lines =<< trim END
vim9script
if exists('this_will_fail')
export var MyVar = "hello"
endif
END
v9.CheckScriptSuccess(lines)
enddef
" Import fails when an autoloaded script is imported again.
" Github issue #14171
def Test_import_autloaded_script()
mkdir('Ximporttwice', 'pR')
mkdir('Ximporttwice/plugin')
mkdir('Ximporttwice/autoload')
var save_rtp = &rtp
exe 'set rtp^=' .. getcwd() .. '/Ximporttwice'
var lines =<< trim END
vim9script
export def H(): number
return 10
enddef
END
writefile(lines, 'Ximporttwice/autoload/hello.vim')
lines =<< trim END
vim9script
import "./hello.vim"
export def W(): number
return 20
enddef
END
writefile(lines, 'Ximporttwice/autoload/world.vim')
lines =<< trim END
vim9script
import autoload '../autoload/hello.vim'
import autoload '../autoload/world.vim'
command Hello echo hello.H()
command World echo world.W()
END
writefile(lines, 'Ximporttwice/plugin/main.vim')
lines =<< trim END
vim9script
source ./Ximporttwice/plugin/main.vim
assert_equal(['20'], execute('World')->split("\n"))
END
v9.CheckScriptSuccess(lines)
&rtp = save_rtp
enddef
" Test for autoloading an imported dict func
def Test_autoload_import_dict_func()
mkdir('Xdir/autoload', 'pR')
var lines =<< trim END
vim9script
export var al_exported_nr: number = 33
def Al_AddNum(n: number)
al_exported_nr += n
enddef
export var al_exportedDict: dict<func> = {Fn: Al_AddNum}
END
writefile(lines, 'Xdir/autoload/Xdictfunc.vim')
var save_rtp = &rtp
exe 'set rtp^=' .. getcwd() .. '/Xdir'
lines =<< trim END
import './Xdir/autoload/Xdictfunc.vim'
call Xdictfunc#al_exportedDict.Fn(5)
call assert_equal(38, Xdictfunc#al_exported_nr)
call call(Xdictfunc#al_exportedDict.Fn, [3])
call assert_equal(41, Xdictfunc#al_exported_nr)
END
v9.CheckScriptSuccess(lines)
&rtp = save_rtp
enddef
" Test for changing the value of an imported Dict item
def Test_set_imported_dict_item()
var lines =<< trim END
vim9script
export var dict1: dict<bool> = {bflag: false}
export var dict2: dict<dict<bool>> = {x: {bflag: false}}
END
writefile(lines, 'XimportedDict.vim', 'D')
lines =<< trim END
vim9script
import './XimportedDict.vim'
assert_equal(XimportedDict.dict1.bflag, false)
XimportedDict.dict1.bflag = true
assert_equal(XimportedDict.dict1.bflag, true)
XimportedDict.dict2.x.bflag = true
assert_equal(XimportedDict.dict2.x.bflag, true)
assert_equal('bool', typename(XimportedDict.dict1.bflag))
assert_equal('bool', typename(XimportedDict.dict2.x.bflag))
assert_equal('bool', typename(XimportedDict.dict2['x'].bflag))
assert_equal('bool', typename(XimportedDict.dict2.x['bflag']))
assert_equal(XimportedDict.dict1['bflag'], true)
XimportedDict.dict1['bflag'] = false
assert_equal(XimportedDict.dict1.bflag, false)
XimportedDict.dict2['x']['bflag'] = false
assert_equal(XimportedDict.dict2['x'].bflag, false)
END
v9.CheckScriptSuccess(lines)
lines =<< trim END
vim9script
import './XimportedDict.vim'
XimportedDict.dict2.x.bflag = []
END
v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected bool but got list<any>', 3)
enddef
" Test for changing the value of an imported class member
def Test_set_imported_class_member()
var lines =<< trim END
vim9script
export class Config
public static var option = false
endclass
END
writefile(lines, 'XimportedClass.vim', 'D')
lines =<< trim END
vim9script
import './XimportedClass.vim' as foo
type FooConfig = foo.Config
assert_equal(false, FooConfig.option)
assert_equal(false, foo.Config.option)
foo.Config.option = true
assert_equal(true, foo.Config.option)
assert_equal(true, FooConfig.option)
END
v9.CheckScriptSuccess(lines)
enddef
" Test for using an imported function from the vimrc file.  The function is
" defined in the 'start' directory of a package.
def Test_import_from_vimrc()
mkdir('Ximport/pack/foobar/start/foo/autoload', 'pR')
var lines =<< trim END
vim9script
export def Foo()
writefile(['Foo called'], 'Xoutput.log')
enddef
END
writefile(lines, 'Ximport/pack/foobar/start/foo/autoload/foo.vim')
lines =<< trim END
vim9script
set packpath+=./Ximport
try
import autoload 'foo.vim'
foo.Foo()
catch
writefile(['Failed to import foo.vim'], 'Xoutput.log')
endtry
qall!
END
writefile(lines, 'Xvimrc', 'D')
g:RunVim([], [], '-u Xvimrc')
assert_equal(['Foo called'], readfile('Xoutput.log'))
delete('Xoutput.log')
enddef
" Test for changing a locked imported variable
def Test_import_locked_var()
var lines =<< trim END
vim9script
export var Foo: number = 10
lockvar Foo
END
writefile(lines, 'Ximportlockedvar.vim', 'D')
lines =<< trim END
vim9script
import './Ximportlockedvar.vim' as Bar
Bar.Foo = 20
END
v9.CheckScriptFailure(lines, 'E741: Value is locked: Foo', 3)
enddef
" Test for using an autoload imported class as the function return type
def Test_imported_class_as_def_func_rettype()
var lines =<< trim END
vim9script
export class Foo
var name: string = "foo"
endclass
END
writefile(lines, 'Ximportclassrettype1.vim', 'D')
lines =<< trim END
vim9script
import autoload "./Ximportclassrettype1.vim" as A
export def CreateFoo(): A.Foo
return A.Foo.new()
enddef
END
writefile(lines, 'Ximportclassrettype2.vim', 'D')
lines =<< trim END
vim9script
import './Ximportclassrettype2.vim' as B
var foo = B.CreateFoo()
assert_equal('foo', foo.name)
END
v9.CheckScriptSuccess(lines)
enddef
" Test for don't crash when using a combination of import and class extends
def Test_vim9_import_and_class_extends()
var lines =<< trim END
vim9script
import './cccc.vim'
export class Property extends cccc.Run
public var value: string
def new(this.value)
cccc.Run.value2 = this.value
enddef
endclass
END
writefile(lines, './aaaa.vim', 'D')
lines =<< trim END
vim9script
export class Run
public var value2: string
def new(this.value)
enddef
endclass
END
writefile(lines, './cccc.vim', 'D')
lines =<< trim END
vim9script
import './aaaa.vim'
class View
var content = aaaa.Property.new('')
endclass
var myView = View.new('This should be ok')
assert_equal('This should be ok', myView.content.value)
END
v9.CheckScriptFailure(lines, 'E1376: Object variable "value2" accessible only using class "Run" object', 2)
enddef
" Test for import and class extends
def Test_vim9_import_and_class_extends_2()
mkdir('import', 'R')
var save_rtp = &rtp
&rtp = getcwd()
var lines =<< trim END
vim9script
export class Property
public var value: string
endclass
END
writefile(lines, './import/libproperty.vim')
lines =<< trim END
vim9script
import 'libproperty.vim'
export class View
var _content = libproperty.Property.new('')
endclass
END
writefile(lines, './import/libview.vim')
lines =<< trim END
vim9script
import 'libview.vim'
class MyView extends libview.View
def new(value: string)
this._content.value = value
enddef
endclass
var myView = MyView.new('This should be ok')
END
v9.CheckScriptSuccess(lines)
&rtp = save_rtp
enddef
" Test for using an imported class as a type
def Test_use_imported_class_as_type()
mkdir('Xdir', 'R')
mkdir('Xdir/autoload', 'D')
mkdir('Xdir/import', 'D')
var lines =<< trim END
vim9script
export class B
var foo: string
def new()
this.foo = 'bar'
enddef
endclass
END
writefile(lines, 'Xdir/autoload/b.vim')
lines =<< trim END
vim9script
import autoload '../autoload/b.vim'
export class A
final AO: b.B = b.B.new()
endclass
var a = A.new()
assert_equal('bar', a.AO.foo)
END
writefile(lines, 'Xdir/import/a.vim')
source Xdir/import/a.vim
enddef
" Test for using an autoloaded class from another autoloaded script
def Test_class_from_auloaded_script()
mkdir('Xdir', 'R')
var save_rtp = &rtp
&rtp = getcwd()
exe 'set rtp^=' .. getcwd() .. '/Xdir'
mkdir('Xdir/autoload/SomeClass/bar', 'p')
var lines =<< trim END
vim9script
export class Baz
static var v1: string = "v1"
var v2: string = "v2"
def GetName(): string
return "baz"
enddef
endclass
END
writefile(lines, 'Xdir/autoload/SomeClass/bar/baz.vim', 'D')
lines =<< trim END
vim9script
import autoload './bar/baz.vim'
export def MyTestFoo(): string
assert_fails('var x = baz.Baz.NonExisting()', 'E1325: Method "NonExisting" not found in class "Baz"')
assert_fails('var x = baz.Baz.foobar', 'E1337: Class variable "foobar" not found in class "Baz"')
const instance = baz.Baz.new()
return $'{instance.GetName()} {baz.Baz.v1} {instance.v2}'
enddef
END
writefile(lines, 'Xdir/autoload/SomeClass/foo.vim', 'D')
lines =<< trim END
vim9script
import autoload 'SomeClass/foo.vim'
import autoload 'SomeClass/bar/baz.vim'
def NotInAutoload()
# Use non-existing class method and variable
assert_fails('var x = baz.Baz.NonExisting()', 'E1325: Method "NonExisting" not found in class "Baz"')
var caught_exception = false
try
var x = baz.Baz.foobar
catch /E1337: Class variable "foobar" not found in class "Baz"/
caught_exception = true
endtry
assert_true(caught_exception)
const instance = baz.Baz.new()
assert_equal("baz v1 v2", $'{instance.GetName()} {baz.Baz.v1} {instance.v2}')
enddef
def InAutoload()
assert_equal("baz v1 v2", foo.MyTestFoo())
enddef
NotInAutoload()
InAutoload()
END
v9.CheckScriptSuccess(lines)
&rtp = save_rtp
enddef
" Test for using an autoloaded enum from another script
def Test_enum_from_auloaded_script()
mkdir('Xdir', 'R')
var save_rtp = &rtp
&rtp = getcwd()
exe 'set rtp^=' .. getcwd() .. '/Xdir'
mkdir('Xdir/autoload/', 'p')
var lines =<< trim END
vim9script
export enum Color
Red,
Green,
Blue
endenum
END
writefile(lines, 'Xdir/autoload/color.vim', 'D')
lines =<< trim END
vim9script
import autoload 'color.vim'
def CheckColor()
var c = color.Color.Green
assert_equal('Green', c.name)
enddef
CheckColor()
END
v9.CheckScriptSuccess(lines)
&rtp = save_rtp
enddef
" Test for using a non-exported constant as an instance variable initiazer in an
" imported class
def Test_import_member_initializer()
var lines =<< trim END
vim9script
const DEFAULT = 'default'
export class Foo
public var x = DEFAULT
endclass
END
writefile(lines, 'Ximportclass.vim', 'D')
# The initializer for Foo.x is evaluated in the context of Ximportclass.vim.
lines =<< trim END
vim9script
import './Ximportclass.vim' as X
class Bar extends X.Foo
endclass
var o = Bar.new()
assert_equal('default', o.x)
END
v9.CheckScriptSuccess(lines)
# Another test
lines =<< trim END
vim9script
export interface IObjKey
var unique_object_id: string
endinterface
# helper sub-class.
export class ObjKey implements IObjKey
const unique_object_id = GenerateKey()
endclass
export def GenerateKey(): string
return "SomeKey"
enddef
END
writefile(lines, 'XobjKey.vim', 'D')
lines =<< trim END
vim9script
import "./XobjKey.vim" as obj_key
const GenKey = obj_key.GenerateKey
class LocalObjKey implements obj_key.IObjKey
const unique_object_id = GenKey()
endclass
type Key1 = obj_key.ObjKey
type Key2 = LocalObjKey
class C1 extends Key1
endclass
class C2 extends Key2
endclass
assert_equal('SomeKey', C1.new().unique_object_id)
assert_equal('SomeKey', C2.new().unique_object_id)
END
v9.CheckScriptSuccess(lines)
enddef
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker