diff src/if_lua.c @ 20441:86dde5c4b375 v8.2.0775

patch 8.2.0775: not easy to call a Vim function from Lua Commit: https://github.com/vim/vim/commit/eb04f0893afe01faff272ef84c70d8cc16d8e80a Author: Bram Moolenaar <Bram@vim.org> Date: Sun May 17 14:32:35 2020 +0200 patch 8.2.0775: not easy to call a Vim function from Lua Problem: Not easy to call a Vim function from Lua. Solution: Add vim.call() and vim.fn(). (Prabir Shrestha, closes https://github.com/vim/vim/issues/6063)
author Bram Moolenaar <Bram@vim.org>
date Sun, 17 May 2020 14:45:04 +0200
parents 4acb165ed0bc
children 070c8a22261d
line wrap: on
line diff
--- a/src/if_lua.c
+++ b/src/if_lua.c
@@ -568,8 +568,21 @@ luaV_totypval(lua_State *L, int pos, typ
 	    break;
 	case LUA_TNUMBER:
 #ifdef FEAT_FLOAT
-	    tv->v_type = VAR_FLOAT;
-	    tv->vval.v_float = (float_T) lua_tonumber(L, pos);
+	{
+	    const lua_Number n = lua_tonumber(L, pos);
+
+	    if (n > (lua_Number)INT64_MAX || n < (lua_Number)INT64_MIN
+		    || ((lua_Number)((varnumber_T)n)) != n)
+	    {
+		tv->v_type = VAR_FLOAT;
+		tv->vval.v_float = (float_T)n;
+	    }
+	    else
+	    {
+		tv->v_type = VAR_NUMBER;
+		tv->vval.v_number = (varnumber_T)n;
+	    }
+	}
 #else
 	    tv->v_type = VAR_NUMBER;
 	    tv->vval.v_number = (varnumber_T) lua_tointeger(L, pos);
@@ -1903,6 +1916,52 @@ luaV_type(lua_State *L)
     return 1;
 }
 
+    static int
+luaV_call(lua_State *L)
+{
+    int		argc = lua_gettop(L) - 1;
+    size_t	funcname_len;
+    char_u	*funcname;
+    char	*error = NULL;
+    typval_T	rettv;
+    typval_T	argv[MAX_FUNC_ARGS + 1];
+    int		i = 0;
+
+    if (argc > MAX_FUNC_ARGS)
+	return luaL_error(L, "Function called with too many arguments");
+
+    funcname = (char_u *)luaL_checklstring(L, 1, &funcname_len);
+
+    for (; i < argc; i++)
+    {
+	if (luaV_totypval(L, i + 2, &argv[i]) == FAIL)
+	{
+	    error = "lua: cannot convert value";
+	    goto free_vim_args;
+	}
+    }
+
+    argv[argc].v_type = VAR_UNKNOWN;
+
+    if (call_vim_function(funcname, argc, argv, &rettv) == FAIL)
+    {
+	error = "lua: call_vim_function failed";
+	goto free_vim_args;
+    }
+
+    luaV_pushtypval(L, &rettv);
+    clear_tv(&rettv);
+
+free_vim_args:
+    while (i > 0)
+	clear_tv(&argv[--i]);
+
+    if (error == NULL)
+	return 1;
+    else
+	return luaL_error(L, error);
+}
+
 static const luaL_Reg luaV_module[] = {
     {"command", luaV_command},
     {"eval", luaV_eval},
@@ -1916,6 +1975,7 @@ static const luaL_Reg luaV_module[] = {
     {"window", luaV_window},
     {"open", luaV_open},
     {"type", luaV_type},
+    {"call", luaV_call},
     {NULL, NULL}
 };
 
@@ -1997,6 +2057,17 @@ luaV_setref(lua_State *L)
     return 1;
 }
 
+#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"\
+    "})"
+
     static int
 luaopen_vim(lua_State *L)
 {
@@ -2052,6 +2123,8 @@ luaopen_vim(lua_State *L)
     lua_pushvalue(L, 1); // cache table
     luaV_openlib(L, luaV_module, 1);
     lua_setglobal(L, LUAVIM_NAME);
+    // custom code
+    luaL_dostring(L, LUA_VIM_FN_CODE);
     return 0;
 }