diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index a26213af98..178375d7f1 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -11,6 +11,7 @@ #include "nvim/api/window.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/lua/executor.h" #include "nvim/ex_docmd.h" #include "nvim/vim.h" #include "nvim/buffer.h" @@ -524,3 +525,39 @@ void nvim_win_close(Window window, Boolean force, Error *err) ex_win_close(force, win, tabpage == curtab ? NULL : tabpage); vim_ignored = try_leave(&tstate, err); } + +/// Calls a function with window as temporary current window. +/// +/// @see |win_execute()| +/// @see |nvim_buf_call()| +/// +/// @param window Window handle, or 0 for current window +/// @param fun Function to call inside the window (currently lua callable +/// only) +/// @param[out] err Error details, if any +/// @return Return value of function. NB: will deepcopy lua values +/// currently, use upvalues to send lua references in and out. +Object nvim_win_call(Window window, LuaRef fun, Error *err) + FUNC_API_SINCE(7) + FUNC_API_LUA_ONLY +{ + win_T *win = find_window_by_handle(window, err); + if (!win) { + return NIL; + } + tabpage_T *tabpage = win_find_tabpage(win); + + win_T *save_curwin; + tabpage_T *save_curtab; + + try_start(); + Object res = OBJECT_INIT; + if (switch_win_noblock(&save_curwin, &save_curtab, win, tabpage, true) == + OK) { + Array args = ARRAY_DICT_INIT; + res = nlua_call_ref(fun, NULL, args, true, err); + } + restore_win_noblock(save_curwin, save_curtab, true); + try_end(err); + return res; +} diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 08a0552a38..836f514433 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1931,6 +1931,34 @@ describe('lua stdlib', function() eq(buf2, val) end) end) + + describe('vim.api.nvim_win_call', function() + it('can access window options', function() + command('vsplit') + local win1 = meths.get_current_win() + command('wincmd w') + local win2 = exec_lua [[ + win2 = vim.api.nvim_get_current_win() + return win2 + ]] + command('wincmd p') + + eq('', meths.win_get_option(win1, 'winhighlight')) + eq('', meths.win_get_option(win2, 'winhighlight')) + + local val = exec_lua [[ + return vim.api.nvim_win_call(win2, function() + vim.cmd "setlocal winhighlight=Normal:Normal" + return vim.api.nvim_get_current_win() + end) + ]] + + eq('', meths.win_get_option(win1, 'winhighlight')) + eq('Normal:Normal', meths.win_get_option(win2, 'winhighlight')) + eq(win1, meths.get_current_win()) + eq(win2, val) + end) + end) end) describe('lua: require("mod") from packages', function()