" Test for python 2 commands. source check.vim CheckFeature python CheckFeature quickfix source shared.vim " NOTE: This will cause errors when run under valgrind. " This would require recompiling Python with: " ./configure --without-pymalloc " See http://svn.python.org/view/python/trunk/Misc/README.valgrind?view=markup " " This function should be called first. This sets up python functions used by " the other tests. func Test_AAA_python_setup() py << trim EOF import vim import sys def emsg(ei): return ei[0].__name__ + ':' + repr(ei[1].args) def ee(expr, g=globals(), l=locals()): try: exec(expr, g, l) except: ei = sys.exc_info() msg = emsg(ei) msg = msg.replace('TypeError:(\'argument 1 ', 'TypeError:(\'') if expr.find('None') > -1: msg = msg.replace('TypeError:(\'iteration over non-sequence\',)', 'TypeError:("\'NoneType\' object is not iterable",)') if expr.find('FailingNumber') > -1: msg = msg.replace(', not \'FailingNumber\'', '').replace('"', '\'') msg = msg.replace('TypeError:(\'iteration over non-sequence\',)', 'TypeError:("\'FailingNumber\' object is not iterable",)') if msg.find('(\'\'') > -1 or msg.find('(\'can\'t') > -1: msg = msg.replace('(\'', '("').replace('\',)', '",)') # Some Python versions say can't, others cannot. if msg.find('can\'t') > -1: msg = msg.replace('can\'t', 'cannot') # Some Python versions use single quote, some double quote if msg.find('"cannot ') > -1: msg = msg.replace('"cannot ', '\'cannot ') if msg.find(' attributes"') > -1: msg = msg.replace(' attributes"', ' attributes\'') if expr == 'fd(self=[])': # HACK: PyMapping_Check changed meaning msg = msg.replace('AttributeError:(\'keys\',)', 'TypeError:(\'unable to convert list to vim dictionary\',)') vim.current.buffer.append(expr + ':' + msg) else: vim.current.buffer.append(expr + ':NOT FAILED') EOF endfunc func Test_pydo() " Check deleting lines does not trigger an ml_get error. new call setline(1, ['one', 'two', 'three']) pydo vim.command("%d_") bwipe! " Check switching to another buffer does not trigger an ml_get error. new let wincount = winnr('$') call setline(1, ['one', 'two', 'three']) pydo vim.command("new") call assert_equal(wincount + 1, winnr('$')) bwipe! bwipe! " Try modifying a buffer with 'nomodifiable' set set nomodifiable call assert_fails('pydo toupper(line)', 'E21:') set modifiable " Invalid command call AssertException(['pydo non_existing_cmd'], \ "Vim(pydo):NameError: global name 'non_existing_cmd' is not defined") call AssertException(["pydo raise Exception('test')"], \ 'Vim(pydo):Exception: test') call AssertException(["pydo {lambda}"], \ 'Vim(pydo):SyntaxError: invalid syntax') endfunc func Test_set_cursor() " Check that setting the cursor position works. new call setline(1, ['first line', 'second line']) normal gg pydo vim.current.window.cursor = (1, 5) call assert_equal([1, 6], [line('.'), col('.')]) " Check that movement after setting cursor position keeps current column. normal j call assert_equal([2, 6], [line('.'), col('.')]) endfunc func Test_vim_function() " Check creating vim.Function object func s:foo() return matchstr(expand(''), '\zs\d\+_foo$') endfunc let name = '' . s:foo() try py f = vim.bindeval('function("s:foo")') call assert_equal(name, pyeval('f.name')) catch call assert_false(v:exception) endtry try py f = vim.Function('\x80\xfdR' + vim.eval('s:foo()')) call assert_equal(name, 'f.name'->pyeval()) catch call assert_false(v:exception) endtry " Non-existing function attribute call AssertException(["let x = pyeval('f.abc')"], \ 'Vim(let):AttributeError: abc') py del f delfunc s:foo endfunc func Test_skipped_python_command_does_not_affect_pyxversion() set pyxversion=0 if 0 python import vim endif call assert_equal(0, &pyxversion) " This assertion would have failed with Vim 8.0.0251. (pyxversion was introduced in 8.0.0251.) endfunc func _SetUpHiddenBuffer() new edit hidden setlocal bufhidden=hide enew let lnum = 0 while lnum < 10 call append( 1, string( lnum ) ) let lnum = lnum + 1 endwhile normal G call assert_equal( line( '.' ), 11 ) endfunc func _CleanUpHiddenBuffer() bwipe! hidden bwipe! endfunc func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_Clear() call _SetUpHiddenBuffer() py vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][:] = None call assert_equal( line( '.' ), 11 ) call _CleanUpHiddenBuffer() endfunc func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_List() call _SetUpHiddenBuffer() py vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][:] = [ 'test' ] call assert_equal( line( '.' ), 11 ) call _CleanUpHiddenBuffer() endfunc func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_Str() call _SetUpHiddenBuffer() py vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][0] = 'test' call assert_equal( line( '.' ), 11 ) call _CleanUpHiddenBuffer() endfunc func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_ClearLine() call _SetUpHiddenBuffer() py vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][0] = None call assert_equal( line( '.' ), 11 ) call _CleanUpHiddenBuffer() endfunc func _SetUpVisibleBuffer() new let lnum = 0 while lnum < 10 call append( 1, string( lnum ) ) let lnum = lnum + 1 endwhile normal G call assert_equal( line( '.' ), 11 ) endfunc func Test_Write_To_Current_Buffer_Fixes_Cursor_Clear() call _SetUpVisibleBuffer() py vim.current.buffer[:] = None call assert_equal( line( '.' ), 1 ) bwipe! endfunc func Test_Write_To_Current_Buffer_Fixes_Cursor_List() call _SetUpVisibleBuffer() py vim.current.buffer[:] = [ 'test' ] call assert_equal( line( '.' ), 1 ) bwipe! endfunc func Test_Write_To_Current_Buffer_Fixes_Cursor_Str() call _SetUpVisibleBuffer() py vim.current.buffer[-1] = None call assert_equal( line( '.' ), 10 ) bwipe! endfunc func Test_Catch_Exception_Message() try py raise RuntimeError( 'TEST' ) catch /.*/ call assert_match( '^Vim(.*):RuntimeError: TEST$', v:exception ) endtry endfunc " Test for various heredoc syntax func Test_python_heredoc() python << END s='A' END python << s+='B' . python << trim END s+='C' END python << trim s+='D' . python << trim eof s+='E' eof call assert_equal('ABCDE', pyxeval('s')) endfunc " Test for the buffer range object func Test_python_range() new call setline(1, ['one', 'two', 'three']) py b = vim.current.buffer py r = b.range(1, 3) call assert_equal(0, pyeval('r.start')) call assert_equal(2, pyeval('r.end')) call assert_equal('one', pyeval('r[0]')) call assert_equal('one', pyeval('r[-3]')) call assert_equal('three', pyeval('r[-4]')) call assert_equal(['two', 'three'], pyeval('r[1:]')) py r[0] = 'green' call assert_equal(['green', 'two', 'three'], getline(1, '$')) py r[0:2] = ['red', 'blue'] call assert_equal(['red', 'blue', 'three'], getline(1, '$')) call assert_equal(['start', 'end', '__members__'], pyeval('r.__members__')) " try different invalid start/end index for the range slice %d call setline(1, ['one', 'two', 'three']) py r[-10:1] = ["a"] py r[10:12] = ["b"] py r[-10:-9] = ["c"] py r[1:0] = ["d"] call assert_equal(['c', 'd', 'a', 'two', 'three', 'b'], getline(1, '$')) " The following code used to trigger an ml_get error %d let x = pyeval('r[:]') " Non-existing range attribute call AssertException(["let x = pyeval('r.abc')"], \ 'Vim(let):AttributeError: abc') close! endfunc " Test for the python tabpage object func Test_python_tabpage() tabnew py t = vim.tabpages[1] py wl = t.windows tabclose " Accessing a closed tabpage call AssertException(["let n = pyeval('t.number')"], \ 'Vim(let):vim.error: attempt to refer to deleted tab page') call AssertException(["let n = pyeval('len(wl)')"], \ 'Vim(let):vim.error: attempt to refer to deleted tab page') call AssertException(["py w = wl[0]"], \ 'Vim(python):vim.error: attempt to refer to deleted tab page') call AssertException(["py vim.current.tabpage = t"], \ 'Vim(python):vim.error: attempt to refer to deleted tab page') call assert_match(', , ]", substitute(pyeval('repr(dv)'),'0x\x\+','','g')) call assert_equal("[('-1', ), ('0', -1L), ('1', 'asd'), ('b', ), ('f', )]", substitute(pyeval('repr(di)'),'0x\x\+','','g')) call assert_equal(['0', '1', 'b', 'f', '-1'], keys(d)) call assert_equal("[-1, 'asd', [1, 2, function('strlen')], function('1'), {'a': 1}]", string(values(d))) py del dk py del di py del dv endfunc func Test_python_list_del_items() " removing items with del let l = [0, function("strlen"), [1, 2, function("strlen"), {'a': 1}]] py l = vim.bindeval('l') py del l[2] call assert_equal("[0, function('strlen')]", string(l)) let l = range(8) py l = vim.bindeval('l') py del l[:3] py del l[1:] call assert_equal([3], l) " removing items out of range: silently skip items that don't exist " The following two ranges delete nothing as they match empty list: let l = [0, 1, 2, 3] py l = vim.bindeval('l') py del l[2:1] call assert_equal([0, 1, 2, 3], l) py del l[2:2] call assert_equal([0, 1, 2, 3], l) py del l[2:3] call assert_equal([0, 1, 3], l) let l = [0, 1, 2, 3] py l = vim.bindeval('l') py del l[2:4] call assert_equal([0, 1], l) let l = [0, 1, 2, 3] py l = vim.bindeval('l') py del l[2:5] call assert_equal([0, 1], l) let l = [0, 1, 2, 3] py l = vim.bindeval('l') py del l[2:6] call assert_equal([0, 1], l) " The following two ranges delete nothing as they match empty list: let l = [0, 1, 2, 3] py l = vim.bindeval('l') py del l[-1:2] call assert_equal([0, 1, 2, 3], l) py del l[-2:2] call assert_equal([0, 1, 2, 3], l) py del l[-3:2] call assert_equal([0, 2, 3], l) let l = [0, 1, 2, 3] py l = vim.bindeval('l') py del l[-4:2] call assert_equal([2, 3], l) let l = [0, 1, 2, 3] py l = vim.bindeval('l') py del l[-5:2] call assert_equal([2, 3], l) let l = [0, 1, 2, 3] py l = vim.bindeval('l') py del l[-6:2] call assert_equal([2, 3], l) let l = [0, 1, 2, 3] py l = vim.bindeval('l') py del l[::2] call assert_equal([1, 3], l) let l = [0, 1, 2, 3] py l = vim.bindeval('l') py del l[3:0:-2] call assert_equal([0, 2], l) let l = [0, 1, 2, 3] py l = vim.bindeval('l') py del l[2:4:-2] let l = [0, 1, 2, 3] endfunc func Test_python_dict_del_items() let d = eval("{'0' : -1, '1' : 'asd', 'b' : [1, 2, function('strlen')], 'f' : function('min'), '-1' : {'a': 1}}") py d = vim.bindeval('d') py del d['-1'] py del d['f'] call assert_equal([1, 2, function('strlen')], pyeval('d.get(''b'', 1)')) call assert_equal([1, 2, function('strlen')], pyeval('d.pop(''b'')')) call assert_equal(1, pyeval('d.get(''b'', 1)')) call assert_equal('asd', pyeval('d.pop(''1'', 2)')) call assert_equal(2, pyeval('d.pop(''1'', 2)')) call assert_equal('True', pyeval('repr(d.has_key(''0''))')) call assert_equal('False', pyeval('repr(d.has_key(''1''))')) call assert_equal('True', pyeval('repr(''0'' in d)')) call assert_equal('False', pyeval('repr(''1'' in d)')) call assert_equal("['0']", pyeval('repr(list(iter(d)))')) call assert_equal({'0' : -1}, d) call assert_equal("('0', -1L)", pyeval('repr(d.popitem())')) call assert_equal('None', pyeval('repr(d.get(''0''))')) call assert_equal('[]', pyeval('repr(list(iter(d)))')) endfunc " Slice assignment to a list func Test_python_slice_assignment() let l = [0, 1, 2, 3] py l = vim.bindeval('l') py l[0:0] = ['a'] call assert_equal(['a', 0, 1, 2, 3], l) let l = [0, 1, 2, 3] py l = vim.bindeval('l') py l[1:2] = ['b'] call assert_equal([0, 'b', 2, 3], l) let l = [0, 1, 2, 3] py l = vim.bindeval('l') py l[2:4] = ['c'] call assert_equal([0, 1, 'c'], l) let l = [0, 1, 2, 3] py l = vim.bindeval('l') py l[4:4] = ['d'] call assert_equal([0, 1, 2, 3, 'd'], l) let l = [0, 1, 2, 3] py l = vim.bindeval('l') py l[-1:2] = ['e'] call assert_equal([0, 1, 2, 'e', 3], l) let l = [0, 1, 2, 3] py l = vim.bindeval('l') py l[-10:2] = ['f'] call assert_equal(['f', 2, 3], l) let l = [0, 1, 2, 3] py l = vim.bindeval('l') py l[2:-10] = ['g'] call assert_equal([0, 1, 'g', 2, 3], l) let l = [] py l = vim.bindeval('l') py l[0:0] = ['h'] call assert_equal(['h'], l) let l = range(8) py l = vim.bindeval('l') py l[2:6:2] = [10, 20] call assert_equal([0, 1, 10, 3, 20, 5, 6, 7], l) let l = range(8) py l = vim.bindeval('l') py l[6:2:-2] = [10, 20] call assert_equal([0, 1, 2, 3, 20, 5, 10, 7], l) let l = range(8) py l = vim.bindeval('l') py l[6:2] = () call assert_equal([0, 1, 2, 3, 4, 5, 6, 7], l) let l = range(8) py l = vim.bindeval('l') py l[6:2:1] = () call assert_equal([0, 1, 2, 3, 4, 5, 6, 7], l) let l = range(8) py l = vim.bindeval('l') py l[2:2:1] = () call assert_equal([0, 1, 2, 3, 4, 5, 6, 7], l) call AssertException(["py x = l[10:11:0]"], \ "Vim(python):ValueError: slice step cannot be zero") endfunc " Locked variables func Test_python_lockedvar() new py cb = vim.current.buffer let l = [0, 1, 2, 3] py l = vim.bindeval('l') lockvar! l py << trim EOF try: l[2]='i' except vim.error: cb.append('l[2] threw vim.error: ' + emsg(sys.exc_info())) EOF call assert_equal(['', "l[2] threw vim.error: error:('list is locked',)"], \ getline(1, '$')) " Try to concatenate a locked list call AssertException(['py l += [4, 5]'], \ 'Vim(python):vim.error: list is locked') call assert_equal([0, 1, 2, 3], l) unlockvar! l close! endfunc " Test for calling a function func Test_python_function_call() func New(...) return ['NewStart'] + a:000 + ['NewEnd'] endfunc func DictNew(...) dict return ['DictNewStart'] + a:000 + ['DictNewEnd', self] endfunc new let l = [function('New'), function('DictNew')] py l = vim.bindeval('l') py l.extend(list(l[0](1, 2, 3))) call assert_equal([function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd'], l) py l.extend(list(l[1](1, 2, 3, self={'a': 'b'}))) call assert_equal([function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}], l) py l.extend([l[0].name]) call assert_equal([function('New'), function('DictNew'), 'NewStart', 1, 2, 3, 'NewEnd', 'DictNewStart', 1, 2, 3, 'DictNewEnd', {'a': 'b'}, 'New'], l) py ee('l[1](1, 2, 3)') call assert_equal("l[1](1, 2, 3):error:('Vim:E725: Calling dict function without Dictionary: DictNew',)", getline(2)) %d py f = l[0] delfunction New py ee('f(1, 2, 3)') call assert_equal("f(1, 2, 3):error:('Vim:E117: Unknown function: New',)", getline(2)) close! delfunction DictNew endfunc func Test_python_float() let l = [0.0] py l = vim.bindeval('l') py l.extend([0.0]) call assert_equal([0.0, 0.0], l) endfunc " Test for Dict key errors func Test_python_dict_key_error() let messages = [] py << trim EOF d = vim.bindeval('{}') m = vim.bindeval('messages') def em(expr, g=globals(), l=locals()): try: exec(expr, g, l) except: m.extend([sys.exc_type.__name__]) em('d["abc1"]') em('d["abc1"]="\\0"') em('d["abc1"]=vim') em('d[""]=1') em('d["a\\0b"]=1') em('d[u"a\\0b"]=1') em('d.pop("abc1")') em('d.popitem()') del em del m EOF call assert_equal(['KeyError', 'TypeError', 'TypeError', 'ValueError', \ 'TypeError', 'TypeError', 'KeyError', 'KeyError'], messages) unlet messages endfunc " Test for locked and scope attributes func Test_python_lock_scope_attr() let d = {} | let dl = {} | lockvar dl let res = [] for s in split("d dl v: g:") let name = tr(s, ':', 's') execute 'py ' .. name .. ' = vim.bindeval("' .. s .. '")' call add(res, s .. ' : ' .. join(map(['locked', 'scope'], \ 'v:val .. ":" .. pyeval(name .. "." .. v:val)'), ';')) endfor call assert_equal(['d : locked:0;scope:0', 'dl : locked:1;scope:0', \ 'v: : locked:2;scope:1', 'g: : locked:0;scope:2'], res) silent! let d.abc2 = 1 silent! let dl.abc3 = 1 py d.locked = True py dl.locked = False silent! let d.def = 1 silent! let dl.def = 1 call assert_equal({'abc2': 1}, d) call assert_equal({'def': 1}, dl) unlet d dl let l = [] | let ll = [] | lockvar ll let res = [] for s in split("l ll") let name = tr(s, ':', 's') execute 'py ' .. name .. '=vim.bindeval("' .. s .. '")' call add(res, s .. ' : locked:' .. pyeval(name .. '.locked')) endfor call assert_equal(['l : locked:0', 'll : locked:1'], res) silent! call extend(l, [0]) silent! call extend(ll, [0]) py l.locked = True py ll.locked = False silent! call extend(l, [1]) silent! call extend(ll, [1]) call assert_equal([0], l) call assert_equal([1], ll) unlet l ll " Try changing an attribute of a fixed list py a = vim.bindeval('v:argv') call AssertException(['py a.locked = 0'], \ 'Vim(python):TypeError: cannot modify fixed list') endfunc " Test for pyeval() func Test_python_pyeval() let l = pyeval('range(3)') call assert_equal([0, 1, 2], l) let d = pyeval('{"a": "b", "c": 1, "d": ["e"]}') call assert_equal([['a', 'b'], ['c', 1], ['d', ['e']]], sort(items(d))) let v:errmsg = '' call assert_equal(v:none, pyeval('None')) call assert_equal('', v:errmsg) py v = vim.eval('test_null_function()') call assert_equal(v:none, pyeval('v')) call assert_equal(0.0, pyeval('0.0')) " Evaluate an invalid values call AssertException(['let v = pyeval(''"\0"'')'], 'E859:') call AssertException(['let v = pyeval(''{"\0" : 1}'')'], 'E859:') call AssertException(['let v = pyeval("undefined_name")'], \ "Vim(let):NameError: name 'undefined_name' is not defined") call AssertException(['let v = pyeval("vim")'], 'E859:') endfunc " Test for vim.bindeval() func Test_python_vim_bindeval() " Float let f = 3.14 py f = vim.bindeval('f') call assert_equal(3.14, pyeval('f')) " Blob let b = 0z12 py b = vim.bindeval('b') call assert_equal("\x12", pyeval('b')) " Bool call assert_equal(1, pyeval("vim.bindeval('v:true')")) call assert_equal(0, pyeval("vim.bindeval('v:false')")) call assert_equal(v:none, pyeval("vim.bindeval('v:null')")) call assert_equal(v:none, pyeval("vim.bindeval('v:none')")) " channel/job if has('channel') call assert_equal(v:none, pyeval("vim.bindeval('test_null_channel()')")) endif if has('job') call assert_equal(v:none, pyeval("vim.bindeval('test_null_job()')")) endif endfunc " threading " Running pydo command (Test_pydo) before this test, stops the python thread " from running. So this test should be run before the pydo test func Test_aaa_python_threading() let l = [0] py l = vim.bindeval('l') py << trim EOF import threading import time class T(threading.Thread): def __init__(self): threading.Thread.__init__(self) self.t = 0 self.running = True def run(self): while self.running: self.t += 1 time.sleep(0.1) t = T() del T t.start() EOF sleep 1 py t.running = False py t.join() " Check if the background thread is working. Count should be 10, but on a " busy system (AppVeyor) it can be much lower. py l[0] = t.t > 4 py del time py del threading py del t call assert_equal([1], l) endfunc " settrace func Test_python_settrace() let l = [] py l = vim.bindeval('l') py << trim EOF import sys def traceit(frame, event, arg): global l if event == "line": l.extend([frame.f_lineno]) return traceit def trace_main(): for i in range(5): pass EOF py sys.settrace(traceit) py trace_main() py sys.settrace(None) py del traceit py del trace_main call assert_equal([1, 10, 11, 10, 11, 10, 11, 10, 11, 10, 11, 10, 1], l) endfunc " Slice func Test_python_list_slice() py ll = vim.bindeval('[0, 1, 2, 3, 4, 5]') py l = ll[:4] call assert_equal([0, 1, 2, 3], pyeval('l')) py l = ll[2:] call assert_equal([2, 3, 4, 5], pyeval('l')) py l = ll[:-4] call assert_equal([0, 1], pyeval('l')) py l = ll[-2:] call assert_equal([4, 5], pyeval('l')) py l = ll[2:4] call assert_equal([2, 3], pyeval('l')) py l = ll[4:2] call assert_equal([], pyeval('l')) py l = ll[-4:-2] call assert_equal([2, 3], pyeval('l')) py l = ll[-2:-4] call assert_equal([], pyeval('l')) py l = ll[:] call assert_equal([0, 1, 2, 3, 4, 5], pyeval('l')) py l = ll[0:6] call assert_equal([0, 1, 2, 3, 4, 5], pyeval('l')) py l = ll[-10:10] call assert_equal([0, 1, 2, 3, 4, 5], pyeval('l')) py l = ll[4:2:-1] call assert_equal([4, 3], pyeval('l')) py l = ll[::2] call assert_equal([0, 2, 4], pyeval('l')) py l = ll[4:2:1] call assert_equal([], pyeval('l')) " Error case: Use an invalid index call AssertException(['py ll[-10] = 5'], 'Vim(python):vim.error: internal error:') " Use a step value of 0 call AssertException(['py ll[0:3:0] = [1, 2, 3]'], \ 'Vim(python):ValueError: slice step cannot be zero') " Error case: Invalid slice type call AssertException(["py x = ll['abc']"], \ 'Vim(python):TypeError: index must be int or slice, not str') py del l " Error case: List with a null list item let l = [test_null_list()] py ll = vim.bindeval('l') call AssertException(["py x = ll[:]"], \ 'Vim(python):SystemError: error return without exception set') endfunc " Vars func Test_python_vars() let g:foo = 'bac' let w:abc3 = 'def' let b:baz = 'bar' let t:bar = 'jkl' try throw "Abc" catch /Abc/ call assert_equal('Abc', pyeval('vim.vvars[''exception'']')) endtry call assert_equal('bac', pyeval('vim.vars[''foo'']')) call assert_equal('def', pyeval('vim.current.window.vars[''abc3'']')) call assert_equal('bar', pyeval('vim.current.buffer.vars[''baz'']')) call assert_equal('jkl', pyeval('vim.current.tabpage.vars[''bar'']')) endfunc " Options " paste: boolean, global " previewheight number, global " operatorfunc: string, global " number: boolean, window-local " numberwidth: number, window-local " colorcolumn: string, window-local " statusline: string, window-local/global " autoindent: boolean, buffer-local " shiftwidth: number, buffer-local " omnifunc: string, buffer-local " preserveindent: boolean, buffer-local/global " path: string, buffer-local/global func Test_python_opts() let g:res = [] let g:bufs = [bufnr('%')] new let g:bufs += [bufnr('%')] vnew let g:bufs += [bufnr('%')] wincmd j vnew let g:bufs += [bufnr('%')] wincmd l func RecVars(opt) let gval = string(eval('&g:' .. a:opt)) let wvals = join(map(range(1, 4), \ 'v:val .. ":" .. string(getwinvar(v:val, "&" .. a:opt))')) let bvals = join(map(copy(g:bufs), \ 'v:val .. ":" .. string(getbufvar(v:val, "&" .. a:opt))')) call add(g:res, ' G: ' .. gval) call add(g:res, ' W: ' .. wvals) call add(g:res, ' B: ' .. wvals) endfunc py << trim EOF def e(s, g=globals(), l=locals()): try: exec(s, g, l) except: vim.command('return ' + repr(sys.exc_type.__name__)) def ev(s, g=globals(), l=locals()): try: return eval(s, g, l) except: vim.command('let exc=' + repr(sys.exc_type.__name__)) return 0 EOF func E(s) python e(vim.eval('a:s')) endfunc func Ev(s) let r = pyeval('ev(vim.eval("a:s"))') if exists('exc') throw exc endif return r endfunc py gopts1 = vim.options py wopts1 = vim.windows[2].options py wopts2 = vim.windows[0].options py wopts3 = vim.windows[1].options py bopts1 = vim.buffers[vim.bindeval("g:bufs")[2]].options py bopts2 = vim.buffers[vim.bindeval("g:bufs")[1]].options py bopts3 = vim.buffers[vim.bindeval("g:bufs")[0]].options call add(g:res, 'wopts iters equal: ' .. \ pyeval('list(wopts1) == list(wopts2)')) call add(g:res, 'bopts iters equal: ' .. \ pyeval('list(bopts1) == list(bopts2)')) py gset = set(iter(gopts1)) py wset = set(iter(wopts1)) py bset = set(iter(bopts1)) set path=.,..,, let lst = [] let lst += [['paste', 1, 0, 1, 2, 1, 1, 0]] let lst += [['previewheight', 5, 1, 6, 'a', 0, 1, 0]] let lst += [['operatorfunc', 'A', 'B', 'C', 2, 0, 1, 0]] let lst += [['number', 0, 1, 1, 0, 1, 0, 1]] let lst += [['numberwidth', 2, 3, 5, -100, 0, 0, 1]] let lst += [['colorcolumn', '+1', '+2', '+3', 'abc4', 0, 0, 1]] let lst += [['statusline', '1', '2', '4', 0, 0, 1, 1]] let lst += [['autoindent', 0, 1, 1, 2, 1, 0, 2]] let lst += [['shiftwidth', 0, 2, 1, 3, 0, 0, 2]] let lst += [['omnifunc', 'A', 'B', 'C', 1, 0, 0, 2]] let lst += [['preserveindent', 0, 1, 1, 2, 1, 1, 2]] let lst += [['path', '.,,', ',,', '.', 0, 0, 1, 2]] for [oname, oval1, oval2, oval3, invval, bool, global, local] in lst py oname = vim.eval('oname') py oval1 = vim.bindeval('oval1') py oval2 = vim.bindeval('oval2') py oval3 = vim.bindeval('oval3') if invval is 0 || invval is 1 py invval = bool(vim.bindeval('invval')) else py invval = vim.bindeval('invval') endif if bool py oval1 = bool(oval1) py oval2 = bool(oval2) py oval3 = bool(oval3) endif call add(g:res, '>>> ' .. oname) call add(g:res, ' g/w/b:' .. pyeval('oname in gset') .. '/' .. \ pyeval('oname in wset') .. '/' .. pyeval('oname in bset')) call add(g:res, ' g/w/b (in):' .. pyeval('oname in gopts1') .. '/' .. \ pyeval('oname in wopts1') .. '/' .. pyeval('oname in bopts1')) for v in ['gopts1', 'wopts1', 'bopts1'] try call add(g:res, ' p/' .. v .. ': ' .. Ev('repr(' .. v .. '[''' .. oname .. '''])')) catch call add(g:res, ' p/' .. v .. '! ' .. v:exception) endtry let r = E(v .. '[''' .. oname .. ''']=invval') if r isnot 0 call add(g:res, ' inv: ' .. string(invval) .. '! ' .. r) endif for vv in (v is# 'gopts1' ? [v] : [v, v[:-2] .. '2', v[:-2] .. '3']) let val = substitute(vv, '^.opts', 'oval', '') let r = E(vv .. '[''' .. oname .. ''']=' .. val) if r isnot 0 call add(g:res, ' ' .. vv .. '! ' .. r) endif endfor endfor call RecVars(oname) for v in ['wopts3', 'bopts3'] let r = E('del ' .. v .. '["' .. oname .. '"]') if r isnot 0 call add(g:res, ' del ' .. v .. '! ' .. r) endif endfor call RecVars(oname) endfor delfunction RecVars delfunction E delfunction Ev py del ev py del e only for buf in g:bufs[1:] execute 'bwipeout!' buf endfor py del gopts1 py del wopts1 py del wopts2 py del wopts3 py del bopts1 py del bopts2 py del bopts3 py del oval1 py del oval2 py del oval3 py del oname py del invval let expected =<< trim END wopts iters equal: 1 bopts iters equal: 1 >>> paste g/w/b:1/0/0 g/w/b (in):1/0/0 p/gopts1: False p/wopts1! KeyError inv: 2! KeyError wopts1! KeyError wopts2! KeyError wopts3! KeyError p/bopts1! KeyError inv: 2! KeyError bopts1! KeyError bopts2! KeyError bopts3! KeyError G: 1 W: 1:1 2:1 3:1 4:1 B: 1:1 2:1 3:1 4:1 del wopts3! KeyError del bopts3! KeyError G: 1 W: 1:1 2:1 3:1 4:1 B: 1:1 2:1 3:1 4:1 >>> previewheight g/w/b:1/0/0 g/w/b (in):1/0/0 p/gopts1: 12 inv: 'a'! TypeError p/wopts1! KeyError inv: 'a'! KeyError wopts1! KeyError wopts2! KeyError wopts3! KeyError p/bopts1! KeyError inv: 'a'! KeyError bopts1! KeyError bopts2! KeyError bopts3! KeyError G: 5 W: 1:5 2:5 3:5 4:5 B: 1:5 2:5 3:5 4:5 del wopts3! KeyError del bopts3! KeyError G: 5 W: 1:5 2:5 3:5 4:5 B: 1:5 2:5 3:5 4:5 >>> operatorfunc g/w/b:1/0/0 g/w/b (in):1/0/0 p/gopts1: '' inv: 2! TypeError p/wopts1! KeyError inv: 2! KeyError wopts1! KeyError wopts2! KeyError wopts3! KeyError p/bopts1! KeyError inv: 2! KeyError bopts1! KeyError bopts2! KeyError bopts3! KeyError G: 'A' W: 1:'A' 2:'A' 3:'A' 4:'A' B: 1:'A' 2:'A' 3:'A' 4:'A' del wopts3! KeyError del bopts3! KeyError G: 'A' W: 1:'A' 2:'A' 3:'A' 4:'A' B: 1:'A' 2:'A' 3:'A' 4:'A' >>> number g/w/b:0/1/0 g/w/b (in):0/1/0 p/gopts1! KeyError inv: 0! KeyError gopts1! KeyError p/wopts1: False p/bopts1! KeyError inv: 0! KeyError bopts1! KeyError bopts2! KeyError bopts3! KeyError G: 0 W: 1:1 2:1 3:0 4:0 B: 1:1 2:1 3:0 4:0 del wopts3! ValueError del bopts3! KeyError G: 0 W: 1:1 2:1 3:0 4:0 B: 1:1 2:1 3:0 4:0 >>> numberwidth g/w/b:0/1/0 g/w/b (in):0/1/0 p/gopts1! KeyError inv: -100! KeyError gopts1! KeyError p/wopts1: 4 inv: -100! error p/bopts1! KeyError inv: -100! KeyError bopts1! KeyError bopts2! KeyError bopts3! KeyError G: 4 W: 1:3 2:5 3:2 4:4 B: 1:3 2:5 3:2 4:4 del wopts3! ValueError del bopts3! KeyError G: 4 W: 1:3 2:5 3:2 4:4 B: 1:3 2:5 3:2 4:4 >>> colorcolumn g/w/b:0/1/0 g/w/b (in):0/1/0 p/gopts1! KeyError inv: 'abc4'! KeyError gopts1! KeyError p/wopts1: '' inv: 'abc4'! error p/bopts1! KeyError inv: 'abc4'! KeyError bopts1! KeyError bopts2! KeyError bopts3! KeyError G: '' W: 1:'+2' 2:'+3' 3:'+1' 4:'' B: 1:'+2' 2:'+3' 3:'+1' 4:'' del wopts3! ValueError del bopts3! KeyError G: '' W: 1:'+2' 2:'+3' 3:'+1' 4:'' B: 1:'+2' 2:'+3' 3:'+1' 4:'' >>> statusline g/w/b:1/1/0 g/w/b (in):1/1/0 p/gopts1: '' inv: 0! TypeError p/wopts1: None inv: 0! TypeError p/bopts1! KeyError inv: 0! KeyError bopts1! KeyError bopts2! KeyError bopts3! KeyError G: '1' W: 1:'2' 2:'4' 3:'1' 4:'1' B: 1:'2' 2:'4' 3:'1' 4:'1' del bopts3! KeyError G: '1' W: 1:'2' 2:'1' 3:'1' 4:'1' B: 1:'2' 2:'1' 3:'1' 4:'1' >>> autoindent g/w/b:0/0/1 g/w/b (in):0/0/1 p/gopts1! KeyError inv: 2! KeyError gopts1! KeyError p/wopts1! KeyError inv: 2! KeyError wopts1! KeyError wopts2! KeyError wopts3! KeyError p/bopts1: False G: 0 W: 1:0 2:1 3:0 4:1 B: 1:0 2:1 3:0 4:1 del wopts3! KeyError del bopts3! ValueError G: 0 W: 1:0 2:1 3:0 4:1 B: 1:0 2:1 3:0 4:1 >>> shiftwidth g/w/b:0/0/1 g/w/b (in):0/0/1 p/gopts1! KeyError inv: 3! KeyError gopts1! KeyError p/wopts1! KeyError inv: 3! KeyError wopts1! KeyError wopts2! KeyError wopts3! KeyError p/bopts1: 8 G: 8 W: 1:0 2:2 3:8 4:1 B: 1:0 2:2 3:8 4:1 del wopts3! KeyError del bopts3! ValueError G: 8 W: 1:0 2:2 3:8 4:1 B: 1:0 2:2 3:8 4:1 >>> omnifunc g/w/b:0/0/1 g/w/b (in):0/0/1 p/gopts1! KeyError inv: 1! KeyError gopts1! KeyError p/wopts1! KeyError inv: 1! KeyError wopts1! KeyError wopts2! KeyError wopts3! KeyError p/bopts1: '' inv: 1! TypeError G: '' W: 1:'A' 2:'B' 3:'' 4:'C' B: 1:'A' 2:'B' 3:'' 4:'C' del wopts3! KeyError del bopts3! ValueError G: '' W: 1:'A' 2:'B' 3:'' 4:'C' B: 1:'A' 2:'B' 3:'' 4:'C' >>> preserveindent g/w/b:0/0/1 g/w/b (in):0/0/1 p/gopts1! KeyError inv: 2! KeyError gopts1! KeyError p/wopts1! KeyError inv: 2! KeyError wopts1! KeyError wopts2! KeyError wopts3! KeyError p/bopts1: False G: 0 W: 1:0 2:1 3:0 4:1 B: 1:0 2:1 3:0 4:1 del wopts3! KeyError del bopts3! ValueError G: 0 W: 1:0 2:1 3:0 4:1 B: 1:0 2:1 3:0 4:1 >>> path g/w/b:1/0/1 g/w/b (in):1/0/1 p/gopts1: '.,..,,' inv: 0! TypeError p/wopts1! KeyError inv: 0! KeyError wopts1! KeyError wopts2! KeyError wopts3! KeyError p/bopts1: None inv: 0! TypeError G: '.,,' W: 1:'.,,' 2:',,' 3:'.,,' 4:'.' B: 1:'.,,' 2:',,' 3:'.,,' 4:'.' del wopts3! KeyError G: '.,,' W: 1:'.,,' 2:',,' 3:'.,,' 4:'.,,' B: 1:'.,,' 2:',,' 3:'.,,' 4:'.,,' END call assert_equal(expected, g:res) unlet g:res call assert_equal(0, pyeval("'' in vim.options")) " use an empty key to index vim.options call AssertException(["let v = pyeval(\"vim.options['']\")"], \ 'Vim(let):ValueError: empty keys are not allowed') call AssertException(["py vim.current.window.options[''] = 0"], \ 'Vim(python):ValueError: empty keys are not allowed') call AssertException(["py vim.current.window.options[{}] = 0"], \ 'Vim(python):TypeError: expected str() or unicode() instance, but got dict') " set one of the number options to a very large number let cmd = ["py vim.options['previewheight'] = 9999999999999999"] call AssertException(cmd, 'OverflowError:') " unset a global-local string option call AssertException(["py del vim.options['errorformat']"], \ 'Vim(python):ValueError: unable to unset global option errorformat') endfunc " Test for vim.buffer object func Test_python_buffer() new call setline(1, "Hello\nWorld") call assert_fails("let x = pyeval('vim.current.buffer[0]')", 'E859:') %bw! edit Xfile1 let bnr1 = bufnr() py cb = vim.current.buffer vnew Xfile2 let bnr2 = bufnr() call setline(1, ['First line', 'Second line', 'Third line']) py b = vim.current.buffer wincmd w " Test for getting lines from the buffer using a slice call assert_equal(['First line'], pyeval('b[-10:1]')) call assert_equal(['Third line'], pyeval('b[2:10]')) call assert_equal([], pyeval('b[2:0]')) call assert_equal([], pyeval('b[10:12]')) call assert_equal([], pyeval('b[-10:-8]')) call AssertException(["py x = b[0:3:0]"], \ "Vim(python):TypeError: sequence index must be integer, not 'slice'") call AssertException(["py b[0:3:0] = 'abc'"], \ "Vim(python):TypeError: sequence index must be integer, not 'slice'") call AssertException(["py x = b[{}]"], \ "Vim(python):TypeError: sequence index must be integer, not 'dict'") call AssertException(["py b[{}] = 'abc'"], \ "Vim(python):TypeError: sequence index must be integer, not 'dict'") " Test for getting lines using a range call AssertException(["py x = b.range(0,3)[0:2:0]"], \ "Vim(python):TypeError: sequence index must be integer, not 'slice'") call AssertException(["py b.range(0,3)[0:2:0] = 'abc'"], \ "Vim(python):TypeError: sequence index must be integer, not 'slice'") " Tests BufferAppend and BufferItem py cb.append(b[0]) call assert_equal(['First line'], getbufline(bnr1, 2)) %d " Try to append using out-of-range line number call AssertException(["py b.append('abc', 10)"], \ 'Vim(python):IndexError: line number out of range') " Append a non-string item call AssertException(["py b.append([22])"], \ 'Vim(python):TypeError: expected str() or unicode() instance, but got int') " Tests BufferSlice and BufferAssSlice py cb.append('abc5') # Will be overwritten py cb[-1:] = b[:-2] call assert_equal(['First line'], getbufline(bnr1, 2)) %d " Test BufferLength and BufferAssSlice py cb.append('def') # Will not be overwritten py cb[len(cb):] = b[:] call assert_equal(['def', 'First line', 'Second line', 'Third line'], \ getbufline(bnr1, 2, '$')) %d " Test BufferAssItem and BufferMark call setbufline(bnr1, 1, ['one', 'two', 'three']) call cursor(1, 3) normal ma py cb.append('ghi') # Will be overwritten py cb[-1] = repr((len(cb) - cb.mark('a')[0], cb.mark('a')[1])) call assert_equal(['(3, 2)'], getbufline(bnr1, 4)) %d " Test BufferRepr py cb.append(repr(cb) + repr(b)) call assert_equal([''], getbufline(bnr1, 2)) %d " Modify foreign buffer py << trim EOF b.append('foo') b[0]='bar' b[0:0]=['baz'] vim.command('call append("$", getbufline(%i, 1, "$"))' % b.number) EOF call assert_equal(['baz', 'bar', 'Second line', 'Third line', 'foo'], \ getbufline(bnr2, 1, '$')) %d " Test assigning to name property augroup BUFS autocmd BufFilePost * python cb.append(vim.eval('expand("")') + ':BufFilePost:' + vim.eval('bufnr("%")')) autocmd BufFilePre * python cb.append(vim.eval('expand("")') + ':BufFilePre:' + vim.eval('bufnr("%")')) augroup END py << trim EOF import os old_name = cb.name cb.name = 'foo' cb.append(cb.name[-11:].replace(os.path.sep, '/')) b.name = 'bar' cb.append(b.name[-11:].replace(os.path.sep, '/')) cb.name = old_name cb.append(cb.name[-14:].replace(os.path.sep, '/')) del old_name EOF call assert_equal([bnr1 .. ':BufFilePre:' .. bnr1, \ bnr1 .. ':BufFilePost:' .. bnr1, \ 'testdir/foo', \ bnr2 .. ':BufFilePre:' .. bnr2, \ bnr2 .. ':BufFilePost:' .. bnr2, \ 'testdir/bar', \ bnr1 .. ':BufFilePre:' .. bnr1, \ bnr1 .. ':BufFilePost:' .. bnr1, \ 'testdir/Xfile1'], getbufline(bnr1, 2, '$')) %d " Test CheckBuffer py << trim EOF for _b in vim.buffers: if _b is not cb: vim.command('bwipeout! ' + str(_b.number)) del _b cb.append('valid: b:%s, cb:%s' % (repr(b.valid), repr(cb.valid))) EOF call assert_equal('valid: b:False, cb:True', getline(2)) %d py << trim EOF for expr in ('b[1]','b[:] = ["A", "B"]','b[:]','b.append("abc6")', 'b.name = "!"'): try: exec(expr) except vim.error: pass else: # Usually a SEGV here # Should not happen in any case cb.append('No exception for ' + expr) vim.command('cd .') del b EOF call assert_equal([''], getline(1, '$')) " Delete all the lines in a buffer call setline(1, ['a', 'b', 'c']) py vim.current.buffer[:] = [] call assert_equal([''], getline(1, '$')) " Test for buffer marks call assert_equal(v:none, pyeval("vim.current.buffer.mark('r')")) " Test for modifying a 'nomodifiable' buffer setlocal nomodifiable call AssertException(["py vim.current.buffer[0] = 'abc'"], \ "Vim(python):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") call AssertException(["py vim.current.buffer[0] = None"], \ "Vim(python):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") call AssertException(["py vim.current.buffer[:] = None"], \ "Vim(python):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") call AssertException(["py vim.current.buffer[:] = []"], \ "Vim(python):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") call AssertException(["py vim.current.buffer.append('abc')"], \ "Vim(python):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") call AssertException(["py vim.current.buffer.append([])"], \ "Vim(python):vim.error: Vim:E21: Cannot make changes, 'modifiable' is off") setlocal modifiable augroup BUFS autocmd! augroup END augroup! BUFS %bw! " Range object for a deleted buffer new Xpbuffile call setline(1, ['one', 'two', 'three']) py b = vim.current.buffer py r = vim.current.buffer.range(0, 2) call assert_equal('', pyeval('repr(r)')) %bw! call AssertException(['py r[:] = []'], \ 'Vim(python):vim.error: attempt to refer to deleted buffer') call assert_match('