Skip to content

Commit 2d8889d

Browse files
committed
implement nvim.exec_lua and nvim.lua.function
1 parent 13f7635 commit 2d8889d

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

neovim/api/nvim.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ def __init__(self, session, channel_id, metadata, types,
9292
self.current = Current(self)
9393
self.session = CompatibilitySession(self)
9494
self.funcs = Funcs(self)
95+
self.lua = LuaFuncs(self)
9596
self.error = NvimError
9697
self._decode = decode
9798
self._err_cb = err_cb
@@ -253,6 +254,27 @@ def call(self, name, *args, **kwargs):
253254
"""Call a vimscript function."""
254255
return self.request('nvim_call_function', name, args, **kwargs)
255256

257+
def exec_lua(self, code, *args, **kwargs):
258+
"""Execute lua code.
259+
260+
Additional parameters are available as `...` inside the lua chunk.
261+
Only statements are executed. To evaluate an expression, prefix it
262+
with `return`: `return my_function(...)`
263+
264+
There is a shorthand syntax to call lua functions with arguments:
265+
266+
nvim.lua.func(1,2)
267+
nvim.lua.mymod.myfunction(data, async_=True)
268+
269+
is equivalent to
270+
271+
nvim.exec_lua("return func(...)", 1, 2)
272+
nvim.exec_lua("mymod.myfunction(...)", data, async_=True)
273+
274+
Note that with `async_=True` there is no return value.
275+
"""
276+
return self.request('nvim_execute_lua', code, args, **kwargs)
277+
256278
def strwidth(self, string):
257279
"""Return the number of display cells `string` occupies.
258280
@@ -467,5 +489,29 @@ def __getattr__(self, name):
467489
return partial(self._nvim.call, name)
468490

469491

492+
class LuaFuncs(object):
493+
494+
"""Wrapper to allow lua functions to be called like python methods."""
495+
496+
def __init__(self, nvim, name=""):
497+
self._nvim = nvim
498+
self.name = name
499+
500+
def __getattr__(self, name):
501+
"""Return wrapper to named api method."""
502+
prefix = self.name + "." if self.name else ""
503+
return LuaFuncs(self._nvim, prefix + name)
504+
505+
def __call__(self, *args, **kwargs):
506+
# first new function after keyword rename, be a bit noisy
507+
if 'async' in kwargs:
508+
raise ValueError('"async" argument is not allowed. '
509+
'Use "async_" instead.')
510+
async_ = kwargs.get('async_', False)
511+
pattern = "return {}(...)" if not async_ else "{}(...)"
512+
code = pattern.format(self.name)
513+
return self._nvim.exec_lua(code, *args, **kwargs)
514+
515+
470516
class NvimError(Exception):
471517
pass

test/test_vim.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,32 @@ def test_cwd(vim, tmpdir):
168168
cwd_python = vim.command_output('{} print(os.getcwd())'.format(pycmd))
169169
assert cwd_python == cwd_vim
170170
assert cwd_python != cwd_before
171+
172+
lua_code = """
173+
local a = vim.api
174+
local y = ...
175+
function pynvimtest_func(x)
176+
return x+y
177+
end
178+
179+
local function setbuf(buf,lines)
180+
a.nvim_buf_set_lines(buf, 0, -1, true, lines)
181+
end
182+
183+
184+
local function getbuf(buf)
185+
return a.nvim_buf_line_count(buf)
186+
end
187+
188+
pynvimtest = {setbuf=setbuf,getbuf=getbuf}
189+
190+
return "eggspam"
191+
"""
192+
193+
def test_lua(vim):
194+
assert vim.exec_lua(lua_code, 7) == "eggspam"
195+
assert vim.lua.pynvimtest_func(3) == 10
196+
testmod = vim.lua.pynvimtest
197+
buf = vim.current.buffer
198+
testmod.setbuf(buf, ["a", "b", "c", "d"], async_=True)
199+
assert testmod.getbuf(buf) == 4

0 commit comments

Comments
 (0)