]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 8.2.0858: not easy to require Lua modules v8.2.0858
authorBram Moolenaar <Bram@vim.org>
Sun, 31 May 2020 12:08:12 +0000 (14:08 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 31 May 2020 12:08:12 +0000 (14:08 +0200)
Problem:    Not easy to require Lua modules.
Solution:   Improve use of Lua path. (Prabir Shrestha, closes #6098)

Filelist
src/if_lua.c
src/optionstr.c
src/proto/if_lua.pro
src/testdir/test_lua.vim
src/testdir/testluaplugin/lua/testluaplugin/hello.lua [new file with mode: 0644]
src/testdir/testluaplugin/lua/testluaplugin/init.lua [new file with mode: 0644]
src/version.c

index 6cd442a6a975425c3e06e6883eebfc0e055e2728..8bb0e2fb79054a04d6d7414aba464f3d97ef2f29 100644 (file)
--- 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 \
index 3ecedaf7d609a7ad375a8ff009050ca6362da666..75231b4c272361d2f6525f41452a0ee55e65b73b 100644 (file)
@@ -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
index ff0186f429d0bbe1a6659f1ff87a3253d82f7c1d..c03d994c3257957bc39dbf582d92c4a46358cafd 100644 (file)
@@ -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;
index c33678e13daf75b9ead213bad2bf492f32318af6..2e5da0c48fa321bbf2335f950ef5987c19afb8bb 100644 (file)
@@ -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 : */
index f92208c209657b8b91128f47b0ee0448d03b65a8..bd50bce56475f591362967b75bf26638e6ccf976 100644 (file)
@@ -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 (file)
index 0000000..7c90552
--- /dev/null
@@ -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 (file)
index 0000000..1e6c474
--- /dev/null
@@ -0,0 +1,5 @@
+local hello = require('testluaplugin/hello').hello
+
+return {
+    hello = hello
+}
index 5bd8609c9acdf23966d57ab97e720e99219a4538..27ed559d8512c1a07142c36d43e820192e467e35 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    858,
 /**/
     857,
 /**/