diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2024-11-25 19:15:05 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2024-11-25 19:27:38 +0000 |
commit | c5d770d311841ea5230426cc4c868e8db27300a8 (patch) | |
tree | dd21f70127b4b8b5f109baefc8ecc5016f507c91 /src/nvim/lua | |
parent | 9be89f131f87608f224f0ee06d199fcd09d32176 (diff) | |
parent | 081beb3659bd6d8efc3e977a160b1e72becbd8a2 (diff) | |
download | rneovim-c5d770d311841ea5230426cc4c868e8db27300a8.tar.gz rneovim-c5d770d311841ea5230426cc4c868e8db27300a8.tar.bz2 rneovim-c5d770d311841ea5230426cc4c868e8db27300a8.zip |
Merge remote-tracking branch 'upstream/master' into mix_20240309
Diffstat (limited to 'src/nvim/lua')
-rw-r--r-- | src/nvim/lua/executor.c | 103 | ||||
-rw-r--r-- | src/nvim/lua/stdlib.c | 14 | ||||
-rw-r--r-- | src/nvim/lua/treesitter.c | 49 |
3 files changed, 100 insertions, 66 deletions
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index d4940f3add..c4fa8b0fff 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -187,7 +187,7 @@ static void nlua_luv_error_event(void **argv) msg_ext_set_kind("lua_error"); switch (type) { case kCallback: - semsg_multiline("Error executing luv callback:\n%s", error); + semsg_multiline("Error executing callback:\n%s", error); break; case kThread: semsg_multiline("Error in luv thread:\n%s", error); @@ -201,13 +201,13 @@ static void nlua_luv_error_event(void **argv) xfree(error); } -static int nlua_luv_cfpcall(lua_State *lstate, int nargs, int nresult, int flags) +/// Execute callback in "fast" context. Used for luv and some vim.ui_event +/// callbacks where using the API directly is not safe. +static int nlua_fast_cfpcall(lua_State *lstate, int nargs, int nresult, int flags) FUNC_ATTR_NONNULL_ALL { int retval; - // luv callbacks might be executed at any os_breakcheck/line_breakcheck - // call, so using the API directly here is not safe. in_fast_callback++; int top = lua_gettop(lstate); @@ -366,11 +366,13 @@ static int nlua_init_argv(lua_State *const L, char **argv, int argc, int lua_arg static void nlua_schedule_event(void **argv) { LuaRef cb = (LuaRef)(ptrdiff_t)argv[0]; + uint32_t ns_id = (uint32_t)(ptrdiff_t)argv[1]; lua_State *const lstate = global_lstate; nlua_pushref(lstate, cb); nlua_unref_global(lstate, cb); if (nlua_pcall(lstate, 0, 0)) { nlua_error(lstate, _("Error executing vim.schedule lua callback: %.*s")); + ui_remove_cb(ns_id, true); } } @@ -392,8 +394,9 @@ static int nlua_schedule(lua_State *const lstate) } LuaRef cb = nlua_ref_global(lstate, 1); - - multiqueue_put(main_loop.events, nlua_schedule_event, (void *)(ptrdiff_t)cb); + // Pass along UI event handler to disable on error. + multiqueue_put(main_loop.events, nlua_schedule_event, (void *)(ptrdiff_t)cb, + (void *)(ptrdiff_t)ui_event_ns_id); return 0; } @@ -425,7 +428,7 @@ static int nlua_wait(lua_State *lstate) FUNC_ATTR_NONNULL_ALL { if (in_fast_callback) { - return luaL_error(lstate, e_luv_api_disabled, "vim.wait"); + return luaL_error(lstate, e_fast_api_disabled, "vim.wait"); } intptr_t timeout = luaL_checkinteger(lstate, 1); @@ -598,7 +601,7 @@ static void nlua_common_vim_init(lua_State *lstate, bool is_thread, bool is_stan luv_set_cthread(lstate, nlua_luv_thread_cfcpcall); } else { luv_set_loop(lstate, &main_loop.uv); - luv_set_callback(lstate, nlua_luv_cfpcall); + luv_set_callback(lstate, nlua_fast_cfpcall); } luaopen_luv(lstate); lua_pushvalue(lstate, -1); @@ -724,7 +727,7 @@ static int nlua_ui_detach(lua_State *lstate) return luaL_error(lstate, "invalid ns_id"); } - ui_remove_cb(ns_id); + ui_remove_cb(ns_id, false); return 0; } @@ -951,41 +954,10 @@ static void nlua_common_free_all_mem(lua_State *lstate) static void nlua_print_event(void **argv) { - char *str = argv[0]; - const size_t len = (size_t)(intptr_t)argv[1] - 1; // exclude final NUL - - for (size_t i = 0; i < len;) { - if (got_int) { - break; - } - const size_t start = i; - while (i < len) { - switch (str[i]) { - case NUL: - str[i] = NL; - i++; - continue; - case NL: - // TODO(bfredl): use proper multiline msg? Probably should implement - // print() in lua in terms of nvim_message(), when it is available. - str[i] = NUL; - i++; - break; - default: - i++; - continue; - } - break; - } - msg(str + start, 0); - if (msg_silent == 0) { - msg_didout = true; // Make blank lines work properly - } - } - if (len && str[len - 1] == NUL) { // Last was newline - msg("", 0); - } - xfree(str); + HlMessage msg = KV_INITIAL_VALUE; + HlMessageChunk chunk = { { .data = argv[0], .size = (size_t)(intptr_t)argv[1] - 1 }, 0 }; + kv_push(msg, chunk); + msg_multihl(msg, "lua_print", true); } /// Print as a Vim message @@ -1174,7 +1146,7 @@ int nlua_call(lua_State *lstate) size_t name_len; const char *name = luaL_checklstring(lstate, 1, &name_len); if (!nlua_is_deferred_safe() && !viml_func_is_fast(name)) { - return luaL_error(lstate, e_luv_api_disabled, "Vimscript function"); + return luaL_error(lstate, e_fast_api_disabled, "Vimscript function"); } int nargs = lua_gettop(lstate) - 1; @@ -1231,7 +1203,7 @@ free_vim_args: static int nlua_rpcrequest(lua_State *lstate) { if (!nlua_is_deferred_safe()) { - return luaL_error(lstate, e_luv_api_disabled, "rpcrequest"); + return luaL_error(lstate, e_fast_api_disabled, "rpcrequest"); } return nlua_rpc(lstate, true); } @@ -1594,6 +1566,12 @@ bool nlua_ref_is_function(LuaRef ref) Object nlua_call_ref(LuaRef ref, const char *name, Array args, LuaRetMode mode, Arena *arena, Error *err) { + return nlua_call_ref_ctx(false, ref, name, args, mode, arena, err); +} + +Object nlua_call_ref_ctx(bool fast, LuaRef ref, const char *name, Array args, LuaRetMode mode, + Arena *arena, Error *err) +{ lua_State *const lstate = global_lstate; nlua_pushref(lstate, ref); int nargs = (int)args.size; @@ -1605,7 +1583,13 @@ Object nlua_call_ref(LuaRef ref, const char *name, Array args, LuaRetMode mode, nlua_push_Object(lstate, &args.items[i], 0); } - if (nlua_pcall(lstate, nargs, 1)) { + if (fast) { + if (nlua_fast_cfpcall(lstate, nargs, 1, -1) < 0) { + // error is already scheduled, set anyways to convey failure. + api_set_error(err, kErrorTypeException, "fast context failure"); + } + return NIL; + } else if (nlua_pcall(lstate, nargs, 1)) { // if err is passed, the caller will deal with the error. if (err) { size_t len; @@ -2063,8 +2047,16 @@ char *nlua_register_table_as_callable(const typval_T *const arg) return name; } -void nlua_execute_on_key(int c, char *typed_buf) +/// @return true to discard the key +bool nlua_execute_on_key(int c, char *typed_buf) { + static bool recursive = false; + + if (recursive) { + return false; + } + recursive = true; + char buf[MB_MAXBYTES * 3 + 4]; size_t buf_len = special_to_buf(c, mod_mask, false, buf); vim_unescape_ks(typed_buf); @@ -2090,9 +2082,15 @@ void nlua_execute_on_key(int c, char *typed_buf) int save_got_int = got_int; got_int = false; // avoid interrupts when the key typed is Ctrl-C - if (nlua_pcall(lstate, 2, 0)) { - nlua_error(lstate, - _("Error executing vim.on_key Lua callback: %.*s")); + bool discard = false; + // Do not use nlua_pcall here to avoid duplicate stack trace information + if (lua_pcall(lstate, 2, 1, 0)) { + nlua_error(lstate, _("Error executing vim.on_key() callbacks: %.*s")); + } else { + if (lua_isboolean(lstate, -1)) { + discard = lua_toboolean(lstate, -1); + } + lua_pop(lstate, 1); } got_int |= save_got_int; @@ -2103,6 +2101,9 @@ void nlua_execute_on_key(int c, char *typed_buf) // [ ] assert(top == lua_gettop(lstate)); #endif + + recursive = false; + return discard; } // Sets the editor "script context" during Lua execution. Used by :verbose. diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index ee0eabbebb..e719d99640 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -181,7 +181,9 @@ int nlua_str_utfindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL } else { idx = luaL_checkinteger(lstate, 2); if (idx < 0 || idx > (intptr_t)s1_len) { - return luaL_error(lstate, "index out of range"); + lua_pushnil(lstate); + lua_pushnil(lstate); + return 2; } } @@ -272,7 +274,8 @@ int nlua_str_byteindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL const char *s1 = luaL_checklstring(lstate, 1, &s1_len); intptr_t idx = luaL_checkinteger(lstate, 2); if (idx < 0) { - return luaL_error(lstate, "index out of range"); + lua_pushnil(lstate); + return 1; } bool use_utf16 = false; if (lua_gettop(lstate) >= 3) { @@ -281,7 +284,8 @@ int nlua_str_byteindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL ssize_t byteidx = mb_utf_index_to_bytes(s1, s1_len, (size_t)idx, use_utf16); if (byteidx == -1) { - return luaL_error(lstate, "index out of range"); + lua_pushnil(lstate); + return 1; } lua_pushinteger(lstate, (lua_Integer)byteidx); @@ -695,10 +699,10 @@ void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread) lua_setfield(lstate, -2, "stricmp"); // str_utfindex lua_pushcfunction(lstate, &nlua_str_utfindex); - lua_setfield(lstate, -2, "str_utfindex"); + lua_setfield(lstate, -2, "_str_utfindex"); // str_byteindex lua_pushcfunction(lstate, &nlua_str_byteindex); - lua_setfield(lstate, -2, "str_byteindex"); + lua_setfield(lstate, -2, "_str_byteindex"); // str_utf_pos lua_pushcfunction(lstate, &nlua_str_utf_pos); lua_setfield(lstate, -2, "str_utf_pos"); diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index ab97704dfe..c80e7b7672 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -271,12 +271,16 @@ int tslua_inspect_lang(lua_State *L) // not used by the API continue; } - lua_createtable(L, 2, 0); // [retval, symbols, elem] - lua_pushstring(L, ts_language_symbol_name(lang, (TSSymbol)i)); - lua_rawseti(L, -2, 1); - lua_pushboolean(L, t == TSSymbolTypeRegular); - lua_rawseti(L, -2, 2); // [retval, symbols, elem] - lua_rawseti(L, -2, (int)i); // [retval, symbols] + const char *name = ts_language_symbol_name(lang, (TSSymbol)i); + bool named = t != TSSymbolTypeAnonymous; + lua_pushboolean(L, named); // [retval, symbols, is_named] + if (!named) { + char buf[256]; + snprintf(buf, sizeof(buf), "\"%s\"", name); + lua_setfield(L, -2, buf); // [retval, symbols] + } else { + lua_setfield(L, -2, name); // [retval, symbols] + } } lua_setfield(L, -2, "symbols"); // [retval] @@ -828,6 +832,7 @@ static struct luaL_Reg node_meta[] = { { "parent", node_parent }, { "__has_ancestor", __has_ancestor }, { "child_containing_descendant", node_child_containing_descendant }, + { "child_with_descendant", node_child_with_descendant }, { "iter_children", node_iter_children }, { "next_sibling", node_next_sibling }, { "prev_sibling", node_prev_sibling }, @@ -1146,7 +1151,7 @@ static int __has_ancestor(lua_State *L) int const pred_len = (int)lua_objlen(L, 2); TSNode node = ts_tree_root_node(descendant.tree); - while (!ts_node_is_null(node)) { + while (node.id != descendant.id && !ts_node_is_null(node)) { char const *node_type = ts_node_type(node); size_t node_type_len = strlen(node_type); @@ -1163,7 +1168,7 @@ static int __has_ancestor(lua_State *L) lua_pop(L, 1); } - node = ts_node_child_containing_descendant(node, descendant); + node = ts_node_child_with_descendant(node, descendant); } lua_pushboolean(L, false); @@ -1179,6 +1184,15 @@ static int node_child_containing_descendant(lua_State *L) return 1; } +static int node_child_with_descendant(lua_State *L) +{ + TSNode node = node_check(L, 1); + TSNode descendant = node_check(L, 2); + TSNode child = ts_node_child_with_descendant(node, descendant); + push_node(L, child, 1); + return 1; +} + static int node_next_sibling(lua_State *L) { TSNode node = node_check(L, 1); @@ -1514,10 +1528,25 @@ static void query_err_string(const char *src, int error_offset, TSQueryError err || error_type == TSQueryErrorField || error_type == TSQueryErrorCapture) { const char *suffix = src + error_offset; + bool is_anonymous = error_type == TSQueryErrorNodeType && suffix[-1] == '"'; int suffix_len = 0; char c = suffix[suffix_len]; - while (isalnum(c) || c == '_' || c == '-' || c == '.') { - c = suffix[++suffix_len]; + if (is_anonymous) { + int backslashes = 0; + // Stop when we hit an unescaped double quote + while (c != '"' || backslashes % 2 != 0) { + if (c == '\\') { + backslashes += 1; + } else { + backslashes = 0; + } + c = suffix[++suffix_len]; + } + } else { + // Stop when we hit the end of the identifier + while (isalnum(c) || c == '_' || c == '-' || c == '.') { + c = suffix[++suffix_len]; + } } snprintf(err, errlen, "\"%.*s\":\n", suffix_len, suffix); offset = strlen(err); |