# HG changeset patch # User Bram Moolenaar # Date 1590927303 -7200 # Node ID 054ba681412d92b4d5fe2f3c0b215dd7bb9abedc # Parent 13d49684acf5f93bc4457978ceb2744741b45ca0 patch 8.2.0858: not easy to require Lua modules Commit: https://github.com/vim/vim/commit/788fbb47079e6df4d4815d27273faf8390395029 Author: Bram Moolenaar Date: Sun May 31 14:08:12 2020 +0200 patch 8.2.0858: not easy to require Lua modules Problem: Not easy to require Lua modules. Solution: Improve use of Lua path. (Prabir Shrestha, closes https://github.com/vim/vim/issues/6098) diff --git a/Filelist b/Filelist --- a/Filelist +++ b/Filelist @@ -157,6 +157,7 @@ SRC_ALL = \ src/testdir/*.py \ src/testdir/lsan-suppress.txt \ src/testdir/sautest/autoload/*.vim \ + src/testdir/testluaplugin/lua/testluaplugin/*.lua \ src/testdir/check.vim \ src/testdir/gui_init.vim \ src/testdir/gui_preinit.vim \ diff --git a/src/if_lua.c b/src/if_lua.c --- a/src/if_lua.c +++ b/src/if_lua.c @@ -2061,15 +2061,80 @@ luaV_setref(lua_State *L) } #define LUA_VIM_FN_CODE \ - "vim.fn = setmetatable({}, {"\ - " __index = function (t, key)"\ - " local function _fn(...)"\ - " return vim.call(key, ...)"\ - " end"\ - " t[key] = _fn"\ - " return _fn"\ - " end"\ - "})" + "vim.fn = setmetatable({}, {\n"\ + " __index = function (t, key)\n"\ + " local function _fn(...)\n"\ + " return vim.call(key, ...)\n"\ + " end\n"\ + " t[key] = _fn\n"\ + " return _fn\n"\ + " end\n"\ + " })" + +#define LUA_VIM_UPDATE_PACKAGE_PATHS \ + "local last_vim_paths = {}\n"\ + "vim._update_package_paths = function ()\n"\ + " local cur_vim_paths = {}\n"\ + " local function split(s, delimiter)\n"\ + " result = {}\n"\ + " for match in (s..delimiter):gmatch(\"(.-)\"..delimiter) do\n"\ + " table.insert(result, match)\n"\ + " end\n"\ + " return result\n"\ + " end\n"\ + " local rtps = split(vim.eval('&runtimepath'), ',')\n"\ + " local sep = package.config:sub(1, 1)\n"\ + " for _, key in ipairs({'path', 'cpath'}) do\n"\ + " local orig_str = package[key] .. ';'\n"\ + " local pathtrails_ordered = {}\n"\ + " -- Note: ignores trailing item without trailing `;`. Not using something\n"\ + " -- simpler in order to preserve empty items (stand for default path).\n"\ + " local orig = {}\n"\ + " for s in orig_str:gmatch('[^;]*;') do\n"\ + " s = s:sub(1, -2) -- Strip trailing semicolon\n"\ + " orig[#orig + 1] = s\n"\ + " end\n"\ + " if key == 'path' then\n"\ + " -- /?.lua and /?/init.lua\n"\ + " pathtrails_ordered = {sep .. '?.lua', sep .. '?' .. sep .. 'init.lua'}\n"\ + " else\n"\ + " local pathtrails = {}\n"\ + " for _, s in ipairs(orig) do\n"\ + " -- Find out path patterns. pathtrail should contain something like\n"\ + " -- /?.so, \?.dll. This allows not to bother determining what correct\n"\ + " -- suffixes are.\n"\ + " local pathtrail = s:match('[/\\\\][^/\\\\]*%?.*$')\n"\ + " if pathtrail and not pathtrails[pathtrail] then\n"\ + " pathtrails[pathtrail] = true\n"\ + " pathtrails_ordered[#pathtrails_ordered + 1] = pathtrail\n"\ + " end\n"\ + " end\n"\ + " end\n"\ + " local new = {}\n"\ + " for _, rtp in ipairs(rtps) do\n"\ + " if not rtp:match(';') then\n"\ + " for _, pathtrail in pairs(pathtrails_ordered) do\n"\ + " local new_path = rtp .. sep .. 'lua' .. pathtrail\n"\ + " -- Always keep paths from &runtimepath at the start:\n"\ + " -- append them here disregarding orig possibly containing one of them.\n"\ + " new[#new + 1] = new_path\n"\ + " cur_vim_paths[new_path] = true\n"\ + " end\n"\ + " end\n"\ + " end\n"\ + " for _, orig_path in ipairs(orig) do\n"\ + " -- Handle removing obsolete paths originating from &runtimepath: such\n"\ + " -- paths either belong to cur_nvim_paths and were already added above or\n"\ + " -- to last_nvim_paths and should not be added at all if corresponding\n"\ + " -- entry was removed from &runtimepath list.\n"\ + " if not (cur_vim_paths[orig_path] or last_vim_paths[orig_path]) then\n"\ + " new[#new + 1] = orig_path\n"\ + " end\n"\ + " end\n"\ + " package[key] = table.concat(new, ';')\n"\ + " end\n"\ + " last_vim_paths = cur_vim_paths\n"\ + "end" static int luaopen_vim(lua_State *L) @@ -2128,6 +2193,14 @@ luaopen_vim(lua_State *L) lua_setglobal(L, LUAVIM_NAME); // custom code (void)luaL_dostring(L, LUA_VIM_FN_CODE); + (void)luaL_dostring(L, LUA_VIM_UPDATE_PACKAGE_PATHS); + + lua_getglobal(L, "vim"); + lua_getfield(L, -1, "_update_package_paths"); + + if (lua_pcall(L, 0, 0, 0)) + luaV_emsg(L); + return 0; } @@ -2329,4 +2402,17 @@ set_ref_in_lua(int copyID) return aborted; } + void +update_package_paths_in_lua() +{ + if (lua_isopen()) + { + lua_getglobal(L, "vim"); + lua_getfield(L, -1, "_update_package_paths"); + + if (lua_pcall(L, 0, 0, 0)) + luaV_emsg(L); + } +} + #endif diff --git a/src/optionstr.c b/src/optionstr.c --- a/src/optionstr.c +++ b/src/optionstr.c @@ -2402,6 +2402,11 @@ did_set_string_option( setmouse(); // in case 'mouse' changed } +#if defined(FEAT_LUA) || defined(PROTO) + if (varp == &p_rtp) + update_package_paths_in_lua(); +#endif + if (curwin->w_curswant != MAXCOL && (get_option_flags(opt_idx) & (P_CURSWANT | P_RALL)) != 0) curwin->w_set_curswant = TRUE; diff --git a/src/proto/if_lua.pro b/src/proto/if_lua.pro --- a/src/proto/if_lua.pro +++ b/src/proto/if_lua.pro @@ -8,4 +8,5 @@ void lua_buffer_free(buf_T *o); void lua_window_free(win_T *o); void do_luaeval(char_u *str, typval_T *arg, typval_T *rettv); int set_ref_in_lua(int copyID); +void update_package_paths_in_lua(void); /* vim: set ft=c : */ diff --git a/src/testdir/test_lua.vim b/src/testdir/test_lua.vim --- a/src/testdir/test_lua.vim +++ b/src/testdir/test_lua.vim @@ -536,6 +536,11 @@ func Test_lua_open() %bwipe! endfunc +func Test_update_package_paths() + set runtimepath+=./testluaplugin + call assert_equal("hello from lua", luaeval("require('testluaplugin').hello()")) +endfunc + " Test vim.line() func Test_lua_line() new diff --git a/src/testdir/testluaplugin/lua/testluaplugin/hello.lua b/src/testdir/testluaplugin/lua/testluaplugin/hello.lua new file mode 100644 --- /dev/null +++ b/src/testdir/testluaplugin/lua/testluaplugin/hello.lua @@ -0,0 +1,7 @@ +local function hello() + return "hello from lua" +end + +return { + hello = hello +} diff --git a/src/testdir/testluaplugin/lua/testluaplugin/init.lua b/src/testdir/testluaplugin/lua/testluaplugin/init.lua new file mode 100644 --- /dev/null +++ b/src/testdir/testluaplugin/lua/testluaplugin/init.lua @@ -0,0 +1,5 @@ +local hello = require('testluaplugin/hello').hello + +return { + hello = hello +} diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -747,6 +747,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 858, +/**/ 857, /**/ 856,