aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/lua
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/lua')
-rw-r--r--src/nvim/lua/converter.c15
-rw-r--r--src/nvim/lua/converter.h8
-rw-r--r--src/nvim/lua/executor.c159
-rw-r--r--src/nvim/lua/stdlib.c37
-rw-r--r--src/nvim/lua/treesitter.c12
5 files changed, 151 insertions, 80 deletions
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c
index 49d49f76b9..bdb0719809 100644
--- a/src/nvim/lua/converter.c
+++ b/src/nvim/lua/converter.c
@@ -15,12 +15,12 @@
#include "nvim/memory.h"
// FIXME: vim.h is not actually needed, but otherwise it states MAXPATHL is
// redefined
+#include "klib/kvec.h"
#include "nvim/ascii.h"
#include "nvim/eval/decode.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/userfunc.h"
#include "nvim/globals.h"
-#include "nvim/lib/kvec.h"
#include "nvim/lua/converter.h"
#include "nvim/lua/executor.h"
#include "nvim/macros.h"
@@ -385,15 +385,12 @@ nlua_pop_typval_table_processing_end:
break;
}
case LUA_TFUNCTION: {
- LuaCFunctionState *state = xmalloc(sizeof(LuaCFunctionState));
- state->lua_callable.func_ref = nlua_ref_global(lstate, -1);
+ LuaRef func = nlua_ref_global(lstate, -1);
- char_u *name = register_cfunc(&nlua_CFunction_func_call,
- &nlua_CFunction_func_free,
- state);
+ char *name = (char *)register_luafunc(func);
cur.tv->v_type = VAR_FUNC;
- cur.tv->vval.v_string = (char *)vim_strsave(name);
+ cur.tv->vval.v_string = xstrdup(name);
break;
}
case LUA_TUSERDATA: {
@@ -476,8 +473,8 @@ static bool typval_conv_special = false;
#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \
do { \
ufunc_T *fp = find_func(fun); \
- if (fp != NULL && fp->uf_cb == nlua_CFunction_func_call) { \
- nlua_pushref(lstate, ((LuaCFunctionState *)fp->uf_cb_state)->lua_callable.func_ref); \
+ if (fp != NULL && fp->uf_flags & FC_LUAREF) { \
+ nlua_pushref(lstate, fp->uf_luaref); \
} else { \
TYPVAL_ENCODE_CONV_NIL(tv); \
} \
diff --git a/src/nvim/lua/converter.h b/src/nvim/lua/converter.h
index f6a85900ba..ddc0acfbfa 100644
--- a/src/nvim/lua/converter.h
+++ b/src/nvim/lua/converter.h
@@ -9,14 +9,6 @@
#include "nvim/eval/typval.h"
#include "nvim/func_attr.h"
-typedef struct {
- LuaRef func_ref;
-} LuaCallable;
-
-typedef struct {
- LuaCallable lua_callable;
-} LuaCFunctionState;
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "lua/converter.h.generated.h"
#endif
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 39585ac182..f3821f149a 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -7,6 +7,7 @@
#include <tree_sitter/api.h>
#include "luv/luv.h"
+#include "nvim/api/extmark.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/vim.h"
@@ -40,6 +41,9 @@
#include "nvim/os/os.h"
#include "nvim/profile.h"
#include "nvim/runtime.h"
+#include "nvim/screen.h"
+#include "nvim/ui.h"
+#include "nvim/ui_compositor.h"
#include "nvim/undo.h"
#include "nvim/usercmd.h"
#include "nvim/version.h"
@@ -244,7 +248,7 @@ static int nlua_luv_thread_common_cfpcall(lua_State *lstate, int nargs, int nres
mch_errmsg(e_outofmem);
mch_errmsg("\n");
lua_close(lstate);
-#ifdef WIN32
+#ifdef MSWIN
ExitThread(0);
#else
pthread_exit(0);
@@ -589,6 +593,71 @@ static bool nlua_init_packages(lua_State *lstate)
return true;
}
+/// "vim.ui_attach(ns_id, {ext_foo=true}, cb)" function
+static int nlua_ui_attach(lua_State *lstate)
+ FUNC_ATTR_NONNULL_ALL
+{
+ uint32_t ns_id = (uint32_t)luaL_checkinteger(lstate, 1);
+
+ if (!ns_initialized(ns_id)) {
+ return luaL_error(lstate, "invalid ns_id");
+ }
+ if (!lua_istable(lstate, 2)) {
+ return luaL_error(lstate, "ext_widgets must be a table");
+ }
+ if (!lua_isfunction(lstate, 3)) {
+ return luaL_error(lstate, "callback must be a Lua function");
+ }
+
+ bool ext_widgets[kUIGlobalCount] = { false };
+ bool tbl_has_true_val = false;
+
+ lua_pushvalue(lstate, 2);
+ lua_pushnil(lstate);
+ while (lua_next(lstate, -2)) {
+ // [dict, key, val]
+ size_t len;
+ const char *s = lua_tolstring(lstate, -2, &len);
+ bool val = lua_toboolean(lstate, -1);
+
+ for (size_t i = 0; i < kUIGlobalCount; i++) {
+ if (strequal(s, ui_ext_names[i])) {
+ if (val) {
+ tbl_has_true_val = true;
+ }
+ ext_widgets[i] = val;
+ goto ok;
+ }
+ }
+
+ return luaL_error(lstate, "Unexpected key: %s", s);
+ok:
+ lua_pop(lstate, 1);
+ }
+
+ if (!tbl_has_true_val) {
+ return luaL_error(lstate, "ext_widgets table must contain at least one 'true' value");
+ }
+
+ LuaRef ui_event_cb = nlua_ref_global(lstate, 3);
+ ui_comp_add_cb(ns_id, ui_event_cb, ext_widgets);
+ return 0;
+}
+
+/// "vim.ui_detach(ns_id)" function
+static int nlua_ui_detach(lua_State *lstate)
+ FUNC_ATTR_NONNULL_ALL
+{
+ uint32_t ns_id = (uint32_t)luaL_checkinteger(lstate, 1);
+
+ if (!ns_initialized(ns_id)) {
+ return luaL_error(lstate, "invalid ns_id");
+ }
+
+ ui_comp_remove_cb(ns_id);
+ return 0;
+}
+
/// Initialize lua interpreter state
///
/// Called by lua interpreter itself to initialize state.
@@ -604,7 +673,7 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_setfield(lstate, -2, "debug");
lua_pop(lstate, 1);
-#ifdef WIN32
+#ifdef MSWIN
// os.getenv
lua_getglobal(lstate, "os");
lua_pushcfunction(lstate, &nlua_getenv);
@@ -649,6 +718,14 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_pushcfunction(lstate, &nlua_wait);
lua_setfield(lstate, -2, "wait");
+ // ui_attach
+ lua_pushcfunction(lstate, &nlua_ui_attach);
+ lua_setfield(lstate, -2, "ui_attach");
+
+ // ui_detach
+ lua_pushcfunction(lstate, &nlua_ui_detach);
+ lua_setfield(lstate, -2, "ui_detach");
+
nlua_common_vim_init(lstate, false);
// patch require() (only for --startuptime)
@@ -967,12 +1044,12 @@ static int nlua_debug(lua_State *lstate)
if (input.v_type != VAR_STRING
|| input.vval.v_string == NULL
|| *input.vval.v_string == NUL
- || STRCMP(input.vval.v_string, "cont") == 0) {
+ || strcmp(input.vval.v_string, "cont") == 0) {
tv_clear(&input);
return 0;
}
if (luaL_loadbuffer(lstate, (const char *)input.vval.v_string,
- STRLEN(input.vval.v_string), "=(debug command)")) {
+ strlen(input.vval.v_string), "=(debug command)")) {
nlua_error(lstate, _("E5115: Error while loading debug string: %.*s"));
} else if (nlua_pcall(lstate, 0, 0)) {
nlua_error(lstate, _("E5116: Error while calling debug string: %.*s"));
@@ -1027,15 +1104,15 @@ int nlua_call(lua_State *lstate)
// TODO(bfredl): this should be simplified in error handling refactor
force_abort = false;
suppress_errthrow = false;
- current_exception = NULL;
+ did_throw = false;
did_emsg = false;
try_start();
typval_T rettv;
funcexe_T funcexe = FUNCEXE_INIT;
- funcexe.firstline = curwin->w_cursor.lnum;
- funcexe.lastline = curwin->w_cursor.lnum;
- funcexe.evaluate = true;
+ funcexe.fe_firstline = curwin->w_cursor.lnum;
+ funcexe.fe_lastline = curwin->w_cursor.lnum;
+ funcexe.fe_evaluate = true;
// call_func() retval is deceptive, ignore it. Instead we set `msg_list`
// (TRY_WRAP) to capture abort-causing non-exception errors.
(void)call_func((char *)name, (int)name_len, &rettv, nargs, vim_args, &funcexe);
@@ -1124,7 +1201,7 @@ static int nlua_empty_dict_tostring(lua_State *lstate)
return 1;
}
-#ifdef WIN32
+#ifdef MSWIN
/// os.getenv: override os.getenv to maintain coherency. #9681
///
/// uv_os_setenv uses SetEnvironmentVariableW which does not update _environ.
@@ -1348,23 +1425,22 @@ int nlua_source_using_linegetter(LineGetter fgetline, void *cookie, char *name)
/// @param[in] argcount Count of typval arguments
/// @param[in] argvars Typval Arguments
/// @param[out] rettv The return value from the called function.
-int typval_exec_lua_callable(lua_State *lstate, LuaCallable lua_cb, int argcount, typval_T *argvars,
- typval_T *rettv)
+int typval_exec_lua_callable(LuaRef lua_cb, int argcount, typval_T *argvars, typval_T *rettv)
{
- LuaRef cb = lua_cb.func_ref;
+ lua_State *lstate = global_lstate;
- nlua_pushref(lstate, cb);
+ nlua_pushref(lstate, lua_cb);
PUSH_ALL_TYPVALS(lstate, argvars, argcount, false);
if (nlua_pcall(lstate, argcount, 1)) {
nlua_print(lstate);
- return ERROR_OTHER;
+ return FCERR_OTHER;
}
nlua_pop_typval(lstate, rettv);
- return ERROR_NONE;
+ return FCERR_NONE;
}
/// Execute Lua string
@@ -1422,9 +1498,10 @@ bool nlua_ref_is_function(LuaRef ref)
/// @param name if non-NULL, sent to callback as first arg
/// if NULL, only args are used
/// @param retval if true, convert return value to Object
-/// if false, discard return value
+/// if false, only check if return value is truthy
/// @param err Error details, if any (if NULL, errors are echoed)
-/// @return Return value of function, if retval was set. Otherwise NIL.
+/// @return Return value of function, if retval was set. Otherwise
+/// BOOLEAN_OBJ(true) or NIL.
Object nlua_call_ref(LuaRef ref, const char *name, Array args, bool retval, Error *err)
{
lua_State *const lstate = global_lstate;
@@ -1438,7 +1515,7 @@ Object nlua_call_ref(LuaRef ref, const char *name, Array args, bool retval, Erro
nlua_push_Object(lstate, args.items[i], false);
}
- if (nlua_pcall(lstate, nargs, retval ? 1 : 0)) {
+ if (nlua_pcall(lstate, nargs, 1)) {
// if err is passed, the caller will deal with the error.
if (err) {
size_t len;
@@ -1458,7 +1535,10 @@ Object nlua_call_ref(LuaRef ref, const char *name, Array args, bool retval, Erro
}
return nlua_pop_Object(lstate, false, err);
} else {
- return NIL;
+ bool value = lua_toboolean(lstate, -1);
+ lua_pop(lstate, 1);
+
+ return value ? BOOLEAN_OBJ(true) : NIL;
}
}
@@ -1561,7 +1641,7 @@ void ex_luado(exarg_T *const eap)
break;
}
if (lua_isstring(lstate, -1)) {
- size_t old_line_len = STRLEN(old_line);
+ size_t old_line_len = strlen(old_line);
size_t new_line_len;
const char *const new_line = lua_tolstring(lstate, -1, &new_line_len);
@@ -1578,7 +1658,7 @@ void ex_luado(exarg_T *const eap)
}
lua_pop(lstate, 1);
check_cursor();
- update_screen(UPD_NOT_VALID);
+ redraw_curbuf_later(UPD_NOT_VALID);
}
/// Run lua file
@@ -1752,26 +1832,6 @@ static int nlua_is_thread(lua_State *lstate)
return 1;
}
-// Required functions for lua c functions as VimL callbacks
-
-int nlua_CFunction_func_call(int argcount, typval_T *argvars, typval_T *rettv, void *state)
-{
- lua_State *const lstate = global_lstate;
- LuaCFunctionState *funcstate = (LuaCFunctionState *)state;
-
- return typval_exec_lua_callable(lstate, funcstate->lua_callable,
- argcount, argvars, rettv);
-}
-
-void nlua_CFunction_func_free(void *state)
-{
- lua_State *const lstate = global_lstate;
- LuaCFunctionState *funcstate = (LuaCFunctionState *)state;
-
- nlua_unref_global(lstate, funcstate->lua_callable.func_ref);
- xfree(funcstate);
-}
-
bool nlua_is_table_from_lua(typval_T *const arg)
{
if (arg->v_type == VAR_DICT) {
@@ -1817,11 +1877,9 @@ char_u *nlua_register_table_as_callable(typval_T *const arg)
}
lua_pop(lstate, 2); // [table]
- LuaCFunctionState *state = xmalloc(sizeof(LuaCFunctionState));
- state->lua_callable.func_ref = nlua_ref_global(lstate, -1);
+ LuaRef func = nlua_ref_global(lstate, -1);
- char_u *name = register_cfunc(&nlua_CFunction_func_call,
- &nlua_CFunction_func_free, state);
+ char_u *name = register_luafunc(func);
lua_pop(lstate, 1); // []
assert(top == lua_gettop(lstate));
@@ -1943,7 +2001,7 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview)
// Split args by unescaped whitespace |<f-args>| (nargs dependent)
if (cmd->uc_argt & EX_NOSPC) {
- if ((cmd->uc_argt & EX_NEEDARG) || STRLEN(eap->arg)) {
+ if ((cmd->uc_argt & EX_NEEDARG) || strlen(eap->arg)) {
// For commands where nargs is 1 or "?" and argument is passed, fargs = { args }
lua_rawseti(lstate, -2, 1);
} else {
@@ -1953,7 +2011,7 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview)
} else if (eap->args == NULL) {
// For commands with more than one possible argument, split if argument list isn't available.
lua_pop(lstate, 1); // Pop the reference of opts.args
- size_t length = STRLEN(eap->arg);
+ size_t length = strlen(eap->arg);
size_t end = 0;
size_t len = 0;
int i = 1;
@@ -1978,7 +2036,8 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview)
}
lua_setfield(lstate, -2, "fargs");
- lua_pushstring(lstate, (const char *)&eap->regname);
+ char reg[2] = { (char)eap->regname, NUL };
+ lua_pushstring(lstate, reg);
lua_setfield(lstate, -2, "reg");
lua_pushinteger(lstate, eap->addr_count);
@@ -2001,7 +2060,7 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview)
lua_newtable(lstate); // smods table
- lua_pushinteger(lstate, cmdmod.cmod_tab);
+ lua_pushinteger(lstate, cmdmod.cmod_tab - 1);
lua_setfield(lstate, -2, "tab");
lua_pushinteger(lstate, cmdmod.cmod_verbose - 1);
@@ -2022,6 +2081,8 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview)
lua_pushboolean(lstate, cmdmod.cmod_split & WSP_VERT);
lua_setfield(lstate, -2, "vertical");
+ lua_pushboolean(lstate, cmdmod.cmod_split & WSP_HOR);
+ lua_setfield(lstate, -2, "horizontal");
lua_pushboolean(lstate, cmdmod.cmod_flags & CMOD_SILENT);
lua_setfield(lstate, -2, "silent");
lua_pushboolean(lstate, cmdmod.cmod_flags & CMOD_ERRSILENT);
diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c
index 64e9abe0c9..2f46f6ff65 100644
--- a/src/nvim/lua/stdlib.c
+++ b/src/nvim/lua/stdlib.c
@@ -60,8 +60,8 @@ static int regex_match(lua_State *lstate, regprog_T **prog, char_u *str)
*prog = rm.regprog;
if (match) {
- lua_pushinteger(lstate, (lua_Integer)(rm.startp[0] - str));
- lua_pushinteger(lstate, (lua_Integer)(rm.endp[0] - str));
+ lua_pushinteger(lstate, (lua_Integer)(rm.startp[0] - (char *)str));
+ lua_pushinteger(lstate, (lua_Integer)(rm.endp[0] - (char *)str));
return 2;
}
return 0;
@@ -111,7 +111,7 @@ static int regex_match_line(lua_State *lstate)
return luaL_error(lstate, "invalid row");
}
- char_u *line = ml_get_buf(buf, rownr + 1, false);
+ char_u *line = (char_u *)ml_get_buf(buf, rownr + 1, false);
size_t len = STRLEN(line);
if (start < 0 || (size_t)start > len) {
@@ -304,8 +304,10 @@ int nlua_regex(lua_State *lstate)
nlua_push_errstr(lstate, "couldn't parse regex: %s", err.msg);
api_clear_error(&err);
return lua_error(lstate);
+ } else if (prog == NULL) {
+ nlua_push_errstr(lstate, "couldn't parse regex");
+ return lua_error(lstate);
}
- assert(prog);
regprog_T **p = lua_newuserdata(lstate, sizeof(regprog_T *));
*p = prog;
@@ -369,12 +371,19 @@ int nlua_setvar(lua_State *lstate)
return 0;
}
+ bool watched = tv_dict_is_watched(dict);
+
if (del) {
// Delete the key
if (di == NULL) {
// Doesn't exist, nothing to do
return 0;
} else {
+ // Notify watchers
+ if (watched) {
+ tv_dict_watcher_notify(dict, key.data, NULL, &di->di_tv);
+ }
+
// Delete the entry
tv_dict_item_remove(dict, di);
}
@@ -388,17 +397,29 @@ int nlua_setvar(lua_State *lstate)
return luaL_error(lstate, "Couldn't convert lua value");
}
+ typval_T oldtv = TV_INITIAL_VALUE;
+
if (di == NULL) {
// Need to create an entry
di = tv_dict_item_alloc_len(key.data, key.size);
tv_dict_add(dict, di);
} else {
+ if (watched) {
+ tv_copy(&di->di_tv, &oldtv);
+ }
// Clear the old value
tv_clear(&di->di_tv);
}
// Update the value
tv_copy(&tv, &di->di_tv);
+
+ // Notify watchers
+ if (watched) {
+ tv_dict_watcher_notify(dict, key.data, &tv, &oldtv);
+ tv_clear(&oldtv);
+ }
+
// Clear the temporary variable
tv_clear(&tv);
}
@@ -494,14 +515,14 @@ static int nlua_iconv(lua_State *lstate)
size_t str_len = 0;
const char *str = lua_tolstring(lstate, 1, &str_len);
- char_u *from = enc_canonize(enc_skip((char_u *)lua_tolstring(lstate, 2, NULL)));
- char_u *to = enc_canonize(enc_skip((char_u *)lua_tolstring(lstate, 3, NULL)));
+ char_u *from = (char_u *)enc_canonize(enc_skip((char *)lua_tolstring(lstate, 2, NULL)));
+ char_u *to = (char_u *)enc_canonize(enc_skip((char *)lua_tolstring(lstate, 3, NULL)));
vimconv_T vimconv;
vimconv.vc_type = CONV_NONE;
- convert_setup_ext(&vimconv, from, false, to, false);
+ convert_setup_ext(&vimconv, (char *)from, false, (char *)to, false);
- char_u *ret = string_convert(&vimconv, (char_u *)str, &str_len);
+ char_u *ret = (char_u *)string_convert(&vimconv, (char *)str, &str_len);
convert_setup(&vimconv, NULL, NULL);
diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c
index 7ff4fbbff4..79b11eca4a 100644
--- a/src/nvim/lua/treesitter.c
+++ b/src/nvim/lua/treesitter.c
@@ -16,9 +16,9 @@
#include <string.h>
#include <uv.h>
+#include "klib/kvec.h"
#include "nvim/api/private/helpers.h"
#include "nvim/buffer.h"
-#include "nvim/lib/kvec.h"
#include "nvim/log.h"
#include "nvim/lua/treesitter.h"
#include "nvim/map.h"
@@ -332,7 +332,7 @@ static const char *input_cb(void *payload, uint32_t byte_index, TSPoint position
*bytes_read = 0;
return "";
}
- char *line = (char *)ml_get_buf(bp, (linenr_T)position.row + 1, false);
+ char *line = ml_get_buf(bp, (linenr_T)position.row + 1, false);
size_t len = STRLEN(line);
if (position.column > len) {
*bytes_read = 0;
@@ -834,7 +834,7 @@ static int node_field(lua_State *L)
do {
const char *current_field = ts_tree_cursor_current_field_name(&cursor);
- if (current_field != NULL && !STRCMP(field_name, current_field)) {
+ if (current_field != NULL && !strcmp(field_name, current_field)) {
push_node(L, ts_tree_cursor_current_node(&cursor), 1); // [table, node]
lua_rawseti(L, -2, (int)++curr_index);
}
@@ -1276,8 +1276,8 @@ int tslua_parse_query(lua_State *L)
TSQuery *query = ts_query_new(lang, src, (uint32_t)len, &error_offset, &error_type);
if (!query) {
- return luaL_error(L, "query: %s at position %d",
- query_err_string(error_type), (int)error_offset);
+ return luaL_error(L, "query: %s at position %d for language %s",
+ query_err_string(error_type), (int)error_offset, lang_name);
}
TSQuery **ud = lua_newuserdata(L, sizeof(TSQuery *)); // [udata]
@@ -1369,7 +1369,7 @@ static int query_inspect(lua_State *L)
lua_rawseti(L, -2, nextitem++); // [retval, patterns, pat, pred]
}
// last predicate should have ended with TypeDone
- lua_pop(L, 1); // [retval, patters, pat]
+ lua_pop(L, 1); // [retval, patterns, pat]
lua_rawseti(L, -2, (int)i + 1); // [retval, patterns]
}
lua_setfield(L, -2, "patterns"); // [retval]